{"record":{"id":"55b2af459dde9b08","repo":"Hmbown/CodeWhale","slug":"managing-api-keys-needs-an-interactive-login-run-codewhale","errorCode":null,"errorMessage":"Managing API keys needs an interactive login. Run `codewhale login`.\n{MACHINE_KEY_ENV} is set, but a Codewhale API key deliberately cannot create, list, or revoke keys — that is what stops a leaked key from minting a replacement for itself.","messagePattern":"Managing API keys needs an interactive login\\. Run `codewhale login`\\.\n(.+?) is set, but a Codewhale API key deliberately cannot create, list, or revoke keys — that is what stops a leaked key from minting a replacement for itself\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/cloud/machine.rs","lineNumber":875,"sourceCode":"in the display prefix. Run `codewhale account api-keys list` to see them.\"\n        );\n    }\n    Ok(id)\n}\n\n/// Refuse a management command that would be authenticated by a machine key.\n///\n/// The server would answer 403 `api_key_route_denied`, but a local refusal is\n/// better: it never puts the credential on the wire, and it names the fix.\n/// This is the load-bearing rule of the whole design — a stolen key must not\n/// be able to bootstrap a successor that outlives the revocation of the key\n/// that was stolen — so the CLI states it rather than discovering it.\npub(crate) fn reject_machine_key_for_management(\n    machine: &MachineKeyEnv,\n    has_session: bool,\n) -> Result<()> {\n    if machine.is_present() && !has_session {\n        bail!(\n            \"Managing API keys needs an interactive login. Run `codewhale login`.\\n\\\n{MACHINE_KEY_ENV} is set, but a Codewhale API key deliberately cannot create, list, or \\\nrevoke keys — that is what stops a leaked key from minting a replacement for itself.\"\n        );\n    }\n    Ok(())\n}\n\n/// Run `codewhale account api-keys …` against the interactive session.\npub(crate) fn run_api_keys<T: CloudTransport, W: Write>(\n    args: ApiKeysArgs,\n    client: &CloudClient<'_, T>,\n    machine: &MachineKeyEnv,\n    provider_secrets: &codewhale_secrets::Secrets,\n    out: &mut W,\n    sleeper: &mut dyn FnMut(Duration),\n) -> Result<()> {\n    reject_machine_key_for_management(machine, client.has_session()?)?;","sourceCodeStart":857,"sourceCodeEnd":893,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/cli/src/cloud/machine.rs#L857-L893","documentation":"reject_machine_key_for_management enforces a security invariant: a machine API key (MACHINE_KEY_ENV) can authenticate API calls but can never create, list, or revoke keys. Key management requires an interactive session login; when a machine key is present and no session exists, the CLI bails and states the rationale — preventing a leaked key from minting its own replacement.","triggerScenarios":"Running any api-keys management subcommand (create/list/revoke) while MACHINE_KEY_ENV is set and there is no interactive login session, i.e. has_session is false and machine.is_present() is true (crates/cli/src/cloud/machine.rs:875).","commonSituations":"CI or scripted environments where only the machine key env var is set and someone tries to rotate keys non-interactively; a developer who logged out but still has the env var exported; Docker containers with the key injected as an env var.","solutions":["Run `codewhale login` in an interactive terminal to establish a session, then retry the management command","Unset the machine key env var if it is not needed for this command: `unset $MACHINE_KEY_ENV`","Perform key management from a machine with an interactive session, not from CI","Use the web console/dashboard to manage keys if CLI login is impossible"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// shell: require a session before management commands\nif [ -n \"$MACHINE_KEY_ENV_VALUE\" ] && ! codewhale whoami >/dev/null 2>&1; then\n  echo \"run 'codewhale login' for key management\"; exit 1\nfi","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do key management from an interactive login session, never via machine keys only","Unset machine-key env vars in contexts where you need management operations","Understand the invariant: machine keys are use-only by design (anti-lateral-minting)"],"tags":["cli","authentication","security","api-key"],"backgroundTag":"authentication-required","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}