Skip to content

refactor(passkey): derive the policy codes by subtraction so additions break the build - #145

Open
Bccorb wants to merge 1 commit into
mainfrom
refactor/passkey-policy-code-drift
Open

refactor(passkey): derive the policy codes by subtraction so additions break the build#145
Bccorb wants to merge 1 commit into
mainfrom
refactor/passkey-policy-code-drift

Conversation

@Bccorb

@Bccorb Bccorb commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

What

PasskeyPolicyErrorCode in src/client/errors.ts already came from
@seamless-auth/types 0.16.0 (WebAuthnErrorCode), and the dependency is
already on ^0.16.0, so the switch the AGENTS.md note asked for had landed. What
had not landed is the property the note wanted from it.

Extract<WebAuthnErrorCode, 'attachment_not_allowed' | ...> catches a rename or
a removal upstream, since the missing name resolves to never. It misses an
addition: a code added to WebAuthnErrorCode is simply not extracted,
PASSKEY_POLICY_ERROR_CODES still compiles, and the SDK quietly degrades the new
refusal to generic messaging. That is the silent drift the union exists to
prevent.

This takes the union minus prf_output_not_allowed instead. A new upstream code
lands in PasskeyPolicyErrorCode, and both Records over it fail to compile
until it is handled or excluded deliberately.

Confirmed by temporarily adding a member to the installed
WebAuthnErrorCodeSchema declaration and running npm run typecheck:

src/client/errors.ts(116,7): error TS2741: Property 'hypothetical_new_code' is missing in type '{ attachment_not_allowed: true; ... }' but required in type 'Record<PasskeyPolicyErrorCode, true>'.
src/views/PassKeyRegistration.tsx(19,7): error TS2741: Property 'hypothetical_new_code' is missing in type '{ attachment_not_allowed: string; ... }' but required in type 'Record<PasskeyPolicyErrorCode, string>'.

The second one is the point: an addition forces the user-facing copy in
POLICY_REFUSAL_MESSAGES to be written too, not just the recognition list.

prf_output_not_allowed stays out

The published union includes it, and getPasskeyPolicyErrorCode() should not
recognize it. In the API it is a 400 from login finish and step-up finish
(webauthn.ts verifyWebAuthn, stepUp.ts finishWebAuthnStepUp), never from
registration. It reports a caller that failed to strip PRF output, not a
deployment refusing an authenticator, so reporting it as a policy refusal would
point an integrator at their configuration for what is a bug in their own code.
tests/errors.test.ts already asserts it is ignored.

Docs

The AGENTS.md paragraph claiming the types package publishes no such union and
that the list is a local copy is replaced with what the code now does, including
why the type is derived by subtraction rather than by listing the wanted names.

Checks

  • npm run typecheck clean
  • npm run lint clean
  • npm run format:check clean
  • npm test 32 suites, 319 tests, all passing

No changeset: the type resolves to the same four members and no runtime
behaviour or public type changes.

…s break the build

PasskeyPolicyErrorCode already came from @seamless-auth/types 0.16.0, but it
picked its four members out of WebAuthnErrorCode with Extract. That catches a
rename or a removal upstream, since the name resolves to never, and misses the
case the check exists for: a code added to WebAuthnErrorCode is simply not
extracted, PASSKEY_POLICY_ERROR_CODES still compiles, and the SDK quietly
degrades the new refusal to generic messaging.

Take the union minus prf_output_not_allowed instead. A new code lands in
PasskeyPolicyErrorCode, and both Record maps over it, the recognition list here
and POLICY_REFUSAL_MESSAGES in PassKeyRegistration, fail to compile until it is
handled or excluded on purpose.

prf_output_not_allowed stays out. It is a 400 from login and step-up finish
(webauthn.ts verifyWebAuthn, stepUp.ts finishWebAuthnStepUp), reporting a caller
that failed to strip PRF output rather than a deployment refusing an
authenticator, so getPasskeyPolicyErrorCode should not report it as a policy
refusal.

The type resolves to the same four members, so no behaviour changes and no
changeset is needed.
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