Skip to content

fix(review): reject protected-file hardlink aliases - #84

Merged
thequantumfalcon merged 1 commit into
mainfrom
fix/r06-protected-hardlinks
Sep 5, 2026
Merged

fix(review): reject protected-file hardlink aliases#84
thequantumfalcon merged 1 commit into
mainfrom
fix/r06-protected-hardlinks

Conversation

@thequantumfalcon

Copy link
Copy Markdown
Owner

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/config could remain stable while the reviewer
was 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

  • The PR title is a Conventional Commit.
  • The canonical aggregate ran the direct equivalent of just test; no
    separate literal just test invocation is claimed.
  • The canonical aggregate ran the direct equivalent of just lint; the
    focused Ruff invocation-form exception is disclosed below.
  • The canonical aggregate ran the direct equivalent of just deps;
    causal_continuity_engine/ remains standard-library only.
  • The canonical aggregate ran the direct equivalent of just bench; all
    eleven scenarios and all six metrics passed.
  • The canonical aggregate ran the direct equivalent of just corpus; the
    reference agreed with all 44 committed vectors.
  • The canonical aggregate ran the direct equivalent of just caps; all
    23 claims resolved and the generated document remained unchanged.
  • A separate literal just build invocation was run. It was not run
    separately; the canonical aggregate's reproducible-distribution,
    structure, and installed-wheel behavior stages passed.
  • The sole commit carries exactly one owner Signed-off-by trailer.
  • No executable gate was weakened or made newly conditional to make a test
    pass. The already-conditional privileged deployment test remains an
    explicit not-passed gap, and no release or active-control claim relies
    on it.
  • The diff, commit metadata, and this title/body contain no prohibited
    authorship attribution.

If this is a bug fix

  • A regression test pins the defect and was verified to fail against exact
    pre-fix public code.

The regression test file was overlaid onto exact public base
68c46336ce168fcca5a6672336abe0b91d9cdb11, tree
cdd557b6f179e9a093b98398dc00f761c3f109ae, while production
.github/scripts/run_isolated_review.py remained at blob
afb3bcb282c584ad2859808d71ebdf3808a86978.

$ python3 -W error -m pytest -p no:cacheprovider -q \
    tests/test_isolated_review.py::test_review_refuses_preexisting_external_alias_to_protected_git_file_before_launch \
    tests/test_isolated_review.py::test_review_rechecks_protected_link_count_after_export
FF                                                                       [100%]
exit 1

The two failures have different meanings:

  • test_review_refuses_preexisting_external_alias_to_protected_git_file_before_launch
    is the deciding reproduction. Base production reached _run_command, whose
    sentinel raised AssertionError: reviewer launched. The stable external
    alias escaped the unchanged path-manifest comparison.
  • test_review_rechecks_protected_link_count_after_export is an attribution
    failure, 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 link
    gate.

On candidate dcce0a7b0216f68b046a6a6d059feeff8e7a09b5:

$ python3 -W error -m pytest -p no:cacheprovider -q \
    tests/test_isolated_review.py::test_review_refuses_preexisting_external_alias_to_protected_git_file_before_launch \
    tests/test_isolated_review.py::test_review_rechecks_protected_link_count_after_export \
    tests/test_isolated_review.py::test_postflight_runs_even_when_review_command_fails
...                                                                      [100%]
exit 0

The unchanged adjacent positive confirms that ordinary single-link state still
reaches _run_command, returns the established review-command failure, and
retains 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 an
explicit not-passed deployment gap, never success evidence.

Canonical verification

One uninterrupted canonical invocation ran on exact commit
dcce0a7b0216f68b046a6a6d059feeff8e7a09b5, tree
a90005547e49011b5602519360e12cd4d656beb0:

$ python3 .github/scripts/bootstrap_tools.py --release

The contemporaneous run record binds immediate child exit 0 to the exact
commit, tree, command, transcript size, and transcript digest. trusted_time
is 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 pass
progress dots and 6 skip markers, with zero F and zero E. Pytest emitted no
numeric summary; those counts are progress-character arithmetic.

The gate also established:

  • 197 Git blobs scanned;
  • locked Ruff 0.16.1 lint success;
  • the standard-library boundary remained clean;
  • all 11 benchmark families and all 6 metrics passed;
  • the reference agreed with all 44 committed corpus vectors;
  • 23 capability claims resolved as 18 implemented, 2 out of scope, and 3
    partial, with no drift;
  • reproducible distributions;
  • non-executing distribution-structure verification;
  • installed-wheel behavior verification;
  • clean tracked source before and after release.

Measured distribution SHA-256 values:

  • wheel: 0eb420be250e52e404e945d3fddc01fd760f87d4b56411a159511374634f7ea5
  • sdist: be2219869a61400aaf887a1c131e97563559878a828090edb03962c5ce3f4469

The 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 ruff exited 1 because Ruff
was 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 gate
ran 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/, and dist/.
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 -sfn created or
replaced 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 and
blob. 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 == 1 only at three scan points. It does
not 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 link result; post-review failure is wrapped by
the 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.patch is a newly reconstructed evidence artifact.
dcce0a7b0216f68b046a6a6d059feeff8e7a09b5 is 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
labeled event for content-integrity-policy-change against the unchanged
exact 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 this
change, and no Unit 14 implementation or readiness claim is made.

Signed-off-by: Thomas Albrecht <241560317+thequantumfalcon@users.noreply.github.com>
@thequantumfalcon thequantumfalcon added the content-integrity-policy-change Owner authorization for exact-head changes to protected integrity controls. label Sep 5, 2026
@thequantumfalcon
thequantumfalcon marked this pull request as ready for review September 5, 2026 04:08
@thequantumfalcon
thequantumfalcon merged commit 44dd338 into main Sep 5, 2026
16 of 17 checks passed
@thequantumfalcon
thequantumfalcon deleted the fix/r06-protected-hardlinks branch September 5, 2026 04:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

content-integrity-policy-change Owner authorization for exact-head changes to protected integrity controls.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant