diff --git a/.claude/skills/upgrading-golang/SKILL.md b/.claude/skills/upgrading-golang/SKILL.md index 596e715cb..750ebb6e0 100644 --- a/.claude/skills/upgrading-golang/SKILL.md +++ b/.claude/skills/upgrading-golang/SKILL.md @@ -1,6 +1,6 @@ --- name: upgrading-golang -description: Upgrades Go version across the entire Chainloop codebase including source files, Docker images, CI/CD workflows, and documentation. Use when the user mentions upgrading Go, golang version, or updating Go compiler version. +description: Upgrades Go version across the entire Chainloop codebase including source files, Docker images, golangci-lint, CI/CD workflows, and documentation. Use when the user mentions upgrading Go, golang version, or updating Go compiler version, or when CI lint fails because golangci-lint was built with an older Go than the one targeted in go.mod. --- # Upgrading Golang Version @@ -12,7 +12,7 @@ This skill automates the comprehensive Go version upgrade process across all com ### 1. Confirm Target Versions Ask the user: -1. What Go version they want to upgrade to (e.g., "1.25.3") +1. What Go version they want to upgrade to (e.g., "1.25.3"). If they give only a minor version (e.g., "1.27"), use the latest patch from `curl -s 'https://go.dev/dl/?mode=json'`. 2. Whether they also want to upgrade Atlas migrations Docker image (if yes, ask for target Atlas version, e.g., "0.38.0") ### 2. Get Docker Image Digest @@ -25,6 +25,16 @@ docker pull golang:X.XX.X Extract the SHA256 digest from the output (format: `sha256:abc123...`). +If the Docker daemon is not running, read the multi-arch index digest from the registry instead: + +```bash +TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/golang:pull" | jq -r .token) +curl -sI -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/vnd.oci.image.index.v1+json" \ + -H "Accept: application/vnd.docker.distribution.manifest.list.v2+json" \ + https://registry-1.docker.io/v2/library/golang/manifests/X.XX.X | grep -i docker-content-digest +``` + ### 3. Update Source Code Update the `go` directive in: @@ -37,6 +47,8 @@ Pattern to replace: go X.XX.X ``` +Then run `go mod tidy` and `go build ./...`. + ### 4. Update Docker Images Update all Dockerfiles with the new version and SHA256 digest. See [files-to-update.md](files-to-update.md) for the complete list. @@ -51,18 +63,42 @@ With: FROM golang:X.XX.X@sha256:NEW_DIGEST AS builder ``` -### 5. Update Documentation +### 5. Update golangci-lint + +golangci-lint refuses to run when it was built with a Go version older than the `go` directive in `go.mod` ("the Go language version (goX.YY) used to build golangci-lint is lower than the targeted Go version"). On a Go minor upgrade, bump it to a release that supports the new Go version. + +1. Find the first golangci-lint release that adds support for the new Go minor (its changelog has a "goX.YY support" entry): `gh release list -R golangci/golangci-lint`. Prefer the latest release. +2. Update every `version:` of `golangci/golangci-lint-action` in `.github/workflows/lint.yml`. +3. Update the install version in the `init` target of `./common.mk` to the same version. +4. Verify locally the way CI runs it (CI uses `only-new-issues`), from the repo root and from `app/cli`, `app/controlplane` and `app/artifact-cas`: + +```bash +GOBIN= go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@vX.Y.Z +/golangci-lint run --new-from-rev=/main +``` + +For a Go patch upgrade, the golangci-lint bump is not required. + +### 5b. Regenerate Protobuf Code + +The protoc plugins (`protoc-gen-go`, etc.) format their output with the `go/format` of the Go toolchain that built them. A new Go minor can change how comments in generated `.pb.go` files are formatted, and the CI `Test (main-module)` job fails with "The Git repository is dirty" when the committed files do not match. + +1. Rebuild the codegen tools with the new Go: `make init-api-tools`. +2. Run `make api` (the openapi step needs Docker running) and `make config`. +3. Commit the regenerated `.pb.go` files. The changes are expected to be comment-only; investigate anything else. + +### 6. Update Documentation Update the version reference in `./CLAUDE.md` under "Key Technologies": ```markdown -- **Language**: Go X.XX.X. To know how to upgrade go version, see docs/runbooks +- **Language**: Go X.XX.X ``` -### 6. Update Atlas Docker Image and CLI (Optional) +### 7. Update Atlas Docker Image and CLI (Optional) If the user requested an Atlas upgrade: -**6a. Pull the Atlas Docker image and extract its SHA256 digest:** +**7a. Pull the Atlas Docker image and extract its SHA256 digest:** ```bash docker pull arigaio/atlas:X.XX.X @@ -70,7 +106,7 @@ docker pull arigaio/atlas:X.XX.X Extract the SHA256 digest from the output (format: `sha256:abc123...`). -**6b. Update `./app/controlplane/Dockerfile.migrations`:** +**7b. Update `./app/controlplane/Dockerfile.migrations`:** Pattern to replace: ```dockerfile @@ -100,17 +136,11 @@ If the command fails or the version is not available, do NOT update common.mk. O Update the Atlas CLI installation version in the `init` target: -Pattern to replace: -```makefile -curl -sSf https://atlasgo.sh | ATLAS_VERSION=vX.XX.X sh -s -- -y -``` - -With the new version (note: use `v` prefix for the version): ```makefile curl -sSf https://atlasgo.sh | ATLAS_VERSION=vX.XX.X sh -s -- -y ``` -### 7. Verify Changes +### 8. Verify Changes Run verification commands: ```bash @@ -120,8 +150,9 @@ make lint If errors occur, address them before completing the upgrade. -### 8. Final Checks +### 9. Final Checks +- Search for leftover references to the old version: `grep -rnE "golang:OLD|go OLD|OLD_MINOR\.[0-9]" --exclude=go.sum .` - Ensure all license headers are updated (2024 → 2024-2025 or add current year) - Run `buf format -w` if any proto files were affected - Run `wire ./...` if any constructor dependencies changed @@ -131,5 +162,6 @@ If errors occur, address them before completing the upgrade. - Always use SHA256 digests for Docker images for security and reproducibility - The dagger module (`./extras/dagger/go.mod`) must NOT be updated +- GitHub Actions workflows read the Go version from `go.mod` (`go-version-file`), so they need no change for Go itself - Test thoroughly as Go upgrades can introduce breaking changes - Multiple components use Go: CLI, Control Plane, and Artifact CAS diff --git a/.claude/skills/upgrading-golang/files-to-update.md b/.claude/skills/upgrading-golang/files-to-update.md index 155560b8f..0674f061a 100644 --- a/.claude/skills/upgrading-golang/files-to-update.md +++ b/.claude/skills/upgrading-golang/files-to-update.md @@ -13,9 +13,7 @@ This reference lists all files that must be updated when upgrading Go versions. ## Docker Images ### Dockerfiles (Golang) -- `./app/artifact-cas/Dockerfile` - `./app/artifact-cas/Dockerfile.goreleaser` -- `./app/controlplane/Dockerfile` - `./app/controlplane/Dockerfile.goreleaser` - `./app/cli/Dockerfile.goreleaser` @@ -24,6 +22,17 @@ Update pattern in all: FROM golang:X.XX.X@sha256:DIGEST AS builder ``` +## golangci-lint (Go minor upgrades) + +- `./.github/workflows/lint.yml` - every `version:` of `golangci/golangci-lint-action` (main module, apps, and dagger module jobs) +- `./common.mk` - golangci-lint install version in the `init` target + +Keep both on the same golangci-lint version. + +## GitHub Actions + +No change needed for Go itself: `test.yml`, `lint.yml`, `release.yaml` and `codeql.yml` use `go-version-file: 'go.mod'`. + ### Atlas Files (Optional) - `./app/controlplane/Dockerfile.migrations` - Docker image for migrations - `./common.mk` - CLI tool installation in `make init` @@ -48,18 +57,20 @@ curl -sSf https://atlasgo.sh | ATLAS_VERSION=vX.XX.X sh -s -- -y ### Project Documentation - `./CLAUDE.md` - Update "Key Technologies" section: ```markdown - - **Language**: Go X.XX.X. To know how to upgrade go version, see docs/runbooks + - **Language**: Go X.XX.X ``` ## Summary -**Total files to update for Go**: 13 files +**Files to update for Go**: 5 files - 1 go.mod file -- 5 Dockerfiles (Golang) -- 5 GitHub Actions workflows -- 1 example workflow +- 3 Dockerfiles (Golang) - 1 documentation file +**golangci-lint (Go minor upgrades)**: 2 files +- 1 GitHub Actions workflow (lint.yml) +- 1 Makefile (common.mk) + **Optional Atlas upgrade**: 2 files - 1 Dockerfile (Atlas migrations) - 1 Makefile (Atlas CLI in make init) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 069c92c1c..cfbea2444 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -37,7 +37,7 @@ jobs: uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 if: ${{ matrix.app == 'main-module' }} with: - version: v2.9.0 + version: v2.14.0 only-new-issues: 'true' - name: Lint ${{ matrix.app }} @@ -45,7 +45,7 @@ jobs: if: ${{ matrix.app != 'main-module' }} with: working-directory: app/${{ matrix.app }} - version: v2.9.0 + version: v2.14.0 only-new-issues: 'true' lint-protos: @@ -87,5 +87,5 @@ jobs: uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 with: working-directory: extras/dagger - version: v2.9.0 + version: v2.14.0 only-new-issues: 'true' diff --git a/CLAUDE.md b/CLAUDE.md index 8f2da7665..f58a7ec1c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -139,7 +139,7 @@ make migration_lint # Lint migration files ## Key Technologies -- **Language**: Go 1.26.4 +- **Language**: Go 1.27.1 - **API**: gRPC with HTTP/JSON gateway, Protocol Buffers with buf - **Database**: PostgreSQL with Ent ORM, Atlas for migrations - **Authentication**: OIDC, JWT tokens diff --git a/app/artifact-cas/Dockerfile.goreleaser b/app/artifact-cas/Dockerfile.goreleaser index 0b7081c4e..7781f24fc 100644 --- a/app/artifact-cas/Dockerfile.goreleaser +++ b/app/artifact-cas/Dockerfile.goreleaser @@ -1,4 +1,4 @@ -FROM golang:1.26.6@sha256:640a234f4bea3e399c056b7b8f9c667c4939befae8db2f14e9785e16eccd4205 AS builder +FROM golang:1.27.1@sha256:1e93e00a31255c07e9a34c4207f3006e1501730c5323697cee7dfb827fdae44c AS builder FROM scratch diff --git a/app/cli/Dockerfile.goreleaser b/app/cli/Dockerfile.goreleaser index 66e0fc1f9..874f7af53 100644 --- a/app/cli/Dockerfile.goreleaser +++ b/app/cli/Dockerfile.goreleaser @@ -1,4 +1,4 @@ -FROM golang:1.26.6@sha256:640a234f4bea3e399c056b7b8f9c667c4939befae8db2f14e9785e16eccd4205 AS builder +FROM golang:1.27.1@sha256:1e93e00a31255c07e9a34c4207f3006e1501730c5323697cee7dfb827fdae44c AS builder RUN mkdir -p /.config/chainloop FROM scratch diff --git a/app/controlplane/Dockerfile.goreleaser b/app/controlplane/Dockerfile.goreleaser index ebc4d8967..69f360ffa 100644 --- a/app/controlplane/Dockerfile.goreleaser +++ b/app/controlplane/Dockerfile.goreleaser @@ -1,4 +1,4 @@ -FROM golang:1.26.6@sha256:640a234f4bea3e399c056b7b8f9c667c4939befae8db2f14e9785e16eccd4205 AS builder +FROM golang:1.27.1@sha256:1e93e00a31255c07e9a34c4207f3006e1501730c5323697cee7dfb827fdae44c AS builder FROM scratch diff --git a/app/controlplane/api/controlplane/v1/signing.pb.go b/app/controlplane/api/controlplane/v1/signing.pb.go index 41e01c56b..fa5f43445 100644 --- a/app/controlplane/api/controlplane/v1/signing.pb.go +++ b/app/controlplane/api/controlplane/v1/signing.pb.go @@ -127,6 +127,7 @@ func (x *GenerateSigningCertResponse) GetChain() *CertificateChain { type CertificateChain struct { state protoimpl.MessageState `protogen:"open.v1"` + // // The PEM-encoded certificate chain, ordered from leaf to intermediate to root as applicable. Certificates []string `protobuf:"bytes,1,rep,name=certificates,proto3" json:"certificates,omitempty"` unknownFields protoimpl.UnknownFields diff --git a/app/controlplane/api/workflowcontract/v1/crafting_schema.pb.go b/app/controlplane/api/workflowcontract/v1/crafting_schema.pb.go index 4dfea60fb..d5e6b58ce 100644 --- a/app/controlplane/api/workflowcontract/v1/crafting_schema.pb.go +++ b/app/controlplane/api/workflowcontract/v1/crafting_schema.pb.go @@ -847,12 +847,11 @@ type PolicyAttachment struct { // optional arguments for policies. Multivalued arguments can be set through multiline strings or comma separated values. It will be // parsed and passed as an array value to the policy engine. // with: - // - // user: john - // users: john, sarah - // licenses: | - // AGPL-1.0 - // AGPL-3.0 + // user: john + // users: john, sarah + // licenses: | + // AGPL-1.0 + // AGPL-3.0 With map[string]string `protobuf:"bytes,5,rep,name=with,proto3" json:"with,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // List of requirements this policy contributes to satisfy Requirements []string `protobuf:"bytes,6,rep,name=requirements,proto3" json:"requirements,omitempty"` @@ -1052,10 +1051,9 @@ type Metadata struct { // Declares the structured output schema for policy violations. // When set, the policy engine validates that violations conform to the // corresponding proto message: - // - // VULNERABILITY -> attestation.v1.PolicyVulnerabilityFinding - // SAST -> attestation.v1.PolicySASTFinding - // LICENSE_VIOLATION -> attestation.v1.PolicyLicenseViolationFinding + // VULNERABILITY -> attestation.v1.PolicyVulnerabilityFinding + // SAST -> attestation.v1.PolicySASTFinding + // LICENSE_VIOLATION -> attestation.v1.PolicyLicenseViolationFinding FindingType *string `protobuf:"bytes,7,opt,name=finding_type,json=findingType,proto3,oneof" json:"finding_type,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache diff --git a/common.mk b/common.mk index a5df2d3ab..5eaf8b95c 100644 --- a/common.mk +++ b/common.mk @@ -7,8 +7,8 @@ init: init-api-tools go install github.com/vektra/mockery/v3@v3.5.0 # using binary release for atlas, since ent schema handler is not included # in the community version anymore https://github.com/ariga/atlas/issues/2388#issuecomment-1864287189 - # install golangci-lint with Go 1.25 support - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $$(go env GOPATH)/bin v2.4.0 + # install golangci-lint, keep in sync with .github/workflows/lint.yml + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $$(go env GOPATH)/bin v2.14.0 curl -sSf https://atlasgo.sh | ATLAS_VERSION=v1.3.2 sh -s -- -y # initialize API tooling diff --git a/go.mod b/go.mod index 850493c66..c3e00fe9f 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/chainloop-dev/chainloop -go 1.26.6 +go 1.27.1 require ( buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.12-20260825204119-511051f7f437.2 diff --git a/pkg/attestation/crafter/api/attestation/v1/crafting_state.pb.go b/pkg/attestation/crafter/api/attestation/v1/crafting_state.pb.go index b5a46a8ec..080106e74 100644 --- a/pkg/attestation/crafter/api/attestation/v1/crafting_state.pb.go +++ b/pkg/attestation/crafter/api/attestation/v1/crafting_state.pb.go @@ -2037,7 +2037,7 @@ func (x *Attestation_SigningOptions) GetSigningCa() string { type Attestation_Material_KeyVal struct { state protoimpl.MessageState `protogen:"open.v1"` - // NOT USED, kept for compatibility with servers that still perform server-side validation“ + // NOT USED, kept for compatibility with servers that still perform server-side validation`` // TODO: remove after some time // // Deprecated: Marked as deprecated in attestation/v1/crafting_state.proto. @@ -2102,7 +2102,7 @@ func (x *Attestation_Material_KeyVal) GetDigest() string { type Attestation_Material_ContainerImage struct { state protoimpl.MessageState `protogen:"open.v1"` - // NOT USED, kept for compatibility with servers that still perform server-side validation“ + // NOT USED, kept for compatibility with servers that still perform server-side validation`` // TODO: remove after some time // // Deprecated: Marked as deprecated in attestation/v1/crafting_state.proto. @@ -2222,7 +2222,7 @@ func (x *Attestation_Material_ContainerImage) GetHasLatestTag() *wrapperspb.Bool type Attestation_Material_Artifact struct { state protoimpl.MessageState `protogen:"open.v1"` - // NOT USED, kept for compatibility with servers that still perform server-side validation“ + // NOT USED, kept for compatibility with servers that still perform server-side validation`` // TODO: remove after some time // // Deprecated: Marked as deprecated in attestation/v1/crafting_state.proto.