@kya-os/checkpoint-wasm-runtime 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +215 -0
- package/dist/engine-edge.d.mts +52 -16
- package/dist/engine-edge.d.ts +52 -16
- package/dist/engine-edge.js +11 -4
- package/dist/engine-edge.mjs +11 -4
- package/dist/index.d.mts +118 -1
- package/dist/index.d.ts +118 -1
- package/dist/orchestrator-edge.js +46 -13
- package/dist/orchestrator-edge.mjs +46 -13
- package/dist/orchestrator-node.js +35 -9
- package/dist/orchestrator-node.mjs +35 -9
- package/dist/orchestrator.d.mts +52 -16
- package/dist/orchestrator.d.ts +52 -16
- package/dist/orchestrator.js +46 -13
- package/dist/orchestrator.mjs +46 -13
- package/dist/policy.d.mts +148 -0
- package/dist/policy.d.ts +148 -0
- package/dist/policy.js +52 -0
- package/dist/policy.mjs +53 -0
- package/dist/reporter.d.mts +102 -0
- package/dist/reporter.d.ts +102 -0
- package/dist/reporter.js +125 -0
- package/dist/reporter.mjs +122 -0
- package/package.json +15 -5
- package/wasm/kya-os-engine/kya_os_engine_bg.wasm +0 -0
- package/wasm/kya-os-engine/package.json +4 -2
- package/wasm/kya-os-engine-bundler/kya_os_engine_bg.wasm +0 -0
- package/wasm/kya-os-engine-cedar/README.md +26 -0
- package/wasm/kya-os-engine-cedar/kya_os_engine.d.ts +77 -0
- package/wasm/kya-os-engine-cedar/kya_os_engine.js +636 -0
- package/wasm/kya-os-engine-cedar/kya_os_engine_bg.wasm +0 -0
- package/wasm/kya-os-engine-cedar/kya_os_engine_bg.wasm.d.ts +11 -0
- package/wasm/kya-os-engine-cedar/package.json +29 -0
- package/wasm/kya-os-engine-cedar-web/README.md +26 -0
- package/wasm/kya-os-engine-cedar-web/kya_os_engine.d.ts +117 -0
- package/wasm/kya-os-engine-cedar-web/kya_os_engine.js +694 -0
- package/wasm/kya-os-engine-cedar-web/kya_os_engine_bg.wasm +0 -0
- package/wasm/kya-os-engine-cedar-web/kya_os_engine_bg.wasm.d.ts +11 -0
- package/wasm/kya-os-engine-cedar-web/package.json +31 -0
- package/wasm/kya-os-engine-web/kya_os_engine_bg.wasm +0 -0
- package/wasm/kya-os-engine-web/package.json +5 -3
- package/wasm/agentshield_wasm.d.ts +0 -485
- package/wasm/agentshield_wasm.js +0 -1551
- package/wasm/agentshield_wasm_bg.wasm +0 -0
- package/wasm/agentshield_wasm_bg.wasm.d.ts +0 -97
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { V as VerifyResult, f as EngineInfo } from './types-C3RniIOM.mjs';
|
|
2
|
+
import '@kya-os/checkpoint-shared';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Detection reporter — fire-and-forget POST to the dashboard's
|
|
6
|
+
* `/api/v1/log-detection` ingest endpoint.
|
|
7
|
+
*
|
|
8
|
+
* The engine-backed middlewares (`withCheckpoint` in `checkpoint-express`
|
|
9
|
+
* and `checkpoint-nextjs`) run verification locally via WASM. Without
|
|
10
|
+
* this reporter the verdict path works in-process but nothing flows
|
|
11
|
+
* back to the dashboard — the onboarding "Verify" check fails forever
|
|
12
|
+
* because the `detections` table never sees a row.
|
|
13
|
+
*
|
|
14
|
+
* Mirrors the contract of the legacy `CheckpointApiClient.logDetection`
|
|
15
|
+
* (see `checkpoint-nextjs/src/api-client.ts`) so the server-side
|
|
16
|
+
* ingest at `/api/v1/log-detection` accepts both paths identically.
|
|
17
|
+
*
|
|
18
|
+
* Subpath: `@kya-os/checkpoint-wasm-runtime/reporter`.
|
|
19
|
+
*
|
|
20
|
+
* @license MIT OR Apache-2.0
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Request context the middleware extracts from its framework-native
|
|
25
|
+
* request object. Shape matches the `ContextSchema` accepted by
|
|
26
|
+
* `/api/v1/log-detection`.
|
|
27
|
+
*/
|
|
28
|
+
interface ReporterContext {
|
|
29
|
+
userAgent?: string;
|
|
30
|
+
ipAddress?: string;
|
|
31
|
+
path?: string;
|
|
32
|
+
url?: string;
|
|
33
|
+
method?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Configuration for the detection reporter.
|
|
37
|
+
*/
|
|
38
|
+
interface DetectionReporterConfig {
|
|
39
|
+
/**
|
|
40
|
+
* Project API key. Resolved server-side at the ingest endpoint into
|
|
41
|
+
* the project association used to insert the detection row. Required.
|
|
42
|
+
*/
|
|
43
|
+
apiKey: string;
|
|
44
|
+
/**
|
|
45
|
+
* Dashboard base URL. Defaults to `https://kya.vouched.id`. Override
|
|
46
|
+
* for staging environments or self-hosted dashboards.
|
|
47
|
+
*/
|
|
48
|
+
baseUrl?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Per-request timeout in milliseconds. Defaults to 5000ms. The POST
|
|
51
|
+
* is fire-and-forget — a timeout aborts the request but never blocks
|
|
52
|
+
* the verdict path.
|
|
53
|
+
*/
|
|
54
|
+
timeoutMs?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Emit `console.warn` on reporter failures. Defaults to `false` —
|
|
57
|
+
* fire-and-forget means silent by design. Enable during development
|
|
58
|
+
* to surface mis-configured `apiKey` / `baseUrl`.
|
|
59
|
+
*/
|
|
60
|
+
debug?: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Self-catching reporter promise. Call after every `verifyRequest`
|
|
64
|
+
* decision. Callers that can extend request lifetime (for example,
|
|
65
|
+
* NextFetchEvent.waitUntil) should attach this promise; callers that
|
|
66
|
+
* cannot may still ignore it safely because errors are swallowed
|
|
67
|
+
* (unless `debug: true`).
|
|
68
|
+
*/
|
|
69
|
+
type DetectionReporter = (result: VerifyResult, ctx: ReporterContext) => Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Build a fire-and-forget reporter bound to a single project API key.
|
|
72
|
+
*
|
|
73
|
+
* The returned function is safe to call from any verdict path — it
|
|
74
|
+
* never throws, never awaits the network round-trip, and never affects
|
|
75
|
+
* the response.
|
|
76
|
+
*/
|
|
77
|
+
declare function makeDetectionReporter(config: DetectionReporterConfig): DetectionReporter;
|
|
78
|
+
/**
|
|
79
|
+
* Translate the engine's `VerifyResult` into the request body shape
|
|
80
|
+
* accepted by `/api/v1/log-detection`. Exported for tests + for
|
|
81
|
+
* advanced consumers wiring a custom transport.
|
|
82
|
+
*/
|
|
83
|
+
declare function buildLogDetectionPayload(result: VerifyResult, ctx: ReporterContext): {
|
|
84
|
+
detection: {
|
|
85
|
+
isAgent: boolean;
|
|
86
|
+
confidence: number;
|
|
87
|
+
agentName: string | undefined;
|
|
88
|
+
agentType: string | undefined;
|
|
89
|
+
detectionClass: string | undefined;
|
|
90
|
+
verificationMethod: "signature" | "pattern" | "behavioral" | "network" | "mcp_i_handshake" | "none" | "error" | undefined;
|
|
91
|
+
reasons: string[];
|
|
92
|
+
};
|
|
93
|
+
context: ReporterContext;
|
|
94
|
+
source: "middleware";
|
|
95
|
+
enforcement: {
|
|
96
|
+
action: string;
|
|
97
|
+
reason?: string;
|
|
98
|
+
};
|
|
99
|
+
engine: EngineInfo | undefined;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export { type DetectionReporter, type DetectionReporterConfig, type ReporterContext, buildLogDetectionPayload, makeDetectionReporter };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { V as VerifyResult, f as EngineInfo } from './types-C3RniIOM.js';
|
|
2
|
+
import '@kya-os/checkpoint-shared';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Detection reporter — fire-and-forget POST to the dashboard's
|
|
6
|
+
* `/api/v1/log-detection` ingest endpoint.
|
|
7
|
+
*
|
|
8
|
+
* The engine-backed middlewares (`withCheckpoint` in `checkpoint-express`
|
|
9
|
+
* and `checkpoint-nextjs`) run verification locally via WASM. Without
|
|
10
|
+
* this reporter the verdict path works in-process but nothing flows
|
|
11
|
+
* back to the dashboard — the onboarding "Verify" check fails forever
|
|
12
|
+
* because the `detections` table never sees a row.
|
|
13
|
+
*
|
|
14
|
+
* Mirrors the contract of the legacy `CheckpointApiClient.logDetection`
|
|
15
|
+
* (see `checkpoint-nextjs/src/api-client.ts`) so the server-side
|
|
16
|
+
* ingest at `/api/v1/log-detection` accepts both paths identically.
|
|
17
|
+
*
|
|
18
|
+
* Subpath: `@kya-os/checkpoint-wasm-runtime/reporter`.
|
|
19
|
+
*
|
|
20
|
+
* @license MIT OR Apache-2.0
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Request context the middleware extracts from its framework-native
|
|
25
|
+
* request object. Shape matches the `ContextSchema` accepted by
|
|
26
|
+
* `/api/v1/log-detection`.
|
|
27
|
+
*/
|
|
28
|
+
interface ReporterContext {
|
|
29
|
+
userAgent?: string;
|
|
30
|
+
ipAddress?: string;
|
|
31
|
+
path?: string;
|
|
32
|
+
url?: string;
|
|
33
|
+
method?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Configuration for the detection reporter.
|
|
37
|
+
*/
|
|
38
|
+
interface DetectionReporterConfig {
|
|
39
|
+
/**
|
|
40
|
+
* Project API key. Resolved server-side at the ingest endpoint into
|
|
41
|
+
* the project association used to insert the detection row. Required.
|
|
42
|
+
*/
|
|
43
|
+
apiKey: string;
|
|
44
|
+
/**
|
|
45
|
+
* Dashboard base URL. Defaults to `https://kya.vouched.id`. Override
|
|
46
|
+
* for staging environments or self-hosted dashboards.
|
|
47
|
+
*/
|
|
48
|
+
baseUrl?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Per-request timeout in milliseconds. Defaults to 5000ms. The POST
|
|
51
|
+
* is fire-and-forget — a timeout aborts the request but never blocks
|
|
52
|
+
* the verdict path.
|
|
53
|
+
*/
|
|
54
|
+
timeoutMs?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Emit `console.warn` on reporter failures. Defaults to `false` —
|
|
57
|
+
* fire-and-forget means silent by design. Enable during development
|
|
58
|
+
* to surface mis-configured `apiKey` / `baseUrl`.
|
|
59
|
+
*/
|
|
60
|
+
debug?: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Self-catching reporter promise. Call after every `verifyRequest`
|
|
64
|
+
* decision. Callers that can extend request lifetime (for example,
|
|
65
|
+
* NextFetchEvent.waitUntil) should attach this promise; callers that
|
|
66
|
+
* cannot may still ignore it safely because errors are swallowed
|
|
67
|
+
* (unless `debug: true`).
|
|
68
|
+
*/
|
|
69
|
+
type DetectionReporter = (result: VerifyResult, ctx: ReporterContext) => Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Build a fire-and-forget reporter bound to a single project API key.
|
|
72
|
+
*
|
|
73
|
+
* The returned function is safe to call from any verdict path — it
|
|
74
|
+
* never throws, never awaits the network round-trip, and never affects
|
|
75
|
+
* the response.
|
|
76
|
+
*/
|
|
77
|
+
declare function makeDetectionReporter(config: DetectionReporterConfig): DetectionReporter;
|
|
78
|
+
/**
|
|
79
|
+
* Translate the engine's `VerifyResult` into the request body shape
|
|
80
|
+
* accepted by `/api/v1/log-detection`. Exported for tests + for
|
|
81
|
+
* advanced consumers wiring a custom transport.
|
|
82
|
+
*/
|
|
83
|
+
declare function buildLogDetectionPayload(result: VerifyResult, ctx: ReporterContext): {
|
|
84
|
+
detection: {
|
|
85
|
+
isAgent: boolean;
|
|
86
|
+
confidence: number;
|
|
87
|
+
agentName: string | undefined;
|
|
88
|
+
agentType: string | undefined;
|
|
89
|
+
detectionClass: string | undefined;
|
|
90
|
+
verificationMethod: "signature" | "pattern" | "behavioral" | "network" | "mcp_i_handshake" | "none" | "error" | undefined;
|
|
91
|
+
reasons: string[];
|
|
92
|
+
};
|
|
93
|
+
context: ReporterContext;
|
|
94
|
+
source: "middleware";
|
|
95
|
+
enforcement: {
|
|
96
|
+
action: string;
|
|
97
|
+
reason?: string;
|
|
98
|
+
};
|
|
99
|
+
engine: EngineInfo | undefined;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export { type DetectionReporter, type DetectionReporterConfig, type ReporterContext, buildLogDetectionPayload, makeDetectionReporter };
|
package/dist/reporter.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/reporter/index.ts
|
|
4
|
+
var DEFAULT_BASE_URL = "https://kya.vouched.id";
|
|
5
|
+
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
6
|
+
var SINGLE_HASH_RULESET_REGEX = /^sha256:[a-f0-9]{64}$/;
|
|
7
|
+
function makeDetectionReporter(config) {
|
|
8
|
+
if (!config.apiKey) {
|
|
9
|
+
throw new Error(
|
|
10
|
+
"makeDetectionReporter: `apiKey` is required. Without it the dashboard cannot associate detections with your project."
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
14
|
+
const endpoint = `${baseUrl}/api/v1/log-detection`;
|
|
15
|
+
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
16
|
+
const debug = config.debug ?? false;
|
|
17
|
+
return function reportDetection(result, ctx) {
|
|
18
|
+
const payload = buildLogDetectionPayload(result, ctx);
|
|
19
|
+
if (debug && !payload.engine && result.engineInfo?.rulesetHash) {
|
|
20
|
+
console.warn(
|
|
21
|
+
`[checkpoint-reporter] dropping engine field \u2014 rulesetHash "${result.engineInfo.rulesetHash}" doesn't match dashboard schema /^sha256:[a-f0-9]{64}$/. Detection row will land with NULL engine_* columns.`
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
const controller = new AbortController();
|
|
25
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
26
|
+
return fetch(endpoint, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers: {
|
|
29
|
+
"Content-Type": "application/json",
|
|
30
|
+
Authorization: `Bearer ${config.apiKey}`
|
|
31
|
+
},
|
|
32
|
+
body: JSON.stringify(payload),
|
|
33
|
+
signal: controller.signal,
|
|
34
|
+
keepalive: true
|
|
35
|
+
}).then((response) => {
|
|
36
|
+
if (!response.ok && debug) {
|
|
37
|
+
console.warn(
|
|
38
|
+
`[checkpoint-reporter] log-detection HTTP ${response.status} at ${endpoint}`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}).catch((err) => {
|
|
42
|
+
if (debug) {
|
|
43
|
+
console.warn("[checkpoint-reporter] log-detection failed:", err);
|
|
44
|
+
}
|
|
45
|
+
}).finally(() => clearTimeout(timeoutId));
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function buildLogDetectionPayload(result, ctx) {
|
|
49
|
+
const detection = result.detectionDetail;
|
|
50
|
+
return {
|
|
51
|
+
detection: {
|
|
52
|
+
isAgent: detection.isAgent,
|
|
53
|
+
confidence: detection.confidence,
|
|
54
|
+
agentName: detection.detectedAgent?.name,
|
|
55
|
+
agentType: detection.detectedAgent?.type ?? detection.agentType,
|
|
56
|
+
detectionClass: stringifyDetectionClass(detection.detectionClass),
|
|
57
|
+
verificationMethod: detection.verificationMethod,
|
|
58
|
+
reasons: detection.reasons
|
|
59
|
+
},
|
|
60
|
+
context: ctx,
|
|
61
|
+
source: "middleware",
|
|
62
|
+
enforcement: extractEnforcement(result),
|
|
63
|
+
engine: sanitizeEngineInfo(result.engineInfo)
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function sanitizeEngineInfo(engine) {
|
|
67
|
+
if (!engine) return void 0;
|
|
68
|
+
if (!SINGLE_HASH_RULESET_REGEX.test(engine.rulesetHash)) return void 0;
|
|
69
|
+
return engine;
|
|
70
|
+
}
|
|
71
|
+
var DETECTION_CLASS_WIRE = {
|
|
72
|
+
Human: "human",
|
|
73
|
+
AiAgent: "ai_agent",
|
|
74
|
+
Automation: "automation",
|
|
75
|
+
Bot: "bot",
|
|
76
|
+
IncompleteData: "incomplete_data",
|
|
77
|
+
Unknown: "unknown"
|
|
78
|
+
};
|
|
79
|
+
function stringifyDetectionClass(detectionClass) {
|
|
80
|
+
if (!detectionClass) return void 0;
|
|
81
|
+
if (typeof detectionClass === "string") {
|
|
82
|
+
return DETECTION_CLASS_WIRE[detectionClass] ?? detectionClass;
|
|
83
|
+
}
|
|
84
|
+
if (typeof detectionClass === "object" && "type" in detectionClass) {
|
|
85
|
+
const variant = String(detectionClass.type);
|
|
86
|
+
return DETECTION_CLASS_WIRE[variant];
|
|
87
|
+
}
|
|
88
|
+
return void 0;
|
|
89
|
+
}
|
|
90
|
+
function extractEnforcement(result) {
|
|
91
|
+
const decision = result.decision;
|
|
92
|
+
switch (decision.kind) {
|
|
93
|
+
case "Permit":
|
|
94
|
+
return { action: result.enforcementMode === "observe" ? "log" : "allow" };
|
|
95
|
+
case "Block":
|
|
96
|
+
return { action: "block", reason: decision.reason.kind };
|
|
97
|
+
case "Challenge":
|
|
98
|
+
return { action: "challenge" };
|
|
99
|
+
case "Redirect":
|
|
100
|
+
return { action: "redirect" };
|
|
101
|
+
case "Instruct":
|
|
102
|
+
return { action: "instruct" };
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Detection reporter — fire-and-forget POST to the dashboard's
|
|
107
|
+
* `/api/v1/log-detection` ingest endpoint.
|
|
108
|
+
*
|
|
109
|
+
* The engine-backed middlewares (`withCheckpoint` in `checkpoint-express`
|
|
110
|
+
* and `checkpoint-nextjs`) run verification locally via WASM. Without
|
|
111
|
+
* this reporter the verdict path works in-process but nothing flows
|
|
112
|
+
* back to the dashboard — the onboarding "Verify" check fails forever
|
|
113
|
+
* because the `detections` table never sees a row.
|
|
114
|
+
*
|
|
115
|
+
* Mirrors the contract of the legacy `CheckpointApiClient.logDetection`
|
|
116
|
+
* (see `checkpoint-nextjs/src/api-client.ts`) so the server-side
|
|
117
|
+
* ingest at `/api/v1/log-detection` accepts both paths identically.
|
|
118
|
+
*
|
|
119
|
+
* Subpath: `@kya-os/checkpoint-wasm-runtime/reporter`.
|
|
120
|
+
*
|
|
121
|
+
* @license MIT OR Apache-2.0
|
|
122
|
+
*/
|
|
123
|
+
|
|
124
|
+
exports.buildLogDetectionPayload = buildLogDetectionPayload;
|
|
125
|
+
exports.makeDetectionReporter = makeDetectionReporter;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// src/reporter/index.ts
|
|
2
|
+
var DEFAULT_BASE_URL = "https://kya.vouched.id";
|
|
3
|
+
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
4
|
+
var SINGLE_HASH_RULESET_REGEX = /^sha256:[a-f0-9]{64}$/;
|
|
5
|
+
function makeDetectionReporter(config) {
|
|
6
|
+
if (!config.apiKey) {
|
|
7
|
+
throw new Error(
|
|
8
|
+
"makeDetectionReporter: `apiKey` is required. Without it the dashboard cannot associate detections with your project."
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
12
|
+
const endpoint = `${baseUrl}/api/v1/log-detection`;
|
|
13
|
+
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
14
|
+
const debug = config.debug ?? false;
|
|
15
|
+
return function reportDetection(result, ctx) {
|
|
16
|
+
const payload = buildLogDetectionPayload(result, ctx);
|
|
17
|
+
if (debug && !payload.engine && result.engineInfo?.rulesetHash) {
|
|
18
|
+
console.warn(
|
|
19
|
+
`[checkpoint-reporter] dropping engine field \u2014 rulesetHash "${result.engineInfo.rulesetHash}" doesn't match dashboard schema /^sha256:[a-f0-9]{64}$/. Detection row will land with NULL engine_* columns.`
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
const controller = new AbortController();
|
|
23
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
24
|
+
return fetch(endpoint, {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: {
|
|
27
|
+
"Content-Type": "application/json",
|
|
28
|
+
Authorization: `Bearer ${config.apiKey}`
|
|
29
|
+
},
|
|
30
|
+
body: JSON.stringify(payload),
|
|
31
|
+
signal: controller.signal,
|
|
32
|
+
keepalive: true
|
|
33
|
+
}).then((response) => {
|
|
34
|
+
if (!response.ok && debug) {
|
|
35
|
+
console.warn(
|
|
36
|
+
`[checkpoint-reporter] log-detection HTTP ${response.status} at ${endpoint}`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}).catch((err) => {
|
|
40
|
+
if (debug) {
|
|
41
|
+
console.warn("[checkpoint-reporter] log-detection failed:", err);
|
|
42
|
+
}
|
|
43
|
+
}).finally(() => clearTimeout(timeoutId));
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function buildLogDetectionPayload(result, ctx) {
|
|
47
|
+
const detection = result.detectionDetail;
|
|
48
|
+
return {
|
|
49
|
+
detection: {
|
|
50
|
+
isAgent: detection.isAgent,
|
|
51
|
+
confidence: detection.confidence,
|
|
52
|
+
agentName: detection.detectedAgent?.name,
|
|
53
|
+
agentType: detection.detectedAgent?.type ?? detection.agentType,
|
|
54
|
+
detectionClass: stringifyDetectionClass(detection.detectionClass),
|
|
55
|
+
verificationMethod: detection.verificationMethod,
|
|
56
|
+
reasons: detection.reasons
|
|
57
|
+
},
|
|
58
|
+
context: ctx,
|
|
59
|
+
source: "middleware",
|
|
60
|
+
enforcement: extractEnforcement(result),
|
|
61
|
+
engine: sanitizeEngineInfo(result.engineInfo)
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function sanitizeEngineInfo(engine) {
|
|
65
|
+
if (!engine) return void 0;
|
|
66
|
+
if (!SINGLE_HASH_RULESET_REGEX.test(engine.rulesetHash)) return void 0;
|
|
67
|
+
return engine;
|
|
68
|
+
}
|
|
69
|
+
var DETECTION_CLASS_WIRE = {
|
|
70
|
+
Human: "human",
|
|
71
|
+
AiAgent: "ai_agent",
|
|
72
|
+
Automation: "automation",
|
|
73
|
+
Bot: "bot",
|
|
74
|
+
IncompleteData: "incomplete_data",
|
|
75
|
+
Unknown: "unknown"
|
|
76
|
+
};
|
|
77
|
+
function stringifyDetectionClass(detectionClass) {
|
|
78
|
+
if (!detectionClass) return void 0;
|
|
79
|
+
if (typeof detectionClass === "string") {
|
|
80
|
+
return DETECTION_CLASS_WIRE[detectionClass] ?? detectionClass;
|
|
81
|
+
}
|
|
82
|
+
if (typeof detectionClass === "object" && "type" in detectionClass) {
|
|
83
|
+
const variant = String(detectionClass.type);
|
|
84
|
+
return DETECTION_CLASS_WIRE[variant];
|
|
85
|
+
}
|
|
86
|
+
return void 0;
|
|
87
|
+
}
|
|
88
|
+
function extractEnforcement(result) {
|
|
89
|
+
const decision = result.decision;
|
|
90
|
+
switch (decision.kind) {
|
|
91
|
+
case "Permit":
|
|
92
|
+
return { action: result.enforcementMode === "observe" ? "log" : "allow" };
|
|
93
|
+
case "Block":
|
|
94
|
+
return { action: "block", reason: decision.reason.kind };
|
|
95
|
+
case "Challenge":
|
|
96
|
+
return { action: "challenge" };
|
|
97
|
+
case "Redirect":
|
|
98
|
+
return { action: "redirect" };
|
|
99
|
+
case "Instruct":
|
|
100
|
+
return { action: "instruct" };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Detection reporter — fire-and-forget POST to the dashboard's
|
|
105
|
+
* `/api/v1/log-detection` ingest endpoint.
|
|
106
|
+
*
|
|
107
|
+
* The engine-backed middlewares (`withCheckpoint` in `checkpoint-express`
|
|
108
|
+
* and `checkpoint-nextjs`) run verification locally via WASM. Without
|
|
109
|
+
* this reporter the verdict path works in-process but nothing flows
|
|
110
|
+
* back to the dashboard — the onboarding "Verify" check fails forever
|
|
111
|
+
* because the `detections` table never sees a row.
|
|
112
|
+
*
|
|
113
|
+
* Mirrors the contract of the legacy `CheckpointApiClient.logDetection`
|
|
114
|
+
* (see `checkpoint-nextjs/src/api-client.ts`) so the server-side
|
|
115
|
+
* ingest at `/api/v1/log-detection` accepts both paths identically.
|
|
116
|
+
*
|
|
117
|
+
* Subpath: `@kya-os/checkpoint-wasm-runtime/reporter`.
|
|
118
|
+
*
|
|
119
|
+
* @license MIT OR Apache-2.0
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
export { buildLogDetectionPayload, makeDetectionReporter };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kya-os/checkpoint-wasm-runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Checkpoint WASM runtime for AI agent detection across all environments (formerly @kya-os/agentshield-wasm-runtime)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -42,6 +42,11 @@
|
|
|
42
42
|
"import": "./dist/node.mjs",
|
|
43
43
|
"require": "./dist/node.js"
|
|
44
44
|
},
|
|
45
|
+
"./policy": {
|
|
46
|
+
"types": "./dist/policy.d.ts",
|
|
47
|
+
"import": "./dist/policy.mjs",
|
|
48
|
+
"require": "./dist/policy.js"
|
|
49
|
+
},
|
|
45
50
|
"./wasm": {
|
|
46
51
|
"types": "./dist/wasm.d.ts",
|
|
47
52
|
"import": "./dist/wasm.mjs"
|
|
@@ -111,10 +116,16 @@
|
|
|
111
116
|
"import": "./dist/adapters.mjs",
|
|
112
117
|
"require": "./dist/adapters.js"
|
|
113
118
|
},
|
|
114
|
-
"./
|
|
119
|
+
"./reporter": {
|
|
120
|
+
"types": "./dist/reporter.d.ts",
|
|
121
|
+
"import": "./dist/reporter.mjs",
|
|
122
|
+
"require": "./dist/reporter.js"
|
|
123
|
+
},
|
|
115
124
|
"./wasm/kya-os-engine/kya_os_engine_bg.wasm": "./wasm/kya-os-engine/kya_os_engine_bg.wasm",
|
|
116
125
|
"./wasm/kya-os-engine-web/kya_os_engine_bg.wasm": "./wasm/kya-os-engine-web/kya_os_engine_bg.wasm",
|
|
117
126
|
"./wasm/kya-os-engine-bundler/kya_os_engine_bg.wasm": "./wasm/kya-os-engine-bundler/kya_os_engine_bg.wasm",
|
|
127
|
+
"./wasm/kya-os-engine-cedar/kya_os_engine_bg.wasm": "./wasm/kya-os-engine-cedar/kya_os_engine_bg.wasm",
|
|
128
|
+
"./wasm/kya-os-engine-cedar-web/kya_os_engine_bg.wasm": "./wasm/kya-os-engine-cedar-web/kya_os_engine_bg.wasm",
|
|
118
129
|
"./wasm/*": "./wasm/*",
|
|
119
130
|
"./package.json": "./package.json"
|
|
120
131
|
},
|
|
@@ -140,15 +151,14 @@
|
|
|
140
151
|
"lint:fix": "eslint src --ext .ts,.tsx --fix",
|
|
141
152
|
"format": "prettier --write \"src/**/*.{ts,tsx,json,md}\"",
|
|
142
153
|
"format:check": "prettier --check \"src/**/*.{ts,tsx,json,md}\"",
|
|
143
|
-
"prepublishOnly": "pnpm copy-
|
|
144
|
-
"copy-wasm": "mkdir -p ./wasm && cp ../../rust/crates/agentshield-wasm/pkg/agentshield_wasm_bg.wasm ./wasm/",
|
|
154
|
+
"prepublishOnly": "pnpm copy-engine-wasm && pnpm copy-engine-wasm-web && pnpm copy-engine-wasm-bundler && pnpm build && pnpm test",
|
|
145
155
|
"copy-engine-wasm": "mkdir -p ./wasm/kya-os-engine && cp ../../rust/crates/kya-os-engine/pkg/kya_os_engine_bg.wasm ../../rust/crates/kya-os-engine/pkg/kya_os_engine_bg.wasm.d.ts ../../rust/crates/kya-os-engine/pkg/kya_os_engine.d.ts ../../rust/crates/kya-os-engine/pkg/kya_os_engine.js ./wasm/kya-os-engine/",
|
|
146
156
|
"copy-engine-wasm-web": "mkdir -p ./wasm/kya-os-engine-web && cp ../../rust/crates/kya-os-engine/pkg-web/kya_os_engine_bg.wasm ../../rust/crates/kya-os-engine/pkg-web/kya_os_engine_bg.wasm.d.ts ../../rust/crates/kya-os-engine/pkg-web/kya_os_engine.d.ts ../../rust/crates/kya-os-engine/pkg-web/kya_os_engine.js ./wasm/kya-os-engine-web/",
|
|
147
157
|
"copy-engine-wasm-bundler": "mkdir -p ./wasm/kya-os-engine-bundler && cp ../../rust/crates/kya-os-engine/pkg-bundler/kya_os_engine_bg.wasm ../../rust/crates/kya-os-engine/pkg-bundler/kya_os_engine_bg.wasm.d.ts ../../rust/crates/kya-os-engine/pkg-bundler/kya_os_engine_bg.js ../../rust/crates/kya-os-engine/pkg-bundler/kya_os_engine.d.ts ../../rust/crates/kya-os-engine/pkg-bundler/kya_os_engine.js ./wasm/kya-os-engine-bundler/ && rm -f ./wasm/kya-os-engine-bundler/.gitignore",
|
|
148
158
|
"wasm:rebuild": "bash ../../rust/scripts/build-engine-wasm.sh"
|
|
149
159
|
},
|
|
150
160
|
"dependencies": {
|
|
151
|
-
"@kya-os/checkpoint-shared": "1.
|
|
161
|
+
"@kya-os/checkpoint-shared": "1.2.0",
|
|
152
162
|
"multiformats": "^13"
|
|
153
163
|
},
|
|
154
164
|
"devDependencies": {
|
|
Binary file
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"kya_os_engine_bg.wasm",
|
|
15
|
-
"kya_os_engine.js"
|
|
15
|
+
"kya_os_engine.js",
|
|
16
|
+
"kya_os_engine.d.ts"
|
|
16
17
|
],
|
|
17
18
|
"main": "kya_os_engine.js",
|
|
18
19
|
"keywords": [
|
|
@@ -23,5 +24,6 @@
|
|
|
23
24
|
"did"
|
|
24
25
|
],
|
|
25
26
|
"type": "commonjs",
|
|
26
|
-
"
|
|
27
|
+
"types": "kya_os_engine.d.ts",
|
|
28
|
+
"_note": "wasm-bindgen --target nodejs output: uses module.exports + require('fs') at module load. The parent wasm/package.json says type:module (for the older agentshield_wasm.js ESM file), which would make Node mis-classify this CJS file and throw ERR_REQUIRE_ESM. This nested package.json overrides per Node's nearest-package.json resolution algorithm. See SDK-WASM-Bundler-Loader-1 (#2613) for the original incident; AIVF-1 Path B (#2639) re-instated this override after a wasm-pack regen silently dropped it, plus a regen-pipeline patcher (rust/scripts/build-engine-wasm.sh) + an integrity test (packages/checkpoint-wasm-runtime/src/__tests__/wasm-artifact-integrity.test.ts) so the next regen can't silently break Node consumers again. Engine-Pattern-Codegen-Retirement-1 extended the patcher to also restore the types/`files` .d.ts references that --no-typescript drops."
|
|
27
29
|
}
|
|
Binary file
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# kya-os-engine
|
|
2
|
+
|
|
3
|
+
Verification engine for the KYA-OS ecosystem. Every TS / .NET / Go / Python /
|
|
4
|
+
Cloudflare-Workers host wrapper is a thin shim around the WASM or WASI build of
|
|
5
|
+
this crate. ADR-001 (Engine-Centric Consolidation) is the architectural
|
|
6
|
+
decision; the locked public API contract is tracked in D-design
|
|
7
|
+
([issue #2484][issue]) and mirrored at
|
|
8
|
+
[`docs/architecture/D-design-ratification.md`][ratification].
|
|
9
|
+
|
|
10
|
+
`kya-os-engine` is the root of the dependency graph. It depends on
|
|
11
|
+
nothing from `@kya-os/*`, `agentshield-*`, or `checkpoint-*`; the
|
|
12
|
+
direction is the other way.
|
|
13
|
+
|
|
14
|
+
The public surface is one function (`verify`), one decision vocabulary (`Decision`
|
|
15
|
+
with five variants — `Permit`, `Block`, `Challenge`, `Redirect`, `Instruct`),
|
|
16
|
+
five dependency-injection traits (`DidResolver`, `StatusListCache`,
|
|
17
|
+
`ReputationOracle`, `PolicyEvaluator`, `Clock`), and one canonical-signing-payload
|
|
18
|
+
helper (`canonical_signing_payload`, RFC 8785 / JCS).
|
|
19
|
+
|
|
20
|
+
This is the **Layer 1 API lock** (D-design, [issue #2484][issue]). The body of
|
|
21
|
+
`verify()` is `todo!()`; trait methods are stubbed. D-impl
|
|
22
|
+
([issue #2485][impl]) satisfies the contract.
|
|
23
|
+
|
|
24
|
+
[issue]: https://github.com/Know-That-Ai/agent-shield/issues/2484
|
|
25
|
+
[impl]: https://github.com/Know-That-Ai/agent-shield/issues/2485
|
|
26
|
+
[ratification]: ../../../docs/architecture/D-design-ratification.md
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/**
|
|
4
|
+
* Cross-boundary `verify` wrapper. The JS host calls `engine.verify(input,
|
|
5
|
+
* ctxSpec)`; on success it gets a [`VerifyResult`] JSON object; on
|
|
6
|
+
* infrastructure failure (or malformed input) it gets a thrown JS error
|
|
7
|
+
* whose message names the failure mode.
|
|
8
|
+
*
|
|
9
|
+
* **Error semantics**:
|
|
10
|
+
*
|
|
11
|
+
* - Verification *verdicts* (Block/Challenge/etc.) surface inside the
|
|
12
|
+
* returned `VerifyResult` — they are not thrown.
|
|
13
|
+
* - Engine [`VerifyError`][crate::error::VerifyError] (resolver / cache /
|
|
14
|
+
* reputation / policy infra failures) surface as thrown JS errors.
|
|
15
|
+
* - Serde deserialisation failures (malformed JS input) surface as thrown
|
|
16
|
+
* JS errors too, mirroring the typed-vs-thrown split.
|
|
17
|
+
*
|
|
18
|
+
* # JS signature
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* function verify(input: AgentRequest, ctx: ContextSpec): VerifyResult;
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function verify(input_js: any, ctx_js: any): any;
|
|
25
|
+
/**
|
|
26
|
+
* Cross-boundary handle to a compiled Cedar policy bundle.
|
|
27
|
+
*
|
|
28
|
+
* Wraps a [`CedarPolicyEvaluator`] so a JS host can compile a tenant
|
|
29
|
+
* policy once and authorize many requests against it. Construction
|
|
30
|
+
* compiles the bundle; each [`authorize`][Self::authorize] call evaluates
|
|
31
|
+
* a single owned request and never re-parses policy text.
|
|
32
|
+
*/
|
|
33
|
+
export class PolicyEvaluator {
|
|
34
|
+
free(): void;
|
|
35
|
+
[Symbol.dispose](): void;
|
|
36
|
+
/**
|
|
37
|
+
* Compile `policy_text` into a reusable evaluator.
|
|
38
|
+
*
|
|
39
|
+
* The Cedar policy bundle is parsed and compiled exactly once here;
|
|
40
|
+
* the resulting evaluator is held for the lifetime of the handle and
|
|
41
|
+
* reused by every [`authorize`][Self::authorize] call.
|
|
42
|
+
*
|
|
43
|
+
* # Errors
|
|
44
|
+
*
|
|
45
|
+
* Returns a thrown JS error whose message names the failure when
|
|
46
|
+
* `policy_text` is not syntactically valid Cedar
|
|
47
|
+
* ([`PolicyEvaluationError::Malformed`][crate::error::PolicyEvaluationError::Malformed]).
|
|
48
|
+
* A malformed bundle is an infrastructure fault surfaced at
|
|
49
|
+
* construction, never as a per-request deny.
|
|
50
|
+
*/
|
|
51
|
+
constructor(policy_text: string);
|
|
52
|
+
/**
|
|
53
|
+
* Authorize one owned request against the compiled policy bundle.
|
|
54
|
+
*
|
|
55
|
+
* The JS host calls `evaluator.authorize(input)` with an
|
|
56
|
+
* [`AuthorizeInput`]-shaped object (camelCase keys); it gets back a
|
|
57
|
+
* [`Decision`][crate::types::Decision] JSON object. The evaluator owns
|
|
58
|
+
* the fail-closed posture — a request it cannot marshal, or one
|
|
59
|
+
* matching no `permit`, comes back as a
|
|
60
|
+
* [`Decision::Block`][crate::types::Decision::Block], not a thrown
|
|
61
|
+
* error.
|
|
62
|
+
*
|
|
63
|
+
* # Errors
|
|
64
|
+
*
|
|
65
|
+
* Returns a thrown JS error only for boundary faults: a malformed
|
|
66
|
+
* `input_js` that fails [`AuthorizeInput`] deserialisation, or a
|
|
67
|
+
* failure serialising the resulting `Decision`. Authorization
|
|
68
|
+
* *verdicts* never throw — they surface inside the returned value.
|
|
69
|
+
*
|
|
70
|
+
* # JS signature
|
|
71
|
+
*
|
|
72
|
+
* ```ts
|
|
73
|
+
* authorize(input: AuthorizeInput): Decision;
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
authorize(input_js: any): any;
|
|
77
|
+
}
|