feat(a2apolicy): A2A caller role/entitlement mapping (lr-0ae541) - #25
Conversation
|
BOBBIE -- clean Scope: base a427bc5..head 84228a0 (task lr-0ae541, A2A caller role/entitlement mapping). 7 files, +596/-0. Findings: none. Review notes:
scanners_run: gitleaks detect (0 leaks), semgrep --config=auto on internal/a2apolicy.go + internal/config/config.go (0 findings, 131 rules), osv-scanner (skipped -- no go.sum diff, no new dependency surface introduced by this PR). |
|
PEACHES — clean (0 blocking findings) AC1–AC5 all passed. PR #25 implements A2A caller entitlement mapping (lr-0ae541) as pure, fail-closed policy:
Tests: 10 new tests covering AC1–AC5 + config wiring + off-by-default. Full suite green. No existing test bodies modified (+75/−0 in config_test.go). Rulebook: no code-craft/path-choice violations. No new deps, no bare TODOs, no stale error fields, nil/*Policy fails closed explicitly. |
|
Merged via clagentic-loadout v0.1.0
|
Implements lr-0ae541: config-driven A2A caller role/entitlement mapping.
Adds internal/a2apolicy, a pure-policy package mapping attested A2A caller
identity -> caller role -> permitted peer audience(s)/scope(s), analogous
to the existing role -> App-slug gate in internal/mint (lr-116b57) but for
the A2A domain instead of the GitHub-App-role domain.
This runs AFTER attestation (lr-a850d0's required-fields contract, merged
via PR #24 / a427bc5) and BEFORE issuance (lr-890fae, downstream token
provider, not implemented here). Pure policy: no minting, no I/O.
What changed
Nil/empty Policy is fully closed (fail-closed default). DeniedError always
names the RESOLVED identity + requested audience, and the resolved role
when the identity was found but the audience was not covered.
helper so a config-sourced map converts to a Policy without a
cross-layer import (config satisfies EntitlementSource structurally).
(a2a_mapping stanza) + A2AEntitlementConfig, parsed independently of
roles. (internal/mint's GitHub-domain gate). Absent/empty by
default.
stanza (invented identities/roles/audiences).
table row.
from roles..entitled_identities.
AC coverage
by TestCheckPermitted, TestNewPolicyFromEntries_ConfigWiring.
requested audience, Role empty. TestCheckIdentityAbsent.
resolved role + denied audience. TestCheckAudienceNotCovered.
zero effect on internal/mint's existing GitHub-domain gate (unchanged
mint test suite still green). TestLoad_A2AMappingAbsent,
TestCheckEmptyPolicyFailsClosed, TestNewPolicyFromEntries_EmptyMapFailsClosed,
plus TestLoad_ExampleConfigParses asserting the shipped example itself
loads with A2AMapping empty (stanza ships commented out).
peer-project-x — all invented).
config.example.yaml).
Test status
go build ./... clean, go vet ./... clean, go test ./... all green
(pre-existing + new: internal/a2apolicy, internal/config, plus the full
pre-existing suite unchanged — confirms AC 4 byte-identical GitHub-domain
behavior).
Branched from main tip a427bc5 (includes lr-a850d0 attestation contract,
PR #24). Task: lr-0ae541. Does not implement token minting/issuance
(lr-890fae, downstream child) — mapping only.