Add CP outbound auth - #38
Conversation
1af2a3e to
2d1fe1a
Compare
|
/agentic_review |
Code Review by Qodo
1.
|
|
@chadcrum PTAL on this one too for authenticating to the CP from the agent |
2d1fe1a to
705df0d
Compare
PR Summary by QodoAdd outbound control-plane authentication and resilient re-registration
AI Description
Diagram
High-Level Assessment
Files changed (15)
|
|
Code review by qodo was updated up to the latest commit 705df0d |
de0e721 to
4744890
Compare
chadcrum
left a comment
There was a problem hiding this comment.
lgtm - only feed back I have is:
The token endpoint currently allows http:// and sends the client secret over that connection, which could expose the credential to network observers.
Could we address this with a clear warning in the docs and an application warning when HTTP is configured? Longer term, we could add an explicit opt-in for insecure HTTP and make HTTPS the default.
…ns, decisions) Doc-first changes for the 5 agreed PR dcm-project#38 review fixes, landed before their corresponding test/code changes per this repo's DOC -> RED -> GREEN -> REFACTOR discipline: - DD-520 (decisions.md): trim to decision-only form, dropping bot name, PR/round references, and rejected-alternative narration. - TC-DCM-UT-AUTH-040 (unit-tests.md): correct the Given/When/Then to describe the actual near-expiry refresh path via a widened safety buffer, replacing the old sleep-past-full-expiry description. - TC-MAIN-UT-AUTH-010..040 (unit-tests.md) + IT-DCM-AUTH-030b (integration-tests.md): add real unit coverage for buildTokenSource's auth-mode precedence (AC-DCM-230), and re-point the integration test that incorrectly claimed AC-DCM-230 at the AC-DCM-210 coverage it actually provides. - TC-DCM-UT-AUTH-090 (unit-tests.md): document surfacing the OAuth2 error/error_description body on token fetch failure (AC-DCM-225). - REQ-DCM-260/AC-DCM-260 (spec.md) + TC-CFG-UT-AUTH-090 (unit-tests.md) + README: new plaintext-HTTP token endpoint warning, and update the README example/caution note accordingly. Assisted by: Claude Code - sonnet-4.5 Signed-off-by: gabriel-farache <gfarache@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…ndling Implements the code/test side of the 5 agreed PR dcm-project#38 review fixes, each already backed by its own DOC-phase commit: - dcm: replace token_test.go's 2s time.Sleep with a deterministic SetExpiryDelta(2*time.Hour) call (export_test.go) to exercise the proactive near-expiry refresh path (TC-DCM-UT-AUTH-040) without wall-clock waiting. - main: add real unit coverage for buildTokenSource's precedence (client-credentials over static token, TC-MAIN-UT-AUTH-010..040), and rename the integration test that incorrectly claimed to prove this (AC-DCM-230) to describe what it actually exercises (IT-DCM-AUTH-030b). - dcm: surface OAuth2 error/error_description from a non-200 token endpoint response instead of a generic HTTP-status-only error, falling back to the generic message when the body isn't valid OAuth2 error JSON (TC-DCM-UT-AUTH-090). - config/main: add DCMConfig.UsesInsecureAuthEndpoint() and log a one-time startup warning when client-credentials mode is configured with a plaintext-HTTP token endpoint (REQ-DCM-260, TC-CFG-UT-AUTH-090). Assisted by: Claude Code - sonnet-4.5 Signed-off-by: gabriel-farache <gfarache@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
4744890 to
f5de298
Compare
@chadcrum I added a warning in the README d7d8005 and in main.go when reading the endpoint value f5de298 |
jordigilh
left a comment
There was a problem hiding this comment.
Second review summary
Substantive findings are posted inline below. The PR is currently dirty/conflicting against main, and the existing approval is not sufficient for the current head.
Verdict: Not GA-ready
The default HTTP client used to fetch OAuth2 client-credentials tokens followed redirects, so a 307/308 response from DCM_AUTH_TOKEN_ENDPOINT could cause the client_id/client_secret form body to be resent to a different origin. The internally-constructed default client (used whenever NewClientCredentialsTokenSource is called with a nil httpClient — the only call site today) now sets CheckRedirect to unconditionally refuse any redirect with an explicit error, which flows through the existing token-request error wrapping. A caller-supplied httpClient is unaffected and remains the caller's own responsibility. Adds TC-DCM-UT-AUTH-100, asserting the redirect target never receives a request. Addresses PR dcm-project#38 review comment: dcm-project#38 (comment) Assisted by: Claude Code - sonnet-5 Signed-off-by: gabriel-farache <gfarache@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
abfefeb to
5d128ef
Compare
c816c5f to
db32d4f
Compare
39201cf to
3855629
Compare
…igration Reword the expires_in overflow requirement/AC and the token-fetch design decisions to describe the upcoming migration of ClientCredentialsTokenSource from a hand-rolled client_credentials POST to golang.org/x/oauth2/clientcredentials (per PR dcm-project#38 review comment from jordigilh): - REQ-DCM-221 / AC-DCM-226: an oversized expires_in is now clamped to math.MaxInt32 seconds (~68 years) by the library's int32-based wire decoder rather than rejected as an overflow error; missing/zero/ negative expires_in is still rejected. - DD-510: replace the hand-rolled rationale with the library-adoption rationale, the Config.Token(ctx)-per-fetch + own-cache design (vs. Config.TokenSource(ctx)/ReuseTokenSource) and why, and the accepted expires_in clamping behavior change. - DD-540: the redirect-refusing http.Client is now injected into the library call via context.WithValue(ctx, oauth2.HTTPClient, ...) rather than passed directly to a hand-rolled http.Do call. - TC-DCM-UT-AUTH-080: description/expected-outcome updated to match the new clamp-not-reject behavior. Assisted by: Claude Code - sonnet-4.6 Signed-off-by: gabriel-farache <gfarache@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the hand-rolled client_credentials POST-and-decode in ClientCredentialsTokenSource.fetchToken with a thin wrapper around clientcredentials.Config.Token(ctx), per PR dcm-project#38 review comment from jordigilh (discussion_r4072664229). - ClientCredentialsTokenSource now holds a *clientcredentials.Config (AuthStyle: oauth2.AuthStyleInParams, matching the previous body-param wire format) instead of raw tokenEndpoint/clientID/ clientSecret fields. The public constructor signature and cache/ refresh/mutex wrapper around fetchToken are unchanged. - fetchToken calls c.conf.Token(ctx) directly on every cache miss (not c.conf.TokenSource(ctx), which would fix ctx at construction time inside an oauth2.ReuseTokenSource) so that attemptRegister's and sendHeartbeat's per-attempt context.WithTimeout/cancellation is preserved exactly as before. - The redirect-refusing http.Client is injected into the library call via context.WithValue(ctx, oauth2.HTTPClient, c.httpClient) rather than a hand-rolled http.NewRequestWithContext/httpClient.Do call. - oauth2.RetrieveError is translated into the same "token endpoint returned HTTP %d: <code>: <description>" message shape the hand-rolled implementation produced (REQ-DCM-225). - expires_in validation now only rejects a zero/non-positive tok.Expiry (REQ-DCM-221); an oversized expires_in is no longer rejected as an overflow error, since the library's wire decoder already clamps it to math.MaxInt32 seconds (AC-DCM-226), which structurally cannot overflow time.Duration. - Dropped the now-unused tokenResponse struct, validateExpiresIn, maxExpiresInSeconds, and maxDrainBytes. - go.mod: golang.org/x/oauth2 promoted from an indirect to a direct dependency via go mod tidy. TC-DCM-UT-AUTH-080 in token_test.go is rewritten to match: it now asserts the oversized expires_in is accepted with a clamped, far-future expiry (confirmed via cache reuse on a second call) instead of a fetch error, per the updated AC-DCM-226 (see prior docs commit). Verified via go build, go vet, golangci-lint, and the full internal/dcm unit + integration suite; make ci passes end to end. Assisted by: Claude Code - sonnet-4.6 Signed-off-by: gabriel-farache <gfarache@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Assisted by: Claude Code - opus-4.6 Signed-off-by: gabriel-farache <gfarache@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Assisted by: Claude Code - opus-4.6 Signed-off-by: gabriel-farache <gfarache@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
49235f2 to
a86df0e
Compare
When the Control-Plane (CP) has authN enabled, the agent will have to provide an Authorization token to be able to register and send its hearbeat.
3 options: