@shipfox/api-server 7.1.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +27 -0
- package/README.md +9 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modules.d.ts +5 -0
- package/dist/modules.d.ts.map +1 -1
- package/dist/modules.js +8 -3
- package/dist/modules.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +18 -18
- package/src/auth-token-interoperability.test.ts +52 -0
- package/src/index.ts +1 -0
- package/src/modules.test.ts +36 -5
- package/src/modules.ts +13 -3
- package/tsconfig.build.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@shipfox/api-server",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"private": false,
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "8.0.0",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/ShipfoxHQ/shipfox.git",
|
|
@@ -25,37 +25,37 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@shipfox/annotations": "
|
|
29
|
-
"@shipfox/api-agent": "7.1.0",
|
|
28
|
+
"@shipfox/annotations": "8.0.0",
|
|
30
29
|
"@shipfox/annotations-dto": "6.0.0",
|
|
31
|
-
"@shipfox/api-agent
|
|
30
|
+
"@shipfox/api-agent": "8.0.0",
|
|
31
|
+
"@shipfox/api-agent-dto": "8.0.0",
|
|
32
32
|
"@shipfox/api-auth": "7.1.0",
|
|
33
33
|
"@shipfox/api-auth-dto": "7.1.0",
|
|
34
|
+
"@shipfox/api-definitions": "8.0.0",
|
|
34
35
|
"@shipfox/api-definitions-dto": "6.0.0",
|
|
35
36
|
"@shipfox/api-dispatcher": "7.1.0",
|
|
36
37
|
"@shipfox/api-email-challenges": "0.3.0",
|
|
37
|
-
"@shipfox/api-
|
|
38
|
-
"@shipfox/api-integration-core": "
|
|
39
|
-
"@shipfox/api-
|
|
40
|
-
"@shipfox/api-
|
|
41
|
-
"@shipfox/api-projects-dto": "
|
|
42
|
-
"@shipfox/api-runners": "
|
|
38
|
+
"@shipfox/api-integration-core": "8.0.0",
|
|
39
|
+
"@shipfox/api-integration-core-dto": "8.0.0",
|
|
40
|
+
"@shipfox/api-logs": "8.0.0",
|
|
41
|
+
"@shipfox/api-projects": "8.0.0",
|
|
42
|
+
"@shipfox/api-projects-dto": "8.0.0",
|
|
43
|
+
"@shipfox/api-runners": "8.0.0",
|
|
43
44
|
"@shipfox/api-runners-dto": "7.0.1",
|
|
44
|
-
"@shipfox/api-secrets": "
|
|
45
|
-
"@shipfox/api-integration-core-dto": "6.0.0",
|
|
46
|
-
"@shipfox/api-workflows": "7.1.0",
|
|
45
|
+
"@shipfox/api-secrets": "8.0.0",
|
|
47
46
|
"@shipfox/api-secrets-dto": "6.0.0",
|
|
48
|
-
"@shipfox/api-triggers": "
|
|
47
|
+
"@shipfox/api-triggers": "8.0.0",
|
|
48
|
+
"@shipfox/api-workflows": "8.0.0",
|
|
49
|
+
"@shipfox/api-workflows-dto": "8.0.0",
|
|
49
50
|
"@shipfox/api-workspaces-dto": "6.0.0",
|
|
50
|
-
"@shipfox/api-workflows-dto": "6.0.0",
|
|
51
51
|
"@shipfox/api-workspaces": "7.1.0",
|
|
52
52
|
"@shipfox/config": "1.2.2",
|
|
53
|
-
"@shipfox/node-fastify": "0.3.0",
|
|
54
53
|
"@shipfox/node-error-monitoring": "0.2.0",
|
|
54
|
+
"@shipfox/node-fastify": "0.3.0",
|
|
55
55
|
"@shipfox/node-jwt": "0.3.0",
|
|
56
|
-
"@shipfox/node-postgres": "0.4.2",
|
|
57
56
|
"@shipfox/node-module": "0.5.0",
|
|
58
|
-
"@shipfox/node-opentelemetry": "0.6.0"
|
|
57
|
+
"@shipfox/node-opentelemetry": "0.6.0",
|
|
58
|
+
"@shipfox/node-postgres": "0.4.2"
|
|
59
59
|
},
|
|
60
60
|
"scripts": {
|
|
61
61
|
"build": "shipfox-swc",
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {AUTH_LEASED_JOB, requireLeasedJobContext} from '@shipfox/api-auth-context';
|
|
2
|
+
import {closeApp, createApp, defineRoute} from '@shipfox/node-fastify';
|
|
3
|
+
import {afterEach, describe, expect, it} from '@shipfox/vitest/vi';
|
|
4
|
+
|
|
5
|
+
process.env.AUTH_ROOT_KEY ??= 'MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=';
|
|
6
|
+
|
|
7
|
+
const leaseRoute = defineRoute({
|
|
8
|
+
method: 'GET',
|
|
9
|
+
path: '/lease',
|
|
10
|
+
description: 'Auth composition test route.',
|
|
11
|
+
handler: (request) => {
|
|
12
|
+
const lease = requireLeasedJobContext(request);
|
|
13
|
+
return {job_id: lease.jobId, step_id: lease.currentStepId};
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('Auth token interoperability', () => {
|
|
18
|
+
afterEach(async () => {
|
|
19
|
+
await closeApp();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('accepts an Auth-issued step lease through the server route boundary', async () => {
|
|
23
|
+
const {createLeaseTokenAuthMethod, issueJobLeaseToken} = await import('@shipfox/api-auth');
|
|
24
|
+
const jobId = crypto.randomUUID();
|
|
25
|
+
const stepId = crypto.randomUUID();
|
|
26
|
+
const token = await issueJobLeaseToken({
|
|
27
|
+
jobId,
|
|
28
|
+
jobExecutionId: crypto.randomUUID(),
|
|
29
|
+
workflowRunId: crypto.randomUUID(),
|
|
30
|
+
workflowRunAttemptId: crypto.randomUUID(),
|
|
31
|
+
projectId: crypto.randomUUID(),
|
|
32
|
+
workspaceId: crypto.randomUUID(),
|
|
33
|
+
runnerSessionId: crypto.randomUUID(),
|
|
34
|
+
currentStepId: stepId,
|
|
35
|
+
currentStepAttempt: 1,
|
|
36
|
+
});
|
|
37
|
+
const app = await createApp({
|
|
38
|
+
auth: [createLeaseTokenAuthMethod()],
|
|
39
|
+
routes: [{prefix: '/runs/jobs/current', auth: AUTH_LEASED_JOB, routes: [leaseRoute]}],
|
|
40
|
+
swagger: false,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const res = await app.inject({
|
|
44
|
+
method: 'GET',
|
|
45
|
+
url: '/runs/jobs/current/lease',
|
|
46
|
+
headers: {authorization: `Bearer ${token}`},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
expect(res.statusCode).toBe(200);
|
|
50
|
+
expect(res.json()).toEqual({job_id: jobId, step_id: stepId});
|
|
51
|
+
});
|
|
52
|
+
});
|
package/src/index.ts
CHANGED
package/src/modules.test.ts
CHANGED
|
@@ -2,15 +2,18 @@ import {annotationsInterModuleContract} from '@shipfox/annotations-dto/inter-mod
|
|
|
2
2
|
import {agentInterModuleContract} from '@shipfox/api-agent-dto/inter-module';
|
|
3
3
|
import {authInterModuleContract} from '@shipfox/api-auth-dto/inter-module';
|
|
4
4
|
import {definitionsInterModuleContract} from '@shipfox/api-definitions-dto/inter-module';
|
|
5
|
-
import {integrationsInterModuleContract} from '@shipfox/api-integration-core-dto';
|
|
6
|
-
import {projectsInterModuleContract} from '@shipfox/api-projects-dto';
|
|
5
|
+
import {integrationsInterModuleContract} from '@shipfox/api-integration-core-dto/inter-module';
|
|
6
|
+
import {projectsInterModuleContract} from '@shipfox/api-projects-dto/inter-module';
|
|
7
7
|
import {runnersInterModuleContract} from '@shipfox/api-runners-dto/inter-module';
|
|
8
8
|
import {
|
|
9
9
|
type SecretsInterModuleClient,
|
|
10
10
|
secretsInterModuleContract,
|
|
11
11
|
} from '@shipfox/api-secrets-dto/inter-module';
|
|
12
12
|
import {workflowsInterModuleContract} from '@shipfox/api-workflows-dto/inter-module';
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
type WorkspacesInterModuleClient,
|
|
15
|
+
workspacesInterModuleContract,
|
|
16
|
+
} from '@shipfox/api-workspaces-dto/inter-module';
|
|
14
17
|
import {defineInterModulePresentation} from '@shipfox/inter-module';
|
|
15
18
|
import {defaultModules} from './modules.js';
|
|
16
19
|
|
|
@@ -30,6 +33,7 @@ const mocks = vi.hoisted(() => ({
|
|
|
30
33
|
deleteSecrets: vi.fn(),
|
|
31
34
|
getIntegrationConnectionById: vi.fn(),
|
|
32
35
|
getSecret: vi.fn(),
|
|
36
|
+
listMembershipsForTokenClaims: vi.fn(),
|
|
33
37
|
setSecrets: vi.fn(),
|
|
34
38
|
}));
|
|
35
39
|
|
|
@@ -96,7 +100,7 @@ vi.mock('@shipfox/api-workspaces', () => ({
|
|
|
96
100
|
{
|
|
97
101
|
contract: workspacesInterModuleContract,
|
|
98
102
|
handlers: {
|
|
99
|
-
listMembershipsForTokenClaims:
|
|
103
|
+
listMembershipsForTokenClaims: mocks.listMembershipsForTokenClaims,
|
|
100
104
|
preflightInvitationAcceptance: vi.fn(),
|
|
101
105
|
acceptInvitation: vi.fn(),
|
|
102
106
|
requireActiveMembership: vi.fn(),
|
|
@@ -123,6 +127,7 @@ describe('defaultModules', () => {
|
|
|
123
127
|
mocks.deleteSecrets.mockReset();
|
|
124
128
|
mocks.getIntegrationConnectionById.mockReset();
|
|
125
129
|
mocks.getSecret.mockReset();
|
|
130
|
+
mocks.listMembershipsForTokenClaims.mockReset();
|
|
126
131
|
mocks.setSecrets.mockReset();
|
|
127
132
|
|
|
128
133
|
mocks.createIntegrationsContext.mockResolvedValue({
|
|
@@ -147,6 +152,7 @@ describe('defaultModules', () => {
|
|
|
147
152
|
mocks.createWorkspaceConnectionSnapshotLoader.mockReturnValue(vi.fn());
|
|
148
153
|
mocks.deleteSecrets.mockResolvedValue({deleted: 1});
|
|
149
154
|
mocks.getSecret.mockResolvedValue({value: 'secret'});
|
|
155
|
+
mocks.listMembershipsForTokenClaims.mockResolvedValue({memberships: []});
|
|
150
156
|
mocks.setSecrets.mockResolvedValue({});
|
|
151
157
|
mocks.createProjectsModule.mockReturnValue({
|
|
152
158
|
name: 'projects',
|
|
@@ -182,7 +188,11 @@ describe('defaultModules', () => {
|
|
|
182
188
|
interModulePresentations: [
|
|
183
189
|
{
|
|
184
190
|
contract: agentInterModuleContract,
|
|
185
|
-
handlers: {
|
|
191
|
+
handlers: {
|
|
192
|
+
getValidationCatalog: vi.fn(),
|
|
193
|
+
resolveAgentConfig: vi.fn(),
|
|
194
|
+
resolveRuntimeCredentials: vi.fn(),
|
|
195
|
+
},
|
|
186
196
|
},
|
|
187
197
|
],
|
|
188
198
|
});
|
|
@@ -288,6 +298,27 @@ describe('defaultModules', () => {
|
|
|
288
298
|
]);
|
|
289
299
|
});
|
|
290
300
|
|
|
301
|
+
it('extends the default module list with the composed Workspaces client', async () => {
|
|
302
|
+
let workspaces: WorkspacesInterModuleClient | undefined;
|
|
303
|
+
const extensionModule = {name: 'cloud'};
|
|
304
|
+
const extension = vi.fn((options: {workspaces: WorkspacesInterModuleClient}) => {
|
|
305
|
+
workspaces = options.workspaces;
|
|
306
|
+
return [extensionModule];
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
const modules = await defaultModules({extension});
|
|
310
|
+
const userId = crypto.randomUUID();
|
|
311
|
+
const memberships = await workspaces?.listMembershipsForTokenClaims({userId});
|
|
312
|
+
|
|
313
|
+
expect(extension).toHaveBeenCalledWith({workspaces: expect.any(Object)});
|
|
314
|
+
expect(memberships).toEqual({memberships: []});
|
|
315
|
+
expect(mocks.listMembershipsForTokenClaims).toHaveBeenCalledWith(
|
|
316
|
+
{userId},
|
|
317
|
+
expect.objectContaining({signal: expect.any(AbortSignal)}),
|
|
318
|
+
);
|
|
319
|
+
expect(modules.at(-1)).toBe(extensionModule);
|
|
320
|
+
});
|
|
321
|
+
|
|
291
322
|
it('injects Workflows into integrations and logs and namespaces provider secrets', async () => {
|
|
292
323
|
await defaultModules();
|
|
293
324
|
|
package/src/modules.ts
CHANGED
|
@@ -13,10 +13,10 @@ import {definitionsInterModuleContract} from '@shipfox/api-definitions-dto/inter
|
|
|
13
13
|
import {dispatcherModule} from '@shipfox/api-dispatcher';
|
|
14
14
|
import {emailChallengesModule} from '@shipfox/api-email-challenges';
|
|
15
15
|
import {createIntegrationsContext, type WebhookDeliverySource} from '@shipfox/api-integration-core';
|
|
16
|
-
import {integrationsInterModuleContract} from '@shipfox/api-integration-core-dto';
|
|
16
|
+
import {integrationsInterModuleContract} from '@shipfox/api-integration-core-dto/inter-module';
|
|
17
17
|
import {createLogsModule} from '@shipfox/api-logs';
|
|
18
18
|
import {createProjectsModule} from '@shipfox/api-projects';
|
|
19
|
-
import {projectsInterModuleContract} from '@shipfox/api-projects-dto';
|
|
19
|
+
import {projectsInterModuleContract} from '@shipfox/api-projects-dto/inter-module';
|
|
20
20
|
import {createRunnersModule} from '@shipfox/api-runners';
|
|
21
21
|
import {runnersInterModuleContract} from '@shipfox/api-runners-dto/inter-module';
|
|
22
22
|
import {createSecretsModule} from '@shipfox/api-secrets';
|
|
@@ -25,7 +25,10 @@ import {createTriggersModule} from '@shipfox/api-triggers';
|
|
|
25
25
|
import {createWorkflowsModule} from '@shipfox/api-workflows';
|
|
26
26
|
import {workflowsInterModuleContract} from '@shipfox/api-workflows-dto/inter-module';
|
|
27
27
|
import {workspacesModule} from '@shipfox/api-workspaces';
|
|
28
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
type WorkspacesInterModuleClient,
|
|
30
|
+
workspacesInterModuleContract,
|
|
31
|
+
} from '@shipfox/api-workspaces-dto/inter-module';
|
|
29
32
|
import {reportError} from '@shipfox/node-error-monitoring';
|
|
30
33
|
import {durationToSeconds} from '@shipfox/node-jwt';
|
|
31
34
|
import type {ShipfoxModule} from '@shipfox/node-module';
|
|
@@ -38,9 +41,13 @@ import {logger} from '@shipfox/node-opentelemetry';
|
|
|
38
41
|
export interface DefaultModulesOptions {
|
|
39
42
|
webhookDeliverySource?: WebhookDeliverySource | undefined;
|
|
40
43
|
runnersModule?: DefaultRunnersModuleFactory | undefined;
|
|
44
|
+
extension?: DefaultModulesExtension | undefined;
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
export type DefaultRunnersModuleFactory = (options: {auth: AuthInterModuleClient}) => ShipfoxModule;
|
|
48
|
+
export type DefaultModulesExtension = (options: {
|
|
49
|
+
workspaces: WorkspacesInterModuleClient;
|
|
50
|
+
}) => ShipfoxModule[];
|
|
44
51
|
|
|
45
52
|
export async function defaultModules(
|
|
46
53
|
options: DefaultModulesOptions = {},
|
|
@@ -151,8 +158,10 @@ export async function defaultModules(
|
|
|
151
158
|
const projectsModule = createProjectsModule({integrations: integrationsClient});
|
|
152
159
|
const definitionsModule = createDefinitionsModule({
|
|
153
160
|
projects: projectsClient,
|
|
161
|
+
agent: agentClient,
|
|
154
162
|
integrations: integrationsClient,
|
|
155
163
|
});
|
|
164
|
+
const extensionModules = options.extension?.({workspaces: workspacesClient}) ?? [];
|
|
156
165
|
|
|
157
166
|
const modules = [
|
|
158
167
|
emailChallengesModule,
|
|
@@ -181,6 +190,7 @@ export async function defaultModules(
|
|
|
181
190
|
}),
|
|
182
191
|
createTriggersModule({workflows: workflowsClient}),
|
|
183
192
|
dispatcherModule,
|
|
193
|
+
...extensionModules,
|
|
184
194
|
];
|
|
185
195
|
registerInterModulePresentations({transport: interModuleTransport, modules});
|
|
186
196
|
interModuleTransport.seal();
|