# 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 accepted [Service Identity and Privilege standard](../../canon/standards/service-identity-privilege_v0.1.md) that a declaration alone can decide. It was built against draft-1, before the founder's review, so a rule change in the standard changes this tool. It follows the accepted v0.1 text (draft-4). ```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. ## Model and rules decided here 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 (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 SI-15 are process rules. Observed state is the health check, NK-WP-0054-T04. ## Declarations `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 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.