Revised per PR #480 (#5607 owner clarification + #5608 codex resolution;
#5612 directs the update):
- The audit row no longer implies upstream observation or agent-only
authorship. Reworded the guarantee: the row cryptographically binds
commit bytes (control-plane-RECOMPUTED SHA) to access to the activation
signing key, and binds that key to control-plane-owned activation
metadata. An agent can sign arbitrary contents but cannot verify as a
different activation or choose the recorded metadata.
- Control plane accepts gateway-delivered opaque bytes, independently
recomputes the Git object ID, verifies the embedded signature against
the activation key, and stamps its own metadata. Trusts no gateway
SHA/key/verdict/metadata. No upstream fetch.
- Purged overclaims: removed "a compromised gateway cannot fabricate an
audit binding" (the sidecar holds the signing capability, so it can —
and that's acceptable under the intended guarantee), plus "accepted
push" / "introduced upstream" framing.
- Resolved the control-plane-transport open question in-PRD (was left
open; codex asked to resolve): transport is gateway bytes +
recompute + verify; mirror-read is no stronger.
Issue: #423
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Revised per PR #480 review (#5590 + didericis-codex review on d8362ec):
- Remove author/committer enforcement entirely (#5590). The gate no
longer matches identity fields; author/committer are recorded as
claims in the audit store. Drop the git-gate.signing.enforce knob
(which also resolves codex issue 1: a knob that weakened the stated
guarantee). Add a "Deferred: identity enforcement" section noting it
as a possible future add. Rename PRD/file to "signed commits & audit
attribution" since identity is no longer guaranteed.
- Fix control-plane vs data-plane verification (codex issue 2, PRD 0070):
git-gate (data plane) does a synchronous pre-forward SIGNATURE check
only; the orchestrator/control plane (sole owner of bot-bottle.db)
independently re-verifies each signature before writing attributed_commit.
A gateway assertion alone never creates an audit row. New "Trust
boundary" + "Control-plane verification & recording" sections.
- Reframe the guarantee to signed provenance + host-owned, independently
verified audit record; ADR 0002 "claimed, not vouched" posture kept.
- attributed_commit now records claimed author/committer columns.
Issue: #423
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Revised per PR #480 review (#5518 → #5556):
- Rename: "forge subroles" → "per-bottle signed identity & audit
attribution"; rename the file to match.
- Reframe the guarantee as bottle/activation provenance, not
cryptographically-vouched author identity. Author/committer name/email
is a claim carried inside the signed object, made trustworthy by a
git-gate acceptance check + the host record, not by the signature.
- Add the gate-side acceptance check: on push, every newly-introduced
commit (excluding upstream-reachable history) must verify against the
activation key AND match git-gate.user in both author and committer
fields, else the push is rejected. Host verifies the signature before
recording a SHA as attributed.
- Audit: retain full public key + fingerprint + principal + validity
interval (not fingerprint-only); state allowed-signers generation.
- Drop from scope: forge subuser accounts, provisioned API tokens/PAT
minting, forge status/Verified badges -> future "forge actors" PRD.
This removes the Gitea PAT bootstrap problem entirely.
- Manifest: drop git-forge/forge-accounts; reuse git-gate.user as the
enforced identity + add opt-in git-gate.signing. Push stays PRD 0048
deploy keys, unchanged.
Issue: #423
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Formalizes the design settled in issue #423: one forge subrole identity
per bottled agent (author + forge account + SSH signing key), reused
across all repos/forges. Vouched attribution via sign-at-commit-time in
the git-gate boundary (forwarded ssh-agent; private key never in the
bottle; no SHA divergence). Forge "Verified" badges abandoned in favor
of local git verify-commit plus durable console audit records and
commit-status badges. Reprovision-per-activation credential lifecycle
(0048 discipline), fail-loud teardown, public-key-fingerprint-only audit
trail on bottled_agent.
Successor to PRD 0027 (claimed-not-vouched, ADR 0002) and PRD 0048
(host-side minting lifecycle).
Issue: #423
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
On a docker daemon that default-enables IPv6 (default-address-pools),
creating the gateway network with only `--subnet` lets the daemon also
attach an fdd0::/64 IPv6 subnet. Its gateway is stored as `::1/64`,
which trips docker's own netip.ParseAddr in `network inspect`/`ls`:
ParseAddr("fdd0:0:0:6::1/64"): unexpected character, want colon
That poisons every `_network_cidr`/`network ls` read and fails the
docker integration suite intermittently (whichever run the runner's
IPv6 pool index lands on a broken network). bot-bottle attribution
pins IPv4 source IPs and has no IPv6 support, so pass `--ipv6=false`
explicitly at network create to keep the gateway network IPv4-only
regardless of the daemon default.
Note: an already-poisoned runner still needs a one-time
`docker network rm bot-bottle-gateway` (and possibly a daemon
restart) to clear the malformed network.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gitea AGit accepts pushes to refs/for/*, refs/draft/*, and
refs/for-review/* and opens pull requests backed by server-managed
refs/pull/<n>/head refs rather than ordinary refs/heads/* branches.
That breaks the git-gate branch workflow: follow-up commits can't be
pushed back through the branch, and Gitea rejects later direct updates
to the generated review ref, so recovery means recreating the PR.
Add a Phase 0 guard to the shared pre-receive hook that rejects
creation or update of those AGit review refs before any gitleaks scan
or upstream forward, with a message pointing callers at the
branch-backed PR workflow. Deletions (new == zero) stay allowed so
legacy AGit refs can still be cleaned up; normal branches and tags are
untouched.
Closes#506
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The require-numbered-prds gate previously ran on every pull request.
Scope its trigger to PRs whose base branch is main, so numbering is
only enforced at the point of merging into main.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>