@xyne/workflow-sdk 3.2.29 → 3.2.32
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/dist/agents/agent-step.d.ts +9 -3
- package/dist/agents/agent-step.d.ts.map +1 -1
- package/dist/agents/agent-step.js +11 -9
- package/dist/agents/agent-step.js.map +1 -1
- package/dist/agents/citation-resolve.d.ts.map +1 -1
- package/dist/agents/citation-resolve.js +2 -2
- package/dist/agents/citation-resolve.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/types.d.ts +35 -17
- package/dist/client/types.d.ts.map +1 -1
- package/dist/client/workflow-client.d.ts.map +1 -1
- package/dist/client/workflow-client.js +24 -13
- package/dist/client/workflow-client.js.map +1 -1
- package/dist/common/citation-ref.d.ts +32 -21
- package/dist/common/citation-ref.d.ts.map +1 -1
- package/dist/common/citation-ref.js +40 -27
- package/dist/common/citation-ref.js.map +1 -1
- package/dist/common/credentials.d.ts +258 -0
- package/dist/common/credentials.d.ts.map +1 -0
- package/dist/common/credentials.js +176 -0
- package/dist/common/credentials.js.map +1 -0
- package/dist/common/expression-eval.d.ts +35 -0
- package/dist/common/expression-eval.d.ts.map +1 -0
- package/dist/common/expression-eval.js +214 -0
- package/dist/common/expression-eval.js.map +1 -0
- package/dist/common/index.d.ts +7 -1
- package/dist/common/index.d.ts.map +1 -1
- package/dist/common/index.js +19 -1
- package/dist/common/index.js.map +1 -1
- package/dist/common/principal.d.ts +45 -0
- package/dist/common/principal.d.ts.map +1 -0
- package/dist/common/principal.js +9 -0
- package/dist/common/principal.js.map +1 -0
- package/dist/engine/workflow-executor.d.ts.map +1 -1
- package/dist/engine/workflow-executor.js +24 -9
- package/dist/engine/workflow-executor.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/persistence/in-memory-adapter.d.ts +93 -29
- package/dist/persistence/in-memory-adapter.d.ts.map +1 -1
- package/dist/persistence/in-memory-adapter.js +171 -52
- package/dist/persistence/in-memory-adapter.js.map +1 -1
- package/dist/persistence/types.d.ts +84 -26
- package/dist/persistence/types.d.ts.map +1 -1
- package/dist/router/workflow-router.d.ts +3 -1
- package/dist/router/workflow-router.d.ts.map +1 -1
- package/dist/router/workflow-router.js +218 -40
- package/dist/router/workflow-router.js.map +1 -1
- package/dist/runtime/workflow-runtime.d.ts +22 -30
- package/dist/runtime/workflow-runtime.d.ts.map +1 -1
- package/dist/runtime/workflow-runtime.js +46 -54
- package/dist/runtime/workflow-runtime.js.map +1 -1
- package/dist/steps/base-step.d.ts +12 -26
- package/dist/steps/base-step.d.ts.map +1 -1
- package/dist/steps/base-step.js +2 -4
- package/dist/steps/base-step.js.map +1 -1
- package/dist/steps/builtin/code.step.d.ts +7 -3
- package/dist/steps/builtin/code.step.d.ts.map +1 -1
- package/dist/steps/builtin/code.step.js +77 -47
- package/dist/steps/builtin/code.step.js.map +1 -1
- package/dist/steps/builtin/http-request.step.d.ts +18 -264
- package/dist/steps/builtin/http-request.step.d.ts.map +1 -1
- package/dist/steps/builtin/http-request.step.js +48 -157
- package/dist/steps/builtin/http-request.step.js.map +1 -1
- package/dist/steps/builtin/ssrf-guard.d.ts +9 -0
- package/dist/steps/builtin/ssrf-guard.d.ts.map +1 -0
- package/dist/steps/builtin/ssrf-guard.js +115 -0
- package/dist/steps/builtin/ssrf-guard.js.map +1 -0
- package/dist/steps/builtin/switch.step.d.ts +14 -14
- package/dist/steps/builtin/transform.step.d.ts +247 -0
- package/dist/steps/builtin/transform.step.d.ts.map +1 -0
- package/dist/steps/builtin/transform.step.js +135 -0
- package/dist/steps/builtin/transform.step.js.map +1 -0
- package/dist/steps/builtin/wait.step.d.ts +56 -56
- package/dist/steps/step-registry.d.ts +1 -3
- package/dist/steps/step-registry.d.ts.map +1 -1
- package/dist/steps/step-registry.js +0 -1
- package/dist/steps/step-registry.js.map +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/mock-step-context.d.ts +7 -2
- package/dist/testing/mock-step-context.d.ts.map +1 -1
- package/dist/testing/mock-step-context.js +9 -1
- package/dist/testing/mock-step-context.js.map +1 -1
- package/dist/triggers/webhook-trigger.d.ts +1 -5
- package/dist/triggers/webhook-trigger.d.ts.map +1 -1
- package/dist/triggers/webhook-trigger.js.map +1 -1
- package/dist/types/attachment.d.ts +23 -0
- package/dist/types/attachment.d.ts.map +1 -0
- package/dist/types/attachment.js +2 -0
- package/dist/types/attachment.js.map +1 -0
- package/dist/types/resume-payload.d.ts +34 -0
- package/dist/types/resume-payload.d.ts.map +1 -0
- package/dist/types/resume-payload.js +12 -0
- package/dist/types/resume-payload.js.map +1 -0
- package/dist/util/executable-check.d.ts +42 -0
- package/dist/util/executable-check.d.ts.map +1 -0
- package/dist/util/executable-check.js +115 -0
- package/dist/util/executable-check.js.map +1 -0
- package/package.json +2 -2
- package/dist/authz/principal-field.d.ts +0 -23
- package/dist/authz/principal-field.d.ts.map +0 -1
- package/dist/authz/principal-field.js +0 -34
- package/dist/authz/principal-field.js.map +0 -1
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
import type { ResumePayload } from '../common/resume-payload.js';
|
|
8
8
|
import type { Action } from '../authz/types.js';
|
|
9
9
|
import type { ResourceAttributes } from '../authz/attributes.js';
|
|
10
|
+
import type { WorkflowContext } from '../types/context.js';
|
|
11
|
+
import type { CredentialSummary, CredentialListItem, ResolvedCredential, CreateCredentialInput, AuthSpecificValues } from '../common/credentials.js';
|
|
10
12
|
/** What the engine stores about a workflow definition. */
|
|
11
13
|
export interface WorkflowRecord {
|
|
12
14
|
id: string;
|
|
@@ -342,34 +344,90 @@ export interface PersistenceAdapter<TFilter> {
|
|
|
342
344
|
data: string;
|
|
343
345
|
createdAt: Date;
|
|
344
346
|
}>>;
|
|
345
|
-
/** Management: create a credential (tenant carried in `attributes`). Returns its id. */
|
|
346
|
-
createCredential(data: {
|
|
347
|
-
id?: string;
|
|
348
|
-
name: string;
|
|
349
|
-
type: string;
|
|
350
|
-
data: Record<string, unknown>;
|
|
351
|
-
attributes?: ResourceAttributes<'credential'>;
|
|
352
|
-
}): Promise<string>;
|
|
353
|
-
/** Management: fetch a credential by id — never the secret `data`. */
|
|
354
|
-
getCredential(id: string): Promise<CredentialRecord | null>;
|
|
355
|
-
/** Management: list credentials matching the caller's `filter` (redacted — no secret). */
|
|
356
|
-
listCredentials(filter: TFilter): Promise<CredentialRecord[]>;
|
|
357
|
-
/** Management: delete a credential by id. */
|
|
358
|
-
deleteCredential(id: string): Promise<void>;
|
|
359
347
|
/**
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
348
|
+
* List all credentials in the workspace, returning safe summaries only.
|
|
349
|
+
*
|
|
350
|
+
* - Ordered by credential name.
|
|
351
|
+
* - Includes both `ACTIVE` and `REVOKED` credentials.
|
|
352
|
+
* - NEVER selects, decrypts, or returns stored values.
|
|
353
|
+
*
|
|
354
|
+
* @param filter - Host-defined visibility filter for the authenticated caller.
|
|
355
|
+
* @param page - Optional database-level pagination.
|
|
356
|
+
* @returns Array of safe credential summaries (no `values` field).
|
|
363
357
|
*/
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
}
|
|
368
|
-
/**
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
358
|
+
listCredentials(filter: TFilter, page?: {
|
|
359
|
+
limit?: number;
|
|
360
|
+
offset?: number;
|
|
361
|
+
}): Promise<CredentialListItem[]>;
|
|
362
|
+
/**
|
|
363
|
+
* Create a new credential.
|
|
364
|
+
*
|
|
365
|
+
* - Insert only — never upsert. Duplicate names must be rejected by
|
|
366
|
+
* the implementation (the caller may translate this to a `409`).
|
|
367
|
+
* - Sets both `createdAt` and `updatedAt` to the current time.
|
|
368
|
+
* - Status is always `ACTIVE` on creation.
|
|
369
|
+
*
|
|
370
|
+
* @param attributes - Host-defined credential scope and actor attributes.
|
|
371
|
+
* @param input - Validated create input: `name`, `authType`, `values`.
|
|
372
|
+
* @returns The safe summary of the newly created credential.
|
|
373
|
+
*/
|
|
374
|
+
createCredential(attributes: ResourceAttributes<'credential'>, input: CreateCredentialInput): Promise<CredentialSummary>;
|
|
375
|
+
/**
|
|
376
|
+
* Completely replace the stored values of an existing credential.
|
|
377
|
+
*
|
|
378
|
+
* - Does NOT decrypt old values — the new values replace the encrypted
|
|
379
|
+
* blob entirely.
|
|
380
|
+
* - Validates the new complete value object using the STORED auth type
|
|
381
|
+
* (the client cannot change the auth type).
|
|
382
|
+
* - Preserves `createdAt` and sets `updatedAt` to the current time.
|
|
383
|
+
* - Must reject if the credential is `REVOKED` (return `null` or throw,
|
|
384
|
+
* depending on implementation convention).
|
|
385
|
+
*
|
|
386
|
+
* @param attributes - Host-defined credential scope and actor attributes.
|
|
387
|
+
* @param name - The credential name (from the URL path).
|
|
388
|
+
* @param values - The complete replacement value set (validated
|
|
389
|
+
* against the stored auth type's schema).
|
|
390
|
+
* @returns The safe summary of the updated credential, or `null` if
|
|
391
|
+
* the credential was not found or is revoked.
|
|
392
|
+
*/
|
|
393
|
+
replaceCredentialValues(attributes: ResourceAttributes<'credential'>, name: string, values: AuthSpecificValues): Promise<CredentialSummary | null>;
|
|
394
|
+
/**
|
|
395
|
+
* Revoke a credential — terminal transition from ACTIVE to REVOKED.
|
|
396
|
+
*
|
|
397
|
+
* - Preserve `createdAt`.
|
|
398
|
+
* - Sets `status` to `REVOKED`.
|
|
399
|
+
* - Sets `updatedAt` to the current time.
|
|
400
|
+
* - Never deletes the row — the credential remains visible.
|
|
401
|
+
* - If the credential is already revoked, return the existing summary
|
|
402
|
+
* WITHOUT changing the original revocation identity/time (idempotent).
|
|
403
|
+
*
|
|
404
|
+
* @param attributes - Host-defined credential scope and actor attributes.
|
|
405
|
+
* @param name - The credential name (from the URL path).
|
|
406
|
+
* @returns The safe summary of the revoked credential, or `null` if
|
|
407
|
+
* the credential was not found.
|
|
408
|
+
*/
|
|
409
|
+
revokeCredential(attributes: ResourceAttributes<'credential'>, name: string): Promise<CredentialSummary | null>;
|
|
410
|
+
/**
|
|
411
|
+
* Resolve a credential for execution-time use.
|
|
412
|
+
*
|
|
413
|
+
* This is the ONLY method that decrypts and returns stored values.
|
|
414
|
+
*
|
|
415
|
+
* - During execution, scope by the running workflow and credential name.
|
|
416
|
+
* - A raw workflow-attribute scope is also accepted for server-side
|
|
417
|
+
* credential testing, where no workflow is running.
|
|
418
|
+
* - Return `null` for missing credentials.
|
|
419
|
+
* - Return `null` for revoked credentials — the executor uses this
|
|
420
|
+
* to fail before making an external request.
|
|
421
|
+
* - Decrypt values, validate the decrypted JSON against the stored
|
|
422
|
+
* auth type's schema, and return the in-memory `ResolvedCredential`.
|
|
423
|
+
*
|
|
424
|
+
* @param workflowOrAttributes - The running workflow, or host-defined scope
|
|
425
|
+
* attributes for a non-execution test request.
|
|
426
|
+
* @param name - The selected credential name.
|
|
427
|
+
* @returns The decrypted, validated credential, or `null` if the
|
|
428
|
+
* credential is missing or revoked.
|
|
429
|
+
*/
|
|
430
|
+
resolveCredential(workflowOrAttributes: WorkflowContext['workflow'] | ResourceAttributes<'workflow'>, name: string): Promise<ResolvedCredential | null>;
|
|
373
431
|
/** Store a webhook path+secret for a workflow. */
|
|
374
432
|
storeWebhookPath(workflowId: string, path: string, secret: string): Promise<void>;
|
|
375
433
|
/** Remove the webhook registration for a workflow. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/persistence/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/persistence/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Usage with Express:
|
|
9
9
|
* ```ts
|
|
10
|
-
* const routes = createWorkflowRouter(runtime, {
|
|
10
|
+
* const routes = createWorkflowRouter(runtime, {
|
|
11
|
+
* authenticate,
|
|
12
|
+
* });
|
|
11
13
|
* for (const route of routes) {
|
|
12
14
|
* const handler = async (req, res) => {
|
|
13
15
|
* const result = await route.handler(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-router.d.ts","sourceRoot":"","sources":["../../src/router/workflow-router.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"workflow-router.d.ts","sourceRoot":"","sources":["../../src/router/workflow-router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAA+B,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA4J3G,wBAAgB,oBAAoB,CAAC,IAAI,GAAG,WAAW,EAGrD,OAAO,EAAE,eAAe,CAAC,GAAG,EAAE,IAAI,CAAC,EAEnC,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,GACzB,eAAe,CAAC,IAAI,CAAC,EAAE,CAk6CzB"}
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Usage with Express:
|
|
9
9
|
* ```ts
|
|
10
|
-
* const routes = createWorkflowRouter(runtime, {
|
|
10
|
+
* const routes = createWorkflowRouter(runtime, {
|
|
11
|
+
* authenticate,
|
|
12
|
+
* });
|
|
11
13
|
* for (const route of routes) {
|
|
12
14
|
* const handler = async (req, res) => {
|
|
13
15
|
* const result = await route.handler(
|
|
@@ -28,6 +30,7 @@ import { getAvailableContext } from '../engine/available-context.js';
|
|
|
28
30
|
import { isExecutable } from '../common/executable-check.js';
|
|
29
31
|
import { createEventChannel } from '../runtime/execution-event-bus.js';
|
|
30
32
|
import { AccessDeniedError, ResourceNotFoundError } from '../authz/default.js';
|
|
33
|
+
import { applyResolvedCredentialAuth, CredentialNameSchema, CredentialAuthSchema, validateCredentialValues, } from '../common/credentials.js';
|
|
31
34
|
// ─── Helpers ───
|
|
32
35
|
function ok(body) {
|
|
33
36
|
return { status: 200, body };
|
|
@@ -41,6 +44,13 @@ function notFound(msg) {
|
|
|
41
44
|
function badRequest(msg) {
|
|
42
45
|
return { status: 400, body: { error: msg } };
|
|
43
46
|
}
|
|
47
|
+
// Step 12: 409 Conflict — used by the credential routes for two distinct
|
|
48
|
+
// "the resource is in a state that forbids this operation" cases:
|
|
49
|
+
// - creating a credential whose name already exists, and
|
|
50
|
+
// - replacing values on a credential that has been REVOKED.
|
|
51
|
+
function conflict(msg) {
|
|
52
|
+
return { status: 409, body: { error: msg } };
|
|
53
|
+
}
|
|
44
54
|
function error(status, msg) {
|
|
45
55
|
return { status, body: { error: msg } };
|
|
46
56
|
}
|
|
@@ -550,7 +560,13 @@ _opts) {
|
|
|
550
560
|
body: bytes,
|
|
551
561
|
headers: {
|
|
552
562
|
'Content-Type': mime,
|
|
553
|
-
|
|
563
|
+
// Force download; never inline-render. An uploaded HTML/SVG must not
|
|
564
|
+
// execute script in the app origin (stored XSS). nosniff stops the
|
|
565
|
+
// browser re-interpreting the type; the CSP neuters any script if a
|
|
566
|
+
// browser renders it regardless.
|
|
567
|
+
'Content-Disposition': `attachment; filename="${encodeURIComponent(name)}"`,
|
|
568
|
+
'X-Content-Type-Options': 'nosniff',
|
|
569
|
+
'Content-Security-Policy': "default-src 'none'; sandbox",
|
|
554
570
|
'Content-Length': String(bytes.byteLength),
|
|
555
571
|
},
|
|
556
572
|
};
|
|
@@ -867,67 +883,229 @@ _opts) {
|
|
|
867
883
|
}
|
|
868
884
|
},
|
|
869
885
|
});
|
|
870
|
-
|
|
886
|
+
const findCredential = async (auth, name) => {
|
|
887
|
+
const all = await runtime.listCredentials(asCtx(auth));
|
|
888
|
+
return all.find((credential) => credential.summary.name === name);
|
|
889
|
+
};
|
|
890
|
+
// ── GET /credentials ──
|
|
891
|
+
// Returns a page of visible credential summaries (ACTIVE and REVOKED).
|
|
892
|
+
// Never decrypts or returns stored values.
|
|
871
893
|
routes.push({
|
|
872
894
|
method: 'GET',
|
|
873
895
|
path: '/credentials',
|
|
874
|
-
handler: async (_req, auth) => {
|
|
875
|
-
const credentials = await runtime.listCredentials(asCtx(auth));
|
|
876
|
-
return ok({ credentials });
|
|
877
|
-
},
|
|
878
|
-
});
|
|
879
|
-
routes.push({
|
|
880
|
-
method: 'GET',
|
|
881
|
-
path: '/credentials/:id',
|
|
882
896
|
handler: async (req, auth) => {
|
|
883
|
-
const
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
if (
|
|
888
|
-
|
|
889
|
-
|
|
897
|
+
const q = req.query;
|
|
898
|
+
const page = {};
|
|
899
|
+
if (typeof q['limit'] === 'string')
|
|
900
|
+
page.limit = Number(q['limit']);
|
|
901
|
+
if (typeof q['offset'] === 'string')
|
|
902
|
+
page.offset = Number(q['offset']);
|
|
903
|
+
const credentials = await runtime.listCredentials(asCtx(auth), page);
|
|
904
|
+
return ok({ credentials });
|
|
890
905
|
},
|
|
891
906
|
});
|
|
907
|
+
// ── POST /credentials ──
|
|
908
|
+
// Create a new credential. Strictly validates name and the discriminated
|
|
909
|
+
// authType/values pair.
|
|
892
910
|
routes.push({
|
|
893
911
|
method: 'POST',
|
|
894
912
|
path: '/credentials',
|
|
895
913
|
handler: async (req, auth) => {
|
|
914
|
+
if (auth === null) {
|
|
915
|
+
return error(401, 'Authentication required to create a credential');
|
|
916
|
+
}
|
|
917
|
+
const capabilities = await runtime.capabilities(auth);
|
|
918
|
+
if (!capabilities.includes('credential:manage')) {
|
|
919
|
+
return error(403, 'Not permitted to create credentials');
|
|
920
|
+
}
|
|
896
921
|
const body = req.body;
|
|
897
|
-
if (!body
|
|
898
|
-
return badRequest('
|
|
922
|
+
if (!body)
|
|
923
|
+
return badRequest('Request body is required');
|
|
924
|
+
const nameResult = CredentialNameSchema.safeParse(body['name']);
|
|
925
|
+
if (!nameResult.success) {
|
|
926
|
+
return badRequest('Invalid or missing "name"');
|
|
927
|
+
}
|
|
928
|
+
const credentialAuthResult = CredentialAuthSchema.safeParse({
|
|
929
|
+
authType: body['authType'],
|
|
930
|
+
values: body['values'],
|
|
931
|
+
});
|
|
932
|
+
if (!credentialAuthResult.success) {
|
|
933
|
+
return badRequest('Invalid or mismatched "authType" and "values"');
|
|
899
934
|
}
|
|
935
|
+
const input = {
|
|
936
|
+
name: nameResult.data,
|
|
937
|
+
...credentialAuthResult.data,
|
|
938
|
+
};
|
|
900
939
|
try {
|
|
901
|
-
const cred = await runtime.createCredential(
|
|
902
|
-
name: body['name'],
|
|
903
|
-
type: body['type'],
|
|
904
|
-
data: body['data'],
|
|
905
|
-
attributes: body['attributes'],
|
|
906
|
-
});
|
|
940
|
+
const cred = await runtime.createCredential(body['attributes'], input);
|
|
907
941
|
return created(cred);
|
|
908
942
|
}
|
|
909
943
|
catch (err) {
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
944
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
945
|
+
if (/already exists/i.test(msg)) {
|
|
946
|
+
return conflict(`Credential "${input.name}" already exists`);
|
|
947
|
+
}
|
|
948
|
+
throw err;
|
|
913
949
|
}
|
|
914
950
|
},
|
|
915
951
|
});
|
|
952
|
+
// ── PUT /credentials/:name ──
|
|
953
|
+
// Completely replace an existing credential's values. Name and auth type are
|
|
954
|
+
// immutable — the new values are validated against the STORED auth type.
|
|
916
955
|
routes.push({
|
|
917
|
-
method: '
|
|
918
|
-
path: '/credentials/:
|
|
956
|
+
method: 'PUT',
|
|
957
|
+
path: '/credentials/:name',
|
|
919
958
|
handler: async (req, auth) => {
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
959
|
+
if (auth === null) {
|
|
960
|
+
return error(401, 'Authentication required to update a credential');
|
|
961
|
+
}
|
|
962
|
+
const name = req.params['name'];
|
|
963
|
+
if (!name)
|
|
964
|
+
return badRequest('Missing credential name');
|
|
965
|
+
const body = req.body;
|
|
966
|
+
if (!body || body['values'] === undefined) {
|
|
967
|
+
return badRequest('Body must contain "values"');
|
|
968
|
+
}
|
|
969
|
+
const credential = await findCredential(auth, name);
|
|
970
|
+
if (!credential) {
|
|
971
|
+
return notFound(`Credential "${name}" not found`);
|
|
972
|
+
}
|
|
973
|
+
if (!credential.permittedActions?.includes('credential:manage')) {
|
|
974
|
+
return error(403, `Not permitted to manage credential "${name}"`);
|
|
975
|
+
}
|
|
976
|
+
const { summary } = credential;
|
|
977
|
+
if (summary.status === 'REVOKED') {
|
|
978
|
+
return conflict(`Credential "${name}" is revoked and cannot be updated`);
|
|
979
|
+
}
|
|
980
|
+
let values;
|
|
923
981
|
try {
|
|
924
|
-
|
|
925
|
-
return { status: 204, body: undefined };
|
|
982
|
+
values = validateCredentialValues(summary.authType, body['values']);
|
|
926
983
|
}
|
|
927
|
-
catch
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
984
|
+
catch {
|
|
985
|
+
return badRequest(`Invalid values for auth type "${summary.authType}"`);
|
|
986
|
+
}
|
|
987
|
+
const updated = await runtime.replaceCredentialValues(body['attributes'], name, values);
|
|
988
|
+
// Defensive: a concurrent revoke between our lookup and the write would
|
|
989
|
+
// make the adapter return null. Treat that as a 409.
|
|
990
|
+
if (!updated) {
|
|
991
|
+
return conflict(`Credential "${name}" could not be updated`);
|
|
992
|
+
}
|
|
993
|
+
return ok(updated);
|
|
994
|
+
},
|
|
995
|
+
});
|
|
996
|
+
// ── POST /credentials/:name/revoke ──
|
|
997
|
+
// Revoke a credential (terminal ACTIVE → REVOKED). No request body. Idempotent
|
|
998
|
+
// — revoking an already-revoked credential returns its existing summary
|
|
999
|
+
// unchanged.
|
|
1000
|
+
routes.push({
|
|
1001
|
+
method: 'POST',
|
|
1002
|
+
path: '/credentials/:name/revoke',
|
|
1003
|
+
handler: async (req, auth) => {
|
|
1004
|
+
if (auth === null) {
|
|
1005
|
+
return error(401, 'Authentication required to revoke a credential');
|
|
1006
|
+
}
|
|
1007
|
+
const name = req.params['name'];
|
|
1008
|
+
if (!name)
|
|
1009
|
+
return badRequest('Missing credential name');
|
|
1010
|
+
const credential = await findCredential(auth, name);
|
|
1011
|
+
if (!credential) {
|
|
1012
|
+
return notFound(`Credential "${name}" not found`);
|
|
1013
|
+
}
|
|
1014
|
+
if (!credential.permittedActions?.includes('credential:manage')) {
|
|
1015
|
+
return error(403, `Not permitted to manage credential "${name}"`);
|
|
1016
|
+
}
|
|
1017
|
+
const body = (req.body ?? {});
|
|
1018
|
+
const revoked = await runtime.revokeCredential(body['attributes'], name);
|
|
1019
|
+
if (!revoked) {
|
|
1020
|
+
return notFound(`Credential "${name}" not found`);
|
|
1021
|
+
}
|
|
1022
|
+
return ok(revoked);
|
|
1023
|
+
},
|
|
1024
|
+
});
|
|
1025
|
+
// ── POST /credentials/:name/test ──
|
|
1026
|
+
// Make a one-off outbound request with this credential's auth applied, so the
|
|
1027
|
+
// user can verify the credential works. The secret is resolved + applied
|
|
1028
|
+
// SERVER-SIDE (via the same helper the HTTP step uses) and never returned to
|
|
1029
|
+
// the browser. Returns a redacted response summary.
|
|
1030
|
+
routes.push({
|
|
1031
|
+
method: 'POST',
|
|
1032
|
+
path: '/credentials/:name/test',
|
|
1033
|
+
handler: async (req, auth) => {
|
|
1034
|
+
if (auth === null) {
|
|
1035
|
+
return error(401, 'Authentication required to test a credential');
|
|
1036
|
+
}
|
|
1037
|
+
const name = req.params['name'];
|
|
1038
|
+
if (!name)
|
|
1039
|
+
return badRequest('Missing credential name');
|
|
1040
|
+
const body = (req.body ?? {});
|
|
1041
|
+
if (!body.url || typeof body.url !== 'string') {
|
|
1042
|
+
return badRequest('Body must contain a "url"');
|
|
1043
|
+
}
|
|
1044
|
+
let url;
|
|
1045
|
+
try {
|
|
1046
|
+
url = new URL(body.url);
|
|
1047
|
+
}
|
|
1048
|
+
catch {
|
|
1049
|
+
return badRequest('Invalid URL');
|
|
1050
|
+
}
|
|
1051
|
+
// Resolve + decrypt the credential (workspace-scoped). Null = missing or
|
|
1052
|
+
// revoked — only ACTIVE credentials can be tested.
|
|
1053
|
+
const cred = await runtime.resolveCredential(body.attributes, name);
|
|
1054
|
+
if (!cred) {
|
|
1055
|
+
return conflict(`Credential "${name}" not found or revoked`);
|
|
1056
|
+
}
|
|
1057
|
+
const method = (body.method ?? 'GET').toUpperCase();
|
|
1058
|
+
const headers = new Headers();
|
|
1059
|
+
if (body.headers) {
|
|
1060
|
+
for (const [k, v] of Object.entries(body.headers)) {
|
|
1061
|
+
if (k)
|
|
1062
|
+
headers.set(k, String(v));
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
// Apply the credential's auth exactly as the HTTP step does at execution.
|
|
1066
|
+
try {
|
|
1067
|
+
applyResolvedCredentialAuth(headers, cred);
|
|
1068
|
+
}
|
|
1069
|
+
catch (e) {
|
|
1070
|
+
return ok({
|
|
1071
|
+
ok: false,
|
|
1072
|
+
error: e instanceof Error ? e.message : 'Failed to apply credential',
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
const init = { method, headers };
|
|
1076
|
+
if (body.body && !['GET', 'HEAD'].includes(method)) {
|
|
1077
|
+
init.body = body.body;
|
|
1078
|
+
}
|
|
1079
|
+
const controller = new AbortController();
|
|
1080
|
+
const timer = setTimeout(() => controller.abort(), 15_000);
|
|
1081
|
+
init.signal = controller.signal;
|
|
1082
|
+
const t0 = Date.now();
|
|
1083
|
+
try {
|
|
1084
|
+
const resp = await fetch(url.toString(), init);
|
|
1085
|
+
const text = await resp.text();
|
|
1086
|
+
const respHeaders = {};
|
|
1087
|
+
resp.headers.forEach((v, k) => {
|
|
1088
|
+
respHeaders[k] = v;
|
|
1089
|
+
});
|
|
1090
|
+
clearTimeout(timer);
|
|
1091
|
+
return ok({
|
|
1092
|
+
ok: resp.ok,
|
|
1093
|
+
status: resp.status,
|
|
1094
|
+
statusText: resp.statusText,
|
|
1095
|
+
durationMs: Date.now() - t0,
|
|
1096
|
+
headers: respHeaders,
|
|
1097
|
+
// Cap the returned body so a huge response can't bloat the UI.
|
|
1098
|
+
bodyText: text.length > 20_000 ? text.slice(0, 20_000) + '…' : text,
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
catch (e) {
|
|
1102
|
+
clearTimeout(timer);
|
|
1103
|
+
const msg = e instanceof DOMException && e.name === 'AbortError'
|
|
1104
|
+
? 'Request timed out after 15s'
|
|
1105
|
+
: e instanceof Error
|
|
1106
|
+
? e.message
|
|
1107
|
+
: String(e);
|
|
1108
|
+
return ok({ ok: false, error: msg, durationMs: Date.now() - t0 });
|
|
931
1109
|
}
|
|
932
1110
|
},
|
|
933
1111
|
});
|