Skip to content

Commit cc00105

Browse files
devin-ai-integration[bot]Joe Petrich
andcommitted
[ENG-xxx] Migrate KMS signer tests and set up CI
Co-Authored-By: Joe Petrich <[email protected]>
1 parent e85d7c0 commit cc00105

File tree

5 files changed

+440
-0
lines changed

5 files changed

+440
-0
lines changed

.github/workflows/ci.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: Go
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
pull_request:
7+
branches: ["main"]
8+
9+
permissions:
10+
id-token: write
11+
contents: read
12+
13+
jobs:
14+
test:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v3
19+
with:
20+
ref: ${{ github.head_ref }}
21+
fetch-depth: 0
22+
23+
- name: Authenticate to Google Cloud
24+
uses: google-github-actions/auth@v1
25+
with:
26+
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
27+
service_account: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }}
28+
29+
- name: Set up gcloud (for KMS client lib to auth)
30+
uses: google-github-actions/setup-gcloud@v1
31+
with:
32+
project_id: courtyard-frontend
33+
34+
- name: Set up Go
35+
uses: actions/setup-go@v3
36+
with:
37+
go-version: 1.24.1
38+
39+
- name: Lint Go files
40+
run: |
41+
find . -name '*.go' | xargs gofmt -d -s -w
42+
if ! git diff-index --quiet HEAD --; then
43+
echo "Code style issues found. Please run 'go fmt ./...' locally and commit changes."
44+
exit 1
45+
fi
46+
47+
- name: Build
48+
run: go build -v ./...
49+
50+
- name: Run unit tests
51+
run: go test -v -timeout 120s ./... -short
52+
53+
- name: Run integration tests
54+
env:
55+
GOOGLE_CLOUD_PROJECT: courtyard-frontend
56+
TEST_KMS_KEY_NAME: ${{ secrets.KMS_KEY_NAME }}
57+
run: go test -v -timeout 300s ./... -run "TestKMSSigner(Integration|Retry)"

go.mod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
cloud.google.com/go/kms v1.21.1
77
github.com/cenkalti/backoff/v4 v4.3.0
88
github.com/ethereum/go-ethereum v1.15.7
9+
github.com/stretchr/testify v1.10.0
910
)
1011

1112
require (
@@ -22,6 +23,7 @@ require (
2223
github.com/consensys/gnark-crypto v0.14.0 // indirect
2324
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect
2425
github.com/crate-crypto/go-kzg-4844 v1.1.0 // indirect
26+
github.com/davecgh/go-spew v1.1.1 // indirect
2527
github.com/deckarep/golang-set/v2 v2.6.0 // indirect
2628
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
2729
github.com/ethereum/c-kzg-4844 v1.0.0 // indirect
@@ -38,6 +40,7 @@ require (
3840
github.com/gorilla/websocket v1.4.2 // indirect
3941
github.com/holiman/uint256 v1.3.2 // indirect
4042
github.com/mmcloughlin/addchain v0.4.0 // indirect
43+
github.com/pmezard/go-difflib v1.0.0 // indirect
4144
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
4245
github.com/supranational/blst v0.3.14 // indirect
4346
github.com/tklauser/go-sysconf v0.3.12 // indirect
@@ -61,5 +64,6 @@ require (
6164
google.golang.org/genproto/googleapis/rpc v0.0.0-20250227231956-55c901821b1e // indirect
6265
google.golang.org/grpc v1.71.0 // indirect
6366
google.golang.org/protobuf v1.36.5 // indirect
67+
gopkg.in/yaml.v3 v3.0.1 // indirect
6468
rsc.io/tmplfunc v0.0.3 // indirect
6569
)

go.sum

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,9 @@ google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
261261
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
262262
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
263263
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
264+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
265+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
266+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
264267
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
265268
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
266269
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=

kms_signer_integration_test.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package signer
2+
3+
import (
4+
"context"
5+
"os"
6+
"sync"
7+
"testing"
8+
9+
"github.com/ethereum/go-ethereum/crypto"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
type TestKeyConfig struct {
15+
KeyName string
16+
}
17+
18+
func getTestKeyConfig(t *testing.T) TestKeyConfig {
19+
keyName := os.Getenv("TEST_KMS_KEY_NAME")
20+
if keyName == "" {
21+
t.Skip("TEST_KMS_KEY_NAME not set, skipping integration test")
22+
}
23+
24+
return TestKeyConfig{
25+
KeyName: keyName,
26+
}
27+
}
28+
29+
func TestKMSSignerIntegration(t *testing.T) {
30+
if testing.Short() {
31+
t.Skip("Skipping integration test in short mode")
32+
}
33+
34+
config := getTestKeyConfig(t)
35+
ctx := context.Background()
36+
37+
signer, err := NewKMSSigner(ctx, KMSSignerConfig{
38+
KeyName: config.KeyName,
39+
})
40+
require.NoError(t, err)
41+
defer signer.Close()
42+
43+
tests := []struct {
44+
name string
45+
message []byte
46+
}{
47+
{
48+
name: "Simple message",
49+
message: []byte("Hello, world!"),
50+
},
51+
{
52+
name: "Empty message",
53+
message: []byte{},
54+
},
55+
{
56+
name: "Long message",
57+
message: []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."),
58+
},
59+
}
60+
61+
for _, tt := range tests {
62+
t.Run(tt.name, func(t *testing.T) {
63+
hash := crypto.Keccak256(tt.message)
64+
signature, err := signer.Sign(ctx, hash)
65+
require.NoError(t, err)
66+
67+
assert.Equal(t, 65, len(signature))
68+
69+
assert.True(t, signature[64] >= 27, "v value should be >= 27")
70+
sigCopy := make([]byte, len(signature))
71+
copy(sigCopy, signature)
72+
sigCopy[64] -= 27
73+
74+
_, err = crypto.Ecrecover(hash, sigCopy)
75+
assert.NoError(t, err, "should be able to recover public key from signature")
76+
})
77+
}
78+
}
79+
80+
func TestKMSSignerIntegrationRetry(t *testing.T) {
81+
if testing.Short() {
82+
t.Skip("Skipping integration test in short mode")
83+
}
84+
85+
config := getTestKeyConfig(t)
86+
ctx := context.Background()
87+
88+
signer, err := NewKMSSigner(ctx, KMSSignerConfig{
89+
KeyName: config.KeyName,
90+
})
91+
require.NoError(t, err)
92+
defer signer.Close()
93+
94+
message := []byte("Test message for concurrent signing")
95+
hash := crypto.Keccak256(message)
96+
var wg sync.WaitGroup
97+
numConcurrent := 5
98+
results := make(chan error, numConcurrent)
99+
100+
for i := 0; i < numConcurrent; i++ {
101+
wg.Add(1)
102+
go func() {
103+
defer wg.Done()
104+
_, err := signer.Sign(ctx, hash)
105+
results <- err
106+
}()
107+
}
108+
109+
wg.Wait()
110+
close(results)
111+
112+
for err := range results {
113+
assert.NoError(t, err, "concurrent signing operation should succeed")
114+
}
115+
}

0 commit comments

Comments
 (0)