Skip to content
This repository was archived by the owner on Jul 19, 2026. It is now read-only.

Commit 73f03d2

Browse files
authored
[codex] Harden ASB CI quality gates (#63)
* Harden ASB CI quality gates * fmt: normalize authn import ordering * Fix ASB buf breaking CI fetch
1 parent eedc721 commit 73f03d2

15 files changed

Lines changed: 137 additions & 23 deletions

File tree

.github/workflows/ci.yml

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
pull_request:
88

99
jobs:
10-
test:
10+
proto:
1111
runs-on: ubuntu-latest
1212
steps:
1313
- name: Checkout
@@ -16,9 +16,9 @@ jobs:
1616
fetch-depth: 0
1717

1818
- name: Setup Go
19-
uses: evalops/service-runtime/.github/actions/setup-go-service@ca09da8302203b96582332dbcababe9f2d906d10
19+
uses: evalops/service-runtime/.github/actions/setup-go-service@cac5638c2935870453cf669e803936a80e17ac7b
2020
with:
21-
go-version-file: go.mod
21+
go-version: "1.26.2"
2222
cache: true
2323

2424
- name: Setup Buf
@@ -32,7 +32,9 @@ jobs:
3232
go install connectrpc.com/connect/cmd/protoc-gen-connect-go@v1.19.1
3333
3434
- name: Format
35-
run: make fmt
35+
run: |
36+
make fmt
37+
git diff --exit-code
3638
3739
- name: Buf lint
3840
run: buf lint
@@ -41,7 +43,6 @@ jobs:
4143
if: github.event_name == 'pull_request'
4244
run: |
4345
if git show origin/main:buf.yaml >/dev/null 2>&1; then
44-
git fetch origin main:refs/remotes/origin/main
4546
buf breaking --against '.git#ref=refs/remotes/origin/main'
4647
else
4748
echo "Skipping: no buf.yaml on main yet"
@@ -50,8 +51,75 @@ jobs:
5051
- name: Verify Proto Sync
5152
run: make proto-check
5253

53-
- name: Vet
54-
run: go vet ./...
54+
test:
55+
runs-on: ubuntu-latest
56+
steps:
57+
- name: Checkout
58+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
59+
with:
60+
fetch-depth: 0
61+
62+
- name: Setup Go
63+
uses: evalops/service-runtime/.github/actions/setup-go-service@cac5638c2935870453cf669e803936a80e17ac7b
64+
with:
65+
go-version: "1.26.2"
66+
cache: true
67+
run-go-test: "true"
68+
go-test-race: "true"
69+
go-test-args: "./... -count=1"
70+
71+
- name: Build
72+
run: go build ./...
73+
74+
- name: Collect coverage
75+
id: coverage
76+
run: |
77+
go test ./... -coverprofile=coverage.out -covermode=atomic -count=1
78+
coverage="$(go tool cover -func=coverage.out | awk '/^total:/ {sub(/%/, "", $3); print $3}')"
79+
echo "value=${coverage}" >> "$GITHUB_OUTPUT"
80+
awk -v got="${coverage}" -v floor="40" 'BEGIN { if ((got + 0) < (floor + 0)) exit 1 }'
81+
82+
- name: Publish coverage summary
83+
run: |
84+
echo "Total coverage: ${{ steps.coverage.outputs.value }}%" >> "$GITHUB_STEP_SUMMARY"
85+
86+
- name: Upload coverage artifact
87+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
88+
with:
89+
name: coverage.out
90+
path: coverage.out
91+
92+
lint:
93+
runs-on: ubuntu-latest
94+
steps:
95+
- name: Checkout
96+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
97+
with:
98+
fetch-depth: 0
99+
100+
- name: Setup Go
101+
uses: evalops/service-runtime/.github/actions/setup-go-service@cac5638c2935870453cf669e803936a80e17ac7b
102+
with:
103+
go-version: "1.26.2"
104+
cache: true
105+
run-golangci-lint: "true"
106+
golangci-lint-args: "--timeout=5m ./..."
107+
108+
security:
109+
runs-on: ubuntu-latest
110+
steps:
111+
- name: Checkout
112+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
113+
with:
114+
fetch-depth: 0
115+
116+
- name: Setup Go
117+
uses: evalops/service-runtime/.github/actions/setup-go-service@cac5638c2935870453cf669e803936a80e17ac7b
118+
with:
119+
go-version: "1.26.2"
120+
cache: true
121+
run-gosec: "true"
122+
run-govulncheck: "true"
55123

56-
- name: Test
57-
run: make test
124+
- name: Verify module checksums
125+
run: go mod verify

.golangci.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
version: "2"
2+
3+
run:
4+
timeout: 5m
5+
6+
linters:
7+
enable:
8+
- errcheck
9+
- govet
10+
- ineffassign
11+
- staticcheck
12+
- unused
13+
- gosec
14+
15+
settings:
16+
errcheck:
17+
check-type-assertions: true

Makefile

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
1-
GO ?= go
1+
TOOLCHAIN ?= go1.26.2
2+
GO ?= env GOTOOLCHAIN=$(TOOLCHAIN) go
23

3-
.PHONY: fmt test vet lint install-hooks proto proto-check migrate run-api run-worker
4+
.PHONY: fmt test test-race vet lint security-scan coverage install-hooks proto proto-check migrate run-api run-worker
45

56
fmt:
67
$(GO) fmt ./...
78

89
test:
910
$(GO) test ./...
1011

12+
test-race:
13+
$(GO) test -race ./...
14+
1115
vet:
1216
$(GO) vet ./...
1317

14-
lint: vet
18+
lint:
19+
golangci-lint run ./...
20+
21+
security-scan:
22+
$(GO) mod verify
23+
gosec ./cmd/... ./internal/...
24+
env GOTOOLCHAIN=$(TOOLCHAIN) govulncheck ./...
25+
26+
coverage:
27+
$(GO) test ./... -coverprofile=coverage.out -covermode=atomic
1528

1629
proto:
1730
bash scripts/sync-proto.sh

cmd/asb-worker/main.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,9 @@ func main() {
6262
mux := http.NewServeMux()
6363
mux.Handle("/metrics", promhttp.Handler())
6464
metricsServer = &http.Server{
65-
Addr: metricsAddr,
66-
Handler: mux,
65+
Addr: metricsAddr,
66+
Handler: mux,
67+
ReadHeaderTimeout: 5 * time.Second,
6768
}
6869
go func() {
6970
if err := metricsServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {

internal/api/connectapi/server_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ func TestServer_CreateSessionAcceptsOIDCAttestationKind(t *testing.T) {
161161
t.Fatalf("unexpected attestation = %#v", req.Attestation)
162162
}
163163
return &core.CreateSessionResponse{
164-
SessionID: "sess_oidc",
164+
SessionID: "sess_oidc",
165+
// #nosec G101 -- Synthetic session token fixture for transport tests.
165166
SessionToken: "eyJ.oidc",
166167
ExpiresAt: time.Date(2026, 4, 15, 6, 0, 0, 0, time.UTC),
167168
}, nil

internal/authn/delegationjwt/validator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import (
66
"fmt"
77
"time"
88

9-
"github.com/golang-jwt/jwt/v5"
109
"github.com/evalops/asb/internal/core"
10+
"github.com/golang-jwt/jwt/v5"
1111
)
1212

1313
type Config struct {

internal/authn/delegationjwt/validator_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import (
66
"testing"
77
"time"
88

9-
"github.com/golang-jwt/jwt/v5"
109
"github.com/evalops/asb/internal/authn/delegationjwt"
1110
"github.com/evalops/asb/internal/core"
11+
"github.com/golang-jwt/jwt/v5"
1212
)
1313

1414
func TestValidator_ValidateSignedDelegation(t *testing.T) {

internal/authn/k8s/verifier.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import (
55
"fmt"
66
"strings"
77

8-
"github.com/golang-jwt/jwt/v5"
98
"github.com/evalops/asb/internal/core"
9+
"github.com/golang-jwt/jwt/v5"
1010
)
1111

1212
type Keyfunc func(ctx context.Context, token *jwt.Token) (any, error)

internal/authn/k8s/verifier_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import (
66
"testing"
77
"time"
88

9-
"github.com/golang-jwt/jwt/v5"
109
"github.com/evalops/asb/internal/authn/k8s"
1110
"github.com/evalops/asb/internal/core"
11+
"github.com/golang-jwt/jwt/v5"
1212
)
1313

1414
func TestVerifier_VerifyProjectedServiceAccountToken(t *testing.T) {

internal/bootstrap/service.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ func redisPoolStats(client *goredis.Client) func() *goredis.PoolStats {
615615
}
616616

617617
func loadPublicKey(path string) (any, error) {
618+
// #nosec G304,G703 -- Public-key paths come from explicit operator configuration.
618619
contents, err := os.ReadFile(path)
619620
if err != nil {
620621
return nil, err
@@ -647,6 +648,7 @@ func loadEd25519PublicKey(path string) (ed25519.PublicKey, error) {
647648
}
648649

649650
func loadEd25519PrivateKey(path string) (ed25519.PrivateKey, error) {
651+
// #nosec G304,G703 -- Private-key paths come from explicit operator configuration.
650652
contents, err := os.ReadFile(path)
651653
if err != nil {
652654
return nil, err
@@ -667,6 +669,7 @@ func loadEd25519PrivateKey(path string) (ed25519.PrivateKey, error) {
667669
}
668670

669671
func loadRSAPrivateKey(path string) (*rsa.PrivateKey, error) {
672+
// #nosec G304,G703 -- Private-key paths come from explicit operator configuration.
670673
contents, err := os.ReadFile(path)
671674
if err != nil {
672675
return nil, err

0 commit comments

Comments
 (0)