Skip to content

feat: remote crew sign-in via Crew's vault on the KAS bundle route - #23657

Open
CrysisDeu wants to merge 1 commit into
mainfrom
feat/kas-bundle-remote-signin
Open

CrysisDeu wants to merge 1 commit into
mainfrom
feat/kas-bundle-remote-signin

Conversation

@CrysisDeu

@CrysisDeu CrysisDeu commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Problem / Motivation

Goal: A remote crew (an EC2 instance signed in by kirocrew cloud login, or the aws_control crew container) that runs the KAS bundle route can be signed in, show who it is signed in as, and sign out through Crew's own vault, with no kiro-cli on the remote machine, while every other route keeps its kiro-cli sign-in exactly as before.

On the KAS bundle route (agent.acp_backend: kas with agent.kas_bundle: true) the engine's only credential is Crew's own vault and kiro-cli is not installed (#21843). Two remote sign-in surfaces still drove kiro-cli on the remote machine:

  • kirocrew cloud login|logout and the launch wizard ran kiro-cli login, kiro-cli whoami --format json and kiro-cli logout on the instance over SSM. On a bundle-route instance every one of those is "command not found": the box cannot be signed in, its identity cannot be read, and the launching machine's own identity (discover_local_identity) also came from kiro-cli whoami.
  • The aws_control crew container's supervisor wrote a sentinel row into kiro-cli's login store and asked kiro-cli whoami to accept it before every start. On a bundle-route task there is no kiro-cli to ask, so the task refuses to start.

Why it matters

The bundle route is the no-kiro-cli install that lets the desktop app drop the bundled kiro-cli-chat (#21843). Until a remote crew can sign in through the vault, turning the route on by default would leave every cloud instance and every crew container with a chat backend nobody can sign in. The relay route must keep working unchanged, because that is what every remote crew runs today.

Not a goal

What changed (motivation → approach → change)

The local kirocrew cloud command cannot read the remote config (it lives in the instance's config.json), so the box decides which program owns the sign-in.

New verbs, kirocrew kas login | whoami | logout | route (cli_kas_login.py), drive the existing KasLoginService from a shell and speak kiro-cli's vocabulary on purpose: login prints Open <URL> and code: XXXX-XXXX, polls until approved and exits 0 once the credential is in the vault (already signed in, exit 0, over a usable identity); whoami --format json prints the kiro-cli whoami document (accountType, startUrl, never a token or an e-mail) and exits 1 when signed out; logout empties the vault; route prints kas-bundle when both halves of the bundle route are on, kiro-cli otherwise.

Every remote script in cloud/login.py (check, whoami, login, logout, callback, cancel, resume) splices in cloud/login_vault.py's prelude, which runs the box's own kirocrew kas route. Only the exact answer kas-bundle takes the vault branch; an empty answer (an older Kiro Crew with no such verb, or no kirocrew) and every other answer run the kiro-cli commands the scripts always ran. Both branches write the same private log, read by the same capture loop and parsers. The device-login script echoes a route sentinel so a failed vault sign-in is reported instead of degrading into the kiro-cli social-callback flow, absent on that box. Cancel and replace stop both command-line patterns. The vault logout kills no engine process: the vault is in the gateway's identity fingerprint, and the pre-turn identity-change check retires the agent processes next turn.

An OIDC sign-in now records its start URL on the stored token (KasToken.extra["start_url"]), and every refresh in auth/refresh.py carries extra onto the renewed token, so an Identity Center vault identity can be matched to its organisation the way a kiro-cli one is, for the life of the sign-in. whoami and login treat a slot whose refresh the issuer rejected as signed out, as doctor and the card do, so login replaces it. Because kas logout is a second process over the gateway's vault, the store now carries a sign-out generation (kas/signed-out): every sign-out bumps it, every login snapshots it when it begins and compares it before it persists, so a dashboard login pending at the moment of a shell sign-out is refused when its code is approved instead of re-filling the emptied vault; dashboard/handlers/kas_login.py answers that refusal from the poll as the same 409 a begin does, so the card ends the sign-in. discover_local_identity reads the launching machine's vault when that machine runs the bundle route, through the same document and parser.

The container supervisor decides after write_backend_config (a crew bundle may ship config): on the bundle route it skips the kiro-cli store seed and requires the installed engine under the task's data home; elsewhere the seed runs as before.

Wiring and wording: cli_kas.py mounts the verbs under kirocrew kas; cli_parser_gateway.py lists them in the kas examples; cli_cloud.py, cli_parser_admin.py and cloud/wizard.py say "Kiro" instead of "kiro-cli" on cloud login|logout.

Backwards compatibility

Compatible: the kiro-cli route's remote commands are unchanged inside the else branch, a box without the new verb answers empty and takes that branch, kirocrew kas keeps install|status|remove, and KasToken.extra already round-trips unknown keys.

Removes nothing: every path, key and function on main stays; the container's kiro-cli seed still runs on every config that does not turn the bundle route on.

Tests

  • test/test_cli_kas_login.py: the parser; route spells the constant the remote scripts compare against; whoami exit codes and a JSON that parses through parse_whoami_output; logout empties every slot; login prints a prompt parse_login_output reads, forwards IdC start URL and region, answers already signed in over a usable identity, names a lapsed slot as the one it replaces, and reports expiry / store failure with exit 1. The login service is faked at its class seam.
  • test/test_cloud_login_vault.py: every remote script asks the box for its route, the vault verb is the if branch and the kiro-cli verb the else, the vault launch is one shape per target with shell-quoted flags, the callback script refuses on the vault route, cancel/replace stop both patterns; the local side reads a vault prompt like a kiro-cli one, never falls back to the callback flow on the vault route, and reads a vault whoami document as the remote identity; discover_local_identity on the bundle route. Then the generated scripts run under bash against stub kirocrew/kiro-cli programs, one isolated HOME per route (kas-bundle, kiro-cli, empty), asserting which program the box ran and the shared sentinels.
  • test/test_kas_login_signout_generation.py: two services over one store (the gateway and a shell): a sign-out in one refuses the other's pending login at persist time with signed_out_during_login and leaves the vault empty; a login with no sign-out in between persists; every sign-out moves the generation; a refresh keeps the recorded start URL; a refresh-rejected slot reads as signed out.
  • test/test_kas_auth_whoami.py: the accountType spelling per slot, the document's parse and target match for Builder ID and Identity Center, no e-mail and no secret in it, resolve_signed_in is the usable predicate, vault_owns_sign_in is positive on both halves, and the service records the start URL on Builder ID and IdC sign-ins.
  • container_tests/test_supervisor_kiro_login.py and test_supervisor_main.py: kas_bundle_route reads the written config and is positive on both halves (unreadable config = relay route); require_bundled_engine asks the task's own engines root and refuses with the install command; run() seeds kiro-cli's store after the config is written and before the backend, skips the seed and requires the engine on the bundle route, and refuses to start when the engine is missing.

Determinism and side effects: no sleeps, no clocks beyond fixed dates, no ports; the bash tests run foreground scripts only with a controlled HOME/PATH whose first entry shadows kirocrew, kiro-cli, pkill and pgrep with logging stubs, so no real process or store is reached and no background login is started.

Manual verification

  • The generated scripts for check / whoami / device login (Builder ID and IdC) / callback / logout / cancel pass bash -n and were driven end to end against stub kirocrew and kiro-cli programs in three isolated HOMEs: with kas route answering kas-bundle the box ran kirocrew kas whoami, kirocrew kas login [--provider idc --start-url … --region …], kirocrew kas logout and refused the callback flow; answering kiro-cli or nothing, it ran kiro-cli whoami, kiro-cli login --use-device-flow […], kiro-cli login (callback) and kiro-cli logout, with the same sentinels on the local side.
  • kirocrew kas route printed kiro-cli on a default config and kas-bundle with {"agent": {"acp_backend": "kas", "kas_bundle": true}}; kas whoami --format json exited 1 signed out; kas logout was a clean no-op signed out.
  • Live issuer, no credentials: kirocrew kas login --provider builder_id in an isolated KIROCREW_HOME completed RegisterClient and StartDeviceAuthorization against oidc.us-east-1.amazonaws.com and printed the verification URL and user code, then was killed after 20 s with nobody approving. The approval half (CreateToken) needs a human's own Builder ID and was not run; kas-auth.md § Validation status says so.
  • Not run: a real EC2 instance on the bundle route over SSM (needs an instance and a human approval), and a bundle-route crew container (the image ships no engine).

Screenshots / video

N/A — CLI and remote-script change, no dashboard surface.

Related Issues

Part of #21843
Refs #21843

Checklist

  • At most two commits (one is the norm), with a Conventional Commits title (feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert: ...)
  • Existing tests pass and new tests added for new functionality
  • Self-review completed; code follows project style guidelines
  • Documentation updated (if applicable)
  • No secrets, credentials, or internal references in the diff

@CrysisDeu
CrysisDeu requested review from a team and KiroCrewCaptain as code owners October 24, 2026 03:47
@CrysisDeu
CrysisDeu requested a review from buluoray October 24, 2026 03:47
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

UX Review (Opus 5.5) — ⏭️ skipped

Revision 5c22485111230131c3ae420207c1ccbfff45620d touches no user-facing surface (no changes under website/ or committed screenshots), so the UX review was skipped. Does not block merge.

@github-actions github-actions Bot added the readiness: checking Automated validation is still running label Oct 24, 2026
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Design Review (Opus 5.5) — ✅ PASS

Design-level review of 5c22485111230131c3ae420207c1ccbfff45620d — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS does not.

Design-Verdict: PASS

Nothing blocks: the box picks the route itself, only an exact kas-bundle answer takes the vault branch, and every other answer keeps the kiro-cli commands that run today.

Notes

  • auth/whoami.py adds a second mapping from claims to account type, separate from feat: name the signed-in account from Crew's vault on the KAS route #23615's account_type_from_claims. The description already defers merging them; track it with an issue so the two whoami documents can't drift apart.
  • If kas route fails on a bundle-route box (unreadable config, crash), that box takes the kiro-cli branch, which isn't installed there, so the operator sees "command not found" instead of a vault error. Printing a distinct error answer from the verb would make that failure readable.

[DESIGN-REVIEWED] 5c22485

Description read

[DESCRIPTION-READ] 3d08a34629bf3931cf57223c0d064b4ca75ed8b71128efeff60e2ee0b6c3968e

That sha256 names everything this verdict read: the PR description, plus the 1 evidence file(s) the workflow collected from it and handed this review. It covers that evidence because the media strip replaces every attachment URL with the same placeholder, so an edit swapping one attachment for another would leave the description's captured text identical while what this review judged changed. Recompute it with .github/scripts/pr-description-capture.sh over the same inputs; if it differs, the description or that evidence changed after this verdict was formed and any finding drawn from either is unproven.

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

First Principles Review (Opus 5.5) — ✅ PASS

Premise-level review of 5c22485111230131c3ae420207c1ccbfff45620d — why this exists and whether the shipped surface is the smallest honest version. Updated in place on each push. A BLOCK verdict blocks PR readiness; PASS does not.

First-Principles-Verdict: PASS

Nothing blocks: each item comes from the bundle route having no kiro-cli (#21843). The relay route's commands stay byte-for-byte unchanged, so nothing new becomes the default.

Notes

  • Item 6 — duplicate: auth/whoami.py:vault_owns_sign_in is a third spelling of the route check. Two already exist: kiro_prerequisite_service._kas_bundle_route and agent_sdk/backend_install._kas_bundle_route (grepped def .*kas_bundle.*route: 3 hits, plus the supervisor's kas_bundle_route). It is stricter than them because it also checks the backend. Subtraction: keep the one positive predicate and have the other two call it, rather than keeping three that can drift apart.
  • Item 8 — one consumer: the container branch's require_bundled_engine has no real user today. The description says "the image still pins kiro-cli and ships no engine." Subtraction: defer the engine refusal until an image ships the engine, and keep only the skip of the kiro-cli store seed.

What this change ships

Inventory (10 items) — 8 justified

Intent: let a remote bundle-route crew sign in, show who it is signed in as, and sign out through Crew's vault, with no kiro-cli on the box. This is an ADDITION.

  1. New kirocrew kas login (device code) from a shell — justified
  2. New kirocrew kas whoami [--format json] — justified
  3. New kirocrew kas logout — justified
  4. New kirocrew kas route prints kas-bundle or kiro-cli — justified
  5. cloud login/logout/whoami scripts on a bundle-route box switch to the vault verbs — justified
  6. discover_local_identity reads the local vault on the bundle route — duplicate of the _kas_bundle_route predicates
  7. Sign-out generation file plus lock; a pending dashboard login is refused with 409 after a sign-out from the shell — justified
  8. Container skips the kiro-cli seed and requires the engine on the bundle route — one consumer, the engine refusal has no user today
  9. IdC start URL is stored on the token and kept across refreshes — justified
  10. Wording changes from "kiro-cli" to "Kiro" in cloud login/logout and the wizard — justified

[FIRST-PRINCIPLES-REVIEWED] 5c22485

Description read

[DESCRIPTION-READ] 64d98273f0c2a1c2e72a7058d30a97725232ee71ef5217eb3078de3882bd5289

That sha256 names the PR description this verdict read. Recompute it with .github/scripts/pr-description-capture.sh; if it differs, the description changed after this verdict was formed and any finding drawn from the description is unproven.

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Opus 5.5 Review — ✅ no blocking findings

Reviewed 5c22485111230131c3ae420207c1ccbfff45620d — this comment is updated in place on each push.

Review details

No findings.

[OPUS-REVIEWED] 5c22485

Verdict parsed from the review's SHA-scoped output markers for commit 5c22485111230131c3ae420207c1ccbfff45620d.

False positive or not applicable? A repository writer can comment:
/ai-review override fable 5c22485111230131c3ae420207c1ccbfff45620d false-positive: <reason, 20 to 500 characters>

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Oct 24, 2026
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

GPT 6.1 Review — ✅ no blocking findings

GPT 6.1 completed its review of 5c22485111230131c3ae420207c1ccbfff45620d and found no blocking issues.

This comment is updated in place on each push.

Review details

No findings.
[GPT-REVIEWED] 5c22485

False positive or not applicable? A repository writer can comment:
/ai-review override gpt 5c22485111230131c3ae420207c1ccbfff45620d false-positive: <reason, 20 to 500 characters>

@CrysisDeu
CrysisDeu force-pushed the feat/kas-bundle-remote-signin branch from 3c7bd0c to f08b7eb Compare October 24, 2026 04:13
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Oct 24, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/kas-bundle-remote-signin branch from f08b7eb to 77e2887 Compare October 24, 2026 04:31
@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Oct 24, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/kas-bundle-remote-signin branch 2 times, most recently from 2c10142 to aa6be00 Compare October 24, 2026 05:13
@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Oct 24, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/kas-bundle-remote-signin branch from aa6be00 to 16dbdc6 Compare October 24, 2026 06:17
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Oct 24, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/kas-bundle-remote-signin branch from 16dbdc6 to d7c215f Compare October 24, 2026 07:22
@github-actions github-actions Bot removed the readiness: action required A blocking check or review needs attention label Oct 24, 2026
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Oct 24, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/kas-bundle-remote-signin branch from d7c215f to 1d8f59c Compare October 24, 2026 07:46
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: passed Eligible automated validation passed for the current revision and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Oct 24, 2026
@CrysisDeu

Copy link
Copy Markdown
Contributor Author

macOS Tests (on demand) shard 5 is red on head 1d8f59c for 25 tests in test/test_ai_review_workflows_human_override.py (${ACTOR,,}: bad substitution on macOS bash 3.2). That is the main defect tracked in #23676 (introduced by #22698 in .github/workflows/ai-review-human-override.yml); this PR touches neither the workflow nor the test. Recorded on #23676 with the run URL. PR Readiness and every required check are green.

@CrysisDeu

Copy link
Copy Markdown
Contributor Author

Rebased: main moved in docs/system-specs/modules/dev-fleet.md (same directory as this PR's spec edits) since this head went green (9ae6bc7 -> d5b8c20); CI re-running.

@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: passed Eligible automated validation passed for the current revision labels Oct 24, 2026

@cruisercohen cruisercohen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed as security scope (KAS vault / credential path), comment only — not approving. I looked specifically for a credential widening and found none.

The feature lets a remote crew instance on the KAS bundle route sign in through the box's own vault instead of kiro-cli (that route installs no kiro-cli). The credential flow does not widen access:

  • The remote box signs ITSELF in. kirocrew cloud runs kirocrew kas login on the instance over SSM; that verb prints its own verification URL + code and the token lands in the BOX's vault. The local machine's vault token is never read or transmitted — I grepped the cloud sign-in scripts and they carry no token value, and the module states it ("the device code and the token stay between the box's kirocrew process and the issuer").
  • The only local vault read is for IDENTITY, not the secret. local_vault_identity renders the whoami document (account kind, start URL — no email, no token) through the same parser the kiro-cli path uses, for inheritance/display.
  • Sign-out gains cross-process consistency — a store-wide sign-out lock and a sign-out generation marker, so a login cannot write into a vault that a concurrent sign-out (the gateway's, or a shell kirocrew kas logout) just emptied; the running agents are retired on the next turn. That's a tightening.
  • require_bundled_engine refuses startup when the bundle-route engine isn't installed, instead of serving a task that answers /health 200 and then 503s every turn.

Tests: 109 pass on the merge with current main (cloud-login-vault, whoami, kas-login-api, cli-kas-login, signout-generation).

No security-default change, no credential widening. Final sign-off is a maintainer's.

@github-actions github-actions Bot added readiness: passed Eligible automated validation passed for the current revision and removed readiness: checking Automated validation is still running labels Oct 24, 2026
On the KAS bundle route (agent.acp_backend kas with agent.kas_bundle on)
the engine's only credential is Crew's own vault and kiro-cli is not
installed, yet two remote sign-in surfaces still drove kiro-cli on the
remote machine: the cloud instance sign-in over SSM and the aws_control
crew container's kiro-cli store seed.

The box now decides which program owns the sign-in. New verbs
`kirocrew kas login | whoami | logout | route` drive KasLoginService
from a shell in kiro-cli's own vocabulary (the device prompt lines, the
`whoami --format json` document, the exit codes), and every remote
script `kirocrew cloud login|logout` runs asks the box's `kirocrew kas
route` before choosing its branch; only the exact answer `kas-bundle`
takes the vault verbs, every other answer (an older Kiro Crew included)
runs the kiro-cli commands it always ran. The local reading of an
identity shares one parser for both, and an OIDC sign-in records its
start URL so an Identity Center vault identity can be matched to its
organisation. The launching machine's own identity is read from its
vault when it runs the bundle route.

The container supervisor decides after writing the backend config:
on the bundle route it skips kiro-cli's sentinel store seed and
requires the installed engine instead; elsewhere the seed runs as
before. Builder ID device authorization through the vault was run
against the live issuer up to the device prompt; the approval half
needs a human and is recorded as not yet validated.

Refs #21843
@CrysisDeu
CrysisDeu force-pushed the feat/kas-bundle-remote-signin branch from 5186c82 to 5c22485 Compare October 24, 2026 09:57
@CrysisDeu

Copy link
Copy Markdown
Contributor Author

Rebased: main moved in test/test_dashboard*.py (shared stem with this PR's dashboard handler change) since this head went green (d5b8c20 -> 1241954); CI re-running. The macOS shard 5 red on 5186c82 is again the main defect in #23676 (bash 3.2 ${ACTOR,,}), not this PR.

@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: passed Eligible automated validation passed for the current revision labels Oct 24, 2026

@cruisercohen cruisercohen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Follow-up on my earlier review — the PR has since rebased to 5c22485. I diffed the credential-path files (cloud/*, auth/*, and the aws_control container supervisor) between the head I reviewed (5186c82) and this one: they are byte-identical, and the new head only pulls in unrelated main churn.

So my earlier conclusion stands on this head: the remote box signs itself in via its own device flow, the local vault token is never read or transmitted, and sign-out gains cross-process consistency. No credential widening on this head either — still comment-only, final sign-off a maintainer's.

@github-actions github-actions Bot added readiness: passed Eligible automated validation passed for the current revision and removed readiness: checking Automated validation is still running labels 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

readiness: passed Eligible automated validation passed for the current revision

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants