Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions .claude/skills/quartr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,19 @@ Precedence (highest to lowest):
2. `QUARTR_API_KEY` env var
3. `~/.config/quartr/config.json` (written 0600 by `quartr auth login`)

For durable use:
For durable use, run `quartr auth login` once with `QUARTR_API_KEY` exported —
the command picks up the env var via the standard precedence and persists it
to `~/.config/quartr/config.json`. Avoid `--api-key VALUE` on `auth login`:
the literal key ends up in shell history, `ps`, scrollback, and CI logs.
When piping from a secret store, use `--api-key-stdin`:

```bash
quartr auth login --api-key "$QUARTR_API_KEY"
# Idiomatic
export QUARTR_API_KEY=...
quartr auth login

# Pipe from a secret store
op read op://Personal/Quartr/api_key | quartr auth login --api-key-stdin
```

For project-scoped use with a `.env` file:
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ build:

install:
go install ./cmd/quartr
@if [ -n "$$QUARTR_API_KEY" ]; then $(GOBIN)/quartr auth login --api-key "$$QUARTR_API_KEY"; fi
@if [ -n "$$QUARTR_API_KEY" ]; then printf '%s' "$$QUARTR_API_KEY" | $(GOBIN)/quartr auth login --api-key-stdin; fi

test:
go test ./...
Expand Down
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,22 @@ export QUARTR_API_KEY="your-api-key"
Or store it locally:

```bash
quartr auth login --api-key "$QUARTR_API_KEY"
# Reads QUARTR_API_KEY from the environment if set; otherwise prompts.
quartr auth login
quartr auth show
```

The key is written to `~/.config/quartr/config.json` with file mode `0600`.

For piping the key in (e.g. from a secret store) without exposing it via argv:

```bash
op read op://Personal/Quartr/api_key | quartr auth login --api-key-stdin
```

`--api-key VALUE` is also supported but discouraged for `auth login` because
the value leaks via shell history, `ps`, terminal scrollback, and CI logs.

Config precedence is:

1. global CLI flags
Expand Down
17 changes: 14 additions & 3 deletions internal/cli/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
"io"
"net/url"
"os"
"path/filepath"
Expand All @@ -23,16 +24,26 @@ func (a *app) handleAuth(args []string) error {
switch args[0] {
case "login", "set-key":
fs := newFlagSet("auth login", a.errOut)
apiKey := fs.String("api-key", "", "Quartr API key")
apiKeyStdin := fs.Bool("api-key-stdin", false, "read API key from stdin (one line, trimmed)")
baseURL := fs.String("base-url", a.cfg.BaseURL(), "API base URL")
format := fs.String("format", a.cfg.Format(), "default output format")
timeout := fs.String("timeout", a.cfg.Timeout(), "default HTTP timeout, e.g. 30s")
if err := parseInterspersed(fs, args[1:]); err != nil {
return err
}

key := strings.TrimSpace(*apiKey)
if key == "" {
// Source priority: --api-key-stdin > resolved config (global flag/env/file) > interactive prompt.
// The global --api-key flag is honored via a.cfg.APIKey() but discouraged for `auth login`
// because the literal value leaks via argv (ps, history, scrollback, CI logs).
var key string
switch {
case *apiKeyStdin:
line, err := bufio.NewReader(os.Stdin).ReadString('\n')
if err != nil && !errors.Is(err, io.EOF) {
return fmt.Errorf("read api key from stdin: %w", err)
}
key = strings.TrimSpace(line)
default:
key = strings.TrimSpace(a.cfg.APIKey())
}
if key == "" {
Expand Down
Loading