NK-WP-0054-T03: service identity schema, offline validator and first declarations
Schema, validator (30 tests), make targets and eight declarations authored from the
inventory, all unconfirmed by their owners. First run: 0 non-conformant, 12 unknown,
2 excepted, 5 planned, 6 conformant. Provisional: built against draft-1 before the
founder's review. Building it changed the draft: custody is a list, SI-X1 now covers
SI-9 and NAMING, and the reserved-name rule applies only to credential-holding
identities (open question 7). Unknown is a finding for every class.
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
2026-10-24 22:38:23 +02:00
# Service Identity Declaration Validator
NK-WP-0054-T03. Offline and read-only. Checks declarations against
`canon/schemas/service-identity_v0.1.schema.json` and evaluates the rules of the
2026-10-25 00:03:24 +02:00
accepted [Service Identity and Privilege standard ](../../canon/standards/service-identity-privilege_v0.1.md )
NK-WP-0054-T03: service identity schema, offline validator and first declarations
Schema, validator (30 tests), make targets and eight declarations authored from the
inventory, all unconfirmed by their owners. First run: 0 non-conformant, 12 unknown,
2 excepted, 5 planned, 6 conformant. Provisional: built against draft-1 before the
founder's review. Building it changed the draft: custody is a list, SI-X1 now covers
SI-9 and NAMING, and the reserved-name rule applies only to credential-holding
identities (open question 7). Unknown is a finding for every class.
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
2026-10-24 22:38:23 +02:00
that a declaration alone can decide. It was built against draft-1, before the founder's review,
2026-10-25 00:03:24 +02:00
so a rule change in the standard changes this tool. It follows the accepted v0.1 text (draft-4).
NK-WP-0054-T03: service identity schema, offline validator and first declarations
Schema, validator (30 tests), make targets and eight declarations authored from the
inventory, all unconfirmed by their owners. First run: 0 non-conformant, 12 unknown,
2 excepted, 5 planned, 6 conformant. Provisional: built against draft-1 before the
founder's review. Building it changed the draft: custody is a list, SI-X1 now covers
SI-9 and NAMING, and the reserved-name rule applies only to credential-holding
identities (open question 7). Unknown is a finding for every class.
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
2026-10-24 22:38:23 +02:00
```bash
make service-identity-test # unit tests
make service-identity-check # evaluate the checked-in declarations
uv run tools/service-identity/validate.py tools/service-identity/declarations/*.yaml --as-of 2026-10-24
```
Options: `--as-of YYYY-MM-DD` (evaluation date, so a run is reproducible and exceptions expire on a
stated day), `--json` , `--fail-on-findings` (exit 2 when anything is non-conformant or unknown).
Exit 1 means invalid input.
## Results
| Result | Meaning |
| --- | --- |
| `conformant` | Every checked rule holds on declared facts |
| `non-conformant` | At least one rule is broken and not covered by a live exception, or an exception has expired |
| `excepted` | Every broken rule has a live, time-boxed exception |
| `unknown` | A fact nobody has established (`unknown` in the declaration). A finding, not a pass |
| `planned` | A target identity that does not exist yet; never counted as conformant |
Alongside the results, **advisories** report declarations not asserted complete by their owner,
declarations not confirmed by the owning service, stale exceptions, more than one service-admin
and more than one break-glass identity.
2026-10-24 23:35:30 +02:00
## Model and rules decided here
NK-WP-0054-T03: service identity schema, offline validator and first declarations
Schema, validator (30 tests), make targets and eight declarations authored from the
inventory, all unconfirmed by their owners. First run: 0 non-conformant, 12 unknown,
2 excepted, 5 planned, 6 conformant. Provisional: built against draft-1 before the
founder's review. Building it changed the draft: custody is a list, SI-X1 now covers
SI-9 and NAMING, and the reserved-name rule applies only to credential-holding
identities (open question 7). Unknown is a finding for every class.
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
2026-10-24 22:38:23 +02:00
2026-10-24 23:35:30 +02:00
Draft-3 of the standard is an estate profile of SecurityCanon. Each account declares an imported
`principal_type` (`HUMAN` , `SERVICE` , `WORKLOAD` , `AGENT` , `CONTROLLER` , `DEVICE` ), its authority as grants
`MODE @ SCOPE` with `activation` and `environments` , and optional estate `conventions` (`bind` ,
`service-admin` ). Break-glass is `activation: BREAK_GLASS` , not a kind of account. `unknown` is allowed where a
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
2026-10-24 23:55:44 +02:00
(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
2026-10-24 23:35:30 +02:00
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
SI-15 are process rules. Observed state is the health check, NK-WP-0054-T04.
NK-WP-0054-T03: service identity schema, offline validator and first declarations
Schema, validator (30 tests), make targets and eight declarations authored from the
inventory, all unconfirmed by their owners. First run: 0 non-conformant, 12 unknown,
2 excepted, 5 planned, 6 conformant. Provisional: built against draft-1 before the
founder's review. Building it changed the draft: custody is a list, SI-X1 now covers
SI-9 and NAMING, and the reserved-name rule applies only to credential-holding
identities (open question 7). Unknown is a finding for every class.
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
2026-10-24 22:38:23 +02:00
## Declarations
2026-10-24 22:50:01 +02:00
`declarations/` holds the first set, authored from `docs/service-identity-inventory.md` . Decided 2026-10-24:
declarations start here and move to each service's repository as its owner confirms them. Every one says `owner_confirmed: false` : they describe what
NK-WP-0054-T03: service identity schema, offline validator and first declarations
Schema, validator (30 tests), make targets and eight declarations authored from the
inventory, all unconfirmed by their owners. First run: 0 non-conformant, 12 unknown,
2 excepted, 5 planned, 6 conformant. Provisional: built against draft-1 before the
founder's review. Building it changed the draft: custody is a list, SI-X1 now covers
SI-9 and NAMING, and the reserved-name rule applies only to credential-holding
identities (open question 7). Unknown is a finding for every class.
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
2026-10-24 22:38:23 +02:00
the repository establishes, not what the owning service has attested. Facts the repository cannot
establish are `unknown` , never guessed.
## Safety
A declaration holds no credential. Secret-shaped values are rejected, and schema messages are never
printed because they can echo the rejected value; invalid input reports only a count.