Credential registry: value templates and verify commands replace the format and probe enums #24

Merged
vnprc merged 1 commit from agent/secret-value-templates into master 2026-09-12 02:23:45 +01:00
Member

Nothing changes on a running machine: this PR changes the public secrets template's registry contract and its check, and no deployment reads this template's registry. It replaces the three hand-named credential formats and the verify-probe enum with one declared shape: a credential's non-secret text is a value.template with exactly one {secret} placeholder (or no value when the plaintext is the secret itself), an optional value.encode drawn from the new lib.credentialEncodings export, and one verify command string per target. The public example credential is migrated to that shape. During the private migration a credential may still be wholly legacy (format plus structured verify.type), never a mixture, and the new credential-registry check enforces all of that with one sabotage witness per rule; lib.forgejoTokenGroups now validates at its export seam so a bad registry fails every consumer, not only nix flake check. Merge this after the archetypes PR (whose check must already accept the new example) and before the tools PR. If it is wrong, revert it: the legacy shape stays valid everywhere until the tools PR lands, and no ciphertext is touched.

What changes

  • flake.nix: lib.credentialEncodings = [ "rclone-obscure" ] exported; credentialRegistryDiagnostics and validateCredentialRegistry implement the contract (exactly one {secret}, encoder membership, non-empty one-line verify on every target, at least one target per credential and one credential per group, legacy-or-new but never both on one credential, one encoding shared by a group's new-shape credentials); lib.forgejoTokenGroups is validated at the export seam.
  • checks.<platform>.credential-registry: validates the shipped registry, a positive legacy-plus-new coexistence fixture, a positive legacy-plus-encoded fixture, and one sabotage fixture per rule, each proven to trip only its own rule.
  • forgejo-token-groups.json: the public example moves from format = "credential-store-url" to value.template and a verify command, byte-identical to the example in allod/secrets#23.
  • README.md: the export table gains lib.credentialEncodings and the check; a "Forgejo credential registry schema" section states the contract, the coexistence rule, and the example verification commands that replace the former probe names.

Risk

R3 in the plan (shared secrets schema and transition compatibility). Residual after the check: a rule that accepts an input the tools renderer or archetypes consumer rejects, or the reverse; both consumers fail loud on such an entry, and the private registry is not read by this template. Rollback is a revert; legacy entries and rotate-token remain valid until the tools PR closes the issue.

Validation

  • nix flake check . in the worktree (plain path per nix.md): ``all checks passed!, exit 0
  • git diff --check: no output, exit 0
  • Witness falsification for the two rules the review found vacuous (delete the rule, the sabotage passes; restore): the check itself now asserts that each of its 20 sabotage fixtures produces exactly its own diagnostic, so a vacuous fixture is a red check; with the encoder rule removed it fails with unexported-encoder wanted [value.encode is not an exported encoding] got [], and likewise for the mix rule (worker-run, captured output read by the overseer). Export seam, run by the overseer: with {secret}removed from the public template,nix eval .#lib.forgejoTokenGroupsexits 1 witherror: credential-registry: value.template must contain exactly one {secret}; the file was restored byte-for-byte
  • Cross-family cold reviews of the pre-fix diff: claude-opus-5 through the pi runner on provider nullsink-claude at thinking high (2 blockers, 4 gaps, 1 simplify: vacuous encoder and mixed-shape sabotage fixtures, legacy credentials counted as an encoding, vacuous empty-targets acceptance, four unwitnessed guards, the unvalidated export, constant assertion messages) and ``claude-fable-5-1as a fresh Claude Code subagent at default effort (2 blockers, 3 gaps, 1 simplify, 2 questions: the same two vacuous fixtures, no witness for a missing or multi-lineverify, the legacy-encoding rule, an undocumented extra-fields rule, the unvalidated export, blank commands and empty targets, and the merge order). All accepted findings are fixed in this diff. The author of the original diff was a Codex model, so both reviewers are cross-family.
  • Not run: no private registry is evaluated here; the private migration is a separate handoff issue.

Refs allod/secrets#23

Nothing changes on a running machine: this PR changes the public secrets template's registry contract and its check, and no deployment reads this template's registry. It replaces the three hand-named credential formats and the verify-probe enum with one declared shape: a credential's non-secret text is a `value.template` with exactly one `{secret}` placeholder (or no `value` when the plaintext is the secret itself), an optional `value.encode` drawn from the new `lib.credentialEncodings` export, and one `verify` command string per target. The public example credential is migrated to that shape. During the private migration a credential may still be wholly legacy (`format` plus structured `verify.type`), never a mixture, and the new `credential-registry` check enforces all of that with one sabotage witness per rule; `lib.forgejoTokenGroups` now validates at its export seam so a bad registry fails every consumer, not only `nix flake check`. Merge this after the archetypes PR (whose check must already accept the new example) and before the tools PR. If it is wrong, revert it: the legacy shape stays valid everywhere until the tools PR lands, and no ciphertext is touched. ## What changes - `flake.nix`: `lib.credentialEncodings = [ "rclone-obscure" ]` exported; `credentialRegistryDiagnostics` and `validateCredentialRegistry` implement the contract (exactly one `{secret}`, encoder membership, non-empty one-line `verify` on every target, at least one target per credential and one credential per group, legacy-or-new but never both on one credential, one encoding shared by a group's new-shape credentials); `lib.forgejoTokenGroups` is validated at the export seam. - `checks.<platform>.credential-registry`: validates the shipped registry, a positive legacy-plus-new coexistence fixture, a positive legacy-plus-encoded fixture, and one sabotage fixture per rule, each proven to trip only its own rule. - `forgejo-token-groups.json`: the public example moves from `format = "credential-store-url"` to `value.template` and a `verify` command, byte-identical to the example in allod/secrets#23. - `README.md`: the export table gains `lib.credentialEncodings` and the check; a "Forgejo credential registry schema" section states the contract, the coexistence rule, and the example verification commands that replace the former probe names. ## Risk R3 in the plan (shared secrets schema and transition compatibility). Residual after the check: a rule that accepts an input the tools renderer or archetypes consumer rejects, or the reverse; both consumers fail loud on such an entry, and the private registry is not read by this template. Rollback is a revert; legacy entries and `rotate-token` remain valid until the tools PR closes the issue. ## Validation - `nix flake check .` in the worktree (plain path per `nix.md`): ``all checks passed!`, exit 0` - `git diff --check`: `no output, exit 0` - Witness falsification for the two rules the review found vacuous (delete the rule, the sabotage passes; restore): `the check itself now asserts that each of its 20 sabotage fixtures produces exactly its own diagnostic, so a vacuous fixture is a red check; with the encoder rule removed it fails with `unexported-encoder wanted [value.encode is not an exported encoding] got []`, and likewise for the mix rule (worker-run, captured output read by the overseer). Export seam, run by the overseer: with `{secret}` removed from the public template, `nix eval .#lib.forgejoTokenGroups` exits 1 with `error: credential-registry: value.template must contain exactly one {secret}`; the file was restored byte-for-byte` - Cross-family cold reviews of the pre-fix diff: `claude-opus-5` through the `pi` runner on provider `nullsink-claude` at thinking `high` (2 blockers, 4 gaps, 1 simplify: vacuous encoder and mixed-shape sabotage fixtures, legacy credentials counted as an encoding, vacuous empty-targets acceptance, four unwitnessed guards, the unvalidated export, constant assertion messages) and ``claude-fable-5-1` as a fresh Claude Code subagent at default effort (2 blockers, 3 gaps, 1 simplify, 2 questions: the same two vacuous fixtures, no witness for a missing or multi-line `verify`, the legacy-encoding rule, an undocumented extra-fields rule, the unvalidated export, blank commands and empty targets, and the merge order)`. All accepted findings are fixed in this diff. The author of the original diff was a Codex model, so both reviewers are cross-family. - Not run: no private registry is evaluated here; the private migration is a separate handoff issue. Refs allod/secrets#23
A credential's non-secret text is value.template with exactly one {secret}
placeholder, or no value when the plaintext is the secret; value.encode is
drawn from the new lib.credentialEncodings export; each target carries one
verify command string. The credential-registry check enforces the contract
and the legacy-or-new coexistence rule with one sabotage fixture per rule,
each asserted to trip exactly its own diagnostic; lib.forgejoTokenGroups
validates at its export seam. The public example moves to the new shape.

Refs allod/secrets#23
vnprc approved these changes 2026-09-12 02:23:40 +01:00
vnprc merged commit 187c9e8f35 into master 2026-09-12 02:23:45 +01:00
vnprc deleted branch agent/secret-value-templates 2026-09-12 02:23:45 +01:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
allod/secrets!24
No description provided.