Skip to content

Commit 5d703f8

Browse files
committed
Merge branch 'main' into dependabot/update-package-lock
2 parents e370a1c + e10c2ea commit 5d703f8

12 files changed

Lines changed: 140 additions & 43 deletions

File tree

packages/blocks/aws-athena/src/lib/actions/query-athena-action.ts

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
amazonAuth,
44
dryRunCheckBox,
55
getAwsAccountsSingleSelectDropdown,
6-
getCredentialsListFromAuth,
6+
getCredentialsForAccount,
77
getRegionsDropdownState,
88
listAthenaDatabases,
99
runAndWaitForQueryResult,
@@ -33,10 +33,9 @@ export const runAthenaQueryAction = createAction({
3333
database: Property.Dropdown<string>({
3434
displayName: 'Database',
3535
description: 'Database that contains the table to query on',
36-
37-
refreshers: ['auth', 'accounts', 'region'],
36+
refreshers: ['auth', 'accounts', 'accounts.accounts', 'region'],
3837
required: true,
39-
options: async ({ auth, accounts, region }) => {
38+
options: async ({ auth, accounts, region }: any) => {
4039
if (!auth) {
4140
return {
4241
disabled: true,
@@ -46,24 +45,14 @@ export const runAthenaQueryAction = createAction({
4645
}
4746

4847
try {
49-
const authProp = auth as {
50-
accessKeyId: string;
51-
secretAccessKey: string;
52-
defaultRegion: string;
53-
};
54-
const selectedAccounts = (
55-
accounts as unknown as {
56-
accounts?: string[];
57-
}
58-
)?.accounts;
59-
const credentialsList = await getCredentialsListFromAuth(
60-
authProp,
61-
selectedAccounts,
48+
const credentials = await getCredentialsForAccount(
49+
auth,
50+
accounts?.['accounts'],
6251
);
6352

6453
const databases = await listAthenaDatabases(
65-
credentialsList[0],
66-
(region as string | undefined) ?? authProp.defaultRegion,
54+
credentials,
55+
(region as string | undefined) ?? auth.defaultRegion,
6756
);
6857

6958
return {
@@ -119,14 +108,13 @@ export const runAthenaQueryAction = createAction({
119108
}
120109

121110
try {
122-
const selectedAccounts = context.propsValue.accounts?.['accounts'];
123-
const credentialsList = await getCredentialsListFromAuth(
111+
const credentials = await getCredentialsForAccount(
124112
context.auth,
125-
selectedAccounts,
113+
context.propsValue.accounts?.['accounts'],
126114
);
127115

128116
return await runAndWaitForQueryResult(
129-
credentialsList[0],
117+
credentials,
130118
context.propsValue.region ?? context.auth.defaultRegion,
131119
query,
132120
database,

packages/blocks/aws-athena/test/athena-query-action.test.ts

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const openopsCommonMock = {
22
...jest.requireActual('@openops/common'),
3-
getCredentialsListFromAuth: jest.fn(),
3+
getCredentialsForAccount: jest.fn(),
44
runAndWaitForQueryResult: jest.fn(),
55
};
66

@@ -12,9 +12,9 @@ describe('runAthenaQueryAction tests', () => {
1212
beforeEach(() => {
1313
jest.clearAllMocks();
1414

15-
openopsCommonMock.getCredentialsListFromAuth.mockResolvedValue([
16-
{ someCreds: 'some creds' },
17-
]);
15+
openopsCommonMock.getCredentialsForAccount.mockResolvedValue({
16+
someCreds: 'some creds',
17+
});
1818
});
1919

2020
const auth = {
@@ -76,7 +76,7 @@ describe('runAthenaQueryAction tests', () => {
7676
...jest.requireActual('@openops/blocks-framework'),
7777
auth: auth,
7878
propsValue: {
79-
accounts: { accounts: ['some-account-id'] },
79+
accounts: { accounts: 'some-account-id' },
8080
query: 'some query',
8181
database: 'some database',
8282
outputBucket: 'some outputBucket',
@@ -87,12 +87,10 @@ describe('runAthenaQueryAction tests', () => {
8787
const result = (await runAthenaQueryAction.run(context)) as any;
8888

8989
expect(result).toEqual('mockResult');
90-
expect(openopsCommonMock.getCredentialsListFromAuth).toHaveBeenCalledTimes(
91-
1,
92-
);
93-
expect(openopsCommonMock.getCredentialsListFromAuth).toHaveBeenCalledWith(
90+
expect(openopsCommonMock.getCredentialsForAccount).toHaveBeenCalledTimes(1);
91+
expect(openopsCommonMock.getCredentialsForAccount).toHaveBeenCalledWith(
9492
auth,
95-
['some-account-id'],
93+
'some-account-id',
9694
);
9795
});
9896

@@ -138,7 +136,6 @@ describe('runAthenaQueryAction tests', () => {
138136
...jest.requireActual('@openops/blocks-framework'),
139137
auth: auth,
140138
propsValue: {
141-
accounts: { accounts: ['some-account-id'] },
142139
region: 'some region',
143140
query: 'some query',
144141
database: 'some database',
@@ -158,12 +155,10 @@ describe('runAthenaQueryAction tests', () => {
158155
'some database',
159156
'some outputBucket',
160157
);
161-
expect(openopsCommonMock.getCredentialsListFromAuth).toHaveBeenCalledTimes(
162-
1,
163-
);
164-
expect(openopsCommonMock.getCredentialsListFromAuth).toHaveBeenCalledWith(
158+
expect(openopsCommonMock.getCredentialsForAccount).toHaveBeenCalledTimes(1);
159+
expect(openopsCommonMock.getCredentialsForAccount).toHaveBeenCalledWith(
165160
auth,
166-
['some-account-id'],
161+
undefined,
167162
);
168163
});
169164

packages/blocks/slack/src/lib/common/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,8 @@ export function dynamicBlockKitProperties(): any {
269269
const result: any = {
270270
blocks: Property.Json({
271271
displayName: 'Block Kit blocks',
272-
description: 'See https://api.slack.com/block-kit for specs',
272+
description:
273+
'See https://api.slack.com/block-kit for specs. Visual preview available at https://app.slack.com/block-kit-builder',
273274
required: true,
274275
defaultValue: [
275276
{

packages/server/api/src/app/app.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,9 @@ export const setupApp = async (
114114
const openapiRoutePrefix = '/v1/openapi';
115115
app.addHook('onRoute', (route) => {
116116
if (route.url.startsWith(openapiRoutePrefix)) {
117-
route.config ??= {};
117+
route.config ??= {
118+
security: PUBLIC_ROUTE_POLICY,
119+
};
118120
route.config.skipAuth = true;
119121
route.config.security = PUBLIC_ROUTE_POLICY;
120122
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { AuthorizationGuards } from './authorization-guards';
2+
import { noopAuthorizationGuards } from './noop-authorization-guards';
3+
4+
export function getAuthorizationGuards(): AuthorizationGuards {
5+
return noopAuthorizationGuards;
6+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import {
2+
CreateStepRunRequestBody,
3+
Principal,
4+
TestFlowRunRequestBody,
5+
} from '@openops/shared';
6+
import { FastifyRequest } from 'fastify';
7+
8+
export type AuthorizationGuards = {
9+
enforceTestStepAuthorizationFromRequest(
10+
request: FastifyRequest,
11+
): Promise<void>;
12+
13+
enforceTestStepAuthorization(
14+
data: CreateStepRunRequestBody,
15+
principal: Principal,
16+
): Promise<void>;
17+
18+
enforceTestRunAuthorization(
19+
data: TestFlowRunRequestBody,
20+
principal: Principal,
21+
): Promise<void>;
22+
23+
enforceWorkflowStatusAuthorization(request: FastifyRequest): Promise<void>;
24+
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import {
2+
CreateStepRunRequestBody,
3+
Principal,
4+
TestFlowRunRequestBody,
5+
} from '@openops/shared';
6+
import { FastifyRequest } from 'fastify';
7+
import { AuthorizationGuards } from './authorization-guards';
8+
9+
export const noopAuthorizationGuards: AuthorizationGuards = {
10+
enforceTestRunAuthorization(
11+
_data: TestFlowRunRequestBody,
12+
_principal: Principal,
13+
): Promise<void> {
14+
return Promise.resolve();
15+
},
16+
17+
enforceTestStepAuthorization(
18+
_data: CreateStepRunRequestBody,
19+
_principal: Principal,
20+
): Promise<void> {
21+
return Promise.resolve();
22+
},
23+
24+
enforceTestStepAuthorizationFromRequest(
25+
_request: FastifyRequest,
26+
): Promise<void> {
27+
return Promise.resolve();
28+
},
29+
30+
enforceWorkflowStatusAuthorization(_request: FastifyRequest): Promise<void> {
31+
return Promise.resolve();
32+
},
33+
};

packages/server/api/src/app/flows/flow.module.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox';
22
import { logger } from '@openops/server-shared';
33
import {
4+
ApplicationError,
45
CreateStepRunRequestBody,
6+
ErrorCode,
57
FlowRunStatus,
68
StepRunResponse,
79
TestFlowRunRequestBody,
810
WebsocketClientEvent,
911
WebsocketServerEvent,
1012
flowHelper,
1113
} from '@openops/shared';
14+
import { Socket } from 'socket.io';
15+
import { getAuthorizationGuards } from '../core/security/authorization-guards/authorization-guards-factory';
1216
import { sendStepFailureEvent } from '../telemetry/event-models/step';
1317
import {
1418
sendWorkflowTestFailureEvent,
@@ -39,6 +43,11 @@ export const flowModule: FastifyPluginAsyncTypebox = async (app) => {
3943
try {
4044
principal = await getPrincipalFromWebsocket(socket);
4145

46+
await getAuthorizationGuards().enforceTestRunAuthorization(
47+
data,
48+
principal,
49+
);
50+
4251
flowRun = await flowRunService.test({
4352
projectId: principal.projectId,
4453
flowVersionId: data.flowVersionId,
@@ -63,6 +72,11 @@ export const flowModule: FastifyPluginAsyncTypebox = async (app) => {
6372
);
6473
socket.emit(WebsocketClientEvent.TEST_FLOW_RUN_STARTED, flowRun);
6574
} catch (err) {
75+
if (isAuthorizationError(err)) {
76+
sendAuthorizationError(socket, err);
77+
return;
78+
}
79+
6680
sendWorkflowTestFailureEvent({
6781
userId: principal?.id ?? '',
6882
projectId: principal?.projectId ?? '',
@@ -90,6 +104,11 @@ export const flowModule: FastifyPluginAsyncTypebox = async (app) => {
90104
try {
91105
principal = await getPrincipalFromWebsocket(socket);
92106

107+
await getAuthorizationGuards().enforceTestStepAuthorization(
108+
data,
109+
principal,
110+
);
111+
93112
logger.debug({ data }, '[Socket#testStepRun]');
94113
const stepRun = await stepRunService.create({
95114
userId: principal.id,
@@ -105,6 +124,11 @@ export const flowModule: FastifyPluginAsyncTypebox = async (app) => {
105124
};
106125
socket.emit(WebsocketClientEvent.TEST_STEP_FINISHED, response);
107126
} catch (err) {
127+
if (isAuthorizationError(err)) {
128+
sendAuthorizationError(socket, err);
129+
return;
130+
}
131+
108132
let step;
109133
try {
110134
const flowVersion = await flowVersionService.getOneOrThrow(
@@ -139,3 +163,20 @@ export const flowModule: FastifyPluginAsyncTypebox = async (app) => {
139163
};
140164
});
141165
};
166+
167+
function isAuthorizationError(error: unknown): boolean {
168+
logger.debug('isAuthorizationError', error);
169+
return (
170+
error instanceof ApplicationError &&
171+
error.error.code === ErrorCode.AUTHORIZATION
172+
);
173+
}
174+
175+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
176+
function sendAuthorizationError(socket: Socket, error: any): void {
177+
socket.emit('error', {
178+
success: false,
179+
code: error.error.code,
180+
output: error.error.params.message,
181+
});
182+
}

packages/server/api/src/app/flows/flow/flow.controller.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
} from '@openops/shared';
3333
import { StatusCodes } from 'http-status-codes';
3434
import { entitiesMustBeOwnedByCurrentProject } from '../../authentication/authorization';
35+
import { getAuthorizationGuards } from '../../core/security/authorization-guards/authorization-guards-factory';
3536
import { getProjectScopedRoutePolicy } from '../../core/security/route-policies/route-security-policy-factory';
3637
import { projectService } from '../../project/project-service';
3738
import { sendWorkflowCreatedFromTemplateEvent } from '../../telemetry/event-models';
@@ -288,9 +289,10 @@ const UpdateFlowRequestOptions = {
288289
config: {
289290
security: getProjectScopedRoutePolicy({
290291
allowedPrincipals: [PrincipalType.USER, PrincipalType.SERVICE],
291-
permission: Permission.UPDATE_FLOW_STATUS,
292+
permission: Permission.WRITE_FLOW,
292293
}),
293294
},
295+
preHandler: getAuthorizationGuards().enforceWorkflowStatusAuthorization,
294296
schema: {
295297
tags: ['flows'],
296298
description:

packages/server/api/src/app/flows/trigger-events/trigger-event.module.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
PrincipalType,
66
TestPollingTriggerRequest,
77
} from '@openops/shared';
8+
import { getAuthorizationGuards } from '../../core/security/authorization-guards/authorization-guards-factory';
89
import { getProjectScopedRoutePolicy } from '../../core/security/route-policies/route-security-policy-factory';
910
import { systemJobsSchedule } from '../../helper/system-jobs';
1011
import { SystemJobName } from '../../helper/system-jobs/common';
@@ -44,6 +45,8 @@ const triggerEventController: FastifyPluginAsyncTypebox = async (fastify) => {
4445
permission: Permission.READ_FLOW,
4546
}),
4647
},
48+
preHandler:
49+
getAuthorizationGuards().enforceTestStepAuthorizationFromRequest,
4750
schema: {
4851
querystring: TestPollingTriggerRequest,
4952
},

0 commit comments

Comments
 (0)