diff --git a/.cspell.json b/.cspell.json index 51ed83f..7a325a4 100644 --- a/.cspell.json +++ b/.cspell.json @@ -1,11 +1,6 @@ { "language": "en", - "dictionaries": [ - "companies", - "filetypes", - "fullstack", - "softwareTerms" - ], + "dictionaries": ["companies", "filetypes", "fullstack", "softwareTerms"], "words": [ "aquasecurity", "artipacked", @@ -20,49 +15,39 @@ "credstore", "ehthumbs", "esac", + "flagwords", "fprintln", + "gjson", "goarch", "gobin", "gofmt", "golangci", "goos", "gopath", - "kics", + "gotoolchain", + "jdoe", + "kwallet", "ldflags", + "lfid", "lfx", "lfxv", "linuxfoundation", + "localappdata", "memprof", "mgechev", "mktemp", "mtimes", "nolint", + "passwordstore", "pipefail", "rundll", "techdocs", + "tidwall", "trimpath", "urfave", "zizmor" ], - "flagWords": [ - "abort: cancel, end, fail, halt, stop, terminate", - "abortion: cancelation, ending, failure, halting, stopping, termination", - "blackhat: attacker, malicious", - "black-hat: attacker, malicious", - "whitehat: ethical, security, researcher", - "white-hat: ethical, security, researcher", - "cripple: disable, degrade, impact", - "crippled: disabled, degraded, impacted", - "grandfathered: legacy, exempted, preauthorized", - "master: controller, primary, main, leader, parent", - "slave: agent, replica, secondary, follower, child", - "tribe: squad, team, group", - "sanity-check: test, verify, validate", - "whitelist: allowlist", - "white-list: allow-list", - "blacklist: denylist", - "black-list: deny-list" - ], + "flagWords": [], "ignorePaths": [ ".cspell.json", "CODEOWNERS", @@ -74,9 +59,7 @@ "languageSettings": [ { "languageId": "markdown", - "ignoreRegExpList": [ - "/^\\s*```\\s*(mermaid)[\\s\\S]*?^\\s*```/gm" - ] + "ignoreRegExpList": ["/^\\s*```\\s*(mermaid)[\\s\\S]*?^\\s*```/gm"] } ] } diff --git a/.github/workflows/mega-linter.yml b/.github/workflows/mega-linter.yml index b5d036d..d866283 100644 --- a/.github/workflows/mega-linter.yml +++ b/.github/workflows/mega-linter.yml @@ -35,7 +35,7 @@ jobs: id: ml # Use the Go flavor. Keep this version in sync with the # `megalinter` target in the Makefile. - uses: oxsecurity/megalinter/flavors/go@ef3e84b8b836d76db562d0f3ed7da61e8fd538bc # v9.6.0 + uses: oxsecurity/megalinter/flavors/go@9949bad031045f366be2467e00e8371a7328a2e2 # v10.1.0 env: # Only Actions-specific values (secrets, runner behavior) belong # here. Generic MegaLinter/repo config belongs in .mega-linter.yml @@ -44,6 +44,9 @@ jobs: # All available variables are described in documentation # https://megalinter.io/latest/configuration/ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Lets Go-based linters download the go.mod toolchain when it is + # newer than the Go bundled in the MegaLinter image. + GOTOOLCHAIN: auto # Allow GITHUB_TOKEN for working around rate limits (aquasecurity/trivy#7668). REPOSITORY_TRIVY_UNSECURED_ENV_VARIABLES: GITHUB_TOKEN # zizmor's "artipacked" audit needs the GitHub API (to verify diff --git a/.mega-linter.yml b/.mega-linter.yml index b93d824..5c326c4 100644 --- a/.mega-linter.yml +++ b/.mega-linter.yml @@ -2,22 +2,32 @@ # SPDX-License-Identifier: MIT --- GITHUB_COMMENT_REPORTER: false +# Excludes locally generated CLI binaries from repository scans. +ADDITIONAL_EXCLUDED_DIRECTORIES: + - bin DISABLE_LINTERS: - # Prefer Revive. - - GO_GOLANGCI_LINT # yamllint is sufficient for us. - YAML_PRETTIER DISABLE_ERRORS_LINTERS: - # Currently disabled upstream by MegaLinter itself (supply chain - # compromise). Keep it non-blocking here so a future upstream restore - # doesn't unexpectedly break the build before we've reviewed it. - - REPOSITORY_KICS # There's no easy local feedback loop for spelling issues before # pushing, so keep them non-blocking to avoid unnecessary PR cycles # for words that just need adding to the dictionary. - SPELL_CSPELL YAML_YAMLLINT_CONFIG_FILE: .yamllint SPELL_CSPELL_ANALYZE_FILE_NAMES: false +SPELL_CSPELL_PRE_COMMANDS: + - command: >- + cp .cspell.json /tmp/cspell.json.orig && + curl -sSf --connect-timeout 5 --max-time 15 https://raw.githubusercontent.com/linuxfoundation/lfx-public-workflows/737873e045a02df2f66b09d8061b98997cdf1880/cspell/flagwords.json.snippet -o /tmp/flagwords.json.snippet && + test "$(grep -c '^[[:space:]]*"flagWords"[[:space:]]*:[[:space:]]*\[\],[[:space:]]*$' .cspell.json)" -eq 1 && + sed -i -e '/^[[:space:]]*"flagWords"[[:space:]]*:[[:space:]]*\[\],[[:space:]]*$/{r /tmp/flagwords.json.snippet' -e 'd}' .cspell.json + cwd: workspace + continue_if_failed: false +SPELL_CSPELL_POST_COMMANDS: + - command: cp /tmp/cspell.json.orig .cspell.json + cwd: workspace +# Allows Grype to complete repository scans over Docker bind mounts. +REPOSITORY_GRYPE_TIMEOUT_SECONDS: 600 # Ignore YAML files with templating macros; these typically fail linting and/or # schema checking. FILTER_REGEX_EXCLUDE: '(templates/.*\.yml|templates/.*\.yaml)' diff --git a/AGENTS.md b/AGENTS.md index 1d20caf..f07d030 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -236,44 +236,8 @@ release binaries may be missing even though the GitHub Release exists. keep dependencies current. This upgrades module dependencies only, not the Go toolchain itself (`go.mod`'s `go` directive) -- see the toolchain policy below before touching that. -4. **Go toolchain version**: Freely bump `go.mod`'s `go` directive to the - latest available *patch* release (e.g. `1.X.Y` → `1.X.{Y+1}`) to pick up - security fixes. Do **not** bump the *minor* version (e.g. `1.X.x` → - `1.{X+1}.x`) unless the user explicitly asks for it, **and** you've - validated it against the Go version MegaLinter itself bundles -- - MegaLinter runs several linters (e.g. `golangci-lint`) against its own - bundled Go version, and a `go.mod` directive newer than that bundled - version breaks those checks. - - To find MegaLinter's bundled Go version: - - ```bash - # 1. Find the MegaLinter flavor and pinned version tag used in CI. - grep -A1 'oxsecurity/megalinter' .github/workflows/*.yml - # e.g. "uses: oxsecurity/megalinter/flavors/@ # " - - # 2. Fetch that flavor's Dockerfile and read its GO_ALPINE_VERSION (or - # GO_IMAGE_VERSION) build arg. - curl -s "https://raw.githubusercontent.com/oxsecurity/megalinter//flavors//Dockerfile" \ - | grep -i 'GO_ALPINE_VERSION\|GO_IMAGE_VERSION' - ``` - - `go.mod`'s `go` directive must never exceed that bundled version. Staying - one minor version behind it (rather than matching its minor *and* patch - exactly) leaves room to always take the latest patch release for security - fixes without ever being blocked by MegaLinter's own bundled patch version - lagging behind a newly disclosed vulnerability. - - There's no built-in `go` subcommand to look up the latest patch release - for a given minor version -- query the official `go.dev/dl` JSON feed - instead: - - ```bash - # Find the latest patch release for the minor version pinned in go.mod. - MINOR=$(grep '^go ' go.mod | awk '{print $2}' | cut -d. -f1,2) - curl -s "https://go.dev/dl/?mode=json&include=all" \ - | jq -r --arg m "go${MINOR}." '.[].version | select(startswith($m))' \ - | sort -V | tail -1 - ``` +4. **Go toolchain version**: Follow the `lfx-megalinter` skill's Go version + policy. It sets `go.mod` to the latest patch of the previous stable Go + minor and caps it at the minor bundled by the pinned MegaLinter release. 5. **Code Quality**: Run `make check` before commits 6. **Documentation**: Update README.md for user-facing changes diff --git a/Makefile b/Makefile index 2ad8f2c..8651b9b 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,10 @@ BINARY_NAME=lfx CMD_DIR=./cmd/lfx BUILD_DIR=./bin +# Run MegaLinter locally via Docker (matches CI Go flavor at v10.1.0). +# Keep this digest in sync with .github/workflows/mega-linter.yml. +MEGALINTER_IMAGE := ghcr.io/oxsecurity/megalinter-go@sha256:42e091a4bcbe9141fe420c2520ed7addf75ae60a0c9d42e3df1278eef1c90a88 # v10.1.0 + # Build flags. Version is not injected via -ldflags: `go build` already # embeds a pseudo-version (encoding the VCS revision, commit time, and # dirty state) into the binary's module version, which main.go reads via @@ -104,11 +108,9 @@ install-tools: *) echo "Warning: $$gobin is not in your PATH; installed tools (golangci-lint, revive) won't be found. Add it to your PATH, e.g.: export PATH=\"$$PATH:$$gobin\"" ;; \ esac -# Run MegaLinter locally via Docker (matches CI Go flavor at v9.6.0). -# Keep this version in sync with .github/workflows/mega-linter.yml. megalinter: - docker pull ghcr.io/oxsecurity/megalinter-go:v9.6.0 - docker run --rm --platform linux/amd64 -v '$(CURDIR):/tmp/lint:rw' ghcr.io/oxsecurity/megalinter-go:v9.6.0 + docker pull $(MEGALINTER_IMAGE) + docker run --rm --platform linux/amd64 -e GOTOOLCHAIN=auto -v '$(CURDIR):/tmp/lint:rw' $(MEGALINTER_IMAGE) # Show help help: diff --git a/go.mod b/go.mod index b62eed4..73fad2b 100644 --- a/go.mod +++ b/go.mod @@ -2,14 +2,14 @@ // SPDX-License-Identifier: MIT module github.com/linuxfoundation/lfx-cli -go 1.25.14 +go 1.26.9 require ( github.com/99designs/keyring v1.2.2 - github.com/tidwall/gjson v1.19.0 + github.com/tidwall/gjson v1.20.0 github.com/urfave/cli-docs/v3 v3.1.0 - github.com/urfave/cli/v3 v3.13.0 - golang.org/x/oauth2 v0.36.0 + github.com/urfave/cli/v3 v3.14.0 + golang.org/x/oauth2 v0.37.0 ) require ( @@ -22,7 +22,7 @@ require ( github.com/mtibben/percent v0.2.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/tidwall/match v1.2.0 // indirect - github.com/tidwall/pretty v1.2.1 // indirect - golang.org/x/sys v0.47.0 // indirect - golang.org/x/term v0.45.0 // indirect + github.com/tidwall/pretty v1.2.2 // indirect + golang.org/x/sys v0.49.0 // indirect + golang.org/x/term v0.47.0 // indirect ) diff --git a/go.sum b/go.sum index 9cc8e0b..f04fee6 100644 --- a/go.sum +++ b/go.sum @@ -25,23 +25,23 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= -github.com/tidwall/gjson v1.19.0 h1:xwxm7n691Uf3u5OFjzngavjGTh55KX5q/9w9xHW88JU= -github.com/tidwall/gjson v1.19.0/go.mod h1:V37/opeE/JbLUOfH0QTXiNez2l0RUjYUhpT4szFQAfc= +github.com/tidwall/gjson v1.20.0 h1:+agJ3rEzKcCXKDKo0ml26UROcpcAlnZyjq+TjbY5Fto= +github.com/tidwall/gjson v1.20.0/go.mod h1:V37/opeE/JbLUOfH0QTXiNez2l0RUjYUhpT4szFQAfc= github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM= github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= -github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.2 h1:dz1jrRuE7or/74V490B4/GP1pZm5WKlt2bgCP5A83w8= +github.com/tidwall/pretty v1.2.2/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/urfave/cli-docs/v3 v3.1.0 h1:Sa5xm19IpE5gpm6tZzXdfjdFxn67PnEsE4dpXF7vsKw= github.com/urfave/cli-docs/v3 v3.1.0/go.mod h1:59d+5Hz1h6GSGJ10cvcEkbIe3j233t4XDqI72UIx7to= -github.com/urfave/cli/v3 v3.13.0 h1:Dr6jqMfIyyFsRVn7Nz5mqLsMY+ZMpfh3a0aMs+umPVY= -github.com/urfave/cli/v3 v3.13.0/go.mod h1:vXn6HxPNccJSzQr2QvwVncOKrgYGIHU0HY5h8B2nQj4= +github.com/urfave/cli/v3 v3.14.0 h1:a8414NQlHJs0c/iBsulKLzlES0n/lEAskbL2LKpU4/s= +github.com/urfave/cli/v3 v3.14.0/go.mod h1:vXn6HxPNccJSzQr2QvwVncOKrgYGIHU0HY5h8B2nQj4= go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= -golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= -golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= -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= +golang.org/x/oauth2 v0.37.0 h1:JUlcxA8oAtauLfiH8FX2/FkAWHAdi0QtGCGc+hofE98= +golang.org/x/oauth2 v0.37.0/go.mod h1:IxwZNxUULJmpBFf9K/9NTMSIfZZuvuTy1gGxhigP/58= +golang.org/x/sys v0.49.0 h1:XbzkgYJHdqh/8m2Uu0W/dQv8nktxx4BFHp1M0gROTXA= +golang.org/x/sys v0.49.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= +golang.org/x/term v0.47.0 h1:cpyOwQkr2Nzxe2p6KnrTG7Ei2wtzjsuSjhpXXepZ/BM= +golang.org/x/term v0.47.0/go.mod h1:efAfAuG6RKABvg1ArGebRkvX6LXul14SM67o2e4mUCY= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=