The Storage class in `packages/sdk/src/utils/storage.ts` constructed a
`Conf` instance without passing `configFileMode`, so the on-disk file
inherited conf's default (0o666 masked by umask, typically 0o644 on
macOS and Linux).
The file holds the OAuth `access_token` and `refresh_token` from
`auth login`, plus — during a pending device-auth window — the
`device_code` and verification phrase written by the agent-mode
`auth login` flow at packages/cli/src/commands/auth/index.tsx:50.
With 0o644 perms, any other local user (shared dev workstations,
multi-user CI runners, lab machines) can:
- Read the access + refresh tokens and call the Link API as the
victim — including `GET /spend_requests/{id}?include=card` to
retrieve unmasked card details from approved spend requests.
- During an active login window, read the `device_code` and race the
legitimate `auth status --interval` poll loop to
`/device/token`. OAuth 2.0 device-flow polls return tokens to the
first caller after user approval; the device_code is the polling
client's secret, and it should never reach disk in a world-readable
form.
This change passes `configFileMode: 0o600` to the Conf constructor.
Owner-only matches the convention used by gh, aws, mercury-cli, and
similar credential-bearing CLIs. conf writes via atomic rename, so
existing 0o644 files are remediated automatically on the next config
write (next setAuth, clearAuth, or setPendingDeviceAuth).
For testability, the `Storage` class is now exported and accepts an
optional `cwd` so unit tests can run against a temp directory instead
of the real platform user-config path.
Tests:
- `writes the config file with mode 0o600 (owner-only)` — fresh write.
- `rewrites with mode 0o600 when an existing file is 0o644` — covers
the upgrade path from a pre-fix install.
- `also restricts pendingDeviceAuth, which is written to the same
file` — covers the device_code race-window vector.
Skipped on Windows (NTFS uses ACLs; POSIX mode bits don't reflect
actual access).
* fix: correctly expose the SPT in the Ink output
* fix: correctly expose the SPT in the Ink output
* fix: stop spend-request commands from making duplicate API calls
The interactive (Ink) path for create, update, request-approval, and
retrieve each rendered a component that called the API, then made a
second identical API call in waitUntilExit().then() to obtain a value
to resolve the Promise. Thread the result back through onComplete so
index.tsx can resolve with the component's result directly.
Committed-By-Agent: claude
* fix: use ref to track latest request in retrieve polling effect
Using `request` state directly in the polling useEffect timeout path
triggered a biome exhaustive-deps lint error. Track the latest value
in a ref so the polling effect dependency array stays stable.
Committed-By-Agent: claude
* changeset
* fix: remove unused file
* add checklist style flow for onboard/demo
* add changeset
* fix fmt
* update galtee link
* continue to show credential in demo flow after it ends
* misc polish
* update text
* fmt
* Fix Card.valid_until type to match API response
The API returns valid_until as an ISO 8601 string, but the Card type
declared it as number. The interactive retrieve component multiplied
the string by 1000 to create a Date, producing NaN and crashing with
"Invalid time value" on toISOString().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Committed-By-Agent: claude
* Fix biome formatting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Committed-By-Agent: claude
---------
Co-authored-by: Ben Davis <ben@bencdavis.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* migrate commander -> incur enabling mcp server
* save
* use incur skill handling and clarify to use mcp if running
* add changeset
* fix type error
* fix fmt
* fix tests
* fmt
Use update notifier to indicate new versions. In TTY outputs, this is a very standard update-notifier integration. For JSON outputs consumed by agents, we include the info in the auth status command to not interfere with agents parsing output in other commands.
npx skills add for skill installation
npm install -g for installing from skill file
remove the unneeded --install option
remove some duplicative instructions
tell it to use --include card when retrieving a card
tell it to check auth status before running a new login command