Skip to content

fix(biometric-puzzles): wire FacePuzzle + HandGesturePuzzle to server validation (Bug 4, 2026-05-12)#90

Closed
ahmetabdullahgultekin wants to merge 6 commits into
mainfrom
fix/2026-05-12-liveness-and-puzzles
Closed

fix(biometric-puzzles): wire FacePuzzle + HandGesturePuzzle to server validation (Bug 4, 2026-05-12)#90
ahmetabdullahgultekin wants to merge 6 commits into
mainfrom
fix/2026-05-12-liveness-and-puzzles

Conversation

@ahmetabdullahgultekin

Copy link
Copy Markdown
Contributor

Summary

Closes Bug 4 (P1) from the 2026-05-12 ML review. The biometric-puzzles training surface (/biometric-puzzles) called onSuccess() purely client-side after local MediaPipe detection — anyone could mock the component and pass any challenge. Now every completion is round-tripped through /biometric/puzzles/verify-challenge for structural validation, and onSuccess only fires on server-200.

  • New hook useBiometricPuzzleServer posts the challenge result.
  • New mapper puzzleServerAction translates web enums → server ChallengeType strings.
  • FacePuzzle.tsx + HandGesturePuzzle.tsx await server validation, show "Verifying with server…" Alert, then resolve onSuccess/onError.
  • 3 new i18n keys in en.json + tr.json (no hardcoded strings).
  • 24 new vitest assertions in __tests__/puzzleServerAction.test.ts pinning every face + hand mapping.

Companion biometric-processor PR adds the /liveness/verify-challenge route: Rollingcat-Software/biometric-processor#102

Graceful degradation

The identity-core-api proxy /biometric/puzzles/verify-challenge is NOT in this PR (it lives in another repo with unrelated in-flight work). To keep the training UI functional during rollout, the hook catches HTTP 404 and soft-passes with a one-shot console warning. Operator action: add the proxy when ready; soft-pass stops being exercised at that point.

Test plan

  • npx tsc --noEmit — clean
  • npx vitest run src/features/biometric-puzzles/__tests__/puzzleServerAction.test.ts — 24 pass
  • npx vitest run src/features/biometric-puzzles — 28 pass / 1 pre-existing PeekABoo failure (unrelated)
  • Operator: land biometric-processor PR fix(web): surface swallowed voice-enrollment + OTP-exhausted errors (F13, F9) #102
  • Operator: add identity-core-api proxy route POST /api/v1/biometric/puzzles/verify-challenge
  • Operator: deploy web-app; verify server validation engages

🤖 Generated with Claude Code

… validation

Closes Bug 4 (P1) from the 2026-05-12 ML review: the biometric-puzzles
training surface called `onSuccess()` purely client-side after local
MediaPipe detection. Anyone could mock the component and "pass" any
challenge — no audit trail, no server-side structural sanity checks.

Wiring
------
* New hook `useBiometricPuzzleServer` posts a single completed challenge
  to `/biometric/puzzles/verify-challenge` (identity-core-api proxy →
  biometric-processor `/liveness/verify-challenge`). Only a server-200
  with `verified=true` resolves the puzzle. Other outcomes surface via
  `formatApiError` + `t()` per `feedback_no_hardcode`.
* New mapper `puzzleServerAction` translates the web's local enums
  (ChallengeType for face, BiometricPuzzleId for hand) into the
  lower_snake_case ChallengeType strings the server enum expects.
  Local variants without a 1:1 server counterpart (CLOSE_LEFT/RIGHT,
  LOOK_UP/DOWN, individual brow raises, NOD, SHAKE_HEAD,
  HAND_TRACE_TEMPLATE) return `null` from the mapper and the puzzle
  resolves locally — the server can't express those challenges today.
* `FacePuzzle.tsx` + `HandGesturePuzzle.tsx`: on local completion, set
  `serverVerifying=true`, await the server round-trip, then `onSuccess`
  or `onError` based on the verdict. Visual: an "Verifying with server…"
  Alert appears between local-pass and server-verdict.
* i18n: 3 new keys (`verifyingServer`, `serverRejected`, `serverError`)
  added to en.json + tr.json — no hardcoded strings.

Graceful degradation
--------------------
The companion biometric-processor PR added the `/liveness/verify-challenge`
route, but the identity-core-api proxy at `/biometric/puzzles/verify-challenge`
is NOT included in this PR (it lives in another repo and that repo currently
has unrelated in-flight work). To keep the training UI functional during
rollout, `useBiometricPuzzleServer` catches HTTP 404 from the proxy path,
logs a one-shot console warning describing the operator action needed,
and resolves the puzzle as a soft-pass. Once the proxy lands, the
soft-pass path stops being exercised.

Tests
-----
* `puzzleServerAction.test.ts` — 24 assertions pinning every face + hand
  mapping (happy paths) and explicitly checking the unmapped variants
  return null (regression guard).
* Type-check: `npx tsc --noEmit` clean.
* `vitest run src/features/biometric-puzzles` — 28 pass / 1 pre-existing
  PeekABoo-detector failure unrelated to this PR.

Operator action items
---------------------
1. Land the matching `biometric-processor` PR (fix/2026-05-12-liveness-and-puzzles).
2. Add the identity-core-api proxy route `POST /api/v1/biometric/puzzles/verify-challenge`
   that forwards to biometric-processor `/liveness/verify-challenge` (mirrors
   the existing `BiometricServiceAdapter.generateLivenessPuzzle` pattern).
3. Deploy web-app. With the proxy in place, server validation engages
   automatically; without it, the soft-pass console warning fires.

Memory rules respected
----------------------
* `feedback_no_hardcode`: every user-facing string is `t()`'d with keys
  in en.json + tr.json. No English literals shipped.
* `feedback_spoof_detector_architecture`: algorithms still live in
  spoof-detector / biometric-processor; this PR is pure plumbing.
* `feedback_git_push`: bare `git push`, no `2>&1`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 12, 2026 17:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@ahmetabdullahgultekin

Copy link
Copy Markdown
Contributor Author

Merge order note (2026-05-12)

This PR depends on two upstream PRs that must merge first to avoid 404-soft-pass mode:

  1. shim: expose BlinkAnalyzer + compute_ear via spoof_detector public namespace spoof-detector#18 — exposes BlinkAnalyzer + compute_ear shim
  2. fix(verify): enforce anti-spoof block + EAR + aged-threshold + SHA-pin + verify-challenge (2026-05-12 ML review) biometric-processor#102 — adds POST /api/v1/liveness/verify-challenge
  3. This PR (web-app fix(biometric-puzzles): wire FacePuzzle + HandGesturePuzzle to server validation (Bug 4, 2026-05-12) #90) — calls the new endpoint via useBiometricPuzzleServer hook

The identity-core-api proxy (POST /api/v1/biometric/puzzles/verify-challenge) is a follow-up. Until it lands, puzzle calls 404 → soft-pass + one-time console.warn. User-visible behavior unchanged. Tracking as item 10 in parent Rollingcat-Software/FIVUCSAS#67 OPERATOR_ACTIONS_2026-05-12.md.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

ahmetabdullahgultekin and others added 4 commits May 18, 2026 09:43
…sas.com root

Source for the verify-widget html/index.html landing block that was deployed
to verify.fivucsas.com today. main.tsx flips data-mounted="true" on first
paint so the static landing hides for iframe/OAuth consumers without flash;
direct visitors and crawlers see brand, 3 method cards, 10 auth-method
pills, integration snippet, footer. Robots lifted to "index, follow";
description + canonical + og + twitter + JSON-LD SoftwareApplication added.
/login behaviour unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a "FIVUCSAS suite" footer block above the existing status tile
with pill links to fivucsas.com / Demo / Widget / amispoof, and turns
the status tile itself into a clickable link to status.fivucsas.com.
Closes the navigation gap supervisor flagged — previously the dashboard
had zero outbound link to landing or sister sites.

i18n keys added to en.json + tr.json (sidebar.suite + sidebar.suite{Home,Demo,Widget}).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…at build

The verify build sets root=src/verify-app, so Vite's envDir defaulted there
(no .env present) and VITE_API_BASE_URL was undefined at build time. Since
PR #62 centralized that var behind src/config/env.ts which throws at module
load when it's unset, the verify bundle crashed on boot and React never
mounted — verify.fivucsas.com/login showed only the static landing for ~11
days. Point envDir at the project root so .env.production is loaded like the
other builds.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… error

A direct top-level visit to verify.fivucsas.com (root, no params) mounted
VerifyApp, which renders a "missing parameters" Error alert with no
session/client context — so visitors saw an error. Only mount React when
there's a real surface (hosted /login, a framed widget, or a widget invoked
with params); otherwise leave the static #verify-landing visible. Verified
live: root → landing (no error), /login → mounts, ?session_id → widget.
@ahmetabdullahgultekin

Copy link
Copy Markdown
Contributor Author

Superseded — closing. The biometric-puzzle liveness issue this PR targeted (Bug 4, 2026-05-12) is resolved on main by the 2026-06-02 P1 batch (PR #188): the fail-closed passive-liveness gate in FacePuzzle now soft-passes a null verdict (the active gesture proves liveness), and the verify-surface BlazeFace/CSP + favicon were fixed there too. This branch's server-validation routes remained unshipped/soft-pass-on-404 and the branch is 3+ weeks stale + conflicts with the merged work. Reopen/rebase if the server-side puzzle-verify endpoints are ever shipped.

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.

2 participants