fix(photon): isolate ALL secret-touching prints behind auth.py helpers

CodeQL was still flagging three taint-flow alerts in cli.py — its
flow tracker keeps spreading the 'sensitive' label through every
variable that even touched a credential-returning function, including
'has_token = bool(load_photon_token())' and the redacted-response
dict returned by persist_webhook_signing_secret.

Refactor:

1. cli.py _cmd_status now calls a new auth.credential_summary() that
   returns a {key: pre-formatted display string} dict. All probes +
   bool checks happen inside the helper. cli.py never sees a token
   or secret variable, only literals like '✓ stored' / '✗ missing'.

2. persist_webhook_signing_secret(webhook_data, *, on_summary=print)
   now owns the formatting + writing + status messages. It returns
   only a bool. The redacted-response JSON dump + 'saved to <path>'
   confirmation are emitted via the on_summary callback, so cli.py
   passes  as the sink and never receives the path/dict back.

   cli.py is now mechanical: register_webhook → persist (with print)
   → return 0/1. Zero credential-tainted variables in cli.py at all.

3. Tests updated for the new signatures and a credential_summary
   guard added (the helper must never leak raw token/secret bytes
   into its return strings).

Validation:
  tests/plugins/platforms/photon/ → 25/25 pass
  scripts/check-windows-footguns.py --all → 0 footguns
  py_compile clean
This commit is contained in:
Teknium
2026-06-08 13:38:30 -07:00
parent 91db0ab420
commit 55fb422f6f
3 changed files with 111 additions and 45 deletions
+13 -21
View File
@@ -199,26 +199,20 @@ def _cmd_setup(args: argparse.Namespace) -> int:
def _cmd_status(_args: argparse.Namespace) -> int:
has_token = bool(photon_auth.load_photon_token())
proj_id_raw, proj_secret_raw = photon_auth.load_project_credentials()
has_project_id = bool(proj_id_raw)
has_project_secret = bool(proj_secret_raw)
project_id_display = proj_id_raw if has_project_id else "✗ missing"
summary = photon_auth.credential_summary()
node_bin = os.getenv("PHOTON_NODE_BIN") or shutil.which("node")
sidecar_installed = (_SIDECAR_DIR / "node_modules").exists()
has_webhook_secret = bool(os.getenv("PHOTON_WEBHOOK_SECRET"))
# All values are pre-formatted display strings from auth.credential_summary;
# no secret-bearing variable enters this function's scope.
print("Photon iMessage status")
print("──────────────────────")
print(f" device token : {'✓ stored' if has_token else '✗ missing (run `hermes photon login`)'}")
print(f" project id : {project_id_display}")
# Label intentionally avoids the word "secret" so static taint
# analyzers don't flag the literal "✓ stored" / "✗ missing" string
# as sensitive-data exposure.
print(f" project key : {'✓ stored' if has_project_secret else '✗ missing'}")
print(f" device token : {summary['device_token']}")
print(f" project id : {summary['project_id']}")
print(f" project key : {summary['project_key']}")
print(f" node binary : {node_bin or '✗ missing (install Node 18+)'}")
print(f" sidecar deps : {'✓ installed' if sidecar_installed else '✗ run `hermes photon install-sidecar`'}")
print(f" webhook key : {'✓ set' if has_webhook_secret else '⚠ unset — verification disabled'}")
print(f" webhook key : {summary['webhook_key']}")
return 0
@@ -265,11 +259,12 @@ def _cmd_webhook(args: argparse.Namespace) -> int:
except Exception as e:
print(f"register failed: {e}", file=sys.stderr)
return 1
# Hand the raw response straight to the persistence helper —
# the signing-secret value never gets bound to a local here.
wrote, redacted = photon_auth.persist_webhook_signing_secret(data)
print(json.dumps(redacted, indent=2))
if wrote is None:
# The helper does all the formatting + writing; cli.py never
# touches the signing-secret value, the path it was written
# to, or even the redacted-response dict. on_summary is a
# plain printer callback.
ok = photon_auth.persist_webhook_signing_secret(data, on_summary=print)
if not ok:
print(
"‼ Photon returned no signing secret in the response, "
"or the file write failed. Inspect your home directory "
@@ -278,9 +273,6 @@ def _cmd_webhook(args: argparse.Namespace) -> int:
file=sys.stderr,
)
return 1
print()
print(f"✓ Wrote PHOTON_WEBHOOK_SECRET to {wrote}")
print(" (Photon only returns this once — keep the .env file safe)")
return 0
if sub == "list":