diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a4c678..8e769c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,18 +4,16 @@ All notable changes to this project will be documented in this file. ## [Unreleased] -### Fixed - -- `grant login` no longer hangs on WSL2; grant now detects WSL and forces the file-based keyring. A token stored in the OS keyring becomes invisible — re-run `grant login` if prompted - ### Added -- End-to-end self-update tests that replace a real, running binary (`internal/selfupdate/e2e_test.go`, build tag `selfupdate_e2e`). They compile two fixture binaries from a dependency-free module, execute one, and swap it through grant's own apply path while a process is still running from that image — so the Windows file-locking semantics behind the two-rename swap are actually exercised, not just the bookkeeping. Success and rollback paths are both covered, and the rolled-back binary is asserted to still run. No network access is required -- CI runs the new self-update end-to-end tests on **both** `ubuntu-latest` and `windows-latest`, closing the gap left by the Windows CI leg added in 0.8.0, which only ran `go build` and `go test` and never exercised a binary replacing itself on Windows +- End-to-end self-update tests that replace a real, running binary, covering both the success and rollback paths (build tag `selfupdate_e2e`) +- CI runs the self-update end-to-end tests on both `ubuntu-latest` and `windows-latest` +- `grant revoke --output json` gains a per-session `outcome` field ### Fixed -- `grant revoke` now exits 1 when the service refused, returned an unrecognized status for, or returned no result at all for any requested session, instead of reporting success; accepted-but-`in_progress` revocations still exit 0, and `--output json` gains a per-session `outcome` field — check scripts relying on exit 0. +- `grant login` no longer hangs on WSL2; grant now detects WSL and forces the file-based keyring. A token stored in the OS keyring becomes invisible — re-run `grant login` if prompted +- `grant revoke` now exits 1 when any requested session was not accepted for revocation, instead of reporting success — check scripts relying on exit 0 ## [0.8.0] - 2026-08-14 diff --git a/CLAUDE.md b/CLAUDE.md index 697ee1b..3487905 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3,7 +3,7 @@ ## Project - **Language:** Go 1.25+ - **Module:** `github.com/aaearon/grant-cli` -- **Dependencies:** `github.com/cyberark/idsec-sdk-golang` is the primary dependency; zero-new-Go-module-deps is a goal, not an absolute rule. Documented exception: `github.com/minio/selfupdate` (+ its one transitive `aead.dev/minisign`) for `grant update`, adopted to remove the abandoned `rhysd/go-github-selfupdate` and advisory GO-2026-5932. Net effect: build graph (`go list -deps`) 39 -> 33 modules, `go.mod` requires 47 -> 39, full module graph (`go list -m all`) 110 -> 95 +- **Dependencies:** `github.com/cyberark/idsec-sdk-golang` is the primary dependency; zero-new-Go-module-deps is a goal, not an absolute rule. Documented exception: `github.com/minio/selfupdate` (+ its one transitive `aead.dev/minisign`) for `grant update`, adopted to remove the abandoned `rhysd/go-github-selfupdate` and advisory GO-2026-5932. It was a net *reduction* in every dependency measure — the exception cost nothing. Measure with `go list -deps` / `go list -m all` if a current figure is needed; do not record one here ## SDK Import Conventions ```go @@ -125,7 +125,7 @@ Custom `SCAAccessService` follows SDK conventions: - `internal/ui/tty.go` — `IsTerminalFunc` (overridable), `IsInteractive()`, `ErrNotInteractive` - All interactive prompts (`SelectTarget`, `SelectSessions`, `ConfirmRevocation`, `SelectGroup`, `uiUnifiedSelector.SelectItem`, `surveyNamePrompter.PromptName`) fail fast with `ErrNotInteractive` when stdin is not a TTY - Error messages suggest the appropriate non-interactive flag (e.g., `--target/--role`, `--all`, `--yes`, `--group`, `--favorite`) -- `go-isatty` v0.0.20 is a direct dependency (promoted from indirect via survey) +- `go-isatty` is a direct dependency (promoted from indirect via survey); see `go.mod` for the pinned version ## JSON Output - `--output` / `-o` persistent flag on root command: `text` (default) or `json` @@ -191,7 +191,7 @@ Custom `SCAAccessService` follows SDK conventions: ## Lint - Config: `.golangci.yml` (golangci-lint v1 format) -- 20 linters enabled: defaults (errcheck, gosimple, govet, ineffassign, staticcheck, unused) + bodyclose, errorlint, noctx, gosec (G101 excluded), errname, gocritic, misspell, revive, gocognit (threshold 40), perfsprint, unconvert, usetesting, gofmt (`simplify: true`) +- Linters enabled (`disable-all: true`, so this list is exhaustive): defaults (errcheck, gosimple, govet, ineffassign, staticcheck, unused) + bodyclose, errorlint, noctx, gosec (G101 excluded), errname, gocritic, misspell, revive, gocognit (threshold 40), perfsprint, unconvert, usetesting, gofmt (`simplify: true`) - Test files excluded from gosec, gocognit, bodyclose — `gofmt` has no exclusion, formatting is universal - Run `gofmt -s -w .` before committing; `gofumpt` was rejected because the codebase is not gofumpt-clean - `revive/unused-parameter` and `revive/exported` disabled (Cobra signatures, established API names) @@ -208,6 +208,8 @@ make lint # Run linter (golangci-lint) make clean # Clean build artifacts ``` - `-trimpath` used in both `Makefile` and `.goreleaser.yaml` for reproducible builds +- `VERSION ?= dev` (`Makefile:2`) is injected as `-X ...cmd.version=$(VERSION)` (`Makefile:5-8`), so a plain `make build` stamps `version=dev`. `runUpdate` refuses `""`/`"dev"` (`cmd/update.go:38-39`, "cannot update a dev build"), so `grant update` can never succeed on a default local build +- To exercise `grant update` locally: `make build VERSION=0.7.0`, then `./grant update`. Use a version *older* than the latest release so an update is actually found - `.goreleaser.yaml` uses `CommitDate` (not build date) and `mod_timestamp` for reproducibility ## CI @@ -219,6 +221,14 @@ make clean # Clean build artifacts - Tests must be OS-portable. Never assert POSIX permission bits without a `runtime.GOOS == "windows"` skip: Go synthesizes `0666`/`0777` for Windows files and `os.Chmod` there only toggles the read-only attribute. Current skips: `internal/config/config_test.go` (`TestLoadConfig_PermissionError`, `TestConfigDir_Error` — chmod 0000 and `HOME`) and `internal/cache/cache_test.go` (`TestSet_FilePermissions`) - Prefer a portable construction over a skip where one exists. To force a write failure, point at a path whose parent component is an existing regular file (`MkdirAll` fails with ENOTDIR on POSIX and ERROR_DIRECTORY on Windows) rather than a hardcoded `/dev/null/...` path, which is an ordinary writable location on Windows +## CHANGELOG Style +Entries are short and concise. This applies to `[Unreleased]` and everything added from now on; already-released sections are published history and are not rewritten. +- One line per entry — a single sentence, ideally under ~120 characters. +- Say WHAT changed and, where it isn't obvious, the user-visible effect. Not the mechanism, not the root cause, not measurements, not `file:line` references. +- Rationale, evidence, benchmarks, dependency counts and advisory analysis go in the PR description. Durable architecture and policy go in CLAUDE.md. +- Keep the Keep-a-Changelog section headings: `Added` / `Changed` / `Fixed` / `Security`. +- A breaking or behaviour-changing entry may add a short second clause naming the impact. Brevity must never hide a behavioural break from someone skimming before an upgrade. + ## Release Process 1. Move `[Unreleased]` entries in `CHANGELOG.md` to a new `[X.Y.Z] - YYYY-MM-DD` section (leave `[Unreleased]` header empty) 2. Commit: `docs: prepare CHANGELOG for vX.Y.Z release` diff --git a/README.md b/README.md index e3921e3..4070f39 100644 --- a/README.md +++ b/README.md @@ -219,6 +219,8 @@ make test-all # All tests make lint # Lint (golangci-lint) ``` +`make build` stamps the version as `dev`, and `grant update` refuses to update a dev build. To try `grant update` locally, build with an explicit version older than the latest release: `make build VERSION=0.7.0`. + ## Contributing Contributions welcome! Please follow existing patterns, write tests (TDD preferred), update docs, and use conventional commits.