feat(manifest): git-gate.signing opt-in (PRD chunk 2)
test / integration-docker (pull_request) Successful in 38s
lint / lint (push) Successful in 56s
test / unit (pull_request) Successful in 52s
test / integration-firecracker (pull_request) Successful in 3m48s
test / coverage (pull_request) Successful in 15s
test / publish-infra (pull_request) Has been skipped
tracker-policy-pr / check-pr (pull_request) Failing after 24s

Implements the manifest surface for the signed-commits & audit-attribution
PRD (#423, PR #480): a bottle opts into per-activation commit signing with

    git-gate:
      signing:
        enabled: true

- New ManifestGitSigning value type (frozen, enabled: bool = False) parsed
  under git-gate.signing; unknown sub-keys and non-bool `enabled` die with
  targeted errors. parse_git_gate_config now returns (repos, user, signing).
- ManifestBottle gains git_signing; defaults to off, so bottles that omit
  the block are unchanged.
- Bottle-only: git-gate.signing on an agent is rejected by the existing
  agent-level non-`user` guard (like git-gate.repos).
- extends/runtime merges thread git_signing with an enable-wins overlay
  (a child enabling signing wins; omitting inherits the parent), mirroring
  the git_user non-empty-wins overlay.
- Facade exports ManifestGitSigning.

Tests: tests/unit/test_manifest_git_signing.py (parse, validation,
agent-level rejection, extends overlay). Full unit suite green.

This is the first stacked chunk; signing pipeline, gate signature check,
and control-plane verification + audit tables follow per the PRD.

Issue: #423

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 02:52:47 +00:00
parent 010e253d66
commit e16efc86ad
5 changed files with 217 additions and 10 deletions
+8 -1
View File
@@ -66,7 +66,12 @@ if TYPE_CHECKING:
from .agent import ManifestAgent, ManifestAgentProvider
from .bottle import ManifestBottle
from .egress import EGRESS_AUTH_SCHEMES, ManifestEgressConfig, ManifestEgressRoute
from .git import ManifestGitEntry, ManifestGitUser, ManifestKeyConfig
from .git import (
ManifestGitEntry,
ManifestGitSigning,
ManifestGitUser,
ManifestKeyConfig,
)
# Facade name -> submodule that defines it. The aggregate model (`Manifest`,
@@ -82,6 +87,7 @@ _LAZY_MODULES: dict[str, str] = {
"ManifestEgressRoute": "egress",
"ManifestEgressConfig": "egress",
"ManifestGitEntry": "git",
"ManifestGitSigning": "git",
"ManifestGitUser": "git",
"ManifestKeyConfig": "git",
}
@@ -107,6 +113,7 @@ __all__ = [
"ManifestIndex",
"ManifestError",
"ManifestGitEntry",
"ManifestGitSigning",
"ManifestGitUser",
"ManifestKeyConfig",
"ManifestAgentProvider",