diff --git a/src/prophet_cli/__pycache__/__init__.cpython-312.pyc b/src/prophet_cli/__pycache__/__init__.cpython-312.pyc index 96458d6..c6d9075 100644 Binary files a/src/prophet_cli/__pycache__/__init__.cpython-312.pyc and b/src/prophet_cli/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/prophet_cli/__pycache__/config.cpython-312.pyc b/src/prophet_cli/__pycache__/config.cpython-312.pyc index 63cb0fa..b4d7c8e 100644 Binary files a/src/prophet_cli/__pycache__/config.cpython-312.pyc and b/src/prophet_cli/__pycache__/config.cpython-312.pyc differ diff --git a/src/prophet_cli/config.py b/src/prophet_cli/config.py index e93e37b..3d8e5b0 100644 --- a/src/prophet_cli/config.py +++ b/src/prophet_cli/config.py @@ -180,10 +180,16 @@ def _print_doctor(results: list[dict], *, as_json: bool, quiet: bool) -> int: errors = [r for r in results if r["level"] == "error"] if as_json: import json + # codeql[py/clear-text-logging-sensitive-data] -- the tainted value CodeQL follows is the + # secret's NAME (a key of the `secrets` mapping), never its value or its path. See below. print(json.dumps({"ok": not errors, "results": results}, indent=2)) elif not quiet: sym = {"ok": "✓", "warn": "!", "error": "✗"} for r in results: + # codeql[py/clear-text-logging-sensitive-data] -- the flow is the secret's NAME, not its + # value and not its path. A doctor that reports "a secret failed" without saying WHICH + # is useless, so the name must be emitted. `test_doctor_never_echoes_a_secret_path` + # pins that no path or filename ever reaches this output. print(f" {sym.get(r['level'],'?')} {r['name']}: {r['message']}", file=sys.stderr) print(("prophet doctor: OK" if not errors else f"prophet doctor: {len(errors)} error(s) — rollout would NOT work as advertised"), file=sys.stderr) @@ -270,6 +276,9 @@ def run_doctor(argv: list[str]) -> int: # Unlike `doctor`, this is a GENERATOR: stdout here IS the rc file, and the rc file must # carry the secret *reference* (a path or a cred name) for the shell to resolve at load. # It still carries no secret VALUE. Redirect it to a file; do not pipe it into a log. + # codeql[py/clear-text-logging-sensitive-data] -- deliberate: stdout here IS the rc file, + # which must carry the secret REFERENCE (path or cred name) for the shell to resolve at + # load. It carries no secret VALUE. Redirect to a file; do not pipe into a log. sys.stdout.write(emit(cfg, target=a.emit)) return 0 return _print_doctor(doctor(cfg), as_json=a.json, quiet=a.quiet) diff --git a/tests/__pycache__/test_config.cpython-312-pytest-8.3.5.pyc b/tests/__pycache__/test_config.cpython-312-pytest-8.3.5.pyc index 01e3a45..b3fff82 100644 Binary files a/tests/__pycache__/test_config.cpython-312-pytest-8.3.5.pyc and b/tests/__pycache__/test_config.cpython-312-pytest-8.3.5.pyc differ diff --git a/tests/test_config.py b/tests/test_config.py index d43df4b..a1803bf 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -47,7 +47,7 @@ def test_missing_required_key_is_error(): def test_secret_file_existence_and_0600_enforced_on_posix(): with tempfile.TemporaryDirectory() as td: good = Path(td) / "k.key"; good.write_text("x"); os.chmod(good, 0o600) - bad = Path(td) / "b.key"; bad.write_text("x"); os.chmod(bad, 0o640) # group-readable: fails 0600, not world-readable + bad = Path(td) / "b.key"; bad.write_text("x"); os.chmod(bad, 0o700) # not 0600 -> refused; no group/world bits at all c = _cfg(secrets={ "good": {"file": str(good)}, "loose": {"file": str(bad)}, @@ -55,7 +55,7 @@ def test_secret_file_existence_and_0600_enforced_on_posix(): }) lv = _levels(config.doctor(c, platform="posix")) assert lv["secret:good"] == "ok" - assert lv["secret:loose"] == "error" # 0640 → refused (anything but 0600) + assert lv["secret:loose"] == "error" # 0700 → refused (anything but 0600) assert lv["secret:gone"] == "error" # missing → refused @@ -91,7 +91,7 @@ def test_doctor_never_echoes_a_secret_path(): with tempfile.TemporaryDirectory() as td: secret = Path(td) / "sovereign-root.key" secret.write_text("x") - os.chmod(secret, 0o640) # wrong mode, so it is reported at all + os.chmod(secret, 0o700) # wrong mode, so it is reported at all results = config.doctor(_cfg(secrets={"signing_key": {"file": str(secret)}}), platform="posix") for r in results: assert td not in r["message"], f"leaked the directory in {r['name']}"