Skip to content

Commit a393f2d

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix(oci): enforce credential and endpoint boundaries
1 parent 8af86c8 commit a393f2d

10 files changed

Lines changed: 234 additions & 55 deletions

File tree

apps/sim/app/workspace/[workspaceId]/integrations/components/connect-service-account-modal/connect-service-account-modal.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,9 @@ function OciApiKeyServiceAccountModal({
393393
}}
394394
placeholder='-----BEGIN PRIVATE KEY-----'
395395
minHeight={120}
396+
className={
397+
privateKey ? '[&_textarea:not(:focus)]:[-webkit-text-security:disc]' : undefined
398+
}
396399
mono
397400
required
398401
/>

apps/sim/lib/credentials/oci-api-key-service-account.server.test.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,12 @@ describe('OCI API-key credential setup', () => {
111111

112112
await expect(
113113
verifyAndEncryptOciApiKeyCredential(fields({ privateKey: encryptedPrivateKey }))
114-
).rejects.toThrow('private key or passphrase')
114+
).rejects.toEqual(new OciCredentialVerificationError('invalid_credentials'))
115115
await expect(
116116
verifyAndEncryptOciApiKeyCredential(
117117
fields({ privateKey: encryptedPrivateKey, privateKeyPassphrase: passphrase.trim() })
118118
)
119-
).rejects.toThrow('private key or passphrase')
119+
).rejects.toEqual(new OciCredentialVerificationError('invalid_credentials'))
120120
})
121121

122122
it('rejects malformed, non-RSA, and undersized keys before network or encryption', async () => {
@@ -134,7 +134,9 @@ describe('OCI API-key credential setup', () => {
134134
}),
135135
]
136136
for (const invalid of cases) {
137-
await expect(verifyAndEncryptOciApiKeyCredential(invalid)).rejects.toThrow()
137+
await expect(verifyAndEncryptOciApiKeyCredential(invalid)).rejects.toEqual(
138+
new OciCredentialVerificationError('invalid_credentials')
139+
)
138140
}
139141
expect(dependencies.verifySetup).not.toHaveBeenCalled()
140142
expect(dependencies.encryptSecret).not.toHaveBeenCalled()
@@ -153,7 +155,9 @@ describe('OCI API-key credential setup', () => {
153155
fields({ tenancyOcid: `ocid1.tenancy.oc1..${'a'.repeat(240)}` }),
154156
]
155157
for (const invalid of invalidCases) {
156-
await expect(verifyAndEncryptOciApiKeyCredential(invalid)).rejects.toThrow()
158+
await expect(verifyAndEncryptOciApiKeyCredential(invalid)).rejects.toEqual(
159+
new OciCredentialVerificationError('invalid_credentials')
160+
)
157161
}
158162
expect(dependencies.verifySetup).not.toHaveBeenCalled()
159163
expect(dependencies.encryptSecret).not.toHaveBeenCalled()

apps/sim/lib/credentials/oci-api-key-service-account.server.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,12 @@ export async function verifyAndEncryptOciApiKeyCredential(
170170
fields: OciApiKeyCredentialFields,
171171
signal?: AbortSignal
172172
): Promise<{ encryptedServiceAccountKey: string; userOcid: string }> {
173-
const secret = buildSecret(fields)
173+
let secret: OciApiKeyServiceAccountSecret
174+
try {
175+
secret = buildSecret(fields)
176+
} catch {
177+
throw new OciCredentialVerificationError('invalid_credentials')
178+
}
174179
let responseBody: Uint8Array
175180
try {
176181
responseBody = await verifyOciApiKeyCredentialForSetup(JSON.stringify(secret), signal)

apps/sim/lib/credentials/service-account-secret.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,29 @@ describe('verifyAndBuildServiceAccountSecret', () => {
242242
}
243243
)
244244

245+
it('classifies local OCI field validation as rejected credentials', async () => {
246+
const { OciCredentialVerificationError } = await import(
247+
'@/lib/credentials/oci-api-key-service-account.server'
248+
)
249+
mockVerifyAndEncryptOci.mockRejectedValue(
250+
new OciCredentialVerificationError('invalid_credentials')
251+
)
252+
253+
await expect(
254+
verifyAndBuildServiceAccountSecret('oci-api-key-service-account', {
255+
tenancyOcid: 'ocid1.tenancy.oc1..tenant',
256+
userOcid: 'ocid1.user.oc1..principal',
257+
fingerprint: 'invalid-fingerprint',
258+
privateKey: 'invalid-key',
259+
region: 'us-ashburn-1',
260+
})
261+
).rejects.toMatchObject({
262+
name: 'ServiceAccountSecretError',
263+
message: 'OCI rejected the API-key credential',
264+
providerErrorCode: 'invalid_credentials',
265+
})
266+
})
267+
245268
it('does not misclassify an internal OCI credential failure as rejected credentials', async () => {
246269
const internalFailure = new Error('internal encryption failure')
247270
mockVerifyAndEncryptOci.mockRejectedValue(internalFailure)

apps/sim/lib/internal/oci/client.server.test.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,10 @@ import { OCI_SERVICE_ID } from '@/lib/oauth/types'
7878
// Fixed test material. The expected signatures were generated independently with
7979
// OpenSSL 3 against Oracle's Request Signatures specification (retrieved 2026-09-03):
8080
// https://docs.oracle.com/en-us/iaas/Content/API/Concepts/signingrequests.htm
81-
// The canonical header order is cross-checked against oci-common 2.140.0.
81+
// The Identity hostname is cross-checked against Oracle's API endpoint catalog:
82+
// https://docs.oracle.com/en-us/iaas/api/
83+
// The canonical header order and hostname template are cross-checked against
84+
// oci-common and oci-identity 2.140.1.
8285
// Keep the synthetic fixture's PEM delimiters split so secret scanners do not
8386
// mistake checked-in conformance material for a deployable credential.
8487
const PRIVATE_KEY = `${['-----BEGIN', 'PRIVATE KEY-----'].join(' ')}
@@ -128,6 +131,7 @@ const SECRET = JSON.stringify({
128131
const STATIC_POLICY = createOciStaticEndpointPolicy({
129132
serviceId: OCI_SERVICE_ID,
130133
serviceName: 'identity',
134+
hostnameTemplate: 'regional-oci',
131135
})
132136

133137
function secureResponse(params: {
@@ -239,6 +243,7 @@ describe('credential-bound OCI client', () => {
239243
const wrongPolicy = createOciStaticEndpointPolicy({
240244
serviceId: 'slack',
241245
serviceName: 'identity',
246+
hostnameTemplate: 'regional-oci',
242247
})
243248
await expect(client.prepareStaticEndpoint(wrongPolicy)).rejects.toMatchObject({
244249
code: 'invalid_endpoint',
@@ -252,7 +257,7 @@ describe('credential-bound OCI client', () => {
252257
code: 'invalid_endpoint',
253258
})
254259
expect((await createPreparedClient({ region: 'eu-frankfurt-1' })).endpoint.origin).toBe(
255-
'https://identity.eu-frankfurt-1.oraclecloud.com'
260+
'https://identity.eu-frankfurt-1.oci.oraclecloud.com'
256261
)
257262
})
258263

@@ -274,15 +279,15 @@ describe('credential-bound OCI client', () => {
274279

275280
const authorization = authorizationFromLastRequest()
276281
expect(authorization).toBe(
277-
'Signature version="1",keyId="ocid1.tenancy.oc1..aaaaaaaafixedvector/ocid1.user.oc1..aaaaaaaafixedvector/25:53:22:62:aa:db:ff:ef:f5:77:08:d1:a2:ed:8b:e6",algorithm="rsa-sha256",headers="x-date (request-target) host",signature="pcMhip57/dPnKl/dfg5usN7oT/illXEGUp9Oj2d9bpGb0aRMBJclgVFKRYdYXciUGPM/9vKluD5/eGPBO1Oh7w/6NCB8UX2Ejh/lw8merU1QalZ/OfHyj+wKNVOpqwQjNqettRUzSVMhCqImDnvgx8ygmVCvdc0CeLXf2ZF9iT1bYlDjOiuxOcWreN2rs1ZmfLCfal204nAjrNAvoBSgHCPVquAYnfsT2auOWP4QeHN/Hd/v7TvNqsWBFIaLCyWZOvRzpsw/ZLgLzB+jkuPTdL7l4hOZATUd7xy1QPFTJ0P1RlLHjZE1sH7hbrqVGORNXrVhA1LaArObz6GWPOOghA=="'
282+
'Signature version="1",keyId="ocid1.tenancy.oc1..aaaaaaaafixedvector/ocid1.user.oc1..aaaaaaaafixedvector/25:53:22:62:aa:db:ff:ef:f5:77:08:d1:a2:ed:8b:e6",algorithm="rsa-sha256",headers="x-date (request-target) host",signature="szHTszQxwI2ewdVaeTurJY0ObT7qSjjTpXKLDRhnBp8g2hT1r2yxs4IaxN+wcrebh4i5tQYq5aBIuM3f5jOe4ng/e9+HCV+J8kHyRMxwk1b3nkqtImf8sPetp1ohD1XeWdT1gw5MSavC/C2mdHdDNlOrYAKD2vwxsKRbS6/C6ngRRcTispz6UU/ydmeYq3JjuFJezFPGWXRdqndM0dC+/ew19x08X/M6quZcxn9JZVw1E2YzSjq8xquLQYyISesVtpN81HEZ9KE9UOhbALNQAJcLCt6R3Su78aOR0S0vh19YkrwxCLbbTmPrVubksXsfZPcotbZmtXVIzNdLW0JpNg=="'
278283
)
279284

280285
const signature = /signature="([^"]+)"/.exec(authorization)?.[1]
281286
expect(signature).toBeDefined()
282287
expect(
283288
verify(
284289
'RSA-SHA256',
285-
'x-date: Thu, 03 Sep 2026 19:00:00 GMT\n(request-target): get /20160918/users?limit=10&name=Team%20X\nhost: identity.us-ashburn-1.oraclecloud.com',
290+
'x-date: Thu, 03 Sep 2026 19:00:00 GMT\n(request-target): get /20160918/users?limit=10&name=Team%20X\nhost: identity.us-ashburn-1.oci.oraclecloud.com',
286291
createPublicKey(PRIVATE_KEY),
287292
Buffer.from(signature!, 'base64')
288293
)
@@ -304,7 +309,7 @@ describe('credential-bound OCI client', () => {
304309
})
305310

306311
expect(authorizationFromLastRequest()).toBe(
307-
'Signature version="1",keyId="ocid1.tenancy.oc1..aaaaaaaafixedvector/ocid1.user.oc1..aaaaaaaafixedvector/25:53:22:62:aa:db:ff:ef:f5:77:08:d1:a2:ed:8b:e6",algorithm="rsa-sha256",headers="x-date (request-target) host content-type content-length x-content-sha256",signature="vyhrwd21evtwFet82VT1FvKEeZV+JSa3VZuS5p4Pj8K2zeU88GO+tGx/voUK9TFHijF7eG5gGS6WWc6tigrByTocbVOHpLtPNgBo2+1NbTbGHGUZIzCOR5CZ1ite74Ak43xZjyKBm+vZHrvS22leVOJe43V/HjqCxqyPn3WkKd7npqo9eFM1sibdj1h3Cmi79b5nXSPFe5KE+rnMRPTOB4nl7iFELvubg/Y7Y8w5hRYEe13w09zw9tTBdGJtZIuMoYwZYzPdZo5wbrN5WM6ylHC2euVh2PSazZZU99q55uhxiR6OaCQWLM0buytCqja8FeiEY8Iw3GuEbKUECKaM8Q=="'
312+
'Signature version="1",keyId="ocid1.tenancy.oc1..aaaaaaaafixedvector/ocid1.user.oc1..aaaaaaaafixedvector/25:53:22:62:aa:db:ff:ef:f5:77:08:d1:a2:ed:8b:e6",algorithm="rsa-sha256",headers="x-date (request-target) host content-type content-length x-content-sha256",signature="W2/OGoa2XuOin6+CQt32/+/lAXG5PWoamkAHr/k84oCYGUuub2mEYw1z9p4gc6/GPgeZ30wVp4DNVLzOjup3nJir1WsEsYzAk27XAIRVjxiQ7oBzCccnSnB88KLeNz1NDz7r4QPQGxZ50MBQEe0C+DEH2P+utpfFN73o7GCUhIN9hb27COg4l7ffdSLgjBWPN/B4AiZXpjz3I/GRHo29otGAhZ3MiX10gJTjy+qeAchAfmXmTx/nJqNhF0Aj255+B2lepCrHdkpcBpiTs5E+ppE6VvML0ByQ9ZLzBISB4MBljuFyey6tnTkueT73fqjQyM/OT+aO9HrAlemc3HSAXA=="'
308313
)
309314
expect(mocks.secureFetch.mock.calls[0][1].headers).toMatchObject({
310315
'content-length': '0',
@@ -337,7 +342,7 @@ describe('credential-bound OCI client', () => {
337342
{ body: Uint8Array; headers: Record<string, string> },
338343
]
339344
expect(url).toBe(
340-
'https://identity.us-ashburn-1.oraclecloud.com/v1/%E2%98%83?z=last&a=&a=%20%21%27%28%29%2A'
345+
'https://identity.us-ashburn-1.oci.oraclecloud.com/v1/%E2%98%83?z=last&a=&a=%20%21%27%28%29%2A'
341346
)
342347
expect([...options.body]).toEqual([...body])
343348
expect(options.body).not.toBe(body)
@@ -666,6 +671,7 @@ describe('credential-bound OCI client', () => {
666671
const policy = createOciDiscoveredEndpointPolicy({
667672
serviceId: OCI_SERVICE_ID,
668673
serviceName: 'database',
674+
hostnameTemplate: 'regional',
669675
responsePolicy: STATIC_POLICY,
670676
source: { kind: 'json', path: ['endpoint'] },
671677
})
@@ -694,6 +700,7 @@ describe('credential-bound OCI client', () => {
694700
const otherPolicy = createOciStaticEndpointPolicy({
695701
serviceId: OCI_SERVICE_ID,
696702
serviceName: 'compute',
703+
hostnameTemplate: 'regional',
697704
})
698705
const otherEndpoint = await first.client.prepareStaticEndpoint(otherPolicy)
699706
mocks.secureFetch.mockResolvedValueOnce(

apps/sim/lib/internal/oci/client.server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,7 @@ export async function verifyOciApiKeyCredentialForSetup(
875875
const policy = createOciStaticEndpointPolicy({
876876
serviceId: OCI_SERVICE_ID,
877877
serviceName: 'objectstorage',
878+
hostnameTemplate: 'regional',
878879
})
879880
const endpoint = resolveStaticOciEndpoint(policy, resolveEffectiveOciRegion(material.region))
880881
const url = buildRequestUrl(endpoint, '/n/', [])

apps/sim/lib/internal/oci/endpoints.test.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ import { OCI_SERVICE_ID } from '@/lib/oauth/types'
1717
const staticPolicy = createOciStaticEndpointPolicy({
1818
serviceId: OCI_SERVICE_ID,
1919
serviceName: 'identity',
20+
hostnameTemplate: 'regional-oci',
2021
})
2122
const discoveryPolicy = createOciDiscoveredEndpointPolicy({
2223
serviceId: OCI_SERVICE_ID,
2324
serviceName: 'database',
25+
hostnameTemplate: 'regional',
2426
responsePolicy: staticPolicy,
2527
source: { kind: 'json', path: ['endpoint'] },
2628
})
@@ -33,7 +35,12 @@ describe('OCI region registry', () => {
3335
expect(region.id).toBe(id)
3436
expect(region.realm.id).toMatch(/^oc\d+$/)
3537
expect(region.realm.domain).toMatch(/^(?:oraclecloud|oraclegovcloud)/)
36-
expect(regionalOciHostname('identity', region)).toBe(`identity.${id}.${region.realm.domain}`)
38+
expect(regionalOciHostname('identity', region, 'regional-oci')).toBe(
39+
`identity.${id}.oci.${region.realm.domain}`
40+
)
41+
expect(regionalOciHostname('objectstorage', region, 'regional')).toBe(
42+
`objectstorage.${id}.${region.realm.domain}`
43+
)
3744
}
3845
})
3946

@@ -58,8 +65,8 @@ describe('OCI endpoint policies', () => {
5865
expect(Object.isFrozen(staticPolicy)).toBe(true)
5966
const endpoint = resolveStaticOciEndpoint(staticPolicy, region)
6067
expect(endpoint).toMatchObject({
61-
origin: 'https://identity.us-ashburn-1.oraclecloud.com',
62-
hostname: 'identity.us-ashburn-1.oraclecloud.com',
68+
origin: 'https://identity.us-ashburn-1.oci.oraclecloud.com',
69+
hostname: 'identity.us-ashburn-1.oci.oraclecloud.com',
6370
serviceId: OCI_SERVICE_ID,
6471
serviceName: 'identity',
6572
provenance: 'static',
@@ -69,7 +76,7 @@ describe('OCI endpoint policies', () => {
6976
expect(Object.isFrozen(endpoint.region.realm)).toBe(true)
7077
expect(Reflect.set(endpoint, 'origin', 'https://attacker.example')).toBe(false)
7178
expect(Reflect.set(endpoint.region, 'id', 'attacker-region-1')).toBe(false)
72-
expect(endpoint.origin).toBe('https://identity.us-ashburn-1.oraclecloud.com')
79+
expect(endpoint.origin).toBe('https://identity.us-ashburn-1.oci.oraclecloud.com')
7380
expect(endpoint.region.id).toBe('us-ashburn-1')
7481
})
7582

@@ -104,6 +111,7 @@ describe('OCI endpoint policies', () => {
104111
const policy = createOciDiscoveredEndpointPolicy({
105112
serviceId: OCI_SERVICE_ID,
106113
serviceName: 'database',
114+
hostnameTemplate: 'regional',
107115
responsePolicy: staticPolicy,
108116
source: { kind: 'header', name: 'Endpoint' },
109117
allowRegionalHost: true,
@@ -118,8 +126,19 @@ describe('OCI endpoint policies', () => {
118126

119127
it('rejects malformed policy declarations and forged region mappings', () => {
120128
expect(() =>
121-
createOciStaticEndpointPolicy({ serviceId: OCI_SERVICE_ID, serviceName: 'bad.name' })
129+
createOciStaticEndpointPolicy({
130+
serviceId: OCI_SERVICE_ID,
131+
serviceName: 'bad.name',
132+
hostnameTemplate: 'regional',
133+
})
122134
).toThrow('service name')
135+
expect(() =>
136+
createOciStaticEndpointPolicy({
137+
serviceId: OCI_SERVICE_ID,
138+
serviceName: 'identity',
139+
hostnameTemplate: 'arbitrary' as never,
140+
})
141+
).toThrow('hostname template')
123142
expect(() =>
124143
resolveStaticOciEndpoint(staticPolicy, {
125144
id: region.id,
@@ -130,9 +149,11 @@ describe('OCI endpoint policies', () => {
130149
createOciDiscoveredEndpointPolicy({
131150
serviceId: OCI_SERVICE_ID,
132151
serviceName: 'database',
152+
hostnameTemplate: 'regional',
133153
responsePolicy: createOciStaticEndpointPolicy({
134154
serviceId: 'slack',
135155
serviceName: 'identity',
156+
hostnameTemplate: 'regional-oci',
136157
}),
137158
source: { kind: 'json', path: ['endpoint'] },
138159
})

apps/sim/lib/internal/oci/endpoints.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { isIpLiteral, unwrapIpv6Brackets } from '@sim/security/ssrf'
22
import type { OAuthService } from '@/lib/oauth/types'
33

44
export type OciDestinationProvenance = 'static' | 'authenticated-discovery'
5+
export type OciHostnameTemplate = 'regional' | 'regional-oci'
56

67
export interface OciRealm {
78
readonly id: string
@@ -32,6 +33,7 @@ export interface OciStaticEndpointPolicy {
3233
readonly kind: 'static'
3334
readonly serviceId: OAuthService
3435
readonly serviceName: string
36+
readonly hostnameTemplate: OciHostnameTemplate
3537
readonly [ociEndpointPolicyBrand]: true
3638
}
3739

@@ -43,6 +45,7 @@ export interface OciDiscoveredEndpointPolicy {
4345
readonly kind: 'authenticated-discovery'
4446
readonly serviceId: OAuthService
4547
readonly serviceName: string
48+
readonly hostnameTemplate: OciHostnameTemplate
4649
readonly responsePolicy: OciEndpointPolicy
4750
readonly source: OciDiscoverySource
4851
readonly allowRegionalHost: boolean
@@ -203,6 +206,12 @@ function assertServiceName(value: string): void {
203206
}
204207
}
205208

209+
function assertHostnameTemplate(value: OciHostnameTemplate): void {
210+
if (value !== 'regional' && value !== 'regional-oci') {
211+
throw new Error('OCI endpoint policy hostname template is invalid')
212+
}
213+
}
214+
206215
function assertDiscoverySource(source: OciDiscoverySource): void {
207216
if (source.kind === 'header') {
208217
if (!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(source.name)) {
@@ -227,24 +236,29 @@ function assertDiscoverySource(source: OciDiscoverySource): void {
227236
export function createOciStaticEndpointPolicy(params: {
228237
serviceId: OAuthService
229238
serviceName: string
239+
hostnameTemplate: OciHostnameTemplate
230240
}): OciStaticEndpointPolicy {
231241
assertServiceName(params.serviceName)
242+
assertHostnameTemplate(params.hostnameTemplate)
232243
return Object.freeze({
233244
kind: 'static',
234245
serviceId: params.serviceId,
235246
serviceName: params.serviceName,
247+
hostnameTemplate: params.hostnameTemplate,
236248
}) as OciStaticEndpointPolicy
237249
}
238250

239251
/** Creates a frozen authenticated-discovery policy without executable hostname callbacks. */
240252
export function createOciDiscoveredEndpointPolicy(params: {
241253
serviceId: OAuthService
242254
serviceName: string
255+
hostnameTemplate: OciHostnameTemplate
243256
responsePolicy: OciEndpointPolicy
244257
source: OciDiscoverySource
245258
allowRegionalHost?: boolean
246259
}): OciDiscoveredEndpointPolicy {
247260
assertServiceName(params.serviceName)
261+
assertHostnameTemplate(params.hostnameTemplate)
248262
assertDiscoverySource(params.source)
249263
if (params.responsePolicy.serviceId !== params.serviceId) {
250264
throw new Error('OCI discovery source policy must have the same owning service')
@@ -257,15 +271,22 @@ export function createOciDiscoveredEndpointPolicy(params: {
257271
kind: 'authenticated-discovery',
258272
serviceId: params.serviceId,
259273
serviceName: params.serviceName,
274+
hostnameTemplate: params.hostnameTemplate,
260275
responsePolicy: params.responsePolicy,
261276
source,
262277
allowRegionalHost: params.allowRegionalHost ?? false,
263278
}) as OciDiscoveredEndpointPolicy
264279
}
265280

266-
export function regionalOciHostname(serviceName: string, region: OciRegion): string {
281+
export function regionalOciHostname(
282+
serviceName: string,
283+
region: OciRegion,
284+
hostnameTemplate: OciHostnameTemplate
285+
): string {
267286
assertServiceName(serviceName)
268-
return `${serviceName}.${region.id}.${region.realm.domain}`
287+
assertHostnameTemplate(hostnameTemplate)
288+
const ociLabel = hostnameTemplate === 'regional-oci' ? '.oci' : ''
289+
return `${serviceName}.${region.id}${ociLabel}.${region.realm.domain}`
269290
}
270291

271292
function validateOciOrigin(params: {
@@ -301,7 +322,11 @@ function validateOciOrigin(params: {
301322
) {
302323
throw new Error('OCI destination must be an exact HTTPS origin with the default port')
303324
}
304-
const regionalHostname = regionalOciHostname(params.policy.serviceName, knownRegion)
325+
const regionalHostname = regionalOciHostname(
326+
params.policy.serviceName,
327+
knownRegion,
328+
params.policy.hostnameTemplate
329+
)
305330
const hostnameMatches =
306331
params.provenance === 'static'
307332
? url.hostname === regionalHostname
@@ -327,7 +352,7 @@ export function resolveStaticOciEndpoint(
327352
policy: OciStaticEndpointPolicy,
328353
region: OciRegion
329354
): OciPreparedEndpoint {
330-
const hostname = regionalOciHostname(policy.serviceName, region)
355+
const hostname = regionalOciHostname(policy.serviceName, region, policy.hostnameTemplate)
331356
return validateOciOrigin({
332357
origin: `https://${hostname}`,
333358
policy,

0 commit comments

Comments
 (0)