Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a14bfc-9643-7872-aa12-98326dcf25e7
130 lines
7.8 KiB
Markdown
130 lines
7.8 KiB
Markdown
# Forge receive-path secret detection
|
|
|
|
FORGE-WP-0006 implements the forge-owned part of RMGR-WP-0021-T03 and
|
|
Custodian CUST-WP-0080 G07. The local Repo Manager scanner remains separate.
|
|
The source adapter is not evidence of installed server enforcement.
|
|
|
|
## Boundary and ownership
|
|
|
|
The forge-owned, standalone Linux adapter composes with Forgejo's generated
|
|
pre-receive dispatcher. It uses pinned Gitleaks 8.30.1 Linux amd64
|
|
(SHA256 `88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509`).
|
|
It requires `/usr/bin/git`, `/proc`, a private writable tmpfs at `/dev/shm`,
|
|
and Linux pidfd support (5.3+ on amd64/arm64) but no Python runtime, issuer credential,
|
|
network access, source checkout, or repository-controlled workflow. The current
|
|
Forgejo 11.0.3 image has no Python interpreter; this keeps the runtime change to
|
|
two reviewed executables and a hook fragment, subject to native admission.
|
|
|
|
The forge owns tool admission, hook installation and recovery. Repo Manager
|
|
coordinates repository-control coverage; enablement owns reusable CI templates;
|
|
source repositories own their workflows. Credential classification and
|
|
revocation remain with existing incident/custody owners.
|
|
|
|
Do not overwrite generated `hooks/pre-receive` or `pre-receive.d/gitea`, or enable
|
|
arbitrary user Git-hook editing. A reviewed additional executable in the existing
|
|
`pre-receive.d/` dispatcher is the proposed integration. Server writers, frontend
|
|
merge/edit/import paths, SSH and HTTP pushes, hook resynchronization, pod restart
|
|
and new repository creation all need separate native acceptance. No admission
|
|
or production coverage is inferred from disposable bare-repository tests.
|
|
|
|
## What is checked
|
|
|
|
Input is the exact `old-object new-object ref-name` batch from receive-pack.
|
|
Malformed, duplicate, oversized, inconsistent or unsupported updates refuse.
|
|
All updated ref names are scanned without echoing them. Ref exclusions are frozen
|
|
from the pre-push snapshot; the traversal scans complete introduced reachable
|
|
objects across every new tip and every parent, including annotated tags and
|
|
direct object tags. A secret added and removed before the tip is still examined.
|
|
|
|
Blob data, raw commit/tag contents and tree names are scanned. Symlink contents
|
|
are read as Git blobs; their filesystem targets are never followed. Changed trees
|
|
containing external gitlinks refuse because the referenced repository is not
|
|
covered. Git replacement objects and grafts cannot hide history. Partial/shallow
|
|
repositories, missing objects and unverified traversal refuse. Receive-pack's
|
|
quarantine object locations are preserved only for Git reads; the adapter never
|
|
updates refs or copies objects into the primary store.
|
|
|
|
The scanner executable is opened without following a final symlink, checked for
|
|
ownership/mode/regular-file shape and exact SHA256, and executed through its open
|
|
file descriptor. Scanner config and ignore files are private temporary files;
|
|
repository configuration, inline allow comments and ambient scanner settings do
|
|
not disable detection. Child diagnostics/findings are discarded. Output contains
|
|
only a fixed status/reason, counts, version and, for an object detection, its ID.
|
|
Privately review the identified object; never paste its contents into an issue,
|
|
State Hub, CI logs or chat. Standard Git output may independently display ref
|
|
names; the adapter does not make Git's transport diagnostics a secret-safe log.
|
|
|
|
Exit 0 is `clean` in this declared scope; exit 1 is `blocked`; exit 2 is
|
|
`unverified`. Both nonzero statuses must refuse the complete push. There is no
|
|
implicit baseline/ignore or override switch. A false-positive exception needs a
|
|
separate reviewed mechanism with exact scope, approval and expiry.
|
|
|
|
## Bounds and remaining coverage
|
|
|
|
Current bounds: 256 updates, 10,000 existing refs, 2,000 introduced objects,
|
|
8 MiB per object, 64 MiB total, 512 KiB update input and 90 seconds for the check.
|
|
Scanner calls also use the scanner's 15-second timeout. Object sizes and total
|
|
bytes are checked before scanning payloads. Limits reject rather
|
|
than skip. Large imports need an admitted path; do not disable the gate to pass
|
|
an unreviewed import. Git/scanner versions and limits require native load testing.
|
|
|
|
FORGE-WP-0010 corrects per-small-input scanner startup overhead without changing
|
|
these limits. It reuses Repo Manager's bounded profile: at most 64 inputs of at
|
|
most 4096 bytes per directory invocation. Larger inputs retain the existing stdin
|
|
reader and fragment behavior. Raw inputs use 0700 private tmpfs directories and
|
|
0600 files with safe object/ref identifiers; no source path controls a filename.
|
|
Missing or nonvolatile storage refuses instead of falling back to ordinary disk.
|
|
|
|
A separately supervised child pins its receiver with pidfd, acknowledges readiness
|
|
before payload writes, and cleans up on pipe EOF. A 180-second backstop terminates
|
|
the exact stalled receiver before cleanup. Git/scanner children die when their
|
|
creating receiver thread dies; it is pinned to its OS thread during each child.
|
|
Normal cleanup and failed cleanup are checked. Directory identity replacement
|
|
refuses deletion. This is not protection against a hostile same-UID host process.
|
|
|
|
Directory scans use the same pinned scanner/default config and explicit empty
|
|
ignore file. Bounded reports contain only known safe payload identifiers. Missing,
|
|
malformed, oversized or inconsistent reports, unknown diagnostics and scanner or
|
|
watchdog failures refuse. Only the exact pinned scanner's positive-finding summary
|
|
is accepted as a warning. The original stdin route is otherwise unchanged.
|
|
|
|
The adapter does not rescan objects already reachable before the push, scan
|
|
unreachable extra pack objects, LFS payloads, other repositories, runtime logs,
|
|
artifacts or credentials outside Git. It is not an authorization boundary against
|
|
a forge administrator or hostile same-UID process. Default scanner rules remain
|
|
heuristic. Historical discovery and finding-to-response are independent work;
|
|
removing a source value or rejecting a push does not revoke an exposed credential.
|
|
CUST-WP-0073-T05's founder-deferred rotation is unchanged.
|
|
|
|
The 165 observed on-disk repository directories are a discovery count, not an
|
|
admitted production-software denominator. The 22 reviewed repositories provide a
|
|
named rollout starting scope; the owner must reconcile all production repositories,
|
|
wikis, archives, mirrors and new-repository lifecycle before claiming DSM coverage.
|
|
|
|
## Build and disposable acceptance
|
|
|
|
Use an admitted Go toolchain. The original deployed revision used Go 1.26.9,
|
|
verified against the SHA256 from go.dev release metadata. The FORGE-WP-0010
|
|
source candidate is separately tested with installed Go 1.26.7; its new source,
|
|
compiler and exact executable still require native admission. No third-party Go
|
|
modules are required. Keep binaries and logs outside the repository:
|
|
|
|
```sh
|
|
cd tools/receive-secret-scan
|
|
FORGE_TEST_GITLEAKS=/reviewed/gitleaks go test -count=1 -v ./...
|
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -buildvcs=false -o /tmp/receive-secret-scan .
|
|
```
|
|
|
|
The root `make test-secret-detection` target requires `FORGE_TEST_GITLEAKS`
|
|
and runs this module; set `GO` to the admitted compiler path where needed.
|
|
|
|
Tests use disposable Git servers, actual receive-pack quarantine and generated
|
|
keys. Scanner-dependent tests explicitly skip without `FORGE_TEST_GITLEAKS`;
|
|
skips are not acceptance. Native activation additionally needs exact original
|
|
hook hashes, tool provenance, dry-run/diff, abort owner, rollback and value-free
|
|
receipts under the accepted build-mode change rule.
|
|
|
|
References: [Git receive-pack and quarantine](https://git-scm.com/docs/git-receive-pack),
|
|
[Git object traversal](https://git-scm.com/docs/git-rev-list),
|
|
[Forgejo 11.0.3 generated hooks](https://codeberg.org/forgejo/forgejo/src/tag/v11.0.3/modules/repository/hooks.go),
|
|
[Gitleaks release](https://github.com/gitleaks/gitleaks/releases/tag/v8.30.1).
|