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>