Skip to content

feat(cli): add tigris env to hand credentials to other tools - #321

Open
katieschilling wants to merge 1 commit into
mainfrom
katie/cli-env
Open

katieschilling wants to merge 1 commit into
mainfrom
katie/cli-env

Conversation

@katieschilling

@katieschilling katieschilling commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor

What

A new top-level command, tigris env, that prints the active credentials as the environment variables the AWS SDKs, the AWS CLI and the Tigris SDKs read:

eval "$(tigris env)"                 # this shell: boto3, aws-cli, rclone now hit Tigris
tigris env --format dotenv > .env    # a .env for the app
tigris env --shell fish | source     # fish
tigris env --shell powershell        # PowerShell
tigris env --tigris                  # TIGRIS_STORAGE_* names for @tigrisdata/storage and storage-go
tigris env --json                    # for scripts

Default output:

export AWS_ACCESS_KEY_ID='tid_AaBb'
export AWS_SECRET_ACCESS_KEY='tsec_XxYy'
export AWS_ENDPOINT_URL_S3='https://t3.storage.dev'
export AWS_ENDPOINT_URL_IAM='https://iam.storageapi.dev'
export AWS_REGION='auto'

Why

The CLI already reads AWS_* and TIGRIS_STORAGE_* (see AUTHENTICATION.md and resolveAuthMethod), but nothing ever wrote them. Going from "I ran tigris login" to "my app / boto3 / the AWS CLI talks to Tigris" meant copying five values out of the docs by hand, which is exactly the step that stalls a migration. The init --agent recipe even spells out the five-variable mapping for agents to transcribe; this makes it one command.

It's the same convention other CLIs use to move a credential from their own store into the shell:

  • gh auth token prints the GitHub token for GH_TOKEN (export GH_TOKEN=$(gh auth token)).
  • fly auth token prints the Fly.io token for FLY_API_TOKEN.
  • direnv's entire model is an .envrc of exports that the shell evaluates on cd.

Design notes

  • stdout is only the assignments. Anything meant for a human goes to stderr, so eval "$(tigris env)" and > .env are safe. The existing messages machinery already writes failures to stderr.
  • Quoting is per shell. POSIX single quotes ('\''), fish single quotes (\'), PowerShell single quotes (''). dotenv values are bare unless they contain something that needs double quotes. renderEnv and envVars are pure functions with unit tests for each.
  • OAuth sessions can't be exported. They carry a bearer token that only the CLI can use, so instead of printing empty keys, env fails with the three commands that get you there (access-keys create → configure → env). Every other auth method (AWS profile, env vars, credentials login, configured) works, and a custom endpoint from configure --endpoint is preserved.
  • Browser build gets it for free via the generated registry, so the embedded shell on the website can run it too.
  • README.md is regenerated from specs.yaml (pnpm run updatedocs); AUTHENTICATION.md gains a "Handing Credentials to Other Tools" section; changeset included (minor).

Testing

  • pnpm exec vitest run (1015 tests, 40 files) and tsc --noEmit pass; biome lint clean.
  • Smoke-tested the built CLI: sh / fish / PowerShell / dotenv / json output, eval "$(…)" round-trip, a secret containing ', --tigris, and the unauthenticated path (exit 2, nothing on stdout).

Follow-ups (not in this PR)

  • The init --agent recipe could say "run tigris env --format dotenv" instead of listing the mapping.
  • The website's "Keep everything, swap the endpoint" section can use this in the embedded shell.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RxFeqmYcQs5JbydZeCzw2j


Note

Medium Risk
The command intentionally writes secrets to stdout for eval/redirect; quoting is tested and OAuth export is blocked, but mishandling output still exposes credentials.

Overview
Adds tigris env, a command that prints the active access-key credentials as environment variables so AWS SDKs, the AWS CLI, and Tigris SDKs can use the same login without manual copy-paste.

Output goes only to stdout (assignments/errors on stderr), supporting eval "$(tigris env)", dotenv files, and shell (sh, fish, PowerShell) via --format / --shell. --tigris switches to TIGRIS_STORAGE_* names; JSON is available for scripts. Implementation lives in env.ts (envVars, renderEnv) wired through specs.yaml, with unit tests for variable sets and quoting.

OAuth-only sessions are rejected with guidance to create/configure an access key first. Docs (AUTHENTICATION.md, README.md) and a minor changeset document the workflow.

Reviewed by Cursor Bugbot for commit 37cc105. Bugbot is set up for automated code reviews on this repo. Configure here.

The CLI reads AWS_* and TIGRIS_STORAGE_* variables but never wrote them,
so going from "logged in with tigris" to "boto3 works" meant copying five
values out of the docs by hand. `tigris env` prints them:

  eval "$(tigris env)"
  tigris env --format dotenv > .env
  tigris env --shell fish | source
  tigris env --tigris          # TIGRIS_STORAGE_* names
  tigris env --json

Only the assignments go to stdout, so the output is safe to eval or
redirect; anything for a human goes to stderr. This is the convention
`gh auth token`, `fly auth token` and direnv's `.envrc` rely on. OAuth
sessions carry a token that only the CLI can use, so `env` explains how to
mint an access key in that case instead of printing something that would
not work.

Quoting is per shell (POSIX, fish, PowerShell) and dotenv values are
quoted only when they need to be; renderEnv and envVars are pure and
covered by unit tests. README regenerated from specs; AUTHENTICATION.md
gains a section; changeset included.

Assisted-by: Claude Fable 5.1 via Claude Code
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RxFeqmYcQs5JbydZeCzw2j
@greptile-apps

greptile-apps Bot commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

The implementation appears behaviorally safe, but the repository’s explicit documentation terminology requirement should be satisfied before merging.

Fix All in Claude CodeFindings

  1. P2 Incorrect Tigris terminology ▶

Summary

This PR adds tigris env, allowing active access-key credentials and endpoints to be rendered for POSIX shells, fish, PowerShell, dotenv files, or JSON.

  • Supports AWS-compatible and TIGRIS_STORAGE_* variable names.
  • Rejects OAuth-only sessions with guidance for creating an exportable access key.
  • Adds command registration, generated CLI documentation, authentication guidance, rendering tests, and a release changeset.
  • The implementation appears functionally sound, but several new documentation strings require a small terminology correction to satisfy the repository’s documentation rule.

Reviews (1) · Last reviewed commit: "feat(cli): add tigris env to hand creden..."

onFailure: 'Failed to get user information'
onAlreadyDone: "Not authenticated\nRun \"tigris login\" to authenticate"
# env
- name: env

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Incorrect Tigris terminology

The command description says “the Tigris SDKs,” which violates the repository directive to use “Tigris” without the definite article. Use “Tigris SDKs” here and in the matching authentication guide and changeset wording; regenerating the README should update its generated occurrences. This repository requirement must be satisfied before merging.

Rule Used: Don't use the definite article 'the' before 'Tigris' in documentation (e.g., write 'Tigris' not 'the Tigris'). (source)

Learned From
tigrisdata/tigris-os-docs#262

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 37cc105. Configure here.

'The current session has no access key to export (OAuth sessions carry a token that only the CLI can use). ' +
'Create one with "tigris access-keys create <name>", save it with "tigris configure", then run "tigris env" again.'
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OAuth session blocks configured key export

High Severity

env resolves credentials through getStorageConfig(), which prefers an active OAuth session over keys saved by tigris configure. OAuth config always has empty accessKeyId and secretAccessKey, so the documented recovery path — create a key, configure, then env — still fails after configure while the OAuth session remains active.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 37cc105. Configure here.

const tigris = getOption<boolean>(options, ['tigris']) === true;

const config = await getStorageConfig();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auto-login contaminates eval stdout

Medium Severity

Unauthenticated TTY runs call getStorageConfig(), which starts interactive auto-login and writes progress to stdout. eval "$(tigris env)" and redirects then capture that text. Auto-login also typically produces an OAuth session, which env cannot export, so the user is prompted to log in only to fail afterward.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 37cc105. Configure here.

@katieschilling

Copy link
Copy Markdown
Contributor Author

Follow-up for the --agent flag, once this ships:

tigris init --agent currently hands the agent the five-variable mapping to transcribe by hand (step "Configure the environment" in src/lib/init/plan.ts: AWS_ACCESS_KEY_ID = .id, AWS_SECRET_ACCESS_KEY = .secret, the two endpoints and AWS_REGION=auto). With tigris env in the CLI that step can become one instruction:

Run `tigris env --format dotenv >> .env` to write the credentials the SDK reads.

(or tigris env --tigris --format dotenv when the project uses @tigrisdata/storage / storage-go). Fewer values for the agent to copy, no chance of a typo in an endpoint, and the recipe stays correct if the variable set ever changes, because there is one source of truth for it. I left the recipe alone in this PR so the diff stays about the command; happy to do the recipe change as a separate small PR after this merges.

export AWS_REGION='auto'
```

This is the same convention other CLIs use to move a credential from their own store into the shell: `gh auth token` prints the GitHub token for `GH_TOKEN`, `fly auth token` prints the Fly.io token for `FLY_API_TOKEN`, and direnv's whole model is an `.envrc` of exports that the shell evaluates on `cd`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line can be removed


`tigris env` needs an access key. OAuth sessions carry a token that only the CLI can use, so from an OAuth session create a key first and save it:

```sh

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could these steps be simplified further

/**
* `tigris env`: hand the CLI's credentials to everything else.
*
* The CLI reads AWS_* and TIGRIS_STORAGE_* variables, but until now nothing

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you ask the agent to be concise when writing code comments? There are several unnecessary comments here

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.

2 participants