Skip to content

Commit 6598401

Browse files
committed
Merge branch 'main' into confhttp3
2 parents 198e96f + 3b2bf34 commit 6598401

101 files changed

Lines changed: 367 additions & 182 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ rm-builders:
3333

3434
.PHONY: generate
3535
generate: mockery install-protoc gomods cre-protoc modgraph
36-
export PATH="$(HOME)/.local/bin:$(PATH)"; gomods -s proto_vendor -go generate -x ./...
36+
export PATH="$(HOME)/.local/bin:$(HOME)/go/bin:$(PATH)"; gomods -s proto_vendor -go generate -x ./...
3737
find . -type f -name .mockery.yaml -execdir mockery \; ## Execute mockery for all .mockery.yaml files. If this fails, you might have a local mockery installed. Uninstall or update it.
3838

3939
.PHONY: cre-protoc

go.mod

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,18 @@ require (
3737
github.com/scylladb/go-reflectx v1.0.1
3838
github.com/shopspring/decimal v1.4.0
3939
github.com/smartcontractkit/chain-selectors v1.0.67
40-
github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.6
41-
github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20250722225531-876fd6b94976
40+
github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.9-0.20251020164035-ab562b473fe2
41+
github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251020004840-4638e4262066
4242
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20251021010742-3f8d3dba17d8
4343
github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b
4444
github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0
45-
github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20250822025801-598d3d86f873
45+
github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20251020004840-4638e4262066
4646
github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e
4747
github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7
4848
github.com/smartcontractkit/libocr v0.0.0-20250912173940-f3ab0246e23d
49-
github.com/stretchr/testify v1.10.0
50-
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0
51-
go.opentelemetry.io/otel v1.37.0
49+
github.com/stretchr/testify v1.11.1
50+
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0
51+
go.opentelemetry.io/otel v1.38.0
5252
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2
5353
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2
5454
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.36.0
@@ -59,21 +59,21 @@ require (
5959
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0
6060
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0
6161
go.opentelemetry.io/otel/log v0.13.0
62-
go.opentelemetry.io/otel/metric v1.37.0
63-
go.opentelemetry.io/otel/sdk v1.37.0
62+
go.opentelemetry.io/otel/metric v1.38.0
63+
go.opentelemetry.io/otel/sdk v1.38.0
6464
go.opentelemetry.io/otel/sdk/log v0.13.0
65-
go.opentelemetry.io/otel/sdk/metric v1.37.0
66-
go.opentelemetry.io/otel/trace v1.37.0
65+
go.opentelemetry.io/otel/sdk/metric v1.38.0
66+
go.opentelemetry.io/otel/trace v1.38.0
6767
go.uber.org/zap v1.27.0
68-
golang.org/x/crypto v0.40.0
68+
golang.org/x/crypto v0.41.0
6969
golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc
7070
golang.org/x/sync v0.16.0
7171
golang.org/x/time v0.12.0
7272
golang.org/x/tools v0.35.0
7373
gonum.org/v1/gonum v0.16.0
74-
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822
75-
google.golang.org/grpc v1.74.2
76-
google.golang.org/protobuf v1.36.7
74+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5
75+
google.golang.org/grpc v1.75.0
76+
google.golang.org/protobuf v1.36.8
7777
gopkg.in/yaml.v3 v3.0.1
7878
sigs.k8s.io/yaml v1.4.0
7979
)
@@ -148,11 +148,11 @@ require (
148148
go.opentelemetry.io/proto/otlp v1.6.0 // indirect
149149
go.uber.org/multierr v1.11.0 // indirect
150150
golang.org/x/mod v0.26.0 // indirect
151-
golang.org/x/net v0.42.0 // indirect
152-
golang.org/x/sys v0.34.0 // indirect
153-
golang.org/x/term v0.33.0 // indirect
154-
golang.org/x/text v0.27.0 // indirect
151+
golang.org/x/net v0.43.0 // indirect
152+
golang.org/x/sys v0.35.0 // indirect
153+
golang.org/x/term v0.34.0 // indirect
154+
golang.org/x/text v0.28.0 // indirect
155155
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
156-
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a // indirect
156+
google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
157157
gopkg.in/yaml.v2 v2.4.0 // indirect
158158
)

go.sum

Lines changed: 38 additions & 38 deletions
Large diffs are not rendered by default.

observability-lib/grafana/builder_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,37 @@ func TestBuilder_AddVars(t *testing.T) {
154154
}
155155
require.Len(t, o.Dashboard.Templating.List, 1)
156156
})
157+
158+
t.Run("AddVars adds variables with AllValue to the dashboard", func(t *testing.T) {
159+
builder := grafana.NewBuilder(&grafana.BuilderOptions{
160+
Name: "Dashboard Name",
161+
})
162+
163+
variable := grafana.NewQueryVariable(&grafana.QueryVariableOptions{
164+
VariableOption: &grafana.VariableOption{
165+
Name: "Variable Name",
166+
Label: "Variable Label",
167+
},
168+
Query: "query",
169+
Datasource: grafana.NewDataSource("Prometheus", "").Name,
170+
IncludeAll: true,
171+
AllValue: ".*",
172+
})
173+
174+
builder.AddVars(variable)
175+
o, err := builder.Build()
176+
if err != nil {
177+
t.Errorf("Error building dashboard: %v", err)
178+
}
179+
require.Len(t, o.Dashboard.Templating.List, 1)
180+
181+
// Verify the AllValue is set correctly
182+
varModel := o.Dashboard.Templating.List[0]
183+
require.NotNil(t, varModel.AllValue)
184+
require.Equal(t, ".*", *varModel.AllValue)
185+
require.NotNil(t, varModel.IncludeAll)
186+
require.True(t, *varModel.IncludeAll)
187+
})
157188
}
158189

159190
func TestBuilder_AddRow(t *testing.T) {

observability-lib/grafana/variables.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ type QueryVariableOptions struct {
8787
Sort dashboard.VariableSort
8888
Refresh *dashboard.VariableRefresh
8989
IncludeAll bool
90+
AllValue string
9091
QueryWithType map[string]any
9192
}
9293

@@ -112,7 +113,8 @@ func NewQueryVariable(options *QueryVariableOptions) *dashboard.QueryVariableBui
112113
Sort(options.Sort).
113114
Refresh(*options.Refresh).
114115
Multi(options.Multi).
115-
IncludeAll(options.IncludeAll)
116+
IncludeAll(options.IncludeAll).
117+
AllValue(options.AllValue)
116118

117119
if options.Query != "" {
118120
variable.Query(dashboard.StringOrMap{String: cog.ToPtr[string](options.Query)})

pkg/beholder/auth.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ type Auth interface {
3838
}
3939

4040
type Signer interface {
41-
Sign(ctx context.Context, keyID []byte, data []byte) ([]byte, error)
41+
Sign(ctx context.Context, keyID string, data []byte) ([]byte, error)
4242
}
4343

4444
type staticAuth struct {
@@ -82,7 +82,10 @@ type rotatingAuth struct {
8282
mu sync.Mutex
8383
}
8484

85-
func NewRotatingAuth(csaPubKey ed25519.PublicKey, signer Signer, ttl time.Duration, requireTransportSecurity bool) Auth {
85+
// NewRotatingAuth creates a rotating auth mechanism that automatically refreshes headers.
86+
// If initialHeaders are provided, they will be used immediately until TTL expires.
87+
// After TTL expiration, the signer is called to generate new headers.
88+
func NewRotatingAuth(csaPubKey ed25519.PublicKey, signer Signer, ttl time.Duration, requireTransportSecurity bool, initialHeaders map[string]string) Auth {
8689
r := &rotatingAuth{
8790
csaPubKey: csaPubKey,
8891
signer: signer,
@@ -91,7 +94,18 @@ func NewRotatingAuth(csaPubKey ed25519.PublicKey, signer Signer, ttl time.Durati
9194
lastUpdatedNanos: atomic.Int64{},
9295
requireTransportSecurity: requireTransportSecurity,
9396
}
94-
r.headers.Store(make(map[string]string))
97+
98+
headers := make(map[string]string)
99+
// If initial headers are provided, use them and set timestamp to now
100+
// Otherwise, leave timestamp at 0 so headers are generated on first call
101+
if len(initialHeaders) > 0 {
102+
headers = initialHeaders
103+
// We assume the time between the initial headers being generated is very small
104+
r.lastUpdatedNanos.Store(time.Now().UnixNano())
105+
}
106+
107+
r.headers.Store(headers)
108+
95109
return r
96110
}
97111

@@ -125,7 +139,7 @@ func (r *rotatingAuth) Headers(ctx context.Context) (map[string]string, error) {
125139
defer cancel()
126140

127141
// Sign(public key bytes + timestamp bytes)
128-
signature, err := r.signer.Sign(ctxWithTimeout, r.csaPubKey, msgBytes)
142+
signature, err := r.signer.Sign(ctxWithTimeout, fmt.Sprintf("%x", r.csaPubKey), msgBytes)
129143
if err != nil {
130144
return nil, fmt.Errorf("beholder: failed to sign auth header: %w", err)
131145
}

pkg/beholder/auth_test.go

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"crypto/ed25519"
66
"encoding/hex"
7+
"fmt"
78
"strings"
89
"testing"
910
"time"
@@ -54,7 +55,7 @@ type MockSigner struct {
5455
mock.Mock
5556
}
5657

57-
func (m *MockSigner) Sign(ctx context.Context, keyID []byte, data []byte) ([]byte, error) {
58+
func (m *MockSigner) Sign(ctx context.Context, keyID string, data []byte) ([]byte, error) {
5859
args := m.Called(ctx, keyID, data)
5960
return args.Get(0).([]byte), args.Error(1)
6061
}
@@ -71,13 +72,13 @@ func TestRotatingAuth(t *testing.T) {
7172
dummySignature := ed25519.Sign(privKey, []byte("test data"))
7273

7374
mockSigner.
74-
On("Sign", mock.Anything, mock.MatchedBy(func(keyID []byte) bool {
75-
return string(keyID) == string(pubKey) // Verify correct public key is passed
75+
On("Sign", mock.Anything, mock.MatchedBy(func(keyID string) bool {
76+
return keyID == hex.EncodeToString(pubKey) // Verify correct public key hex is passed
7677
}), mock.Anything).
7778
Return(dummySignature, nil)
7879

7980
ttl := 5 * time.Minute
80-
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false)
81+
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false, nil)
8182

8283
headers, err := auth.Headers(t.Context())
8384
require.NoError(t, err)
@@ -112,7 +113,7 @@ func TestRotatingAuth(t *testing.T) {
112113
Maybe()
113114

114115
ttl := 5 * time.Minute
115-
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false)
116+
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false, nil)
116117

117118
headers1, err := auth.Headers(t.Context())
118119
require.NoError(t, err)
@@ -135,7 +136,7 @@ func TestRotatingAuth(t *testing.T) {
135136
Return([]byte{}, expectedErr)
136137

137138
ttl := 5 * time.Minute
138-
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false)
139+
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false, nil)
139140

140141
headers, err := auth.Headers(t.Context())
141142
require.Error(t, err)
@@ -157,7 +158,7 @@ func TestRotatingAuth(t *testing.T) {
157158
Maybe()
158159

159160
ttl := 5 * time.Minute
160-
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false)
161+
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false, nil)
161162

162163
creds := auth.Credentials()
163164
require.NotNil(t, creds)
@@ -183,16 +184,52 @@ func TestRotatingAuth(t *testing.T) {
183184

184185
ttl := 5 * time.Minute
185186
// transport security required
186-
authSecure := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, true)
187+
authSecure := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, true, nil)
187188
credsSecure := authSecure.Credentials()
188189
assert.True(t, credsSecure.RequireTransportSecurity())
189190
// transport security not required
190-
authInsecure := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false)
191+
authInsecure := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false, nil)
191192
credsInsecure := authInsecure.Credentials()
192193
assert.False(t, credsInsecure.RequireTransportSecurity())
193194

194195
mockSigner.AssertExpectations(t)
195196
})
197+
198+
t.Run("uses initial headers until TTL expires", func(t *testing.T) {
199+
mockSigner := &MockSigner{}
200+
201+
// Create initial headers with v2 format
202+
ts := time.Now()
203+
signature := ed25519.Sign(privKey, []byte("initial"))
204+
initialHeaders := map[string]string{
205+
"X-Beholder-Node-Auth-Token": "2:" + hex.EncodeToString(pubKey) + ":" + fmt.Sprintf("%d", ts.UnixNano()) + ":" + hex.EncodeToString(signature),
206+
}
207+
208+
// Use a very short TTL so it expires quickly
209+
ttl := 1 * time.Millisecond
210+
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false, initialHeaders)
211+
212+
// First call should return the initial headers without calling Sign
213+
headers1, err := auth.Headers(t.Context())
214+
require.NoError(t, err)
215+
assert.Equal(t, initialHeaders, headers1)
216+
217+
// Wait for TTL to expire
218+
time.Sleep(5 * time.Millisecond)
219+
220+
// Now the signer should be called to generate new headers
221+
newSignature := ed25519.Sign(privKey, []byte("new"))
222+
mockSigner.
223+
On("Sign", mock.Anything, mock.Anything, mock.Anything).
224+
Return(newSignature, nil).
225+
Once()
226+
227+
headers2, err := auth.Headers(t.Context())
228+
require.NoError(t, err)
229+
assert.NotEqual(t, initialHeaders, headers2, "Should generate new headers after TTL expires")
230+
231+
mockSigner.AssertExpectations(t)
232+
})
196233
}
197234

198235
// BenchmarkRotatingAuth_Headers_CachedPath benchmarks the fast path where headers are cached and within TTL.
@@ -212,7 +249,7 @@ func BenchmarkRotatingAuth_Headers_CachedPath(b *testing.B) {
212249

213250
// Use a long TTL so headers don't expire during the benchmark
214251
ttl := 1 * time.Hour
215-
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false)
252+
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false, nil)
216253

217254
// Prime the cache by calling Headers once
218255
ctx := b.Context()
@@ -249,7 +286,7 @@ func BenchmarkRotatingAuth_Headers_ExpiredPath(b *testing.B) {
249286

250287
// Use a TTL of 0 to force regeneration on every call
251288
ttl := 0 * time.Second
252-
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false)
289+
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false, nil)
253290

254291
ctx := b.Context()
255292

@@ -283,7 +320,7 @@ func BenchmarkRotatingAuth_Headers_ParallelCached(b *testing.B) {
283320

284321
// Use a long TTL so headers don't expire during the benchmark
285322
ttl := 1 * time.Hour
286-
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false)
323+
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false, nil)
287324

288325
// Prime the cache
289326
ctx := b.Context()
@@ -323,7 +360,7 @@ func BenchmarkRotatingAuth_Headers_ParallelExpired(b *testing.B) {
323360

324361
// Use a short TTL to cause periodic regeneration
325362
ttl := 10 * time.Millisecond
326-
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false)
363+
auth := beholder.NewRotatingAuth(pubKey, mockSigner, ttl, false, nil)
327364

328365
ctx := b.Context()
329366

0 commit comments

Comments
 (0)