Skip to content

Commit 72a2469

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix(oci): align block and tests with current CI contracts
1 parent 46f8f75 commit 72a2469

11 files changed

Lines changed: 83 additions & 73 deletions

File tree

‎apps/docs/openapi-v2-workflows.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16912,6 +16912,8 @@
1691216912
"notion.pages",
1691316913
"netsuite.recordTypes",
1691416914
"netsuite.asyncTasks",
16915+
"oci_object_storage.buckets",
16916+
"oci_object_storage.objects",
1691516917
"pipedrive.pipelines",
1691616918
"sharepoint.lists",
1691716919
"trello.boards",
@@ -17094,6 +17096,8 @@
1709417096
"notion.pages",
1709517097
"netsuite.recordTypes",
1709617098
"netsuite.asyncTasks",
17099+
"oci_object_storage.buckets",
17100+
"oci_object_storage.objects",
1709717101
"pipedrive.pipelines",
1709817102
"sharepoint.lists",
1709917103
"trello.boards",

‎apps/sim/blocks/blocks/oci_object_storage.ts‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { getScopesForService } from '@/lib/oauth/utils'
33
import type { BlockConfig, BlockMeta } from '@/blocks/types'
44
import { AuthMode, IntegrationType } from '@/blocks/types'
55
import { normalizeFileInput, parseOptionalNumberInput } from '@/blocks/utils'
6-
import type { OciObjectStorageResponse } from '@/tools/oci_object_storage/types'
76

87
const OBJECT_OPERATIONS = [
98
'oci_object_storage_upload_object',
@@ -22,7 +21,7 @@ const BUCKET_OPERATIONS = ['oci_object_storage_list_objects', ...OBJECT_OPERATIO
2221

2322
const UPLOAD_SOURCE_FIELD = ['uploadFile', 'fileReference', 'content'] as const
2423

25-
export const OciObjectStorageBlock: BlockConfig<OciObjectStorageResponse> = {
24+
export const OciObjectStorageBlock: BlockConfig = {
2625
type: 'oci_object_storage',
2726
name: 'OCI Object Storage',
2827
description: 'List, upload, download, inspect, and delete objects in Oracle Cloud',

‎apps/sim/lib/credentials/oci-object-storage-service-account.test.ts‎

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
*/
44
import { ListBucketsCommand, S3Client } from '@aws-sdk/client-s3'
55
import { credential } from '@sim/db/schema'
6-
import { queueTableRows, resetDbChainMock } from '@sim/testing'
6+
import { queueTableRows, resetDbChainMock } from '@sim/testing/mocks/database.mock'
7+
import { encryptionMock, encryptionMockFns } from '@sim/testing/mocks/encryption.mock'
78
import { beforeEach, describe, expect, it, vi } from 'vitest'
89

9-
const mocks = vi.hoisted(() => ({ decryptSecret: vi.fn() }))
10-
11-
vi.mock('@/lib/core/security/encryption', () => ({ decryptSecret: mocks.decryptSecret }))
10+
vi.mock('@/lib/core/security/encryption', () => encryptionMock)
1211

1312
import {
1413
getOciObjectStorageServiceAccountSecret,
@@ -34,10 +33,8 @@ const storedBlob = JSON.stringify({
3433

3534
describe('OCI Object Storage service-account credential', () => {
3635
beforeEach(() => {
37-
vi.restoreAllMocks()
38-
vi.clearAllMocks()
3936
resetDbChainMock()
40-
mocks.decryptSecret.mockResolvedValue({ decrypted: storedBlob })
37+
encryptionMockFns.mockDecryptSecret.mockReset().mockResolvedValue({ decrypted: storedBlob })
4138
})
4239

4340
it('validates the connection with ListBuckets and derives the owner identity', async () => {
@@ -102,7 +99,7 @@ describe('OCI Object Storage service-account credential', () => {
10299
region: 'us-ashburn-1',
103100
ownerId: 'ocid1.user.oc1..owner',
104101
})
105-
expect(mocks.decryptSecret).toHaveBeenCalledWith('ciphertext')
102+
expect(encryptionMockFns.mockDecryptSecret).toHaveBeenCalledWith('ciphertext')
106103
})
107104

108105
it('rejects a wrong provider before decrypting and rejects a wrong blob discriminator', async () => {
@@ -116,7 +113,7 @@ describe('OCI Object Storage service-account credential', () => {
116113
await expect(getOciObjectStorageServiceAccountSecret('credential-1')).rejects.toThrow(
117114
'OCI Object Storage credential not found'
118115
)
119-
expect(mocks.decryptSecret).not.toHaveBeenCalled()
116+
expect(encryptionMockFns.mockDecryptSecret).not.toHaveBeenCalled()
120117

121118
resetDbChainMock()
122119
queueTableRows(credential, [
@@ -127,7 +124,7 @@ describe('OCI Object Storage service-account credential', () => {
127124
encryptedServiceAccountKey: 'ciphertext',
128125
},
129126
])
130-
mocks.decryptSecret.mockResolvedValue({
127+
encryptionMockFns.mockDecryptSecret.mockResolvedValue({
131128
decrypted: storedBlob.replace(
132129
OCI_OBJECT_STORAGE_SERVICE_ACCOUNT_SECRET_TYPE,
133130
'atlassian_service_account'

‎apps/sim/lib/credentials/oci-object-storage-service-account.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export class OciObjectStorageCredentialError extends Error {
6363
}
6464
}
6565

66-
export function normalizeOciObjectStorageCredentialFields(
66+
function normalizeOciObjectStorageCredentialFields(
6767
fields: OciObjectStorageCredentialFields
6868
): OciObjectStorageCredentialFields {
6969
const accessKeyId = fields.accessKeyId.trim()

‎apps/sim/lib/internal/oci-object-storage/client.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { OciObjectStorageOperationError } from '@/lib/internal/oci-object-storag
99
export const OCI_LIST_BUCKETS_MAX_RESPONSE_BYTES = 8 * 1024 * 1024
1010
export const OCI_LIST_BUCKETS_MAX_RESULTS = 10_000
1111

12-
export const OCI_OBJECT_STORAGE_COMMERCIAL_REGIONS = [
12+
const OCI_OBJECT_STORAGE_COMMERCIAL_REGIONS = [
1313
'af-casablanca-1',
1414
'af-johannesburg-1',
1515
'ap-batam-1',

‎apps/sim/lib/internal/oci-object-storage/execute-tool.test.ts‎

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/**
22
* @vitest-environment node
33
*/
4-
import { beforeEach, describe, expect, it, vi } from 'vitest'
4+
import { getMockLogger } from '@sim/testing/mocks/logger.mock'
5+
import { describe, expect, it, vi } from 'vitest'
56
import { PayloadSizeLimitError } from '@/lib/core/utils/stream-limits'
67

78
const mocks = vi.hoisted(() => ({
@@ -11,14 +12,8 @@ const mocks = vi.hoisted(() => ({
1112
downloadObject: vi.fn(),
1213
headObject: vi.fn(),
1314
deleteObject: vi.fn(),
14-
logger: {
15-
warn: vi.fn(),
16-
error: vi.fn(),
17-
},
1815
}))
1916

20-
vi.mock('@sim/logger', () => ({ createLogger: () => mocks.logger }))
21-
2217
vi.mock('@/lib/internal/oci-object-storage/operations', () => ({
2318
executeOciObjectStorageListBuckets: mocks.listBuckets,
2419
executeOciObjectStorageListObjects: mocks.listObjects,
@@ -37,6 +32,8 @@ import { ociObjectStorageListBucketsTool } from '@/tools/oci_object_storage/list
3732
import { ociObjectStorageListObjectsTool } from '@/tools/oci_object_storage/list_objects'
3833
import { ociObjectStorageUploadObjectTool } from '@/tools/oci_object_storage/upload_object'
3934

35+
const logger = getMockLogger('OciObjectStorageToolExecution')
36+
4037
function request(toolId: string, input: Record<string, unknown>) {
4138
return {
4239
toolId,
@@ -47,8 +44,6 @@ function request(toolId: string, input: Record<string, unknown>) {
4744
}
4845

4946
describe('OCI Object Storage tool execution boundary', () => {
50-
beforeEach(() => vi.clearAllMocks())
51-
5247
it.each([
5348
[ociObjectStorageListBucketsTool, mocks.listBuckets],
5449
[ociObjectStorageListObjectsTool, mocks.listObjects],
@@ -58,6 +53,8 @@ describe('OCI Object Storage tool execution boundary', () => {
5853
[ociObjectStorageDeleteObjectTool, mocks.deleteObject],
5954
] as const)('projects native workflow inputs for $0.id', async (tool, execute) => {
6055
execute.mockResolvedValue({ success: true, output: {} })
56+
const mapParams = OciObjectStorageBlock.tools.config?.params
57+
if (!mapParams) throw new Error('Expected OCI Object Storage block parameter mapping')
6158
for (const blank of [null, '', undefined]) {
6259
const raw = {
6360
operation: tool.id,
@@ -79,7 +76,7 @@ describe('OCI Object Storage tool execution boundary', () => {
7976
startAfter: blank,
8077
continuationToken: blank,
8178
}
82-
const params = { ...raw, ...OciObjectStorageBlock.tools.config!.params!(raw) }
79+
const params = { ...raw, ...mapParams(raw) }
8380
const response = await executeOciObjectStorageTool(
8481
request(tool.id, tool.operation.input(params))
8582
)
@@ -129,11 +126,11 @@ describe('OCI Object Storage tool execution boundary', () => {
129126
expect(body.error).toContain(text)
130127
expect(JSON.stringify(body)).not.toContain('secret-key-canary')
131128
if (status >= 500) {
132-
expect(mocks.logger.error).toHaveBeenCalledOnce()
133-
expect(mocks.logger.warn).not.toHaveBeenCalled()
129+
expect(logger.error).toHaveBeenCalledOnce()
130+
expect(logger.warn).not.toHaveBeenCalled()
134131
} else {
135-
expect(mocks.logger.warn).toHaveBeenCalledOnce()
136-
expect(mocks.logger.error).not.toHaveBeenCalled()
132+
expect(logger.warn).toHaveBeenCalledOnce()
133+
expect(logger.error).not.toHaveBeenCalled()
137134
}
138135
}
139136
)
@@ -156,8 +153,8 @@ describe('OCI Object Storage tool execution boundary', () => {
156153
success: false,
157154
error: 'Oracle Object Storage request failed',
158155
})
159-
expect(mocks.logger.error).toHaveBeenCalledOnce()
160-
expect(mocks.logger.warn).not.toHaveBeenCalled()
156+
expect(logger.error).toHaveBeenCalledOnce()
157+
expect(logger.warn).not.toHaveBeenCalled()
161158
}
162159
)
163160

‎apps/sim/lib/internal/oci-object-storage/operations.test.ts‎

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,21 @@ import {
1010
ListObjectsV2Command,
1111
PutObjectCommand,
1212
} from '@aws-sdk/client-s3'
13+
import {
14+
fileUtilsServerMock,
15+
fileUtilsServerMockFns,
16+
} from '@sim/testing/mocks/file-utils-server.mock'
17+
import { fileUtilsMock, fileUtilsMockFns } from '@sim/testing/mocks/file-utils.mock'
18+
import {
19+
filesAuthorizationMock,
20+
filesAuthorizationMockFns,
21+
} from '@sim/testing/mocks/files-authorization.mock'
1322
import { beforeEach, describe, expect, it, vi } from 'vitest'
1423
import { PayloadSizeLimitError } from '@/lib/core/utils/stream-limits'
1524

1625
const mocks = vi.hoisted(() => ({
1726
send: vi.fn(),
1827
getSecret: vi.fn(),
19-
assertToolFileAccess: vi.fn(),
20-
processSingleFile: vi.fn(),
21-
downloadServableFile: vi.fn(),
2228
attempts: vi.fn(),
2329
}))
2430

@@ -38,15 +44,9 @@ vi.mock('@/lib/internal/oci-object-storage/client', () => ({
3844
sendOciListBuckets: (client: { send: typeof mocks.send }, signal?: AbortSignal) =>
3945
client.send(new ListBucketsCommand({}), { abortSignal: signal }),
4046
}))
41-
vi.mock('@/app/api/files/authorization', () => ({
42-
assertToolFileAccess: mocks.assertToolFileAccess,
43-
}))
44-
vi.mock('@/lib/uploads/utils/file-utils', () => ({
45-
processSingleFileToUserFile: mocks.processSingleFile,
46-
}))
47-
vi.mock('@/lib/uploads/utils/file-utils.server', () => ({
48-
downloadServableFileFromStorage: mocks.downloadServableFile,
49-
}))
47+
vi.mock('@/app/api/files/authorization', () => filesAuthorizationMock)
48+
vi.mock('@/lib/uploads/utils/file-utils', () => fileUtilsMock)
49+
vi.mock('@/lib/uploads/utils/file-utils.server', () => fileUtilsServerMock)
5050

5151
import {
5252
executeOciObjectStorageDeleteObject,
@@ -57,20 +57,25 @@ import {
5757
executeOciObjectStorageUploadObject,
5858
} from '@/lib/internal/oci-object-storage/operations'
5959

60+
const assertToolFileAccess = filesAuthorizationMockFns.mockAssertToolFileAccess
61+
const processSingleFile = fileUtilsMockFns.mockProcessSingleFileToUserFile
62+
const downloadServableFile = fileUtilsServerMockFns.mockDownloadServableFileFromStorage
63+
6064
const credential = { credentialId: 'credential-1' }
6165
const object = { ...credential, bucketName: 'bucket-name', objectKey: 'folder/report.txt' }
6266
const context = { userId: 'user-1', requestId: 'request-1' }
6367

6468
describe('OCI Object Storage operations', () => {
6569
beforeEach(() => {
66-
vi.clearAllMocks()
70+
assertToolFileAccess.mockReset()
71+
processSingleFile.mockReset()
72+
downloadServableFile.mockReset()
6773
mocks.getSecret.mockResolvedValue({
6874
accessKeyId: 'access',
6975
secretAccessKey: 'secret',
7076
namespace: 'namespace1',
7177
region: 'us-ashburn-1',
7278
})
73-
mocks.assertToolFileAccess.mockResolvedValue(null)
7479
})
7580

7681
it('maps empty and populated bucket listings with owner identity', async () => {
@@ -172,8 +177,8 @@ describe('OCI Object Storage operations', () => {
172177

173178
it('authorizes a referenced file before reading and uploads exact-limit bytes', async () => {
174179
const file = { name: 'report.txt', key: 'workspace/file-1', size: 5, type: 'text/plain' }
175-
mocks.processSingleFile.mockReturnValue(file)
176-
mocks.downloadServableFile.mockResolvedValue({
180+
processSingleFile.mockReturnValue(file)
181+
downloadServableFile.mockResolvedValue({
177182
buffer: Buffer.from('12345'),
178183
contentType: 'text/plain',
179184
})
@@ -184,16 +189,16 @@ describe('OCI Object Storage operations', () => {
184189
context
185190
)
186191

187-
expect(mocks.assertToolFileAccess).toHaveBeenCalledWith(
192+
expect(assertToolFileAccess).toHaveBeenCalledWith(
188193
'workspace/file-1',
189194
'user-1',
190195
'request-1',
191196
expect.anything()
192197
)
193-
expect(mocks.assertToolFileAccess.mock.invocationCallOrder[0]).toBeLessThan(
194-
mocks.downloadServableFile.mock.invocationCallOrder[0]
198+
expect(assertToolFileAccess.mock.invocationCallOrder[0]).toBeLessThan(
199+
downloadServableFile.mock.invocationCallOrder[0]
195200
)
196-
expect(mocks.downloadServableFile).toHaveBeenCalledWith(file, 'request-1', expect.anything(), {
201+
expect(downloadServableFile).toHaveBeenCalledWith(file, 'request-1', expect.anything(), {
197202
maxBytes: 5,
198203
signal: undefined,
199204
})
@@ -219,9 +224,9 @@ describe('OCI Object Storage operations', () => {
219224
{ requestId: 'request-1' }
220225
)
221226
).rejects.toMatchObject({ status: 401, message: 'Authentication required' })
222-
expect(mocks.processSingleFile).not.toHaveBeenCalled()
223-
expect(mocks.assertToolFileAccess).not.toHaveBeenCalled()
224-
expect(mocks.downloadServableFile).not.toHaveBeenCalled()
227+
expect(processSingleFile).not.toHaveBeenCalled()
228+
expect(assertToolFileAccess).not.toHaveBeenCalled()
229+
expect(downloadServableFile).not.toHaveBeenCalled()
225230
expect(mocks.send).not.toHaveBeenCalled()
226231
})
227232

@@ -232,15 +237,15 @@ describe('OCI Object Storage operations', () => {
232237
size: 6,
233238
type: 'application/octet-stream',
234239
}
235-
mocks.processSingleFile.mockReturnValue(file)
236-
mocks.downloadServableFile.mockRejectedValue(
240+
processSingleFile.mockReturnValue(file)
241+
downloadServableFile.mockRejectedValue(
237242
new PayloadSizeLimitError({ label: 'OCI file upload', maxBytes: 5, observedBytes: 6 })
238243
)
239244

240245
await expect(
241246
executeOciObjectStorageUploadObject({ ...object, file: file as never }, context)
242247
).rejects.toBeInstanceOf(PayloadSizeLimitError)
243-
expect(mocks.assertToolFileAccess).toHaveBeenCalledOnce()
248+
expect(assertToolFileAccess).toHaveBeenCalledOnce()
244249
expect(mocks.send).not.toHaveBeenCalled()
245250
})
246251

‎apps/sim/lib/internal/oci-object-storage/schema.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { z } from 'zod'
22
import { MAX_BUFFERED_TRANSFER_BYTES } from '@/lib/uploads/shared/types'
33
import { RawFileInputSchema } from '@/lib/uploads/utils/file-schemas'
44

5-
export const OCI_BUCKET_NAME_MAX_LENGTH = 256
6-
export const OCI_OBJECT_NAME_MAX_BYTES = 1_024
5+
const OCI_BUCKET_NAME_MAX_LENGTH = 256
6+
const OCI_OBJECT_NAME_MAX_BYTES = 1_024
77
export const OCI_CONTINUATION_TOKEN_MAX_LENGTH = 1_024
88

99
const OCI_BUCKET_NAME_PATTERN = /^[A-Za-z0-9._-]+$/

‎apps/sim/lib/selectors/server/providers/oci-object-storage.test.ts‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ async function prepare(input: ExecuteServerSelectorArgs) {
7171

7272
describe('OCI Object Storage selectors', () => {
7373
beforeEach(() => {
74-
vi.clearAllMocks()
7574
mocks.getSecret.mockResolvedValue({
7675
accessKeyId: 'access-key-canary',
7776
secretAccessKey: 'secret-key-canary',

0 commit comments

Comments
 (0)