From 71c69fbb8a4b02909b4b01c2ce2f31f3feacc6e3 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 14:56:01 +0100 Subject: [PATCH 01/19] Allow test golden files and GitHub config in gitignore Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 1cf384b..5e01dcd 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,10 @@ Temporary Items *.yaml *.yml +# Allow test golden files and GitHub config +!**/testdata/** +!.github/** + dist/ /imscli go.mod.local From 82ad9eef0696d4ea7ebf85dc19471eaf2457af65 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 14:56:15 +0100 Subject: [PATCH 02/19] Add missing golden test files for pretty-print tests The *.json gitignore rule was preventing these from being tracked. Generated from the JSON() function output to match TestJSON expectations. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- cmd/pretty/testdata/already_indented.json | 3 +++ cmd/pretty/testdata/compact_array.json | 8 ++++++++ cmd/pretty/testdata/compact_object.json | 4 ++++ cmd/pretty/testdata/empty_array.json | 1 + cmd/pretty/testdata/empty_object.json | 1 + cmd/pretty/testdata/nested_objects.json | 7 +++++++ cmd/pretty/testdata/null_and_bool.json | 5 +++++ cmd/pretty/testdata/special_chars.json | 6 ++++++ cmd/pretty/testdata/unicode.json | 5 +++++ 9 files changed, 40 insertions(+) create mode 100644 cmd/pretty/testdata/already_indented.json create mode 100644 cmd/pretty/testdata/compact_array.json create mode 100644 cmd/pretty/testdata/compact_object.json create mode 100644 cmd/pretty/testdata/empty_array.json create mode 100644 cmd/pretty/testdata/empty_object.json create mode 100644 cmd/pretty/testdata/nested_objects.json create mode 100644 cmd/pretty/testdata/null_and_bool.json create mode 100644 cmd/pretty/testdata/special_chars.json create mode 100644 cmd/pretty/testdata/unicode.json diff --git a/cmd/pretty/testdata/already_indented.json b/cmd/pretty/testdata/already_indented.json new file mode 100644 index 0000000..7a9e864 --- /dev/null +++ b/cmd/pretty/testdata/already_indented.json @@ -0,0 +1,3 @@ +{ + "key": "value" +} diff --git a/cmd/pretty/testdata/compact_array.json b/cmd/pretty/testdata/compact_array.json new file mode 100644 index 0000000..3a11aa1 --- /dev/null +++ b/cmd/pretty/testdata/compact_array.json @@ -0,0 +1,8 @@ +[ + { + "id": 1 + }, + { + "id": 2 + } +] diff --git a/cmd/pretty/testdata/compact_object.json b/cmd/pretty/testdata/compact_object.json new file mode 100644 index 0000000..60dffeb --- /dev/null +++ b/cmd/pretty/testdata/compact_object.json @@ -0,0 +1,4 @@ +{ + "name": "John", + "age": 30 +} diff --git a/cmd/pretty/testdata/empty_array.json b/cmd/pretty/testdata/empty_array.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/cmd/pretty/testdata/empty_array.json @@ -0,0 +1 @@ +[] diff --git a/cmd/pretty/testdata/empty_object.json b/cmd/pretty/testdata/empty_object.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/cmd/pretty/testdata/empty_object.json @@ -0,0 +1 @@ +{} diff --git a/cmd/pretty/testdata/nested_objects.json b/cmd/pretty/testdata/nested_objects.json new file mode 100644 index 0000000..b2a72ab --- /dev/null +++ b/cmd/pretty/testdata/nested_objects.json @@ -0,0 +1,7 @@ +{ + "a": { + "b": { + "c": 1 + } + } +} diff --git a/cmd/pretty/testdata/null_and_bool.json b/cmd/pretty/testdata/null_and_bool.json new file mode 100644 index 0000000..a28ba15 --- /dev/null +++ b/cmd/pretty/testdata/null_and_bool.json @@ -0,0 +1,5 @@ +{ + "value": null, + "enabled": true, + "disabled": false +} diff --git a/cmd/pretty/testdata/special_chars.json b/cmd/pretty/testdata/special_chars.json new file mode 100644 index 0000000..754a0c9 --- /dev/null +++ b/cmd/pretty/testdata/special_chars.json @@ -0,0 +1,6 @@ +{ + "html": "\u003cscript\u003ealert('xss')\u003c/script\u003e", + "newlines": "line1\nline2", + "tabs": "col1\tcol2", + "quotes": "she said \"hello\"" +} diff --git a/cmd/pretty/testdata/unicode.json b/cmd/pretty/testdata/unicode.json new file mode 100644 index 0000000..49a6d23 --- /dev/null +++ b/cmd/pretty/testdata/unicode.json @@ -0,0 +1,5 @@ +{ + "greeting": "こんにちは", + "emoji": "🎉", + "accented": "café" +} From 9150ded773d2011485f4d65ba217a8edfd5e3f84 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 14:56:22 +0100 Subject: [PATCH 03/19] Fix stale references and add missing commands in documentation Replace nonexistent login command with authorize, fix IMS_ suffix to prefix, remove ghost completion section, add missing commands (pkce, client, decode, refresh, admin, dcr), fix grammar and heading consistency. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- DOCUMENTATION.md | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index a5d8b6d..5f9ac45 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -12,31 +12,31 @@ The command will return 0 in case of success or 1 in case of an error. ## Subcommands ### Authorize -imscli login will negotiate an ***access token*** with IMS following the specified ***flow***. +imscli authorize will negotiate an ***access token*** with IMS following the specified ***flow***. #### imscli authorize user (standard Authorization Code Grant Flow) -This command will launch a browser and execute the normal OAuth2 flow done by users when log into IMS to use a service. +This command will launch a browser and execute the normal OAuth2 flow done by users when logging into IMS to use a service. -#### imscli authz service (an IMS specific flow similar to the Client Credentials Grant Flow). +#### imscli authorize service (an IMS specific flow similar to the Client Credentials Grant Flow). The imscli client will exchange client credentials and an additional service token to obtain the access token. It is used to access an "Application", an Adobe API exposed through Adobe I/O Gateway. -#### imscli authz jwt (JWT Bearer Flow). +#### imscli authorize jwt (JWT Bearer Flow). -This command will build a JWT will all specified claims, sign it with a private key and exchange it for an access token. +This command will build a JWT with all specified claims, sign it with a private key and exchange it for an access token. It is used for "Adobe I/O" integrations. -### Completion +#### imscli authorize pkce (Authorization Code Grant Flow with PKCE) -Generate a script to enable autocompletion for imscli. +Same as the user flow, but uses Proof Key for Code Exchange (PKCE). Supports public clients that cannot securely store a client secret. -To configure bash, add the following line to your .bashrc (or alternative config file): +#### imscli authorize client (Client Credentials Grant Flow) - eval "$(imscli autocompletion bash)" +Exchanges client credentials (client ID + secret) and scopes directly for an access token, without user interaction. ### Profile @@ -59,6 +59,24 @@ Validates a token using the IMS API. Invalidates a token using the IMS API. +### Decode + +Decodes a JWT token locally, printing the header and payload without contacting IMS. + +### Refresh + +Refreshes an access token using a refresh token. + +### Admin + +Administrative operations using a service token: + +- **admin profile**: Retrieve a user profile using a service token, client ID, guid and auth source. +- **admin organizations**: Retrieve organizations for a user using a service token. + +### DCR (Dynamic Client Registration) + +Register a new OAuth client using Dynamic Client Registration. ## Configuration @@ -77,9 +95,9 @@ imscli authz user --scopes AdobeID,openid,session #### Environment variables -Each parameter can be provided using the flag name and the IMS_ suffix. +Each parameter can be provided using the flag name and the IMS_ prefix. ``` -IMS_SCOPES="AdobeID,openid,session" imscli login user +IMS_SCOPES="AdobeID,openid,session" imscli authorize user ``` #### Configuration files @@ -98,6 +116,6 @@ scopes: - openid - session -user@host$ imscli login user +user@host$ imscli authorize user ``` From d04325f80c96311c4637285b0fefab6e8bab8f41 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 14:56:30 +0100 Subject: [PATCH 04/19] Improve README with badges, commands table, and quick start Add CI, Codecov, pkg.go.dev, and license badges. Replace verbose intro with tagline. Add quick start examples, full commands table, global flags table, and configuration summary. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- README.md | 83 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 5652c8a..253bacc 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,83 @@ # imscli ![CodeQL](https://github.com/adobe/imscli/workflows/CodeQL/badge.svg) +[![CI](https://github.com/adobe/imscli/actions/workflows/ci.yml/badge.svg)](https://github.com/adobe/imscli/actions/workflows/ci.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/adobe/imscli)](https://goreportcard.com/report/github.com/adobe/imscli) [![Release with GoReleaser](https://github.com/adobe/imscli/actions/workflows/main.yml/badge.svg)](https://github.com/adobe/imscli/actions/workflows/main.yml) +[![codecov](https://codecov.io/gh/adobe/imscli/branch/main/graph/badge.svg)](https://codecov.io/gh/adobe/imscli) +![Go Version](https://img.shields.io/github/go-mod/go-version/adobe/imscli) +[![Go Reference](https://pkg.go.dev/badge/github.com/adobe/imscli.svg)](https://pkg.go.dev/github.com/adobe/imscli) +[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE) -This project is a small CLI tool to interact with the IMS API. The goal of this project -is to provide a small tool that can be used to troubleshoot integrations with IMS. - -This project is wrapping adobe/ims-go. +A CLI tool to troubleshoot and automate Adobe IMS integrations. ## Installation -Build the CLI or download a prebuilt [release](https://github.com/adobe/imscli/releases). +### Prebuilt binaries + +Download the latest release for your platform from the [releases page](https://github.com/adobe/imscli/releases). -Example: +### From source ```sh go install github.com/adobe/imscli@latest ``` -## Usage - -Once installed, you can start reading the integrated help with the help subcommand. +## Quick Start -Examples: - -``` -imscli help +```sh +# Authorize as a user (launches browser for OAuth2 flow) +imscli authorize user --clientID --clientSecret --organization --scopes openid -imscli authorize help +# Validate a token +imscli validate accessToken --clientID --accessToken -imscli authorize user help +# Decode a JWT locally (no API call) +imscli decode --token ``` -The complete documentation of the project is available in the [DOCUMENTATION.md](DOCUMENTATION.md) file. - -## Development Notes - -### PersistentPreRunE and subcommands - -The root command defines a `PersistentPreRunE` that loads configuration from flags, environment variables, and config files (see `cmd/root.go`). In cobra, if a subcommand defines its own `PersistentPreRunE`, it **overrides** the parent's — the root's `PersistentPreRunE` will not run for that subcommand or its children. If you need to add a `PersistentPreRunE` to a subcommand, you must explicitly call the parent's first. +## Commands + +| Command | Description | +|---------|-------------| +| `authorize user` | OAuth2 Authorization Code Grant Flow (launches browser) | +| `authorize pkce` | Authorization Code Grant Flow with PKCE (public clients) | +| `authorize service` | Service authorization (client credentials + service token) | +| `authorize jwt` | JWT Bearer Flow (signed JWT exchanged for access token) | +| `authorize client` | Client Credentials Grant Flow | +| `validate` | Validate a token using the IMS API | +| `invalidate` | Invalidate a token using the IMS API | +| `decode` | Decode a JWT token locally | +| `refresh` | Refresh an access token | +| `exchange` | Cluster access token exchange across IMS Orgs | +| `profile` | Retrieve user profile | +| `organizations` | List user organizations | +| `admin` | Admin operations (profile, organizations) via service token | +| `dcr` | Dynamic Client Registration | + +See [DOCUMENTATION.md](DOCUMENTATION.md) for full details on each command. + +## Global Flags + +These flags apply to all commands: + +| Flag | Short | Default | Description | +|------|-------|---------|-------------| +| `--url` | `-U` | `https://ims-na1.adobelogin.com` | IMS endpoint URL | +| `--proxyUrl` | `-P` | | HTTP(S) proxy (`http(s)://host:port`) | +| `--proxyIgnoreTLS` | `-T` | `false` | Skip TLS verification (proxy only) | +| `--configFile` | `-f` | | Configuration file path | +| `--timeout` | | `30` | HTTP client timeout in seconds | +| `--verbose` | `-v` | `false` | Verbose output | + +## Configuration + +Parameters can be provided from three sources (highest to lowest priority): + +1. **CLI flags** — `imscli authorize user --scopes openid` +2. **Environment variables** — `IMS_SCOPES=openid imscli authorize user` +3. **Configuration file** — `~/.config/imscli.yaml` or specified with `-f` + +See [DOCUMENTATION.md](DOCUMENTATION.md) for configuration file format and examples. ## Contributing From b1cec9b5587701e56897dedcafd6d1bd71a5e561 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 14:56:38 +0100 Subject: [PATCH 05/19] Add development setup, CI pipeline docs, and repo settings to contributing guide Add Development section with build/test/vet commands. Document all CI pipelines (ci, pr-title, release, codeql) with triggers. Document repo settings (squash merge, auto-delete). Fix gorelease typo and --rm-dist flag. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- CONTRIBUTING.md | 66 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4ba3aff..fa69b69 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,14 +1,76 @@ # Contributing -## Release process + +This project wraps [adobe/ims-go](https://github.com/adobe/ims-go). + +## Development + +```bash +# Build +go build -o imscli . + +# Run all tests +go test ./... + +# Run a single test by name +go test ./ims/ -run TestValidateURL + +# Vet (static analysis) +go vet ./... +``` + +## CI Pipelines + +All pipelines are defined in `.github/workflows/`. + +### CI (`ci.yml`) + +**Triggers:** Every push to any branch and pull requests targeting `main`. + +Runs three parallel jobs: + +- **Test** — Runs `go test -race` with coverage and uploads the report to Codecov. +- **Lint** — Runs `go vet` and [golangci-lint](https://golangci-lint.run/) for extended static analysis. +- **Build** — Verifies the project compiles. Cross-platform builds are handled by GoReleaser at release time, so a single-platform check suffices here. + +### PR Title (`pr-title.yml`) + +**Triggers:** When a pull request is opened, edited, synchronized or reopened. + +Validates that the PR title follows the [Conventional Commits](https://www.conventionalcommits.org) format (e.g. `feat: add token refresh`, `fix(auth): handle expired tokens`). This is enforced because the repository is configured for **squash merging only** — the PR title becomes the commit message on `main`, and GoReleaser uses these prefixes to group the release changelog into Features, Bug Fixes, etc. + +### Release (`main.yml`) + +**Triggers:** Pushing a version tag (e.g. `v1.2.3`) or manual dispatch from the Actions tab. + +Runs [GoReleaser](https://goreleaser.com) to build cross-platform binaries (linux/darwin/windows × amd64/arm64), package them as archives and system packages (deb, rpm, apk), generate a changelog grouped by commit type, and publish a GitHub Release with all artifacts. + +### CodeQL (`codeql-analysis.yml`) + +**Triggers:** Every push, pull requests targeting `main`, and weekly on a cron schedule. + +Runs GitHub's CodeQL security analysis to detect vulnerabilities in the Go source code. + +## Repository Settings + +- **Squash merge only** — Merge commits and rebase merging are disabled. The PR title is used as the squash commit message, ensuring conventional commit messages land on `main`. +- **Auto-delete branches** — Head branches are automatically deleted after a PR is merged. + +## Release Process In order to standardize the release process, [goreleaser](https://goreleaser.com) has been adopted. To build and release a new version: ``` git tag vX.X.X && git push --tags -gorelease --rm-dist +goreleaser release --clean ``` The binary version is set automatically to the git tag. Please tag new versions using [semantic versioning](https://semver.org/spec/v2.0.0.html). + +## Development Notes + +### PersistentPreRunE and subcommands + +The root command defines a `PersistentPreRunE` that loads configuration from flags, environment variables, and config files (see `cmd/root.go`). In cobra, if a subcommand defines its own `PersistentPreRunE`, it **overrides** the parent's — the root's `PersistentPreRunE` will not run for that subcommand or its children. If you need to add a `PersistentPreRunE` to a subcommand, you must explicitly call the parent's first. From 576d4cc5202961f53d5fa594b0c12ac77c38cae4 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 14:56:46 +0100 Subject: [PATCH 06/19] Add CI and PR title validation workflows CI workflow runs test (with coverage upload to Codecov), lint (go vet + golangci-lint v2), and build jobs on every push and PR to main. PR title workflow enforces conventional commit format on PR titles to support squash-merge changelog generation. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- .github/workflows/ci.yml | 78 ++++++++++++++++++++++++++++++++++ .github/workflows/pr-title.yml | 41 ++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/pr-title.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..effe32a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,78 @@ +name: CI + +# Run on every push and on pull requests targeting main. +on: + push: + branches: ['**'] + pull_request: + branches: [main] + +# Read-only access is sufficient for running tests and linting. +permissions: + contents: read + +jobs: + # Run the full test suite with race detection and generate a coverage report. + test: + name: Test + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + # Go version is read from go.mod so it stays in sync with the project. + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version-file: go.mod + + - name: Run tests + run: go test -race -coverprofile=coverage.out -covermode=atomic ./... + + # Upload the coverage report to Codecov. Non-blocking so CI still + # passes if Codecov is temporarily unavailable. + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + with: + files: coverage.out + fail_ci_if_error: false + + # Static analysis: go vet for built-in checks, golangci-lint for extended linting. + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version-file: go.mod + + - name: Run go vet + run: go vet ./... + + # golangci-lint v2 runs 50+ linters in a single pass. + # Without a .golangci.yml config file it uses sensible defaults. + - name: Run golangci-lint + uses: golangci/golangci-lint-action@v7 + with: + version: v2.10.1 + + # Verify the project compiles. Cross-platform builds are handled by + # GoReleaser at release time, so a single-platform check suffices here. + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version-file: go.mod + + - name: Build + run: go build -o /dev/null . diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml new file mode 100644 index 0000000..06a7064 --- /dev/null +++ b/.github/workflows/pr-title.yml @@ -0,0 +1,41 @@ +# Ensure PR titles follow the Conventional Commits format so that +# squash-merged commits produce a clean changelog via GoReleaser. +# See: https://www.conventionalcommits.org +name: PR Title + +on: + pull_request_target: + types: [opened, edited, synchronize, reopened] + +permissions: + pull-requests: read + +jobs: + lint: + name: Validate PR title + runs-on: ubuntu-latest + steps: + # Validates that the PR title matches the conventional commit format. + # Examples of valid titles: + # feat: add token refresh command + # fix(auth): handle expired tokens + # docs: update CONTRIBUTING.md + - uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + # Types allowed in PR titles. These map to GoReleaser changelog groups. + types: | + feat + fix + docs + chore + ci + test + refactor + perf + style + build + revert + # Require a scope in parentheses (optional — set to true to enforce). + requireScope: false From 827460ea487dcbc7c625629c13dbc759ca793870 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 14:56:54 +0100 Subject: [PATCH 07/19] Clean up release workflow and add changelog grouping Remove boilerplate comments and add meaningful ones explaining each step. Switch from hardcoded go-version to go-version-file for automatic sync. Add conventional commit changelog grouping (Features, Bug Fixes, Other) and exclude ci/chore prefixes. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- .github/workflows/main.yml | 26 ++++++++++---------------- .goreleaser.yml | 12 ++++++++++++ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ddcfd96..7634b94 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,39 +1,34 @@ -# This is a basic workflow to help you get started with Actions - name: Release with GoReleaser -# Controls when the action will run. +# Triggered by pushing a version tag (e.g. v1.2.3) or manually via the Actions tab. on: - # Triggers the release workflow only for new tags push: tags: - '*' - - # Allows you to run this workflow manually from the Actions tab workflow_dispatch: -# A workflow run is made up of one or more jobs that can run sequentially or in parallel +# GoReleaser needs write access to create the GitHub release and upload artifacts. +permissions: + contents: write + jobs: - # This workflow contains a single job called "build" release: - # The type of runner that the job will run on runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + # Full history is required for GoReleaser to generate the changelog. - name: Checkout uses: actions/checkout@v6 with: fetch-depth: 0 - # Runs a single command using the runners shell + # Go version is read from go.mod so it stays in sync with the project. - name: Set up Go uses: actions/setup-go@v6 with: - go-version: 1.26 + go-version: 'stable' - # Runs a set of commands using the runners shell + # GoReleaser builds, packages and publishes the release. + # See .goreleaser.yml for build targets and packaging configuration. - name: Run GoReleaser uses: goreleaser/goreleaser-action@v7 with: @@ -41,4 +36,3 @@ jobs: args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - diff --git a/.goreleaser.yml b/.goreleaser.yml index 8bfdc52..41c7072 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -22,12 +22,24 @@ checksum: name_template: 'checksums.txt' snapshot: version_template: "{{ .Version }}-next" +# Group commits by conventional-commit prefix for cleaner release notes. changelog: sort: asc + groups: + - title: Features + regexp: '^.*?feat(\([^)]+\))?!?:.+$' + order: 0 + - title: Bug Fixes + regexp: '^.*?fix(\([^)]+\))?!?:.+$' + order: 1 + - title: Other + order: 999 filters: exclude: - '^docs:' - '^test:' + - '^ci:' + - '^chore:' nfpms: - file_name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' homepage: "https://github.com/adobe/imscli" From 3faa3b8781941c236569861538b5873fb8a6a926 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 14:57:02 +0100 Subject: [PATCH 08/19] Fix unchecked error returns flagged by linter Explicitly discard error returns from fmt.Fprintln in HTTP handlers (connection already dead if write fails), listener.Close and res.Body.Close in deferred calls (nothing actionable on failure). Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- ims/authz_user.go | 6 +++--- ims/register.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ims/authz_user.go b/ims/authz_user.go index 07685e2..452e946 100644 --- a/ims/authz_user.go +++ b/ims/authz_user.go @@ -85,13 +85,13 @@ func (i Config) authorizeUser(pkce bool) (string, error) { UsePKCE: pkce, RedirectURI: fmt.Sprintf("http://localhost:%d", i.Port), OnError: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintln(w, ` + _, _ = fmt.Fprintln(w, `

An error occurred

Please look at the terminal output for further details.

`) }), OnSuccess: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintln(w, ` + _, _ = fmt.Fprintln(w, `

Login successful!

You can close this tab.

`) @@ -105,7 +105,7 @@ func (i Config) authorizeUser(pkce bool) (string, error) { if err != nil { return "", fmt.Errorf("unable to listen at port %d", i.Port) } - defer listener.Close() + defer func() { _ = listener.Close() }() log.Println("Local server successfully launched and contacted.") diff --git a/ims/register.go b/ims/register.go index 7f70e8c..1590231 100644 --- a/ims/register.go +++ b/ims/register.go @@ -59,7 +59,7 @@ func (i Config) Register() (RegisterResponse, error) { if err != nil { return RegisterResponse{}, fmt.Errorf("error making registration request: %v", err) } - defer res.Body.Close() + defer func() { _ = res.Body.Close() }() body, err := io.ReadAll(res.Body) if err != nil { From 37d0923008d077baff1bc62c5cb1f7cc521eb566 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 15:39:25 +0100 Subject: [PATCH 09/19] Clarify PKCE usage for public and private clients PKCE is mandatory for public clients but optional (recommended) for private clients in IMS. The previous docs implied PKCE was only for public clients. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- DOCUMENTATION.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index 5f9ac45..58e7774 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -32,7 +32,7 @@ It is used for "Adobe I/O" integrations. #### imscli authorize pkce (Authorization Code Grant Flow with PKCE) -Same as the user flow, but uses Proof Key for Code Exchange (PKCE). Supports public clients that cannot securely store a client secret. +Like the user command, it uses the Authorization Code Grant Flow but with Proof Key for Code Exchange (PKCE). In IMS, PKCE is mandatory for public clients and recommended for private clients. #### imscli authorize client (Client Credentials Grant Flow) diff --git a/README.md b/README.md index 253bacc..11b39fd 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ imscli decode --token | Command | Description | |---------|-------------| | `authorize user` | OAuth2 Authorization Code Grant Flow (launches browser) | -| `authorize pkce` | Authorization Code Grant Flow with PKCE (public clients) | +| `authorize pkce` | Authorization Code Grant Flow with PKCE (mandatory for public clients, optional for private) | | `authorize service` | Service authorization (client credentials + service token) | | `authorize jwt` | JWT Bearer Flow (signed JWT exchanged for access token) | | `authorize client` | Client Credentials Grant Flow | From 785da2ca42397212d88d1e092eab89039fb0d5e4 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 15:45:11 +0100 Subject: [PATCH 10/19] Replace Codecov with coverage summary in CI log Codecov requires admin access to install the GitHub App. Replace with a go tool cover summary printed to the CI log. Remove the Codecov badge from README. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- .github/workflows/ci.yml | 10 +++------- README.md | 1 - 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index effe32a..cefbfb6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,13 +29,9 @@ jobs: - name: Run tests run: go test -race -coverprofile=coverage.out -covermode=atomic ./... - # Upload the coverage report to Codecov. Non-blocking so CI still - # passes if Codecov is temporarily unavailable. - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v5 - with: - files: coverage.out - fail_ci_if_error: false + # Print coverage summary to the CI log. + - name: Coverage summary + run: go tool cover -func=coverage.out | tail -1 # Static analysis: go vet for built-in checks, golangci-lint for extended linting. lint: diff --git a/README.md b/README.md index 11b39fd..d7562e4 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ [![CI](https://github.com/adobe/imscli/actions/workflows/ci.yml/badge.svg)](https://github.com/adobe/imscli/actions/workflows/ci.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/adobe/imscli)](https://goreportcard.com/report/github.com/adobe/imscli) [![Release with GoReleaser](https://github.com/adobe/imscli/actions/workflows/main.yml/badge.svg)](https://github.com/adobe/imscli/actions/workflows/main.yml) -[![codecov](https://codecov.io/gh/adobe/imscli/branch/main/graph/badge.svg)](https://codecov.io/gh/adobe/imscli) ![Go Version](https://img.shields.io/github/go-mod/go-version/adobe/imscli) [![Go Reference](https://pkg.go.dev/badge/github.com/adobe/imscli.svg)](https://pkg.go.dev/github.com/adobe/imscli) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE) From e77f0a8fc5371e4e2cb939ae83517fad6f2adb27 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 16:08:34 +0100 Subject: [PATCH 11/19] Add govulncheck workflow for dependency vulnerability scanning --- .github/workflows/govulncheck.yml | 29 +++++++++++++++++++++++++++++ CONTRIBUTING.md | 6 ++++++ README.md | 1 + 3 files changed, 36 insertions(+) create mode 100644 .github/workflows/govulncheck.yml diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml new file mode 100644 index 0000000..8c6e528 --- /dev/null +++ b/.github/workflows/govulncheck.yml @@ -0,0 +1,29 @@ +# Runs Go's official vulnerability scanner against project dependencies. +# Fails the job if any known vulnerabilities affect the code. +# See https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck + +name: govulncheck + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + govulncheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + # golang/govulncheck-action runs govulncheck against all packages (./...). + # With the default text output format, the job fails if vulnerabilities are found. + - uses: golang/govulncheck-action@v1 + with: + go-version-file: go.mod diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fa69b69..a263c97 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -50,6 +50,12 @@ Runs [GoReleaser](https://goreleaser.com) to build cross-platform binaries (linu Runs GitHub's CodeQL security analysis to detect vulnerabilities in the Go source code. +### govulncheck (`govulncheck.yml`) + +**Triggers:** Every push to `main` and pull requests. + +Runs Go's official vulnerability scanner ([govulncheck](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck)) against all packages. The job fails if any known vulnerabilities in the Go vulnerability database affect the code. Unlike general-purpose scanners, govulncheck traces call graphs — it only reports vulnerabilities in functions your code actually calls. + ## Repository Settings - **Squash merge only** — Merge commits and rebase merging are disabled. The PR title is used as the squash commit message, ensuring conventional commit messages land on `main`. diff --git a/README.md b/README.md index d7562e4..0693334 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # imscli ![CodeQL](https://github.com/adobe/imscli/workflows/CodeQL/badge.svg) +[![govulncheck](https://github.com/adobe/imscli/actions/workflows/govulncheck.yml/badge.svg)](https://github.com/adobe/imscli/actions/workflows/govulncheck.yml) [![CI](https://github.com/adobe/imscli/actions/workflows/ci.yml/badge.svg)](https://github.com/adobe/imscli/actions/workflows/ci.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/adobe/imscli)](https://goreportcard.com/report/github.com/adobe/imscli) [![Release with GoReleaser](https://github.com/adobe/imscli/actions/workflows/main.yml/badge.svg)](https://github.com/adobe/imscli/actions/workflows/main.yml) From 0f01bbabdff96831eb4eb89386aa26af11983509 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 16:09:41 +0100 Subject: [PATCH 12/19] Link docs/ write-ups from CONTRIBUTING.md --- CONTRIBUTING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a263c97..eb12e9a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -80,3 +80,10 @@ Please tag new versions using [semantic versioning](https://semver.org/spec/v2.0 ### PersistentPreRunE and subcommands The root command defines a `PersistentPreRunE` that loads configuration from flags, environment variables, and config files (see `cmd/root.go`). In cobra, if a subcommand defines its own `PersistentPreRunE`, it **overrides** the parent's — the root's `PersistentPreRunE` will not run for that subcommand or its children. If you need to add a `PersistentPreRunE` to a subcommand, you must explicitly call the parent's first. + +## Additional Reading + +The `docs/` directory contains write-ups on non-obvious problems encountered during development: + +- [OAuth Local Server: Unhandled Serve() Error](docs/oauth-serve-error.md) — Why the `Serve` goroutine error is captured via a buffered channel, and why the channel must be buffered. +- [OAuth Local Server Shutdown Deadlock](docs/oauth-shutdown-deadlock.md) — How an unbuffered channel creates a deadlock between the HTTP handler and `Shutdown()`, and the two-part fix. From b75534b05f428213648d12c1e13a9d9b6a7c41cd Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 16:12:33 +0100 Subject: [PATCH 13/19] Enable Renovate auto-merge for patch dependency updates --- CONTRIBUTING.md | 1 + renovate.json | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eb12e9a..ba07257 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,6 +60,7 @@ Runs Go's official vulnerability scanner ([govulncheck](https://pkg.go.dev/golan - **Squash merge only** — Merge commits and rebase merging are disabled. The PR title is used as the squash commit message, ensuring conventional commit messages land on `main`. - **Auto-delete branches** — Head branches are automatically deleted after a PR is merged. +- **Renovate auto-merge** — [Renovate](https://docs.renovatebot.com/) monitors `go.mod` for dependency updates and opens PRs automatically. Patch updates (e.g., `v1.8.0` → `v1.8.1`) are auto-merged after CI passes. Minor and major updates require manual review. Configuration lives in `renovate.json`. ## Release Process diff --git a/renovate.json b/renovate.json index c3bdc63..35384c9 100644 --- a/renovate.json +++ b/renovate.json @@ -6,5 +6,12 @@ "postUpdateOptions": [ "gomodTidy", "gomodUpdateImportPaths" + ], + "packageRules": [ + { + "description": "Auto-merge patch updates after CI passes", + "matchUpdateTypes": ["patch"], + "automerge": true + } ] } From ead6e1c78c979a18b883cdb32f04e4ce4e71f939 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 16:35:28 +0100 Subject: [PATCH 14/19] Add weekly govulncheck schedule with auto-issue on failure --- .github/workflows/govulncheck.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index 8c6e528..51df0dc 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -8,9 +8,13 @@ on: push: branches: [main] pull_request: + # Weekly scan catches new vulnerabilities even when the code hasn't changed. + schedule: + - cron: '0 9 * * 1' # Every Monday at 9:00 UTC permissions: contents: read + issues: write jobs: govulncheck: @@ -27,3 +31,25 @@ jobs: - uses: golang/govulncheck-action@v1 with: go-version-file: go.mod + + # Open a GitHub issue when the scheduled scan finds vulnerabilities. + # Only runs on cron failures — PR and push failures are visible in the checks UI. + notify: + needs: govulncheck + runs-on: ubuntu-latest + if: failure() && github.event_name == 'schedule' + steps: + - uses: actions/github-script@v7 + with: + script: | + await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: 'govulncheck: vulnerability detected', + body: [ + 'The weekly [govulncheck scan](' + context.serverUrl + '/' + context.repo.owner + '/' + context.repo.repo + '/actions/runs/' + context.runId + ') found vulnerabilities.', + '', + 'Review the workflow run and update affected dependencies.' + ].join('\n'), + labels: ['security'] + }); From 53b7e572ab047ce16ea98a6a5cdf8c7e7592166f Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 16:37:28 +0100 Subject: [PATCH 15/19] Add go mod verify and goreleaser check to CI --- .github/workflows/ci.yml | 10 ++++++++++ CONTRIBUTING.md | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cefbfb6..54897f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,10 @@ jobs: with: go-version-file: go.mod + # Verify dependency checksums match go.sum (detects corrupted or tampered modules). + - name: Verify dependencies + run: go mod verify + - name: Run tests run: go test -race -coverprofile=coverage.out -covermode=atomic ./... @@ -72,3 +76,9 @@ jobs: - name: Build run: go build -o /dev/null . + + # Validate .goreleaser.yml so config errors are caught before tagging a release. + - name: Verify GoReleaser config + uses: goreleaser/goreleaser-action@v6 + with: + args: check diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ba07257..3aedfd8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,9 +28,9 @@ All pipelines are defined in `.github/workflows/`. Runs three parallel jobs: -- **Test** — Runs `go test -race` with coverage and uploads the report to Codecov. +- **Test** — Runs `go test -race` with coverage and prints a coverage summary to the log. Verifies dependency checksums with `go mod verify`. - **Lint** — Runs `go vet` and [golangci-lint](https://golangci-lint.run/) for extended static analysis. -- **Build** — Verifies the project compiles. Cross-platform builds are handled by GoReleaser at release time, so a single-platform check suffices here. +- **Build** — Verifies the project compiles and validates `.goreleaser.yml` with `goreleaser check`. Cross-platform builds are handled by GoReleaser at release time, so a single-platform check suffices here. ### PR Title (`pr-title.yml`) @@ -52,9 +52,9 @@ Runs GitHub's CodeQL security analysis to detect vulnerabilities in the Go sourc ### govulncheck (`govulncheck.yml`) -**Triggers:** Every push to `main` and pull requests. +**Triggers:** Every push to `main`, pull requests, and weekly on Monday at 9:00 UTC. -Runs Go's official vulnerability scanner ([govulncheck](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck)) against all packages. The job fails if any known vulnerabilities in the Go vulnerability database affect the code. Unlike general-purpose scanners, govulncheck traces call graphs — it only reports vulnerabilities in functions your code actually calls. +Runs Go's official vulnerability scanner ([govulncheck](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck)) against all packages. The job fails if any known vulnerabilities in the Go vulnerability database affect the code. Unlike general-purpose scanners, govulncheck traces call graphs — it only reports vulnerabilities in functions your code actually calls. The weekly schedule catches new vulnerabilities even when the code hasn't changed. If the scheduled scan fails, a GitHub issue labeled `security` is created automatically. ## Repository Settings From 916f7111768813fc8b49ad46a809deec117567e8 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 16:46:46 +0100 Subject: [PATCH 16/19] Use go-version stable across all workflows --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/govulncheck.yml | 8 ++++---- .github/workflows/main.yml | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54897f5..85680a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,11 +20,11 @@ jobs: - name: Checkout uses: actions/checkout@v6 - # Go version is read from go.mod so it stays in sync with the project. + # Always use the latest stable Go release for the newest compiler and stdlib fixes. - name: Set up Go uses: actions/setup-go@v6 with: - go-version-file: go.mod + go-version: 'stable' # Verify dependency checksums match go.sum (detects corrupted or tampered modules). - name: Verify dependencies @@ -48,7 +48,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version-file: go.mod + go-version: 'stable' - name: Run go vet run: go vet ./... @@ -72,7 +72,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version-file: go.mod + go-version: 'stable' - name: Build run: go build -o /dev/null . diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index 51df0dc..e1ca98e 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -20,17 +20,17 @@ jobs: govulncheck: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - - uses: actions/setup-go@v5 + - uses: actions/setup-go@v6 with: - go-version-file: go.mod + go-version: 'stable' # golang/govulncheck-action runs govulncheck against all packages (./...). # With the default text output format, the job fails if vulnerabilities are found. - uses: golang/govulncheck-action@v1 with: - go-version-file: go.mod + go-version-input: 'stable' # Open a GitHub issue when the scheduled scan finds vulnerabilities. # Only runs on cron failures — PR and push failures are visible in the checks UI. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7634b94..11290e8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,7 +21,7 @@ jobs: with: fetch-depth: 0 - # Go version is read from go.mod so it stays in sync with the project. + # Always use the latest stable Go release for the newest compiler and stdlib fixes. - name: Set up Go uses: actions/setup-go@v6 with: From 26032793407c568c4d529ce0b08cda7082940404 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 16:49:29 +0100 Subject: [PATCH 17/19] Revert to go-version-file go.mod for controllable Go version pinning --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/govulncheck.yml | 4 ++-- .github/workflows/main.yml | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 85680a6..54897f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,11 +20,11 @@ jobs: - name: Checkout uses: actions/checkout@v6 - # Always use the latest stable Go release for the newest compiler and stdlib fixes. + # Go version is read from go.mod so it stays in sync with the project. - name: Set up Go uses: actions/setup-go@v6 with: - go-version: 'stable' + go-version-file: go.mod # Verify dependency checksums match go.sum (detects corrupted or tampered modules). - name: Verify dependencies @@ -48,7 +48,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: 'stable' + go-version-file: go.mod - name: Run go vet run: go vet ./... @@ -72,7 +72,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: 'stable' + go-version-file: go.mod - name: Build run: go build -o /dev/null . diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index e1ca98e..1af609d 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -24,13 +24,13 @@ jobs: - uses: actions/setup-go@v6 with: - go-version: 'stable' + go-version-file: go.mod # golang/govulncheck-action runs govulncheck against all packages (./...). # With the default text output format, the job fails if vulnerabilities are found. - uses: golang/govulncheck-action@v1 with: - go-version-input: 'stable' + go-version-file: go.mod # Open a GitHub issue when the scheduled scan finds vulnerabilities. # Only runs on cron failures — PR and push failures are visible in the checks UI. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 11290e8..d57156e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,11 +21,11 @@ jobs: with: fetch-depth: 0 - # Always use the latest stable Go release for the newest compiler and stdlib fixes. + # Go version is read from go.mod so it stays in sync with the project. - name: Set up Go uses: actions/setup-go@v6 with: - go-version: 'stable' + go-version-file: go.mod # GoReleaser builds, packages and publishes the release. # See .goreleaser.yml for build targets and packaging configuration. From a9bc578d70b77d16975bc345d102a23ab2d2adeb Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 16:50:25 +0100 Subject: [PATCH 18/19] Document Go version pinning strategy in CONTRIBUTING.md --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3aedfd8..1d8f1f4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -61,6 +61,7 @@ Runs Go's official vulnerability scanner ([govulncheck](https://pkg.go.dev/golan - **Squash merge only** — Merge commits and rebase merging are disabled. The PR title is used as the squash commit message, ensuring conventional commit messages land on `main`. - **Auto-delete branches** — Head branches are automatically deleted after a PR is merged. - **Renovate auto-merge** — [Renovate](https://docs.renovatebot.com/) monitors `go.mod` for dependency updates and opens PRs automatically. Patch updates (e.g., `v1.8.0` → `v1.8.1`) are auto-merged after CI passes. Minor and major updates require manual review. Configuration lives in `renovate.json`. +- **Go version pinning** — All CI workflows use `go-version-file: go.mod` so the Go compiler version is controlled by the `toolchain` directive in `go.mod`. To upgrade Go, update `go.mod` (Renovate opens PRs for this automatically). To downgrade after a bad release, revert the `toolchain` line in `go.mod` — all workflows pick up the change immediately. ## Release Process From 1ecaa4d791a7157cce305fb0188b6c70bb484c62 Mon Sep 17 00:00:00 2001 From: Jose Antonio Insua Date: Sat, 28 Feb 2026 17:56:48 +0100 Subject: [PATCH 19/19] Fix govulncheck duplicate auth header by disabling persist-credentials --- .github/workflows/govulncheck.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index 1af609d..50dbdbd 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -21,6 +21,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - uses: actions/setup-go@v6 with: