Skip to content

feat(login)!: replace --paste/--stdin/--no-browser with --api-key - #7

Merged
doedja merged 1 commit into
mainfrom
agent/headless-login-api-key
Aug 7, 2026
Merged

feat(login)!: replace --paste/--stdin/--no-browser with --api-key#7
doedja merged 1 commit into
mainfrom
agent/headless-login-api-key

Conversation

@doedja

@doedja doedja commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Problem

kenari login completes approval over a loopback callback on 127.0.0.1, which needs a browser on the same machine as the CLI. Over SSH or in a container there is no browser, and opening the printed URL on a laptop sends the callback to the laptop's own localhost. The CLI waits out its five minute timeout with no useful error.

--paste and --stdin already worked headless but were listed only in the usage line, never in the README.

Change

Loopback OAuth is untouched and stays the default. The three headless side paths collapse into one flag.

kenari login              # OAuth loopback + browser (unchanged)
kenari login --api-key    # hidden prompt on a TTY, stdin when piped

--api-key branches on process.stdin.isTTY, so an SSH session and a container entrypoint run the same command:

kenari login --api-key                       # hidden prompt
echo "$KENARI_KEY" | kenari login --api-key  # CI, entrypoint

--no-browser, --paste and --stdin now error with a message naming --api-key and the keys URL, so an upgrade does not strand anyone mid-session.

Two guards

The key is rejected as an argv value. parseFlags would have swallowed --api-key kn-... happily. A key on the command line goes into shell history on the box and is readable from /proc/<pid>/cmdline by any user on the machine while the command runs. The error names the pipe form instead.

askHidden was broken and had no caller. This change is its first. Ctrl-D at the prompt left its promise pending, so the process exited 0 with nothing stored and no error, meaning kenari login --api-key && kenari configure would have run configure against no login. It now resolves empty on close and the caller exits 1.

Verification

93/93 pass. Every guard was reverted individually and watched go red before restoring:

guard removed observed failure
removed-flag rejection assertion failure, flags fall through to loopback
argv-value refusal hangs on stdin instead of rejecting
askHidden close handler promise never settles, suite hangs

Real binary smoke-tested across the flag matrix, plus two expect pty runs confirming the hidden prompt stores the key without echoing it, and that Ctrl-D exits 1. credentials.json stays 0600 and logout removes it.

Docs

README gains a "Signing in" section: the server/SSH flow, the CI pipe, KENARI_HOME for containers with a read-only home, and why an argv key is refused.

Loopback OAuth needs a browser on the same machine as the CLI, so
`kenari login` could not complete over SSH, on a VPS, or in a container.
The loopback flow is unchanged and stays the default. The three headless
side paths collapse into one flag.

`kenari login --api-key` prompts hidden on a terminal and reads stdin
when piped, so an SSH session and a container entrypoint run the same
command. Passing the key as a value is rejected: a key on the command
line is written to shell history and is readable from /proc/<pid>/cmdline
by any user on the machine.

Also fixes askHidden, which had no caller before this change. Ctrl-D at
the prompt left its promise pending, so the process exited 0 with no
credential stored and no error, and `kenari login --api-key && kenari
configure` would have run configure against no login.

BREAKING CHANGE: --no-browser, --paste and --stdin are removed. Use
--api-key instead. Each prints an error naming the replacement.
@doedja
doedja merged commit 470cc48 into main Aug 7, 2026
6 checks passed
@doedja
doedja deleted the agent/headless-login-api-key branch August 7, 2026 02:51
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.

1 participant