Allow platform/suppliers/<supplier>/<account> in credential-change applier
WARDEN-WP-0043-T02: supplier account credentials (first: IONOS) live on the platform mount at exactly two segments under suppliers/. Wildcard, parent, empty-segment and KV-v2 API-path checks are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 469992@bnt-lap001 Assistant-Session: e4b8e420-df0a-441d-83ae-7f19130594d9
This commit is contained in:
parent
1b36e147e3
commit
b77cb41275
2 changed files with 47 additions and 6 deletions
|
|
@ -838,20 +838,30 @@ def applier_policy_violations(ccr: dict[str, Any]) -> list[str]:
|
|||
|
||||
# WARDEN-WP-0028: platform fleet lanes stay under platform/workloads/;
|
||||
# client/tenant commercial secrets live on mount tenants/ (exact-path policies).
|
||||
# WARDEN-WP-0043: supplier account credentials live at
|
||||
# platform/suppliers/<supplier>/<account> (exactly two segments).
|
||||
allowed_mount_prefixes = {
|
||||
"platform": "platform/workloads/",
|
||||
"tenants": "tenants/",
|
||||
"platform": ("platform/workloads/", "platform/suppliers/"),
|
||||
"tenants": ("tenants/",),
|
||||
}
|
||||
if mount not in allowed_mount_prefixes:
|
||||
violations.append(
|
||||
f"openbao.mount must be one of {sorted(allowed_mount_prefixes)}, got {mount}"
|
||||
)
|
||||
else:
|
||||
prefix = allowed_mount_prefixes[mount]
|
||||
if not kv_path.startswith(prefix):
|
||||
prefixes = allowed_mount_prefixes[mount]
|
||||
if not kv_path.startswith(prefixes):
|
||||
violations.append(
|
||||
f"openbao.kv_path for mount {mount!r} must stay under {prefix}"
|
||||
f"openbao.kv_path for mount {mount!r} must stay under "
|
||||
+ " or ".join(prefixes)
|
||||
)
|
||||
elif kv_path.startswith("platform/suppliers/"):
|
||||
segments = kv_path[len("platform/suppliers/"):].split("/")
|
||||
if len(segments) != 2 or not all(segments):
|
||||
violations.append(
|
||||
"openbao.kv_path under platform/suppliers/ must be exactly "
|
||||
"<supplier>/<account>"
|
||||
)
|
||||
if any(fragment in kv_path for fragment in ("*", "..", "//")):
|
||||
violations.append("openbao.kv_path must not contain wildcard, parent, or empty segments")
|
||||
if "/data/" in kv_path or "/metadata/" in kv_path:
|
||||
|
|
@ -1888,7 +1898,7 @@ def decision_templates(ccr: dict[str, Any] | None = None) -> dict[str, str]:
|
|||
else:
|
||||
context = {
|
||||
"id": "<CCR-ID>",
|
||||
"kv_path": "<platform/workloads/...> or <tenants/<tenant>/...>",
|
||||
"kv_path": "<platform/workloads/...>, <platform/suppliers/<supplier>/<account>> or <tenants/<tenant>/...>",
|
||||
"policy_name": "<workload-kv-read-...>",
|
||||
"auth_role_path": "auth/<mount>/role/<role>",
|
||||
"decision_link": "<link State Hub decision>",
|
||||
|
|
|
|||
|
|
@ -771,6 +771,37 @@ class CredentialChangeTests(unittest.TestCase):
|
|||
violations = credential_change.applier_policy_violations(ccr)
|
||||
self.assertEqual(violations, [], violations)
|
||||
|
||||
def _supplier_ccr(self, kv_path: str) -> dict:
|
||||
ccr, errors, _warnings = credential_change.validate_ccr(self.sample)
|
||||
self.assertEqual(errors, [])
|
||||
ccr["status"] = "approved"
|
||||
ccr["openbao"]["mount"] = "platform"
|
||||
ccr["openbao"]["kv_path"] = kv_path
|
||||
ccr["openbao"]["policy_file"] = ""
|
||||
return ccr
|
||||
|
||||
def test_applier_accepts_platform_suppliers_path(self) -> None:
|
||||
"""WARDEN-WP-0043-T02 — supplier accounts at platform/suppliers/<s>/<a>."""
|
||||
ccr = self._supplier_ccr("platform/suppliers/ionos/main")
|
||||
violations = credential_change.applier_policy_violations(ccr)
|
||||
self.assertEqual(violations, [], violations)
|
||||
|
||||
def test_applier_rejects_malformed_platform_suppliers_paths(self) -> None:
|
||||
for kv_path in (
|
||||
"platform/suppliers/ionos",
|
||||
"platform/suppliers/ionos/main/extra",
|
||||
"platform/suppliers/*/main",
|
||||
"platform/suppliers/../workloads/x",
|
||||
"platform/suppliers/ionos//main",
|
||||
"platform/data/suppliers/ionos/main",
|
||||
"platform/other/ionos/main",
|
||||
):
|
||||
with self.subTest(kv_path=kv_path):
|
||||
violations = credential_change.applier_policy_violations(
|
||||
self._supplier_ccr(kv_path)
|
||||
)
|
||||
self.assertNotEqual(violations, [], kv_path)
|
||||
|
||||
def test_nonprod_applier_policy_remains_metadata_only(self) -> None:
|
||||
policy = (
|
||||
REPO_DIR / "openbao/policies/credential-change-nonprod-applier.hcl"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue