Skip to content

S6: retain secret denials across diagnostic exemptions - #960

Closed
seathatflowsinourveins wants to merge 3 commits into
mainfrom
codex/ns2604-s6-secret-path-guard-20261010
Closed

seathatflowsinourveins wants to merge 3 commits into
mainfrom
codex/ns2604-s6-secret-path-guard-20261010

Conversation

@seathatflowsinourveins

@seathatflowsinourveins seathatflowsinourveins commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator

Scope

This PR corrects secret-guard diagnostic false positives while retaining the existing denials. jq's recognized FILTER can mention the input member .env, but the exemption retains refusal when that program executes env/$ENV. Actual input files, file-taking options and redirections still use the original dotenv/store checks. Standalone single-TMPDIR and exact clearing-only env diagnostics are admitted; xargs provenance is copied through both shell/eval readings so replacement or appended operands cannot use those exceptions. Both after-source predicates conservatively refuse printenv after a credential file is sourced.

  • Base commit: a30c2188e4423f05a7448e5f7a3bcfd858e0f5b8 (main when this slice began).
  • Lane: lane:shared; both client lanes use the guard, and existing shared file evidence is updated. Other-lane acknowledgement remains a landing gate.
  • Owned paths: scripts/hooks/secret_path_guard.py, tests/test_secret_path_guard.py, adoption/hooks/claude/SHA256SUMS, docs/decisions/2026-10-08-guard-hook-fails-closed.md, and four existing hash/length rows in manifests/evidence.json.
  • Reviewed correction head: b97522c8c701e1035a1ef32e316438903def7d0c, exactly one forward commit after 6a9d9f20; tested tree f9c1f9fb38f148e82c7d31ff331a6d7a0bd5855b. Guard anchors: recursive current expansion at :1618/:1686, jq lexical/exemption checks at :1958/:2015, after-source checks at :2115/:2539, prior recursion at :2422.
  • The two decision locators now name full main commit a30c2188e4423f05a7448e5f7a3bcfd858e0f5b8 with their verified original line ranges. No heredoc body is exempted and no host hook is deployed by this PR.

SOTA sources

  • Installed GNU findutils 4.10.0, /usr/share/man/man1/xargs.1.gz:16-25 and :136-145: xargs appends stdin items after initial arguments, while -I replaces occurrences anywhere in the initial arguments, including a shell's program string. The guard copies recognized xargs provenance through current and prior shell/eval recursion and current substitution readings, then retains the ordinary diagnostic refusal. Independent outer command segments receive separate state.
  • Installed jq 1.8.1, /usr/share/man/man1/jq.1.gz:2235-2239, defines $ENV as the starting environment and env as the current environment. jqlang/jq jq-1.8.1, src/lexer.l:41-46,99-133 distinguishes comments, strings/interpolation, identifiers, FIELD tokens and bindings. The budgeted lexical check examines executable regions, including interpolation; ordinary .env members, literal strings and object keys stay distinct.
  • jqlang/jq jq-1.8.1, src/main.c: jq [options] <jq filter> [file...] and its file-option branches distinguish FILTER from filenames. Only the recognized filter's original argument position is removed from the dotenv read; unknown option shapes retain the conservative reading. There is no JSON-filename exception.
  • Installed GNU Bash 5.3.9, /usr/share/man/man1/bash.1.gz:5917-5923 and :9016-9020: prefix assignments form the child command's environment and source executes in the current shell. A TMPDIR operand cannot establish a non-secret value after a credential source; both after-source predicates retain their original conservative printenv refusal independently of the standalone exception.
  • Installed uutils/coreutils 0.10.0, printenv.rs and env.rs define per-name printenv output and removal of inherited variables for exact clearing-only env. Input redirections, commands/assignments, xargs-controlled diagnostics and after-source printenv receive no standalone exception.
  • env-cmd 10.1.0, README, Supported file formats lists .env.json as environment key/value JSON. Those filenames continue to match the guard's unchanged dotenv matcher.

Evidence-class table

Claim Evidence class Command / receipt
All nine micro findings deny through both public interfaces after failing first synthetic Six recursive xargs, two jq environment-program and one sourced-TMPDIR text each failed guard.check and JSON-hook denial assertions before its repair (18 failures). Exact reviewed-source replay confirms nine old allows per interface and nine final denials per interface. No payload command was executed.
Intended ordinary diagnostics remain allowed synthetic Separate .env member, literal/string/object-key and standalone TMPDIR tests; 20 revised S6 methods pass.
Guard/installer corpus passes local_integration CI=true python3 -B -m unittest tests.test_secret_path_guard tests.test_install_claude_profile: 226 tests, four existing skips, rc 0. Installer tests use temporary homes.
Registered integrity and scope checks pass in FULL local_integration python3 scripts/validate.py: rc 0, 11,331 hashes, 70 components, four profiles, 239 receipts; current tooling-derived hashes/byte lengths.
PR-range scan contains no credential findings local_integration gitleaks 8.30.1 on explicit a30c2188e4423f05a7448e5f7a3bcfd858e0f5b8..HEAD: three commits, no leaks, rc 0; no full-history scan.
Mechanisms follow installed command semantics source_review The installed manuals and pinned jq/uutils/env-cmd source above; historical doc locators verified with the cited main source.

Local commands run

python3 -B -m unittest tests.test_secret_path_guard.S6FalsePositiveTests.test_gpt_micro_xargs_replacement_retains_recursive_diagnostic_denials
# Before repair: rc 1, six texts fail both public interfaces (12 failures).
# After repair: rc 0.
python3 -B -m unittest tests.test_secret_path_guard.S6FalsePositiveTests.test_gpt_micro_jq_environment_program_never_gets_filter_exemption tests.test_secret_path_guard.S6FalsePositiveTests.test_jq_input_member_env_stays_distinct_from_environment_primitives
# Before repair: rc 1, two environment programs fail both interfaces (four failures); literal/member controls pass.
# After repair: rc 0.
python3 -B -m unittest tests.test_secret_path_guard.S6FalsePositiveTests.test_gpt_micro_sourced_credential_retains_conservative_printenv_denial tests.test_secret_path_guard.S6FalsePositiveTests.test_standalone_tmpdir_diagnostic_stays_allowed_without_credential_source
# Before repair: rc 1, sourced-TMPDIR fails both interfaces (two failures); ordinary diagnostics pass.
# After repair: rc 0.
python3 -B -m unittest tests.test_secret_path_guard.S6FalsePositiveTests
# Complete revised set: 20 test methods pass, rc 0.
CI=true python3 -B -m unittest tests.test_secret_path_guard tests.test_install_claude_profile
# Complete modules: 226 tests, four existing skips, rc 0.
python3 scripts/validate.py
# FULL mode; no --failed.
# rc 0: 11,331 hashes, 70 components, four profiles, 239 receipts.
gitleaks git --log-opts=a30c2188e4423f05a7448e5f7a3bcfd858e0f5b8..HEAD --redact --no-banner
# Explicit PR range only; no full history or --all.
# Three commits, no leaks, rc 0.
git diff --check
# rc 0.

The exact reviewed 6a9d9f20 source was loaded from Git into an in-memory classifier and ephemeral JSON-hook snapshot: all nine reported texts allowed through both interfaces there, then denied through both final interfaces. The snapshot was removed. Command strings remained data throughout; no credential/environment payload was created or executed.

CI=true uses existing skip rules while deployment awaits review: host-copy equality, two scratch mutation adapters without their driver, and the installer context-mode test requiring its configured security module. No new skip was added. Main's pre-existing bare jq environment/indirect-expansion/uninventoried-name gaps remain the separately directed follow-up; the lexical rejection preserves refusals that the filter exemption would otherwise remove.

Decision record

~/.local/state/native-agent-stack/research/harness-rules-20261010/S6-GPT-MICRO-FIX2-20261010.md records primary-source verification, all nine failing-first cases, corrected scope/provenance, tooling-derived evidence rows, final gates and ONE exact-leased forward repair. Any subsequent demonstrated credential exposure requires another source-backed regression before its correction.

Host evidence

No host default or live guard is changed. Hook rollout remains CC-owned after the required exact-head reads and landing.

Checklist

  • No workflow/permission/dependency/billing changes.
  • No credentials printed, read or copied; no credential payloads executed.
  • Peer-owned state and protected lanes preserved.
  • Every reported command has failing-first denial coverage through both public interfaces.
  • Intended diagnostic allows remain covered; full corpus and FULL validation required before publication.
  • Designated renewed GPT/CC reads, other-lane acknowledgement and complete current-head CI remain CC-owned landing gates.

@seathatflowsinourveins seathatflowsinourveins added the lane:shared Touches files owned by both lanes; needs both lanes' acknowledgement label Oct 10, 2026
@seathatflowsinourveins seathatflowsinourveins changed the title S6: fix secret guard false positives for jq JSON, TMPDIR and empty env S6: distinguish jq filters and preserve diagnostic secret denials Oct 10, 2026
@seathatflowsinourveins seathatflowsinourveins changed the title S6: distinguish jq filters and preserve diagnostic secret denials S6: retain secret denials across diagnostic exemptions Oct 10, 2026
@seathatflowsinourveins

Copy link
Copy Markdown
Collaborator Author

Closing on the converged evidence (CC, 2026-10-10): three review rounds found 13 secret-read bypasses in the relaxed guard rules (9 verified as regressions at b97522c), against three minor false positives that already have workarounds. Main's guard stays as it is. Record: the CC owner brief of 2026-10-10 09:45 ET (research-cc-role-20261008/owner-brief-20261010-0945ET.md).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lane:shared Touches files owned by both lanes; needs both lanes' acknowledgement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant