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
10 changes: 3 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,12 @@ jobs:
# run `make docs-commands` locally and commit the result.
go run ./cmd/gendocs -check

# Prebuilt golangci-lint binaries may be compiled with an older Go than
# go.mod; loading .golangci.yml then fails ("Go language version used to
# build golangci-lint is lower than the targeted Go version"). Building
# from source with setup-go matches the project's toolchain.
- name: golangci-lint
if: runner.os == 'Linux'
uses: golangci/golangci-lint-action@v6
uses: golangci/golangci-lint-action@v9
with:
version: v1.64.8
install-mode: goinstall
version: v2.12.2
install-mode: binary
args: --timeout=5m

- name: Build CLI
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ jobs:
fi

- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v3
uses: actions/upload-pages-artifact@v5
with:
path: ./_site

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ jobs:
uses: sigstore/cosign-installer@v4.1.2

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
uses: goreleaser/goreleaser-action@v7
with:
distribution: goreleaser
version: "~> v2"
Expand Down
159 changes: 88 additions & 71 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
version: "2"

# golangci-lint configuration for agora-cli-go.
#
# This is a deliberately conservative ruleset suitable for a public CLI:
Expand All @@ -14,21 +16,18 @@
# CI runs `golangci-lint run --timeout=5m` from .github/workflows/ci.yml.

run:
timeout: 5m
tests: true
build-tags: []
modules-download-mode: readonly

linters:
disable-all: true
default: none
enable:
# correctness — must always pass
- errcheck
- govet
- staticcheck
- ineffassign
- unused
- typecheck

# security — must always pass (with tuned exclusions below)
- gosec
Expand All @@ -39,81 +38,99 @@ linters:
- misspell
- unconvert

linters-settings:
errcheck:
# We allow ignoring errors from these methods because they are best-effort
# cleanup paths; the right thing to do is fall through.
exclude-functions:
- (io.Closer).Close
- (*os.File).Close
- fmt.Fprint
- fmt.Fprintf
- fmt.Fprintln
- (net/http.Client).Do
- (*net/http.Response).Body.Close
settings:
errcheck:
# We allow ignoring errors from these methods because they are best-effort
# cleanup paths; the right thing to do is fall through.
exclude-functions:
- (io.Closer).Close
- (*os.File).Close
- fmt.Fprint
- fmt.Fprintf
- fmt.Fprintln
- (net/http.Client).Do
- (*net/http.Response).Body.Close

gosec:
excludes:
# G104: many `_ = ...` patterns are intentional best-effort cleanup
# (already covered by errcheck which is the more granular linter).
- G104
# G304: file paths are validated by callers; the CLI necessarily reads
# files at user-supplied paths (e.g. .env, config.json).
- G304
# G306: 0o644 vs 0o600 — we already use 0o600 for secret-bearing files
# via writeSecureJSON; the rest are user-readable artefacts by design.
- G306
# G401/G501: SHA-1 / MD5 — not used by us; in case a transitive caller
# surfaces in tests, suppress to avoid noise.
- G401
- G501
gosec:
excludes:
# G104: many `_ = ...` patterns are intentional best-effort cleanup
# (already covered by errcheck which is the more granular linter).
- G104
# G304: file paths are validated by callers; the CLI necessarily reads
# files at user-supplied paths (e.g. .env, config.json).
- G304
# G306: 0o644 vs 0o600 — we already use 0o600 for secret-bearing files
# via writeSecureJSON; the rest are user-readable artefacts by design.
- G306
# G401/G501: SHA-1 / MD5 — not used by us; in case a transitive caller
# surfaces in tests, suppress to avoid noise.
- G401
- G501
# G703 is a newer path-taint rule; these paths are validated by the
# command-specific input and output-path checks already in place.
- G703

govet:
enable-all: true
disable:
# fieldalignment is purely a micro-optimization; not worth churn.
- fieldalignment
# shadow is not in govet's default set and flags every `if err := ...`
# block. Idiomatic Go uses scoped err shadowing inside short blocks; we
# rely on errcheck + staticcheck to catch real assignment bugs instead.
- shadow
govet:
enable-all: true
disable:
# fieldalignment is purely a micro-optimization; not worth churn.
- fieldalignment
# shadow is not in govet's default set and flags every `if err := ...`
# block. Idiomatic Go uses scoped err shadowing inside short blocks; we
# rely on errcheck + staticcheck to catch real assignment bugs instead.
- shadow

staticcheck:
checks:
- all
# SA1019 covers deprecated APIs; we lean on this elsewhere via go vet
# and want to keep it active. No exclusions.
staticcheck:
checks:
- all
# Keep the existing v1 lint baseline. These style checks were newly
# surfaced by the v2 analyzer and are unrelated to this change.
- -ST1005
- -QF1001
- -S1021
# SA1019 covers deprecated APIs; we lean on this elsewhere via go vet
# and want to keep it active. No exclusions.

misspell:
locale: US
misspell:
locale: US

errorlint:
# %w wrapping is preferred but legacy %v errors are still acceptable
# while we incrementally migrate; keep this off-by-default check off.
errorf: false
asserts: true
comparison: true
errorlint:
# %w wrapping is preferred but legacy %v errors are still acceptable
# while we incrementally migrate; keep this off-by-default check off.
errorf: false
asserts: true
comparison: true

issues:
exclude-dirs:
- packaging
exclude-rules:
# Test files commonly use t.TempDir() / os.Setenv / panic patterns
# that gosec flags; keep the production code strict but loosen tests.
- path: _test\.go
linters:
- gosec
- errcheck
- bodyclose
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- packaging
- third_party$
- builtin$
- examples$
rules:
# Test files commonly use t.TempDir() / os.Setenv / panic patterns
# that gosec flags; keep the production code strict but loosen tests.
- path: _test\.go
linters:
- gosec
- errcheck
- bodyclose

# The OAuth callback handler intentionally writes a fixed HTML response
# without checking the io.Writer error (the connection may already be
# closed by the time we write).
- path: internal/cli/auth\.go
text: "Error return value of `\\(net/http\\.ResponseWriter\\)\\.Write` is not checked"
linters:
- errcheck
# The OAuth callback handler intentionally writes a fixed HTML response
# without checking the io.Writer error (the connection may already be
# closed by the time we write).
- path: internal/cli/auth\.go
text: "Error return value of `\\(net/http\\.ResponseWriter\\)\\.Write` is not checked"
linters:
- errcheck

issues:
# Show every issue (don't truncate). Useful for an aggregate fix pass.
max-issues-per-linter: 0
max-same-issues: 0
8 changes: 4 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,17 +172,17 @@ make lint # gofmt + golangci-lint + error-code audit
golangci-lint run # standalone (config: .golangci.yml)
```

CI uses `golangci-lint v1.64.8`, installed via `go install` so the linter is built with the same Go version as `go.mod`. Install locally to match:
CI uses `golangci-lint v2.12.2` through the v9 action. Install locally to match:

```bash
go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.8
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2
```

Alternatively, download the release binary (must be built with a Go version ≥ `go.mod`; if config load fails, prefer `go install` above):

```bash
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh \
| sh -s -- -b "$(go env GOPATH)/bin" v1.64.8
curl -sSfL https://golangci-lint.run/install.sh \
| sh -s -- -b "$(go env GOPATH)/bin" v2.12.2
```

The ruleset is intentionally conservative (errcheck, govet, staticcheck, ineffassign, unused, gosec, bodyclose, errorlint, misspell, unconvert). When a finding is a false positive, prefer narrowing the rule via `.golangci.yml` `exclude-rules` over adding inline `//nolint` directives.
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
module github.com/AgoraIO/cli

go 1.26.4
go 1.26.5

require (
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
golang.org/x/term v0.43.0
golang.org/x/term v0.45.0
)

require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
golang.org/x/sys v0.44.0 // indirect
golang.org/x/sys v0.47.0 // indirect
)
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=