Commit 3fa65b0
authored
Extract DCR resolver into pkg/auth/dcr (#5198)
* Extract DCR resolver into pkg/auth/dcr
Sub-issue 4a of #5145. Creates the shared pkg/auth/dcr package and
migrates the embedded authserver to consume it. The CLI flow
migration (pkg/auth/discovery::PerformOAuthFlow) is left to
sub-issue 4b (#5219) so this slice stays under the project's
PR-size limit.
Files moved (renamed via git mv so the diff shows as renames, not
deletions + additions):
pkg/authserver/runner/dcr.go -> pkg/auth/dcr/resolver.go
pkg/authserver/runner/dcr_store.go -> pkg/auth/dcr/store.go
pkg/authserver/runner/dcr_test.go -> pkg/auth/dcr/resolver_test.go
pkg/authserver/runner/dcr_store_test.go -> pkg/auth/dcr/store_test.go
pkg/authserver/runner/dcr_testhelpers_test.go -> pkg/auth/dcr/testhelpers_test.go
Public API surface (renamed from runner-package internals because
they now cross a package boundary):
Resolution (was DCRResolution)
Key (was DCRKey, alias to storage.DCRKey unchanged)
CredentialStore (was the package-private dcrResolutionCache)
ResolveCredentials (was resolveDCRCredentials)
NeedsDCR (was needsDCR)
ConsumeResolution (was consumeResolution)
ApplyResolutionToOAuth2Config (was applyResolutionToOAuth2Config)
LogStepError (was logDCRStepError)
NewInMemoryStore (new convenience constructor wrapping
storage.NewMemoryStorage; mirrors the pattern
the per-test newMemoryDCRStore helpers use)
NewStorageBackedStore (was the package-private newStorageBackedStore)
SanitizeErrorForLog (was sanitizeErrorForLog; promoted to
exported because the deferred-cleanup log
path in pkg/authserver/runner needs it)
Names follow the pkg/auth/dcr.* form so the linter's stuttering
check (revive: dcr.DCRResolution would stutter) passes and the
surface reads as ordinary package API.
resolveSecret was duplicated into the dcr package because
pkg/auth/dcr must stay profile-agnostic and cannot reach back into
pkg/authserver/runner. The duplication is intentional and called
out in a comment; future consolidation can move it into a shared
helper if a third caller appears. A parallel TestResolveSecret /
TestResolveSecretWithEnvVar suite in pkg/auth/dcr/secret_test.go
mirrors the runner-package twin's observable contract so any
future drift between the two copies fails CI on at least one side.
Review-feedback bits applied alongside the move:
- Package doc comment in pkg/auth/dcr/resolver.go now documents the
process-global singleflight in a Concurrency section, and labels
the profile-agnostic framing as a target state for sub-issue 4b
rather than as a description of the current API shape (the
package's public API still takes embedded-authserver types).
- dcrFlight var doc gains a cross-consumer caveat naming the
"third consumer with colliding redirect URI" failure mode.
- Flight-key construction extracted into flightKeyOf(Key) string so
the canonical key shape is inspectable rather than buried in a
string-concatenation literal.
- endpointsFromMetadata gains a defensive nil check; the function's
doc comment names the oauthproto contract being defended.
- newMemoryDCRStore test helper is duplicated across the two
packages because Go test helpers cannot be shared without
exporting them; the duplication is documented at both sites.
Acceptance criteria status (#5145):
AC#1 (pkg/auth/dcr exists, exports a stateful resolver, consumed
by both call sites): partially met — package exists and is
consumed by EmbeddedAuthServer. CLI flow migration is
sub-issue 4b (#5219).
AC#2 (stateless RFC 7591 helpers in pkg/oauthproto): met
(already satisfied before this PR).
AC#3 (no direct oauthproto.RegisterClientDynamically calls
outside pkg/auth/dcr): not yet met — pkg/auth/discovery
still calls it. Resolved by sub-issue 4b (#5219).
AC#4 (review-property behaviours apply to CLI flow): not yet
met — same dependency on 4b (#5219).
Closes #5220.
Verified via task lint-fix (0 issues), task license-check (clean),
and go test -count=1 -race ./pkg/auth/dcr/... ./pkg/authserver/...
(all pass).
* Harden pkg/auth/dcr/store.go constructors
Addresses #5198 review comments:
- MEDIUM pkg/auth/dcr/store.go (3219717154): remove NewInMemoryStore
— its CredentialStore return type has no Close method, so the
storage.NewMemoryStorage cleanup goroutine the constructor spawns
cannot be stopped through the returned interface. With no
production caller in this PR (the test helpers wire their own
*MemoryStorage with t.Cleanup), removing it is the lightest fix
and resolves the "public API ahead of caller" smell. A real
consumer with lifecycle management can reintroduce the appropriate
shape (e.g. returning a paired shutdown func, or adding Close to
CredentialStore) when 4b lands.
- MEDIUM pkg/auth/dcr/store.go (3219717166): panic on nil backend in
NewStorageBackedStore. Per .claude/rules/go-style.md "Constructor
Validation: Fail Loudly on Invalid Input" — a nil backend is
unambiguously a programming error and silent acceptance would only
delay the nil-pointer dereference to the first Get/Put call, far
from the constructor site.
* Sweep stale doc references and tighten advisory comments
Addresses #5198 review comments:
- MEDIUM pkg/authserver/storage/types.go (review body finding #2):
DCRCredentials "Converter contract" doc named the now-deleted
pkg/authserver/runner/dcr_store.go path and the *DCRResolution
type. Updated to pkg/auth/dcr/store.go, *dcr.Resolution, and
pkg/auth/dcr/store_test.go (the rename sweep had missed this
out-of-diff file).
- MEDIUM pkg/auth/dcr/resolver.go (3219717202): dcrFlight doc named
EmbeddedAuthServer.dcrStore, a field #5196 removed. Reframed the
lifetime contrast in terms of the public injection point — the
CredentialStore the embedded authserver constructs and injects
into ResolveCredentials — rather than a private field across a
package boundary.
- MEDIUM pkg/authserver/runner/embeddedauthserver_test.go
(3219717294): drift-guard cross-reference was one-way. Added
reciprocal doc comments on TestResolveSecret and
TestResolveSecretWithEnvVar naming the dcr-side twin at
pkg/auth/dcr/secret_test.go, mirroring the dcr-side comment that
already names the runner-side twin.
- LOW pkg/auth/dcr/resolver.go (3219717277): SanitizeErrorForLog
reads as a generic URL sanitiser but only handles http(s);
tightened the doc with an "IMPORTANT — caller responsibility"
warning that callers receiving non-http(s) URLs with
credential-bearing components (redis://user:pass@host, postgres://,
etc.) MUST verify those separately. Long-term consolidation into
a shared helper appropriate for sub-issue 4b.
- LOW pkg/authserver/server/handlers/dcr.go (review body finding #7):
log-correlation comment named pkg/authserver/runner/dcr.go;
updated to pkg/auth/dcr/resolver.go (also missed by the rename
sweep).
- LOW pkg/auth/dcr/resolver.go (3219717222): package doc listed
*authserver.DCRUpstreamConfig as a parameter type — no exported
function takes it; it is reached transitively via
OAuth2UpstreamRunConfig.DCRConfig. Applied the reviewer's
suggested wording.
- LOW pkg/auth/dcr/resolver.go (3219717247): flightKeyOf doc cited
RFC 6749 §3.3 (scope tokens) for the ScopesHash field, which is a
hex digest, not a scope token. Removed the misaligned citation.
- LOW pkg/authserver/runner/embeddedauthserver_test.go (3219717303):
qualified four bare "DCRKey" references to "storage.DCRKey" in
comments and an assertion message; also fixed a sibling staleness
in the same test-doc block where the comment named the deleted
dcrStore field.
- LOW pkg/auth/dcr/resolver.go (3219717270): added a
TODO(#5219) on dcrFlight noting that the flight key must gain a
consumer-identifier component when sub-issue 4b wires the CLI
flow as the second consumer. The colliding-Key risk is theoretical
today; once two profiles share this group it becomes a correctness
hazard. Cross-consumer caveat above already describes the failure
mode; this TODO ties it to the resolution PR.
- LOW pkg/auth/dcr/resolver.go (3219717285): resolveSecret has no
production caller in this PR. Tightened the duplication doc to
state that the helper is staged for sub-issue 4b (#5219) to wire
as part of the CLI flow migration, and that at that point this
copy SHOULD be promoted to a shared helper with both consumers
migrated in the same PR — i.e., the threshold for consolidation
is "second caller wires up", not "third caller appears".
* Make DCR consume helpers value-in / value-out
Addresses #5198 review comments:
- INFO pkg/auth/dcr/resolver.go (3227004701): ConsumeResolution and
ApplyResolutionToOAuth2Config mutated caller-supplied pointers and
documented the "pass a copy" invariant only in prose. Converted
both to value-in / value-out signatures so the no-caller-mutation
contract is compile-time enforced rather than a prose discipline
the second consumer (CLI flow in sub-issue 4b, #5219) would have
to remember.
The change is structural but small: two signature changes
(ConsumeResolution / ApplyResolutionToOAuth2Config), two function
bodies returning the modified value, and call-site updates in
embeddedauthserver.go (1 production call site per function) and
resolver_test.go (4 test call sites for ConsumeResolution; zero for
ApplyResolutionToOAuth2Config).
Doc comments updated to describe the new value-in / value-out shape;
the "pass a copy of the run-config" prose-discipline paragraph is
removed because the type system now enforces it. Pointer-typed fields
inside the struct (DCRConfig) still share storage with the caller
via the shallow copy, but the only mutation here is nil-assignment to
the copy's DCRConfig field, which does not reach back through the
caller's pointer; this nuance is now called out in the doc comment.
ResolveCredentials is left as *authserver.OAuth2UpstreamRunConfig
deliberately: its rc input is read-only (no mutation), so the
pointer is just for avoiding a struct copy on the hot path.
Satisfies .claude/rules/go-style.md "Copy Before Mutating Caller
Input".1 parent 110b9a7 commit 3fa65b0
11 files changed
Lines changed: 597 additions & 275 deletions
File tree
- pkg
- authserver
- runner
- server/handlers
- storage
- auth/dcr
Lines changed: 242 additions & 100 deletions
Large diffs are not rendered by default.
Lines changed: 66 additions & 66 deletions
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
Lines changed: 39 additions & 31 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
28 | 29 | | |
29 | | - | |
| 30 | + | |
30 | 31 | | |
31 | 32 | | |
32 | 33 | | |
33 | 34 | | |
34 | 35 | | |
35 | | - | |
| 36 | + | |
36 | 37 | | |
37 | 38 | | |
38 | 39 | | |
39 | 40 | | |
40 | 41 | | |
41 | | - | |
| 42 | + | |
42 | 43 | | |
43 | | - | |
| 44 | + | |
44 | 45 | | |
45 | | - | |
| 46 | + | |
46 | 47 | | |
47 | 48 | | |
48 | | - | |
| 49 | + | |
49 | 50 | | |
50 | 51 | | |
51 | 52 | | |
52 | 53 | | |
53 | 54 | | |
54 | | - | |
| 55 | + | |
55 | 56 | | |
56 | 57 | | |
57 | | - | |
| 58 | + | |
58 | 59 | | |
59 | | - | |
| 60 | + | |
60 | 61 | | |
61 | 62 | | |
62 | | - | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
63 | 71 | | |
64 | 72 | | |
65 | 73 | | |
66 | | - | |
| 74 | + | |
67 | 75 | | |
68 | | - | |
| 76 | + | |
69 | 77 | | |
70 | 78 | | |
71 | 79 | | |
72 | 80 | | |
73 | 81 | | |
74 | | - | |
| 82 | + | |
75 | 83 | | |
76 | 84 | | |
77 | 85 | | |
78 | | - | |
| 86 | + | |
79 | 87 | | |
80 | 88 | | |
81 | 89 | | |
| |||
86 | 94 | | |
87 | 95 | | |
88 | 96 | | |
89 | | - | |
| 97 | + | |
90 | 98 | | |
91 | 99 | | |
92 | 100 | | |
93 | 101 | | |
94 | 102 | | |
95 | | - | |
| 103 | + | |
96 | 104 | | |
97 | 105 | | |
98 | 106 | | |
99 | 107 | | |
100 | 108 | | |
101 | 109 | | |
102 | 110 | | |
103 | | - | |
104 | | - | |
| 111 | + | |
| 112 | + | |
105 | 113 | | |
106 | 114 | | |
107 | 115 | | |
108 | 116 | | |
109 | | - | |
| 117 | + | |
110 | 118 | | |
111 | 119 | | |
112 | 120 | | |
| |||
116 | 124 | | |
117 | 125 | | |
118 | 126 | | |
119 | | - | |
| 127 | + | |
120 | 128 | | |
121 | 129 | | |
122 | 130 | | |
| |||
136 | 144 | | |
137 | 145 | | |
138 | 146 | | |
139 | | - | |
| 147 | + | |
140 | 148 | | |
141 | 149 | | |
142 | 150 | | |
143 | 151 | | |
144 | 152 | | |
145 | | - | |
| 153 | + | |
146 | 154 | | |
147 | 155 | | |
148 | 156 | | |
149 | | - | |
| 157 | + | |
150 | 158 | | |
151 | 159 | | |
152 | 160 | | |
| |||
0 commit comments