Skip to content

feat(core): TOFU signer-identity anchor with change detection - #53

Open
a-d-j-i wants to merge 1 commit into
mainfrom
feat/signer-identity-tofu
Open

a-d-j-i wants to merge 1 commit into
mainfrom
feat/signer-identity-tofu

Conversation

@a-d-j-i

@a-d-j-i a-d-j-i commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator

Pins the manifest signer on first install (TOFU) and treats a subsequent disagreement between the bootstrap config and the stored anchor as a manifest-level violation.

storage/manifest-store.js:

  • New IDB key 'active-identity' holding { signatureType, identity, enrolledAt }.
  • addLatest(manifest, signer) now writes the signer pair onto each trusted- manifest entry (signatureType, signerIdentity) and, atomically in the same tx, seeds active-identity on first write — can't leave the manifest and anchor out of sync on a crash.
  • New getActiveIdentity() with a cache mirror.

manifest-loader.js:

  • storeManifestFromResponse now resolves the anchor before verifying. Three paths:
    1. No anchor (first install) → trust config.identity, verify, store manifest + seed anchor atomically.
    2. Anchor present AND matches config → verify against the anchor (equivalent to current behavior).
    3. Anchor present AND disagrees with config → return MANIFEST_UNTRUSTED + reason='SIGNER_CHANGED' without fetching or verifying. Bootstrap-level identity swap is a rotation signal the user has to accept explicitly.
  • verifyManifestSignature receives the anchor identity (not the config), so a manifest signed by a different key than the pinned anchor also fails even when the config appears to agree.

@a-d-j-i
a-d-j-i added this pull request to stack #54 October 9, 2026 22:22
@a-d-j-i
a-d-j-i requested a review from a team as a code owner October 10, 2026 00:46
@a-d-j-i
a-d-j-i force-pushed the feat/signer-identity-tofu branch 4 times, most recently from c81c361 to 5b40058 Compare October 16, 2026 15:50
@a-d-j-i
a-d-j-i force-pushed the feat/signer-identity-tofu branch from 5b40058 to 8ffb698 Compare October 16, 2026 18:48
Base automatically changed from refactor/verification-status-shortcut to main October 19, 2026 16:47
Pins the manifest signer on first install (TOFU) and treats a subsequent
disagreement between the bootstrap config and the stored anchor as a
manifest-level violation.

storage/manifest-store.js:
- New IDB key 'active-identity' holding
  { signatureType, identity, enrolledAt }.
- addLatest(manifest, signer) now writes the signer pair onto each trusted-
  manifest entry (signatureType, signerIdentity) and, atomically in the
  same tx, seeds active-identity on first write — can't leave the manifest
  and anchor out of sync on a crash.
- New getActiveIdentity() with a cache mirror.

manifest-loader.js:
- storeManifestFromResponse now resolves the anchor before verifying.
  Three paths:
    1. No anchor (first install) → trust config.identity, verify, store
       manifest + seed anchor atomically.
    2. Anchor present AND matches config → verify against the anchor
       (equivalent to current behavior).
    3. Anchor present AND disagrees with config → return
       MANIFEST_UNTRUSTED + reason='SIGNER_CHANGED' without fetching or
       verifying. Bootstrap-level identity swap is a rotation signal the
       user has to accept explicitly.
- verifyManifestSignature receives the anchor identity (not the config),
  so a manifest signed by a different key than the pinned anchor also
  fails even when the config appears to agree.
@a-d-j-i
a-d-j-i force-pushed the feat/signer-identity-tofu branch from 8ffb698 to 17ea1dc Compare October 19, 2026 16:47

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant