fix(launchpad): scope tracked-sensitive-files to what the cohort owns - #1983
fix(launchpad): scope tracked-sensitive-files to what the cohort owns#1983tucktuck101 wants to merge 2 commits into
Conversation
`audit` failed on `launchpad` trunk, and therefore on every branch cut after
2026-08-28, over six files nobody here wrote.
The check is not wrong about them. Four of the six genuinely contain private key
material:
apns-test-cert-only.pem CERTIFICATE
apns-test-encrypted-identity.pem ENCRYPTED PRIVATE KEY, CERTIFICATE
apns-test-identity.pem PRIVATE KEY, CERTIFICATE
apns-test-key-only.pem PRIVATE KEY
apns-test-mismatched-identity.pem PRIVATE KEY, CERTIFICATE
apple-app-attestation-root.pem CERTIFICATE
They arrived in `c432a111c` ("feat(mobile): push notifications MVP (block#6269)"),
which is an ancestor of `block/buzz@main`, and they are byte-for-byte identical
here. They are APNs test fixtures in upstream's public repository. This fork
operates the upstream product rather than developing it: it cannot fix them, and
it does not move or rename upstream paths.
So this narrows by OWNERSHIP, not by exemption. An allowlist would be a standing
hole, and this check deliberately has none — a suffix exemption was removed after
one let a tracked `seed/authorized_keys.example` through, which is the shape #68
documents a real past incident for. Adding the mechanism back for these six would
undo that.
IDENTITY, NOT ORIGIN. `security_audit_classifier.classify` already answered "did
this path exist upstream", and that is not enough: an inherited filename is
exactly where cohort-added key material could hide. `divergence()` compares blob
OIDs and returns one of `fork-added`, `inherited-modified`, `inherited-identical`
or `indeterminate`. Only `inherited-identical` licenses a skip; the other three
are cohort-accountable or unknown.
The OID comes from the same single `git fetch` the classifier already performed —
`git ls-tree` without `--name-only` is one column wider and costs no extra
network. `fetch_upstream_paths` and `classify` are untouched, so this is additive.
It is also the classifier's first caller: it was built for #62 and never wired.
Unreachable upstream reports INDETERMINATE, naming the paths — neither PASS nor
FAIL is honest when ownership cannot be established, and INDETERMINATE is visibly
not-green so it cannot be mistaken for clean. Upstream-identical hits are named
in the PASS detail: a skip nobody can see is indistinguishable from a check that
stopped looking.
The pre-existing controls now patch the upstream fetch rather than reaching the
network to decide something their own fixtures already know. Four controls added:
upstream-identical does not fail and is named; a cohort-added key still fails
alongside upstream fixtures; an inherited path modified here still fails;
unreachable upstream is INDETERMINATE, not PASS.
Verified against this repository:
status : pass
detail : no cohort-owned tracked file matches a sensitive shape (5718 tracked
files checked); 6 sensitive-shaped file(s) are byte-for-byte
upstream's and not cohort-owned: crates/buzz-push-gateway/tests/
fixtures/apns-test-cert-only.pem; ... apple-app-attestation-root.pem
Tests: 88 security-audit tests pass (14 in this check's own suite, 4 new).
Closes #1965
Signed-off-by: tucktuck101 <jeffreytaylorrobertson@gmail.com>
There was a problem hiding this comment.
Reviewed commit 4b6570ffa46e9407e4d3327dfae6f3eff7c018c7 against merge base 1ed55e980b0043f92d9c652e6a39a8e49345389c.
Incomplete
This review is INCOMPLETE and must not be read as a full pass:
- no dimension was actually reviewed: the pipeline ran the 'default_reviewer' stub reviewer, which reports every dimension clean without reading it (a real dimension reviewer is #116)
Containment
No containment findings.
Fetched and empty: pr_issue_comments, pr_review_comments.
Automated containment covers the delimiter boundary and unambiguous injection tells only. It does not cover injection phrased as ordinary, unremarkable prose. The absence of a containment finding is not evidence that this pull request contains no injection attempt.
The previous revision used a real `-----BEGIN PRIVATE KEY-----` header as fixture content, and `gitleaks-secret-scan` flagged two of those lines as private-key findings — correctly. The check under test matches on path shape and never reads content, so the header bought nothing. A control for a secret-detection suite must not itself be the thing it detects. Refs #1965 Signed-off-by: tucktuck101 <jeffreytaylorrobertson@gmail.com>
|
Superseded by #1984, which carries identical content as one clean commit. Reason: this branch's first commit used a real Worth recording: |
Summary
auditfailed onlaunchpadtrunk, and so on every branch cut after 2026-08-28, over six files nobody in this cohort wrote. The check is not wrong about them — four genuinely contain private key material — but they are byte-for-byte upstream's APNs test fixtures, and this fork cannot fix them. This narrows the check by ownership rather than adding an exemption, because the check deliberately has no exemption mechanism and an earlier one caused a real miss.Feature
N/A - single-issue PR
Related issue
Closes #1965
Issue type
Bug
Agent provenance
Objective
A
tracked-sensitive-filescheck that passes onlaunchpadtrunk while still failing on any sensitive-shaped file this cohort added or modified.Impacted components
Approach and rejected alternatives
The six files, classified by content — headers only, no key material printed:
They arrived in
c432a111c("feat(mobile): push notifications MVP (block#6269)"), an ancestor ofblock/buzz@main, and are byte-for-byte identical here (git rev-parseon fork and upstream returns the same OIDs).block/buzzis public, so they have always been public — consistent with deliberately generated APNs test fixtures.Rejected: an allowlist or path exemption. This was my first instinct and it is wrong.
_matches_sensitive_shapehas no exemption mechanism on purpose: a*.examplesuffix exemption was removed after it let a trackedseed/authorized_keys.examplethrough, which is exactly the shape #68 documents a real past incident for. Re-adding the mechanism for these six would undo a control that was hardened deliberately.Rejected: match on content instead of filename. Would not help — four of the six really do contain
PRIVATE KEYblocks, so a content rule still fires.Rejected: untrack them, or generate them at test time. Both edit upstream-owned test code, which this fork does not do.
Rejected: raise it upstream only. Arguably correct owner, and worth doing separately, but it leaves trunk red indefinitely.
Chosen: scope by ownership. A fork that operates the upstream product is accountable for what it wrote, not for what it inherited unchanged.
divergence()returnsfork-added,inherited-modified,inherited-identicalorindeterminate, and onlyinherited-identicallicenses a skip.Identity, not origin — this is the part that matters.
classify()already answered "did this path exist upstream", and that is not sufficient: an inherited filename is precisely where cohort-added key material could hide.divergence()compares blob OIDs, so a path present upstream but modified here still fails. The OID comes from the same singlegit fetchthe classifier already ran —git ls-treewithout--name-onlyis one column wider and costs no extra network.fetch_upstream_pathsandclassifyare untouched, so the change is additive. Incidentally this is the classifier's first caller: it was written for #62 and never wired to anything.Unreachable upstream reports INDETERMINATE, naming the paths. Neither PASS nor FAIL is honest when ownership cannot be established, and INDETERMINATE is visibly not-green so it cannot be read as clean. Upstream-identical hits are named in the PASS detail — a skip nobody can see is indistinguishable from a check that stopped looking.
Verification
Command run:
Raw output:
The negative control is the acceptance criterion demonstrated rather than asserted: with the six upstream fixtures present and correctly excluded, one cohort-added key still fails the run.
Not verified
security_audit.pyharness was not run to completion locally. It downloads and checksum-verifies a pinned gitleaks binary and exceeded a 600s timeout on this machine. Only the check I changed was run against the repository, plus all 88 unit controls. CI on this PR is the first end-to-end run.fetch_upstream_blobsis unproven. The workflow already usesfetch-depth: 0because the classifier fetchesblock/buzz, but no job has ever exercised that fetch — this is the classifier's first caller, so its behaviour on a runner is untested.apns-test-*, live in a test fixtures directory, and are public in upstream — but nothing here proves they are unused elsewhere.fork-addedat its old path and would fail. No such case exists today.git ls-treeparsing assumes the standard<mode> <type> <oid>\t<path>shape. Malformed entries are skipped rather than raising, which is a silent-ish failure mode.Authority
N/A - no approval or merge performed by an agent; this PR is submitted for human review.
Deferred blockers
none
Security implications
This narrows a security control, so it deserves the scrutiny. What it gives up: a sensitive-shaped file that is byte-for-byte identical to upstream's no longer fails. What it keeps: everything the cohort added (
fork-added), everything the cohort changed (inherited-modified), and everything whose ownership cannot be established (indeterminate, which is not-green). The negative control above proves a cohort-added key still fails with the upstream fixtures present.The alternative was an exemption list, which would have been a permanent hole matched by name rather than by content identity — strictly weaker than this, and against the documented intent of the function it would have modified.
One genuine new dependency: correctness now rests on
git fetchof a public upstream reaching the network. Failure is handled as INDETERMINATE rather than PASS, so a network outage cannot silently turn the check green.Escalations
block/buzz, not a code fix.