@kya-os/checkpoint-nextjs 1.1.4 → 1.7.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 +190 -0
- package/dist/composed-policy.d.mts +108 -0
- package/dist/composed-policy.d.ts +108 -0
- package/dist/composed-policy.js +91 -0
- package/dist/composed-policy.mjs +85 -0
- package/dist/config-_nfPN3E3.d.mts +205 -0
- package/dist/config-kxFihzR_.d.ts +205 -0
- package/dist/create-middleware.js +0 -2
- package/dist/create-middleware.mjs +0 -2
- package/dist/edge-runtime-loader.js +3 -1
- package/dist/edge-runtime-loader.mjs +3 -1
- package/dist/edge-wasm-middleware.d.mts +6 -6
- package/dist/edge-wasm-middleware.d.ts +6 -6
- package/dist/index.d.mts +6 -14
- package/dist/index.d.ts +6 -14
- package/dist/index.js +162 -9
- package/dist/index.mjs +163 -10
- package/dist/middleware-edge.d.mts +7 -3
- package/dist/middleware-edge.d.ts +7 -3
- package/dist/middleware-edge.js +159 -4
- package/dist/middleware-edge.mjs +156 -4
- package/dist/middleware-node.d.mts +39 -101
- package/dist/middleware-node.d.ts +39 -101
- package/dist/middleware-node.js +166 -4
- package/dist/middleware-node.mjs +163 -5
- package/dist/middleware.d.mts +10 -1
- package/dist/middleware.d.ts +10 -1
- package/dist/middleware.js +6 -0
- package/dist/middleware.mjs +6 -1
- package/dist/nodejs-wasm-loader.d.mts +3 -4
- package/dist/nodejs-wasm-loader.d.ts +3 -4
- package/dist/nodejs-wasm-loader.js +1 -1
- package/dist/nodejs-wasm-loader.mjs +1 -1
- package/dist/signature-verifier.js +2 -2
- package/dist/signature-verifier.mjs +2 -2
- package/dist/wasm-setup.js +1 -1
- package/dist/wasm-setup.mjs +1 -1
- package/package.json +8 -11
- package/dist/wasm-middleware.d.mts +0 -98
- package/dist/wasm-middleware.d.ts +0 -98
- package/dist/wasm-middleware.js +0 -125
- package/dist/wasm-middleware.mjs +0 -121
- package/templates/middleware-wasm-100.ts +0 -161
package/dist/middleware-edge.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var edge = require('@kya-os/checkpoint-wasm-runtime/orchestrator/edge');
|
|
4
|
-
var
|
|
4
|
+
var policyEdge = require('@kya-os/checkpoint-wasm-runtime/policy-edge');
|
|
5
5
|
var checkpointShared = require('@kya-os/checkpoint-shared');
|
|
6
|
+
var server = require('next/server');
|
|
7
|
+
var composedPolicy = require('@kya-os/checkpoint-wasm-runtime/composed-policy');
|
|
6
8
|
require('@kya-os/checkpoint-wasm-runtime/orchestrator');
|
|
7
9
|
var adapters = require('@kya-os/checkpoint-wasm-runtime/adapters');
|
|
10
|
+
var reporter = require('@kya-os/checkpoint-wasm-runtime/reporter');
|
|
8
11
|
|
|
9
12
|
// src/middleware-edge.ts
|
|
10
13
|
function adaptToNextResponse(rendered, req) {
|
|
@@ -55,6 +58,85 @@ function applyHeaders(res, headers) {
|
|
|
55
58
|
res.headers.set(key, value);
|
|
56
59
|
}
|
|
57
60
|
}
|
|
61
|
+
var DEFAULT_DASHBOARD_URL = "https://kya.vouched.id";
|
|
62
|
+
var NOOP_LOGGER = {
|
|
63
|
+
shadowDivergence: () => {
|
|
64
|
+
},
|
|
65
|
+
evaluationError: () => {
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
function makeComposedPolicyContext(opts) {
|
|
69
|
+
const { projectId, fetcher } = opts;
|
|
70
|
+
const cache = composedPolicy.makeComposedPolicyCache({ compile: opts.compile, cacheMax: opts.cacheMax });
|
|
71
|
+
const logger = opts.logger ?? NOOP_LOGGER;
|
|
72
|
+
return {
|
|
73
|
+
async apply(result, path) {
|
|
74
|
+
const structured = { decision: result.decision, acted: false };
|
|
75
|
+
const policy = await fetcher.getPolicy(projectId);
|
|
76
|
+
const outcome = await composedPolicy.evaluateComposedPolicy({
|
|
77
|
+
cache,
|
|
78
|
+
projectId,
|
|
79
|
+
flags: {
|
|
80
|
+
policyLanguage: policy.policyLanguage,
|
|
81
|
+
policySourceText: policy.policySourceText,
|
|
82
|
+
engineEnforcementEnabled: policy.engineEnforcementEnabled,
|
|
83
|
+
enabled: policy.enabled
|
|
84
|
+
},
|
|
85
|
+
authorizeInput: composedPolicy.verifyResultToAuthorizeInput(result, { tenantId: projectId, path }),
|
|
86
|
+
baselineDecisionKind: result.decision.kind
|
|
87
|
+
});
|
|
88
|
+
if ((outcome.status === "acting" || outcome.status === "shadow") && outcome.diverged) {
|
|
89
|
+
logger.shadowDivergence({
|
|
90
|
+
projectId,
|
|
91
|
+
path,
|
|
92
|
+
engineDecision: outcome.engineDecision.kind,
|
|
93
|
+
structuredDecision: result.decision.kind,
|
|
94
|
+
detectionClass: result.detectionDetail.detectionClass.type,
|
|
95
|
+
verificationMethod: result.detectionDetail.verificationMethod,
|
|
96
|
+
confidence: result.detectionDetail.confidence,
|
|
97
|
+
agentName: result.detectionDetail.detectedAgent?.name
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (outcome.status === "error") {
|
|
101
|
+
logger.evaluationError(projectId, outcome.error);
|
|
102
|
+
return structured;
|
|
103
|
+
}
|
|
104
|
+
if (outcome.status === "acting") {
|
|
105
|
+
return { decision: outcome.engineDecision, acted: true };
|
|
106
|
+
}
|
|
107
|
+
return structured;
|
|
108
|
+
},
|
|
109
|
+
async trustedDelegationRoots() {
|
|
110
|
+
const policy = await fetcher.getPolicy(projectId);
|
|
111
|
+
return policy.trustedDelegationRoots ?? [];
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
async function resolveTrustedDelegationRootsForRequest(resolver, headers) {
|
|
116
|
+
if (!resolver) return void 0;
|
|
117
|
+
if (!checkpointShared.requestCarriesDelegationProof(headers)) return void 0;
|
|
118
|
+
const roots = await resolver();
|
|
119
|
+
return roots.length > 0 ? roots : void 0;
|
|
120
|
+
}
|
|
121
|
+
async function applyComposedPolicy(context, result, path) {
|
|
122
|
+
if (!context) return;
|
|
123
|
+
try {
|
|
124
|
+
const outcome = await context.apply(result, path);
|
|
125
|
+
if (outcome.acted) result.decision = outcome.decision;
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
var consoleComposedPolicyLogger = {
|
|
130
|
+
shadowDivergence(info) {
|
|
131
|
+
console.warn("[checkpoint/composed-policy] shadow-divergence", info);
|
|
132
|
+
},
|
|
133
|
+
evaluationError(projectId, error) {
|
|
134
|
+
console.error(
|
|
135
|
+
`[checkpoint/composed-policy] evaluation failed for ${projectId}; using structured decision:`,
|
|
136
|
+
error
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
58
140
|
|
|
59
141
|
// src/translate.ts
|
|
60
142
|
async function nextRequestToHttpLike(req, opts = {}) {
|
|
@@ -97,6 +179,42 @@ function extractRemoteAddress(req) {
|
|
|
97
179
|
}
|
|
98
180
|
|
|
99
181
|
// src/middleware-node.ts
|
|
182
|
+
var SDK_NAME = "@kya-os/checkpoint-nextjs";
|
|
183
|
+
var VERSION = "1.7.0";
|
|
184
|
+
function buildReporter(config, runtime = "node") {
|
|
185
|
+
if (!config.apiKey) return null;
|
|
186
|
+
return reporter.makeDetectionReporter({
|
|
187
|
+
apiKey: config.apiKey,
|
|
188
|
+
baseUrl: config.baseUrl,
|
|
189
|
+
debug: config.debug,
|
|
190
|
+
// Self-identify (incl. node-vs-edge) so the dashboard can version-gate
|
|
191
|
+
// enforcement. Next.js EDGE composed enforcement is opt-in (needs
|
|
192
|
+
// `cedarWasmModule`), so the dashboard shows it as opt-in, never "Enforcing".
|
|
193
|
+
sdk: { name: SDK_NAME, version: VERSION, runtime }
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
function buildTrustedRootsResolver(config, composed) {
|
|
197
|
+
if (composed?.trustedDelegationRoots) {
|
|
198
|
+
return () => composed.trustedDelegationRoots();
|
|
199
|
+
}
|
|
200
|
+
if (!config.projectId) return null;
|
|
201
|
+
const fetcher = new checkpointShared.PolicyFetcher({
|
|
202
|
+
apiBaseUrl: config.dashboardUrl ?? config.baseUrl ?? DEFAULT_DASHBOARD_URL,
|
|
203
|
+
apiKey: config.apiKey,
|
|
204
|
+
cacheTtlSeconds: config.policyCacheTtlSeconds
|
|
205
|
+
});
|
|
206
|
+
const projectId = config.projectId;
|
|
207
|
+
return async () => (await fetcher.getPolicy(projectId)).trustedDelegationRoots ?? [];
|
|
208
|
+
}
|
|
209
|
+
function extractReporterContext(req) {
|
|
210
|
+
return {
|
|
211
|
+
userAgent: req.headers.get("user-agent") ?? void 0,
|
|
212
|
+
ipAddress: req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? req.headers.get("x-real-ip") ?? void 0,
|
|
213
|
+
path: req.nextUrl.pathname,
|
|
214
|
+
url: req.nextUrl.href,
|
|
215
|
+
method: req.method
|
|
216
|
+
};
|
|
217
|
+
}
|
|
100
218
|
function buildVerifyOpts(config) {
|
|
101
219
|
const overrides = config.adapters ?? {};
|
|
102
220
|
return {
|
|
@@ -109,7 +227,8 @@ function buildVerifyOpts(config) {
|
|
|
109
227
|
enforcementMode: config.enforcementMode ?? "enforce",
|
|
110
228
|
reputationBaseline: config.reputationBaseline,
|
|
111
229
|
argusUrl: config.argusUrl,
|
|
112
|
-
legacyEnvelopeFallback: config.legacyEnvelopeFallback ?? false
|
|
230
|
+
legacyEnvelopeFallback: config.legacyEnvelopeFallback ?? false,
|
|
231
|
+
engineConfig: config.engineConfig
|
|
113
232
|
};
|
|
114
233
|
}
|
|
115
234
|
|
|
@@ -117,10 +236,27 @@ function buildVerifyOpts(config) {
|
|
|
117
236
|
function withCheckpoint(config) {
|
|
118
237
|
void edge.initEngineEdge();
|
|
119
238
|
const opts = buildVerifyOpts(config);
|
|
239
|
+
const reporter = buildReporter(config, "edge");
|
|
240
|
+
const composed = buildComposedContext(config);
|
|
241
|
+
const trustedRootsResolver = buildTrustedRootsResolver(config, composed);
|
|
120
242
|
const translateOpts = { drainJsonBody: config.drainJsonBody };
|
|
121
|
-
return async function checkpointMiddlewareEdge(req) {
|
|
243
|
+
return async function checkpointMiddlewareEdge(req, event) {
|
|
122
244
|
const httpLike = await nextRequestToHttpLike(req, translateOpts);
|
|
123
|
-
const
|
|
245
|
+
const trustedDelegationRoots = await resolveTrustedDelegationRootsForRequest(
|
|
246
|
+
trustedRootsResolver,
|
|
247
|
+
req.headers
|
|
248
|
+
);
|
|
249
|
+
const result = await edge.verifyRequestEdge(
|
|
250
|
+
httpLike,
|
|
251
|
+
trustedDelegationRoots ? { ...opts, trustedDelegationRoots } : opts
|
|
252
|
+
);
|
|
253
|
+
await applyComposedPolicy(composed, result, req.nextUrl.pathname);
|
|
254
|
+
if (reporter) {
|
|
255
|
+
const reportPromise = reporter(result, extractReporterContext(req));
|
|
256
|
+
if (event) {
|
|
257
|
+
event.waitUntil(reportPromise);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
124
260
|
await dispatchOnResult(config, result, req);
|
|
125
261
|
const rendered = edge.renderDecisionAsResponse(result);
|
|
126
262
|
return adaptToNextResponse(rendered, req);
|
|
@@ -133,9 +269,28 @@ async function dispatchOnResult(config, result, req) {
|
|
|
133
269
|
} catch {
|
|
134
270
|
}
|
|
135
271
|
}
|
|
272
|
+
function buildComposedContext(config) {
|
|
273
|
+
if (config.composedPolicyEnforcer) return config.composedPolicyEnforcer;
|
|
274
|
+
if (!config.projectId || !config.cedarWasmModule) return null;
|
|
275
|
+
policyEdge.initPolicyEvaluatorEdge(config.cedarWasmModule);
|
|
276
|
+
return makeComposedPolicyContext({
|
|
277
|
+
projectId: config.projectId,
|
|
278
|
+
fetcher: new checkpointShared.PolicyFetcher({
|
|
279
|
+
apiBaseUrl: config.dashboardUrl ?? config.baseUrl ?? DEFAULT_DASHBOARD_URL,
|
|
280
|
+
apiKey: config.apiKey,
|
|
281
|
+
cacheTtlSeconds: config.policyCacheTtlSeconds
|
|
282
|
+
}),
|
|
283
|
+
compile: (language, source) => policyEdge.evaluatePolicy(language, source),
|
|
284
|
+
logger: config.debug ? consoleComposedPolicyLogger : void 0
|
|
285
|
+
});
|
|
286
|
+
}
|
|
136
287
|
|
|
137
288
|
Object.defineProperty(exports, "initEngineEdge", {
|
|
138
289
|
enumerable: true,
|
|
139
290
|
get: function () { return edge.initEngineEdge; }
|
|
140
291
|
});
|
|
292
|
+
Object.defineProperty(exports, "initPolicyEvaluatorEdge", {
|
|
293
|
+
enumerable: true,
|
|
294
|
+
get: function () { return policyEdge.initPolicyEvaluatorEdge; }
|
|
295
|
+
});
|
|
141
296
|
exports.withCheckpoint = withCheckpoint;
|
package/dist/middleware-edge.mjs
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { initEngineEdge, verifyRequestEdge, renderDecisionAsResponse } from '@kya-os/checkpoint-wasm-runtime/orchestrator/edge';
|
|
2
2
|
export { initEngineEdge } from '@kya-os/checkpoint-wasm-runtime/orchestrator/edge';
|
|
3
|
+
import { initPolicyEvaluatorEdge, evaluatePolicy } from '@kya-os/checkpoint-wasm-runtime/policy-edge';
|
|
4
|
+
export { initPolicyEvaluatorEdge } from '@kya-os/checkpoint-wasm-runtime/policy-edge';
|
|
5
|
+
import { PolicyFetcher, requestCarriesDelegationProof, acceptsHtml, encodeVerdictCookie, classifyResponseShape, BLOCKED_PATH, VERDICT_COOKIE_NAME } from '@kya-os/checkpoint-shared';
|
|
3
6
|
import { NextResponse } from 'next/server';
|
|
4
|
-
import {
|
|
7
|
+
import { makeComposedPolicyCache, evaluateComposedPolicy, verifyResultToAuthorizeInput } from '@kya-os/checkpoint-wasm-runtime/composed-policy';
|
|
5
8
|
import '@kya-os/checkpoint-wasm-runtime/orchestrator';
|
|
6
9
|
import { makeSystemClock, makePolicyEvaluator, makeReputationOracle, makeStatusListCache, makeDidResolver } from '@kya-os/checkpoint-wasm-runtime/adapters';
|
|
10
|
+
import { makeDetectionReporter } from '@kya-os/checkpoint-wasm-runtime/reporter';
|
|
7
11
|
|
|
8
12
|
// src/middleware-edge.ts
|
|
9
13
|
function adaptToNextResponse(rendered, req) {
|
|
@@ -54,6 +58,85 @@ function applyHeaders(res, headers) {
|
|
|
54
58
|
res.headers.set(key, value);
|
|
55
59
|
}
|
|
56
60
|
}
|
|
61
|
+
var DEFAULT_DASHBOARD_URL = "https://kya.vouched.id";
|
|
62
|
+
var NOOP_LOGGER = {
|
|
63
|
+
shadowDivergence: () => {
|
|
64
|
+
},
|
|
65
|
+
evaluationError: () => {
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
function makeComposedPolicyContext(opts) {
|
|
69
|
+
const { projectId, fetcher } = opts;
|
|
70
|
+
const cache = makeComposedPolicyCache({ compile: opts.compile, cacheMax: opts.cacheMax });
|
|
71
|
+
const logger = opts.logger ?? NOOP_LOGGER;
|
|
72
|
+
return {
|
|
73
|
+
async apply(result, path) {
|
|
74
|
+
const structured = { decision: result.decision, acted: false };
|
|
75
|
+
const policy = await fetcher.getPolicy(projectId);
|
|
76
|
+
const outcome = await evaluateComposedPolicy({
|
|
77
|
+
cache,
|
|
78
|
+
projectId,
|
|
79
|
+
flags: {
|
|
80
|
+
policyLanguage: policy.policyLanguage,
|
|
81
|
+
policySourceText: policy.policySourceText,
|
|
82
|
+
engineEnforcementEnabled: policy.engineEnforcementEnabled,
|
|
83
|
+
enabled: policy.enabled
|
|
84
|
+
},
|
|
85
|
+
authorizeInput: verifyResultToAuthorizeInput(result, { tenantId: projectId, path }),
|
|
86
|
+
baselineDecisionKind: result.decision.kind
|
|
87
|
+
});
|
|
88
|
+
if ((outcome.status === "acting" || outcome.status === "shadow") && outcome.diverged) {
|
|
89
|
+
logger.shadowDivergence({
|
|
90
|
+
projectId,
|
|
91
|
+
path,
|
|
92
|
+
engineDecision: outcome.engineDecision.kind,
|
|
93
|
+
structuredDecision: result.decision.kind,
|
|
94
|
+
detectionClass: result.detectionDetail.detectionClass.type,
|
|
95
|
+
verificationMethod: result.detectionDetail.verificationMethod,
|
|
96
|
+
confidence: result.detectionDetail.confidence,
|
|
97
|
+
agentName: result.detectionDetail.detectedAgent?.name
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (outcome.status === "error") {
|
|
101
|
+
logger.evaluationError(projectId, outcome.error);
|
|
102
|
+
return structured;
|
|
103
|
+
}
|
|
104
|
+
if (outcome.status === "acting") {
|
|
105
|
+
return { decision: outcome.engineDecision, acted: true };
|
|
106
|
+
}
|
|
107
|
+
return structured;
|
|
108
|
+
},
|
|
109
|
+
async trustedDelegationRoots() {
|
|
110
|
+
const policy = await fetcher.getPolicy(projectId);
|
|
111
|
+
return policy.trustedDelegationRoots ?? [];
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
async function resolveTrustedDelegationRootsForRequest(resolver, headers) {
|
|
116
|
+
if (!resolver) return void 0;
|
|
117
|
+
if (!requestCarriesDelegationProof(headers)) return void 0;
|
|
118
|
+
const roots = await resolver();
|
|
119
|
+
return roots.length > 0 ? roots : void 0;
|
|
120
|
+
}
|
|
121
|
+
async function applyComposedPolicy(context, result, path) {
|
|
122
|
+
if (!context) return;
|
|
123
|
+
try {
|
|
124
|
+
const outcome = await context.apply(result, path);
|
|
125
|
+
if (outcome.acted) result.decision = outcome.decision;
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
var consoleComposedPolicyLogger = {
|
|
130
|
+
shadowDivergence(info) {
|
|
131
|
+
console.warn("[checkpoint/composed-policy] shadow-divergence", info);
|
|
132
|
+
},
|
|
133
|
+
evaluationError(projectId, error) {
|
|
134
|
+
console.error(
|
|
135
|
+
`[checkpoint/composed-policy] evaluation failed for ${projectId}; using structured decision:`,
|
|
136
|
+
error
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
57
140
|
|
|
58
141
|
// src/translate.ts
|
|
59
142
|
async function nextRequestToHttpLike(req, opts = {}) {
|
|
@@ -96,6 +179,42 @@ function extractRemoteAddress(req) {
|
|
|
96
179
|
}
|
|
97
180
|
|
|
98
181
|
// src/middleware-node.ts
|
|
182
|
+
var SDK_NAME = "@kya-os/checkpoint-nextjs";
|
|
183
|
+
var VERSION = "1.7.0";
|
|
184
|
+
function buildReporter(config, runtime = "node") {
|
|
185
|
+
if (!config.apiKey) return null;
|
|
186
|
+
return makeDetectionReporter({
|
|
187
|
+
apiKey: config.apiKey,
|
|
188
|
+
baseUrl: config.baseUrl,
|
|
189
|
+
debug: config.debug,
|
|
190
|
+
// Self-identify (incl. node-vs-edge) so the dashboard can version-gate
|
|
191
|
+
// enforcement. Next.js EDGE composed enforcement is opt-in (needs
|
|
192
|
+
// `cedarWasmModule`), so the dashboard shows it as opt-in, never "Enforcing".
|
|
193
|
+
sdk: { name: SDK_NAME, version: VERSION, runtime }
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
function buildTrustedRootsResolver(config, composed) {
|
|
197
|
+
if (composed?.trustedDelegationRoots) {
|
|
198
|
+
return () => composed.trustedDelegationRoots();
|
|
199
|
+
}
|
|
200
|
+
if (!config.projectId) return null;
|
|
201
|
+
const fetcher = new PolicyFetcher({
|
|
202
|
+
apiBaseUrl: config.dashboardUrl ?? config.baseUrl ?? DEFAULT_DASHBOARD_URL,
|
|
203
|
+
apiKey: config.apiKey,
|
|
204
|
+
cacheTtlSeconds: config.policyCacheTtlSeconds
|
|
205
|
+
});
|
|
206
|
+
const projectId = config.projectId;
|
|
207
|
+
return async () => (await fetcher.getPolicy(projectId)).trustedDelegationRoots ?? [];
|
|
208
|
+
}
|
|
209
|
+
function extractReporterContext(req) {
|
|
210
|
+
return {
|
|
211
|
+
userAgent: req.headers.get("user-agent") ?? void 0,
|
|
212
|
+
ipAddress: req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? req.headers.get("x-real-ip") ?? void 0,
|
|
213
|
+
path: req.nextUrl.pathname,
|
|
214
|
+
url: req.nextUrl.href,
|
|
215
|
+
method: req.method
|
|
216
|
+
};
|
|
217
|
+
}
|
|
99
218
|
function buildVerifyOpts(config) {
|
|
100
219
|
const overrides = config.adapters ?? {};
|
|
101
220
|
return {
|
|
@@ -108,7 +227,8 @@ function buildVerifyOpts(config) {
|
|
|
108
227
|
enforcementMode: config.enforcementMode ?? "enforce",
|
|
109
228
|
reputationBaseline: config.reputationBaseline,
|
|
110
229
|
argusUrl: config.argusUrl,
|
|
111
|
-
legacyEnvelopeFallback: config.legacyEnvelopeFallback ?? false
|
|
230
|
+
legacyEnvelopeFallback: config.legacyEnvelopeFallback ?? false,
|
|
231
|
+
engineConfig: config.engineConfig
|
|
112
232
|
};
|
|
113
233
|
}
|
|
114
234
|
|
|
@@ -116,10 +236,27 @@ function buildVerifyOpts(config) {
|
|
|
116
236
|
function withCheckpoint(config) {
|
|
117
237
|
void initEngineEdge();
|
|
118
238
|
const opts = buildVerifyOpts(config);
|
|
239
|
+
const reporter = buildReporter(config, "edge");
|
|
240
|
+
const composed = buildComposedContext(config);
|
|
241
|
+
const trustedRootsResolver = buildTrustedRootsResolver(config, composed);
|
|
119
242
|
const translateOpts = { drainJsonBody: config.drainJsonBody };
|
|
120
|
-
return async function checkpointMiddlewareEdge(req) {
|
|
243
|
+
return async function checkpointMiddlewareEdge(req, event) {
|
|
121
244
|
const httpLike = await nextRequestToHttpLike(req, translateOpts);
|
|
122
|
-
const
|
|
245
|
+
const trustedDelegationRoots = await resolveTrustedDelegationRootsForRequest(
|
|
246
|
+
trustedRootsResolver,
|
|
247
|
+
req.headers
|
|
248
|
+
);
|
|
249
|
+
const result = await verifyRequestEdge(
|
|
250
|
+
httpLike,
|
|
251
|
+
trustedDelegationRoots ? { ...opts, trustedDelegationRoots } : opts
|
|
252
|
+
);
|
|
253
|
+
await applyComposedPolicy(composed, result, req.nextUrl.pathname);
|
|
254
|
+
if (reporter) {
|
|
255
|
+
const reportPromise = reporter(result, extractReporterContext(req));
|
|
256
|
+
if (event) {
|
|
257
|
+
event.waitUntil(reportPromise);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
123
260
|
await dispatchOnResult(config, result, req);
|
|
124
261
|
const rendered = renderDecisionAsResponse(result);
|
|
125
262
|
return adaptToNextResponse(rendered, req);
|
|
@@ -132,5 +269,20 @@ async function dispatchOnResult(config, result, req) {
|
|
|
132
269
|
} catch {
|
|
133
270
|
}
|
|
134
271
|
}
|
|
272
|
+
function buildComposedContext(config) {
|
|
273
|
+
if (config.composedPolicyEnforcer) return config.composedPolicyEnforcer;
|
|
274
|
+
if (!config.projectId || !config.cedarWasmModule) return null;
|
|
275
|
+
initPolicyEvaluatorEdge(config.cedarWasmModule);
|
|
276
|
+
return makeComposedPolicyContext({
|
|
277
|
+
projectId: config.projectId,
|
|
278
|
+
fetcher: new PolicyFetcher({
|
|
279
|
+
apiBaseUrl: config.dashboardUrl ?? config.baseUrl ?? DEFAULT_DASHBOARD_URL,
|
|
280
|
+
apiKey: config.apiKey,
|
|
281
|
+
cacheTtlSeconds: config.policyCacheTtlSeconds
|
|
282
|
+
}),
|
|
283
|
+
compile: (language, source) => evaluatePolicy(language, source),
|
|
284
|
+
logger: config.debug ? consoleComposedPolicyLogger : void 0
|
|
285
|
+
});
|
|
286
|
+
}
|
|
135
287
|
|
|
136
288
|
export { withCheckpoint };
|
|
@@ -1,99 +1,12 @@
|
|
|
1
|
+
import * as _kya_os_checkpoint_wasm_runtime_engine from '@kya-os/checkpoint-wasm-runtime/engine';
|
|
1
2
|
import * as _kya_os_checkpoint_wasm_runtime_adapters from '@kya-os/checkpoint-wasm-runtime/adapters';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { NextRequest, NextFetchEvent, NextResponse } from 'next/server';
|
|
4
|
+
import { DetectionReporter, ReporterContext } from '@kya-os/checkpoint-wasm-runtime/reporter';
|
|
5
|
+
import { C as CheckpointConfig } from './config-_nfPN3E3.mjs';
|
|
6
|
+
import { ComposedPolicyContext, TrustedDelegationRootsResolver } from './composed-policy.mjs';
|
|
7
|
+
import '@kya-os/checkpoint-wasm-runtime/composed-policy';
|
|
8
|
+
import '@kya-os/checkpoint-shared';
|
|
5
9
|
|
|
6
|
-
/**
|
|
7
|
-
* Configuration for `withCheckpoint`.
|
|
8
|
-
*
|
|
9
|
-
* The new minimal shape Phase D's middleware needs. Legacy
|
|
10
|
-
* `AgentShieldMiddlewareConfig` (from `./api-middleware`) remains
|
|
11
|
-
* exported during the deprecation window — see D.4 cutover.
|
|
12
|
-
*/
|
|
13
|
-
interface CheckpointConfig {
|
|
14
|
-
/**
|
|
15
|
-
* Tenant identifier — typically the customer's dashboard hostname
|
|
16
|
-
* (e.g. `acme.checkpoint.example`). The PolicyEvaluator uses this
|
|
17
|
-
* to look up tenant policy from the dashboard.
|
|
18
|
-
*/
|
|
19
|
-
tenantHost: string;
|
|
20
|
-
/**
|
|
21
|
-
* `'enforce'` (default) blocks; `'observe'` passes everything
|
|
22
|
-
* through with `X-Checkpoint-Would-Have-Been` headers. Per Phase 0.2.
|
|
23
|
-
*/
|
|
24
|
-
enforcementMode?: EnforcementMode;
|
|
25
|
-
/**
|
|
26
|
-
* Argus reputation oracle base URL. Omit to use the trust-by-default
|
|
27
|
-
* baseline (reputation defaults to 1.0; orchestrator logs a one-shot
|
|
28
|
-
* warning at first request).
|
|
29
|
-
*/
|
|
30
|
-
argusUrl?: string;
|
|
31
|
-
/**
|
|
32
|
-
* Dashboard base URL for the PolicyEvaluator to fetch tenant policy
|
|
33
|
-
* from. Omit to use the open-by-default tenant policy.
|
|
34
|
-
*/
|
|
35
|
-
dashboardUrl?: string;
|
|
36
|
-
/**
|
|
37
|
-
* Returned to the PolicyEvaluator for anonymous requests (no agent
|
|
38
|
-
* DID). Default 1.0 (trust-by-default).
|
|
39
|
-
*/
|
|
40
|
-
reputationBaseline?: number;
|
|
41
|
-
/**
|
|
42
|
-
* Pre-built adapter instances. Production deployments use the
|
|
43
|
-
* factory-built defaults from `@kya-os/checkpoint-wasm-runtime/adapters`;
|
|
44
|
-
* tests use stubs. The factory composes any provided overrides over
|
|
45
|
-
* defaults — partial overrides are supported.
|
|
46
|
-
*/
|
|
47
|
-
adapters?: Partial<{
|
|
48
|
-
didResolver: DidResolverAdapter;
|
|
49
|
-
statusListCache: StatusListCacheAdapter;
|
|
50
|
-
reputationOracle: ReputationOracleAdapter;
|
|
51
|
-
policyEvaluator: PolicyEvaluatorAdapter;
|
|
52
|
-
}>;
|
|
53
|
-
/**
|
|
54
|
-
* Optional callback for the post-verdict path — fires after every
|
|
55
|
-
* verification, regardless of permit/block, with the full
|
|
56
|
-
* `VerifyResult`. Use for logging, dashboards, telemetry. Errors
|
|
57
|
-
* thrown here are swallowed so user code can't break the middleware
|
|
58
|
-
* response.
|
|
59
|
-
*/
|
|
60
|
-
onResult?: (result: VerifyResult, req: NextRequest) => void | Promise<void>;
|
|
61
|
-
/**
|
|
62
|
-
* Accept legacy `KYA-Delegation`-header envelope form alongside the
|
|
63
|
-
* canonical `_meta.proof.jws` body form. Default `false`.
|
|
64
|
-
*
|
|
65
|
-
* **When to enable** — customers whose agents pre-date Envelope-1
|
|
66
|
-
* (#2537) and ship MCP-I proofs as `{protected,payload,signature}`
|
|
67
|
-
* JSON in a `KYA-Delegation` HTTP header. Post-Envelope-1 agents
|
|
68
|
-
* ship compact JWS in the request body's `_meta.proof.jws` field;
|
|
69
|
-
* those don't need this flag.
|
|
70
|
-
*
|
|
71
|
-
* Forwarded to the orchestrator's `VerifyRequestOpts.legacyEnvelopeFallback`.
|
|
72
|
-
* Both transports (header + body) are honored when this is `true`;
|
|
73
|
-
* the orchestrator's detection order is body first, then header
|
|
74
|
-
* (`packages/checkpoint-wasm-runtime/src/engine/orchestrator/build-agent-request.ts`).
|
|
75
|
-
*
|
|
76
|
-
* SDK-Envelope-Plumbing-1 (#2594). Added in `@kya-os/checkpoint-nextjs@1.1.0`.
|
|
77
|
-
*/
|
|
78
|
-
legacyEnvelopeFallback?: boolean;
|
|
79
|
-
/**
|
|
80
|
-
* Read the request body when `content-type` is `application/json` so
|
|
81
|
-
* the orchestrator can extract an MCP-I envelope from
|
|
82
|
-
* `_meta.proof.jws`. Default `true`.
|
|
83
|
-
*
|
|
84
|
-
* **When to disable** — streaming middlewares that can't tolerate
|
|
85
|
-
* the `req.clone()` memory overhead (one full-body copy is buffered
|
|
86
|
-
* during the read). For those, set `false` and route MCP-I
|
|
87
|
-
* envelopes through the `KYA-Delegation` header transport instead
|
|
88
|
-
* (requires `legacyEnvelopeFallback: true`).
|
|
89
|
-
*
|
|
90
|
-
* The clone preserves `req.body` for downstream handlers — disabling
|
|
91
|
-
* is a performance optimization, not a correctness fix.
|
|
92
|
-
*
|
|
93
|
-
* SDK-Envelope-Plumbing-1 (#2594). Added in `@kya-os/checkpoint-nextjs@1.1.0`.
|
|
94
|
-
*/
|
|
95
|
-
drainJsonBody?: boolean;
|
|
96
|
-
}
|
|
97
10
|
/**
|
|
98
11
|
* Build the Checkpoint middleware. Returns a function `(req) => NextResponse`
|
|
99
12
|
* suitable for `export default withCheckpoint({...})` in `middleware.ts`.
|
|
@@ -103,23 +16,48 @@ interface CheckpointConfig {
|
|
|
103
16
|
* `verifyRequest`, and translates the verdict to `NextResponse`. No
|
|
104
17
|
* verification logic lives in this file.
|
|
105
18
|
*/
|
|
106
|
-
declare function withCheckpoint(config: CheckpointConfig): (req: NextRequest) => Promise<NextResponse>;
|
|
19
|
+
declare function withCheckpoint(config: CheckpointConfig): (req: NextRequest, event?: NextFetchEvent) => Promise<NextResponse>;
|
|
20
|
+
/**
|
|
21
|
+
* Installed SDK version, self-reported to the detection reporter so the
|
|
22
|
+
* dashboard can version-gate "composed policy enforces here". MUST equal
|
|
23
|
+
* `package.json` version — pinned by a unit test (the old hardcoded `0.1.0` had
|
|
24
|
+
* drifted). Re-exported as `VERSION` from the package index.
|
|
25
|
+
*/
|
|
26
|
+
declare const VERSION = "1.7.0";
|
|
27
|
+
declare function buildReporter(config: CheckpointConfig, runtime?: 'node' | 'edge'): DetectionReporter | null;
|
|
28
|
+
/**
|
|
29
|
+
* Build the per-factory trusted-delegation-roots resolver (P2 / DR-1). Root
|
|
30
|
+
* pinning is a security concern INDEPENDENT of composed Cedar enforcement, so it
|
|
31
|
+
* must resolve wherever a `projectId` exists — including Edge setups that never
|
|
32
|
+
* wire `cedarWasmModule` (where `buildComposedContext` returns null). Prefers the
|
|
33
|
+
* composed context's accessor (reuses its cached fetcher / honors an injected
|
|
34
|
+
* enforcer); otherwise falls back to a `projectId`-only policy fetch. Returns
|
|
35
|
+
* `null` when no source is configured (no roots → engine open default).
|
|
36
|
+
*/
|
|
37
|
+
declare function buildTrustedRootsResolver(config: CheckpointConfig, composed: ComposedPolicyContext | null): TrustedDelegationRootsResolver | null;
|
|
38
|
+
/**
|
|
39
|
+
* Pull the request context the dashboard's `/api/v1/log-detection`
|
|
40
|
+
* endpoint expects out of a `NextRequest`. Works under both Node and
|
|
41
|
+
* Edge runtimes — no runtime-specific APIs.
|
|
42
|
+
*/
|
|
43
|
+
declare function extractReporterContext(req: NextRequest): ReporterContext;
|
|
107
44
|
/**
|
|
108
45
|
* Compose adapter defaults with caller-supplied overrides. Factored
|
|
109
46
|
* out so the Edge entry (which uses the same composition) can reuse
|
|
110
47
|
* the shape.
|
|
111
48
|
*/
|
|
112
49
|
declare function buildVerifyOpts(config: CheckpointConfig): {
|
|
113
|
-
didResolver: DidResolverAdapter;
|
|
114
|
-
statusListCache: StatusListCacheAdapter;
|
|
115
|
-
reputationOracle: ReputationOracleAdapter;
|
|
116
|
-
policyEvaluator: PolicyEvaluatorAdapter;
|
|
50
|
+
didResolver: _kya_os_checkpoint_wasm_runtime_adapters.DidResolverAdapter;
|
|
51
|
+
statusListCache: _kya_os_checkpoint_wasm_runtime_adapters.StatusListCacheAdapter;
|
|
52
|
+
reputationOracle: _kya_os_checkpoint_wasm_runtime_adapters.ReputationOracleAdapter;
|
|
53
|
+
policyEvaluator: _kya_os_checkpoint_wasm_runtime_adapters.PolicyEvaluatorAdapter;
|
|
117
54
|
clock: _kya_os_checkpoint_wasm_runtime_adapters.ClockAdapter;
|
|
118
55
|
tenantHost: string;
|
|
119
|
-
enforcementMode: EnforcementMode;
|
|
56
|
+
enforcementMode: _kya_os_checkpoint_wasm_runtime_engine.EnforcementMode;
|
|
120
57
|
reputationBaseline: number | undefined;
|
|
121
58
|
argusUrl: string | undefined;
|
|
122
59
|
legacyEnvelopeFallback: boolean;
|
|
60
|
+
engineConfig: _kya_os_checkpoint_wasm_runtime_engine.EngineConfig | undefined;
|
|
123
61
|
};
|
|
124
62
|
|
|
125
|
-
export {
|
|
63
|
+
export { CheckpointConfig, VERSION, buildReporter as _buildReporter, buildTrustedRootsResolver as _buildTrustedRootsResolver, buildVerifyOpts as _buildVerifyOpts, extractReporterContext as _extractReporterContext, withCheckpoint };
|