Repository navigation
Conversation
UX Review (Opus 5.5) — ⏭️ skippedRevision |
Design Review (Opus 5.5) — ✅ PASSDesign-level review of Design-Verdict: PASS Nothing blocks: the box picks the route itself, only an exact Notes
[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 |
First Principles Review (Opus 5.5) — ✅ PASSPremise-level review of 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
What this change shipsInventory (10 items) — 8 justifiedIntent: 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.
[FIRST-PRINCIPLES-REVIEWED] 5c22485 Description read[DESCRIPTION-READ] 64d98273f0c2a1c2e72a7058d30a97725232ee71ef5217eb3078de3882bd5289 That sha256 names the PR description this verdict read. Recompute it with |
Opus 5.5 Review — ✅ no blocking findingsReviewed Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
GPT 6.1 Review — ✅ no blocking findingsGPT 6.1 completed its review of This comment is updated in place on each push. Review detailsNo findings. False positive or not applicable? A repository writer can comment: |
3c7bd0c to
f08b7eb
Compare
f08b7eb to
77e2887
Compare
2c10142 to
aa6be00
Compare
aa6be00 to
16dbdc6
Compare
16dbdc6 to
d7c215f
Compare
d7c215f to
1d8f59c
Compare
|
macOS Tests (on demand) shard 5 is red on head 1d8f59c for 25 tests in |
1d8f59c to
5186c82
Compare
cruisercohen
left a comment
There was a problem hiding this comment.
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 cloudrunskirocrew kas loginon 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_identityrenders thewhoamidocument (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_enginerefuses startup when the bundle-route engine isn't installed, instead of serving a task that answers/health200 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.
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
5186c82 to
5c22485
Compare
cruisercohen
left a comment
There was a problem hiding this comment.
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.
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: kaswithagent.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|logoutand the launch wizard rankiro-cli login,kiro-cli whoami --format jsonandkiro-cli logouton 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 fromkiro-cli whoami.kiro-cli whoamito 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
kirocrew doctor(feat(doctor): report the KAS bundle engine instead of probing kiro-cli #23617) and the model picker (feat(models): serve the KAS bundle picker from the engine model select #23618): other items of KAS bundle route by default: replace the remaining kiro-cli calls (whoami, list-models, update, doctor) so the desktop app can drop the bundled kiro-cli-chat #21843. This PR adds its own smallauth/whoami.pymapping; it can collapse onto feat: name the signed-in account from Crew's vault on the KAS route #23615'saccount_type_from_claimsonce both are on main.agent.kas_bundleto default-on, or the live validation of the approval half of Builder ID / IdC / External IdP sign-in (recorded as open inkas-auth.md).cloud/login.pytoday, now inside theelsebranch.What changed (motivation → approach → change)
The local
kirocrew cloudcommand cannot read the remote config (it lives in the instance'sconfig.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 existingKasLoginServicefrom a shell and speak kiro-cli's vocabulary on purpose:loginprintsOpen <URL>andcode: 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 jsonprints thekiro-cli whoamidocument (accountType,startUrl, never a token or an e-mail) and exits 1 when signed out;logoutempties the vault;routeprintskas-bundlewhen both halves of the bundle route are on,kiro-cliotherwise.Every remote script in
cloud/login.py(check, whoami, login, logout, callback, cancel, resume) splices incloud/login_vault.py's prelude, which runs the box's ownkirocrew kas route. Only the exact answerkas-bundletakes the vault branch; an empty answer (an older Kiro Crew with no such verb, or nokirocrew) 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 inauth/refresh.pycarriesextraonto 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.whoamiandlogintreat a slot whose refresh the issuer rejected as signed out, as doctor and the card do, sologinreplaces it. Becausekas logoutis 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.pyanswers that refusal from the poll as the same 409 a begin does, so the card ends the sign-in.discover_local_identityreads 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.pymounts the verbs underkirocrew kas;cli_parser_gateway.pylists them in thekasexamples;cli_cloud.py,cli_parser_admin.pyandcloud/wizard.pysay "Kiro" instead of "kiro-cli" oncloud login|logout.Backwards compatibility
Compatible: the kiro-cli route's remote commands are unchanged inside the
elsebranch, a box without the new verb answers empty and takes that branch,kirocrew kaskeepsinstall|status|remove, andKasToken.extraalready 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;routespells the constant the remote scripts compare against;whoamiexit codes and a JSON that parses throughparse_whoami_output;logoutempties every slot;loginprints a promptparse_login_outputreads, forwards IdC start URL and region, answersalready signed inover 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 theifbranch and the kiro-cli verb theelse, 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 vaultwhoamidocument as the remote identity;discover_local_identityon the bundle route. Then the generated scripts run under bash against stubkirocrew/kiro-cliprograms, 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 withsigned_out_during_loginand 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: theaccountTypespelling 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_inis the usable predicate,vault_owns_sign_inis positive on both halves, and the service records the start URL on Builder ID and IdC sign-ins.container_tests/test_supervisor_kiro_login.pyandtest_supervisor_main.py:kas_bundle_routereads the written config and is positive on both halves (unreadable config = relay route);require_bundled_engineasks 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/PATHwhose first entry shadowskirocrew,kiro-cli,pkillandpgrepwith logging stubs, so no real process or store is reached and no background login is started.Manual verification
bash -nand were driven end to end against stubkirocrewandkiro-cliprograms in three isolated HOMEs: withkas routeansweringkas-bundlethe box rankirocrew kas whoami,kirocrew kas login [--provider idc --start-url … --region …],kirocrew kas logoutand refused the callback flow; answeringkiro-clior nothing, it rankiro-cli whoami,kiro-cli login --use-device-flow […],kiro-cli login(callback) andkiro-cli logout, with the same sentinels on the local side.kirocrew kas routeprintedkiro-clion a default config andkas-bundlewith{"agent": {"acp_backend": "kas", "kas_bundle": true}};kas whoami --format jsonexited 1 signed out;kas logoutwas a clean no-op signed out.kirocrew kas login --provider builder_idin an isolatedKIROCREW_HOMEcompletedRegisterClientandStartDeviceAuthorizationagainstoidc.us-east-1.amazonaws.comand 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.Screenshots / video
N/A — CLI and remote-script change, no dashboard surface.
Related Issues
Part of #21843
Refs #21843
Checklist
feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert: ...)