fix(review): reject protected-file hardlink aliases - #84
Merged
Conversation
Signed-off-by: Thomas Albrecht <241560317+thequantumfalcon@users.noreply.github.com>
thequantumfalcon
marked this pull request as ready for review
September 5, 2026 04:08
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
A protected regular file could already have a stable external hardlink alias
when an isolated review began. Because the protected manifests compared the
same path metadata before and after review, an alias to a protected but
unexported file such as
.git/configcould remain stable while the reviewerwas launched.
This change adds a narrow single-link validator for protected regular files.
It runs after the pre-export protected-manifest capture, after the post-export
capture, and again after review before accepting output. The first two checks
run before either the negative control or reviewer. The post-review check
fails closed before output acceptance, although its specific cause is wrapped
by the existing postflight error boundary.
protected_manifest()remains observational. Existing path, hash, mode,ownership, export, manifest-comparison, cleanup, DAC, and Seatbelt behavior is
unchanged.
Linked issue
No linked issue. This was prompted by the retained Round-6 isolated-review
finding.
Checklist
just test; noseparate literal
just testinvocation is claimed.just lint; thefocused Ruff invocation-form exception is disclosed below.
just deps;causal_continuity_engine/remains standard-library only.just bench; alleleven scenarios and all six metrics passed.
just corpus; thereference agreed with all 44 committed vectors.
just caps; all23 claims resolved and the generated document remained unchanged.
just buildinvocation was run. It was not runseparately; the canonical aggregate's reproducible-distribution,
structure, and installed-wheel behavior stages passed.
Signed-off-bytrailer.pass. The already-conditional privileged deployment test remains an
explicit not-passed gap, and no release or active-control claim relies
on it.
authorship attribution.
If this is a bug fix
pre-fix public code.
The regression test file was overlaid onto exact public base
68c46336ce168fcca5a6672336abe0b91d9cdb11, treecdd557b6f179e9a093b98398dc00f761c3f109ae, while production.github/scripts/run_isolated_review.pyremained at blobafb3bcb282c584ad2859808d71ebdf3808a86978.The two failures have different meanings:
test_review_refuses_preexisting_external_alias_to_protected_git_file_before_launchis the deciding reproduction. Base production reached
_run_command, whosesentinel raised
AssertionError: reviewer launched. The stable externalalias escaped the unchanged path-manifest comparison.
test_review_rechecks_protected_link_count_after_exportis an attributionfailure, not a second reviewer launch. Base production already failed closed
with
BoundaryError("repository changed while the review snapshot was exported");the test failed because it required attribution to the new
exactly one linkgate.
On candidate
dcce0a7b0216f68b046a6a6d059feeff8e7a09b5:The unchanged adjacent positive confirms that ordinary single-link state still
reaches
_run_command, returns the established review-command failure, andretains the existing five manifest observations.
The complete isolated-review module collected 44 cases and emitted 43 pass
progress dots plus one skip marker, exit 0. The skip was
test_real_seatbelt_denies_child_and_grandchild_when_privileged; it is anexplicit not-passed deployment gap, never success evidence.
Canonical verification
One uninterrupted canonical invocation ran on exact commit
dcce0a7b0216f68b046a6a6d059feeff8e7a09b5, treea90005547e49011b5602519360e12cd4d656beb0:The contemporaneous run record binds immediate child exit 0 to the exact
commit, tree, command, transcript size, and transcript digest.
trusted_timeis false.
All 15 repository-defined stages appeared exactly once and in order. Stage 7
is named
stdlib boundary. The tests-stage transcript emitted 2,249 passprogress dots and 6 skip markers, with zero
Fand zeroE. Pytest emitted nonumeric summary; those counts are progress-character arithmetic.
The gate also established:
partial, with no drift;
Measured distribution SHA-256 values:
0eb420be250e52e404e945d3fddc01fd760f87d4b56411a159511374634f7ea5be2219869a61400aaf887a1c131e97563559878a828090edb03962c5ce3f4469The canonical bootstrap downloaded its hash-locked tool closure from the
public package index. It was not offline, and its local distribution stages do
not establish hosted cross-job artifact handoff.
Ratified preparation deviations and local residue
The prescribed focused command using
python3 -m ruffexited 1 because Ruffwas unavailable as a module in that interpreter. The same pinned Ruff 0.16.1
standalone executable passed, and the canonical hash-locked Ruff 0.16.1 lint
stage independently passed. The literal prescribed command form never passed.
The owner ratified this invocation-form deviation before the branch push.
The preparation brief called canonical stage 7
standard-library boundary;the repository script's actual banner is
stdlib boundary. The intended gateran and passed under its repository-defined name. The owner ratified that
specification mismatch before the branch push.
Focused verification restored a physically clean worktree at that point. The
subsequent canonical gate left 17 ignored outputs under
.github/scripts/__pycache__/,.pytest_cache/,.ruff_cache/, anddist/.They are outside the candidate commit; tracked, staged, and nonignored
candidate state remained clean.
The branch-push audit later added 13 items to retained task scratch despite an
instruction to leave it frozen. They are unmanifested, non-authoritative
process residue and are not evidence. The executor reported that the original
15 items remained unmodified, but no prior digest ledger independently proves
that assertion. The owner ratified this scope exception before authorizing
this draft PR. The old scratch is excluded from this task.
During the stopped first body-construction attempt,
ln -sfncreated orreplaced a temporary pointer outside the task-owned scratch. The next command
observed it pointing only to the current task scratch and removed it before any
PR POST. No pre-state had been captured, so the record does not prove whether
the pointer path was previously absent or whether an earlier symlink was
replaced. This violated the working-file boundary. The owner ratified this
narrow exception before PR creation; literal compliance is not claimed, and
the pointer is not evidence.
The first trusted-template lookup used incorrect filename casing and printed
FAIL. The corrected lookup verified the exact committed lowercase path andblob. This was an instrument error, not repository drift, and the failed lookup
is not relied on as evidence.
Limits and deployment posture
The validator establishes
link_count == 1only at three scan points. It doesnot prove that no alias ever existed and does not prevent a cooperating
unsandboxed process from creating an alias between or after scans. It does not
establish universal confidentiality, kernel sandboxing, protected-path or
inode secrecy, privileged deployment, or release readiness. Legitimately
hardlinked protected files fail closed.
The focused tests monkeypatch platform and security mechanisms and establish
ordering and deciding-path behavior only. They do not exercise a provisioned
root-controlled macOS deployment. The privileged macOS acceptance remains
unrun and skipped, and the local isolated-review launcher remains inactive
until exact installed bytes pass that acceptance. The external hosted App is
also undeployed and inactive.
There is no focused negative dedicated solely to the third, post-review
hardlink check. Its placement was verified statically, and a persistent
post-review mutation remains covered by the generic manifest comparison, but
hardlink-specific attribution at that third call could regress without either
new selector failing. The pre-export and post-export checks pin the
hardlink-specific
exactly one linkresult; post-review failure is wrapped bythe existing generic postflight boundary.
The trust-closure sheet's reference to every acceptance criterion is read
against its revised release-required matrix, not as a claim that the explicitly
deferred privileged deployment criterion passed.
Provenance and preservation
The selected historical content was reconstructed, but no contemporaneous
historical publication commit, author/committer identity, signature, DCO
trailer, patch artifact, or bundle was recovered. The local
unit13-exact.patchis a newly reconstructed evidence artifact.dcce0a7b0216f68b046a6a6d059feeff8e7a09b5is a new owner-authored,owner-signed, DCO-bearing publication candidate.
At PR creation, Unit 13 evidence was not included in the active preservation
manifest; the prior manifest remained 77/77 valid and unchanged. This PR does
not claim Unit 13 preservation closeout or release readiness.
Protected-control authorization
This diff changes a protected control path. The PR-creation request does not
apply a policy label. Its opened-event advisory is expected to report missing
exact-head owner authorization; any different policy outcome must be reported
rather than normalized.
Merge eligibility requires a later, separately authorized owner-generated
labeledevent forcontent-integrity-policy-changeagainst the unchangedexact head, title, and body. This paragraph records the required condition and
does not assert the label's current application state. Any later head, title,
or body change requires a new owner-authorization event.
Unit 14 boundary
At PR creation, Unit 14's branch and PR were absent. The candidate head does
not contain
tests/test_identity_compatibility.py. Unit 14 is not part of thischange, and no Unit 14 implementation or readiness claim is made.