You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(cli): --registry-password-stdin and --zap-auth-password-stdin (#145)
Closes hardening item #2 from "Secret Handling & Credential Surface
Hardening" in docs/developer/SDK-ROADMAP.md. Two new flags on
`argus scan` let users supply credentials via stdin, mirroring
`docker login --password-stdin`. The value never appears on argv,
in shell history, in argus.yml, or in any persisted argus artifact
(argus-audit.json, argus.log, argus-results.*).
Implementation:
- argus/core/secrets.py: module-level `_STDIN_OVERRIDES` slot
registry with set_stdin_override / get_stdin_override /
clear_stdin_overrides. Slots are stable cross-scanner names
("registry_password", "zap_auth_password") so the same stdin
value can fill the same logical credential across scanners
(e.g., registry password for container + zap), while distinct
credentials (registry vs. ZAP web-app auth) stay in separate
slots.
- argus/cli.py:
--registry-password-stdin → slot: registry_password
--zap-auth-password-stdin → slot: zap_auth_password
New helper _consume_stdin_password_flags(args) runs at the top
of cmd_scan. Errors out cleanly when stdin is a TTY, when more
than one stdin flag is set (stdin is single-stream), or when
stdin is empty. Reads stdin once, strips a single trailing
newline (multi-line tokens preserved for PEM-style payloads),
routes the value into the slot registry.
- argus/scanners/container.py + zap.py: container_env / _build_env
pass `stdin_override=get_stdin_override(slot)` to resolve_secret.
Highest precedence: stdin > _env > literal > None.
Test coverage:
- 5 new tests in argus/tests/core/test_secrets.py::TestStdinOverrideSlots
cover the slot APIs (set/get/clear/isolation/explicit-override-arg).
- 9 new tests in argus/tests/test_cli.py::TestStdinPasswordFlags cover
the CLI helper: no-flag noop, single-flag happy path for both
flags, trailing-newline trim, no-newline preserved, multi-line
preserved, both-flags error, TTY error, empty-stdin error.
Docs + .ai/:
- docs/config-reference.md: new "Third form — CLI stdin" subsection
in the credential-fields section with a precedence table and
worked examples. The validation-rules list now sits below it.
- docs/cli-reference.md: regenerated from cli.py via
scripts/ci/check_cli_docs.py --fix.
- .ai/architecture.yaml: core/secrets.py description updated in both
SDK structure blocks to document the three-form precedence and the
slot registry; explicit note that the stdin path never reaches the
per-scanner config dict.
- docs/developer/SDK-ROADMAP.md: hardening item (2) flipped to
shipped with implementation summary.
Full suite: 3080 passed, 2 skipped.
Co-authored-by: eFAILution <eFAILution@users.noreply.github.com>
"core/sbom.py": "SBOM format detection (CycloneDX JSON/XML, SPDX JSON/tag-value, Syft JSON) for ``argus scan --sbom``"
41
-
"core/secrets.py": "Credential resolution for any scanner config field. resolve_secret(config, field) accepts either <field> (literal, warned at config-load if vendor-shaped via looks_like_literal_secret) or <field>_env (env-var name reference; reads os.environ at scan time). validate_env_var_name enforces POSIX shell identifier rules. Stdlib-only. Used by scanners.container and scanners.zap; future scanners with credential needs use the same helper. See ADR-024."
41
+
"core/secrets.py": "Credential resolution for any scanner config field. resolve_secret(config, field, *, stdin_override=None) accepts three forms in precedence order: stdin_override (highest, populated by CLI --*-password-stdin flags via a module-level slot registry — set_stdin_override / get_stdin_override / clear_stdin_overrides), <field>_env (env-var name reference; reads os.environ at scan time), or <field> literal (back-compat, warned at config-load if vendor-shaped via looks_like_literal_secret). The stdin path never reaches the per-scanner config dict so it can't leak into argus-audit.json / argus.log. validate_env_var_name enforces POSIX shell identifier rules. Stdlib-only. Used by scanners.container and scanners.zap; future scanners with credential needs use the same helper. See ADR-024."
42
42
"core/findings_view.py": "Shared UI-free logic for findings display — ViewState, SEVERITY_ORDER, finding_detail_rows, compute_summary, diff_scans (scan-over-scan bucketing keyed off (scanner, id, location)). Consumed by argus view terminal (TUI ``D`` keybind, DiffScreen) and argus view browser (web UI ``/diff`` route)."
"core/sbom.py": "SBOM format detection (CycloneDX JSON/XML, SPDX JSON/tag-value, Syft JSON) for ``argus scan --sbom``"
474
-
"core/secrets.py": "Credential resolution for any scanner config field. resolve_secret(config, field) accepts either <field> (literal, warned at config-load if vendor-shaped via looks_like_literal_secret) or <field>_env (env-var name reference; reads os.environ at scan time). validate_env_var_name enforces POSIX shell identifier rules. Stdlib-only. Used by scanners.container and scanners.zap; future scanners with credential needs use the same helper. See ADR-024."
474
+
"core/secrets.py": "Credential resolution for any scanner config field. resolve_secret(config, field, *, stdin_override=None) accepts three forms in precedence order: stdin_override (highest, populated by CLI --*-password-stdin flags via a module-level slot registry — set_stdin_override / get_stdin_override / clear_stdin_overrides), <field>_env (env-var name reference; reads os.environ at scan time), or <field> literal (back-compat, warned at config-load if vendor-shaped via looks_like_literal_secret). The stdin path never reaches the per-scanner config dict so it can't leak into argus-audit.json / argus.log. validate_env_var_name enforces POSIX shell identifier rules. Stdlib-only. Used by scanners.container and scanners.zap; future scanners with credential needs use the same helper. See ADR-024."
475
475
"core/findings_view.py": "Shared UI-free logic for findings display — ViewState, SEVERITY_ORDER, finding_detail_rows, compute_summary, diff_scans (scan-over-scan bucketing keyed off (scanner, id, location)). Consumed by argus view terminal (TUI ``D`` keybind, DiffScreen) and argus view browser (web UI ``/diff`` route)."
0 commit comments