Revise KeyCape secrets-engine-openbao custody: OpenBao-only, operator reader CCR-2026-0034 (source only)
Founder direction 2026-10-06 and ops-mason plan keycape-secrets-engine-openbao-client-custody (658cdbc, MASON-WP-0009): the client secret lives only in OpenBao. - CCR-2026-0033: consumer file and secrets-engine D1-D4 removed; KV metadata declared (cas_required, max_versions=2, delete_version_after=0s, custom_metadata); target.domain infotech; live order and roll-forward rollback revised; status stays proposed. - New sibling CCR-2026-0034 + policy: attended OIDC operator reader on auth/netkingdom, read data path + revoke-self only, 5m/4 uses, no default policy, bound groups=net-kingdom-admins and /assurance/level=aal2 (KeyCape 7d96ee4). Proposed, bound claims unconfirmed (founder item for both readers). - credential-change.py: OIDC roles carry token_max_ttl/explicit_max_ttl/no_default_policy/ num_uses/type and bound_claims_type (string only); token_revoke_self policy option; validated openbao.kv_metadata. Tests added. - Custody child: consumer write and check-secret-file removed; cas=0 create / --rotate cas=<current>; compare-before-write metadata put; refusals unchanged. - Founder runbook (keycape/founder-runbook.md), window docs, RPF-WP-0035-T09 (waits on A1/A2/A3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 132360@bnt-lap001 Assistant-Session: 769b1afd-4330-4c86-96b2-e510e26db42b
This commit is contained in:
parent
9e23eaa067
commit
4a284f0a3b
11 changed files with 734 additions and 307 deletions
|
|
@ -453,6 +453,65 @@ class CredentialChangeTests(unittest.TestCase):
|
|||
["openid", "profile", "email", "groups"],
|
||||
)
|
||||
|
||||
def test_oidc_operator_reader_carries_token_bounds_and_assurance(self) -> None:
|
||||
path = REPO_DIR / "credential-change-requests/CCR-2026-0034.yaml"
|
||||
ccr, errors, _warnings = credential_change.validate_ccr(path)
|
||||
self.assertEqual(errors, [])
|
||||
payload = credential_change.auth_payload(ccr)
|
||||
self.assertEqual(payload["token_num_uses"], 4)
|
||||
self.assertEqual((payload["ttl"], payload["token_max_ttl"], payload["token_explicit_max_ttl"]),
|
||||
("5m", "5m", "5m"))
|
||||
self.assertIs(payload["token_no_default_policy"], True)
|
||||
self.assertEqual(payload["token_type"], "service")
|
||||
self.assertEqual(payload["bound_claims_type"], "string")
|
||||
self.assertEqual(payload["bound_claims"],
|
||||
{"groups": ["net-kingdom-admins"], "/assurance/level": "aal2"})
|
||||
body = credential_change.generated_policy_hcl(ccr)
|
||||
self.assertIn('path "auth/token/revoke-self"', body)
|
||||
self.assertNotIn("lookup-self", body)
|
||||
self.assertNotIn("/metadata/", body)
|
||||
self.assertEqual(credential_change.policy_artifact_diff(ccr)["status"], "matches")
|
||||
self.assertEqual(credential_change.applier_policy_violations(ccr), [])
|
||||
|
||||
def test_oidc_token_bounds_and_kv_metadata_are_validated(self) -> None:
|
||||
import yaml
|
||||
source = yaml.safe_load((REPO_DIR / "credential-change-requests/CCR-2026-0034.yaml").read_text())
|
||||
cases = [
|
||||
(("openbao", "auth", "token_num_uses"), 0, "token_num_uses must be a positive integer"),
|
||||
(("openbao", "auth", "token_num_uses"), True, "token_num_uses must be a positive integer"),
|
||||
(("openbao", "auth", "token_type"), "root", "token_type must be one of"),
|
||||
(("openbao", "auth", "bound_claims_type"), "glob", "glob matching is not admitted"),
|
||||
(("openbao", "auth", "token_max_ttl"), "5 minutes", "token_max_ttl must be a TTL string"),
|
||||
(("openbao", "kv_metadata"), {"max_versions": 0}, "max_versions must be a positive integer"),
|
||||
(("openbao", "kv_metadata"), {"delete_version_after": "never"}, "delete_version_after"),
|
||||
(("openbao", "kv_metadata"), {"versions": 2}, "unknown keys"),
|
||||
(("openbao", "kv_metadata"), {"custom_metadata": {"a": 1}}, "custom_metadata must map"),
|
||||
]
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
for keys, value, message in cases:
|
||||
ccr = yaml.safe_load(yaml.safe_dump(source))
|
||||
target = ccr
|
||||
for key in keys[:-1]:
|
||||
target = target[key]
|
||||
target[keys[-1]] = value
|
||||
path = Path(tmp) / "CCR-2026-0034.yaml"
|
||||
path.write_text(yaml.safe_dump(ccr))
|
||||
_ccr, errors, _ = credential_change.validate_ccr(path)
|
||||
self.assertTrue(any(message in error for error in errors), (keys, value, errors))
|
||||
|
||||
def test_keycape_secrets_engine_openbao_ccr_declares_kv_metadata_without_consumer_copy(self) -> None:
|
||||
path = REPO_DIR / "credential-change-requests/CCR-2026-0033.yaml"
|
||||
ccr, errors, _ = credential_change.validate_ccr(path)
|
||||
self.assertEqual(errors, [])
|
||||
self.assertNotIn("consumer_copy", ccr)
|
||||
self.assertEqual(ccr["target"]["domain"], "infotech")
|
||||
self.assertEqual(ccr["status"], "proposed")
|
||||
meta = ccr["openbao"]["kv_metadata"]
|
||||
self.assertEqual((meta["cas_required"], meta["max_versions"], meta["delete_version_after"]),
|
||||
(True, 2, "0s"))
|
||||
self.assertEqual(meta["custom_metadata"]["readers"], "eso-sso-issuer,oidc-secrets-engine-operator")
|
||||
self.assertIs(ccr["openbao"]["auth"]["bound_claims_confirmed"], False)
|
||||
|
||||
def test_apply_plan_refuses_unapproved_ccr(self) -> None:
|
||||
with self.assertRaises(SystemExit):
|
||||
credential_change.command_apply_plan(type("Args", (), {"ref": str(self.issue_core)})())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue