Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9b32fa5
feat(oci): add native foundation
BillLeoutsakosvl346 Sep 3, 2026
4ee814c
fix(oci): harden endpoint and error validation
BillLeoutsakosvl346 Sep 3, 2026
b322a13
fix(oci): fail closed on encoded diagnostics
BillLeoutsakosvl346 Sep 3, 2026
60f00d1
fix(oci): reject ambiguous diagnostics
BillLeoutsakosvl346 Sep 3, 2026
f7c0b63
fix(oci): harden signed request boundaries
BillLeoutsakosvl346 Sep 3, 2026
c9eecff
fix(oci): bound and sanitize provider errors
BillLeoutsakosvl346 Sep 3, 2026
3e476e7
refactor(oci): bind requests to authorized credentials
Sep 4, 2026
fe1e8d5
feat(credentials): complete OCI API key setup
Sep 4, 2026
cf39099
test(oci): add signing and transport conformance
Sep 4, 2026
84fe75a
fix(oci): mark signing fixture as synthetic
Sep 4, 2026
71d8330
fix(oci): align authorization regression coverage
Sep 4, 2026
05c4a4e
refactor(oci): isolate credential handoff
Sep 4, 2026
1d1f773
chore(oci): minimize shared integration churn
Sep 4, 2026
4c5f6ec
fix(oci): preserve endpoint and failure invariants
Sep 4, 2026
2511962
fix(oci): enforce credential and endpoint boundaries
Sep 4, 2026
75f37ee
fix(oci): close transport review gaps
Sep 4, 2026
476a07a
fix(oci): enforce destination validation deadlines
Sep 4, 2026
0d2e254
fix(oci): stop requests after DNS deadlines
Sep 4, 2026
b22b106
refactor(oci): remove shared credential hardening
Sep 4, 2026
5055d3d
fix(oci): tighten request lifecycle
Sep 4, 2026
9abff14
fix(oci): preserve transport size errors
Sep 4, 2026
2864a4d
feat(oci): support multi-label service prefixes
Sep 5, 2026
6b6d43f
feat(oci): support region-first endpoint policies
Sep 5, 2026
1b74526
feat(oci): expose streaming and object storage response headers
Sep 5, 2026
3fa59e7
fix(oci): preserve encoded resource path separators
Sep 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/docs/components/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9405,6 +9405,8 @@ export function NetSuiteIcon(props: SVGProps<SVGSVGElement>) {
)
}

export const OracleIcon = NetSuiteIcon

export function WizaIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='0 0 51 49' fill='none' xmlns='http://www.w3.org/2000/svg'>
Expand Down
5 changes: 5 additions & 0 deletions apps/docs/content/docs/cli/credentials.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ Update Credential (personal API key required)
| `--auth-method <value>` | No | Provider authentication method. |
| `--private-key <value>` | No | Write-only PEM private key. |
| `--username <value>` | No | Provider run-as username. |
| `--tenancy-ocid <value>` | No | OCI tenancy OCID. |
| `--user-ocid <value>` | No | OCI user OCID. |
| `--fingerprint <value>` | No | OCI API-key fingerprint. |
| `--private-key-passphrase <value>` | No | Write-only OCI private-key passphrase. |
| `--region <value>` | No | OCI home region. |
| `--name <displayName>` | No | Alias for --display-name. |

</CommandTable>
Expand Down
5 changes: 5 additions & 0 deletions apps/docs/content/docs/cli/reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,11 @@ sim credentials update <credentialId> [options]
| `--auth-method <value>` | No | Provider authentication method. |
| `--private-key <value>` | No | Write-only PEM private key. |
| `--username <value>` | No | Provider run-as username. |
| `--tenancy-ocid <value>` | No | OCI tenancy OCID. |
| `--user-ocid <value>` | No | OCI user OCID. |
| `--fingerprint <value>` | No | OCI API-key fingerprint. |
| `--private-key-passphrase <value>` | No | Write-only OCI private-key passphrase. |
| `--region <value>` | No | OCI home region. |
| `--name <displayName>` | No | Alias for --display-name. |

</CommandTable>
Expand Down
30 changes: 30 additions & 0 deletions apps/docs/openapi-v2-resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -9393,6 +9393,36 @@
"type": "string",
"minLength": 1,
"maxLength": 255
},
"tenancyOcid": {
"description": "OCI tenancy OCID.",
"type": "string",
"minLength": 1,
"maxLength": 255
},
"userOcid": {
"description": "OCI user OCID.",
"type": "string",
"minLength": 1,
"maxLength": 255
},
"fingerprint": {
"description": "OCI API-key fingerprint.",
"type": "string",
"minLength": 1,
"maxLength": 128
},
"privateKeyPassphrase": {
"description": "Write-only OCI private-key passphrase.",
"writeOnly": true,
"type": "string",
"maxLength": 4096
},
"region": {
"description": "OCI home region.",
"type": "string",
"minLength": 1,
"maxLength": 128
}
},
"additionalProperties": false,
Expand Down
64 changes: 64 additions & 0 deletions apps/sim/app/api/credentials/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -550,4 +550,68 @@ describe('POST /api/credentials', () => {
expect(dbChainMockFns.insert).not.toHaveBeenCalled()
})
})

it('forwards OCI API-key fields without returning secret material', async () => {
mockVerifyAndBuildServiceAccountSecret.mockResolvedValueOnce({
providerId: 'oci-api-key-service-account',
encryptedServiceAccountKey: 'encrypted-oci-blob',
displayName: 'ocid1.user.oc1..principal',
auditMetadata: {
principalKind: 'user',
principalId: 'ocid1.user.oc1..principal',
},
principal: { kind: 'user', id: 'ocid1.user.oc1..principal' },
})
queueTableRows(credential, [])
queueTableRows(credential, [])
queueTableRows(credential, [
{
id: 'credential-oci',
workspaceId: WORKSPACE_ID,
type: 'service_account',
displayName: 'ocid1.user.oc1..principal',
description: null,
unredacted: false,
providerId: 'oci-api-key-service-account',
accountId: null,
envKey: null,
envOwnerUserId: null,
encryptedServiceAccountKey: 'encrypted-oci-blob',
createdBy: 'user-1',
createdAt: new Date('2026-08-11T00:00:00.000Z'),
updatedAt: new Date('2026-08-11T00:00:00.000Z'),
},
])

const response = await POST(
createMockRequest('POST', {
workspaceId: WORKSPACE_ID,
type: 'service_account',
providerId: 'oci-api-key-service-account',
tenancyOcid: 'ocid1.tenancy.oc1..tenant',
userOcid: 'ocid1.user.oc1..principal',
fingerprint: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff',
privateKey: '-----BEGIN PRIVATE KEY-----\nkey\n-----END PRIVATE KEY-----',
privateKeyPassphrase: ' exact passphrase ',
region: 'us-ashburn-1',
})
)
const body = await response.text()

expect(response.status).toBe(201)
expect(mockVerifyAndBuildServiceAccountSecret).toHaveBeenCalledWith(
'oci-api-key-service-account',
expect.objectContaining({
tenancyOcid: 'ocid1.tenancy.oc1..tenant',
userOcid: 'ocid1.user.oc1..principal',
fingerprint: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff',
privateKey: '-----BEGIN PRIVATE KEY-----\nkey\n-----END PRIVATE KEY-----',
privateKeyPassphrase: ' exact passphrase ',
region: 'us-ashburn-1',
})
)
expect(body).not.toContain('PRIVATE KEY')
expect(body).not.toContain('exact passphrase')
expect(body).not.toContain('encrypted-oci-blob')
})
})
27 changes: 27 additions & 0 deletions apps/sim/app/api/v2/credentials/[credentialId]/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,33 @@ describe('PATCH /api/v2/credentials/[credentialId]', () => {
expect(body).not.toContain('MUST_NOT_LEAK_CIPHERTEXT')
})

it('forwards a complete OCI rotation tuple with an omitted replacement passphrase', async () => {
const request = patchRequest({
tenancyOcid: 'ocid1.tenancy.oc1..tenant',
userOcid: 'ocid1.user.oc1..replacement',
fingerprint: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff',
privateKey: '-----BEGIN PRIVATE KEY-----\nreplacement\n-----END PRIVATE KEY-----',
region: 'us-ashburn-1',
})
const response = await PATCH(request, context)

expect(response.status).toBe(200)
expect(mocks.update).toHaveBeenCalledWith({
principal: auth.principal,
input: {
tenancyOcid: 'ocid1.tenancy.oc1..tenant',
userOcid: 'ocid1.user.oc1..replacement',
fingerprint: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff',
privateKey: '-----BEGIN PRIVATE KEY-----\nreplacement\n-----END PRIVATE KEY-----',
region: 'us-ashburn-1',
credentialId: CREDENTIAL_ID,
assertedWorkspaceId: WORKSPACE_ID,
},
request,
})
expect(JSON.stringify(await response.json())).not.toContain('PRIVATE KEY')
})

it('asserts the workspace scope and preserves the credential id', async () => {
const request = patchRequest({ displayName: 'Zoom prod' })
await PATCH(request, context)
Expand Down
44 changes: 44 additions & 0 deletions apps/sim/app/api/v2/credentials/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,11 +288,55 @@ describe('POST /api/v2/credentials', () => {
authMethod: undefined,
privateKey: undefined,
username: undefined,
tenancyOcid: undefined,
userOcid: undefined,
fingerprint: undefined,
privateKeyPassphrase: undefined,
region: undefined,
},
request,
})
})

it('forwards OCI credential fields from the write-only credentials envelope', async () => {
const request = new NextRequest('http://localhost:3000/api/v2/credentials', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
workspaceId: WORKSPACE_ID,
type: 'service_account',
providerId: 'oci-api-key-service-account',
credentials: JSON.stringify({
tenancyOcid: 'ocid1.tenancy.oc1..tenant',
userOcid: 'ocid1.user.oc1..user',
fingerprint: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff',
privateKey: '-----BEGIN PRIVATE KEY-----\nkey\n-----END PRIVATE KEY-----',
privateKeyPassphrase: ' exact passphrase ',
region: 'us-ashburn-1',
}),
}),
})
const response = await POST(request)
const body = await response.text()

expect(response.status).toBe(201)
expect(mocks.create).toHaveBeenCalledWith({
principal: { kind: 'personal_api_key', userId: 'user-1', keyId: 'key-1' },
input: expect.objectContaining({
providerId: 'oci-api-key-service-account',
tenancyOcid: 'ocid1.tenancy.oc1..tenant',
userOcid: 'ocid1.user.oc1..user',
fingerprint: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff',
privateKey: '-----BEGIN PRIVATE KEY-----\nkey\n-----END PRIVATE KEY-----',
privateKeyPassphrase: ' exact passphrase ',
region: 'us-ashburn-1',
}),
request,
})
expect(body).not.toContain('PRIVATE KEY')
expect(body).not.toContain('exact passphrase')
})

it('rejects an unknown service-account provider before the use case', async () => {
const response = await POST(
new NextRequest('http://localhost:3000/api/v2/credentials', {
Expand Down
Loading
Loading