Skip to content

passkey support - #29

Merged
code-hustler-ft3d merged 5 commits into
code-hustler-ft3d:mainfrom
rundelac:main
Sep 14, 2026
Merged

code-hustler-ft3d merged 5 commits into
code-hustler-ft3d:mainfrom
rundelac:main

Conversation

@jpike88

@jpike88 jpike88 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

What this PR does

This PR adds support for passkey dialog flow detection. It just presses authenticate, and leaves the user to use their passkey authentication, which on success will log the user in.

Checklist

  • make clean && make && make test passes (full unit suite green)
  • No credentials, account numbers, or PII in the diff
  • CHANGELOG.md updated under the next version's heading
  • docs/OBSERVABILITY.md updated (if touching ALERT tokens, /health, or env vars listed there)
  • docs/FROM_IBC.md updated (if changing anything that maps to an IBC key)
  • docs/UPGRADING.md gets a new ### vX.Y.Z section if the change is operator-visible
  • Commit messages imperative ("fix X", not "fixed X" or "WIP")

See CONTRIBUTING.md for the
"Adding a new..." walkthroughs covering the most common extension
points (ALERT tokens, dialog handlers, env vars, IBC-key mappings).

@jpike88
jpike88 marked this pull request as draft September 8, 2026 04:19
@jpike88 jpike88 changed the title passkey support passkey support - I AM STILL CONFIRMING IT WORKS Sep 8, 2026
@jpike88

jpike88 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

@code-hustler-ft3d can you please confirm this script works for your existing 2fa flow... (I am using passless to provide the passkey virtual device). I have confirmed that it works for me

@jpike88 jpike88 changed the title passkey support - I AM STILL CONFIRMING IT WORKS passkey support Sep 8, 2026
@jpike88
jpike88 marked this pull request as ready for review September 8, 2026 04:59
code-hustler-ft3d added a commit that referenced this pull request Sep 11, 2026
Builds on jpike88's passkey handling (PR #29) without altering its
mechanics. Four additions:

Opt-in gate. PASSKEY_AUTHENTICATE (default unset = off). With it unset,
a passkey prompt in the Second Factor dialog still fails loudly, using
the exact reason string v0.8.1 emits for the browser-window variant so
existing monitors keep matching, now with a remediation= hint pointing
at the flag. Every existing flow is byte-for-byte unchanged unless the
operator opts in. Off by default because the maintainer has no passkey
account to verify against; the contributor does, and uses it in
production.

Flow tests. tests/test_pure_logic.py drives the real handle_2fa with a
mock agent in the configurations that matter: TOTP dialog with the gate
on and off (code still typed, Authenticate never pressed), passkey
dialog with and without a TOTP secret (Authenticate pressed, nothing
typed), gate off on a passkey dialog (fails loud, touches nothing), and
the IB Key push loop with a normal dialog (left alone, success via the
API port) -- the path the issue #23 reporter and every IB Key user runs.
Each asserts the handler was actually consulted rather than bypassed.
Plus the pure helper and the env parsing. 13 new tests; 335 pass.

Docs. README reframes the passkey paragraph from "not supported" to
"the controller presses Authenticate, you supply the authenticator",
marked as contributor-validated; OBSERVABILITY gains the new
ALERT_2FA_FAILED reason and the env var; UPGRADING gets an entry.

Changelog. The one-line entry was inside [0.9.0], which shipped on
2026-09-07; it moves to a new [Unreleased] section with a full entry
crediting the contributor, including the latent IB Key bug the PR
fixed in the post-relogin loop.

Also a comment at the point where the handler returns True on an
accepted click, spelling out that this reports 2FA success before the
ceremony completes and that a never-answering authenticator surfaces as
the API-port wait timing out.
@code-hustler-ft3d

code-hustler-ft3d commented Sep 11, 2026

Copy link
Copy Markdown
Owner

Thanks — and to answer your question directly: yes, it leaves the existing 2FA flows intact. I didn't want to say that from reading alone, so I drove the real handle_2fa against a mock agent on your commit (4f8047b). Four cases, sixteen assertions, all green, each also asserting your handler actually ran rather than being bypassed:

Your full suite passes on that commit too (322). And the code is careful in ways I appreciated: no new agent commands, no coordinates, refusing an ambiguous multi-window match, re-reading the dialog before the raw-name retry, stripping CR/LF because the protocol is line-oriented. You also fixed a latent bug of ours — the post-relogin loop would have called the TOTP generator with an empty secret in IB Key mode.

On scope: this is the arrangement I said in #22 I'd revisit if someone got an out-of-tree signer working. You did, with passless. Pressing Authenticate and leaving the ceremony to your authenticator is driving Gateway's dialog, not holding a key. I'm in.

What I've added rather than ask you to do, on pr29/followups in this repo, on top of your three commits:

  1. An opt-in gate, PASSKEY_AUTHENTICATE=yes. With it unset, a passkey prompt fails loudly with the same reason string v0.8.1 emits (plus a remediation= hint), so every existing deployment is byte-for-byte unchanged. I'm adding this because I have no passkey account to verify against — you do — and it makes the ⚠️ in the compatibility table honest. It's one if; push back if you think it's wrong.
  2. 13 tests — the four flows above as unit tests, the pure helper, and the env parsing. 344 pass on the branch, rebased on current main.
  3. Docs: README reframed from "not supported" to "the controller presses Authenticate, you supply the authenticator"; the new ALERT_2FA_FAILED reason in OBSERVABILITY; an UPGRADING entry. (The checklist ticked those boxes but the diff didn't touch them — no action needed from you now.)
  4. Changelog: your line landed inside [0.9.0], which shipped 2026-09-07; it's now a full [Unreleased] entry crediting you.
  5. A comment where the handler returns True on an accepted click, saying plainly that 2FA reports success before the ceremony completes and a silent authenticator surfaces as the API-port timeout.

Two ways to get those onto this PR — your call:

  • Tick "Allow edits by maintainers" on the PR sidebar and I'll push the commit straight onto your branch. Simplest.
  • Or bring your branch up to date first (main moved since you branched — fix(config): verify the Lock and Exit schedule actually stuck #30 landed), then git fetch upstream pr29/followups && git cherry-pick eebaebd and push yourself.

Then one thing only you can do: re-run your live passless login with PASSKEY_AUTHENTICATE=yes set and confirm it still works with the gate in. I'm approving the CI run now so the PR shows a status (first-time fork contributions need that here); I'll merge once you confirm the live run.

code-hustler-ft3d added a commit that referenced this pull request Sep 11, 2026
Builds on jpike88's passkey handling (PR #29) without altering its
mechanics. Four additions:

Opt-in gate. PASSKEY_AUTHENTICATE (default unset = off). With it unset,
a passkey prompt in the Second Factor dialog still fails loudly, using
the exact reason string v0.8.1 emits for the browser-window variant so
existing monitors keep matching, now with a remediation= hint pointing
at the flag. Every existing flow is byte-for-byte unchanged unless the
operator opts in. Off by default because the maintainer has no passkey
account to verify against; the contributor does, and uses it in
production.

Flow tests. tests/test_pure_logic.py drives the real handle_2fa with a
mock agent in the configurations that matter: TOTP dialog with the gate
on and off (code still typed, Authenticate never pressed), passkey
dialog with and without a TOTP secret (Authenticate pressed, nothing
typed), gate off on a passkey dialog (fails loud, touches nothing), and
the IB Key push loop with a normal dialog (left alone, success via the
API port) -- the path the issue #23 reporter and every IB Key user runs.
Each asserts the handler was actually consulted rather than bypassed.
Plus the pure helper and the env parsing. 13 new tests; 335 pass.

Docs. README reframes the passkey paragraph from "not supported" to
"the controller presses Authenticate, you supply the authenticator",
marked as contributor-validated; OBSERVABILITY gains the new
ALERT_2FA_FAILED reason and the env var; UPGRADING gets an entry.

Changelog. The one-line entry was inside [0.9.0], which shipped on
2026-09-07; it moves to a new [Unreleased] section with a full entry
crediting the contributor, including the latent IB Key bug the PR
fixed in the post-relogin loop.

Also a comment at the point where the handler returns True on an
accepted click, spelling out that this reports 2FA success before the
ceremony completes and that a never-answering authenticator surfaces as
the API-port wait timing out.
jpike88 and others added 2 commits September 13, 2026 14:04
…ler-ft3d#29

Builds on jpike88's passkey handling (PR code-hustler-ft3d#29) without altering its
mechanics. Four additions:

Opt-in gate. PASSKEY_AUTHENTICATE (default unset = off). With it unset,
a passkey prompt in the Second Factor dialog still fails loudly, using
the exact reason string v0.8.1 emits for the browser-window variant so
existing monitors keep matching, now with a remediation= hint pointing
at the flag. Every existing flow is byte-for-byte unchanged unless the
operator opts in. Off by default because the maintainer has no passkey
account to verify against; the contributor does, and uses it in
production.

Flow tests. tests/test_pure_logic.py drives the real handle_2fa with a
mock agent in the configurations that matter: TOTP dialog with the gate
on and off (code still typed, Authenticate never pressed), passkey
dialog with and without a TOTP secret (Authenticate pressed, nothing
typed), gate off on a passkey dialog (fails loud, touches nothing), and
the IB Key push loop with a normal dialog (left alone, success via the
API port) -- the path the issue code-hustler-ft3d#23 reporter and every IB Key user runs.
Each asserts the handler was actually consulted rather than bypassed.
Plus the pure helper and the env parsing. 13 new tests; 335 pass.

Docs. README reframes the passkey paragraph from "not supported" to
"the controller presses Authenticate, you supply the authenticator",
marked as contributor-validated; OBSERVABILITY gains the new
ALERT_2FA_FAILED reason and the env var; UPGRADING gets an entry.

Changelog. The one-line entry was inside [0.9.0], which shipped on
2026-09-07; it moves to a new [Unreleased] section with a full entry
crediting the contributor, including the latent IB Key bug the PR
fixed in the post-relogin loop.

Also a comment at the point where the handler returns True on an
accepted click, spelling out that this reports 2FA success before the
ceremony completes and that a never-answering authenticator surfaces as
the API-port wait timing out.
@jpike88

jpike88 commented Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

I have updated my branch as requested, and I have tested the update to date branch with the PASSKEY_AUTHENTICATE=yes flag present, and it appears to work fine :)

@code-hustler-ft3d
code-hustler-ft3d merged commit 05de821 into code-hustler-ft3d:main Sep 14, 2026
6 checks passed
@code-hustler-ft3d

Copy link
Copy Markdown
Owner

Merged — thank you. Before merging I checked that your branch is byte-identical to the one I tested, and the full suite passes on your exact commit (352).

It's on main with the gate, tests and docs, and ships in the next release. Your live run with PASSKEY_AUTHENTICATE=yes is the real-account validation behind it, and the README credits you for it.

If a Gateway update or a passless change stops the prompt from matching, the signal will be ALERT_2FA_FAILED reason="passkey Authenticate lookup failed". Open an issue with that line and the dialog dump that follows it, and I'll take a look.

code-hustler-ft3d added a commit that referenced this pull request Sep 14, 2026
#30, #32 and #34 each change what an operator sees, and none of them
added the docs/UPGRADING.md entry the PR checklist asks for:

- #30 adds ALERT_CONFIG_NOT_APPLIED, an ERROR-level token worth paging
  on, and a few seconds to the post-login config pass.
- #32 makes a mis-shaped TWOFACTOR_CODE exit with status 2 at startup
  instead of crashing with a traceback at the 2FA dialog after a full
  login.
- #34 changes device-list matching and its log output, and only takes
  effect from a new image because it lives in the agent jar.

Entries go under the existing Unreleased heading alongside #29's.
code-hustler-ft3d added a commit that referenced this pull request Sep 14, 2026
…, config and secret checks

Cuts 0.10.0 from what landed since v0.9.0:

- #29 (@jpike88): press Authenticate on Gateway's passkey prompt,
  opt-in via PASSKEY_AUTHENTICATE; an authenticator running alongside
  the container completes the WebAuthn ceremony.
- #34 (fixes #33, reported by @ldicarlo): the 2FA device selector no
  longer fails on a difference in case or spacing, and a miss lists the
  entries. Agent change.
- #32: a mis-shaped TWOFACTOR_CODE stops the controller at startup
  instead of crashing at the 2FA dialog after a full login.
- #30: a Lock and Exit schedule Gateway drops is reported with
  ALERT_CONFIG_NOT_APPLIED instead of being claimed as applied.
- #31: the README documents the attended VNC fallback.

Minor rather than patch: #29 adds a feature and an env var.

Release prep:
- version 0.9.0 -> 0.10.0 in the controller and Makefile;
- CHANGELOG [Unreleased] -> [0.10.0] - 2026-09-14, and UPGRADING
  Unreleased -> v0.10.0;
- OBSERVABILITY said ALERT_CONFIG_NOT_APPLIED arrived "in v0.9.1", a
  version that will never exist, and dated several additions by PR or
  issue number; all now follow the file's "Added vX.Y.Z" convention;
- the README env table gains the PASSKEY_AUTHENTICATE row it lacked;
- ci.yml gains workflow_dispatch. GitHub created no CI run for the push
  of #34's merge commit (8cadf39): no check suite at all, and no skip
  directive, path filter or concurrency setting to explain it. There
  was no way to start one by hand. Every release step is conditioned on
  a tag ref, so a dispatch on a branch builds and tests without
  publishing.
code-hustler-ft3d added a commit that referenced this pull request Sep 14, 2026
…, config and secret checks (#35)

- Passkey (#29): with PASSKEY_AUTHENTICATE=yes the controller presses
  Authenticate on Gateway's passkey prompt, and an authenticator running
  next to the container completes WebAuthn. Off by default.
- 2FA device selector (#34, fixes #33): an exact TWOFA_DEVICE match
  wins, otherwise the one entry matching without regard to case,
  spacing or HTML is picked. A miss logs the entries. Agent change, so
  it needs the new image.
- TWOFACTOR_CODE (#32): a value that isn't a base32 secret exits with
  status 2 at startup.
- Lock and Exit (#30): the schedule is read back after it is applied,
  and a dropped value raises ALERT_CONFIG_NOT_APPLIED.
- README (#31): finishing 2FA by hand over VNC.
- ci.yml: manual runs via workflow_dispatch. Only tags publish.
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