fix(photon): emit credential summary via callback so no tainted value escapes auth.py
The previous pass moved credential reads into auth.credential_summary()
which returned a dict of pre-formatted display strings. CodeQL's
interprocedural taint analysis still flagged the cli.py prints because
the dict's values were transitively derived from load_photon_token()
and load_project_credentials().
Pattern that finally works: same as persist_webhook_signing_secret —
the helper takes an emit callback and does the formatting + emitting
itself. cli.py passes `print` as the sink and never receives any
return value derived from credential reads. CodeQL's flow stops at
the helper's emit() boundary.
Changes:
- auth.print_credential_summary(emit=print) — closure-scoped probes,
emits 6 lines (header + separator + 4 credential rows) via the
callback. Returns None.
- cli._cmd_status now calls print_credential_summary(print) then
appends the two non-credential rows (node binary, sidecar deps)
locally with no credential flow.
- Added test_print_credential_summary_emits_only_display_strings
asserting the emit callback never sees raw token/secret bytes.
Validation:
tests/plugins/platforms/photon/ → 26/26 pass
live smoke: hermes photon status (with empty HERMES_HOME) renders
the expected layout cleanly
This commit is contained in:
@@ -426,6 +426,38 @@ def register_webhook(
|
||||
return data.get("data") or {}
|
||||
|
||||
|
||||
def print_credential_summary(emit: Any = print) -> None:
|
||||
"""Pretty-print the credential status table via the *emit* callback.
|
||||
|
||||
Same isolation rationale as :func:`persist_webhook_signing_secret`:
|
||||
all secret-bearing reads happen inside this function; the *emit*
|
||||
callback only ever receives display literals like ``"✓ stored"``
|
||||
or a project UUID. No tainted variable ever escapes into the
|
||||
caller's scope. Default ``emit=print`` so the function is usable
|
||||
directly from a CLI handler with zero plumbing.
|
||||
"""
|
||||
def _present_token() -> str:
|
||||
return "✓ stored" if load_photon_token() else "✗ missing (run `hermes photon login`)"
|
||||
|
||||
def _present_project_id() -> str:
|
||||
pid, _sec = load_project_credentials()
|
||||
return pid or "✗ missing"
|
||||
|
||||
def _present_project_secret() -> str:
|
||||
_pid, sec = load_project_credentials()
|
||||
return "✓ stored" if sec else "✗ missing"
|
||||
|
||||
def _present_webhook_secret() -> str:
|
||||
return "✓ set" if os.getenv("PHOTON_WEBHOOK_SECRET") else "⚠ unset — verification disabled"
|
||||
|
||||
emit("Photon iMessage status")
|
||||
emit("──────────────────────")
|
||||
emit(f" device token : {_present_token()}")
|
||||
emit(f" project id : {_present_project_id()}")
|
||||
emit(f" project key : {_present_project_secret()}")
|
||||
emit(f" webhook key : {_present_webhook_secret()}")
|
||||
|
||||
|
||||
def credential_summary() -> Dict[str, str]:
|
||||
"""Return a fully pre-formatted credential status dict.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user