feat(cli): STACKBILT_API_KEY env var auth; deprecate charter login#111
Merged
stackbilt-admin merged 2 commits intomainfrom Apr 16, 2026
Merged
feat(cli): STACKBILT_API_KEY env var auth; deprecate charter login#111stackbilt-admin merged 2 commits intomainfrom
stackbilt-admin merged 2 commits intomainfrom
Conversation
Additive preparation for the 1.0 package split (see charter RFC TBD).
No public API removed or renamed — follows OSS update policy.
Why
The CLI currently solicits a Stackbilt API key via `charter login`, which
is the most eyebrow-raising OSS/commercial coupling in the package: an
OSS governance tool writing a bearer token to ~/.charter/credentials.json.
Supporting the standard env-var path lets users authenticate the
commercial commands (`run`, `architect`) without the CLI persisting
anything to disk, materially improving the audit story now while the
full split to @stackbilt/build is scoped and sequenced separately.
What changes
credentials.ts
+ API_KEY_ENV_VAR = 'STACKBILT_API_KEY'
+ resolveApiKey() → { apiKey, source: 'env' | 'credentials', baseUrl? } | null
Env var wins over stored credentials; empty/whitespace env var falls
through. loadCredentials(), saveCredentials(), clearCredentials()
preserved unchanged.
commands/architect.ts, commands/run.ts
- loadCredentials() call sites → resolveApiKey(). `run`'s useGateway
decision now honors the env var path identically to stored creds.
commands/login.ts
- printDeprecationNotice() on stderr for every invocation except
--logout. Command functionality unchanged. Help text reworked: env
var is the "Preferred" path, stored credentials the "Deprecated
alternative." If the env var is set and no --key is given, we
report the env var as the authoritative source.
http-client.ts
- Scaffold auth-error string now points at STACKBILT_API_KEY first,
`charter login` marked deprecated.
Tests
+ credentials.test.ts — 4 tests covering env-var precedence, trimming,
empty-string fallthrough, whitespace-only fallthrough.
+ login.test.ts — 2 tests covering the stderr deprecation notice and
env-var reporting path.
All 405 existing tests still pass.
Docs
- packages/cli/README.md: new "Authentication (optional)" section
documenting the env var and login deprecation. Root README
unchanged — that rewrite ships with the package split.
- CHANGELOG.md: [Unreleased] section added with Added/Deprecated/Changed
subsections.
Follow-ups (not in this PR)
- Root README rewrite when package split lands
- RFC: extract commercial surface into @stackbilt/build
- 1.0 cut removes login, credentials persistence, run/architect/scaffold
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Addresses feedback on PR #111: - credentials.test.ts: mock node:fs so loadCredentials returns deterministic results instead of reading the developer's real ~/.charter/credentials.json. Empty/whitespace-env-var cases are now pinned to the stored-credentials fallback with stubbed data rather than being conditionally skipped. Added explicit "env wins when both sources set" test that was claimed by the describe block but never exercised. - STACKBILT_API_BASE_URL companion env var: resolveApiKey now returns a baseUrl from the env when source='env'. Fixes the silent base-URL drop for users migrating from `charter login --url https://custom ...`. - login.ts: --logout now emits the deprecation notice before clearing credentials. One-line fix; users exiting the deprecated surface see the upgrade path. - CLI README: "Authentication (optional)" gains a one-line security caveat about env-var inheritance by child processes, recommending per-invocation setting in CI over global export in shared shells. - auth-wiring.test.ts (new): mocks resolveApiKey and EngineClient; pins the useGateway decision for `run` (scaffold vs build) and asserts architect forwards the resolved apiKey + baseUrl into the client constructor. 5 tests covering env/credentials/null. All 16 auth-related tests pass (credentials: 9, login: 2, auth-wiring: 5). Full suite: 413/415 pass; the two failures are the same WSL-flaky precommit-hook integration test already flagged on PR #110 and unrelated to this diff. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Member
Author
Review response — 869eb1dAddressed the blocker + non-critical items. Keeping "will be removed in 1.0" per your explicit call. Blocker fixed:
Non-critical items:
Deferred per your own framing:
Open question answered: kept "will be removed in 1.0" per your call. Vague deprecations rot; commit to the window. Test results after changes:
|
10 tasks
stackbilt-admin
pushed a commit
that referenced
this pull request
Apr 16, 2026
Synchronized version bump for all @stackbilt/* packages to 0.11.0. Highlights: - STACKBILT_API_KEY / STACKBILT_API_BASE_URL env-var auth (#111) - Zod-Core-Out vertical slice for @stackbilt/blast + charter_blast MCP tool (#110) - charter login deprecated; scheduled for 1.0 removal alongside @stackbilt/build split (#112) See CHANGELOG.md [0.11.0] for the full entry. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Additive preparation for the 1.0 package split. No public API removed or renamed — follows the OSS additive-only update policy.
Why
charter loginis the single most eyebrow-raising OSS/commercial coupling in@stackbilt/cli: an OSS governance tool soliciting a bearer token and writing it to~/.charter/credentials.json. For a regulated-company security review, that's the line that gets flagged — not that the tool calls an external API the user opted into, but that the tool asks for and persists credentials.Supporting the standard
STACKBILT_API_KEYenv var lets users authenticate the commercial commands (run,architect) without the CLI persisting anything to disk. The solicitation in the README /charter loginoutput gets demoted from "Preferred" to "Deprecated alternative." The capability remains; the audit surface gets much cleaner today while the full@stackbilt/buildpackage split is scoped separately.What ships
credentials.tsAPI_KEY_ENV_VAR = 'STACKBILT_API_KEY'export.resolveApiKey()→{ apiKey, source: 'env' | 'credentials', baseUrl? } | null. Env var wins over stored credentials. Empty-string and whitespace-only env vars are treated as unset and fall through.loadCredentials(),saveCredentials(),clearCredentials()preserved unchanged for back-compat.commands/architect.ts,commands/run.tsloadCredentials()→resolveApiKey().run'suseGatewaydecision honors the env var identically to stored credentials, so users with only the env var set get the same rich gateway scaffold output thatcharter loginusers get today.commands/login.ts--logout). Command functionality unchanged.STACKBILT_API_KEYis set and--keyis not provided, report the env var as the authoritative source.http-client.tsSTACKBILT_API_KEYfirst,charter loginmarked deprecated.Tests
credentials.test.ts(new, 4 tests): env-var precedence over stored credentials, whitespace trimming, empty-string fallthrough, whitespace-only fallthrough.login.test.ts(new, 2 tests): stderr deprecation notice on invocation; env-var reporting path when set.Docs
packages/cli/README.md: new Authentication (optional) section — one paragraph, documents the env-var path and flagscharter loginas deprecated.CHANGELOG.md:[Unreleased]section with Added / Deprecated / Changed.README.mdintentionally unchanged in this PR. The hero still leads with scaffolding; that rewrite lands with the package split so the docs and the code tell a coherent story in one release note.Why additive, not a breaking change (0.11.0 minor, not 1.0)
The OSS policy requires a major bump for public-API removal. Yanking
login.ts+credentials.tswould force a coordinated 1.0 ship that also needs@stackbilt/buildto exist. That package doesn't exist yet. The env-var bridge is the disciplined sequencing move: remove the solicitation optics now (additively), do the proper split later when the receiving package is built.Signal that informed the deprecation window
30-day telemetry on one active install:
validate(14),doctor(7),adf.evidence(7),run(5),blast(5),audit(3),surface(3).architectandscaffolddon't register.runis ~10% of governance use combined — real but not dominant. Justifies a deprecation-with-notice path rather than same-release removal.Follow-ups (explicitly not this PR)
@stackbilt/cliinto@stackbilt/build— list of files, target repo, publish pipeline.login,credentialspersistence,run/architect/scaffold. They live in@stackbilt/buildby then.Test plan
pnpm buildclean.pnpm test— 405/405 pass (including the new 6 tests and the previously-flaky precommit-hook integration test which passed cleanly this run at 40s).charter loginwith no args emits the stderr deprecation notice and preserves existing "Logged in as: …" output when stored creds are present.STACKBILT_API_KEY=ea_… charter loginemits the deprecation notice and reports "Using STACKBILT_API_KEY from environment: …".