Two defects found while running /wiki-compile, both from tooling assuming
a path instead of resolving it.
1. Plaintext Syncro API keys. Mike's and Howard's live PSA keys were
copy-pasted into three command files, a script, and two catalog docs --
despite both already being vaulted at msp-tools/syncro and
msp-tools/syncro-howard. Replaced with reads from the SOPS vault via a
new sourced helper, .claude/scripts/syncro-env.sh. Write paths fail
closed; read-only paths degrade to skipped enrichment rather than a
wrong key. Per-user mapping is unchanged, so Syncro attribution is too.
2. Hardcoded repo root. wiki-compile/wiki-lint/inject-standards and
gen_b64.py hardcoded D:/claudetools; this machine is C:/claudetools.
syncro.md also read ~/.claude/identity.json before the repo copy -- the
same bug that made remediation-tool's consent-audit report a fully
consented tenant as RED. Root now resolves from the script's own
location, with identity.json claudetools_root as the override.
get-identity.sh had a chicken-and-egg bug: it read ${CLAUDETOOLS_ROOT:-.}
but never set it, so every caller had to already know the root. It now
self-resolves and exports CLAUDETOOLS_ROOT + VAULT_ROOT.
Verified: all three command setup blocks authenticate against live Syncro;
get-identity.sh works from any cwd and honors a pre-set root; gps-rmm
autoenroll resolves its key from the vault. security-review: no findings.
NOTE: both keys remain valid in git history. Rotation in the Syncro portal
is the required follow-up -- this commit does not resolve that exposure.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
46 lines
2.1 KiB
Bash
46 lines
2.1 KiB
Bash
#!/usr/bin/env bash
|
|
# get-identity.sh — Read identity.json and export user/machine vars for attribution
|
|
#
|
|
# Source this at the start of any skill that needs attribution (bot alerts, commits,
|
|
# logs, RMM operations). Exports $USER_NAME, $USER_SHORT, $MACHINE, $USER_EMAIL.
|
|
#
|
|
# Usage:
|
|
# source .claude/scripts/get-identity.sh
|
|
# echo "[RMM] $USER_SHORT deployed to X machines..."
|
|
#
|
|
# Soft-fails: if identity.json is missing, exports "Unknown" values and returns 1
|
|
# (but does NOT exit, so the caller continues). This ensures skills never break on
|
|
# missing identity - they just attribute to "Unknown".
|
|
|
|
# Resolve the repo root from this script's own location (mirrors vault.sh) so callers
|
|
# don't have to know it. An already-set CLAUDETOOLS_ROOT still wins, and identity.json's
|
|
# claudetools_root overrides both. Never hardcode a drive letter.
|
|
if [ -z "${CLAUDETOOLS_ROOT:-}" ]; then
|
|
export CLAUDETOOLS_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
fi
|
|
|
|
IDENTITY_FILE="$CLAUDETOOLS_ROOT/.claude/identity.json"
|
|
|
|
if [ ! -f "$IDENTITY_FILE" ]; then
|
|
echo "[WARNING] identity.json not found at $IDENTITY_FILE - attribution will be 'Unknown'" >&2
|
|
export USER_NAME="Unknown User"
|
|
export USER_SHORT="unknown"
|
|
export MACHINE="unknown-machine"
|
|
export USER_EMAIL="unknown@unknown.com"
|
|
return 1
|
|
fi
|
|
|
|
export USER_NAME=$(jq -r '.full_name // .user // "Unknown"' "$IDENTITY_FILE" 2>/dev/null || echo "Unknown")
|
|
export USER_SHORT=$(jq -r '.user // "unknown"' "$IDENTITY_FILE" 2>/dev/null || echo "unknown")
|
|
export MACHINE=$(jq -r '.machine // "unknown"' "$IDENTITY_FILE" 2>/dev/null || echo "unknown")
|
|
export USER_EMAIL=$(jq -r '.email // "unknown@unknown.com"' "$IDENTITY_FILE" 2>/dev/null || echo "unknown@unknown.com")
|
|
|
|
# identity.json is authoritative for the root and the vault location.
|
|
_root_override=$(jq -r '.claudetools_root // empty' "$IDENTITY_FILE" 2>/dev/null)
|
|
[ -n "$_root_override" ] && [ -d "$_root_override" ] && export CLAUDETOOLS_ROOT="$_root_override"
|
|
export VAULT_ROOT=$(jq -r '.vault_path // empty' "$IDENTITY_FILE" 2>/dev/null)
|
|
unset _root_override
|
|
|
|
# Success
|
|
return 0
|