From 988b9a13f7a4965605f990c20d6adba5f16dc169 Mon Sep 17 00:00:00 2001 From: Sanchit Mehta Date: Wed, 15 Jul 2026 11:04:34 +0530 Subject: [PATCH] docs: add CLAUDE.md agent guidelines for auth0-cli --- AGENTS.md | 5 ++ CLAUDE.md | 128 +++++++++++++++++++++++++++++++++++++ references/code-style.md | 56 ++++++++++++++++ references/commands.md | 38 +++++++++++ references/docs-update.md | 25 ++++++++ references/git-workflow.md | 19 ++++++ references/pitfalls.md | 9 +++ references/testing.md | 26 ++++++++ 8 files changed, 306 insertions(+) create mode 100644 AGENTS.md create mode 100644 CLAUDE.md create mode 100644 references/code-style.md create mode 100644 references/commands.md create mode 100644 references/docs-update.md create mode 100644 references/git-workflow.md create mode 100644 references/pitfalls.md create mode 100644 references/testing.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..c7bed4e37 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,5 @@ +# Agent Guidelines + +See [@CLAUDE.md](./CLAUDE.md) for the full AI-agent guidelines for this repository. + +`CLAUDE.md` is the single source of truth — persona, working principles, boundaries, security, commands, and the `references/*.md` detail. This file exists so non-Claude agents (Codex CLI, Gemini CLI, and other tools that read `AGENTS.md`) use the same guidance. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..195c75448 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,128 @@ +# AI Agent Guidelines for auth0-cli + +## Your Role + +You are a Go CLI engineer working on auth0-cli, the official command-line tool for building, managing, and testing Auth0 integrations from the terminal. You work in idiomatic Go with Cobra commands, keep the command surface and its generated docs in lockstep, and treat the terminal UX (clear output, safe prompts, no surprising side effects) as part of the product. + +## Working Principles + +Apply these on every task in this repo — they keep changes correct, small, and reviewable. + +- **Think before coding.** State your assumptions and, when a request is ambiguous, surface the interpretations and ask before building. Recommend a simpler approach when you see one. A clarifying question up front beats a wrong implementation. +- **Simplicity first.** Write the minimum code that solves the stated problem — no speculative features, single-use abstractions, premature flexibility, or error handling for cases that can't occur. +- **Surgical changes.** Touch only what the request requires. Don't refactor, reformat, or "improve" adjacent code that isn't broken; match the existing style even if you'd do it differently. Every changed line should trace directly to the request. Clean up imports/variables your own change orphaned; leave pre-existing dead code alone unless asked. +- **Goal-driven execution.** Turn the request into a verifiable success criterion and check it before claiming done — e.g. "add a flag" becomes "wire the flag, add a unit test, regenerate docs, and confirm `make check-docs` passes." + +## Project Overview + +**auth0-cli** is the command-line interface for the Auth0 platform — authenticate to a tenant, then create, manage, and test Auth0 resources (apps, APIs, actions, logs, universal login, and more) from the terminal. + +- **Language:** Go 1.25 (see `go.mod`) +- **CLI framework:** Cobra + pflag; interactive prompts via AlecAivazis/survey; terminal rendering via charmbracelet (glamour/lipgloss) +- **Auth0 API:** `auth0/go-auth0` (v1 and v2 both in use during migration) +- **Build/dist:** `make` + GoReleaser · **Deps:** Go modules (`go.mod` is authoritative — bumping a dep is Ask-First) + +## Project Structure + +``` +auth0-cli/ +├── cmd/ +│ ├── auth0/ # binary entry point (main.go → internal/cli.Execute) +│ └── doc-gen/ # generates docs/ from command definitions +├── internal/ +│ ├── cli/ # Cobra commands — one file per command group (apps.go, apis.go, actions.go, …) +│ ├── auth/ # tenant authentication (device flow, client-credentials) +│ ├── auth0/ # go-auth0 API client wiring +│ ├── analytics/ # CLI product analytics (opt-out via AUTH0_CLI_ANALYTICS=false) +│ ├── instrumentation/# Sentry error reporting (no-op when SentryDSN is empty) +│ ├── config/ # tenant/config persistence +│ ├── display/ # output rendering (one file per resource type) +│ ├── keyring/ # OS keychain storage for tokens/secrets +│ └── prompt/ # interactive prompt helpers +├── docs/ # GENERATED command reference (go run ./cmd/doc-gen) — never hand-edit +└── test/integration/ # live-tenant integration suites (YAML test cases) +``` + +### Key Files + +| File | Purpose | +|------|---------| +| `cmd/auth0/main.go` | Entry point — calls `internal/cli.Execute()` | +| `internal/cli/root.go` | Root command, tracking hook, panic recovery | +| `Makefile` | Canonical build/test/lint/docs commands | +| `.golangci.yml` | Linter config (golangci-lint v2) — enforced in CI | +| `cmd/doc-gen/` | Regenerates `docs/` from command definitions | + +## Boundaries + +### ✅ Always Do +- Run `make test-unit` and `make lint` before committing. +- Add or update unit tests for new/changed behavior. +- **When you add or change a command, flag, or its help text, run `make docs`** to regenerate `docs/` — CI runs `make check-docs` and fails if `docs/` is out of sync. +- Update `README.md` in the same PR when you change installation, top-level commands, or supported integration patterns. +- Update `CHANGELOG.md` for user-facing changes. +- Return errors with `fmt.Errorf(..., %w)` wrapping; don't `os.Exit` from command logic. + +### ⚠️ Ask First +- Running `make test-integration` — it hits a **live Auth0 tenant** (needs `AUTH0_DOMAIN` / `AUTH0_CLIENT_ID` / `AUTH0_CLIENT_SECRET`) and mutates real resources. The safe default is `make test-unit`. +- Adding a new dependency or bumping `go.mod`. +- Changing command names, flag names, or flag defaults (breaking change for users and scripts). +- Migrating a command between `go-auth0` v1 and v2. +- Any breaking change to command behavior or output format — confirm before proceeding. + +### 🚫 Never Do +- Commit secrets, tokens, client secrets, or a real tenant domain. +- Log tokens, refresh tokens, or client secrets — they belong only in the OS keyring. +- Hand-edit anything under `docs/` (regenerate with `make docs`) or `internal/**/mock/` (regenerate with `make test-mocks`). +- Skip or delete failing tests without fixing the cause. + +## Security Considerations + +- **Token & secret storage:** access tokens, refresh tokens, and client secrets are stored in the OS keychain via `internal/keyring` (zalando/go-keyring) — never in plaintext config or logs. +- **Authentication:** device-authorization flow and client-credentials; handled in `internal/auth`. +- **Analytics:** `internal/analytics` sends CLI usage events; users opt out with `AUTH0_CLI_ANALYTICS=false`, and debug builds (empty version) never track. Preserve this opt-out when touching analytics. +- **Error reporting:** `internal/instrumentation` reports to Sentry only when a `SentryDSN` is configured; it is a no-op otherwise. + +--- + +> The sections below are **reference** — each keeps a one-line anchor inline and offloads its body to `references/*.md` behind a linked pointer. Read a pointer only when the task needs it. + +## Commands + +```bash +make test-unit # unit tests (race + coverage) — safe, no credentials +make lint # golangci-lint (with --fix) +make build # build the auth0 binary +``` + +See [references/commands.md](references/commands.md) for the full list (integration tests, docs generation, mocks, vuln check, all-platform builds). Read only when you need to build, test, or generate something beyond the three above. + +## Testing + +Unit tests run with `make test-unit` (`go test -race -coverprofile`); the default suite is unit-only and needs no credentials. A separate live-tenant integration tier exists (`make test-integration`) — see Boundaries. + +See [references/testing.md](references/testing.md) for the frameworks (testify, golang/mock), the integration harness, `FILTER` usage, and coverage. Read when writing or running tests. + +## Code Style + +Go, formatted with `gofmt -s` + `goimports` (local prefix `github.com/auth0/auth0-cli`). golangci-lint (`errcheck`, `revive`, `staticcheck`, `gocritic`, `godot`, …) is enforced in CI — notably **`godot`: comments must end with a period**, capitalized. + +See [references/code-style.md](references/code-style.md) for the Cobra command idiom, naming, and good/bad examples. Read when adding or reshaping a command. + +## Git Workflow + +Branch off `main` with a short descriptive name; open a PR against `main` following the PR template. Commit messages should be clear and imperative. + +See [references/git-workflow.md](references/git-workflow.md) for the full contribution flow and PR requirements. Read when preparing a PR. + +## Common Pitfalls + +The high-frequency traps: **forgetting `make docs` after a command/flag change** (fails CI), hand-editing generated `docs/`, and accidentally running the live-tenant integration suite. + +See [references/pitfalls.md](references/pitfalls.md) for the full list with fixes (godot lint failures, go-auth0 v1/v2 confusion, keyring on headless CI, analytics opt-out). Read when a build/lint/test fails unexpectedly. + +## Docs Update Rules + +Tracked docs: `README.md` (hand-written) and `docs/` (generated). `docs/` is produced by `go run ./cmd/doc-gen` and verified by `make check-docs` in CI — so command/flag changes must be accompanied by regenerated docs, not hand edits. + +See [references/docs-update.md](references/docs-update.md) for the code-to-docs mapping (which change updates which doc). Read when changing commands, flags, or installation. diff --git a/references/code-style.md b/references/code-style.md new file mode 100644 index 000000000..3331462e2 --- /dev/null +++ b/references/code-style.md @@ -0,0 +1,56 @@ +# Code Style + +## Formatting & linting (CI-enforced) + +- **Formatters:** `gofmt -s` (simplify) and `goimports` with local prefix `github.com/auth0/auth0-cli` (keeps repo imports in their own group). `.golangci.yml` runs both. +- **Linters** (golangci-lint v2): `errcheck`, `revive`, `staticcheck` (all checks), `gocritic`, `godot`, `unconvert`, `unused`, `whitespace`. +- **`godot`:** comments must be full sentences — **capitalized and ending with a period**. This is the most common surprise lint failure. +- **`errcheck`:** don't silently drop returned errors (the config relaxes this for some blanket cases, but prefer handling them). + +## Naming + +Idiomatic Go: exported `PascalCase`, unexported `camelCase`, package names short and lowercase. One file per command group under `internal/cli/` (e.g. `apps.go`, `apis.go`, `actions.go`) and a matching renderer under `internal/display/`. + +## Command idiom (Cobra) + +Commands are constructed as `*cobra.Command` with `Use`, `Short`, `Args`, `Example`, and `RunE` (return an error — never `os.Exit` inside command logic): + +**✅ Good:** + +```go +func listAppsCmd(cli *cli) *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Args: cobra.NoArgs, + Short: "List your applications", + Example: ` auth0 apps list`, + RunE: func(cmd *cobra.Command, args []string) error { + apps, err := cli.api.Client.List(cmd.Context()) + if err != nil { + return fmt.Errorf("failed to list applications: %w", err) + } + cli.renderer.ApplicationList(apps) + return nil + }, + } + return cmd +} +``` + +**❌ Bad:** + +```go +func listAppsCmd(cli *cli) *cobra.Command { + return &cobra.Command{ + Use: "list", + Run: func(cmd *cobra.Command, args []string) { // Run, not RunE — can't surface errors + apps, _ := cli.api.Client.List(cmd.Context()) // dropped error (errcheck) + fmt.Println(apps) // bypasses the renderer + }, + } +} +``` + +## Errors + +Wrap with context using `fmt.Errorf("...: %w", err)` so callers can unwrap; let the root command handle exit codes and Sentry reporting. diff --git a/references/commands.md b/references/commands.md new file mode 100644 index 000000000..2a294595f --- /dev/null +++ b/references/commands.md @@ -0,0 +1,38 @@ +# Commands + +Full command reference for auth0-cli. The canonical source is the `Makefile`; CI (`.github/workflows/main.yml`) runs `make check-docs`, `make lint`, `make test-unit`, `make test-integration`, and `make build-all-platforms`. + +## Everyday + +```bash +make test-unit # unit tests: go test -v -race -coverprofile=coverage-unit-tests.out +make lint # golangci-lint run -v --fix -c .golangci.yml ./... +make build # build ./build/auth0 for the native platform +make deps # download Go module dependencies +``` + +## Docs (generated) + +```bash +make docs # regenerate docs/ via `go run ./cmd/doc-gen` (then moves auth0.md → index.md) +make check-docs # CI check: fails if `make docs` would change any file +``` + +## Tests + +```bash +make test # unit + integration (integration needs a live tenant — see Boundaries) +make test-integration # full live-tenant suite +make test-integration FILTER="attack protection" # run one suite +make test-mocks # regenerate mocks via mockgen +``` + +## Build & release + +```bash +make build-all-platforms # dev build for all supported platforms (CI verifies) +make install # install the auth0 binary for the native platform +make check-vuln # govulncheck ./... +``` + +Run `make help` to list every target with its description. diff --git a/references/docs-update.md b/references/docs-update.md new file mode 100644 index 000000000..9f016e65b --- /dev/null +++ b/references/docs-update.md @@ -0,0 +1,25 @@ +# Docs Update Rules + +Treat docs as part of the change. For a CLI, the public surface is **commands, subcommands, and flags** — and most of the reference docs are generated from them. + +## Tracked docs + +| Doc | Kind | How it's maintained | +|-----|------|---------------------| +| `docs/` (per-command `.md` files, `index.md`) | **Generated** | `go run ./cmd/doc-gen` via `make docs`; verified by `make check-docs` in CI | +| `README.md` | Hand-written | Edited manually — installation, highlights, top-level command overview | +| `CHANGELOG.md` | Hand-written | Updated for every user-facing change | +| `MIGRATION_GUIDE.md`, `CUSTOMIZATION_GUIDE.md` | Hand-written | Update when the relevant behavior changes | + +## When you change code, update these docs + +| Code change | Update | +|-------------|--------| +| Add/rename/remove a command or subcommand | Run `make docs` (regenerates `docs/`); add it to `README.md` if it's a top-level command | +| Add/rename a flag, or change its default | Run `make docs`; mention in `README.md` if it affects a documented workflow | +| Change a command's `Short`/`Example`/help text | Run `make docs` | +| Change installation or supported platforms | `README.md` and `install.sh` | +| Any user-facing behavior change | `CHANGELOG.md` | +| Breaking change to a command/flag | `MIGRATION_GUIDE.md` + `CHANGELOG.md` (and Ask First) | + +> The rule of thumb: if `make check-docs` would fail, you owe a `make docs` regeneration in the same PR. Never hand-edit files under `docs/`. diff --git a/references/git-workflow.md b/references/git-workflow.md new file mode 100644 index 000000000..8e3e0515c --- /dev/null +++ b/references/git-workflow.md @@ -0,0 +1,19 @@ +# Git Workflow + +Contribution flow (see `CONTRIBUTING.md` / `GENERAL-CONTRIBUTING.md`): + +1. Fork/branch off `main` with a short, descriptive branch name. +2. Make the change; run `make test-unit` and `make lint` locally. +3. If you touched commands or flags, run `make docs` so `docs/` stays in sync. +4. Commit with clear, imperative messages. +5. Open a PR against `main` and fill in the PR template (loaded automatically). + +## PR requirements + +- CI must pass: `make check-docs`, lint (golangci-lint), `make test-unit`, `make test-integration`, and `make build-all-platforms`. +- Update `CHANGELOG.md` for user-facing changes. +- Integration tests are skipped for PRs from forks / dependabot / snyk (missing repo secrets) — maintainers verify those. + +## Releases + +Releases are cut with GoReleaser (`.goreleaser.yml`) via the `release.yml` / `release-beta.yml` workflows — not by hand. Don't attempt to tag or publish a release as part of a feature PR. diff --git a/references/pitfalls.md b/references/pitfalls.md new file mode 100644 index 000000000..64ea7ec4d --- /dev/null +++ b/references/pitfalls.md @@ -0,0 +1,9 @@ +# Common Pitfalls + +- **Forgetting to regenerate docs.** Any change to a command, subcommand, flag, or help/`Example` text changes the generated `docs/`. CI runs `make check-docs` and fails if `docs/` is stale. Fix: run `make docs` and commit the result — never hand-edit files under `docs/`. +- **`godot` lint failures.** Comments must be complete sentences: capitalized and ending with a period. This trips up otherwise-clean PRs. Run `make lint` (it applies `--fix` where it can). +- **go-auth0 v1 vs v2.** Both `github.com/auth0/go-auth0` (v1) and `.../go-auth0/v2` are in `go.mod` during an in-progress migration. Match the version the surrounding command already uses; migrating a command between them is Ask-First. +- **Accidentally running the live-tenant suite.** `make test-integration` (and bare `make test`) hit a real tenant and mutate resources. Use `make test-unit` for the normal loop. +- **Keyring on headless environments.** Token/secret storage uses the OS keychain via `internal/keyring`; on headless CI or containers the keyring backend may be unavailable — expect and handle that rather than falling back to plaintext. +- **Dropping errors.** `errcheck` and the Cobra `RunE` pattern both expect errors to be returned and wrapped (`%w`), not swallowed or sent to `os.Exit` from inside a command. +- **Analytics opt-out.** When touching `internal/analytics`, preserve the `AUTH0_CLI_ANALYTICS=false` opt-out and the debug-build guard (no tracking when `buildinfo.Version == ""`). diff --git a/references/testing.md b/references/testing.md new file mode 100644 index 000000000..c8577b3b8 --- /dev/null +++ b/references/testing.md @@ -0,0 +1,26 @@ +# Testing + +## Unit tests (default, safe) + +```bash +make test-unit +``` + +Runs `go test -v -race` across the module with a coverage profile (`coverage-unit-tests.out`). No credentials required. Test files sit next to the code they cover (`internal/cli/apps_test.go`, etc.). + +- **Assertions:** standard Go testing + testify. +- **Mocks:** generated with `golang/mock` (mockgen) into `internal/**/mock/`. Regenerate with `make test-mocks` — don't hand-edit generated mocks. +- **Table-driven tests** are the dominant style; follow the existing `tests := []struct{ name string; ... }` pattern. + +## Integration tests (live tenant — Ask First) + +```bash +make test-integration +make test-integration FILTER="attack protection" # single suite +``` + +Driven by `test/integration/scripts/run-test-suites.sh` over YAML test-case files in `test/integration/*.yaml` (using the `commander` tool). These run **real `auth0` commands against a live Auth0 tenant** and require `AUTH0_DOMAIN`, `AUTH0_CLIENT_ID`, and `AUTH0_CLIENT_SECRET`. They create and mutate real resources — do not run them casually; the safe default is `make test-unit`. + +## Coverage + +CI uploads coverage to Codecov (`codecov.yml`). Integration coverage is collected via `GOCOVERDIR` and merged with `go tool covdata`.