refactor(beholder): extract newRotatingAuthFromConfig helper and add NewChipIngressHeaderProvider#2096
Conversation
…NewChipIngressHeaderProvider - Extract rotating auth setup logic from NewGRPCClient into newRotatingAuthFromConfig helper in auth.go - Add NewChipIngressHeaderProvider in chipingress_auth.go for external consumers needing a chipingress.HeaderProvider from beholder config - Add exhaustive test coverage for all auth paths (static, rotating, error cases, boundary conditions)
📊 API Diff Results
|
|
|
||
| // newRotatingAuthFromConfig validates config and returns a rotating Auth and its lazySigner. | ||
| // Returns (nil, nil, nil) if AuthHeadersTTL == 0 (no rotating auth configured). | ||
| func newRotatingAuthFromConfig(cfg Config) (Auth, *lazySigner, error) { |
There was a problem hiding this comment.
is there a better name that RotatingAuth? if not, can we have a comment about what type of downstream consumers need this?
| // NewChipIngressHeaderProvider creates a new chipingress.HeaderProvider | ||
| // using the same auth logic as NewGRPCClient. | ||
| // Returns nil provider (no error) if no auth is configured. | ||
| func NewChipIngressHeaderProvider(cfg Config) (chipingress.HeaderProvider, error) { |
There was a problem hiding this comment.
can this be extracted out of pkg/beholder into a chip specific pkg?
There was a problem hiding this comment.
Yes, I was thinking that’d be the next refactoring step, but we could probably just do it in one shot.
…ngress Move the header-provider construction logic out of pkg/beholder and into pkg/chipingress so the chipingress module owns its auth surface. - Add chipingress.NewHeaderProvider plus HeaderProviderConfig, Signer, and TransportSecurityRequirer, along with internal static/rotating providers and the V2 auth-header helper. The X-Beholder-Node-Auth-Token header name and wire format are preserved verbatim. - Port the 18 existing test cases to pkg/chipingress, using a local fake signer and TransportSecurityRequirer type assertions. - Delete pkg/beholder/chipingress_auth.go and its test (the function was new in this PR; no external callers exist). - Rename beholder's internal newRotatingAuthFromConfig to buildRotatingAuth and update its single call site in client.go.
✅ API Diff Results -
|
Trim the chipingress header-provider API to the minimum needed by callers that want to build an auth provider from the same config beholder uses. - Unexport newStaticHeaderProvider and newRotatingHeaderProvider; the config-driven NewHeaderProvider is the sole entry point. - Delete the TransportSecurityRequirer interface; tests use a local inline interface for the RequireTransportSecurity() type assertion. - Document the parity contract on NewHeaderProvider, mapping each beholder.Config field to its HeaderProviderConfig counterpart so the two code paths stay in lockstep. Note: ChipIngressInsecureConnection on beholder.Config maps to InsecureConnection here (the chipingress package has no need for a redundant prefix on its own type names). Public surface is now exactly: Signer, HeaderProviderConfig, NewHeaderProvider. A defensive parity test against beholder's internal wiring will land in a follow-up PR after the chipingress module version is bumped in chainlink-common's root go.mod.
| return s.headers, nil | ||
| } | ||
|
|
||
| func (s *staticHeaderProvider) RequireTransportSecurity() bool { |
There was a problem hiding this comment.
/nit for methods that return a bool, prefer to prefix with Is..., i.e. IsTLSRequired
There was a problem hiding this comment.
The intention of this PR is to extract auth, keep the surface area minimal, and keep it as close as possible to pkg/beholder.
| // preserved verbatim from the original beholder-side implementation to keep | ||
| // the wire protocol unchanged. | ||
| const ( | ||
| authHeaderKey = "X-Beholder-Node-Auth-Token" |
There was a problem hiding this comment.
/nit should this be named to something with beholder in it? the default for grpc authorization is authorization, so perhaps the difference in default behavior protects the naming as is.
There was a problem hiding this comment.
grpc authorization is authorization
Yes, the Authorization header is the standard header for auth tokens in HTTP/gRPC requests.
We have tickets in place to support this. Most of the work has been completed, and only a few items remain to fully wire it up.
There was a problem hiding this comment.
should this be named to something with beholder in it
we were going to replace it withauthorizationheader at some point
|
|
||
| // Double-check after acquiring the lock in case another goroutine | ||
| // already refreshed. | ||
| lastUpdated = time.Unix(0, r.lastUpdatedNanos.Load()) |
There was a problem hiding this comment.
/nit can leave for a follow up, but technically we could just acquire the lock and only make the top level if time.Since(lastUpdated) > r.ttl { check as its duplicated on line 178 to check under the lock
There was a problem hiding this comment.
The intention is to keep 1:1 parity with existing implementation in pkg/beholder
CRE-4422
Summary
Introduces
pkg/chipingress.NewHeaderProvider, a self-contained constructor forthe ChIP Ingress auth header provider. Lets non-beholder callers (e.g. the
DurableEmitter wiring in smartcontractkit/chainlink#22648) construct auth without
importing
pkg/beholder.Motivation
pkg/chipingressis a separate Go module and cannot depend onpkg/beholder.Today,
core/services/chainlink/application.go(in smartcontractkit/chainlink#22648)reaches into
beholder.NewStaticAuthsolely to obtain achipingress.HeaderProvider, and only the static-auth case is wired — rotatingauth is silently unsupported on the DurableEmitter path.
Changes
pkg/chipingress/header_provider.goSignerinterface (duck-typed; satisfied bybeholder.Signer,lazySigner,keystore.CSASigner).HeaderProviderConfigwith fields:AuthHeaders,AuthHeadersTTL,AuthPublicKeyHex,AuthKeySigner,InsecureConnection.NewHeaderProvider— uniformly returns nil / static / rotating providerbased on config, mirroring
pkg/beholder/client.go:200-212selection logic.pkg/beholder/auth.go: rename internal helpernewRotatingAuthFromConfig->buildRotatingAuth(single call site updated).pkg/beholder/chipingress_auth.go(+ its test) — replaced by thenew package-local implementation.
Parity Contract
The new chipingress provider preserves wire-protocol parity with beholder:
X-Beholder-Node-Auth-Token"auth: public key hex required for rotating auth (TTL > 0)","auth: headers TTL must be at least 10 minutes","auth: failed to decode public key hex"Documented as a doc comment on
NewHeaderProvider. A cross-package parity testis deferred to a follow-up PR — the chipingress module version must be bumped in
the chainlink-common root
go.modfirst sopkg/beholdercan import the newsymbols.
Public Surface
Exactly three exports from the new file:
Signer,HeaderProviderConfig,NewHeaderProvider. Static/rotating provider types are unexported.Testing
pkg/chipingress— 18 test cases covering static, rotating, nil, transportsecurity, and validation error paths.
pkg/beholder/...— existing suite passes; helper rename is internal.Consumer
smartcontractkit/chainlink#22648 (DurableEmitter Core Integration) will adopt
this in
core/services/chainlink/application.go, collapsing the inline authbranch into a single
chipingress.NewHeaderProvider(...)call.Follow-ups (separate PRs)
pkg/chipingressversion in chainlink-common rootgo.mod.pkg/beholder/chipingress_auth_parity_test.go(table-driven, 8 cases)plus
pkg/beholder/export_test.goexposingBuildRotatingAuth.