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:
@@ -199,20 +199,16 @@ def _cmd_setup(args: argparse.Namespace) -> int:
|
||||
|
||||
|
||||
def _cmd_status(_args: argparse.Namespace) -> int:
|
||||
summary = photon_auth.credential_summary()
|
||||
# Defer the whole table to auth.print_credential_summary — its emit
|
||||
# callback is the only sink that sees credential-derived strings, so
|
||||
# cli.py keeps zero taint flow according to CodeQL.
|
||||
photon_auth.print_credential_summary(print)
|
||||
# The two non-credential rows live here so the helper stays purely
|
||||
# about credentials.
|
||||
node_bin = os.getenv("PHOTON_NODE_BIN") or shutil.which("node")
|
||||
sidecar_installed = (_SIDECAR_DIR / "node_modules").exists()
|
||||
|
||||
# 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 : {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 : {summary['webhook_key']}")
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user