@ankhorage/flow 0.0.0-stage → 0.4.1
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/CHANGELOG.md +33 -0
- package/LICENSE +21 -0
- package/README.md +17 -2
- package/dist/ai.d.ts +7 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +7 -0
- package/dist/ai.js.map +1 -0
- package/dist/features/execution/application/executeFlowAsync.d.ts +4 -0
- package/dist/features/execution/application/executeFlowAsync.d.ts.map +1 -0
- package/dist/features/execution/application/executeFlowAsync.js +211 -0
- package/dist/features/execution/application/executeFlowAsync.js.map +1 -0
- package/dist/features/execution/domain/assertFlowGraphSchemasSupported.d.ts +5 -0
- package/dist/features/execution/domain/assertFlowGraphSchemasSupported.d.ts.map +1 -0
- package/dist/features/execution/domain/assertFlowGraphSchemasSupported.js +11 -0
- package/dist/features/execution/domain/assertFlowGraphSchemasSupported.js.map +1 -0
- package/dist/features/execution/domain/compileFlowGraph.d.ts +5 -0
- package/dist/features/execution/domain/compileFlowGraph.d.ts.map +1 -0
- package/dist/features/execution/domain/compileFlowGraph.js +76 -0
- package/dist/features/execution/domain/compileFlowGraph.js.map +1 -0
- package/dist/features/execution/domain/createDefaultNodeRegistry.d.ts +4 -0
- package/dist/features/execution/domain/createDefaultNodeRegistry.d.ts.map +1 -0
- package/dist/features/execution/domain/createDefaultNodeRegistry.js +15 -0
- package/dist/features/execution/domain/createDefaultNodeRegistry.js.map +1 -0
- package/dist/features/execution/domain/validateFlowDataSchema.d.ts +6 -0
- package/dist/features/execution/domain/validateFlowDataSchema.d.ts.map +1 -0
- package/dist/features/execution/domain/validateFlowDataSchema.js +144 -0
- package/dist/features/execution/domain/validateFlowDataSchema.js.map +1 -0
- package/dist/features/mcp/McpToolError.d.ts +6 -0
- package/dist/features/mcp/McpToolError.d.ts.map +1 -0
- package/dist/features/mcp/McpToolError.js +10 -0
- package/dist/features/mcp/McpToolError.js.map +1 -0
- package/dist/features/mcp/createMcpRemoteTransport.d.ts +8 -0
- package/dist/features/mcp/createMcpRemoteTransport.d.ts.map +1 -0
- package/dist/features/mcp/createMcpRemoteTransport.js +23 -0
- package/dist/features/mcp/createMcpRemoteTransport.js.map +1 -0
- package/dist/features/mcp/createMcpToolRegistry.d.ts +10 -0
- package/dist/features/mcp/createMcpToolRegistry.d.ts.map +1 -0
- package/dist/features/mcp/createMcpToolRegistry.js +185 -0
- package/dist/features/mcp/createMcpToolRegistry.js.map +1 -0
- package/dist/features/mcp/loadMcpSdkAsync.d.ts +12 -0
- package/dist/features/mcp/loadMcpSdkAsync.d.ts.map +1 -0
- package/dist/features/mcp/loadMcpSdkAsync.js +20 -0
- package/dist/features/mcp/loadMcpSdkAsync.js.map +1 -0
- package/dist/features/mcp/prepareMcpProviders.d.ts +4 -0
- package/dist/features/mcp/prepareMcpProviders.d.ts.map +1 -0
- package/dist/features/mcp/prepareMcpProviders.js +97 -0
- package/dist/features/mcp/prepareMcpProviders.js.map +1 -0
- package/dist/features/mcp/validateMcpSchema.d.ts +6 -0
- package/dist/features/mcp/validateMcpSchema.d.ts.map +1 -0
- package/dist/features/mcp/validateMcpSchema.js +220 -0
- package/dist/features/mcp/validateMcpSchema.js.map +1 -0
- package/dist/features/security/FlowSecurityError.d.ts +6 -0
- package/dist/features/security/FlowSecurityError.d.ts.map +1 -0
- package/dist/features/security/FlowSecurityError.js +10 -0
- package/dist/features/security/FlowSecurityError.js.map +1 -0
- package/dist/features/security/application/createFlowSecurityPort.d.ts +12 -0
- package/dist/features/security/application/createFlowSecurityPort.d.ts.map +1 -0
- package/dist/features/security/application/createFlowSecurityPort.js +208 -0
- package/dist/features/security/application/createFlowSecurityPort.js.map +1 -0
- package/dist/features/security/domain/validateFlowSecurityTarget.d.ts +4 -0
- package/dist/features/security/domain/validateFlowSecurityTarget.d.ts.map +1 -0
- package/dist/features/security/domain/validateFlowSecurityTarget.js +57 -0
- package/dist/features/security/domain/validateFlowSecurityTarget.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.d.ts +4 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +3 -0
- package/dist/mcp.js.map +1 -0
- package/dist/social.d.ts +7 -0
- package/dist/social.d.ts.map +1 -0
- package/dist/social.js +7 -0
- package/dist/social.js.map +1 -0
- package/dist/types/execution.d.ts +33 -0
- package/dist/types/execution.d.ts.map +1 -0
- package/dist/types/execution.js +2 -0
- package/dist/types/execution.js.map +1 -0
- package/dist/types/mcp.d.ts +61 -0
- package/dist/types/mcp.d.ts.map +1 -0
- package/dist/types/mcp.js +2 -0
- package/dist/types/mcp.js.map +1 -0
- package/dist/types/security.d.ts +123 -0
- package/dist/types/security.d.ts.map +1 -0
- package/dist/types/security.js +2 -0
- package/dist/types/security.js.map +1 -0
- package/package.json +86 -4
- package/src/ai.ts +6 -0
- package/src/features/execution/application/executeFlowAsync.ts +338 -0
- package/src/features/execution/domain/assertFlowGraphSchemasSupported.ts +17 -0
- package/src/features/execution/domain/compileFlowGraph.ts +97 -0
- package/src/features/execution/domain/createDefaultNodeRegistry.ts +26 -0
- package/src/features/execution/domain/validateFlowDataSchema.ts +218 -0
- package/src/features/mcp/McpToolError.ts +10 -0
- package/src/features/mcp/createMcpRemoteTransport.ts +34 -0
- package/src/features/mcp/createMcpToolRegistry.ts +324 -0
- package/src/features/mcp/loadMcpSdkAsync.ts +32 -0
- package/src/features/mcp/prepareMcpProviders.ts +135 -0
- package/src/features/mcp/validateMcpSchema.ts +269 -0
- package/src/features/security/FlowSecurityError.ts +17 -0
- package/src/features/security/application/createFlowSecurityPort.ts +339 -0
- package/src/features/security/domain/validateFlowSecurityTarget.ts +73 -0
- package/src/index.ts +35 -0
- package/src/mcp.ts +11 -0
- package/src/social.ts +6 -0
- package/src/types/execution.ts +41 -0
- package/src/types/mcp.ts +70 -0
- package/src/types/security.ts +148 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { validateFlowSecurityTarget } from '../domain/validateFlowSecurityTarget.js';
|
|
2
|
+
import { FlowSecurityError } from '../FlowSecurityError.js';
|
|
3
|
+
const METADATA_CAPABILITY = 'secrets:metadata';
|
|
4
|
+
const CREATE_CAPABILITY = 'secrets:create';
|
|
5
|
+
const REVOKE_CAPABILITY = 'secrets:revoke';
|
|
6
|
+
/*** Creates the provider-neutral server-side authorization, approval, audit, and secret boundary. */
|
|
7
|
+
export const createFlowSecurityPort = (input) => ({
|
|
8
|
+
authorizeAsync: async (operation) => authorizeAsync(input, operation),
|
|
9
|
+
createSecretAsync: async (request) => createSecretAsync(input, request),
|
|
10
|
+
getSecretMetadataAsync: async ({ actor, ref }) => getSecretMetadataAsync(input, actor, ref),
|
|
11
|
+
revokeSecretAsync: async (request) => revokeSecretAsync(input, request),
|
|
12
|
+
});
|
|
13
|
+
/*** Authorizes and durably claims one exact operation before resolving any secret material. */
|
|
14
|
+
const authorizeAsync = async (input, operation) => {
|
|
15
|
+
const identity = identityOf(operation);
|
|
16
|
+
const targetHost = validateFlowSecurityTarget(identity.target);
|
|
17
|
+
if (!isGranted(input.grants, identity.actor, identity.capability))
|
|
18
|
+
return denyAsync(input.audit, identity, targetHost, 'permission_denied');
|
|
19
|
+
const approval = await input.approvalStore.getAsync(identity);
|
|
20
|
+
if (!approval || approval.status === 'pending')
|
|
21
|
+
return denyAsync(input.audit, identity, targetHost, 'approval_pending');
|
|
22
|
+
if (approval.status !== 'approved' || !sameIdentity(approval.operation, identity))
|
|
23
|
+
return denyAsync(input.audit, identity, targetHost, 'approval_rejected');
|
|
24
|
+
if (!(await input.operationStore.claimAsync(identity)))
|
|
25
|
+
return denyAsync(input.audit, identity, targetHost, 'idempotency_conflict');
|
|
26
|
+
try {
|
|
27
|
+
if (!(await input.rateLimit.acquireAsync({
|
|
28
|
+
actor: identity.actor,
|
|
29
|
+
capability: identity.capability,
|
|
30
|
+
operationId: identity.operationId,
|
|
31
|
+
})))
|
|
32
|
+
return denyAfterReleaseAsync(input, identity, targetHost, 'rate_limited');
|
|
33
|
+
await writeAuditAsync(input.audit, identity, targetHost, 'permitted', 'permission_denied');
|
|
34
|
+
return createPermit(input, identity);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
await input.operationStore.releaseAsync(identity);
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
/*** Creates a one-use permit that atomically consumes the durable operation claim before side effects. */
|
|
42
|
+
const createPermit = (input, identity) => ({
|
|
43
|
+
operation: identity,
|
|
44
|
+
executeAsync: async (callback) => {
|
|
45
|
+
if (!(await input.operationStore.consumeAsync(identity)))
|
|
46
|
+
throw new FlowSecurityError('idempotency_conflict', 'The operation permit has already been consumed.');
|
|
47
|
+
return resolveAndExecuteAsync(input, identity.actor, identity.secretRefs, callback);
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
/*** Releases an unconsumed claim before emitting a retryable denial. */
|
|
51
|
+
const denyAfterReleaseAsync = async (input, identity, targetHost, reason) => {
|
|
52
|
+
await input.operationStore.releaseAsync(identity);
|
|
53
|
+
return denyAsync(input.audit, identity, targetHost, reason);
|
|
54
|
+
};
|
|
55
|
+
/*** Creates a credential only after an explicit server-side scoped grant and redacted audit. */
|
|
56
|
+
const createSecretAsync = async (input, request) => {
|
|
57
|
+
const actor = snapshotActor(request.actor);
|
|
58
|
+
if (!isGranted(input.grants, actor, CREATE_CAPABILITY))
|
|
59
|
+
return denyCredentialAsync(input.audit, actor, request.ref, CREATE_CAPABILITY);
|
|
60
|
+
await writeCredentialAuditAsync(input.audit, actor, request.ref, CREATE_CAPABILITY);
|
|
61
|
+
const result = await input.secretStore.create({
|
|
62
|
+
kind: request.kind,
|
|
63
|
+
payload: request.payload,
|
|
64
|
+
...(request.provider === undefined ? {} : { provider: request.provider }),
|
|
65
|
+
ref: request.ref,
|
|
66
|
+
scope: scopeOf(actor),
|
|
67
|
+
});
|
|
68
|
+
if (!result.ok)
|
|
69
|
+
throw new FlowSecurityError('secret_unavailable', 'The requested secret is unavailable.');
|
|
70
|
+
return result.data;
|
|
71
|
+
};
|
|
72
|
+
/*** Returns metadata only after an explicit actor, tenant, project, and environment grant. */
|
|
73
|
+
const getSecretMetadataAsync = async (input, actor, ref) => {
|
|
74
|
+
const identity = snapshotActor(actor);
|
|
75
|
+
if (!isGranted(input.grants, identity, METADATA_CAPABILITY))
|
|
76
|
+
throw new FlowSecurityError('permission_denied', 'The actor is not permitted to inspect secrets.');
|
|
77
|
+
const result = await input.secretStore.getMetadata({ scope: scopeOf(identity), ref });
|
|
78
|
+
if (!result.ok)
|
|
79
|
+
throw new FlowSecurityError('secret_unavailable', 'The requested secret is unavailable.');
|
|
80
|
+
return result.data;
|
|
81
|
+
};
|
|
82
|
+
/*** Revokes a credential only after an explicit server-side scoped grant and redacted audit. */
|
|
83
|
+
const revokeSecretAsync = async (input, request) => {
|
|
84
|
+
const actor = snapshotActor(request.actor);
|
|
85
|
+
if (!isGranted(input.grants, actor, REVOKE_CAPABILITY))
|
|
86
|
+
return denyCredentialAsync(input.audit, actor, request.ref, REVOKE_CAPABILITY);
|
|
87
|
+
await writeCredentialAuditAsync(input.audit, actor, request.ref, REVOKE_CAPABILITY);
|
|
88
|
+
const result = await input.secretStore.remove({ ref: request.ref, scope: scopeOf(actor) });
|
|
89
|
+
if (!result.ok)
|
|
90
|
+
throw new FlowSecurityError('secret_unavailable', 'The requested secret is unavailable.');
|
|
91
|
+
};
|
|
92
|
+
/*** Resolves secrets only in the server-side callback after durable consumption succeeds. */
|
|
93
|
+
const resolveAndExecuteAsync = async (input, actor, secretRefs, callback) => {
|
|
94
|
+
const resolved = await Promise.all(secretRefs.map(async (ref) => [ref, await resolveSecretAsync(input.secretStore, actor, ref)]));
|
|
95
|
+
return callback(Object.fromEntries(resolved));
|
|
96
|
+
};
|
|
97
|
+
/*** Resolves one published secret reference without exposing a provider error or payload in failures. */
|
|
98
|
+
const resolveSecretAsync = async (secretStore, actor, ref) => {
|
|
99
|
+
const result = await secretStore.resolve({ scope: scopeOf(actor), ref });
|
|
100
|
+
if (!result.ok)
|
|
101
|
+
throw new FlowSecurityError('secret_unavailable', 'A required secret is unavailable.');
|
|
102
|
+
return result.data;
|
|
103
|
+
};
|
|
104
|
+
/*** Creates a deterministic complete identity from untrusted operation input. */
|
|
105
|
+
const identityOf = (operation) => Object.freeze({
|
|
106
|
+
actor: snapshotActor(operation.actor),
|
|
107
|
+
capability: operation.capability,
|
|
108
|
+
idempotencyKey: operation.idempotencyKey,
|
|
109
|
+
operationId: operation.operationId,
|
|
110
|
+
secretRefs: Object.freeze(unique(operation.secretRefs ?? [])),
|
|
111
|
+
...(operation.target
|
|
112
|
+
? {
|
|
113
|
+
target: Object.freeze({
|
|
114
|
+
allowedHosts: Object.freeze([...operation.target.allowedHosts]),
|
|
115
|
+
url: operation.target.url,
|
|
116
|
+
}),
|
|
117
|
+
}
|
|
118
|
+
: {}),
|
|
119
|
+
});
|
|
120
|
+
/*** Captures a runtime-immutable actor scope before any authorization boundary can await. */
|
|
121
|
+
const snapshotActor = (actor) => Object.freeze({ ...actor });
|
|
122
|
+
/*** Compares every authorization-relevant operation field without relying on object identity. */
|
|
123
|
+
const sameIdentity = (left, right) => left.actor.id === right.actor.id &&
|
|
124
|
+
left.actor.tenantId === right.actor.tenantId &&
|
|
125
|
+
left.actor.projectId === right.actor.projectId &&
|
|
126
|
+
left.actor.environment === right.actor.environment &&
|
|
127
|
+
left.capability === right.capability &&
|
|
128
|
+
left.idempotencyKey === right.idempotencyKey &&
|
|
129
|
+
left.operationId === right.operationId &&
|
|
130
|
+
sameStrings(left.secretRefs, right.secretRefs) &&
|
|
131
|
+
sameTarget(left.target, right.target);
|
|
132
|
+
/*** Compares target authority exactly so approvals cannot move an operation to another host. */
|
|
133
|
+
const sameTarget = (left, right) => left === undefined || right === undefined
|
|
134
|
+
? left === right
|
|
135
|
+
: left.url === right.url && sameStrings(left.allowedHosts, right.allowedHosts);
|
|
136
|
+
/*** Matches two ordered identity arrays exactly. */
|
|
137
|
+
const sameStrings = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
138
|
+
/*** Matches a grant only when all actor isolation dimensions are equal. */
|
|
139
|
+
const isGranted = (grants, actor, capability) => grants.some((grant) => grant.actorId === actor.id &&
|
|
140
|
+
grant.capability === capability &&
|
|
141
|
+
grant.tenantId === actor.tenantId &&
|
|
142
|
+
grant.projectId === actor.projectId &&
|
|
143
|
+
grant.environment === actor.environment);
|
|
144
|
+
/*** Converts a trusted actor boundary to the published secret-store scope. */
|
|
145
|
+
const scopeOf = (actor) => ({
|
|
146
|
+
projectId: actor.projectId,
|
|
147
|
+
environment: actor.environment,
|
|
148
|
+
});
|
|
149
|
+
/*** Deduplicates secret references without changing their deterministic order. */
|
|
150
|
+
const unique = (refs) => [...new Set(refs)];
|
|
151
|
+
/*** Audits a redacted decision before returning a stable denial. */
|
|
152
|
+
const denyAsync = async (audit, identity, targetHost, reason) => {
|
|
153
|
+
await writeAuditAsync(audit, identity, targetHost, 'denied', reason);
|
|
154
|
+
throw new FlowSecurityError(reason, denialMessage(reason));
|
|
155
|
+
};
|
|
156
|
+
/*** Emits only identifiers and target host metadata to the audit edge. */
|
|
157
|
+
const writeAuditAsync = (audit, identity, targetHost, decision, reason) => audit.writeAsync({
|
|
158
|
+
actorId: identity.actor.id,
|
|
159
|
+
capability: identity.capability,
|
|
160
|
+
decision,
|
|
161
|
+
operationId: identity.operationId,
|
|
162
|
+
reason,
|
|
163
|
+
secretRefs: identity.secretRefs,
|
|
164
|
+
...(targetHost ? { targetHost } : {}),
|
|
165
|
+
});
|
|
166
|
+
/*** Audits a credential-management decision without accepting its payload at the audit edge. */
|
|
167
|
+
const writeCredentialAuditAsync = (audit, actor, ref, capability) => audit.writeAsync({
|
|
168
|
+
actorId: actor.id,
|
|
169
|
+
capability,
|
|
170
|
+
decision: 'permitted',
|
|
171
|
+
operationId: ref,
|
|
172
|
+
reason: capability === CREATE_CAPABILITY ? 'credential_create' : 'credential_revoke',
|
|
173
|
+
secretRefs: [ref],
|
|
174
|
+
});
|
|
175
|
+
/*** Audits and returns a stable denial for unauthorized credential management. */
|
|
176
|
+
const denyCredentialAsync = async (audit, actor, ref, capability) => {
|
|
177
|
+
await audit.writeAsync({
|
|
178
|
+
actorId: actor.id,
|
|
179
|
+
capability,
|
|
180
|
+
decision: 'denied',
|
|
181
|
+
operationId: ref,
|
|
182
|
+
reason: 'permission_denied',
|
|
183
|
+
secretRefs: [ref],
|
|
184
|
+
});
|
|
185
|
+
throw new FlowSecurityError('permission_denied', 'The actor is not permitted to perform this operation.');
|
|
186
|
+
};
|
|
187
|
+
/*** Maps policy reasons to public redaction-safe error text. */
|
|
188
|
+
const denialMessage = (reason) => {
|
|
189
|
+
switch (reason) {
|
|
190
|
+
case 'approval_pending':
|
|
191
|
+
return 'The operation requires an approved Flow approval gate.';
|
|
192
|
+
case 'approval_rejected':
|
|
193
|
+
return 'The Flow approval gate rejected this operation.';
|
|
194
|
+
case 'idempotency_conflict':
|
|
195
|
+
return 'The idempotency key is already bound to another operation.';
|
|
196
|
+
case 'invalid_target':
|
|
197
|
+
return 'The external target is not permitted.';
|
|
198
|
+
case 'permission_denied':
|
|
199
|
+
return 'The actor is not permitted to perform this operation.';
|
|
200
|
+
case 'rate_limited':
|
|
201
|
+
return 'The operation is rate limited.';
|
|
202
|
+
case 'secret_unavailable':
|
|
203
|
+
return 'A required secret is unavailable.';
|
|
204
|
+
}
|
|
205
|
+
const impossible = reason;
|
|
206
|
+
return impossible;
|
|
207
|
+
};
|
|
208
|
+
//# sourceMappingURL=createFlowSecurityPort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createFlowSecurityPort.js","sourceRoot":"","sources":["../../../../src/features/security/application/createFlowSecurityPort.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SecretRef, SecretStoreAdapter } from '@ankhorage/contracts/secrets';\n\nimport type {\n FlowApprovalStorePort,\n FlowOperationStorePort,\n FlowRateLimitPort,\n FlowResolvedSecrets,\n FlowSecretCreateInput,\n FlowSecretMetadata,\n FlowSecretRevokeInput,\n FlowSecurityActor,\n FlowSecurityAuditEvent,\n FlowSecurityAuditPort,\n FlowSecurityGrant,\n FlowSecurityOperation,\n FlowSecurityOperationIdentity,\n FlowSecurityPermit,\n FlowSecurityPort,\n FlowSecurityTarget,\n} from '../../../types/security.js';\nimport { validateFlowSecurityTarget } from '../domain/validateFlowSecurityTarget.js';\nimport { FlowSecurityError } from '../FlowSecurityError.js';\n\nconst METADATA_CAPABILITY = 'secrets:metadata';\nconst CREATE_CAPABILITY = 'secrets:create';\nconst REVOKE_CAPABILITY = 'secrets:revoke';\ntype FlowSecurityDenialReason = Exclude<\n FlowSecurityAuditEvent['reason'],\n 'credential_create' | 'credential_revoke'\n>;\n\n/*** Creates the provider-neutral server-side authorization, approval, audit, and secret boundary. */\nexport const createFlowSecurityPort = (input: {\n readonly approvalStore: FlowApprovalStorePort;\n readonly audit: FlowSecurityAuditPort;\n readonly grants: readonly FlowSecurityGrant[];\n readonly operationStore: FlowOperationStorePort;\n readonly rateLimit: FlowRateLimitPort;\n readonly secretStore: SecretStoreAdapter;\n}): FlowSecurityPort => ({\n authorizeAsync: async (operation) => authorizeAsync(input, operation),\n createSecretAsync: async (request) => createSecretAsync(input, request),\n getSecretMetadataAsync: async ({ actor, ref }) => getSecretMetadataAsync(input, actor, ref),\n revokeSecretAsync: async (request) => revokeSecretAsync(input, request),\n});\n\n/*** Authorizes and durably claims one exact operation before resolving any secret material. */\nconst authorizeAsync = async (\n input: Parameters<typeof createFlowSecurityPort>[0],\n operation: FlowSecurityOperation,\n): Promise<FlowSecurityPermit> => {\n const identity = identityOf(operation);\n const targetHost = validateFlowSecurityTarget(identity.target);\n if (!isGranted(input.grants, identity.actor, identity.capability))\n return denyAsync(input.audit, identity, targetHost, 'permission_denied');\n const approval = await input.approvalStore.getAsync(identity);\n if (!approval || approval.status === 'pending')\n return denyAsync(input.audit, identity, targetHost, 'approval_pending');\n if (approval.status !== 'approved' || !sameIdentity(approval.operation, identity))\n return denyAsync(input.audit, identity, targetHost, 'approval_rejected');\n if (!(await input.operationStore.claimAsync(identity)))\n return denyAsync(input.audit, identity, targetHost, 'idempotency_conflict');\n try {\n if (\n !(await input.rateLimit.acquireAsync({\n actor: identity.actor,\n capability: identity.capability,\n operationId: identity.operationId,\n }))\n )\n return denyAfterReleaseAsync(input, identity, targetHost, 'rate_limited');\n await writeAuditAsync(input.audit, identity, targetHost, 'permitted', 'permission_denied');\n return createPermit(input, identity);\n } catch (error) {\n await input.operationStore.releaseAsync(identity);\n throw error;\n }\n};\n\n/*** Creates a one-use permit that atomically consumes the durable operation claim before side effects. */\nconst createPermit = (\n input: Parameters<typeof createFlowSecurityPort>[0],\n identity: FlowSecurityOperationIdentity,\n): FlowSecurityPermit => ({\n operation: identity,\n executeAsync: async (callback) => {\n if (!(await input.operationStore.consumeAsync(identity)))\n throw new FlowSecurityError(\n 'idempotency_conflict',\n 'The operation permit has already been consumed.',\n );\n return resolveAndExecuteAsync(input, identity.actor, identity.secretRefs, callback);\n },\n});\n\n/*** Releases an unconsumed claim before emitting a retryable denial. */\nconst denyAfterReleaseAsync = async (\n input: Parameters<typeof createFlowSecurityPort>[0],\n identity: FlowSecurityOperationIdentity,\n targetHost: string | undefined,\n reason: FlowSecurityDenialReason,\n): Promise<never> => {\n await input.operationStore.releaseAsync(identity);\n return denyAsync(input.audit, identity, targetHost, reason);\n};\n\n/*** Creates a credential only after an explicit server-side scoped grant and redacted audit. */\nconst createSecretAsync = async (\n input: Parameters<typeof createFlowSecurityPort>[0],\n request: FlowSecretCreateInput,\n): Promise<FlowSecretMetadata> => {\n const actor = snapshotActor(request.actor);\n if (!isGranted(input.grants, actor, CREATE_CAPABILITY))\n return denyCredentialAsync(input.audit, actor, request.ref, CREATE_CAPABILITY);\n await writeCredentialAuditAsync(input.audit, actor, request.ref, CREATE_CAPABILITY);\n const result = await input.secretStore.create({\n kind: request.kind,\n payload: request.payload,\n ...(request.provider === undefined ? {} : { provider: request.provider }),\n ref: request.ref,\n scope: scopeOf(actor),\n });\n if (!result.ok)\n throw new FlowSecurityError('secret_unavailable', 'The requested secret is unavailable.');\n return result.data;\n};\n\n/*** Returns metadata only after an explicit actor, tenant, project, and environment grant. */\nconst getSecretMetadataAsync = async (\n input: Parameters<typeof createFlowSecurityPort>[0],\n actor: FlowSecurityActor,\n ref: SecretRef,\n) => {\n const identity = snapshotActor(actor);\n if (!isGranted(input.grants, identity, METADATA_CAPABILITY))\n throw new FlowSecurityError(\n 'permission_denied',\n 'The actor is not permitted to inspect secrets.',\n );\n const result = await input.secretStore.getMetadata({ scope: scopeOf(identity), ref });\n if (!result.ok)\n throw new FlowSecurityError('secret_unavailable', 'The requested secret is unavailable.');\n return result.data;\n};\n\n/*** Revokes a credential only after an explicit server-side scoped grant and redacted audit. */\nconst revokeSecretAsync = async (\n input: Parameters<typeof createFlowSecurityPort>[0],\n request: FlowSecretRevokeInput,\n): Promise<void> => {\n const actor = snapshotActor(request.actor);\n if (!isGranted(input.grants, actor, REVOKE_CAPABILITY))\n return denyCredentialAsync(input.audit, actor, request.ref, REVOKE_CAPABILITY);\n await writeCredentialAuditAsync(input.audit, actor, request.ref, REVOKE_CAPABILITY);\n const result = await input.secretStore.remove({ ref: request.ref, scope: scopeOf(actor) });\n if (!result.ok)\n throw new FlowSecurityError('secret_unavailable', 'The requested secret is unavailable.');\n};\n\n/*** Resolves secrets only in the server-side callback after durable consumption succeeds. */\nconst resolveAndExecuteAsync = async <T>(\n input: Parameters<typeof createFlowSecurityPort>[0],\n actor: FlowSecurityActor,\n secretRefs: readonly SecretRef[],\n callback: (secrets: FlowResolvedSecrets) => Promise<T>,\n): Promise<T> => {\n const resolved = await Promise.all(\n secretRefs.map(\n async (ref) => [ref, await resolveSecretAsync(input.secretStore, actor, ref)] as const,\n ),\n );\n return callback(Object.fromEntries(resolved));\n};\n\n/*** Resolves one published secret reference without exposing a provider error or payload in failures. */\nconst resolveSecretAsync = async (\n secretStore: SecretStoreAdapter,\n actor: FlowSecurityActor,\n ref: SecretRef,\n) => {\n const result = await secretStore.resolve({ scope: scopeOf(actor), ref });\n if (!result.ok)\n throw new FlowSecurityError('secret_unavailable', 'A required secret is unavailable.');\n return result.data;\n};\n\n/*** Creates a deterministic complete identity from untrusted operation input. */\nconst identityOf = (operation: FlowSecurityOperation): FlowSecurityOperationIdentity =>\n Object.freeze({\n actor: snapshotActor(operation.actor),\n capability: operation.capability,\n idempotencyKey: operation.idempotencyKey,\n operationId: operation.operationId,\n secretRefs: Object.freeze(unique(operation.secretRefs ?? [])),\n ...(operation.target\n ? {\n target: Object.freeze({\n allowedHosts: Object.freeze([...operation.target.allowedHosts]),\n url: operation.target.url,\n }),\n }\n : {}),\n });\n\n/*** Captures a runtime-immutable actor scope before any authorization boundary can await. */\nconst snapshotActor = (actor: FlowSecurityActor): FlowSecurityActor => Object.freeze({ ...actor });\n\n/*** Compares every authorization-relevant operation field without relying on object identity. */\nconst sameIdentity = (\n left: FlowSecurityOperationIdentity,\n right: FlowSecurityOperationIdentity,\n): boolean =>\n left.actor.id === right.actor.id &&\n left.actor.tenantId === right.actor.tenantId &&\n left.actor.projectId === right.actor.projectId &&\n left.actor.environment === right.actor.environment &&\n left.capability === right.capability &&\n left.idempotencyKey === right.idempotencyKey &&\n left.operationId === right.operationId &&\n sameStrings(left.secretRefs, right.secretRefs) &&\n sameTarget(left.target, right.target);\n\n/*** Compares target authority exactly so approvals cannot move an operation to another host. */\nconst sameTarget = (\n left: FlowSecurityTarget | undefined,\n right: FlowSecurityTarget | undefined,\n): boolean =>\n left === undefined || right === undefined\n ? left === right\n : left.url === right.url && sameStrings(left.allowedHosts, right.allowedHosts);\n\n/*** Matches two ordered identity arrays exactly. */\nconst sameStrings = (left: readonly string[], right: readonly string[]): boolean =>\n JSON.stringify(left) === JSON.stringify(right);\n\n/*** Matches a grant only when all actor isolation dimensions are equal. */\nconst isGranted = (\n grants: readonly FlowSecurityGrant[],\n actor: FlowSecurityActor,\n capability: string,\n): boolean =>\n grants.some(\n (grant) =>\n grant.actorId === actor.id &&\n grant.capability === capability &&\n grant.tenantId === actor.tenantId &&\n grant.projectId === actor.projectId &&\n grant.environment === actor.environment,\n );\n/*** Converts a trusted actor boundary to the published secret-store scope. */\nconst scopeOf = (actor: FlowSecurityActor) => ({\n projectId: actor.projectId,\n environment: actor.environment,\n});\n/*** Deduplicates secret references without changing their deterministic order. */\nconst unique = (refs: readonly SecretRef[]): readonly SecretRef[] => [...new Set(refs)];\n/*** Audits a redacted decision before returning a stable denial. */\nconst denyAsync = async (\n audit: FlowSecurityAuditPort,\n identity: FlowSecurityOperationIdentity,\n targetHost: string | undefined,\n reason: FlowSecurityDenialReason,\n): Promise<never> => {\n await writeAuditAsync(audit, identity, targetHost, 'denied', reason);\n throw new FlowSecurityError(reason, denialMessage(reason));\n};\n/*** Emits only identifiers and target host metadata to the audit edge. */\nconst writeAuditAsync = (\n audit: FlowSecurityAuditPort,\n identity: FlowSecurityOperationIdentity,\n targetHost: string | undefined,\n decision: FlowSecurityAuditEvent['decision'],\n reason: FlowSecurityAuditEvent['reason'],\n): Promise<void> =>\n audit.writeAsync({\n actorId: identity.actor.id,\n capability: identity.capability,\n decision,\n operationId: identity.operationId,\n reason,\n secretRefs: identity.secretRefs,\n ...(targetHost ? { targetHost } : {}),\n });\n/*** Audits a credential-management decision without accepting its payload at the audit edge. */\nconst writeCredentialAuditAsync = (\n audit: FlowSecurityAuditPort,\n actor: FlowSecurityActor,\n ref: SecretRef,\n capability: typeof CREATE_CAPABILITY | typeof REVOKE_CAPABILITY,\n): Promise<void> =>\n audit.writeAsync({\n actorId: actor.id,\n capability,\n decision: 'permitted',\n operationId: ref,\n reason: capability === CREATE_CAPABILITY ? 'credential_create' : 'credential_revoke',\n secretRefs: [ref],\n });\n/*** Audits and returns a stable denial for unauthorized credential management. */\nconst denyCredentialAsync = async (\n audit: FlowSecurityAuditPort,\n actor: FlowSecurityActor,\n ref: SecretRef,\n capability: typeof CREATE_CAPABILITY | typeof REVOKE_CAPABILITY,\n): Promise<never> => {\n await audit.writeAsync({\n actorId: actor.id,\n capability,\n decision: 'denied',\n operationId: ref,\n reason: 'permission_denied',\n secretRefs: [ref],\n });\n throw new FlowSecurityError(\n 'permission_denied',\n 'The actor is not permitted to perform this operation.',\n );\n};\n/*** Maps policy reasons to public redaction-safe error text. */\nconst denialMessage = (reason: FlowSecurityDenialReason): string => {\n switch (reason) {\n case 'approval_pending':\n return 'The operation requires an approved Flow approval gate.';\n case 'approval_rejected':\n return 'The Flow approval gate rejected this operation.';\n case 'idempotency_conflict':\n return 'The idempotency key is already bound to another operation.';\n case 'invalid_target':\n return 'The external target is not permitted.';\n case 'permission_denied':\n return 'The actor is not permitted to perform this operation.';\n case 'rate_limited':\n return 'The operation is rate limited.';\n case 'secret_unavailable':\n return 'A required secret is unavailable.';\n }\n const impossible: never = reason;\n return impossible;\n};\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { FlowSecurityTarget } from '../../../types/security.js';
|
|
2
|
+
/*** Validates target syntax before the host transport verifies every resolved network peer. */
|
|
3
|
+
export declare const validateFlowSecurityTarget: (target: FlowSecurityTarget | undefined) => string | undefined;
|
|
4
|
+
//# sourceMappingURL=validateFlowSecurityTarget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateFlowSecurityTarget.d.ts","sourceRoot":"","sources":["../../../../src/features/security/domain/validateFlowSecurityTarget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAGrE,+FAA+F;AAC/F,eAAO,MAAM,0BAA0B,GACrC,QAAQ,kBAAkB,GAAG,SAAS,KACrC,MAAM,GAAG,SAuBX,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { FlowSecurityError } from '../FlowSecurityError.js';
|
|
2
|
+
/*** Validates target syntax before the host transport verifies every resolved network peer. */
|
|
3
|
+
export const validateFlowSecurityTarget = (target) => {
|
|
4
|
+
if (!target)
|
|
5
|
+
return undefined;
|
|
6
|
+
let url;
|
|
7
|
+
try {
|
|
8
|
+
url = new URL(target.url);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
throw new FlowSecurityError('invalid_target', 'External targets must be absolute HTTPS URLs.');
|
|
12
|
+
}
|
|
13
|
+
const host = url.hostname.replace(/^\[|\]$/g, '').toLowerCase();
|
|
14
|
+
if (url.protocol !== 'https:' ||
|
|
15
|
+
url.username ||
|
|
16
|
+
url.password ||
|
|
17
|
+
url.hash ||
|
|
18
|
+
!uniqueStrings(target.allowedHosts) ||
|
|
19
|
+
!target.allowedHosts.includes(host) ||
|
|
20
|
+
isUnsafeLiteralHost(host))
|
|
21
|
+
throw new FlowSecurityError('invalid_target', 'External targets must use an explicitly allowlisted public HTTPS host.');
|
|
22
|
+
return host;
|
|
23
|
+
};
|
|
24
|
+
/*** Rejects normalized loopback, local, private, and special-use IP literals before transport access. */
|
|
25
|
+
const isUnsafeLiteralHost = (host) => host === 'localhost' || host.endsWith('.localhost') || isUnsafeIpv4(host) || isUnsafeIpv6(host);
|
|
26
|
+
/*** Identifies IPv4 ranges that must never be an outbound target. */
|
|
27
|
+
const isUnsafeIpv4 = (host) => {
|
|
28
|
+
const parts = host.split('.').map(Number);
|
|
29
|
+
if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255))
|
|
30
|
+
return false;
|
|
31
|
+
const [first, second] = parts;
|
|
32
|
+
return (first === 0 ||
|
|
33
|
+
first === 10 ||
|
|
34
|
+
first === 127 ||
|
|
35
|
+
first >= 224 ||
|
|
36
|
+
(first === 169 && second === 254) ||
|
|
37
|
+
(first === 172 && second >= 16 && second <= 31) ||
|
|
38
|
+
(first === 192 && second === 168));
|
|
39
|
+
};
|
|
40
|
+
/*** Identifies IPv6 loopback, unspecified, unique-local, link-local, and mapped literal forms. */
|
|
41
|
+
const isUnsafeIpv6 = (host) => {
|
|
42
|
+
const normalized = host.toLowerCase();
|
|
43
|
+
return (normalized === '::' ||
|
|
44
|
+
normalized === '::1' ||
|
|
45
|
+
normalized.startsWith('fc') ||
|
|
46
|
+
normalized.startsWith('fd') ||
|
|
47
|
+
normalized.startsWith('fe8') ||
|
|
48
|
+
normalized.startsWith('fe9') ||
|
|
49
|
+
normalized.startsWith('fea') ||
|
|
50
|
+
normalized.startsWith('feb') ||
|
|
51
|
+
normalized.startsWith('::ffff:'));
|
|
52
|
+
};
|
|
53
|
+
/*** Checks unique non-empty authority strings. */
|
|
54
|
+
const uniqueStrings = (values) => values.length > 0 &&
|
|
55
|
+
values.every((value) => value.length > 0) &&
|
|
56
|
+
new Set(values).size === values.length;
|
|
57
|
+
//# sourceMappingURL=validateFlowSecurityTarget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateFlowSecurityTarget.js","sourceRoot":"","sources":["../../../../src/features/security/domain/validateFlowSecurityTarget.ts"],"names":[],"mappings":"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","sourcesContent":["import type { FlowSecurityTarget } from '../../../types/security.js';\nimport { FlowSecurityError } from '../FlowSecurityError.js';\n\n/*** Validates target syntax before the host transport verifies every resolved network peer. */\nexport const validateFlowSecurityTarget = (\n target: FlowSecurityTarget | undefined,\n): string | undefined => {\n if (!target) return undefined;\n let url: URL;\n try {\n url = new URL(target.url);\n } catch {\n throw new FlowSecurityError('invalid_target', 'External targets must be absolute HTTPS URLs.');\n }\n const host = url.hostname.replace(/^\\[|\\]$/g, '').toLowerCase();\n if (\n url.protocol !== 'https:' ||\n url.username ||\n url.password ||\n url.hash ||\n !uniqueStrings(target.allowedHosts) ||\n !target.allowedHosts.includes(host) ||\n isUnsafeLiteralHost(host)\n )\n throw new FlowSecurityError(\n 'invalid_target',\n 'External targets must use an explicitly allowlisted public HTTPS host.',\n );\n return host;\n};\n\n/*** Rejects normalized loopback, local, private, and special-use IP literals before transport access. */\nconst isUnsafeLiteralHost = (host: string): boolean =>\n host === 'localhost' || host.endsWith('.localhost') || isUnsafeIpv4(host) || isUnsafeIpv6(host);\n\n/*** Identifies IPv4 ranges that must never be an outbound target. */\nconst isUnsafeIpv4 = (host: string): boolean => {\n const parts = host.split('.').map(Number);\n if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255))\n return false;\n const [first, second] = parts as [number, number, number, number];\n return (\n first === 0 ||\n first === 10 ||\n first === 127 ||\n first >= 224 ||\n (first === 169 && second === 254) ||\n (first === 172 && second >= 16 && second <= 31) ||\n (first === 192 && second === 168)\n );\n};\n\n/*** Identifies IPv6 loopback, unspecified, unique-local, link-local, and mapped literal forms. */\nconst isUnsafeIpv6 = (host: string): boolean => {\n const normalized = host.toLowerCase();\n return (\n normalized === '::' ||\n normalized === '::1' ||\n normalized.startsWith('fc') ||\n normalized.startsWith('fd') ||\n normalized.startsWith('fe8') ||\n normalized.startsWith('fe9') ||\n normalized.startsWith('fea') ||\n normalized.startsWith('feb') ||\n normalized.startsWith('::ffff:')\n );\n};\n\n/*** Checks unique non-empty authority strings. */\nconst uniqueStrings = (values: readonly string[]): boolean =>\n values.length > 0 &&\n values.every((value) => value.length > 0) &&\n new Set(values).size === values.length;\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/*** Headless graph compilation and deterministic single-process execution. */
|
|
2
|
+
export { executeFlowAsync } from './features/execution/application/executeFlowAsync.js';
|
|
3
|
+
export { compileFlowGraph } from './features/execution/domain/compileFlowGraph.js';
|
|
4
|
+
export { createDefaultNodeRegistry } from './features/execution/domain/createDefaultNodeRegistry.js';
|
|
5
|
+
export { createFlowSecurityPort } from './features/security/application/createFlowSecurityPort.js';
|
|
6
|
+
export { FlowSecurityError } from './features/security/FlowSecurityError.js';
|
|
7
|
+
export type { FlowClock, FlowCompiledGraph, FlowExecutionResult, FlowNodeOperation, FlowNodeOperationResult, FlowNodeRegistry, FlowRunRequest, } from './types/execution.js';
|
|
8
|
+
export type { FlowApprovalStorePort, FlowOperationStorePort, FlowOutboundTransportPort, FlowRateLimitPort, FlowResolvedSecrets, FlowSecretCreateInput, FlowSecretMetadata, FlowSecretRevokeInput, FlowSecurityActor, FlowSecurityApproval, FlowSecurityAuditEvent, FlowSecurityAuditPort, FlowSecurityGrant, FlowSecurityOperation, FlowSecurityOperationIdentity, FlowSecurityPermit, FlowSecurityPort, FlowSecurityTarget, } from './types/security.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,sDAAsD,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iDAAiD,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,0DAA0D,CAAC;AACrG,OAAO,EAAE,sBAAsB,EAAE,MAAM,2DAA2D,CAAC;AACnG,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AAC7E,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,gBAAgB,EAChB,cAAc,GACf,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,qBAAqB,EACrB,sBAAsB,EACtB,yBAAyB,EACzB,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,6BAA6B,EAC7B,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/*** Headless graph compilation and deterministic single-process execution. */
|
|
2
|
+
export { executeFlowAsync } from './features/execution/application/executeFlowAsync.js';
|
|
3
|
+
export { compileFlowGraph } from './features/execution/domain/compileFlowGraph.js';
|
|
4
|
+
export { createDefaultNodeRegistry } from './features/execution/domain/createDefaultNodeRegistry.js';
|
|
5
|
+
export { createFlowSecurityPort } from './features/security/application/createFlowSecurityPort.js';
|
|
6
|
+
export { FlowSecurityError } from './features/security/FlowSecurityError.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,sDAAsD,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iDAAiD,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,0DAA0D,CAAC;AACrG,OAAO,EAAE,sBAAsB,EAAE,MAAM,2DAA2D,CAAC;AACnG,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC","sourcesContent":["/*** Headless graph compilation and deterministic single-process execution. */\nexport { executeFlowAsync } from './features/execution/application/executeFlowAsync.js';\nexport { compileFlowGraph } from './features/execution/domain/compileFlowGraph.js';\nexport { createDefaultNodeRegistry } from './features/execution/domain/createDefaultNodeRegistry.js';\nexport { createFlowSecurityPort } from './features/security/application/createFlowSecurityPort.js';\nexport { FlowSecurityError } from './features/security/FlowSecurityError.js';\nexport type {\n FlowClock,\n FlowCompiledGraph,\n FlowExecutionResult,\n FlowNodeOperation,\n FlowNodeOperationResult,\n FlowNodeRegistry,\n FlowRunRequest,\n} from './types/execution.js';\nexport type {\n FlowApprovalStorePort,\n FlowOperationStorePort,\n FlowOutboundTransportPort,\n FlowRateLimitPort,\n FlowResolvedSecrets,\n FlowSecretCreateInput,\n FlowSecretMetadata,\n FlowSecretRevokeInput,\n FlowSecurityActor,\n FlowSecurityApproval,\n FlowSecurityAuditEvent,\n FlowSecurityAuditPort,\n FlowSecurityGrant,\n FlowSecurityOperation,\n FlowSecurityOperationIdentity,\n FlowSecurityPermit,\n FlowSecurityPort,\n FlowSecurityTarget,\n} from './types/security.js';\n"]}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/*** Optional, allowlist-only MCP tool discovery and invocation integration. */
|
|
2
|
+
export { createMcpToolRegistry } from './features/mcp/createMcpToolRegistry.js';
|
|
3
|
+
export type { McpProviderDefinition, McpToolInvocation, McpToolMetadata, McpToolPermission, McpToolRegistry, McpToolResult, McpTrustedStdioProvider, } from './types/mcp.js';
|
|
4
|
+
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AAChF,YAAY,EACV,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,uBAAuB,GACxB,MAAM,gBAAgB,CAAC"}
|
package/dist/mcp.js
ADDED
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC","sourcesContent":["/*** Optional, allowlist-only MCP tool discovery and invocation integration. */\nexport { createMcpToolRegistry } from './features/mcp/createMcpToolRegistry.js';\nexport type {\n McpProviderDefinition,\n McpToolInvocation,\n McpToolMetadata,\n McpToolPermission,\n McpToolRegistry,\n McpToolResult,\n McpTrustedStdioProvider,\n} from './types/mcp.js';\n"]}
|
package/dist/social.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"social.d.ts","sourceRoot":"","sources":["../src/social.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,CAAC"}
|
package/dist/social.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"social.js","sourceRoot":"","sources":["../src/social.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,CAAC","sourcesContent":["/***\n * Reserved public subpath for future social-provider adapters.\n *\n * This bootstrap intentionally provides no social execution, configuration, or dependencies.\n */\nexport {};\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { DataSchemaRegistry } from '@ankhorage/contracts/data';
|
|
2
|
+
import type { FlowDataRef, FlowDefinition, FlowEdge, FlowNode, FlowNodeConfig, FlowPortId, FlowRunSnapshot } from '@ankhorage/contracts/flow';
|
|
3
|
+
export interface FlowClock {
|
|
4
|
+
readonly now: () => Date;
|
|
5
|
+
}
|
|
6
|
+
export interface FlowNodeOperationResult {
|
|
7
|
+
readonly output?: Readonly<Record<FlowPortId, FlowDataRef>>;
|
|
8
|
+
}
|
|
9
|
+
export interface FlowNodeOperation {
|
|
10
|
+
readonly executeAsync: (input: {
|
|
11
|
+
readonly config: FlowNodeConfig | undefined;
|
|
12
|
+
readonly input: Readonly<Record<FlowPortId, FlowDataRef>>;
|
|
13
|
+
readonly node: FlowNode;
|
|
14
|
+
readonly signal: AbortSignal;
|
|
15
|
+
}) => Promise<FlowNodeOperationResult>;
|
|
16
|
+
}
|
|
17
|
+
export type FlowNodeRegistry = Readonly<Record<string, FlowNodeOperation>>;
|
|
18
|
+
export interface FlowCompiledGraph {
|
|
19
|
+
readonly definition: FlowDefinition;
|
|
20
|
+
readonly edgesBySourceNodeId: Readonly<Record<string, readonly FlowEdge[]>>;
|
|
21
|
+
readonly topologicalNodeIds: readonly string[];
|
|
22
|
+
}
|
|
23
|
+
export interface FlowRunRequest {
|
|
24
|
+
readonly input?: Readonly<Record<FlowPortId, FlowDataRef>>;
|
|
25
|
+
readonly runId: string;
|
|
26
|
+
readonly schemaRegistry?: DataSchemaRegistry;
|
|
27
|
+
readonly signal?: AbortSignal;
|
|
28
|
+
readonly triggerId: string;
|
|
29
|
+
}
|
|
30
|
+
export interface FlowExecutionResult {
|
|
31
|
+
readonly run: FlowRunSnapshot;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=execution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../../src/types/execution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,UAAU,EACV,eAAe,EAChB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,IAAI,CAAC;CAC1B;AACD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;CAC7D;AACD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,YAAY,EAAE,CAAC,KAAK,EAAE;QAC7B,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,CAAC;QAC5C,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;QAC1D,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;QACxB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;KAC9B,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;CACxC;AACD,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC;AAC3E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,QAAQ,CAAC,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC5E,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;CAChD;AACD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;IAC3D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,cAAc,CAAC,EAAE,kBAAkB,CAAC;IAC7C,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AACD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAC;CAC/B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution.js","sourceRoot":"","sources":["../../src/types/execution.ts"],"names":[],"mappings":"","sourcesContent":["import type { DataSchemaRegistry } from '@ankhorage/contracts/data';\nimport type {\n FlowDataRef,\n FlowDefinition,\n FlowEdge,\n FlowNode,\n FlowNodeConfig,\n FlowPortId,\n FlowRunSnapshot,\n} from '@ankhorage/contracts/flow';\n\nexport interface FlowClock {\n readonly now: () => Date;\n}\nexport interface FlowNodeOperationResult {\n readonly output?: Readonly<Record<FlowPortId, FlowDataRef>>;\n}\nexport interface FlowNodeOperation {\n readonly executeAsync: (input: {\n readonly config: FlowNodeConfig | undefined;\n readonly input: Readonly<Record<FlowPortId, FlowDataRef>>;\n readonly node: FlowNode;\n readonly signal: AbortSignal;\n }) => Promise<FlowNodeOperationResult>;\n}\nexport type FlowNodeRegistry = Readonly<Record<string, FlowNodeOperation>>;\nexport interface FlowCompiledGraph {\n readonly definition: FlowDefinition;\n readonly edgesBySourceNodeId: Readonly<Record<string, readonly FlowEdge[]>>;\n readonly topologicalNodeIds: readonly string[];\n}\nexport interface FlowRunRequest {\n readonly input?: Readonly<Record<FlowPortId, FlowDataRef>>;\n readonly runId: string;\n readonly schemaRegistry?: DataSchemaRegistry;\n readonly signal?: AbortSignal;\n readonly triggerId: string;\n}\nexport interface FlowExecutionResult {\n readonly run: FlowRunSnapshot;\n}\n"]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { SecretRef } from '@ankhorage/contracts/secrets';
|
|
2
|
+
import type { FlowSecurityActor } from './security.js';
|
|
3
|
+
/** Public configuration and results for the optional MCP integration. */
|
|
4
|
+
export interface McpToolPermission {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly grantedScopes: readonly string[];
|
|
7
|
+
}
|
|
8
|
+
export type McpProviderDefinition = {
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly transport: 'remote';
|
|
11
|
+
readonly endpoint: string;
|
|
12
|
+
readonly allowedHosts: readonly string[];
|
|
13
|
+
readonly allowedTools: readonly McpToolPermission[];
|
|
14
|
+
readonly grantedScopes: readonly string[];
|
|
15
|
+
readonly timeoutMs?: number;
|
|
16
|
+
} | {
|
|
17
|
+
readonly id: string;
|
|
18
|
+
readonly transport: 'stdio';
|
|
19
|
+
readonly allowedTools: readonly McpToolPermission[];
|
|
20
|
+
readonly grantedScopes: readonly string[];
|
|
21
|
+
readonly timeoutMs?: number;
|
|
22
|
+
};
|
|
23
|
+
/** Host-owned command configuration. It is deliberately separate from workflow provider data. */
|
|
24
|
+
export interface McpTrustedStdioProvider {
|
|
25
|
+
readonly command: string;
|
|
26
|
+
readonly args?: readonly string[];
|
|
27
|
+
}
|
|
28
|
+
export interface McpToolMetadata {
|
|
29
|
+
readonly providerId: string;
|
|
30
|
+
readonly name: string;
|
|
31
|
+
readonly title?: string;
|
|
32
|
+
readonly description?: string;
|
|
33
|
+
readonly inputSchema: Readonly<Record<string, unknown>>;
|
|
34
|
+
readonly schemaFingerprint: string;
|
|
35
|
+
readonly scopes: readonly string[];
|
|
36
|
+
readonly readOnly: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface McpToolInvocation {
|
|
39
|
+
readonly providerId: string;
|
|
40
|
+
readonly toolName: string;
|
|
41
|
+
readonly schemaFingerprint: string;
|
|
42
|
+
readonly arguments: Readonly<Record<string, unknown>>;
|
|
43
|
+
readonly scopes: readonly string[];
|
|
44
|
+
readonly security: {
|
|
45
|
+
readonly actor: FlowSecurityActor;
|
|
46
|
+
readonly idempotencyKey: string;
|
|
47
|
+
readonly operationId: string;
|
|
48
|
+
readonly secretRefs?: readonly SecretRef[];
|
|
49
|
+
};
|
|
50
|
+
readonly signal?: AbortSignal;
|
|
51
|
+
}
|
|
52
|
+
export interface McpToolResult {
|
|
53
|
+
readonly content: readonly unknown[];
|
|
54
|
+
readonly structuredContent?: Readonly<Record<string, unknown>>;
|
|
55
|
+
readonly isError: boolean;
|
|
56
|
+
}
|
|
57
|
+
export interface McpToolRegistry {
|
|
58
|
+
discoverAsync(signal?: AbortSignal): Promise<readonly McpToolMetadata[]>;
|
|
59
|
+
invokeAsync(invocation: McpToolInvocation): Promise<McpToolResult>;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/types/mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/types/mcp.ts"],"names":[],"mappings":"","sourcesContent":["import type { SecretRef } from '@ankhorage/contracts/secrets';\n\nimport type { FlowSecurityActor } from './security.js';\n\n/** Public configuration and results for the optional MCP integration. */\nexport interface McpToolPermission {\n readonly name: string;\n readonly grantedScopes: readonly string[];\n}\n\nexport type McpProviderDefinition =\n | {\n readonly id: string;\n readonly transport: 'remote';\n readonly endpoint: string;\n readonly allowedHosts: readonly string[];\n readonly allowedTools: readonly McpToolPermission[];\n readonly grantedScopes: readonly string[];\n readonly timeoutMs?: number;\n }\n | {\n readonly id: string;\n readonly transport: 'stdio';\n readonly allowedTools: readonly McpToolPermission[];\n readonly grantedScopes: readonly string[];\n readonly timeoutMs?: number;\n };\n\n/** Host-owned command configuration. It is deliberately separate from workflow provider data. */\nexport interface McpTrustedStdioProvider {\n readonly command: string;\n readonly args?: readonly string[];\n}\n\nexport interface McpToolMetadata {\n readonly providerId: string;\n readonly name: string;\n readonly title?: string;\n readonly description?: string;\n readonly inputSchema: Readonly<Record<string, unknown>>;\n readonly schemaFingerprint: string;\n readonly scopes: readonly string[];\n readonly readOnly: boolean;\n}\n\nexport interface McpToolInvocation {\n readonly providerId: string;\n readonly toolName: string;\n readonly schemaFingerprint: string;\n readonly arguments: Readonly<Record<string, unknown>>;\n readonly scopes: readonly string[];\n readonly security: {\n readonly actor: FlowSecurityActor;\n readonly idempotencyKey: string;\n readonly operationId: string;\n readonly secretRefs?: readonly SecretRef[];\n };\n readonly signal?: AbortSignal;\n}\n\nexport interface McpToolResult {\n readonly content: readonly unknown[];\n readonly structuredContent?: Readonly<Record<string, unknown>>;\n readonly isError: boolean;\n}\n\nexport interface McpToolRegistry {\n discoverAsync(signal?: AbortSignal): Promise<readonly McpToolMetadata[]>;\n invokeAsync(invocation: McpToolInvocation): Promise<McpToolResult>;\n}\n"]}
|