witnora 0.14.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gateway.js +33 -3
- package/dist/internal/control-client/remote-collector.d.ts +18 -0
- package/dist/internal/control-client/remote-collector.d.ts.map +1 -1
- package/dist/onboard.js +5 -2
- package/dist/real-path-activation.js +100 -0
- package/dist/vendor/onegent-runtime/provider-integration-packs.d.ts +92 -0
- package/dist/vendor/onegent-runtime/provider-integration-packs.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/provider-integration-packs.js +76 -0
- package/package.json +5 -1
package/dist/gateway.js
CHANGED
|
@@ -669,6 +669,7 @@ export async function createConfiguredWorkflowHarness(input) {
|
|
|
669
669
|
workerReady: !closing && !lastError,
|
|
670
670
|
...(lastTickAt ? { lastTickAt } : {}),
|
|
671
671
|
...(lastError ? { lastError } : {}),
|
|
672
|
+
...(input.config.schemaVersion === MANAGED_WORKFLOW_HARNESS_SCHEMA && input.config.realPathActivations?.length ? { realPathActivations: structuredClone(input.config.realPathActivations) } : {}),
|
|
672
673
|
};
|
|
673
674
|
},
|
|
674
675
|
tick,
|
|
@@ -1116,7 +1117,8 @@ export function parseManagedWorkflowHarnessConfig(raw) {
|
|
|
1116
1117
|
&& Array.isArray(workflowIds);
|
|
1117
1118
|
const managed = value.schemaVersion === MANAGED_WORKFLOW_HARNESS_SCHEMA
|
|
1118
1119
|
&& safeRelativeModulePath(value.evaluatorModulePath)
|
|
1119
|
-
&& validDigest(value.evaluatorModuleSha256 ?? "")
|
|
1120
|
+
&& validDigest(value.evaluatorModuleSha256 ?? "")
|
|
1121
|
+
&& validRealPathActivations(value.realPathActivations);
|
|
1120
1122
|
if (value.enabled !== true || !validDigest(value.evaluatorContractSha256 ?? "") || !workflowIdsValid || (!external && !managed)) {
|
|
1121
1123
|
throw new Error("workflow-harness.json requires an enabled, digest-pinned literal-loopback evaluator and a local credential handle.");
|
|
1122
1124
|
}
|
|
@@ -1128,6 +1130,25 @@ export function parseManagedWorkflowHarnessConfig(raw) {
|
|
|
1128
1130
|
}
|
|
1129
1131
|
return value;
|
|
1130
1132
|
}
|
|
1133
|
+
function validRealPathActivations(value) {
|
|
1134
|
+
if (value === undefined)
|
|
1135
|
+
return true;
|
|
1136
|
+
if (!Array.isArray(value) || value.length < 1 || value.length > 50)
|
|
1137
|
+
return false;
|
|
1138
|
+
return value.every((item) => Boolean(item && typeof item === "object" && !Array.isArray(item)
|
|
1139
|
+
&& /^[A-Za-z0-9._:-]{1,200}$/.test(String(item.integrationId ?? ""))
|
|
1140
|
+
&& validDigest(item.integrationDigestSha256)
|
|
1141
|
+
&& /^[A-Za-z0-9._:-]{1,200}$/.test(String(item.taskContractId ?? ""))
|
|
1142
|
+
&& validDigest(item.taskContractDigestSha256)
|
|
1143
|
+
&& /^[A-Za-z0-9._:-]{1,200}$/.test(String(item.agentId ?? ""))
|
|
1144
|
+
&& typeof item.agentVersion === "string"
|
|
1145
|
+
&& ["sandbox", "staging", "production"].includes(item.environment)
|
|
1146
|
+
&& validDigest(item.providerContractDigestSha256)
|
|
1147
|
+
&& item.acceptance?.kind === "READ_ONLY_PROVIDER_PREFLIGHT"
|
|
1148
|
+
&& item.acceptance?.productionWrites === 0
|
|
1149
|
+
&& validDigest(item.acceptance?.observationDigestSha256)
|
|
1150
|
+
&& Number.isFinite(Date.parse(item.acceptance?.passedAt ?? ""))));
|
|
1151
|
+
}
|
|
1131
1152
|
export async function activateManagedWorkflowHarness(options) {
|
|
1132
1153
|
const repository = resolve(options.repository ?? process.cwd());
|
|
1133
1154
|
const directory = join(repository, ".witnora", "gateway");
|
|
@@ -1163,14 +1184,19 @@ export async function activateManagedWorkflowHarness(options) {
|
|
|
1163
1184
|
...(options.workflowIds ? { workflowIds: options.workflowIds } : {}),
|
|
1164
1185
|
...(options.pollIntervalMs === undefined ? {} : { pollIntervalMs: options.pollIntervalMs }),
|
|
1165
1186
|
...(options.maxConcurrency === undefined ? {} : { maxConcurrency: options.maxConcurrency }),
|
|
1187
|
+
...(options.realPathActivations?.length ? { realPathActivations: structuredClone(options.realPathActivations) } : {}),
|
|
1166
1188
|
}));
|
|
1167
1189
|
const path = join(directory, "workflow-harness.json");
|
|
1168
1190
|
const serialized = `${JSON.stringify(config, null, 2)}\n`;
|
|
1169
1191
|
let created = false;
|
|
1170
1192
|
if (await exists(path)) {
|
|
1171
1193
|
const current = await readFile(path, "utf8");
|
|
1172
|
-
if (current !== serialized)
|
|
1173
|
-
|
|
1194
|
+
if (current !== serialized) {
|
|
1195
|
+
const parsed = parseManagedWorkflowHarnessConfig(current);
|
|
1196
|
+
if (parsed.schemaVersion !== MANAGED_WORKFLOW_HARNESS_SCHEMA || canonicalHarnessConfig(parsed) !== canonicalHarnessConfig(config))
|
|
1197
|
+
throw new Error("Existing workflow-harness.json differs from the generated Assurance Harness binding; refusing to overwrite customer configuration.");
|
|
1198
|
+
await writeFile(path, serialized, { encoding: "utf8", mode: 0o600 });
|
|
1199
|
+
}
|
|
1174
1200
|
}
|
|
1175
1201
|
else {
|
|
1176
1202
|
await writeFile(path, serialized, { encoding: "utf8", mode: 0o600, flag: "wx" });
|
|
@@ -1178,6 +1204,10 @@ export async function activateManagedWorkflowHarness(options) {
|
|
|
1178
1204
|
}
|
|
1179
1205
|
return { state: "READY_TO_START", path, modulePath: evaluatorModulePath, config, created };
|
|
1180
1206
|
}
|
|
1207
|
+
function canonicalHarnessConfig(value) {
|
|
1208
|
+
const { realPathActivations: _activations, ...stable } = value;
|
|
1209
|
+
return JSON.stringify(stable);
|
|
1210
|
+
}
|
|
1181
1211
|
export async function configureManagedWorkflowHarness(options) {
|
|
1182
1212
|
const directory = resolve(options.repository ?? process.cwd(), options.dir ?? ".witnora/gateway");
|
|
1183
1213
|
if (!await exists(join(directory, "gateway.json")))
|
|
@@ -63,6 +63,24 @@ export interface AssuranceHarnessHeartbeat {
|
|
|
63
63
|
workerReady: boolean;
|
|
64
64
|
lastTickAt?: string;
|
|
65
65
|
lastError?: string;
|
|
66
|
+
realPathActivations?: RealPathHarnessActivation[];
|
|
67
|
+
}
|
|
68
|
+
export interface RealPathHarnessActivation {
|
|
69
|
+
integrationId: string;
|
|
70
|
+
integrationDigestSha256: string;
|
|
71
|
+
taskContractId: string;
|
|
72
|
+
taskContractDigestSha256: string;
|
|
73
|
+
agentId: string;
|
|
74
|
+
agentVersion: string;
|
|
75
|
+
environment: "sandbox" | "staging" | "production";
|
|
76
|
+
providerPackId: string;
|
|
77
|
+
providerContractDigestSha256: string;
|
|
78
|
+
acceptance: {
|
|
79
|
+
kind: "READ_ONLY_PROVIDER_PREFLIGHT";
|
|
80
|
+
passedAt: string;
|
|
81
|
+
productionWrites: 0;
|
|
82
|
+
observationDigestSha256: string;
|
|
83
|
+
};
|
|
66
84
|
}
|
|
67
85
|
export interface RemoteCollectorClientOptions {
|
|
68
86
|
baseUrl: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-collector.d.ts","sourceRoot":"","sources":["../../../../agentcert-sdk/src/remote-collector.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB;AAeD,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,sCAAsC,CAAC;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE,CAAC;IACxG,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE;QAAE,SAAS,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7E;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,qCAAqC,CAAC;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAChC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,2BAA2B,EAAE,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,yBAAyB;IACxC,cAAc,EAAE,oBAAoB,CAAC;IACrC,OAAO,EAAE,uBAAuB,CAAC;IACjC,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,yBAAyB;IACxC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,uBAAuB,EAAE,MAAM,CAAC;IAChC,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"remote-collector.d.ts","sourceRoot":"","sources":["../../../../agentcert-sdk/src/remote-collector.ts"],"names":[],"mappings":"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"}
|
package/dist/onboard.js
CHANGED
|
@@ -10,6 +10,7 @@ import { writeTryEvidence } from "./try.js";
|
|
|
10
10
|
import { doctorCustomerGateway, activateManagedWorkflowHarness, initializeCustomerGateway, inspectLocalRuntimeBinding, inspectCustomerGatewayFiles, startManagedCustomerGateway, stopManagedCustomerGateway, upgradeCustomerGatewayRuntime, RuntimeSetupNotReadyError, } from "./gateway.js";
|
|
11
11
|
import { discoverRuntimeReferences, planRuntimeSandboxModules } from "./runtime-sandbox-kit.js";
|
|
12
12
|
import { automaticRuntimeReferencesUsable, bootstrapLocalRuntime, verifyAutomaticRuntimeProbe } from "./runtime-bootstrap.js";
|
|
13
|
+
import { activateRealPathIntegrations } from "./real-path-activation.js";
|
|
13
14
|
export async function runOnboard(options) {
|
|
14
15
|
const requestFetch = options.fetch ?? fetch;
|
|
15
16
|
const output = options.output ?? ((message) => process.stdout.write(message));
|
|
@@ -188,8 +189,10 @@ export async function runOnboard(options) {
|
|
|
188
189
|
}
|
|
189
190
|
const runtimeConfigured = await gatewayHasRuntimeWorker(repositoryPath);
|
|
190
191
|
generatedFiles.push(...await generateAutopilotFiles(repositoryPath, repository.name, runtimeConfigured));
|
|
192
|
+
const realPathActivation = await activateRealPathIntegrations({ repository: repositoryPath, server, projectId: token.projectId, apiKey: token.apiKey, env: options.env, fetch: requestFetch });
|
|
193
|
+
generatedFiles.push(...realPathActivation.generatedFiles);
|
|
191
194
|
try {
|
|
192
|
-
const activation = await activateManagedWorkflowHarness({ repository: repositoryPath });
|
|
195
|
+
const activation = await activateManagedWorkflowHarness({ repository: repositoryPath, realPathActivations: realPathActivation.activations });
|
|
193
196
|
if (activation.created)
|
|
194
197
|
generatedFiles.push(activation.path);
|
|
195
198
|
assuranceHarnessChanged = activation.created;
|
|
@@ -234,7 +237,7 @@ export async function runOnboard(options) {
|
|
|
234
237
|
? "Runtime: LOCAL_SANDBOX_READY. This proves only the generated localhost sandbox loop is ready; it does not establish coverage, CURRENT, or a verified customer outcome.\n"
|
|
235
238
|
: `Runtime: RECORDED_ONLY. ${runtimeReadiness.limitations[0]}\n`);
|
|
236
239
|
output(assuranceHarnessReadiness.state === "ACTIVE"
|
|
237
|
-
?
|
|
240
|
+
? `Assurance Harness: ACTIVE. Nora can dispatch authority-ready Replay and no-write Shadow evaluations without manual Workflow IDs, evaluator origins, credentials, or contract digests.${realPathActivation.activations.length ? ` ${realPathActivation.activations.length} exact Stripe test-mode real-path binding(s) passed read-only preflight.` : ""}\n`
|
|
238
241
|
: `Assurance Harness: WAITING_FOR_CUSTOMER_HARNESS. ${assuranceHarnessReadiness.limitation}\n`);
|
|
239
242
|
output("The self-test remains isolated. The Gateway is ready in the background; run the agent normally. The first source-signed, server-reconciled Gateway run completes onboarding.\n");
|
|
240
243
|
return { projectId: token.projectId, connectionName: token.connectionName, credentialsPath, template: repository.template,
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
export async function activateRealPathIntegrations(options) {
|
|
5
|
+
const repository = resolve(options.repository ?? process.cwd());
|
|
6
|
+
const request = options.fetch ?? fetch;
|
|
7
|
+
const base = options.server.replace(/\/$/, "");
|
|
8
|
+
const response = await request(`${base}/v1/projects/${encodeURIComponent(options.projectId)}/real-path-integrations`, { headers: { authorization: `Bearer ${options.apiKey}` } });
|
|
9
|
+
if (response.status === 404)
|
|
10
|
+
return { state: "NOT_CONFIGURED", created: false, activations: [], generatedFiles: [] };
|
|
11
|
+
if (!response.ok)
|
|
12
|
+
throw new Error(`Could not load approved real-path integrations (${response.status}).`);
|
|
13
|
+
const body = await boundedJson(response);
|
|
14
|
+
const approved = Array.isArray(body.integrations) ? body.integrations.map(parsePlan).filter((plan) => plan.status === "READY_TO_ACTIVATE") : [];
|
|
15
|
+
const plans = approved.filter((plan) => plan.generated.providerPackId === "STRIPE_REFUND" && plan.environment === "sandbox" && plan.customerSummary.evaluationMode === "SHADOW");
|
|
16
|
+
if (!plans.length)
|
|
17
|
+
return { state: "NOT_CONFIGURED", created: false, activations: [], generatedFiles: [] };
|
|
18
|
+
const secret = options.env?.STRIPE_SECRET_KEY ?? process.env.STRIPE_SECRET_KEY;
|
|
19
|
+
if (!secret?.startsWith("sk_test_") || secret.length < 12)
|
|
20
|
+
throw new Error("Stripe test-mode activation requires STRIPE_SECRET_KEY to reference an sk_test_ credential in the customer environment.");
|
|
21
|
+
const activations = [];
|
|
22
|
+
const scenarios = [];
|
|
23
|
+
for (const plan of plans) {
|
|
24
|
+
const preflight = await stripePreflight(request, secret, plan, options.now?.() ?? new Date());
|
|
25
|
+
const acceptance = preflight.acceptance;
|
|
26
|
+
activations.push({ integrationId: plan.id, integrationDigestSha256: plan.digestSha256, taskContractId: plan.taskContractId, taskContractDigestSha256: plan.taskContractDigestSha256, agentId: plan.subject.agentId, agentVersion: plan.subject.agentVersion, environment: plan.environment, providerPackId: plan.generated.providerPackId, providerContractDigestSha256: plan.generated.providerContractDigestSha256, acceptance });
|
|
27
|
+
scenarios.push({ plan, value: [preflight.scenario] });
|
|
28
|
+
}
|
|
29
|
+
const modulePath = join(repository, "witnora.assurance-harness.mjs");
|
|
30
|
+
const manifestPath = join(repository, ".witnora", "gateway", "real-path-activations.json");
|
|
31
|
+
const source = generatedStripeHarness(plans);
|
|
32
|
+
const moduleDigestSha256 = sha(source);
|
|
33
|
+
let created = false;
|
|
34
|
+
const generatedFiles = [];
|
|
35
|
+
const current = await readFile(modulePath, "utf8").catch((error) => error.code === "ENOENT" ? undefined : Promise.reject(error));
|
|
36
|
+
const prior = await readFile(manifestPath, "utf8").then((value) => JSON.parse(value)).catch(() => undefined);
|
|
37
|
+
if (current === undefined) {
|
|
38
|
+
await writeFile(modulePath, source, { encoding: "utf8", mode: 0o600, flag: "wx" });
|
|
39
|
+
created = true;
|
|
40
|
+
generatedFiles.push(modulePath);
|
|
41
|
+
}
|
|
42
|
+
else if (sha(current) !== prior?.moduleDigestSha256)
|
|
43
|
+
throw new Error("Existing Assurance Harness is customer-modified or belongs to a different integration; refusing to overwrite it.");
|
|
44
|
+
else if (current !== source) {
|
|
45
|
+
const temporary = `${modulePath}.${randomUUID()}.tmp`;
|
|
46
|
+
await writeFile(temporary, source, { encoding: "utf8", mode: 0o600, flag: "wx" });
|
|
47
|
+
await rename(temporary, modulePath);
|
|
48
|
+
generatedFiles.push(modulePath);
|
|
49
|
+
}
|
|
50
|
+
const manifest = { schemaVersion: "witnora.real_path_activation_manifest.v0.1", projectId: options.projectId, moduleDigestSha256, activations };
|
|
51
|
+
await mkdir(dirname(manifestPath), { recursive: true });
|
|
52
|
+
await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
|
|
53
|
+
generatedFiles.push(manifestPath);
|
|
54
|
+
for (const item of scenarios) {
|
|
55
|
+
const path = join(repository, ".witnora", "scenarios", `${item.plan.taskContractId}.json`);
|
|
56
|
+
await mkdir(dirname(path), { recursive: true });
|
|
57
|
+
try {
|
|
58
|
+
await writeFile(path, `${JSON.stringify(item.value, null, 2)}\n`, { encoding: "utf8", mode: 0o600, flag: "wx" });
|
|
59
|
+
generatedFiles.push(path);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (error.code !== "EEXIST")
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return { state: "READY_TO_START", created, modulePath: "witnora.assurance-harness.mjs", activations, generatedFiles };
|
|
67
|
+
}
|
|
68
|
+
async function stripePreflight(request, secret, plan, now) {
|
|
69
|
+
const response = await request("https://api.stripe.com/v1/refunds?limit=1", { headers: { authorization: `Bearer ${secret}` }, redirect: "error", signal: AbortSignal.timeout(5_000) });
|
|
70
|
+
if (!response.ok)
|
|
71
|
+
throw new Error(`Stripe test-mode read-only preflight failed (${response.status}).`);
|
|
72
|
+
const body = await boundedJson(response);
|
|
73
|
+
if (body.object !== "list" || !Array.isArray(body.data))
|
|
74
|
+
throw new Error("Stripe test-mode preflight returned an unexpected contract.");
|
|
75
|
+
const first = body.data[0] && typeof body.data[0] === "object" && !Array.isArray(body.data[0]) ? body.data[0] : undefined;
|
|
76
|
+
if (!first || typeof first.id !== "string" || !/^re_[A-Za-z0-9_]{1,200}$/.test(first.id))
|
|
77
|
+
throw new Error("Stripe test-mode activation requires one existing test refund for the no-write acceptance.");
|
|
78
|
+
const observation = Object.fromEntries(["status", "amount", "currency", "failure_reason"].flatMap((key) => scalar(first[key]) ? [[key, first[key]]] : []));
|
|
79
|
+
if (observation[plan.generated.criterion.field] !== plan.generated.criterion.expected)
|
|
80
|
+
throw new Error("The latest Stripe test refund does not satisfy the approved business success definition.");
|
|
81
|
+
const parameterDigest = sha(first.id);
|
|
82
|
+
const resultDigest = sha(canonical(observation));
|
|
83
|
+
return { acceptance: { kind: "READ_ONLY_PROVIDER_PREFLIGHT", passedAt: now.toISOString(), productionWrites: 0, observationDigestSha256: resultDigest }, scenario: { id: `stripe:${sha(first.id).slice(0, 16)}`, source: "LIVE_SHADOW", sanitized: true, input: { resourceId: first.id }, inputDigestSha256: sha(canonical({ resourceId: first.id })), baseline: { resultDigestSha256: resultDigest, actionIntents: plan.generated.actionPathBindings.map((item) => ({ pathId: item.actionPathId, parametersDigestSha256: parameterDigest })) } } };
|
|
84
|
+
}
|
|
85
|
+
function generatedStripeHarness(plans) {
|
|
86
|
+
const contracts = plans.map((plan) => ({ taskContractId: plan.taskContractId, criterion: plan.generated.criterion, actionPathIds: plan.generated.actionPathBindings.map((item) => item.actionPathId) }));
|
|
87
|
+
return `import {createHash} from "node:crypto";\nimport {readFile} from "node:fs/promises";\nimport {join} from "node:path";\nconst contracts=${JSON.stringify(contracts)};\nconst sha=(value)=>createHash("sha256").update(typeof value==="string"?value:JSON.stringify(value)).digest("hex");\nexport function createWitnoraBusinessTaskEvaluatorOptions(context){return {\n loadShadowObservations:async(task)=>{const contract=contracts.find((item)=>item.taskContractId===task.id);if(!contract)throw new Error("No exact real-path contract.");const path=join(context.repository,".witnora","scenarios",task.id+".json");const value=JSON.parse(await readFile(path,"utf8"));if(!Array.isArray(value)||value.length>100)throw new Error("Local scenario file is invalid.");return value;},\n evaluateShadowCandidate:async(candidate,task)=>{const contract=contracts.find((item)=>item.taskContractId===task.id);if(!contract)throw new Error("No exact real-path contract.");const resourceId=String(candidate.input?.resourceId??"");if(!/^re_[A-Za-z0-9_]{1,200}$/.test(resourceId))throw new Error("Stripe refund resourceId is invalid.");for(const pathId of contract.actionPathIds)candidate.propose({pathId,parametersDigestSha256:sha(resourceId)});const key=process.env.STRIPE_SECRET_KEY;if(!key?.startsWith("sk_test_"))throw new Error("Stripe test-mode credential is unavailable.");const response=await fetch("https://api.stripe.com/v1/refunds/"+encodeURIComponent(resourceId),{headers:{authorization:"Bearer "+key},redirect:"error",signal:AbortSignal.timeout(5000)});if(!response.ok)throw new Error("Stripe read-only observation failed.");const raw=await response.json();const observed={status:raw.status,amount:raw.amount,currency:raw.currency,failure_reason:raw.failure_reason};const actual=observed[contract.criterion.field];return {resultDigestSha256:sha(observed),criteria:[{id:contract.criterion.id,passed:actual===contract.criterion.expected}]};}\n};}\n`;
|
|
88
|
+
}
|
|
89
|
+
function parsePlan(value) { if (!value || typeof value !== "object" || Array.isArray(value))
|
|
90
|
+
throw new Error("Real-path integration response is invalid."); const plan = value; if (plan.schemaVersion !== "witnora.real_path_integration.v0.1" || !plan.id || !plan.taskContractId || !plan.subject?.agentId || !plan.subject.agentVersion || !plan.generated || plan.generated.boundaries?.rawPayloadUpload !== false || plan.generated.boundaries.rawCredentialUpload !== false || plan.generated.boundaries.evaluatorWrites !== false || plan.generated.boundaries.firstAcceptanceProductionWrites !== 0 || !digest(plan.digestSha256) || !digest(plan.taskContractDigestSha256) || !digest(plan.generated.providerContractDigestSha256))
|
|
91
|
+
throw new Error("Real-path integration response failed its safety contract."); return plan; }
|
|
92
|
+
async function boundedJson(response) { const text = await response.text(); if (text.length > 1_048_576)
|
|
93
|
+
throw new Error("Real-path response exceeded the size limit."); const value = JSON.parse(text); if (!value || typeof value !== "object" || Array.isArray(value))
|
|
94
|
+
throw new Error("Real-path response is invalid."); return value; }
|
|
95
|
+
function scalar(value) { return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean"; }
|
|
96
|
+
function digest(value) { return typeof value === "string" && /^[a-f0-9]{64}$/.test(value); }
|
|
97
|
+
function canonical(value) { if (value === null || typeof value !== "object")
|
|
98
|
+
return JSON.stringify(value); if (Array.isArray(value))
|
|
99
|
+
return `[${value.map(canonical).join(",")}]`; return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`).join(",")}}`; }
|
|
100
|
+
function sha(value) { return createHash("sha256").update(value).digest("hex"); }
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { type BrowserWorkflowOutcomeEvaluatorOptions, type DatabaseReadOnlyEvaluatorOptions, type HttpProductionEvaluatorOptions, type ProductionOutcomeEvaluator, type ProductionEvaluatorTemplate } from "./production-evaluator-kit.js";
|
|
2
|
+
export declare const PROVIDER_INTEGRATION_PACK_SCHEMA_VERSION: "witnora.provider_integration_pack.v0.1";
|
|
3
|
+
export type ProviderIntegrationPackId = "STRIPE_REFUND" | "SALESFORCE_RECORD" | "HUBSPOT_CRM_RECORD" | "ZENDESK_TICKET" | "INTERCOM_TICKET" | "POSTGRES_RECORD" | "MYSQL_RECORD" | "WEBHOOK_DELIVERY" | "QUEUE_JOB" | "EMAIL_DELIVERY" | "BROWSER_WORKFLOW";
|
|
4
|
+
export interface ProviderIntegrationPack {
|
|
5
|
+
schemaVersion: typeof PROVIDER_INTEGRATION_PACK_SCHEMA_VERSION;
|
|
6
|
+
id: ProviderIntegrationPackId;
|
|
7
|
+
provider: string;
|
|
8
|
+
title: string;
|
|
9
|
+
template: ProductionEvaluatorTemplate;
|
|
10
|
+
environments: Array<"sandbox" | "staging" | "production">;
|
|
11
|
+
credential: {
|
|
12
|
+
access: "READ_ONLY";
|
|
13
|
+
scopes: string[];
|
|
14
|
+
suggestedHandle: string;
|
|
15
|
+
healthCheck: "RESOURCE_GET" | "PREPARED_SELECT" | "OBSERVER_READ";
|
|
16
|
+
};
|
|
17
|
+
fieldAllowlist: string[];
|
|
18
|
+
commonCriteria: Array<{
|
|
19
|
+
id: string;
|
|
20
|
+
question: string;
|
|
21
|
+
field: string;
|
|
22
|
+
suggestedValues: Array<string | number | boolean>;
|
|
23
|
+
}>;
|
|
24
|
+
endpoint: {
|
|
25
|
+
origin?: string;
|
|
26
|
+
configurableOrigin: boolean;
|
|
27
|
+
resourcePattern: string;
|
|
28
|
+
};
|
|
29
|
+
boundaries: {
|
|
30
|
+
writes: false;
|
|
31
|
+
redirects: false;
|
|
32
|
+
rawPayloadUpload: false;
|
|
33
|
+
rawCredentialUpload: false;
|
|
34
|
+
};
|
|
35
|
+
contractDigestSha256: string;
|
|
36
|
+
}
|
|
37
|
+
type HttpPackOptions = {
|
|
38
|
+
packId: Exclude<ProviderIntegrationPackId, "POSTGRES_RECORD" | "MYSQL_RECORD" | "BROWSER_WORKFLOW">;
|
|
39
|
+
environment: "sandbox" | "staging" | "production";
|
|
40
|
+
credentialHandle: string;
|
|
41
|
+
resolveCredential: HttpProductionEvaluatorOptions["resolveCredential"];
|
|
42
|
+
allowedOrigin?: string;
|
|
43
|
+
fetch?: typeof fetch;
|
|
44
|
+
timeoutMs?: number;
|
|
45
|
+
now?: () => Date;
|
|
46
|
+
};
|
|
47
|
+
type DatabasePackOptions = {
|
|
48
|
+
packId: "POSTGRES_RECORD" | "MYSQL_RECORD";
|
|
49
|
+
environment: "sandbox" | "staging" | "production";
|
|
50
|
+
credentialHandle: string;
|
|
51
|
+
resolveCredential: DatabaseReadOnlyEvaluatorOptions["resolveCredential"];
|
|
52
|
+
statementId: string;
|
|
53
|
+
executePrepared: DatabaseReadOnlyEvaluatorOptions["executePrepared"];
|
|
54
|
+
timeoutMs?: number;
|
|
55
|
+
now?: () => Date;
|
|
56
|
+
};
|
|
57
|
+
type BrowserPackOptions = {
|
|
58
|
+
packId: "BROWSER_WORKFLOW";
|
|
59
|
+
environment: "sandbox" | "staging" | "production";
|
|
60
|
+
credentialHandle: string;
|
|
61
|
+
resolveCredential: BrowserWorkflowOutcomeEvaluatorOptions["resolveCredential"];
|
|
62
|
+
observerIdentity: BrowserWorkflowOutcomeEvaluatorOptions["observerIdentity"];
|
|
63
|
+
observe: BrowserWorkflowOutcomeEvaluatorOptions["observe"];
|
|
64
|
+
timeoutMs?: number;
|
|
65
|
+
now?: () => Date;
|
|
66
|
+
};
|
|
67
|
+
export type CreateProviderPackEvaluatorOptions = HttpPackOptions | DatabasePackOptions | BrowserPackOptions;
|
|
68
|
+
export interface ProviderPackPreflightResult {
|
|
69
|
+
schemaVersion: "witnora.provider_pack_preflight.v0.1";
|
|
70
|
+
packId: ProviderIntegrationPackId;
|
|
71
|
+
state: "READY" | "FIELD_NOT_OBSERVED";
|
|
72
|
+
productionWrites: 0;
|
|
73
|
+
credentialResolvedLocally: true;
|
|
74
|
+
observedFieldNames: string[];
|
|
75
|
+
observationDigestSha256: string;
|
|
76
|
+
limitations: string[];
|
|
77
|
+
}
|
|
78
|
+
export declare function listProviderIntegrationPacks(): ProviderIntegrationPack[];
|
|
79
|
+
export declare function getProviderIntegrationPack(id: ProviderIntegrationPackId): ProviderIntegrationPack;
|
|
80
|
+
export declare function createProviderPackEvaluator(options: CreateProviderPackEvaluatorOptions): ProductionOutcomeEvaluator;
|
|
81
|
+
export declare function preflightProviderIntegration(input: {
|
|
82
|
+
evaluator: ProductionOutcomeEvaluator;
|
|
83
|
+
packId: ProviderIntegrationPackId;
|
|
84
|
+
resourceId: string;
|
|
85
|
+
criterion: {
|
|
86
|
+
id: string;
|
|
87
|
+
field: string;
|
|
88
|
+
expected: string | number | boolean | null;
|
|
89
|
+
};
|
|
90
|
+
}): Promise<ProviderPackPreflightResult>;
|
|
91
|
+
export {};
|
|
92
|
+
//# sourceMappingURL=provider-integration-packs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-integration-packs.d.ts","sourceRoot":"","sources":["../../../../onegent-runtime/src/provider-integration-packs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { createBrowserWorkflowOutcomeEvaluator, createCrmRecordStateEvaluator, createDatabaseReadOnlyEvaluator, createEmailDeliveryEvaluator, createPaymentRefundResultEvaluator, createQueueJobCompletionEvaluator, createTicketStatusEvaluator, createWebhookDeliveryEvaluator, } from "./production-evaluator-kit.js";
|
|
3
|
+
import { canonicalJson } from "./trust-crypto.js";
|
|
4
|
+
export const PROVIDER_INTEGRATION_PACK_SCHEMA_VERSION = "witnora.provider_integration_pack.v0.1";
|
|
5
|
+
const BASE = [
|
|
6
|
+
pack("STRIPE_REFUND", "stripe", "Stripe refund result", "PAYMENT_REFUND_RESULT", ["sandbox", "production"], ["refunds:read"], "env://STRIPE_SECRET_KEY", ["status", "amount", "currency", "failure_reason"], "/v1/refunds/{resourceId}", "https://api.stripe.com", [criterion("refund-complete", "Which Stripe status means the refund completed?", "status", ["succeeded"])]),
|
|
7
|
+
pack("SALESFORCE_RECORD", "salesforce", "Salesforce record state", "CRM_RECORD_STATE", ["sandbox", "production"], ["API enabled with object and field read-only permission set"], "env://SALESFORCE_ACCESS_TOKEN", ["Status__c", "Refund_Status__c", "IsClosed", "StageName"], "/services/data/v61.0/sobjects/{object}/{resourceId}", undefined, [criterion("crm-state", "Which Salesforce field and value establish success?", "Status__c", ["Completed", "Approved"])]),
|
|
8
|
+
pack("HUBSPOT_CRM_RECORD", "hubspot", "HubSpot CRM record", "CRM_RECORD_STATE", ["sandbox", "production"], ["crm.objects.read"], "env://HUBSPOT_ACCESS_TOKEN", ["hs_pipeline_stage", "hs_status", "closedate", "amount"], "/crm/v3/objects/{object}/{resourceId}", "https://api.hubapi.com", [criterion("crm-state", "Which HubSpot property means the business task completed?", "hs_status", ["closed", "completed"])]),
|
|
9
|
+
pack("ZENDESK_TICKET", "zendesk", "Zendesk ticket status", "TICKET_STATUS", ["sandbox", "production"], ["tickets:read"], "env://ZENDESK_API_TOKEN", ["status", "priority", "type", "via.channel"], "/api/v2/tickets/{resourceId}.json", undefined, [criterion("ticket-complete", "Which Zendesk status means the ticket is complete?", "status", ["solved", "closed"])]),
|
|
10
|
+
pack("INTERCOM_TICKET", "intercom", "Intercom ticket status", "TICKET_STATUS", ["sandbox", "production"], ["tickets:read"], "env://INTERCOM_ACCESS_TOKEN", ["state", "priority", "ticket_type", "open"], "/tickets/{resourceId}", "https://api.intercom.io", [criterion("ticket-complete", "Which Intercom state means the ticket is complete?", "state", ["closed"])]),
|
|
11
|
+
pack("POSTGRES_RECORD", "postgresql", "PostgreSQL prepared read", "DATABASE_READ_ONLY", ["sandbox", "staging", "production"], ["SELECT on approved view"], "env://WITNORA_POSTGRES_READ_URL", ["status", "state", "result", "completed", "version"], "prepared://{statementId}", undefined, [criterion("record-state", "Which allowlisted result field proves success?", "status", ["completed", "succeeded"])]),
|
|
12
|
+
pack("MYSQL_RECORD", "mysql", "MySQL prepared read", "DATABASE_READ_ONLY", ["sandbox", "staging", "production"], ["SELECT on approved view"], "env://WITNORA_MYSQL_READ_URL", ["status", "state", "result", "completed", "version"], "prepared://{statementId}", undefined, [criterion("record-state", "Which allowlisted result field proves success?", "status", ["completed", "succeeded"])]),
|
|
13
|
+
pack("WEBHOOK_DELIVERY", "webhook", "Webhook delivery status", "WEBHOOK_DELIVERY", ["sandbox", "staging", "production"], ["delivery:read"], "env://WITNORA_WEBHOOK_READ_TOKEN", ["status", "delivered", "attempts", "response_code"], "/deliveries/{resourceId}", undefined, [criterion("webhook-delivered", "What delivery state counts as received?", "delivered", [true])]),
|
|
14
|
+
pack("QUEUE_JOB", "queue", "Queue or job completion", "QUEUE_JOB_COMPLETION", ["sandbox", "staging", "production"], ["jobs:read"], "env://WITNORA_QUEUE_READ_TOKEN", ["status", "completed", "attempts", "result_code"], "/jobs/{resourceId}", undefined, [criterion("job-complete", "What job state means processing completed?", "status", ["completed", "succeeded"])]),
|
|
15
|
+
pack("EMAIL_DELIVERY", "email", "Email delivery result", "EMAIL_DELIVERY", ["sandbox", "staging", "production"], ["messages:read"], "env://WITNORA_EMAIL_READ_TOKEN", ["status", "delivered", "bounce_type", "response_code"], "/messages/{resourceId}", undefined, [criterion("email-delivered", "What provider state means the message was delivered?", "delivered", [true])]),
|
|
16
|
+
pack("BROWSER_WORKFLOW", "browser", "Browser workflow outcome", "BROWSER_WORKFLOW_OUTCOME", ["sandbox", "staging", "production"], ["read-only observer"], "file://.witnora/secrets/browser-probe", ["status", "completed", "state", "result"], "observer://{resourceId}", undefined, [criterion("workflow-complete", "Which observable page state means the workflow completed?", "completed", [true])]),
|
|
17
|
+
];
|
|
18
|
+
export function listProviderIntegrationPacks() { return BASE.map((item) => structuredClone(item)); }
|
|
19
|
+
export function getProviderIntegrationPack(id) {
|
|
20
|
+
const found = BASE.find((item) => item.id === id);
|
|
21
|
+
if (!found)
|
|
22
|
+
throw new Error("Provider integration pack is not supported.");
|
|
23
|
+
return structuredClone(found);
|
|
24
|
+
}
|
|
25
|
+
export function createProviderPackEvaluator(options) {
|
|
26
|
+
const spec = getProviderIntegrationPack(options.packId);
|
|
27
|
+
if (!spec.environments.includes(options.environment))
|
|
28
|
+
throw new Error("Provider pack does not support this environment.");
|
|
29
|
+
const select = selector(spec.fieldAllowlist);
|
|
30
|
+
const common = { provider: spec.provider, environment: options.environment, credentialHandle: options.credentialHandle, resolveCredential: options.resolveCredential, select, timeoutMs: options.timeoutMs, now: options.now };
|
|
31
|
+
if (options.packId === "POSTGRES_RECORD" || options.packId === "MYSQL_RECORD")
|
|
32
|
+
return createDatabaseReadOnlyEvaluator({ ...common, statementId: options.statementId, executePrepared: options.executePrepared });
|
|
33
|
+
if (options.packId === "BROWSER_WORKFLOW")
|
|
34
|
+
return createBrowserWorkflowOutcomeEvaluator({ ...common, observerIdentity: options.observerIdentity, observe: options.observe });
|
|
35
|
+
const http = options;
|
|
36
|
+
const origin = http.allowedOrigin ?? spec.endpoint.origin;
|
|
37
|
+
if (!origin)
|
|
38
|
+
throw new Error("Provider pack requires the customer-specific HTTPS origin discovered during local setup.");
|
|
39
|
+
const resourcePath = resourcePathBuilder(spec.endpoint.resourcePattern);
|
|
40
|
+
const input = { ...common, allowedOrigin: origin, resourcePath, fetch: http.fetch };
|
|
41
|
+
switch (spec.template) {
|
|
42
|
+
case "CRM_RECORD_STATE": return createCrmRecordStateEvaluator(input);
|
|
43
|
+
case "TICKET_STATUS": return createTicketStatusEvaluator(input);
|
|
44
|
+
case "EMAIL_DELIVERY": return createEmailDeliveryEvaluator(input);
|
|
45
|
+
case "WEBHOOK_DELIVERY": return createWebhookDeliveryEvaluator(input);
|
|
46
|
+
case "QUEUE_JOB_COMPLETION": return createQueueJobCompletionEvaluator(input);
|
|
47
|
+
case "PAYMENT_REFUND_RESULT": return createPaymentRefundResultEvaluator(input);
|
|
48
|
+
default: throw new Error("Provider pack evaluator template is unsupported.");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export async function preflightProviderIntegration(input) {
|
|
52
|
+
const pack = getProviderIntegrationPack(input.packId);
|
|
53
|
+
if (!pack.fieldAllowlist.includes(input.criterion.field))
|
|
54
|
+
throw new Error("Preflight criterion is outside the provider field allowlist.");
|
|
55
|
+
const observation = await input.evaluator.evaluate({ resourceId: input.resourceId, criterionId: input.criterion.id, expected: { [input.criterion.field]: input.criterion.expected } });
|
|
56
|
+
const observedFieldNames = Object.keys(observation.observation.fields).sort();
|
|
57
|
+
return {
|
|
58
|
+
schemaVersion: "witnora.provider_pack_preflight.v0.1", packId: input.packId,
|
|
59
|
+
state: observedFieldNames.includes(input.criterion.field) ? "READY" : "FIELD_NOT_OBSERVED",
|
|
60
|
+
productionWrites: 0, credentialResolvedLocally: true, observedFieldNames,
|
|
61
|
+
observationDigestSha256: observation.observation.digestSha256,
|
|
62
|
+
limitations: [...observation.limitations, "Preflight validates one read-only provider observation; it does not approve a production action or establish a release decision."],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function pack(id, provider, title, template, environments, scopes, suggestedHandle, fields, resourcePattern, origin, criteria) {
|
|
66
|
+
const value = { schemaVersion: PROVIDER_INTEGRATION_PACK_SCHEMA_VERSION, id, provider, title, template, environments, credential: { access: "READ_ONLY", scopes, suggestedHandle, healthCheck: template === "DATABASE_READ_ONLY" ? "PREPARED_SELECT" : template === "BROWSER_WORKFLOW_OUTCOME" ? "OBSERVER_READ" : "RESOURCE_GET" }, fieldAllowlist: fields, commonCriteria: criteria, endpoint: { ...(origin ? { origin } : {}), configurableOrigin: !origin, resourcePattern }, boundaries: { writes: false, redirects: false, rawPayloadUpload: false, rawCredentialUpload: false } };
|
|
67
|
+
const material = { id, fields: [...fields], scopes: [...scopes], environments: [...environments], criteria: criteria.map((item) => ({ id: item.id, field: item.field, values: [...item.suggestedValues] })) };
|
|
68
|
+
return { ...value, contractDigestSha256: createHash("sha256").update(canonicalJson(material)).digest("hex") };
|
|
69
|
+
}
|
|
70
|
+
function criterion(id, question, field, suggestedValues) { return { id, question, field, suggestedValues }; }
|
|
71
|
+
function selector(fields) {
|
|
72
|
+
return (value) => Object.fromEntries(fields.flatMap((field) => { const selected = field.split(".").reduce((current, key) => current && typeof current === "object" ? current[key] : undefined, value); return selected === undefined ? [] : [[field, selected]]; }));
|
|
73
|
+
}
|
|
74
|
+
function resourcePathBuilder(pattern) {
|
|
75
|
+
return (resourceId) => pattern.replace("{resourceId}", encodeURIComponent(resourceId)).replace("{object}", "records");
|
|
76
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "witnora",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.1",
|
|
4
4
|
"description": "Independent assurance for covered agent action paths across models and frameworks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -48,6 +48,10 @@
|
|
|
48
48
|
"types": "./dist/vendor/onegent-runtime/production-evaluator-kit.d.ts",
|
|
49
49
|
"import": "./dist/vendor/onegent-runtime/production-evaluator-kit.js"
|
|
50
50
|
},
|
|
51
|
+
"./provider-integration-packs": {
|
|
52
|
+
"types": "./dist/vendor/onegent-runtime/provider-integration-packs.d.ts",
|
|
53
|
+
"import": "./dist/vendor/onegent-runtime/provider-integration-packs.js"
|
|
54
|
+
},
|
|
51
55
|
"./change-manifest": {
|
|
52
56
|
"types": "./dist/vendor/onegent-runtime/signed-change-manifest.d.ts",
|
|
53
57
|
"import": "./dist/vendor/onegent-runtime/signed-change-manifest.js"
|