@@ -129,7 +129,8 @@ describe('tokenCheckValidator', () => {
129129} )
130130
131131describe ( 'tokenCheckValidator with a typed host' , ( ) => {
132- const secureFetch = inputValidationMockFns . mockSecureFetchWithValidation
132+ const validateUrl = inputValidationMockFns . mockValidateUrlWithDNS
133+ const pinnedFetch = inputValidationMockFns . mockSecureFetchWithPinnedIP
133134 const validateHost = tokenCheckValidator ( {
134135 serviceLabel : 'Example' ,
135136 domain : ( { domain } ) => {
@@ -145,17 +146,30 @@ describe('tokenCheckValidator with a typed host', () => {
145146 } )
146147
147148 beforeEach ( ( ) => {
148- secureFetch . mockReset ( )
149+ validateUrl . mockReset ( )
150+ validateUrl . mockResolvedValue ( {
151+ isValid : true ,
152+ resolvedIP : '203.0.113.7' ,
153+ originalHostname : 'tools.example.com' ,
154+ } )
155+ pinnedFetch . mockReset ( )
149156 } )
150157
151158 it ( 'verifies at the normalized host through the guarded egress and stores that host' , async ( ) => {
152- secureFetch . mockResolvedValue ( jsonResponse ( { ok : true } ) )
159+ pinnedFetch . mockResolvedValue ( jsonResponse ( { ok : true } ) )
153160
154161 await expect (
155162 validateHost ( { apiToken : 'good' , domain : ' Tools.Example.com ' } )
156163 ) . resolves . toMatchObject ( { normalizedDomain : 'tools.example.com' } )
157- expect ( secureFetch ) . toHaveBeenCalledWith (
164+ expect ( validateUrl ) . toHaveBeenCalledWith (
165+ 'https://tools.example.com/api/me' ,
166+ 'url' ,
167+ 'configuredEndpoint' ,
168+ expect . anything ( )
169+ )
170+ expect ( pinnedFetch ) . toHaveBeenCalledWith (
158171 'https://tools.example.com/api/me' ,
172+ '203.0.113.7' ,
159173 expect . objectContaining ( { profile : 'configuredEndpoint' , maxRedirects : 0 } )
160174 )
161175 } )
@@ -174,22 +188,41 @@ describe('tokenCheckValidator with a typed host', () => {
174188 await expect (
175189 validateHost ( { apiToken : 'good' , domain : 'evil.example.com@tools.example.com' } )
176190 ) . rejects . toMatchObject ( { code : 'invalid_credentials' } )
177- expect ( secureFetch ) . not . toHaveBeenCalled ( )
191+ expect ( validateUrl ) . not . toHaveBeenCalled ( )
192+ expect ( pinnedFetch ) . not . toHaveBeenCalled ( )
193+ } )
194+
195+ it ( 'reports a host the egress policy refuses as the user input, not a retryable outage' , async ( ) => {
196+ validateUrl . mockResolvedValue ( { isValid : false , error : 'url resolves to a private address' } )
197+
198+ await expect (
199+ validateHost ( { apiToken : 'good' , domain : 'grafana.internal' } )
200+ ) . rejects . toMatchObject ( { code : 'invalid_credentials' , status : 400 } )
201+ expect ( pinnedFetch ) . not . toHaveBeenCalled ( )
202+ } )
203+
204+ it ( 'reports a host that cannot be reached as the provider being unavailable' , async ( ) => {
205+ pinnedFetch . mockRejectedValue ( new Error ( 'connect ECONNREFUSED' ) )
206+
207+ await expect (
208+ validateHost ( { apiToken : 'good' , domain : 'tools.example.com' } )
209+ ) . rejects . toMatchObject ( { code : 'provider_unavailable' , status : 502 } )
178210 } )
179211
180212 it . each ( [
181213 [
182214 'Node (code on cause)' ,
183- new Error ( 'fetch failed' , {
215+ new Error ( 'lookup failed' , {
184216 cause : Object . assign ( new Error ( 'getaddrinfo ENOTFOUND' ) , { code : 'ENOTFOUND' } ) ,
185217 } ) ,
186218 ] ,
187- [
188- 'Bun (code on the error)' ,
189- Object . assign ( new TypeError ( 'fetch failed' ) , { code : 'ENOTFOUND' } ) ,
190- ] ,
191- ] ) ( 'reports a host that does not exist as not found under %s' , async ( _runtime , error ) => {
192- secureFetch . mockRejectedValue ( error )
219+ [ 'Bun (code on the error)' , Object . assign ( new Error ( 'lookup failed' ) , { code : 'ENOTFOUND' } ) ] ,
220+ ] ) ( 'reports a host that does not exist as not found under %s' , async ( _runtime , cause ) => {
221+ validateUrl . mockResolvedValue ( {
222+ isValid : false ,
223+ error : 'url hostname could not be resolved' ,
224+ cause,
225+ } )
193226
194227 await expect (
195228 validateHost ( { apiToken : 'good' , domain : 'tools.exmaple.com' } )
0 commit comments