NK-WP-0054: standard draft-4 applies the owner replies; review outcome recorded
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

security-canon confirmed all five mode readings and found citation errors, now
corrected in section 4 and 8 (anti-patterns cited as rules, a MUST resting on a SHOULD,
INV-001 for SI-9, SI-15 beyond AUDIT-001). Environment of platform-root, GOVERN for a
single-tier service admin (SI-4 allows it), principal_type ownership wording. Records
railiance-platform's prepared F-1 and aal2 changes (source only), key-cape's agent
token mechanism, glas-harness's harness-launched-only scope and state-hub's attribution
design. A hub decision routes ratification and the workers' open choices. No founder
decision changed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: sonnet
Assistant-Process: 328925@bnt-lap001
Assistant-Session: 14b795fd-c632-4c01-8d28-e7e490c7b0ed
This commit is contained in:
tegwick 2026-10-24 23:55:44 +02:00
parent 2438556edf
commit 951c7eac2d
7 changed files with 166 additions and 71 deletions

View file

@ -39,7 +39,7 @@ Draft-3 of the standard is an estate profile of SecurityCanon. Each account decl
fact is not established and is reported as a finding. Exceptions carry an `elimination_path` (DSM-EXC-004).
Decided from a declaration: SI-1, SI-2, SI-3 (including a credential shared by more than one service), SI-4
(a service-admin holds `ADMINISTER` over one service only), SI-6 (`SOVEREIGN` is offline and break-glass in
(a service-admin holds `ADMINISTER`, and `GOVERN` where the service has one admin tier, over one service only), SI-6 (`SOVEREIGN` is offline and break-glass in
production), SI-7 (`CONSTRUCT` never in production), SI-8 (second factor; admin roles bind the assurance
claim), SI-9, SI-11 (overdue legacy disposition), SI-12, SI-14 (an agent presents as an agent, tokens at most
3600 seconds) and naming. More than one service-admin account per service is an advisory. SI-5, SI-10, SI-13 and

View file

@ -12,7 +12,9 @@ identities:
principal_type: HUMAN
conventions: [service-admin]
purpose: "privacyIDEA's local administrator; policy pi-admin-all-rights restricted to adminuser=pi-admin"
grants: [{mode: ADMINISTER, scope: privacyidea, activation: STANDING, environments: [PRODUCTION]}]
grants:
- {mode: ADMINISTER, scope: privacyidea, activation: STANDING, environments: [PRODUCTION]}
- {mode: GOVERN, scope: privacyidea, activation: STANDING, environments: [PRODUCTION], note: "pi-admin-all-rights can set the policies that bound other admins"}
interactive_login: true
second_factor: unknown
custody: [personal-safe]

View file

@ -124,6 +124,9 @@ class RuleTests(unittest.TestCase):
def test_si4_service_admin_holds_administer_over_one_service(self):
self.assertEqual(self.rules(**HUMAN_ADMIN), [])
self.assertIn("SI-4", self.rules(**{**HUMAN_ADMIN, "grants": [grant("ADMINISTER"), grant("USE")]}))
# GOVERN over the same service is allowed (a single admin tier can set the policies that bound other admins).
self.assertEqual(self.rules(**{**HUMAN_ADMIN, "grants": [grant("ADMINISTER"), grant("GOVERN")]}), [])
self.assertIn("SI-4", self.rules(**{**HUMAN_ADMIN, "grants": [grant("ADMINISTER"), grant("GOVERN", "other")]}))
self.assertIn("SI-4", self.rules(**{**HUMAN_ADMIN, "grants": [grant("ADMINISTER", "a"), grant("ADMINISTER", "b")]}))
def test_si6_sovereign_is_offline_and_break_glass_in_production(self):

View file

@ -131,9 +131,9 @@ def _violations(identity: dict[str, Any]) -> tuple[set[str], list[str]]:
reads_only = all(g["mode"] == "USE" and g.get("read_only") is True for g in grants)
if principal != "SERVICE" or not reads_only or identity["interactive_login"] or persons or len(services) != 1:
broken.add("SI-3")
# SI-4 a service-admin account holds ADMINISTER over one service only.
# SI-4 a service-admin account holds ADMINISTER, and GOVERN where the service has one admin tier, over one service only.
if "service-admin" in conventions:
if {g["mode"] for g in grants} - {"ADMINISTER", "unknown"} or len({g["scope"] for g in grants}) != 1:
if {g["mode"] for g in grants} - {"ADMINISTER", "GOVERN", "unknown"} or len({g["scope"] for g in grants}) != 1:
broken.add("SI-4")
# SI-6 SOVEREIGN is offline and break-glass in production; break-glass serves no automation.
for grant in grants: