From afc6b0e950c8bb43625e45357fe0e5e5a7f20dde Mon Sep 17 00:00:00 2001 From: Nitin Kumar Patel Date: Sun, 12 Jul 2026 10:02:07 +0530 Subject: [PATCH 1/7] ci: add GitHub Actions workflow for build, vet, test, and lint No CI existed. Adds .github/workflows/ci.yml running go build / vet / test on push to development|master and on every PR (Go 1.25, module cache). A golangci-lint v2 job runs advisory-only for now (the repo's strict config was never enforced in CI); flip continue-on-error once the tree is lint-clean. --- .github/workflows/ci.yml | 54 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9591dde --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,54 @@ +name: CI + +on: + push: + branches: [development, master] + pull_request: + +permissions: + contents: read + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-test: + name: build · vet · test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version: "1.25" + cache: true + + - name: go build + run: go build ./... + + - name: go vet + run: go vet ./... + + - name: go test + run: go test ./... + + lint: + name: golangci-lint (advisory) + runs-on: ubuntu-latest + # Advisory for now: the repo's strict golangci-lint v2 config has not been + # enforced in CI before, so this reports findings without blocking merges. + # Flip continue-on-error to false once the tree is lint-clean. + continue-on-error: true + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version: "1.25" + cache: true + + - uses: golangci/golangci-lint-action@v6 + with: + version: v2.1.6 + args: --timeout=9m From fa1d3b2a7c3d5930ecf49efe7b3fcff791368411 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Patel Date: Sun, 12 Jul 2026 10:03:39 +0530 Subject: [PATCH 2/7] ci: install golangci-lint v2 via official script (advisory job) golangci-lint-action@v6 installs golangci-lint v1, incompatible with the repo's v2 config. Install v2 via the official script instead. Still advisory (continue-on-error) until the tree is lint-clean. --- .github/workflows/ci.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9591dde..aaccaa5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,7 +48,8 @@ jobs: go-version: "1.25" cache: true - - uses: golangci/golangci-lint-action@v6 - with: - version: v2.1.6 - args: --timeout=9m + - name: install golangci-lint v2 + run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b "$(go env GOPATH)/bin" + + - name: golangci-lint run + run: "$(go env GOPATH)/bin/golangci-lint run --timeout=9m ./..." From 794453d852dea2025083c82a19570b9d8f58bd2e Mon Sep 17 00:00:00 2001 From: Nitin Kumar Patel Date: Sun, 12 Jul 2026 10:06:48 +0530 Subject: [PATCH 3/7] =?UTF-8?q?ci:=20slim=20to=20one=20lean=20job=20(build?= =?UTF-8?q?=C2=B7vet=C2=B7test),=20PR-only=20+=20push-to-master?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Public repo, so Actions minutes are free — but keep it lean: trigger on pull_request (feature pushes covered by their PR) plus push to master; drop the separate golangci-lint download job (go vet stays); keep caching and cancel-in-progress. --- .github/workflows/ci.yml | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aaccaa5..6895057 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,9 +1,13 @@ name: CI +# Public repo → GitHub-hosted Actions minutes are free/unlimited. Kept lean +# anyway: one run per PR (pull_request only; feature-branch pushes are covered +# by their PR), plus push to master to verify releases. Superseded runs cancel, +# and the Go build/module cache keeps runs short. on: - push: - branches: [development, master] pull_request: + push: + branches: [master] permissions: contents: read @@ -32,24 +36,3 @@ jobs: - name: go test run: go test ./... - - lint: - name: golangci-lint (advisory) - runs-on: ubuntu-latest - # Advisory for now: the repo's strict golangci-lint v2 config has not been - # enforced in CI before, so this reports findings without blocking merges. - # Flip continue-on-error to false once the tree is lint-clean. - continue-on-error: true - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-go@v5 - with: - go-version: "1.25" - cache: true - - - name: install golangci-lint v2 - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b "$(go env GOPATH)/bin" - - - name: golangci-lint run - run: "$(go env GOPATH)/bin/golangci-lint run --timeout=9m ./..." From c4278a9591af29e434bb47a63a6ada369420dfd9 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Patel Date: Sun, 12 Jul 2026 10:13:19 +0530 Subject: [PATCH 4/7] ci: split into parallel per-check jobs + add a security workflow CI (ci.yml): Build, Vet, Test, Tidy as blocking parallel jobs; Format and Lint advisory (pre-existing test-file gofmt + never-enforced golangci config). Security (security.yml): govulncheck, gosec, CodeQL, and Dependency Review as separate parallel jobs (advisory scanners to start), on PR / push-to-master / weekly. Every job restores the Go build+module cache to stay fast. --- .github/workflows/ci.yml | 91 +++++++++++++++++++++++++++++----- .github/workflows/security.yml | 83 +++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/security.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6895057..fa1ab4a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,9 +1,9 @@ name: CI -# Public repo → GitHub-hosted Actions minutes are free/unlimited. Kept lean -# anyway: one run per PR (pull_request only; feature-branch pushes are covered -# by their PR), plus push to master to verify releases. Superseded runs cancel, -# and the Go build/module cache keeps runs short. +# Public repo → GitHub-hosted Actions are free. Every check is its own job so +# they run in parallel; each restores the Go build/module cache to stay fast. +# One run per PR (feature-branch pushes are covered by their PR) plus push to +# master. Superseded runs cancel automatically. on: pull_request: push: @@ -13,26 +13,91 @@ permissions: contents: read concurrency: - group: ci-${{ github.ref }} + group: ci-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: - build-test: - name: build · vet · test + build: + name: Build runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "1.25" + cache: true + - run: go build ./... + + vet: + name: Vet + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "1.25" + cache: true + - run: go vet ./... + test: + name: Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: "1.25" cache: true + - run: go test ./... - - name: go build - run: go build ./... + tidy: + name: Tidy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "1.25" + cache: true + - name: go mod tidy is clean + run: | + go mod tidy + git diff --exit-code go.mod go.sum - - name: go vet - run: go vet ./... + format: + name: Format + runs-on: ubuntu-latest + # Advisory: some pre-existing _test.go files are not gofmt-clean (the repo's + # golangci config skips tests). Reports without blocking; flip to blocking + # after a one-time `gofmt -w`. + continue-on-error: true + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "1.25" + cache: true + - name: gofmt + run: | + unformatted="$(gofmt -l .)" + if [ -n "$unformatted" ]; then + echo "::warning::gofmt needed on:"; echo "$unformatted" + exit 1 + fi - - name: go test - run: go test ./... + lint: + name: Lint + runs-on: ubuntu-latest + # Advisory: the repo's strict golangci-lint v2 config was never enforced in + # CI. Reports findings without blocking; flip to blocking once clean. + continue-on-error: true + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "1.25" + cache: true + - name: install golangci-lint v2 + run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b "$(go env GOPATH)/bin" + - name: golangci-lint run + run: "$(go env GOPATH)/bin/golangci-lint run --timeout=9m ./..." diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..8124c27 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,83 @@ +name: Security + +# Security scanning, separate from CI so it runs in parallel and is easy to +# read. Each scanner is its own cached job. Runs on PRs, on push to master, and +# weekly (so newly-disclosed CVEs are caught even without a push). +on: + pull_request: + push: + branches: [master] + schedule: + - cron: "0 6 * * 1" # Mondays 06:00 UTC + +permissions: + contents: read + +concurrency: + group: security-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + govulncheck: + name: Vulnerabilities (govulncheck) + runs-on: ubuntu-latest + # Advisory to start: flags known CVEs in dependencies the code reaches. + # Flip to blocking once the baseline is confirmed clean. + continue-on-error: true + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "1.25" + cache: true + - name: install govulncheck + run: go install golang.org/x/vuln/cmd/govulncheck@latest + - name: govulncheck + run: "$(go env GOPATH)/bin/govulncheck ./..." + + gosec: + name: SAST (gosec) + runs-on: ubuntu-latest + # Advisory to start: static security analysis (hardcoded creds, weak crypto, + # unsafe patterns). Reports without blocking until the baseline is triaged. + continue-on-error: true + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "1.25" + cache: true + - name: install gosec + run: go install github.com/securego/gosec/v2/cmd/gosec@latest + - name: gosec + run: "$(go env GOPATH)/bin/gosec -exclude-generated ./..." + + codeql: + name: CodeQL (SAST) + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + actions: read + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "1.25" + cache: true + - uses: github/codeql-action/init@v3 + with: + languages: go + - uses: github/codeql-action/autobuild@v3 + - uses: github/codeql-action/analyze@v3 + + dependency-review: + name: Dependency Review + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + steps: + - uses: actions/checkout@v4 + - name: Review dependency changes for known vulnerabilities + uses: actions/dependency-review-action@v4 + with: + fail-on-severity: high From 0678096d09baf134cef1dcbc8124bfac29834089 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Patel Date: Sun, 12 Jul 2026 10:15:22 +0530 Subject: [PATCH 5/7] ci: make advisory scanners report-only (green with warnings) Format, Lint, govulncheck, and gosec now run and surface findings as workflow annotations without failing the check, so the PR isn't red on pre-existing findings while the real gates (Build/Vet/Test/Tidy) stay blocking. CodeQL reports to the Security tab; Dependency Review blocks new high-severity CVEs. --- .github/workflows/ci.yml | 12 +++++++----- .github/workflows/security.yml | 8 ++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa1ab4a..01f1d4d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,12 +77,14 @@ jobs: with: go-version: "1.25" cache: true - - name: gofmt + - name: gofmt (report-only) run: | unformatted="$(gofmt -l .)" if [ -n "$unformatted" ]; then - echo "::warning::gofmt needed on:"; echo "$unformatted" - exit 1 + echo "::warning::gofmt needed on the following files (advisory):" + echo "$unformatted" + else + echo "all files gofmt-clean" fi lint: @@ -99,5 +101,5 @@ jobs: cache: true - name: install golangci-lint v2 run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b "$(go env GOPATH)/bin" - - name: golangci-lint run - run: "$(go env GOPATH)/bin/golangci-lint run --timeout=9m ./..." + - name: golangci-lint run (report-only) + run: "$(go env GOPATH)/bin/golangci-lint run --timeout=9m ./... || echo '::warning::golangci-lint reported findings (advisory)'" diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 8124c27..c2932b0 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -32,8 +32,8 @@ jobs: cache: true - name: install govulncheck run: go install golang.org/x/vuln/cmd/govulncheck@latest - - name: govulncheck - run: "$(go env GOPATH)/bin/govulncheck ./..." + - name: govulncheck (report-only) + run: "$(go env GOPATH)/bin/govulncheck ./... || echo '::warning::govulncheck reported findings (advisory)'" gosec: name: SAST (gosec) @@ -49,8 +49,8 @@ jobs: cache: true - name: install gosec run: go install github.com/securego/gosec/v2/cmd/gosec@latest - - name: gosec - run: "$(go env GOPATH)/bin/gosec -exclude-generated ./..." + - name: gosec (report-only) + run: "$(go env GOPATH)/bin/gosec -exclude-generated ./... || echo '::warning::gosec reported findings (advisory)'" codeql: name: CodeQL (SAST) From ba1d2413eba18da20a0aa9a0235d0bde6ab0b77e Mon Sep 17 00:00:00 2001 From: Nitin Kumar Patel Date: Sun, 12 Jul 2026 10:28:06 +0530 Subject: [PATCH 6/7] ci: fix go vet failure + combine Build & Vet to cut CI time - Fix pre-existing 'using resp before checking for errors' (httpresponse vet check) in kubernetes/handlers_http_test.go: check the Do() error before deferring resp.Body.Close() (4 sites). - Combine Build and Vet into one job so 'go vet' reuses the compile cache 'go build' just populated, instead of a standalone 'go vet ./...' that recompiles the whole module (~4-5 min). Test stays a parallel job. --- .github/workflows/ci.yml | 37 +++++++++++--------------------- kubernetes/handlers_http_test.go | 20 +++++++++++++---- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 01f1d4d..45bff9c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,9 +1,11 @@ name: CI -# Public repo → GitHub-hosted Actions are free. Every check is its own job so -# they run in parallel; each restores the Go build/module cache to stay fast. -# One run per PR (feature-branch pushes are covered by their PR) plus push to -# master. Superseded runs cancel automatically. +# Public repo → GitHub-hosted Actions are free. Kept fast: Build and Vet share +# one job so `go vet` reuses the compile cache `go build` just populated +# (standalone `go vet ./...` recompiles everything and is slow). Test runs in +# parallel; the quick checks (Tidy/Format) give sub-minute feedback. Every job +# restores the Go build+module cache. One run per PR (+ push to master); +# superseded runs cancel. on: pull_request: push: @@ -17,8 +19,8 @@ concurrency: cancel-in-progress: true jobs: - build: - name: Build + build-vet: + name: Build & Vet runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -26,18 +28,10 @@ jobs: with: go-version: "1.25" cache: true - - run: go build ./... - - vet: - name: Vet - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - go-version: "1.25" - cache: true - - run: go vet ./... + - name: go build + run: go build ./... + - name: go vet (reuses the build cache) + run: go vet ./... test: name: Test @@ -67,10 +61,6 @@ jobs: format: name: Format runs-on: ubuntu-latest - # Advisory: some pre-existing _test.go files are not gofmt-clean (the repo's - # golangci config skips tests). Reports without blocking; flip to blocking - # after a one-time `gofmt -w`. - continue-on-error: true steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 @@ -90,9 +80,6 @@ jobs: lint: name: Lint runs-on: ubuntu-latest - # Advisory: the repo's strict golangci-lint v2 config was never enforced in - # CI. Reports findings without blocking; flip to blocking once clean. - continue-on-error: true steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 diff --git a/kubernetes/handlers_http_test.go b/kubernetes/handlers_http_test.go index 9b0e2b2..67b9b54 100644 --- a/kubernetes/handlers_http_test.go +++ b/kubernetes/handlers_http_test.go @@ -496,7 +496,10 @@ func TestConfigMap_PatchBadContentTypeReturns400(t *testing.T) { base+"/api/v1/namespaces/default/configmaps/p", bytes.NewReader([]byte(`[]`))) req.Header.Set("Content-Type", "application/strategic-merge-patch+json") - resp, _ := http.DefaultClient.Do(req) + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("request: %v", err) + } defer resp.Body.Close() if resp.StatusCode != http.StatusBadRequest { @@ -595,7 +598,10 @@ func TestConfigMap_PatchBadJSONReturns400(t *testing.T) { ) req.Header.Set("Content-Type", "application/merge-patch+json") - resp, _ := http.DefaultClient.Do(req) + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("request: %v", err) + } defer resp.Body.Close() if resp.StatusCode != http.StatusBadRequest { @@ -618,7 +624,10 @@ func TestConfigMap_PatchTypeIncompatibleReturns400(t *testing.T) { ) req.Header.Set("Content-Type", "application/merge-patch+json") - resp, _ := http.DefaultClient.Do(req) + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("request: %v", err) + } defer resp.Body.Close() if resp.StatusCode != http.StatusBadRequest { @@ -636,7 +645,10 @@ func TestNamespace_PatchOnMissingReturns404(t *testing.T) { ) req.Header.Set("Content-Type", "application/merge-patch+json") - resp, _ := http.DefaultClient.Do(req) + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("request: %v", err) + } defer resp.Body.Close() if resp.StatusCode != http.StatusNotFound { From 5581528f15c8fdad4ca3a4f274c0176ef8ff01c0 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Patel Date: Sun, 12 Jul 2026 10:35:30 +0530 Subject: [PATCH 7/7] ci: cache Go build+module dirs with restore-keys for fast repeat runs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit setup-go's built-in cache keys on an exact go.sum hash, so every branch that adds a dependency gets a cold cache and recompiles the whole cloud-SDK tree (~4-5 min). Switch to actions/cache with a restore-keys fallback (go--*) so a changed go.sum still restores the previous build cache and only the changed deps recompile — repeat/PR runs drop to ~1-2 min. --- .github/workflows/ci.yml | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 45bff9c..c58bf0a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,18 @@ jobs: - uses: actions/setup-go@v5 with: go-version: "1.25" - cache: true + cache: false + # Manual cache with restore-keys so a changed go.sum still restores the + # previous build+module cache (only the changed deps recompile) instead + # of a full cold compile of the whole cloud-SDK dependency tree. + - uses: actions/cache@v4 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: go-${{ runner.os }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + go-${{ runner.os }}- - name: go build run: go build ./... - name: go vet (reuses the build cache) @@ -41,7 +52,15 @@ jobs: - uses: actions/setup-go@v5 with: go-version: "1.25" - cache: true + cache: false + - uses: actions/cache@v4 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: go-${{ runner.os }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + go-${{ runner.os }}- - run: go test ./... tidy: