Skip to content

Commit 36f909d

Browse files
committed
Merge branch 'main' into cezudas/OPS-3888
2 parents 1bb0e51 + 6ee6158 commit 36f909d

100 files changed

Lines changed: 3156 additions & 2652 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

THIRD_PARTY_LICENSES.txt

Lines changed: 291 additions & 176 deletions
Large diffs are not rendered by default.

package-lock.json

Lines changed: 1741 additions & 2021 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@
185185
"dotenv": "16.4.5",
186186
"embla-carousel-react": "8.1.8",
187187
"fast-deep-equal": "3.1.3",
188-
"fastify": "5.4.0",
188+
"fastify": "5.8.2",
189189
"fastify-favicon": "5.0.0",
190190
"fastify-plugin": "5.0.1",
191191
"fastify-raw-body": "5.0.0",

packages/blocks/aws/src/lib/actions/get-price-action.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { Property, createAction } from '@openops/blocks-framework';
33
import {
44
amazonAuth,
55
getAttributeValues,
6+
getAwsAccountsSingleSelectDropdown,
7+
getCredentialsForAccount,
68
getCredentialsFromAuth,
79
getPriceListWithCache,
810
getServices,
@@ -17,12 +19,13 @@ export const getPriceAction = createAction({
1719
displayName: 'Get Price from Price Catalog',
1820
isWriteAction: false,
1921
props: {
22+
account: getAwsAccountsSingleSelectDropdown().accounts,
2023
service: Property.Dropdown({
2124
displayName: 'Service Code',
2225
description: 'Service code for which to fetch the price',
23-
refreshers: ['auth'],
26+
refreshers: ['auth', 'account', 'account.accounts'],
2427
required: true,
25-
options: async ({ auth }: any) => {
28+
options: async ({ auth, account }: any) => {
2629
if (!auth) {
2730
return {
2831
disabled: true,
@@ -31,8 +34,11 @@ export const getPriceAction = createAction({
3134
};
3235
}
3336

34-
const credentials = await getCredentialsFromAuth(auth);
3537
try {
38+
const credentials = await getCredentialsForAccount(
39+
auth,
40+
account?.['accounts'],
41+
);
3642
const services = await getServices(credentials, PRICING_REGION);
3743

3844
if (!services.length) {
@@ -66,8 +72,8 @@ export const getPriceAction = createAction({
6672
displayName: '',
6773
description: '',
6874
required: true,
69-
refreshers: ['auth', 'service'],
70-
props: async ({ auth, service }, { input }) => {
75+
refreshers: ['auth', 'account', 'account.accounts', 'service'],
76+
props: async ({ auth, account, service }, { input }) => {
7177
if (!auth || !service) {
7278
return {};
7379
}
@@ -101,7 +107,10 @@ export const getPriceAction = createAction({
101107
};
102108
}
103109

104-
const credentials = await getCredentialsFromAuth(auth);
110+
const credentials = await getCredentialsForAccount(
111+
auth,
112+
account?.['accounts'],
113+
);
105114
try {
106115
const attributeValues: AttributeValue[] =
107116
await getAttributeValues(
@@ -139,17 +148,20 @@ export const getPriceAction = createAction({
139148
},
140149
async run(context) {
141150
try {
142-
const { service, queryFilters } = context.propsValue;
151+
const { account, service, queryFilters } = context.propsValue;
143152
const filters = queryFilters['queryFilters'].map((filter: any) => {
144153
return {
145154
Field: filter.attributeName,
146155
Type: FilterType.TERM_MATCH,
147156
Value: filter.attributeValue,
148157
};
149158
});
159+
const credentials = account?.['accounts']
160+
? await getCredentialsForAccount(context.auth, account['accounts'])
161+
: await getCredentialsFromAuth(context.auth);
150162

151163
const priceList = getPriceListWithCache(
152-
context.auth,
164+
credentials,
153165
service.ServiceCode!,
154166
filters,
155167
PRICING_REGION,

packages/blocks/aws/test/get-price-action.test.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const openopsCommonMock = {
22
...jest.requireActual('@openops/common'),
33
getCredentialsFromAuth: jest.fn(),
4+
getCredentialsForAccount: jest.fn(),
45
getAttributeValues: jest.fn(),
56
getServices: jest.fn(),
67
getPriceListWithCache: jest.fn(),
@@ -18,6 +19,9 @@ describe('getPriceAction', () => {
1819
openopsCommonMock.getCredentialsFromAuth.mockResolvedValue({
1920
someCreds: 'some value',
2021
});
22+
openopsCommonMock.getCredentialsForAccount.mockResolvedValue({
23+
someCreds: 'some value',
24+
});
2125
});
2226

2327
const auth = {
@@ -34,12 +38,16 @@ describe('getPriceAction', () => {
3438
},
3539
auth: auth,
3640
propsValue: {
37-
accountId: 'some account id',
41+
account: { accounts: 'some account id' },
3842
},
3943
};
4044

4145
test('should create action with correct properties', () => {
4246
expect(getPriceAction.props).toMatchObject({
47+
account: {
48+
type: 'DYNAMIC',
49+
required: true,
50+
},
4351
service: {
4452
type: 'DROPDOWN',
4553
required: true,
@@ -80,22 +88,40 @@ describe('getPriceAction', () => {
8088

8189
expect(openopsCommonMock.getPriceListWithCache).toHaveBeenCalledTimes(1);
8290
expect(openopsCommonMock.getPriceListWithCache).toHaveBeenCalledWith(
83-
auth,
91+
{ someCreds: 'some value' },
8492
'some service',
8593
expectedFilters,
8694
'us-east-1',
8795
);
96+
expect(openopsCommonMock.getCredentialsForAccount).toHaveBeenCalledWith(
97+
auth,
98+
'some account id',
99+
);
88100
},
89101
);
90102

103+
test('should fallback to getCredentialsFromAuth when account is missing in run', async () => {
104+
openopsCommonMock.getPriceListWithCache.mockResolvedValue('mockResult');
105+
context.propsValue = {
106+
service: { ServiceCode: 'some service' },
107+
queryFilters: { queryFilters: [] },
108+
};
109+
110+
const result = (await getPriceAction.run(context)) as any;
111+
112+
expect(result).toEqual('mockResult');
113+
expect(openopsCommonMock.getCredentialsFromAuth).toHaveBeenCalledWith(auth);
114+
expect(openopsCommonMock.getCredentialsForAccount).not.toHaveBeenCalled();
115+
});
116+
91117
test('should return the list of services in property service', async () => {
92118
openopsCommonMock.getServices.mockResolvedValue([
93119
{ ServiceCode: 'service1' },
94120
{ ServiceCode: 'service2' },
95121
]);
96122

97123
const result = await getPriceAction.props['service'].options(
98-
{ auth },
124+
{ auth, account: { accounts: 'some account id' } },
99125
context,
100126
);
101127

@@ -118,6 +144,7 @@ describe('getPriceAction', () => {
118144
ServiceCode: 'some service',
119145
AttributeNames: ['some attibute'],
120146
};
147+
context.propsValue.account = { accounts: 'some account id' };
121148
context.propsValue.auth = auth;
122149
context.input = { attributeName: 'some attibute' };
123150

packages/engine/src/lib/handler/context/engine-constants.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
TestRunLimitSettings,
1515
TriggerHookType,
1616
} from '@openops/shared';
17+
import { parseJsonResponse } from '../../helper/response-helper';
1718
import {
1819
createPropsResolver,
1920
PropsResolver,
@@ -232,7 +233,7 @@ export class EngineConstants {
232233
},
233234
});
234235

235-
return (await response.json()) as Project;
236+
return parseJsonResponse<Project>(response);
236237
}
237238
}
238239

packages/engine/src/lib/helper/execution-errors.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,17 @@ export class FetchError extends ExecutionError {
100100
}
101101
}
102102

103+
export class InfrastructureError extends ExecutionError {
104+
constructor(message: string, cause?: unknown) {
105+
super(
106+
'InfrastructureError',
107+
formatMessage(message),
108+
ExecutionErrorType.ENGINE,
109+
cause,
110+
);
111+
}
112+
}
113+
103114
export class ExecutionLimitReachedError extends ExecutionError {
104115
formated: boolean;
105116

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { logger } from '@openops/server-shared';
2+
import { InfrastructureError } from './execution-errors';
3+
4+
export const parseJsonResponse = async <T>(response: Response): Promise<T> => {
5+
const contentType = response.headers.get('content-type');
6+
const text = await response.text();
7+
8+
if (contentType && !contentType.includes('application/json')) {
9+
logger.warn('Expected JSON response but received non-JSON content type', {
10+
status: response.status,
11+
contentType,
12+
body: text,
13+
});
14+
throw new InfrastructureError(
15+
`Expected JSON response, but received status ${response.status} and ${contentType}.`,
16+
);
17+
}
18+
19+
try {
20+
return JSON.parse(text) as T;
21+
} catch (e) {
22+
logger.warn('Failed to parse JSON response', {
23+
status: response.status,
24+
body: text,
25+
});
26+
throw new InfrastructureError(
27+
`Failed to parse JSON response with status ${response.status}.`,
28+
e,
29+
);
30+
}
31+
};

packages/engine/src/lib/operations.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ import {
3434
import { testExecutionContext } from './handler/context/test-execution-context';
3535
import { flowExecutor } from './handler/flow-executor';
3636
import { blockHelper } from './helper/block-helper';
37-
import { ExecutionLimitReachedError } from './helper/execution-errors';
37+
import {
38+
ExecutionLimitReachedError,
39+
InfrastructureError,
40+
} from './helper/execution-errors';
3841
import { triggerHelper } from './helper/trigger-helper';
3942
import { resolveVariable } from './resolve-variable';
4043
import { progressService } from './services/progress.service';
@@ -330,6 +333,10 @@ function evaluateError(error: Error): {
330333
message = error.getMessage();
331334
}
332335

336+
if (error instanceof InfrastructureError) {
337+
status = FlowRunStatus.INFRASTRUCTURE_ERROR;
338+
}
339+
333340
return {
334341
status,
335342
message,

packages/engine/src/lib/services/connections.service.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import {
1111
ConnectionExpiredError,
1212
ConnectionLoadingError,
1313
ConnectionNotFoundError,
14-
ExecutionError,
1514
FetchError,
1615
} from '../helper/execution-errors';
16+
import { parseJsonResponse } from '../helper/response-helper';
1717

1818
export const createConnectionService = ({
1919
projectId,
@@ -40,16 +40,13 @@ export const createConnectionService = ({
4040
httpStatus: response.status,
4141
});
4242
}
43-
const connection: AppConnection = await response.json();
43+
const connection: AppConnection =
44+
await parseJsonResponse<AppConnection>(response);
4445
if (connection.status === AppConnectionStatus.ERROR) {
4546
throw new ConnectionExpiredError(connectionName);
4647
}
4748
return getConnectionValue(connection);
4849
} catch (e) {
49-
if (e instanceof ExecutionError) {
50-
throw e;
51-
}
52-
5350
return handleFetchError({
5451
url,
5552
cause: e,

0 commit comments

Comments
 (0)