diff --git a/.github/actions/upload-artifact-resilient/action.yml b/.github/actions/upload-artifact-resilient/action.yml index ce4322fb..79942eef 100644 --- a/.github/actions/upload-artifact-resilient/action.yml +++ b/.github/actions/upload-artifact-resilient/action.yml @@ -52,7 +52,7 @@ runs: - name: "๐Ÿ“ค Upload ${{ inputs.artifact-name }} (attempt 1)" id: attempt1 continue-on-error: true - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: ${{ inputs.artifact-name }} path: ${{ inputs.artifact-path }} @@ -80,7 +80,7 @@ runs: id: attempt2 if: steps.attempt1.outcome == 'failure' continue-on-error: true - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: ${{ inputs.artifact-name }} path: ${{ inputs.artifact-path }} @@ -108,7 +108,7 @@ runs: id: attempt3 if: steps.attempt1.outcome == 'failure' && steps.attempt2.outcome == 'failure' continue-on-error: ${{ inputs.continue-on-error == 'true' }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: ${{ inputs.artifact-name }} path: ${{ inputs.artifact-path }} diff --git a/.github/actions/upload-statistics/action.yml b/.github/actions/upload-statistics/action.yml index db9c5096..e3b55dfc 100644 --- a/.github/actions/upload-statistics/action.yml +++ b/.github/actions/upload-statistics/action.yml @@ -59,7 +59,7 @@ runs: - name: ๐Ÿ“ค Upload ${{ inputs.artifact-name }} if: always() # Always run to capture data even on job failure continue-on-error: ${{ inputs.continue-on-error == 'true' }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: ${{ inputs.artifact-name }} path: ${{ inputs.artifact-path }} diff --git a/.github/actions/warm-cache/action.yml b/.github/actions/warm-cache/action.yml index b5a6bb5c..f569d8bd 100644 --- a/.github/actions/warm-cache/action.yml +++ b/.github/actions/warm-cache/action.yml @@ -461,7 +461,7 @@ runs: # -------------------------------------------------------------------- - name: ๐Ÿ“ค Upload cache statistics if: always() - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: cache-stats-${{ inputs.matrix-os }}-${{ inputs.go-version }} path: cache-stats-*.json diff --git a/.github/env/10-mage-x.env b/.github/env/10-mage-x.env index 7d30f31d..d7c94345 100644 --- a/.github/env/10-mage-x.env +++ b/.github/env/10-mage-x.env @@ -36,7 +36,7 @@ # ================================================================================================ # MAGE-X version -MAGE_X_VERSION=v1.28.0 +MAGE_X_VERSION=v1.29.0 # For mage-x development, set to 'true' to use local version instead of downloading from releases MAGE_X_USE_LOCAL=false @@ -84,8 +84,8 @@ MAGE_X_GOFUMPT_VERSION=v0.11.0 MAGE_X_GOFUMPT_VERSION_LATEST=v0.12.0 MAGE_X_GOFUMPT_VERSION_LATEST_MIN_GO=1.26 MAGE_X_GOLANGCI_LINT_VERSION=v2.14.0 -MAGE_X_GORELEASER_VERSION=v2.18.2 -MAGE_X_GOVULNCHECK_VERSION=v1.8.0 +MAGE_X_GORELEASER_VERSION=v2.18.3 +MAGE_X_GOVULNCHECK_VERSION=v1.9.0 MAGE_X_GO_SECONDARY_VERSION=1.24.x MAGE_X_GO_VERSION=1.24.x MAGE_X_MOCKGEN_VERSION=v0.6.0 @@ -93,8 +93,8 @@ MAGE_X_NANCY_VERSION=v2.1.0 # OSV-Scanner version for MAGE-X parity (authoritative pin is OSV_SCANNER_VERSION in # 10-security.env, which the CI workflow uses to download the official release binary # and verify it against the SHA-256 digests pinned there). -MAGE_X_OSV_SCANNER_VERSION=v2.6.0 -MAGE_X_STATICCHECK_VERSION=2026.2.1 +MAGE_X_OSV_SCANNER_VERSION=v2.7.0 +MAGE_X_STATICCHECK_VERSION=2026.2.2 MAGE_X_SWAG_VERSION=v1.16.6 MAGE_X_YAMLFMT_VERSION=v0.21.0 # benchstat is versioned by two pins. golang.org/x/perf ships only pseudo-versions @@ -117,7 +117,7 @@ MAGE_X_YAMLFMT_VERSION=v0.21.0 # runners on Go >= _LATEST_MIN_GO install _LATEST; Go 1.25.x runners install the held # MAGE_X_BENCHSTAT_VERSION; Go < 1.25 is skipped (benchstat's floor). MAGE_X_BENCHSTAT_VERSION=v0.0.0-20260813145340-fd4a688df892 -MAGE_X_BENCHSTAT_VERSION_LATEST=v0.0.0-20260929162123-406019bb8b68 +MAGE_X_BENCHSTAT_VERSION_LATEST=v0.0.0-20261009192801-be2c69fb417e MAGE_X_BENCHSTAT_VERSION_LATEST_MIN_GO=1.26 MAGE_X_MAGE_VERSION=v1.17.2 diff --git a/.github/env/10-security.env b/.github/env/10-security.env index 9bdfddf8..bcaba822 100644 --- a/.github/env/10-security.env +++ b/.github/env/10-security.env @@ -80,9 +80,9 @@ OSV_SCANNER_FAIL_ON_VULNERABILITY=true # ================================================================================================ GITLEAKS_VERSION=8.30.1 -GOVULNCHECK_VERSION=v1.8.0 +GOVULNCHECK_VERSION=v1.9.0 NANCY_VERSION=v2.1.0 -OSV_SCANNER_VERSION=v2.6.0 +OSV_SCANNER_VERSION=v2.7.0 # SHA-256 digests of the OFFICIAL OSV-Scanner release binaries, per runner # platform. These are the supply-chain trust anchor for the prebuilt-binary @@ -100,5 +100,5 @@ OSV_SCANNER_VERSION=v2.6.0 # `osv-scanner_SHA256SUMS` asset ( is the pinned version above, # e.g. v2.5.1); the URL is illustrative, so it is not rewritten on a version bump: # https://github.com/google/osv-scanner/releases/download//osv-scanner_SHA256SUMS -OSV_SCANNER_SHA256_LINUX_AMD64=ca69b3d3cd08f889a49dc0a383122f71cc528b83803671df5fd874d97485b108 -OSV_SCANNER_SHA256_LINUX_ARM64=2c71403eb443d05891c4f268c3ad771cf4f16e5443463fd7851ef8f454d3c7e4 +OSV_SCANNER_SHA256_LINUX_AMD64=160c6253e2922e9e0a6a9771c5c4c40a4b3c6090b34a3cdd5e80c96cc2e4218b +OSV_SCANNER_SHA256_LINUX_ARM64=4061ef4c021ed3c47f203b818f337e351336cc5cd67c0274fc36bd1dfc728dd7 diff --git a/.github/tech-conventions/go-essentials.md b/.github/tech-conventions/go-essentials.md index 4b486fbe..c95ac4a2 100644 --- a/.github/tech-conventions/go-essentials.md +++ b/.github/tech-conventions/go-essentials.md @@ -10,7 +10,7 @@ Context should flow through your entire call stackโ€”no exceptions. * **Always pass `context.Context` as the first parameter** for any operation that could be canceled, timeout, or carry request-scoped values * **Never store context in structs**โ€”pass it explicitly through function calls -* **Use `context.Background()` only at the top level** (main, tests, or service initialization) +* **Use `context.Background()` only at the top level** (main or service initialization); tests use `t.Context()` * **Derive child contexts** using `context.WithTimeout()`, `context.WithCancel()`, or `context.WithValue()` * **Respect context cancellation** by checking `ctx.Done()` in long-running operations @@ -197,13 +197,13 @@ func CreateUser(ctx context.Context, user User) error { // โœ… Explicit initialization type Cache struct { mu sync.RWMutex - data map[string]interface{} + data map[string]any once sync.Once } func NewCache() *Cache { return &Cache{ - data: make(map[string]interface{}), + data: make(map[string]any), } } @@ -215,10 +215,10 @@ func (c *Cache) ensureInitialized() { } // ๐Ÿšซ Hidden initialization -var globalCache map[string]interface{} +var globalCache map[string]any func init() { - globalCache = make(map[string]interface{}) + globalCache = make(map[string]any) // This runs at import time - unpredictable order // Hard to test, hard to control } @@ -344,8 +344,7 @@ Write code that performs well by default, and measure when optimization is neede func BenchmarkUserProcessing(b *testing.B) { users := generateTestUsers(1000) - b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { // times only the loop, not the setup above processUsers(users) } } diff --git a/.github/tech-conventions/testing-standards.md b/.github/tech-conventions/testing-standards.md index a1b166e1..47b474d8 100644 --- a/.github/tech-conventions/testing-standards.md +++ b/.github/tech-conventions/testing-standards.md @@ -24,18 +24,17 @@ We use the `testify` suite for unit tests. All tests must follow these conventio * Mock external dependencies โ€” tests should be fast and deterministic * Use descriptive test names that explain the scenario being tested * Test error cases โ€” ensure your error handling actually works +* Use the test's own helpers: `t.Context()` instead of `context.Background()`, `t.Setenv()` instead of `os.Setenv()`, `t.Chdir()` instead of `os.Chdir()`, and `t.TempDir()` instead of `os.MkdirTemp()`. `t.Setenv()` and `t.Chdir()` restore process state when the test ends; neither can be used in parallel tests or tests with parallel ancestors * Handle all errors in tests properly: - * `os.Setenv()` returns an error - use `require.NoError(t, err)` * `os.Unsetenv()` returns an error - use `require.NoError(t, err)` * `db.Close()` in defer statements - wrap in anonymous function: `defer func() { _ = db.Close() }()` - * Deferred `os.Setenv()` for cleanup - wrap in anonymous function to ignore error

## ๐Ÿ“ Test Structure Example ```go -func TestUserService_CreateUser(t *testing.T) { +func TestUserServiceCreateUser(t *testing.T) { tests := []struct { name string input User @@ -78,7 +77,7 @@ func TestUserService_CreateUser(t *testing.T) { service := NewUserService(mockDB) // Execute - err := service.CreateUser(context.Background(), tt.input) + err := service.CreateUser(t.Context(), tt.input) // Assert if tt.wantErr { @@ -207,7 +206,7 @@ func requireUserEqual(t *testing.T, expected, actual User) { } // Bad: Overly generic helper -func assertStuff(t *testing.T, a, b interface{}) { +func assertStuff(t *testing.T, a, b any) { // Too vague, hard to understand intent } ``` diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 4d25135f..9b8ab16f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -49,7 +49,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 + uses: github/codeql-action/init@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -60,7 +60,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 + uses: github/codeql-action/autobuild@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3 # โ„น๏ธ Command-line programs to run using the OS shell. # ๐Ÿ“š https://git.io/JvXDl @@ -70,4 +70,4 @@ jobs: # uses a compiled language - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 + uses: github/codeql-action/analyze@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3 diff --git a/.github/workflows/fortress-security-scans.yml b/.github/workflows/fortress-security-scans.yml index bb501f10..453886cc 100644 --- a/.github/workflows/fortress-security-scans.yml +++ b/.github/workflows/fortress-security-scans.yml @@ -854,7 +854,7 @@ jobs: # Scanning hiccup must not fail the security job. if: always() && inputs.enable-osv && hashFiles('osv-results.sarif') != '' continue-on-error: true - uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 + uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3 with: sarif_file: osv-results.sarif category: osv-scanner diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 493a3c77..098ecfba 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -68,7 +68,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: SARIF file path: results.sarif @@ -77,6 +77,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable the upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 + uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3 with: sarif_file: results.sarif