Skip to content

Commit 9df7986

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix(oci): accept Oracle API key download markers
1 parent 3fa59e7 commit 9df7986

5 files changed

Lines changed: 68 additions & 6 deletions

File tree

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,56 @@ describe('OCI API-key credential setup', () => {
101101
)
102102
})
103103

104+
it.each(['\n', '\r\n'])(
105+
'accepts the exact Oracle download marker with %j line endings',
106+
async (newline) => {
107+
for (const [pem, keyPassphrase] of [
108+
[privateKey, undefined],
109+
[encryptedPrivateKey, passphrase],
110+
]) {
111+
await verifyAndEncryptOciApiKeyCredential(
112+
fields({
113+
privateKey: `${pem}OCI_API_KEY\n`.replaceAll('\n', newline),
114+
privateKeyPassphrase: keyPassphrase,
115+
})
116+
)
117+
const serialized = dependencies.verifySetup.mock.lastCall![0]
118+
expect(JSON.parse(serialized).privateKey).toBe(pem)
119+
expect(dependencies.encryptSecret).toHaveBeenLastCalledWith(serialized)
120+
}
121+
}
122+
)
123+
124+
it('rejects malformed download trailers before provider verification', async () => {
125+
for (const suffix of [
126+
'OCI_API_KEY_EXTRA',
127+
'oci_api_key',
128+
'OCI_API_KEY\nextra',
129+
'extra\nOCI_API_KEY',
130+
'OCI_API_KEY\nOCI_API_KEY',
131+
'\u0000OCI_API_KEY',
132+
]) {
133+
await expect(
134+
verifyAndEncryptOciApiKeyCredential(fields({ privateKey: `${privateKey}${suffix}` }))
135+
).rejects.toEqual(new OciCredentialVerificationError('invalid_credentials'))
136+
}
137+
await expect(
138+
verifyAndEncryptOciApiKeyCredential(
139+
fields({ privateKey: `${privateKey}${' '.repeat(65536)}\nOCI_API_KEY` })
140+
)
141+
).rejects.toEqual(new OciCredentialVerificationError('invalid_credentials'))
142+
await expect(
143+
verifyAndEncryptOciApiKeyCredential(
144+
fields({
145+
privateKey: `${privateKey}OCI_API_KEY`,
146+
fingerprint: '00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00',
147+
})
148+
)
149+
).rejects.toEqual(new OciCredentialVerificationError('invalid_credentials'))
150+
expect(dependencies.verifySetup).not.toHaveBeenCalled()
151+
expect(dependencies.encryptSecret).not.toHaveBeenCalled()
152+
})
153+
104154
it('accepts encrypted RSA keys only with the exact preserved passphrase', async () => {
105155
await verifyAndEncryptOciApiKeyCredential(
106156
fields({ privateKey: encryptedPrivateKey, privateKeyPassphrase: passphrase })

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,17 @@ function normalizeFingerprint(value: unknown): string {
9494
function normalizePrivateKey(value: unknown): string {
9595
assertBoundedText(value, 'private key', MAX_PRIVATE_KEY_BYTES, PEM_CONTROL_CHARACTER_PATTERN)
9696
const normalized = value.replace(/\r\n?/g, '\n').trim()
97-
if (!normalized.startsWith('-----BEGIN ') || !normalized.endsWith('-----')) {
97+
const pem = normalized.endsWith('\nOCI_API_KEY')
98+
? normalized.slice(0, -'\nOCI_API_KEY'.length).trimEnd()
99+
: normalized
100+
if (
101+
!/^-----BEGIN (PRIVATE KEY|RSA PRIVATE KEY|ENCRYPTED PRIVATE KEY)-----\n[\s\S]+\n-----END \1-----$/.test(
102+
pem
103+
)
104+
) {
98105
throw new Error('OCI private key must be PEM encoded')
99106
}
100-
return `${normalized}\n`
107+
return `${pem}\n`
101108
}
102109

103110
function validatePassphrase(value: unknown): string | undefined {

apps/sim/lib/credentials/orchestration/credential-create.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ export async function createCredentialRecord(
545545
return failure(
546546
providerUnavailable
547547
? 'OCI is temporarily unavailable for credential verification'
548-
: 'OCI rejected the API-key credential',
548+
: 'OCI API-key credential could not be verified',
549549
'validation',
550550
{ providerErrorCode, providerUnavailable }
551551
)

apps/sim/lib/credentials/orchestration/index.test.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ describe('performUpdateCredential — service-account secret rotation', () => {
230230
})
231231

232232
it.each([
233-
['invalid_credentials', 'invalid_credentials', 'OCI rejected the API-key credential'],
233+
['invalid_credentials', 'invalid_credentials', 'OCI API-key credential could not be verified'],
234234
[
235235
'service_unavailable',
236236
'provider_unavailable',
@@ -724,7 +724,12 @@ describe('createServiceAccountCredential', () => {
724724
})
725725

726726
it.each([
727-
['invalid_credentials', 'invalid_credentials', false, 'OCI rejected the API-key credential'],
727+
[
728+
'invalid_credentials',
729+
'invalid_credentials',
730+
false,
731+
'OCI API-key credential could not be verified',
732+
],
728733
[
729734
'service_unavailable',
730735
'provider_unavailable',

apps/sim/lib/credentials/orchestration/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ export async function updateCredentialRecord(
412412
success: false,
413413
error: providerUnavailable
414414
? 'OCI is temporarily unavailable for credential verification'
415-
: 'OCI rejected the API-key credential',
415+
: 'OCI API-key credential could not be verified',
416416
errorCode: 'validation',
417417
providerErrorCode: providerUnavailable ? 'provider_unavailable' : 'invalid_credentials',
418418
}

0 commit comments

Comments
 (0)