Skip to content

export-safety: scope history mode to the local clone and add a triage note - #71

Merged
sumitake merged 1 commit into
mainfrom
dev/claude/export-safety-history-clone-scope
Jul 28, 2026
Merged

export-safety: scope history mode to the local clone and add a triage note#71
sumitake merged 1 commit into
mainfrom
dev/claude/export-safety-history-clone-scope

Conversation

@sumitake

Copy link
Copy Markdown
Owner

Summary

--history walks every ref reachable in the local clone, not live remote state. A clone that retains pre-rewrite refs therefore fails the gate even when the canonical remote is clean.

Four contributor-facing surfaces instructed running the gate locally and, on failure, escalating under SECURITY.md — with no warning about that scope. A contributor on a pre-rewrite clone was steered into filing a false private security advisory. This documents the scope rule and adds an advisory triage note to the gate itself.

Investigation detail (this repository's published history is not implicated): a disposable full clone of the canonical remote passes --active-tree --history at the snapshot checked (origin/main 6c3073e, tags v4.2.0–v4.5.1), and release run 30212936289 logged RESULT: SAFE FOR REQUESTED PUBLIC EXPORT CHECKS. Per the wording rule this PR adds, that is evidence about the recorded snapshot only — not clearance of any failing clone.

Boundary declaration

  • No provider executor source, raw provider command, credential, private absolute path, retired package tree, downloader, or post-install hook is included.
  • Native-runtime changes, if any, contain only a final signed artifact and reviewed public verification metadata; implementation and credentials remain private.
  • The change does not create a host-specific preset or provider-specific plugin.

The new test deliberately reuses the already-allowlisted codex_exec.py literal rather than embedding a fresh credential pattern, so HARMLESS_AUDIT_LITERALS is not widened.

Generated and release surfaces

  • Skill specs and generated SKILL.md files are in parity.
  • Claude and Codex marketplaces/manifests are in parity.
  • A unique changelog.d/ fragment is present; generated CHANGELOG.md untouched.
  • Version metadata unchanged — no distributed plugin content or behavior changes.

Verification

  • python3 scripts/build_skills.py --check — OK
  • python3 scripts/build_marketplace.py --check — OK
  • python3 scripts/build-changelog.py --dry-run — OK (fragment-only; CHANGELOG.md not written)
  • python3 -m unittest discover -s tests -t . -v — 588 tests; 9 new all pass. One pre-existing environmental failure, test_host_metadata_and_homelab_labels_are_not_distributed, caused by a gitignored local .claude-session-owner session artifact; the same test passes on unmodified origin/main in a clean clone, so it cannot occur in CI.
  • python3 -m unittest discover -s scripts -p 'test_*.py' -v — 254 tests, OK
  • python3 scripts/check_release_consistency.py — OK
  • python3 scripts/secret_scan.py — clean, 324 files
  • python3 scripts/check-public-export-safety.py --active-tree --history — active tree SAFE; history fails in this pre-rewrite clone as designed, now with the note, exit 1, all 1551 FAIL lines intact, RESULT: last
  • git diff --check — clean

Design notes

Rejected: a --remote flag scoping the walk. Narrowing a security gate's scope is itself a laundering vector.

Chosen: a purely additive diagnostic. No violation suppressed, filtered, reordered, or downgraded; exit code untouched; RESULT: remains the last line; no network; bounded git timeouts; fail-safe to silence.

Two reviewer-driven properties are load-bearing:

  1. Gated on a clean active tree. An active-tree violation is present-state contamination; a lineage note beside it would reassure an operator out of escalating. The note requires both modes run, an empty active set, and a non-empty history set. Regression-tested.
  2. Non-exculpatory wording. The signal is clone topology, which carries no provenance. The note names current-candidate contamination alongside the benign explanation, states it identifies no FAIL line and clears no remote, and warns the output is unsafe to paste publicly. multiple_roots was dropped as a trigger because every root can still be remote-reachable, which would make the note assert something false.

Review and post-condition

Tier 3 (governance gate). Independent cross-family adversarial plan review before codegen, per the standing directive for bypass-prone surfaces.

Codex (OpenAI family), two rounds, converged:

  • Round 1 — PROCEED WITH CHANGES. Load-bearing: a real credential in the active tree plus one unpushed commit would fire the note and reassure the operator. Also: exculpatory wording, "does not change the result above" factually wrong (RESULT: prints below), unbounded git calls breaking the fail-safe claim, exact counts leaking private-work size, and an over-strong "the public repo is clean" claim needing snapshot scoping.
  • Round 2 — PROCEED WITH CHANGES. Load-bearing: drop multiple_roots as a trigger; balance the message with current-candidate contamination. Confirmed the documentation wording is now safe against suppressing a genuine escalation.

All required changes integrated. Round 2's accepted residual false-silence (annotated-tag/blob-ref violations that create no commit outside remote reachability) is safety-preserving — the verdict stays UNSAFE — and is deliberately not papered over with a provenance heuristic.

Post-condition: main CI green on validate-frontmatter, smoke-test, consistency, scan, unittest, validate-trace; the gate's behavior on a clean clone is unchanged (verified: still exits 0 with no note).

Compliance trace

author: Claude (Anthropic family, Opus 5)
standing_directives: public source/release boundary and full AGENTS.md validation suite; adversarial cross-family plan review before codegen on a bypass-prone surface; fragment-only changelog with no version bump
tier: 3
cross_check: PROCEED WITH CHANGES - Codex (OpenAI family), 2 rounds, converged; every required change integrated
post_condition: required CI green on main; clean-clone gate behavior unchanged (exit 0, no note); note verified to fire only with a clean active tree
mcp_coverage_gap: NONE
contributor_rights: OWNER-AUTHORED
operator_reserved: yes

operator_reserved: yesAGENTS.md matches a specific operator-only CODEOWNERS rule. The operator granted explicit merge pre-authorization for this change in-session; recording the reservation truthfully rather than marking the PR unreserved.

… note

History mode walks every ref in the local clone, so a clone retaining
pre-rewrite refs fails the gate even when the canonical remote is clean.
Four contributor-facing surfaces instructed running the gate locally and
escalating under SECURITY.md on failure with no warning about that scope,
steering contributors on a stale clone into a false private advisory.

Document the scope rule and add an advisory triage note. The note is purely
additive: no violation is suppressed, the exit code and the RESULT line are
unchanged, no network call is made, and no ref names or counts are emitted.
It stays silent whenever the active tree is contaminated, so present-state
findings are never accompanied by a reassuring signal, and its wording names
current-candidate contamination alongside the benign explanation rather than
clearing any remote.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sumitake
sumitake merged commit 274053e into main Jul 28, 2026
15 checks passed
@sumitake
sumitake deleted the dev/claude/export-safety-history-clone-scope branch July 28, 2026 07:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant