Skip to content

fix(auth): maintain native verification state - #8845

Open
iscekic wants to merge 10 commits into
mainfrom
drain/native-code-state
Open

iscekic wants to merge 10 commits into
mainfrom
drain/native-code-state

Conversation

@iscekic

@iscekic iscekic commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Evidence

Evidence: demonstrated — local dev web app with local PostgreSQL at head 55bed42ed: the native code request and code exchange routes were driven over HTTP with a non-production admission sentinel and the local email outbox, and the observed results are listed under Verification.

Change

  • Use dedicated persisted state for each supported native verification mode.
  • Apply one wrong-guess allowance per issued code across both modes: a wrong guess is refused once the combined count reaches the allowance, and each failure is recorded against the mode it arrived in.
  • Add one additive database migration for the new counter column, generated on current main at the next free index (0302), plus behavioral regression coverage.
  • Preserve existing response values, compatibility support, telemetry, and the planned compatibility-removal note.

Verification

  • The full migration chain applied in order to an empty database from this head, and drizzle-kit check reports a consistent journal and snapshot set; the generated DDL is a single additive column at index 0302.
  • Native auth route suites on this head: 432 tests passed, including the cross-mode allowance cases (sequential mixed-mode wrong guesses, and twenty concurrent mixed-mode wrong guesses) and both settlement cases.
  • HTTP against the local dev app and local PostgreSQL, one challenge row per request:
    • A code request returned a challenge identifier and wrote the code email to the local outbox.
    • Three wrong guesses with the challenge and two without each returned 401 INVALID_CODE; the persisted counters then read 3 and 2 for that code.
    • The next wrong guess returned 429 TOO_MANY_ATTEMPTS in either mode.
    • The correct code then verified with its challenge and returned access plus refresh credentials.
    • Five wrong guesses without a challenge left the challenge mode open: the correct code with its challenge verified and returned credentials.
    • Five wrong guesses with the challenge left that mode exhausted for the correct code (429 TOO_MANY_ATTEMPTS) while the code still settled through the other mode.
    • A consumed code replayed as 401 INVALID_CODE, and a code presented without a challenge settled and returned credentials.
  • Web-shared package type check, targeted lint, formatting, and git diff --check: passed.

This is a nonvisual backend change. Live email delivery, production firewall configuration, and platform attestation were not exercised; development admission was used only with local fixtures.

Production prerequisites

None.

Proxy answers

The owner's proxy gave these answers in the owner's place.

  1. Question: Policy scope: Source confirms optional-challenge compatibility is intentional, and issuance already calls the email firewall limiter. Approve the scoped plan: retain both verification modes, give each its own five-failure counter, add legacy_attempts defaulting to zero while retaining historical attempts, and leave issuance/resend policy unchanged?
    Answer: Approve scoped compatibility plan
    Confidence: 0.86 · Precedent: Autonomy: make executive decisions yourself with "is this reasonable?" as the test; the plan matches the brief, and the pull request is merge-by-human for auth and database changes.
  2. Question: Inherited CI: The PR's verify job fails on two pre-existing operator-assignment lint errors in the supported browser extension, introduced on main before this branch. No upstream correction exists for that file. Approve a separate two-line changed ||= nested.changed cleanup so this PR can obtain green CI?
    Answer: Apply minimal CI cleanup
    Confidence: 0.80 · Precedent: Fix a gap or error even when it is not the current task, and a work item must converge.
  3. Question: Guess budget: should the single wrong-guess allowance also cover a submission carrying the correct code, or only wrong guesses, given that a correct code must still verify when the other mode spent the allowance?
    Answer: Combined cap on wrong guesses only (Recommended)
    Confidence: 0.70 · Precedent: Keep one allowance without denying the legitimate holder or breaking shipped compatibility clients.

@iscekic iscekic added drain Work item from the findings drain janitor:trust Janitor finding: trust boundary hardening labels Oct 23, 2026
Comment thread packages/web-shared/src/lib/auth/magic-link-tokens.ts
@kilo-code-bot

kilo-code-bot Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The follow-up commit adds the missing legacy_attempts migration at index 0302 with a matching snapshot and journal entry, resolving the previously flagged schema/migration gap; the diff contains only generated migration artifacts that match packages/db/src/schema.ts:5062.

Assumptions: [INFERENCE] The deploy pipeline runs the Drizzle migrator before promotion, as the PR description states; the additive NOT NULL DEFAULT 0 column on magic_link_tokens is metadata-only on PostgreSQL 11+ and does not rewrite the table. Migration artifacts were not executed in this read-only review; correctness was verified by comparing the SQL, snapshot delta, and journal chain against the schema.

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 0
Files Reviewed (6 files)
  • packages/db/src/migrations/0302_harsh_silhouette.sql - 0 issues (single additive ADD COLUMN legacy_attempts integer DEFAULT 0 NOT NULL, matches schema)
  • packages/db/src/migrations/meta/0302_snapshot.json - 0 issues (generated; delta from 0301 is only the new column plus chained id/prevId)
  • packages/db/src/migrations/meta/_journal.json - 0 issues (idx 302 follows 301, tag matches SQL file)
  • packages/db/src/schema.ts - 0 issues (previous finding resolved: migration now exists)
  • packages/web-shared/src/lib/auth/magic-link-tokens.ts - 0 issues (targeted re-check: shared attempts + legacy_attempts bound present at lines 210 and 247)
  • packages/web-shared/src/lib/auth/magic-link-tokens.test.ts - 0 issues
Previous Review Summaries (6 snapshots, latest commit 571a0d1)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 571a0d1)

Status: 1 Issues Found | Recommendation: Address before merge

Executive Summary

The revised shared wrong-guess allowance fixes the previously flagged split-budget issue, but the merge with main dropped the only migration for legacy_attempts, so the schema and runtime now reference a column the deploy pipeline will never create.

Assumptions: [INFERENCE] The deploy pipeline applies only the committed Drizzle migrations (as the PR description states); if legacy_attempts is created out-of-band in production the outage would not occur. The earlier in-thread WARNING about two independent per-mode allowances is resolved by the new attempts + legacy_attempts bound.

Overview

Severity Count
CRITICAL 1
WARNING 0
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
packages/db/src/schema.ts 5062 legacy_attempts is declared in the schema but no migration adds it: the branch's additive migration was dropped during the final merge with main and never regenerated. _journal.json ends at 0301_contributor_credit_window and meta/0301_snapshot.json has no legacy_attempts, while reserveSignInCode selects the full row and evaluates magic_link_tokens.legacy_attempts, so native sign-in code verification fails with "column does not exist". Regenerate on current main at index 0302 with SQL, snapshot, and journal.
Files Reviewed (3 files)
  • packages/db/src/schema.ts - 1 issue
  • packages/web-shared/src/lib/auth/magic-link-tokens.ts - 0 issues
  • packages/web-shared/src/lib/auth/magic-link-tokens.test.ts - 0 issues

Fix these issues in Kilo Cloud

Previous review (commit 4f0839e)

Status: 1 Issues Found | Recommendation: Address before merge

Executive Summary

The change's only substantive concern remains the split per-mode guess budget: one live sign-in code now carries two independent five-failure counters, so the same row admits up to ten wrong guesses; the migration renumber and snapshot regeneration are otherwise clean.

Assumptions: [INFERENCE] Issuance-side and email-firewall rate limiting were not re-read in full; the doubled per-code budget assumes those do not also cap wrong guesses per code. The per-mode counter split is described in the PR as an owner-approved policy decision, so the WARNING is carried forward for the human merge decision rather than as a new blocking finding.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/web-shared/src/lib/auth/magic-link-tokens.ts 170 Choosing the counter from challengeId gives one live sign-in code two independent five-guess allowances (attempts and legacy_attempts), so the same row admits up to ten wrong guesses instead of one five-guess cap; when one mode is exhausted, switching modes yields a fresh budget for the same code. The new serializes verification counters test asserts attempts: 5 and legacy_attempts: 5 on the same row, confirming the behavior. Already raised inline; the author declined in-thread citing the owner-approved per-mode contract, so it is carried forward only for the human merge decision.
Files Reviewed (6 files)
  • packages/db/src/migrations/0300_flaky_magdalene.sql - 0 issues (additive ADD COLUMN ... DEFAULT 0 NOT NULL; constant default is metadata-only on PostgreSQL, no table rewrite)
  • packages/db/src/migrations/meta/0300_snapshot.json - 0 issues (generated; prevId matches the 0299 snapshot id, and a normalized diff against 0299 shows only the added legacy_attempts column)
  • packages/db/src/migrations/meta/_journal.json - 0 issues (generated; idx/tag 0300_flaky_magdalene consistent with the SQL file and snapshot)
  • packages/db/src/schema.ts - 0 issues (legacy_attempts default/notNull match the migration and snapshot)
  • packages/web-shared/src/lib/auth/magic-link-tokens.test.ts - 0 issues
  • packages/web-shared/src/lib/auth/magic-link-tokens.ts - 1 issue (carried forward from the active inline comment)

Previous review

Status: 1 Issues Found | Recommendation: Address before merge

Executive Summary

The sign-in code still splits one live code's five-guess budget into two independent five-guess counters, so the same row admits up to ten wrong guesses; all other changes since the prior review are a clean migration renumber and a merge from main.

Assumptions: [INFERENCE] Issuance-side rate limiting and the email firewall limiter were not re-read in full; the doubled per-code budget assumes those do not also cap wrong guesses per code. The per-mode counter split is an owner-approved policy decision per the PR, so the WARNING is carried forward for the human merge decision.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/web-shared/src/lib/auth/magic-link-tokens.ts 170 Selecting the counter from challengeId gives one live sign-in code two independent five-guess allowances (attempts and legacy_attempts), so the same row admits up to ten wrong guesses instead of one five-guess cap. Previously raised inline; the author declined in-thread citing the owner-approved per-mode contract. The new serializes verification counters test asserts attempts: 5 and legacy_attempts: 5 on the same row, confirming the behavior.
Files Reviewed (6 files)
  • packages/db/src/migrations/0300_flaky_magdalene.sql - 0 issues (additive ADD COLUMN ... DEFAULT 0 NOT NULL; constant default is metadata-only on PostgreSQL)
  • packages/db/src/migrations/meta/0300_snapshot.json - 0 issues (generated; legacy_attempts present and prevId matches the 0299 snapshot id)
  • packages/db/src/migrations/meta/_journal.json - 0 issues (generated; idx/tag 0300_flaky_magdalene consistent)
  • packages/db/src/schema.ts - 0 issues
  • packages/web-shared/src/lib/auth/magic-link-tokens.test.ts - 0 issues
  • packages/web-shared/src/lib/auth/magic-link-tokens.ts - 1 issue (carried forward from the active inline comment)

Fix these issues in Kilo Cloud

Previous review (commit 9906fec)

Status: 1 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/web-shared/src/lib/auth/magic-link-tokens.ts 170 Selecting the attempt counter from challengeId gives one live sign-in code two independent five-guess allowances (attempts and legacy_attempts), so the same row admits up to ten wrong guesses instead of one five-guess cap. Previously raised inline; the author declined in-thread citing the owner-approved per-mode contract. Included for the human merge decision.
Files Reviewed (6 files)
  • packages/db/src/migrations/0299_cynical_retro_girl.sql - 0 issues (additive ADD COLUMN ... DEFAULT 0 NOT NULL; metadata-only on PostgreSQL)
  • packages/db/src/migrations/meta/0299_snapshot.json - 0 issues (generated; legacy_attempts and prevId match 0298)
  • packages/db/src/migrations/meta/_journal.json - 0 issues (generated; idx/tag 0299_cynical_retro_girl consistent)
  • packages/db/src/schema.ts - 0 issues
  • packages/web-shared/src/lib/auth/magic-link-tokens.test.ts - 0 issues
  • packages/web-shared/src/lib/auth/magic-link-tokens.ts - 1 issue (carried forward from the active inline comment)

Previous review

Status: 1 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/web-shared/src/lib/auth/magic-link-tokens.ts 170 Selecting the counter from challengeId gives one live sign-in code two independent five-guess allowances (attempts and legacy_attempts), so the same row admits up to ten wrong guesses instead of one five-guess cap. Previously raised inline; the author declined in-thread citing the owner-approved per-mode contract. Included for the human merge decision.
Files Reviewed (6 files)
  • packages/db/src/migrations/0299_cynical_retro_girl.sql - 0 issues (additive ADD COLUMN ... DEFAULT 0 NOT NULL; metadata-only on PostgreSQL)
  • packages/db/src/migrations/meta/0299_snapshot.json - 0 issues (generated; legacy_attempts and prevId match 0298)
  • packages/db/src/migrations/meta/_journal.json - 0 issues (generated; idx/tag 0299_cynical_retro_girl consistent)
  • packages/db/src/schema.ts - 0 issues
  • packages/web-shared/src/lib/auth/magic-link-tokens.test.ts - 0 issues
  • packages/web-shared/src/lib/auth/magic-link-tokens.ts - 1 issue (carried forward from the active inline comment)

Previous review

Status: 1 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/web-shared/src/lib/auth/magic-link-tokens.ts 170 Splitting the attempt counter by challengeId presence gives one sign-in code two independent 5-attempt allowances, so the same live row can be guessed ten times and is never locked out across modes; the removed R6 test guarded the previous single-cap invariant. Consider bounding attempts + legacy_attempts instead of each column separately.
Files Reviewed (7 files)
  • apps/extension/src/shared/browser-tool-redaction.ts - 0 issues
  • packages/db/src/migrations/0297_public_pepper_potts.sql - 0 issues
  • packages/db/src/migrations/meta/0297_snapshot.json - 0 issues (generated)
  • packages/db/src/migrations/meta/_journal.json - 0 issues (generated)
  • packages/db/src/schema.ts - 0 issues
  • packages/web-shared/src/lib/auth/magic-link-tokens.test.ts - 0 issues
  • packages/web-shared/src/lib/auth/magic-link-tokens.ts - 1 issue

Fix these issues in Kilo Cloud


Reviewed by deepseek-flash-latest · Input: 46.2K · Output: 4.4K · Cached: 429.4K

Review guidance: REVIEW.md from base branch main

@iscekic iscekic added merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head merge:human Substantive functional risk requires human review. merge:blocked:judge-unavailable Risk assessment unavailable merge:bot Bot-owned review; merge when ready once readiness passes and a review approves. and removed merge:human Substantive functional risk requires human review. merge:blocked:judge-unavailable Risk assessment unavailable merge:bot Bot-owned review; merge when ready once readiness passes and a review approves. labels Oct 23, 2026
# Conflicts:
#	packages/db/src/migrations/meta/0297_snapshot.json
#	packages/db/src/migrations/meta/_journal.json
@iscekic iscekic added needs:prod-action Prod prerequisite (env var, secret, firewall rule, config) needed before merge merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head merge:human Substantive functional risk requires human review. and removed merge:human Substantive functional risk requires human review. merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head labels Oct 24, 2026
Regenerate the additive schema migration at the next free sequence number so it
does not collide with the migration main added.
@iscekic iscekic added merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head merge:human Substantive functional risk requires human review. and removed merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head merge:human Substantive functional risk requires human review. labels Oct 24, 2026
@iscekic iscekic removed the merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head label Oct 24, 2026
@iscekic iscekic added merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head merge:human Substantive functional risk requires human review. and removed merge:human Substantive functional risk requires human review. labels Oct 24, 2026
@iscekic iscekic removed merge:human Substantive functional risk requires human review. merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head labels Oct 24, 2026
@iscekic

iscekic commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

Changes requested: keep one wrong-guess budget per sign-in code, and renumber the migration.

  • reserveSignInCode (packages/web-shared/src/lib/auth/magic-link-tokens.ts) now gives each mode its own cap of 5. POST /api/auth/native/otp returns the challenge id to the requester, so one caller can make 5 guesses with it and 5 without it. That is 10 guesses per issued code instead of 5.
  • Keep both counters, but also reject a reservation when attempts + legacy_attempts >= 5. Apply this in the pre-check and in the reservation guard.
  • Restore a test equivalent to the removed R6: guesses across both modes together stop at 5 for one code.
  • fix(kilo-mcp): require the confirmed client for a device pairing #8534 is in the merge queue with migration 0300. After it lands, merge main and regenerate this migration at the next free number.
  • Fix the PR body's production prerequisites section so that it reads exactly None. if no manual step is needed.

@iscekic iscekic added merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head merge:human Substantive functional risk requires human review. labels Oct 24, 2026
@iscekic

iscekic commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

Changes requested: renumber the migration again. It collides with main.

@iscekic iscekic removed merge:human Substantive functional risk requires human review. merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head labels Oct 24, 2026
Comment thread packages/db/src/schema.ts
@iscekic iscekic added merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head merge:human Substantive functional risk requires human review. labels Oct 24, 2026
@iscekic

iscekic commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

bot: Applied in 571a0d11c.

  • One wrong-guess allowance per issued code across both modes: a wrong guess is refused once the combined counted failures reach the allowance, checked before the code comparison resolves and again in the increment guard. Each failure is still recorded against the mode it arrived in, so both counters stay meaningful.
  • The correct code is accepted unless the mode it arrives in has itself spent the allowance, so one mode cannot deny the holder through the other.
  • Restored the cross-mode test: three wrong guesses with a challenge plus two without stop the next wrong guess in either mode at the allowance, with counters 3 and 2, and the correct code still settles. A concurrent mixed-mode test covers the same property under a race (five counted, the rest refused).
  • Migration regenerated at the next free index; see the renumber reply.

@iscekic

iscekic commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

bot: Renumbered in 24f377b9f.

  • Merged current main, kept main's journal and snapshots, and regenerated this branch's additive migration at 0302 (0302_harsh_silhouette.sql); the earlier branch migration file and its metadata are gone.
  • Applied the full migration chain in order from an empty database, and drizzle-kit check reports a consistent journal and snapshot set. The generated DDL is one additive column.
  • If another pull request takes 0302 first, I will merge main again and regenerate at the next free index.

@iscekic iscekic added merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head merge:human Substantive functional risk requires human review. and removed merge:blocked:kilobot-not-ready Review bot has not recommended merge at this head merge:human Substantive functional risk requires human review. labels Oct 24, 2026
@iscekic

iscekic commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

bot: Correction to the renumber reply's commit reference: the migration file, its snapshot, and the journal entry landed in 55bed42ed, after the merge commit. The functional change is in 571a0d11c. Verification in the body ran at 55bed42ed.

@iscekic iscekic removed the needs:prod-action Prod prerequisite (env var, secret, firewall rule, config) needed before merge label Oct 24, 2026

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

drain Work item from the findings drain janitor:trust Janitor finding: trust boundary hardening merge:human Substantive functional risk requires human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant