-
Notifications
You must be signed in to change notification settings - Fork 6
fix: require a serviceAuth entry for every serviceDomains host #59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,10 +17,18 @@ import ( | |
|
|
||
| // validateServiceAuthMappings fails loudly when a network.serviceAuth or | ||
| // network.serviceDomains service id does not map to a declared | ||
| // credentials.sources id. buildSecrets only walks credentials.sources, so an | ||
| // unmatched id (e.g. a typo) is otherwise silently dropped: the secret ends up | ||
| // with no HTTP release rule and its token is injected as a raw env value | ||
| // instead of a proxy-swapped placeholder — a secret-leak risk. | ||
| // credentials.sources id, and when the serviceDomains ↔ serviceAuth pairing is | ||
| // incomplete in either direction. | ||
| // | ||
| // buildSecrets only builds an HTTP release rule for ids present in both | ||
| // credentials.sources and network.serviceAuth, so a serviceDomains id with no | ||
| // serviceAuth entry (a typo, or a dropped serviceAuth line) is silently inert: | ||
| // the token is injected as a raw env value instead of a proxy-swapped | ||
| // placeholder — a secret-leak risk — and the serviceDomains hosts drop out of | ||
| // the release hosts unioned into the effective allowlist. The reverse, a | ||
| // serviceAuth entry with no hosts from either source, would otherwise be | ||
| // rejected downstream by normalizeHosts, but with a message that never names | ||
| // serviceDomains; catching it here points both directions at the same remedy. | ||
| func validateServiceAuthMappings(doc specDocument, specPath string) error { | ||
| if doc.Network == nil { | ||
| return nil | ||
|
|
@@ -31,19 +39,48 @@ func validateServiceAuthMappings(doc specDocument, specPath string) error { | |
| sources[id] = struct{}{} | ||
| } | ||
| } | ||
| // Unknown ids come first: a typo'd id also breaks the pairing, and reporting | ||
| // the pairing gap would send the author to the wrong line. | ||
| for id := range doc.Network.ServiceAuth { | ||
| if _, ok := sources[id]; !ok { | ||
| return fmt.Errorf("%s: network.serviceAuth[%q] has no matching credentials.sources entry", specPath, id) | ||
| } | ||
| } | ||
| hostedServices := map[string]struct{}{} | ||
| for host, id := range doc.Network.ServiceDomains { | ||
| if _, ok := sources[id]; !ok { | ||
| return fmt.Errorf("%s: network.serviceDomains[%q] references service %q with no matching credentials.sources entry", specPath, host, id) | ||
| } | ||
| if strings.TrimSpace(host) != "" { | ||
| hostedServices[id] = struct{}{} | ||
| } | ||
| } | ||
|
|
||
| // Then the pairing, in both directions. | ||
| for id, auth := range doc.Network.ServiceAuth { | ||
| if _, ok := hostedServices[id]; !ok && !hasNonBlank(auth.Hosts) { | ||
| return fmt.Errorf("%s: network.serviceAuth[%q] has no hosts to release the credential to (add a hosts list, or map hosts to this service under network.serviceDomains)", specPath, id) | ||
| } | ||
| } | ||
| for host, id := range doc.Network.ServiceDomains { | ||
| if _, ok := doc.Network.ServiceAuth[id]; !ok { | ||
| return fmt.Errorf("%s: network.serviceDomains[%q] references service %q with no matching network.serviceAuth entry (add one, or list the hosts under network.allowedDomains instead)", specPath, host, id) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This flips a previously accepted (if inert) sbx kit spec into a hard load error, and for a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keeping the hard fail, deliberately. A load warning would preserve exactly the behaviour this PR exists to remove. With no It is also the treatment the loader already gives this class of authoring mistake: unknown keys under On blast radius: no built-in spec is affected, and for features Note that the reverse-direction check added in 35152b5 does not widen this: it only re-messages specs |
||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // hasNonBlank reports whether hosts holds at least one entry that survives the | ||
| // blank-stripping normalizeHosts applies later. | ||
| func hasNonBlank(hosts []string) bool { | ||
| for _, host := range hosts { | ||
| if strings.TrimSpace(host) != "" { | ||
| return true | ||
| } | ||
| } | ||
| return false | ||
| } | ||
|
|
||
| // validateProxyManaged fails loudly when an environment.proxyManaged entry | ||
| // does not name a declared credentials.sources env alias. proxyManaged selects | ||
| // which aliases carry the proxy-swapped placeholder; a typo'd entry would | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reverse direction is required but not nearly as legible. A
serviceAuthentry with nohostsand noserviceDomainsreference bottoms out insecrets["tok"].release.http: hosts must contain at least one domain pattern(here), which never mentionsserviceDomains. Catching that case here too would make both directions point at the same remedy.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 35152b5.
validateServiceAuthMappingsnow also rejects aserviceAuthentry that gets no hosts from either source:Two follow-on adjustments. The check runs ahead of
normalizeHosts, soTestLoadProfileRejectsSecretReleaseWithEmptyHostsnow asserts the new message, andTestValidateAndNormalizeSecretConfigsEmptyReleaseHostscovers thenormalizeHostsguard directly to keep it from going untested. The unknown-id checks for both maps also run before both pairing checks now, otherwise a typo likeserviceDomains: { ghe.com: github-tokn }would report the hostlessserviceAuthentry it happens to create rather than the typo itself.