Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 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
9df7986
fix(oci): accept Oracle API key download markers
Sep 7, 2026
22df743
fix(oci): require a single downloaded PEM key block
Sep 7, 2026
2d620d0
feat(oci-events): add native Events integration
Sep 6, 2026
868a76c
Merge staging into OCI foundation and resolve credential compatibilit…
Oct 3, 2026
71cd1c8
Fix canonical OCI docs icon generation after staging merge
Oct 3, 2026
43ce72d
Merge feat/oci-foundation and resolve PR #7544 conflicts
Oct 3, 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
6 changes: 5 additions & 1 deletion apps/docs/components/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9500,7 +9500,7 @@ export function NewRelicIcon(props: SVGProps<SVGSVGElement>) {
)
}

export function NetSuiteIcon(props: SVGProps<SVGSVGElement>) {
export function OracleIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='0 0 93.9 59.4' xmlns='http://www.w3.org/2000/svg'>
<path
Expand All @@ -9511,6 +9511,10 @@ export function NetSuiteIcon(props: SVGProps<SVGSVGElement>) {
)
}

export function NetSuiteIcon(props: SVGProps<SVGSVGElement>) {
return <OracleIcon {...props} />
}

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
3 changes: 3 additions & 0 deletions apps/docs/components/ui/icon-mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ import {
OktaIcon,
OnePasswordIcon,
OpenAIIcon,
OracleIcon,
OtterIcon,
OutlookIcon,
PackageSearchIcon,
Expand Down Expand Up @@ -543,6 +544,8 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
notion: NotionIcon,
notion_v2: NotionIcon,
obsidian: ObsidianIcon,
oci: OracleIcon,
oci_events: NetSuiteIcon,
okta: OktaIcon,
onedrive: MicrosoftOneDriveIcon,
onepassword: OnePasswordIcon,
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 @@ -114,6 +114,11 @@ Update Credential (OAuth login or 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 @@ -547,6 +547,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
1 change: 1 addition & 0 deletions apps/docs/content/docs/integrations/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@
"notion",
"notion-service-account",
"obsidian",
"oci_events",
"okta",
"onedrive",
"onepassword",
Expand Down
175 changes: 175 additions & 0 deletions apps/docs/content/docs/integrations/oci_events.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
---
title: OCI Events
description: Discover and manage OCI event routing rules
---

import { BlockInfoCard } from "@/components/ui/block-info-card"

<BlockInfoCard
type="oci_events"
color="#FFFFFF"
/>

## Usage Instructions

Manage OCI Events rules using a reusable OCI API signing-key credential. List and inspect rules, create routing to existing Notifications topics, Streaming streams or Functions, update conditions and enabled states, move rules, and delete rules. Conditions match events in the rule compartment and child compartments. Updates replace supplied actions and tag maps; omit fields to retain them and use an ETag to protect concurrent changes. IAM must permit rule management and the selected action destinations. Sim limits requests to 1 MiB, responses to 8 MiB and each JSON input to 10000 values, 32 nesting levels and 1 MiB of text. This integration manages routing configuration; it does not receive events or start Sim workflows. Topic subscriptions, stream consumption and function management belong to their respective services.



## Actions

### OCI Events List Rules

List one page of OCI Events rules in a compartment

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `oauthCredential` | string | Yes | Reusable OCI API signing-key credential. |
| `region` | string | No | OCI region override; omit to use the credential region. |
| `opcRequestId` | string | No | Optional request identifier for OCI support correlation. |
| `compartmentId` | string | Yes | Compartment OCID for listing or creating rules. |
| `limit` | number | No | Maximum rules on this page: 1–50; defaults to 10. |
| `page` | string | No | Opaque nextPage from the preceding list response. |
| `displayName` | string | No | Rule display name; list operations apply the OCI displayName filter. |
| `lifecycleState` | string | No | Filter: CREATING, ACTIVE, INACTIVE, UPDATING, DELETING, DELETED or FAILED. |
| `sortBy` | string | No | Sort field: TIME_CREATED, ID or DISPLAY_NAME. |
| `sortOrder` | string | No | Sort direction: ASC or DESC. |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `status` | number | OCI HTTP response status |
| `opcRequestId` | string | OCI request identifier |
| `rules` | array | One page of rule summaries; actions require Get Rule |
| `nextPage` | string | Opaque continuation token |

### OCI Events Get Rule

Get an OCI Events rule with its actions and ETag

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `oauthCredential` | string | Yes | Reusable OCI API signing-key credential. |
| `region` | string | No | OCI region override; omit to use the credential region. |
| `opcRequestId` | string | No | Optional request identifier for OCI support correlation. |
| `ruleId` | string | Yes | Rule OCID, from List Rules or a previous rule response. |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `status` | number | OCI HTTP response status |
| `opcRequestId` | string | OCI request identifier |
| `rule` | json | Rule configuration including its actions |
| `etag` | string | ETag for conditional updates, moves or deletion |

### OCI Events Create Rule

Create an OCI Events rule routing matching events to existing action resources

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `oauthCredential` | string | Yes | Reusable OCI API signing-key credential. |
| `region` | string | No | OCI region override; omit to use the credential region. |
| `opcRequestId` | string | No | Optional request identifier for OCI support correlation. |
| `compartmentId` | string | Yes | Compartment OCID for listing or creating rules. |
| `displayName` | string | Yes | Rule display name; list operations apply the OCI displayName filter. |
| `description` | string | No | Rule description, up to 1024 characters. An explicit empty string clears it on update. |
| `isEnabled` | boolean | Yes | Whether the rule is enabled. Omit on update to keep the current state. |
| `condition` | json | Yes | JSON filter object, for example \{"eventType":"com.oraclecloud.objectstorage.createbucket"\}. Explicit \{\} matches all compartment and child-compartment events. Replaces the condition on update. |
| `actions` | json | Yes | Array of 1–10 actions. Each requires actionType, isEnabled and topicId \(ONS\), streamId \(OSS\) or functionId \(FAAS\); description is optional. Replaces all actions on update. No action IDs or lifecycle fields. |
| `freeformTags` | json | No | Map of tag names to string values. Replaces all freeform tags on update; \{\} clears them. |
| `definedTags` | json | No | Map of tag namespaces to tag-name/string-value maps. Replaces defined tags on update; \{\} clears them. |
| `opcRetryToken` | string | No | Optional stable retry token, 1–64 characters. Reuse for retries of the same create or move request. |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `status` | number | OCI HTTP response status |
| `opcRequestId` | string | OCI request identifier |
| `rule` | json | Rule configuration including its actions |
| `etag` | string | ETag for conditional updates, moves or deletion |

### OCI Events Update Rule

Update rule settings and replace supplied conditions, actions or tags

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `oauthCredential` | string | Yes | Reusable OCI API signing-key credential. |
| `region` | string | No | OCI region override; omit to use the credential region. |
| `opcRequestId` | string | No | Optional request identifier for OCI support correlation. |
| `ruleId` | string | Yes | Rule OCID, from List Rules or a previous rule response. |
| `displayName` | string | No | Rule display name; list operations apply the OCI displayName filter. |
| `description` | string | No | Rule description, up to 1024 characters. An explicit empty string clears it on update. |
| `isEnabled` | boolean | No | Whether the rule is enabled. Omit on update to keep the current state. |
| `condition` | json | No | JSON filter object, for example \{"eventType":"com.oraclecloud.objectstorage.createbucket"\}. Explicit \{\} matches all compartment and child-compartment events. Replaces the condition on update. |
| `actions` | json | No | Array of 1–10 actions. Each requires actionType, isEnabled and topicId \(ONS\), streamId \(OSS\) or functionId \(FAAS\); description is optional. Replaces all actions on update. No action IDs or lifecycle fields. |
| `freeformTags` | json | No | Map of tag names to string values. Replaces all freeform tags on update; \{\} clears them. |
| `definedTags` | json | No | Map of tag namespaces to tag-name/string-value maps. Replaces defined tags on update; \{\} clears them. |
| `ifMatch` | string | No | ETag from Get Rule; mutation fails if the rule changed since that read. |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `status` | number | OCI HTTP response status |
| `opcRequestId` | string | OCI request identifier |
| `rule` | json | Rule configuration including its actions |
| `etag` | string | ETag for conditional updates, moves or deletion |

### OCI Events Delete Rule

Delete an OCI Events rule, optionally matching an ETag

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `oauthCredential` | string | Yes | Reusable OCI API signing-key credential. |
| `region` | string | No | OCI region override; omit to use the credential region. |
| `opcRequestId` | string | No | Optional request identifier for OCI support correlation. |
| `ruleId` | string | Yes | Rule OCID, from List Rules or a previous rule response. |
| `ifMatch` | string | No | ETag from Get Rule; mutation fails if the rule changed since that read. |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `status` | number | OCI HTTP response status |
| `opcRequestId` | string | OCI request identifier |

### OCI Events Change Rule Compartment

Move an OCI Events rule to another compartment in the same tenancy

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `oauthCredential` | string | Yes | Reusable OCI API signing-key credential. |
| `region` | string | No | OCI region override; omit to use the credential region. |
| `opcRequestId` | string | No | Optional request identifier for OCI support correlation. |
| `ruleId` | string | Yes | Rule OCID, from List Rules or a previous rule response. |
| `destinationCompartmentId` | string | Yes | Destination compartment OCID in the same tenancy; moving changes event matching scope. |
| `ifMatch` | string | No | ETag from Get Rule; mutation fails if the rule changed since that read. |
| `opcRetryToken` | string | No | Optional stable retry token, 1–64 characters. Reuse for retries of the same create or move request. |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `status` | number | OCI HTTP response status |
| `opcRequestId` | string | OCI request identifier |


30 changes: 30 additions & 0 deletions apps/docs/openapi-v2-resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -13928,6 +13928,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 @@ -345,4 +345,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 @@ -121,6 +121,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('clears a description with an explicit null and leaves an omitted field alone', async () => {
await PATCH(patchRequest({ description: null }), context)

Expand Down
Loading