@aexhq/sdk 0.13.6
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/LICENSE +201 -0
- package/README.md +160 -0
- package/dist/_contracts/connection-ticket.d.ts +21 -0
- package/dist/_contracts/connection-ticket.js +49 -0
- package/dist/_contracts/event-envelope.d.ts +276 -0
- package/dist/_contracts/event-envelope.js +324 -0
- package/dist/_contracts/event-stream-client.d.ts +47 -0
- package/dist/_contracts/event-stream-client.js +141 -0
- package/dist/_contracts/http.d.ts +35 -0
- package/dist/_contracts/http.js +114 -0
- package/dist/_contracts/index.d.ts +28 -0
- package/dist/_contracts/index.js +29 -0
- package/dist/_contracts/managed-key.d.ts +74 -0
- package/dist/_contracts/managed-key.js +110 -0
- package/dist/_contracts/operations.d.ts +237 -0
- package/dist/_contracts/operations.js +632 -0
- package/dist/_contracts/provider-support.d.ts +220 -0
- package/dist/_contracts/provider-support.js +90 -0
- package/dist/_contracts/proxy-protocol.d.ts +257 -0
- package/dist/_contracts/proxy-protocol.js +234 -0
- package/dist/_contracts/proxy-validation.d.ts +19 -0
- package/dist/_contracts/proxy-validation.js +51 -0
- package/dist/_contracts/run-artifacts.d.ts +47 -0
- package/dist/_contracts/run-artifacts.js +101 -0
- package/dist/_contracts/run-config.d.ts +304 -0
- package/dist/_contracts/run-config.js +659 -0
- package/dist/_contracts/run-cost.d.ts +125 -0
- package/dist/_contracts/run-cost.js +616 -0
- package/dist/_contracts/run-custody.d.ts +226 -0
- package/dist/_contracts/run-custody.js +465 -0
- package/dist/_contracts/run-record.d.ts +127 -0
- package/dist/_contracts/run-record.js +177 -0
- package/dist/_contracts/run-retention.d.ts +213 -0
- package/dist/_contracts/run-retention.js +484 -0
- package/dist/_contracts/run-unit.d.ts +194 -0
- package/dist/_contracts/run-unit.js +215 -0
- package/dist/_contracts/runner-event.d.ts +114 -0
- package/dist/_contracts/runner-event.js +187 -0
- package/dist/_contracts/runtime-manifest.d.ts +106 -0
- package/dist/_contracts/runtime-manifest.js +98 -0
- package/dist/_contracts/runtime-security-profile.d.ts +27 -0
- package/dist/_contracts/runtime-security-profile.js +82 -0
- package/dist/_contracts/runtime-sizes.d.ts +144 -0
- package/dist/_contracts/runtime-sizes.js +136 -0
- package/dist/_contracts/runtime-types.d.ts +212 -0
- package/dist/_contracts/runtime-types.js +2 -0
- package/dist/_contracts/sdk-errors.d.ts +34 -0
- package/dist/_contracts/sdk-errors.js +52 -0
- package/dist/_contracts/sdk-secrets.d.ts +31 -0
- package/dist/_contracts/sdk-secrets.js +220 -0
- package/dist/_contracts/side-effect-audit.d.ts +129 -0
- package/dist/_contracts/side-effect-audit.js +494 -0
- package/dist/_contracts/sse.d.ts +74 -0
- package/dist/_contracts/sse.js +0 -0
- package/dist/_contracts/stable.d.ts +26 -0
- package/dist/_contracts/stable.js +44 -0
- package/dist/_contracts/status.d.ts +19 -0
- package/dist/_contracts/status.js +61 -0
- package/dist/_contracts/submission.d.ts +383 -0
- package/dist/_contracts/submission.js +1380 -0
- package/dist/agents-md.d.ts +46 -0
- package/dist/agents-md.js +83 -0
- package/dist/agents-md.js.map +1 -0
- package/dist/asset-upload.d.ts +66 -0
- package/dist/asset-upload.js +168 -0
- package/dist/asset-upload.js.map +1 -0
- package/dist/bundle.d.ts +33 -0
- package/dist/bundle.js +89 -0
- package/dist/bundle.js.map +1 -0
- package/dist/cli.mjs +4140 -0
- package/dist/cli.mjs.sha256 +1 -0
- package/dist/client.d.ts +460 -0
- package/dist/client.js +857 -0
- package/dist/client.js.map +1 -0
- package/dist/fetch-archive.d.ts +16 -0
- package/dist/fetch-archive.js +170 -0
- package/dist/fetch-archive.js.map +1 -0
- package/dist/file.d.ts +57 -0
- package/dist/file.js +153 -0
- package/dist/file.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.d.ts +84 -0
- package/dist/mcp-server.js +114 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/node-fs.d.ts +12 -0
- package/dist/node-fs.js +44 -0
- package/dist/node-fs.js.map +1 -0
- package/dist/proxy-endpoint.d.ts +131 -0
- package/dist/proxy-endpoint.js +147 -0
- package/dist/proxy-endpoint.js.map +1 -0
- package/dist/skill.d.ts +117 -0
- package/dist/skill.js +169 -0
- package/dist/skill.js.map +1 -0
- package/dist/version.d.ts +9 -0
- package/dist/version.js +10 -0
- package/dist/version.js.map +1 -0
- package/docs/cleanup.md +38 -0
- package/docs/credentials.md +153 -0
- package/docs/events.md +76 -0
- package/docs/mcp.md +47 -0
- package/docs/outputs.md +157 -0
- package/docs/product-boundaries.md +57 -0
- package/docs/provider-runtime-capabilities.md +103 -0
- package/docs/quickstart.md +110 -0
- package/docs/release.md +99 -0
- package/docs/run-config.md +53 -0
- package/docs/run-record.md +39 -0
- package/docs/skills.md +139 -0
- package/docs/testing.md +29 -0
- package/package.json +47 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { CredentialMode } from "./managed-key.js";
|
|
2
|
+
import type { RunProvider, RuntimeKind } from "./submission.js";
|
|
3
|
+
export declare const SIDE_EFFECT_AUDIT_SCHEMA_VERSION = 1;
|
|
4
|
+
export declare const SIDE_EFFECT_AUDIT_REDACTION_SCANNER_VERSION = 1;
|
|
5
|
+
export declare const SIDE_EFFECT_AUDIT_KIND = "aex.side_effect_audit.v1";
|
|
6
|
+
export declare const SIDE_EFFECT_AUDIT_ACTIONS: readonly ["run.submit.accepted", "run.submit.rejected", "run.cancel.requested", "run.delete.requested", "run.delete.completed", "run.delete.failed", "run.download.requested", "run.output.downloaded", "run.log.downloaded", "run.event.downloaded", "workspace.asset.uploaded", "workspace.asset.deleted", "proxy.endpoint.called", "mcp.credential.accessed", "mcp.proxy.called", "provider.proxy.called", "custody.manifest.written", "custody.transition.recorded", "runtime.cleanup.completed", "runtime.cleanup.failed", "managed_key.quota.denied", "terminal_redrive.attempted", "terminal_redrive.completed", "api_token.created", "api_token.revoked", "api_token.used"];
|
|
7
|
+
export type SideEffectAuditAction = (typeof SIDE_EFFECT_AUDIT_ACTIONS)[number];
|
|
8
|
+
export declare const SIDE_EFFECT_AUDIT_ACTOR_PRINCIPAL_TYPES: readonly ["user", "api_token", "system", "runtime"];
|
|
9
|
+
export type SideEffectAuditActorPrincipalType = (typeof SIDE_EFFECT_AUDIT_ACTOR_PRINCIPAL_TYPES)[number];
|
|
10
|
+
export declare const SIDE_EFFECT_AUDIT_SOURCE_PLANES: readonly ["dashboard", "worker", "runtime", "system"];
|
|
11
|
+
export type SideEffectAuditSourcePlane = (typeof SIDE_EFFECT_AUDIT_SOURCE_PLANES)[number];
|
|
12
|
+
export declare const SIDE_EFFECT_AUDIT_AUTHENTICATION_KINDS: readonly ["dashboard_auth", "api_token", "runner_token", "system"];
|
|
13
|
+
export type SideEffectAuditAuthenticationKind = (typeof SIDE_EFFECT_AUDIT_AUTHENTICATION_KINDS)[number];
|
|
14
|
+
export declare const SIDE_EFFECT_AUDIT_TARGET_TYPES: readonly ["workspace", "run", "proxy_endpoint", "mcp_credential", "mcp_proxy", "provider_proxy", "output_archive", "run_output", "run_log", "run_event_stream", "workspace_asset", "custody_manifest", "custody_transition", "cleanup", "deletion", "managed_key_gate", "terminal_redrive", "api_token"];
|
|
15
|
+
export type SideEffectAuditTargetType = (typeof SIDE_EFFECT_AUDIT_TARGET_TYPES)[number];
|
|
16
|
+
export declare const SIDE_EFFECT_AUDIT_OUTCOMES: readonly ["accepted", "rejected", "succeeded", "failed", "denied", "canceled", "pending"];
|
|
17
|
+
export type SideEffectAuditOutcome = (typeof SIDE_EFFECT_AUDIT_OUTCOMES)[number];
|
|
18
|
+
export declare const SIDE_EFFECT_AUDIT_COUNT_NAMES: readonly ["requestBytes", "responseBytes", "durationMs", "attemptCount", "retryCount", "outputCount", "logCount", "eventCount", "assetCount", "proxyCallCount", "mcpCallCount", "providerProxyCallCount", "secretClassCount", "resourceClassCount", "deletedObjectCount", "retainedObjectCount", "failedObjectCount", "quotaRequestedUnits", "quotaRemainingUnits", "reservationCount"];
|
|
19
|
+
export type SideEffectAuditCountName = (typeof SIDE_EFFECT_AUDIT_COUNT_NAMES)[number];
|
|
20
|
+
export declare const SIDE_EFFECT_AUDIT_TIMESTAMP_NAMES: readonly ["startedAt", "finishedAt", "observedAt", "decidedAt", "deletedAt", "tombstonedAt", "terminalAt", "expiresAt"];
|
|
21
|
+
export type SideEffectAuditTimestampName = (typeof SIDE_EFFECT_AUDIT_TIMESTAMP_NAMES)[number];
|
|
22
|
+
export declare const SIDE_EFFECT_AUDIT_METADATA_EXCLUDED_VALUE_CLASSES: readonly ["headers", "bodies", "raw_urls", "raw_paths", "query_strings", "provider_response_bodies", "signed_urls", "r2_object_keys", "vault_ids", "resource_handles", "bearer_hashes", "secret_values", "customer_or_agent_identity", "private_pricing_or_provider_deployment"];
|
|
23
|
+
export type SideEffectAuditMetadataExcludedValueClass = (typeof SIDE_EFFECT_AUDIT_METADATA_EXCLUDED_VALUE_CLASSES)[number];
|
|
24
|
+
export interface SideEffectAuditPrincipalV1 {
|
|
25
|
+
readonly type: SideEffectAuditActorPrincipalType;
|
|
26
|
+
/**
|
|
27
|
+
* Existing platform principal reference such as app-user id or API-token id.
|
|
28
|
+
* This is not an agent id, customer end-user id, provider session id, or
|
|
29
|
+
* stateful identity primitive.
|
|
30
|
+
*/
|
|
31
|
+
readonly ref?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface SideEffectAuditActorV1 {
|
|
34
|
+
readonly principal: SideEffectAuditPrincipalV1;
|
|
35
|
+
readonly sourcePlane: SideEffectAuditSourcePlane;
|
|
36
|
+
readonly authenticatedBy?: SideEffectAuditAuthenticationKind;
|
|
37
|
+
}
|
|
38
|
+
export interface SideEffectAuditTargetV1 {
|
|
39
|
+
readonly type: SideEffectAuditTargetType;
|
|
40
|
+
readonly id?: string;
|
|
41
|
+
readonly name?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface SideEffectAuditCorrelationV1 {
|
|
44
|
+
readonly requestId?: string;
|
|
45
|
+
readonly operationId?: string;
|
|
46
|
+
readonly eventId?: string;
|
|
47
|
+
readonly parentAuditId?: string;
|
|
48
|
+
readonly sourceAuditId?: string;
|
|
49
|
+
readonly idempotencyKeyRef?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface SideEffectAuditStatusMetadataV1 {
|
|
52
|
+
readonly status?: string;
|
|
53
|
+
readonly statusCode?: number;
|
|
54
|
+
readonly errorClass?: string;
|
|
55
|
+
readonly denialReason?: string;
|
|
56
|
+
readonly followUpRequired?: boolean;
|
|
57
|
+
}
|
|
58
|
+
export interface SideEffectAuditDimensionsMetadataV1 {
|
|
59
|
+
readonly provider?: RunProvider | string;
|
|
60
|
+
readonly runtime?: RuntimeKind | string;
|
|
61
|
+
readonly credentialMode?: CredentialMode;
|
|
62
|
+
readonly namespace?: "metadata" | "events" | "logs" | "outputs" | "archive";
|
|
63
|
+
readonly method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
64
|
+
readonly surface?: string;
|
|
65
|
+
}
|
|
66
|
+
export interface SideEffectAuditRedactionMetadataV1 {
|
|
67
|
+
readonly policy: "metadata_only";
|
|
68
|
+
readonly scannerVersion: typeof SIDE_EFFECT_AUDIT_REDACTION_SCANNER_VERSION;
|
|
69
|
+
readonly excludes: readonly SideEffectAuditMetadataExcludedValueClass[];
|
|
70
|
+
}
|
|
71
|
+
export interface SideEffectAuditMetadataV1 {
|
|
72
|
+
readonly status?: SideEffectAuditStatusMetadataV1;
|
|
73
|
+
readonly counts?: Readonly<Partial<Record<SideEffectAuditCountName, number>>>;
|
|
74
|
+
readonly timestamps?: Readonly<Partial<Record<SideEffectAuditTimestampName, string>>>;
|
|
75
|
+
readonly dimensions?: SideEffectAuditDimensionsMetadataV1;
|
|
76
|
+
readonly redaction: SideEffectAuditRedactionMetadataV1;
|
|
77
|
+
}
|
|
78
|
+
export interface SideEffectAuditEventV1 {
|
|
79
|
+
readonly schemaVersion: typeof SIDE_EFFECT_AUDIT_SCHEMA_VERSION;
|
|
80
|
+
readonly kind: typeof SIDE_EFFECT_AUDIT_KIND;
|
|
81
|
+
readonly auditId?: string;
|
|
82
|
+
readonly workspaceId: string;
|
|
83
|
+
readonly runId?: string;
|
|
84
|
+
readonly action: SideEffectAuditAction;
|
|
85
|
+
readonly outcome: SideEffectAuditOutcome;
|
|
86
|
+
readonly observedAt: string;
|
|
87
|
+
readonly actor: SideEffectAuditActorV1;
|
|
88
|
+
readonly target: SideEffectAuditTargetV1;
|
|
89
|
+
readonly correlation?: SideEffectAuditCorrelationV1;
|
|
90
|
+
readonly metadata: SideEffectAuditMetadataV1;
|
|
91
|
+
}
|
|
92
|
+
export type SideEffectAuditPrincipalInput = SideEffectAuditPrincipalV1;
|
|
93
|
+
export type SideEffectAuditActorInput = SideEffectAuditActorV1;
|
|
94
|
+
export type SideEffectAuditTargetInput = SideEffectAuditTargetV1;
|
|
95
|
+
export type SideEffectAuditCorrelationInput = SideEffectAuditCorrelationV1;
|
|
96
|
+
export type SideEffectAuditMetadataInput = Omit<SideEffectAuditMetadataV1, "redaction"> & {
|
|
97
|
+
readonly redaction?: never;
|
|
98
|
+
};
|
|
99
|
+
export type SideEffectAuditEventInput = Omit<SideEffectAuditEventV1, "schemaVersion" | "kind" | "metadata"> & {
|
|
100
|
+
readonly metadata?: SideEffectAuditMetadataInput;
|
|
101
|
+
};
|
|
102
|
+
export interface SideEffectAuditRunScopedInput {
|
|
103
|
+
readonly workspaceId: string;
|
|
104
|
+
readonly runId: string;
|
|
105
|
+
readonly observedAt: string;
|
|
106
|
+
readonly actor: SideEffectAuditActorInput;
|
|
107
|
+
readonly correlation?: SideEffectAuditCorrelationInput;
|
|
108
|
+
readonly metadata?: SideEffectAuditMetadataInput;
|
|
109
|
+
}
|
|
110
|
+
export type SideEffectAuditRedactionReason = "forbidden_field_name" | "bearer_token" | "provider_key" | "signed_url" | "r2_object_key" | "vault_id" | "private_resource_handle" | "raw_url" | "raw_path" | "high_entropy_token";
|
|
111
|
+
export interface SideEffectAuditRedactionFinding {
|
|
112
|
+
readonly path: string;
|
|
113
|
+
readonly reason: SideEffectAuditRedactionReason;
|
|
114
|
+
readonly valueLength?: number;
|
|
115
|
+
}
|
|
116
|
+
export declare class SideEffectAuditRedactionError extends Error {
|
|
117
|
+
readonly code = "side_effect_audit_not_public_safe";
|
|
118
|
+
readonly findings: readonly SideEffectAuditRedactionFinding[];
|
|
119
|
+
constructor(findings: readonly SideEffectAuditRedactionFinding[]);
|
|
120
|
+
}
|
|
121
|
+
export declare function buildSideEffectAuditEvent(input: SideEffectAuditEventInput): SideEffectAuditEventV1;
|
|
122
|
+
export declare function buildRunDeletionRequestedAuditEvent(input: SideEffectAuditRunScopedInput): SideEffectAuditEventV1;
|
|
123
|
+
export declare function buildRunDeletionCompletedAuditEvent(input: SideEffectAuditRunScopedInput): SideEffectAuditEventV1;
|
|
124
|
+
export declare function buildRunDeletionFailedAuditEvent(input: SideEffectAuditRunScopedInput): SideEffectAuditEventV1;
|
|
125
|
+
export declare function buildRunDownloadRequestedAuditEvent(input: SideEffectAuditRunScopedInput): SideEffectAuditEventV1;
|
|
126
|
+
export declare function buildCustodyManifestWrittenAuditEvent(input: SideEffectAuditRunScopedInput): SideEffectAuditEventV1;
|
|
127
|
+
export declare function redactSideEffectAuditMetadata(input: SideEffectAuditMetadataInput, action?: SideEffectAuditAction): SideEffectAuditMetadataV1;
|
|
128
|
+
export declare function scanSideEffectAuditPayloadForSensitiveValues(input: unknown): readonly SideEffectAuditRedactionFinding[];
|
|
129
|
+
export declare function assertPublicSafeSideEffectAuditPayload(input: unknown): void;
|
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
export const SIDE_EFFECT_AUDIT_SCHEMA_VERSION = 1;
|
|
2
|
+
export const SIDE_EFFECT_AUDIT_REDACTION_SCANNER_VERSION = 1;
|
|
3
|
+
export const SIDE_EFFECT_AUDIT_KIND = "aex.side_effect_audit.v1";
|
|
4
|
+
export const SIDE_EFFECT_AUDIT_ACTIONS = [
|
|
5
|
+
"run.submit.accepted",
|
|
6
|
+
"run.submit.rejected",
|
|
7
|
+
"run.cancel.requested",
|
|
8
|
+
"run.delete.requested",
|
|
9
|
+
"run.delete.completed",
|
|
10
|
+
"run.delete.failed",
|
|
11
|
+
"run.download.requested",
|
|
12
|
+
"run.output.downloaded",
|
|
13
|
+
"run.log.downloaded",
|
|
14
|
+
"run.event.downloaded",
|
|
15
|
+
"workspace.asset.uploaded",
|
|
16
|
+
"workspace.asset.deleted",
|
|
17
|
+
"proxy.endpoint.called",
|
|
18
|
+
"mcp.credential.accessed",
|
|
19
|
+
"mcp.proxy.called",
|
|
20
|
+
"provider.proxy.called",
|
|
21
|
+
"custody.manifest.written",
|
|
22
|
+
"custody.transition.recorded",
|
|
23
|
+
"runtime.cleanup.completed",
|
|
24
|
+
"runtime.cleanup.failed",
|
|
25
|
+
"managed_key.quota.denied",
|
|
26
|
+
"terminal_redrive.attempted",
|
|
27
|
+
"terminal_redrive.completed",
|
|
28
|
+
"api_token.created",
|
|
29
|
+
"api_token.revoked",
|
|
30
|
+
"api_token.used"
|
|
31
|
+
];
|
|
32
|
+
export const SIDE_EFFECT_AUDIT_ACTOR_PRINCIPAL_TYPES = [
|
|
33
|
+
"user",
|
|
34
|
+
"api_token",
|
|
35
|
+
"system",
|
|
36
|
+
"runtime"
|
|
37
|
+
];
|
|
38
|
+
export const SIDE_EFFECT_AUDIT_SOURCE_PLANES = [
|
|
39
|
+
"dashboard",
|
|
40
|
+
"worker",
|
|
41
|
+
"runtime",
|
|
42
|
+
"system"
|
|
43
|
+
];
|
|
44
|
+
export const SIDE_EFFECT_AUDIT_AUTHENTICATION_KINDS = [
|
|
45
|
+
"dashboard_auth",
|
|
46
|
+
"api_token",
|
|
47
|
+
"runner_token",
|
|
48
|
+
"system"
|
|
49
|
+
];
|
|
50
|
+
export const SIDE_EFFECT_AUDIT_TARGET_TYPES = [
|
|
51
|
+
"workspace",
|
|
52
|
+
"run",
|
|
53
|
+
"proxy_endpoint",
|
|
54
|
+
"mcp_credential",
|
|
55
|
+
"mcp_proxy",
|
|
56
|
+
"provider_proxy",
|
|
57
|
+
"output_archive",
|
|
58
|
+
"run_output",
|
|
59
|
+
"run_log",
|
|
60
|
+
"run_event_stream",
|
|
61
|
+
"workspace_asset",
|
|
62
|
+
"custody_manifest",
|
|
63
|
+
"custody_transition",
|
|
64
|
+
"cleanup",
|
|
65
|
+
"deletion",
|
|
66
|
+
"managed_key_gate",
|
|
67
|
+
"terminal_redrive",
|
|
68
|
+
"api_token"
|
|
69
|
+
];
|
|
70
|
+
export const SIDE_EFFECT_AUDIT_OUTCOMES = [
|
|
71
|
+
"accepted",
|
|
72
|
+
"rejected",
|
|
73
|
+
"succeeded",
|
|
74
|
+
"failed",
|
|
75
|
+
"denied",
|
|
76
|
+
"canceled",
|
|
77
|
+
"pending"
|
|
78
|
+
];
|
|
79
|
+
export const SIDE_EFFECT_AUDIT_COUNT_NAMES = [
|
|
80
|
+
"requestBytes",
|
|
81
|
+
"responseBytes",
|
|
82
|
+
"durationMs",
|
|
83
|
+
"attemptCount",
|
|
84
|
+
"retryCount",
|
|
85
|
+
"outputCount",
|
|
86
|
+
"logCount",
|
|
87
|
+
"eventCount",
|
|
88
|
+
"assetCount",
|
|
89
|
+
"proxyCallCount",
|
|
90
|
+
"mcpCallCount",
|
|
91
|
+
"providerProxyCallCount",
|
|
92
|
+
"secretClassCount",
|
|
93
|
+
"resourceClassCount",
|
|
94
|
+
"deletedObjectCount",
|
|
95
|
+
"retainedObjectCount",
|
|
96
|
+
"failedObjectCount",
|
|
97
|
+
"quotaRequestedUnits",
|
|
98
|
+
"quotaRemainingUnits",
|
|
99
|
+
"reservationCount"
|
|
100
|
+
];
|
|
101
|
+
export const SIDE_EFFECT_AUDIT_TIMESTAMP_NAMES = [
|
|
102
|
+
"startedAt",
|
|
103
|
+
"finishedAt",
|
|
104
|
+
"observedAt",
|
|
105
|
+
"decidedAt",
|
|
106
|
+
"deletedAt",
|
|
107
|
+
"tombstonedAt",
|
|
108
|
+
"terminalAt",
|
|
109
|
+
"expiresAt"
|
|
110
|
+
];
|
|
111
|
+
export const SIDE_EFFECT_AUDIT_METADATA_EXCLUDED_VALUE_CLASSES = [
|
|
112
|
+
"headers",
|
|
113
|
+
"bodies",
|
|
114
|
+
"raw_urls",
|
|
115
|
+
"raw_paths",
|
|
116
|
+
"query_strings",
|
|
117
|
+
"provider_response_bodies",
|
|
118
|
+
"signed_urls",
|
|
119
|
+
"r2_object_keys",
|
|
120
|
+
"vault_ids",
|
|
121
|
+
"resource_handles",
|
|
122
|
+
"bearer_hashes",
|
|
123
|
+
"secret_values",
|
|
124
|
+
"customer_or_agent_identity",
|
|
125
|
+
"private_pricing_or_provider_deployment"
|
|
126
|
+
];
|
|
127
|
+
export class SideEffectAuditRedactionError extends Error {
|
|
128
|
+
code = "side_effect_audit_not_public_safe";
|
|
129
|
+
findings;
|
|
130
|
+
constructor(findings) {
|
|
131
|
+
super(`side-effect audit payload contains non-public data at ${formatFindingPaths(findings)}`);
|
|
132
|
+
this.name = "SideEffectAuditRedactionError";
|
|
133
|
+
this.findings = Object.freeze([...findings]);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export function buildSideEffectAuditEvent(input) {
|
|
137
|
+
const action = normalizeAction(input.action);
|
|
138
|
+
const event = Object.freeze({
|
|
139
|
+
schemaVersion: SIDE_EFFECT_AUDIT_SCHEMA_VERSION,
|
|
140
|
+
kind: SIDE_EFFECT_AUDIT_KIND,
|
|
141
|
+
...(input.auditId ? { auditId: assertSafeIdentifier(input.auditId, "auditId") } : {}),
|
|
142
|
+
workspaceId: assertSafeIdentifier(input.workspaceId, "workspaceId"),
|
|
143
|
+
...(input.runId ? { runId: assertSafeIdentifier(input.runId, "runId") } : {}),
|
|
144
|
+
action,
|
|
145
|
+
outcome: normalizeOutcome(input.outcome),
|
|
146
|
+
observedAt: assertTimestamp(input.observedAt, "observedAt"),
|
|
147
|
+
actor: normalizeActor(input.actor),
|
|
148
|
+
target: normalizeTarget(input.target),
|
|
149
|
+
...(input.correlation ? { correlation: normalizeCorrelation(input.correlation) } : {}),
|
|
150
|
+
metadata: redactSideEffectAuditMetadata(input.metadata ?? {}, action)
|
|
151
|
+
});
|
|
152
|
+
assertPublicSafeSideEffectAuditPayload(event);
|
|
153
|
+
return event;
|
|
154
|
+
}
|
|
155
|
+
export function buildRunDeletionRequestedAuditEvent(input) {
|
|
156
|
+
return buildRunScopedAuditEvent(input, {
|
|
157
|
+
action: "run.delete.requested",
|
|
158
|
+
outcome: "accepted",
|
|
159
|
+
targetType: "deletion"
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
export function buildRunDeletionCompletedAuditEvent(input) {
|
|
163
|
+
return buildRunScopedAuditEvent(input, {
|
|
164
|
+
action: "run.delete.completed",
|
|
165
|
+
outcome: "succeeded",
|
|
166
|
+
targetType: "deletion"
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
export function buildRunDeletionFailedAuditEvent(input) {
|
|
170
|
+
return buildRunScopedAuditEvent(input, {
|
|
171
|
+
action: "run.delete.failed",
|
|
172
|
+
outcome: "failed",
|
|
173
|
+
targetType: "deletion"
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
export function buildRunDownloadRequestedAuditEvent(input) {
|
|
177
|
+
return buildRunScopedAuditEvent(input, {
|
|
178
|
+
action: "run.download.requested",
|
|
179
|
+
outcome: "accepted",
|
|
180
|
+
targetType: "output_archive"
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
export function buildCustodyManifestWrittenAuditEvent(input) {
|
|
184
|
+
return buildRunScopedAuditEvent(input, {
|
|
185
|
+
action: "custody.manifest.written",
|
|
186
|
+
outcome: "succeeded",
|
|
187
|
+
targetType: "custody_manifest"
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
export function redactSideEffectAuditMetadata(input, action) {
|
|
191
|
+
assertPublicSafeSideEffectAuditPayload(input);
|
|
192
|
+
assertSupportedMetadataKeys(input, action);
|
|
193
|
+
const metadata = Object.freeze({
|
|
194
|
+
...(input.status ? { status: normalizeStatusMetadata(input.status) } : {}),
|
|
195
|
+
...(input.counts ? { counts: normalizeCounts(input.counts) } : {}),
|
|
196
|
+
...(input.timestamps ? { timestamps: normalizeTimestamps(input.timestamps) } : {}),
|
|
197
|
+
...(input.dimensions && !isDeletionAction(action)
|
|
198
|
+
? { dimensions: normalizeDimensions(input.dimensions) }
|
|
199
|
+
: {}),
|
|
200
|
+
redaction: Object.freeze({
|
|
201
|
+
policy: "metadata_only",
|
|
202
|
+
scannerVersion: SIDE_EFFECT_AUDIT_REDACTION_SCANNER_VERSION,
|
|
203
|
+
excludes: Object.freeze([...SIDE_EFFECT_AUDIT_METADATA_EXCLUDED_VALUE_CLASSES])
|
|
204
|
+
})
|
|
205
|
+
});
|
|
206
|
+
assertPublicSafeSideEffectAuditPayload(metadata);
|
|
207
|
+
return metadata;
|
|
208
|
+
}
|
|
209
|
+
export function scanSideEffectAuditPayloadForSensitiveValues(input) {
|
|
210
|
+
const findings = [];
|
|
211
|
+
visitAuditValue(input, "$", findings);
|
|
212
|
+
return Object.freeze(findings);
|
|
213
|
+
}
|
|
214
|
+
export function assertPublicSafeSideEffectAuditPayload(input) {
|
|
215
|
+
const findings = scanSideEffectAuditPayloadForSensitiveValues(input);
|
|
216
|
+
if (findings.length > 0) {
|
|
217
|
+
throw new SideEffectAuditRedactionError(findings);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function normalizeActor(input) {
|
|
221
|
+
if (!input || typeof input !== "object") {
|
|
222
|
+
throw new Error("side-effect audit actor must be an object");
|
|
223
|
+
}
|
|
224
|
+
return Object.freeze({
|
|
225
|
+
principal: normalizePrincipal(input.principal),
|
|
226
|
+
sourcePlane: normalizeSourcePlane(input.sourcePlane),
|
|
227
|
+
...(input.authenticatedBy ? { authenticatedBy: normalizeAuthentication(input.authenticatedBy) } : {})
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
function normalizePrincipal(input) {
|
|
231
|
+
if (!input || typeof input !== "object") {
|
|
232
|
+
throw new Error("side-effect audit actor principal must be an object");
|
|
233
|
+
}
|
|
234
|
+
const type = normalizePrincipalType(input.type);
|
|
235
|
+
const ref = input.ref ? assertSafePrincipalRef(input.ref, "actor.principal.ref") : undefined;
|
|
236
|
+
return Object.freeze({
|
|
237
|
+
type,
|
|
238
|
+
...(ref ? { ref } : {})
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
function normalizeTarget(input) {
|
|
242
|
+
if (!input || typeof input !== "object") {
|
|
243
|
+
throw new Error("side-effect audit target must be an object");
|
|
244
|
+
}
|
|
245
|
+
return Object.freeze({
|
|
246
|
+
type: normalizeTargetType(input.type),
|
|
247
|
+
...(input.id ? { id: assertSafeIdentifier(input.id, "target.id") } : {}),
|
|
248
|
+
...(input.name ? { name: assertSafeMetadataString(input.name, "target.name") } : {})
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
function normalizeCorrelation(input) {
|
|
252
|
+
return Object.freeze({
|
|
253
|
+
...(input.requestId ? { requestId: assertSafeIdentifier(input.requestId, "correlation.requestId") } : {}),
|
|
254
|
+
...(input.operationId
|
|
255
|
+
? { operationId: assertSafeIdentifier(input.operationId, "correlation.operationId") }
|
|
256
|
+
: {}),
|
|
257
|
+
...(input.eventId ? { eventId: assertSafeIdentifier(input.eventId, "correlation.eventId") } : {}),
|
|
258
|
+
...(input.parentAuditId
|
|
259
|
+
? { parentAuditId: assertSafeIdentifier(input.parentAuditId, "correlation.parentAuditId") }
|
|
260
|
+
: {}),
|
|
261
|
+
...(input.sourceAuditId
|
|
262
|
+
? { sourceAuditId: assertSafeIdentifier(input.sourceAuditId, "correlation.sourceAuditId") }
|
|
263
|
+
: {}),
|
|
264
|
+
...(input.idempotencyKeyRef
|
|
265
|
+
? {
|
|
266
|
+
idempotencyKeyRef: assertSafeIdentifier(input.idempotencyKeyRef, "correlation.idempotencyKeyRef")
|
|
267
|
+
}
|
|
268
|
+
: {})
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
function normalizeStatusMetadata(input) {
|
|
272
|
+
assertSupportedNestedKeys(input, ["status", "statusCode", "errorClass", "denialReason", "followUpRequired"], "metadata.status");
|
|
273
|
+
return Object.freeze({
|
|
274
|
+
...(input.status ? { status: assertSafeMetadataString(input.status, "metadata.status.status") } : {}),
|
|
275
|
+
...(input.statusCode !== undefined
|
|
276
|
+
? { statusCode: nonNegativeInteger(input.statusCode, "metadata.status.statusCode") }
|
|
277
|
+
: {}),
|
|
278
|
+
...(input.errorClass
|
|
279
|
+
? { errorClass: assertSafeMetadataString(input.errorClass, "metadata.status.errorClass") }
|
|
280
|
+
: {}),
|
|
281
|
+
...(input.denialReason
|
|
282
|
+
? { denialReason: assertSafeMetadataString(input.denialReason, "metadata.status.denialReason") }
|
|
283
|
+
: {}),
|
|
284
|
+
...(input.followUpRequired !== undefined ? { followUpRequired: input.followUpRequired } : {})
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
function normalizeCounts(input) {
|
|
288
|
+
const out = {};
|
|
289
|
+
for (const [key, value] of Object.entries(input)) {
|
|
290
|
+
if (!isStringIn(key, SIDE_EFFECT_AUDIT_COUNT_NAMES)) {
|
|
291
|
+
throw new Error(`side-effect audit metadata.counts.${key} is not supported`);
|
|
292
|
+
}
|
|
293
|
+
if (value !== undefined) {
|
|
294
|
+
out[key] = nonNegativeFinite(value, `metadata.counts.${key}`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return Object.freeze(out);
|
|
298
|
+
}
|
|
299
|
+
function normalizeTimestamps(input) {
|
|
300
|
+
const out = {};
|
|
301
|
+
for (const [key, value] of Object.entries(input)) {
|
|
302
|
+
if (!isStringIn(key, SIDE_EFFECT_AUDIT_TIMESTAMP_NAMES)) {
|
|
303
|
+
throw new Error(`side-effect audit metadata.timestamps.${key} is not supported`);
|
|
304
|
+
}
|
|
305
|
+
if (value !== undefined) {
|
|
306
|
+
out[key] = assertTimestamp(value, `metadata.timestamps.${key}`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return Object.freeze(out);
|
|
310
|
+
}
|
|
311
|
+
function normalizeDimensions(input) {
|
|
312
|
+
assertSupportedNestedKeys(input, ["provider", "runtime", "credentialMode", "namespace", "method", "surface"], "metadata.dimensions");
|
|
313
|
+
return Object.freeze({
|
|
314
|
+
...(input.provider ? { provider: assertSafeMetadataString(input.provider, "metadata.dimensions.provider") } : {}),
|
|
315
|
+
...(input.runtime ? { runtime: assertSafeMetadataString(input.runtime, "metadata.dimensions.runtime") } : {}),
|
|
316
|
+
...(input.credentialMode ? { credentialMode: input.credentialMode } : {}),
|
|
317
|
+
...(input.namespace ? { namespace: input.namespace } : {}),
|
|
318
|
+
...(input.method ? { method: input.method } : {}),
|
|
319
|
+
...(input.surface ? { surface: assertSafeMetadataString(input.surface, "metadata.dimensions.surface") } : {})
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
function assertSupportedMetadataKeys(input, action) {
|
|
323
|
+
const allowed = isDeletionAction(action)
|
|
324
|
+
? ["status", "counts", "timestamps"]
|
|
325
|
+
: ["status", "counts", "timestamps", "dimensions"];
|
|
326
|
+
assertSupportedNestedKeys(input, allowed, "metadata");
|
|
327
|
+
}
|
|
328
|
+
function assertSupportedNestedKeys(input, allowed, field) {
|
|
329
|
+
for (const key of Object.keys(input)) {
|
|
330
|
+
if (!allowed.includes(key)) {
|
|
331
|
+
throw new Error(`side-effect audit ${field}.${key} is not supported`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
function buildRunScopedAuditEvent(input, spec) {
|
|
336
|
+
return buildSideEffectAuditEvent({
|
|
337
|
+
workspaceId: input.workspaceId,
|
|
338
|
+
runId: input.runId,
|
|
339
|
+
action: spec.action,
|
|
340
|
+
outcome: spec.outcome,
|
|
341
|
+
observedAt: input.observedAt,
|
|
342
|
+
actor: input.actor,
|
|
343
|
+
target: { type: spec.targetType, id: input.runId },
|
|
344
|
+
...(input.correlation ? { correlation: input.correlation } : {}),
|
|
345
|
+
...(input.metadata ? { metadata: input.metadata } : {})
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
function normalizeAction(input) {
|
|
349
|
+
if (!isStringIn(input, SIDE_EFFECT_AUDIT_ACTIONS)) {
|
|
350
|
+
throw new Error(`side-effect audit action ${String(input)} is not supported`);
|
|
351
|
+
}
|
|
352
|
+
return input;
|
|
353
|
+
}
|
|
354
|
+
function normalizeOutcome(input) {
|
|
355
|
+
if (!isStringIn(input, SIDE_EFFECT_AUDIT_OUTCOMES)) {
|
|
356
|
+
throw new Error(`side-effect audit outcome ${String(input)} is not supported`);
|
|
357
|
+
}
|
|
358
|
+
return input;
|
|
359
|
+
}
|
|
360
|
+
function normalizePrincipalType(input) {
|
|
361
|
+
if (!isStringIn(input, SIDE_EFFECT_AUDIT_ACTOR_PRINCIPAL_TYPES)) {
|
|
362
|
+
throw new Error(`side-effect audit principal type ${String(input)} is not supported`);
|
|
363
|
+
}
|
|
364
|
+
return input;
|
|
365
|
+
}
|
|
366
|
+
function normalizeSourcePlane(input) {
|
|
367
|
+
if (!isStringIn(input, SIDE_EFFECT_AUDIT_SOURCE_PLANES)) {
|
|
368
|
+
throw new Error(`side-effect audit source plane ${String(input)} is not supported`);
|
|
369
|
+
}
|
|
370
|
+
return input;
|
|
371
|
+
}
|
|
372
|
+
function normalizeAuthentication(input) {
|
|
373
|
+
if (!isStringIn(input, SIDE_EFFECT_AUDIT_AUTHENTICATION_KINDS)) {
|
|
374
|
+
throw new Error(`side-effect audit authentication kind ${String(input)} is not supported`);
|
|
375
|
+
}
|
|
376
|
+
return input;
|
|
377
|
+
}
|
|
378
|
+
function normalizeTargetType(input) {
|
|
379
|
+
if (!isStringIn(input, SIDE_EFFECT_AUDIT_TARGET_TYPES)) {
|
|
380
|
+
throw new Error(`side-effect audit target type ${String(input)} is not supported`);
|
|
381
|
+
}
|
|
382
|
+
return input;
|
|
383
|
+
}
|
|
384
|
+
function isDeletionAction(action) {
|
|
385
|
+
return action === "run.delete.requested" || action === "run.delete.completed" || action === "run.delete.failed";
|
|
386
|
+
}
|
|
387
|
+
function visitAuditValue(input, path, findings) {
|
|
388
|
+
if (typeof input === "string") {
|
|
389
|
+
scanStringValue(input, path, findings);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
if (Array.isArray(input)) {
|
|
393
|
+
input.forEach((value, index) => visitAuditValue(value, `${path}[${index}]`, findings));
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
if (!input || typeof input !== "object") {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
for (const [key, value] of Object.entries(input)) {
|
|
400
|
+
const childPath = `${path}.${key}`;
|
|
401
|
+
if (isForbiddenAuditFieldName(key)) {
|
|
402
|
+
findings.push(Object.freeze({ path: childPath, reason: "forbidden_field_name" }));
|
|
403
|
+
}
|
|
404
|
+
visitAuditValue(value, childPath, findings);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function scanStringValue(value, path, findings) {
|
|
408
|
+
for (const pattern of forbiddenStringPatterns) {
|
|
409
|
+
if (pattern.regex.test(value)) {
|
|
410
|
+
findings.push(Object.freeze({
|
|
411
|
+
path,
|
|
412
|
+
reason: pattern.reason,
|
|
413
|
+
valueLength: value.length
|
|
414
|
+
}));
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
const forbiddenStringPatterns = Object.freeze([
|
|
419
|
+
{ reason: "bearer_token", regex: /\bBearer\s+[A-Za-z0-9._~+/=-]{8,}/i },
|
|
420
|
+
{
|
|
421
|
+
reason: "provider_key",
|
|
422
|
+
regex: /\b(?:sk-(?:ant|proj|live|test|deepseek|openai)|xox[baprs]-|AIza)[A-Za-z0-9_-]{8,}/i
|
|
423
|
+
},
|
|
424
|
+
{ reason: "signed_url", regex: /[?&](?:X-Amz-Signature|X-Amz-Credential|X-Amz-Algorithm|AWSAccessKeyId)=/i },
|
|
425
|
+
{ reason: "r2_object_key", regex: /(^|[\s"'`])(?:runs|assets)\/[^?<#\s"'`]+/i },
|
|
426
|
+
{ reason: "vault_id", regex: /\b(?:vault|vlt|secret)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i },
|
|
427
|
+
{
|
|
428
|
+
reason: "private_resource_handle",
|
|
429
|
+
regex: /\b(?:machine|session|agent|file|skill|env|resource|handle|token_hash|bearer_hash)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i
|
|
430
|
+
},
|
|
431
|
+
{ reason: "raw_url", regex: /\bhttps?:\/\/\S+/i },
|
|
432
|
+
{ reason: "raw_path", regex: /(^|[\s"'`])\/[A-Za-z0-9._~!$&'()*+,;=:@%-]+(?:[/?#][^\s"'`]*)?/ },
|
|
433
|
+
{ reason: "high_entropy_token", regex: /\b(?=[A-Za-z0-9_-]{40,}\b)(?=.*[A-Za-z])(?=.*\d)[A-Za-z0-9_-]{40,}\b/ }
|
|
434
|
+
]);
|
|
435
|
+
function isForbiddenAuditFieldName(key) {
|
|
436
|
+
return /^(authorization|headers?|requestHeaders?|responseHeaders?|body|requestBody|responseBody|rawBody|prompt|url|rawUrl|href|query|queryString|path|rawPath|signedUrl|r2Key|objectKey|vaultId|providerResponseBody|providerAccountId|providerDeployment|rateCard|rateCardVersion|margin|discount|calculator|reconciliation|resourceHandle|privateResourceHandle|bearerHash|tokenHash|apiKey|secretValue|sessionId|providerSessionId|agentId|customerId|endUserId|identity|email)$/i.test(key);
|
|
437
|
+
}
|
|
438
|
+
function assertSafeIdentifier(value, field) {
|
|
439
|
+
assertNonEmptyString(value, field);
|
|
440
|
+
if (!/^[A-Za-z0-9._:-]+$/.test(value)) {
|
|
441
|
+
throw new Error(`side-effect audit ${field} must be an opaque identifier without path separators`);
|
|
442
|
+
}
|
|
443
|
+
assertPublicSafeSideEffectAuditPayload(value);
|
|
444
|
+
return value;
|
|
445
|
+
}
|
|
446
|
+
function assertSafePrincipalRef(value, field) {
|
|
447
|
+
assertNonEmptyString(value, field);
|
|
448
|
+
if (!/^[A-Za-z0-9._:-]+$/.test(value)) {
|
|
449
|
+
throw new Error(`side-effect audit ${field} must be an opaque identifier without path separators`);
|
|
450
|
+
}
|
|
451
|
+
const ref = value;
|
|
452
|
+
if (/^(?:agent|session|customer|end[_-]?user|provider[_-]?session)[_.:-]/i.test(ref)) {
|
|
453
|
+
throw new Error(`side-effect audit ${field} must not introduce agent, session, or customer identity`);
|
|
454
|
+
}
|
|
455
|
+
assertPublicSafeSideEffectAuditPayload(ref);
|
|
456
|
+
return ref;
|
|
457
|
+
}
|
|
458
|
+
function assertSafeMetadataString(value, field) {
|
|
459
|
+
assertNonEmptyString(value, field);
|
|
460
|
+
assertPublicSafeSideEffectAuditPayload(value);
|
|
461
|
+
return value;
|
|
462
|
+
}
|
|
463
|
+
function assertNonEmptyString(value, field) {
|
|
464
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
465
|
+
throw new Error(`side-effect audit ${field} must be a non-empty string`);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
function assertTimestamp(value, field) {
|
|
469
|
+
assertSafeMetadataString(value, field);
|
|
470
|
+
const ms = Date.parse(value);
|
|
471
|
+
if (!Number.isFinite(ms)) {
|
|
472
|
+
throw new Error(`side-effect audit ${field} must be an ISO timestamp string`);
|
|
473
|
+
}
|
|
474
|
+
return value;
|
|
475
|
+
}
|
|
476
|
+
function nonNegativeInteger(value, field) {
|
|
477
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
478
|
+
throw new Error(`side-effect audit ${field} must be a non-negative safe integer`);
|
|
479
|
+
}
|
|
480
|
+
return value;
|
|
481
|
+
}
|
|
482
|
+
function nonNegativeFinite(value, field) {
|
|
483
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
484
|
+
throw new Error(`side-effect audit ${field} must be a non-negative finite number`);
|
|
485
|
+
}
|
|
486
|
+
return value;
|
|
487
|
+
}
|
|
488
|
+
function formatFindingPaths(findings) {
|
|
489
|
+
return findings.map((finding) => `${finding.path} (${finding.reason})`).join(", ");
|
|
490
|
+
}
|
|
491
|
+
function isStringIn(value, allowed) {
|
|
492
|
+
return typeof value === "string" && allowed.includes(value);
|
|
493
|
+
}
|
|
494
|
+
//# sourceMappingURL=side-effect-audit.js.map
|