witnora 0.13.11 → 0.14.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/dist/cli.js +1 -1
- package/dist/gateway.js +157 -19
- package/dist/internal/control-client/collector-gateway.d.ts +6 -1
- package/dist/internal/control-client/collector-gateway.d.ts.map +1 -1
- package/dist/internal/control-client/collector-gateway.js +2 -0
- package/dist/internal/control-client/remote-collector.d.ts +8 -0
- package/dist/internal/control-client/remote-collector.d.ts.map +1 -1
- package/dist/internal/control-client/remote-collector.js +1 -0
- package/dist/onboard.js +28 -2
- package/dist/vendor/onegent-runtime/production-evaluator-kit.d.ts +85 -0
- package/dist/vendor/onegent-runtime/production-evaluator-kit.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/production-evaluator-kit.js +131 -0
- package/dist/vendor/onegent-runtime/signed-change-manifest.d.ts +40 -0
- package/dist/vendor/onegent-runtime/signed-change-manifest.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/signed-change-manifest.js +22 -0
- package/package.json +9 -1
package/dist/cli.js
CHANGED
|
@@ -246,7 +246,7 @@ else if (command === "gateway") {
|
|
|
246
246
|
maxConcurrency: readFlag("--max-concurrency") ? Number(readFlag("--max-concurrency")) : undefined,
|
|
247
247
|
force: readBoolFlag("--force"),
|
|
248
248
|
});
|
|
249
|
-
process.stdout.write(`Configured the Managed Workflow Harness for ${result.config.workflowIds
|
|
249
|
+
process.stdout.write(`Configured the Managed Workflow Harness for ${result.config.workflowIds?.length ?? "all active"} Workflow Contract(s).\nConfig: ${result.path}\nRestart the managed Gateway to activate it.\n`);
|
|
250
250
|
}
|
|
251
251
|
else {
|
|
252
252
|
throw new Error("Use witnora gateway init|doctor|start|status|logs|restart|stop|run|workflow-harness.");
|
package/dist/gateway.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createHash, createPrivateKey, createPublicKey, randomBytes } from "node:crypto";
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import { closeSync, openSync } from "node:fs";
|
|
4
|
-
import { access, chmod, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
5
|
-
import { basename, dirname, join, resolve } from "node:path";
|
|
4
|
+
import { access, chmod, mkdir, readFile, realpath, rename, rm, writeFile } from "node:fs/promises";
|
|
5
|
+
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
6
6
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
7
|
import { loadConnection } from "./credentials.js";
|
|
8
8
|
import { authorizeProjectConnection } from "./device-authorization.js";
|
|
@@ -14,6 +14,7 @@ const CONFIG_SCHEMA = "witnora.customer_gateway_setup.v0.1";
|
|
|
14
14
|
const SECRETS_SCHEMA = "witnora.customer_gateway_local_secrets.v0.1";
|
|
15
15
|
const RUNTIME_SCHEMA = "witnora.managed_gateway_runtime.v0.1";
|
|
16
16
|
const WORKFLOW_HARNESS_SCHEMA = "witnora.managed_workflow_harness.v0.1";
|
|
17
|
+
const MANAGED_WORKFLOW_HARNESS_SCHEMA = "witnora.managed_workflow_harness.v0.2";
|
|
17
18
|
export async function initializeCustomerGateway(options) {
|
|
18
19
|
const repository = resolve(options.repository ?? process.cwd());
|
|
19
20
|
const outDir = resolve(repository, options.outDir ?? ".witnora/gateway");
|
|
@@ -547,6 +548,9 @@ export async function runCustomerGateway(options) {
|
|
|
547
548
|
fixtureReady: false,
|
|
548
549
|
} } : {}),
|
|
549
550
|
} } : {}),
|
|
551
|
+
...(workflowHarnessConfig?.schemaVersion === MANAGED_WORKFLOW_HARNESS_SCHEMA && workflowHarness
|
|
552
|
+
? { assuranceHarness: { status: () => workflowHarness.status() } }
|
|
553
|
+
: {}),
|
|
550
554
|
});
|
|
551
555
|
workflowHarness?.start();
|
|
552
556
|
process.stdout.write(`Witnora customer-owned Gateway listening on ${gateway.baseUrl}\n`);
|
|
@@ -567,10 +571,24 @@ export async function runCustomerGateway(options) {
|
|
|
567
571
|
function configManagedWorkflowHarnessImport() {
|
|
568
572
|
return import(new URL("./vendor/onegent-runtime/managed-workflow-harness.js", import.meta.url).href);
|
|
569
573
|
}
|
|
574
|
+
function configBusinessTaskEvaluatorImport() {
|
|
575
|
+
return import(new URL("./vendor/onegent-runtime/business-task-evaluator.js", import.meta.url).href);
|
|
576
|
+
}
|
|
570
577
|
export async function createConfiguredWorkflowHarness(input) {
|
|
571
578
|
const requestFetch = input.fetch ?? fetch;
|
|
572
|
-
|
|
573
|
-
|
|
579
|
+
let managedEvaluator;
|
|
580
|
+
let credential;
|
|
581
|
+
let evaluatorOrigin;
|
|
582
|
+
if (input.config.schemaVersion === MANAGED_WORKFLOW_HARNESS_SCHEMA) {
|
|
583
|
+
managedEvaluator = await startManagedLocalEvaluator(input.directory, input.config, input.evaluatorKit);
|
|
584
|
+
credential = managedEvaluator.credential;
|
|
585
|
+
evaluatorOrigin = managedEvaluator.origin;
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
credential = await readSecretProviderHandle(input.config.evaluatorCredentialHandle);
|
|
589
|
+
evaluatorOrigin = input.config.evaluatorOrigin;
|
|
590
|
+
}
|
|
591
|
+
const health = await requestFetch(`${evaluatorOrigin}/healthz`, {
|
|
574
592
|
headers: { authorization: `Bearer ${credential}` },
|
|
575
593
|
redirect: "error",
|
|
576
594
|
signal: AbortSignal.timeout(2_000),
|
|
@@ -580,6 +598,7 @@ export async function createConfiguredWorkflowHarness(input) {
|
|
|
580
598
|
|| healthBody.schemaVersion !== "witnora.business_task_evaluator.v0.1"
|
|
581
599
|
|| healthBody.contractSha256 !== input.config.evaluatorContractSha256
|
|
582
600
|
|| healthBody.ready !== true) {
|
|
601
|
+
await managedEvaluator?.close();
|
|
583
602
|
throw new Error("Managed Workflow evaluator health did not match its pinned local contract.");
|
|
584
603
|
}
|
|
585
604
|
const hosted = input.managed.createManagedWorkflowHostedClient({
|
|
@@ -594,7 +613,7 @@ export async function createConfiguredWorkflowHarness(input) {
|
|
|
594
613
|
checkpoints: new input.managed.FileWorkflowEvaluationCheckpointStore(join(input.directory, "data", "workflow-evaluations")),
|
|
595
614
|
maxConcurrency: input.config.maxConcurrency,
|
|
596
615
|
evaluate: async ({ task, evaluation }) => {
|
|
597
|
-
const response = await requestFetch(`${
|
|
616
|
+
const response = await requestFetch(`${evaluatorOrigin}/v1/evaluate`, {
|
|
598
617
|
method: "POST",
|
|
599
618
|
headers: { authorization: `Bearer ${credential}`, "content-type": "application/json" },
|
|
600
619
|
body: JSON.stringify({ schemaVersion: "witnora.business_task_evaluation_request.v0.1", task, evaluation }),
|
|
@@ -610,12 +629,23 @@ export async function createConfiguredWorkflowHarness(input) {
|
|
|
610
629
|
});
|
|
611
630
|
let timer;
|
|
612
631
|
let closing = false;
|
|
632
|
+
let lastTickAt;
|
|
633
|
+
let lastError;
|
|
613
634
|
const tick = async () => {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
635
|
+
try {
|
|
636
|
+
const result = await worker.tick();
|
|
637
|
+
lastTickAt = new Date().toISOString();
|
|
638
|
+
lastError = (result.evaluationsFailed ?? 0) > 0 ? result.limitations?.[0] ?? "One or more evaluations failed closed." : undefined;
|
|
639
|
+
if ((result.evaluationsFailed ?? 0) > 0) {
|
|
640
|
+
process.stderr.write(`Managed Workflow Harness stopped ${result.evaluationsFailed} evaluation(s) fail-closed. ${lastError}\n`);
|
|
641
|
+
}
|
|
642
|
+
return result;
|
|
643
|
+
}
|
|
644
|
+
catch (error) {
|
|
645
|
+
lastTickAt = new Date().toISOString();
|
|
646
|
+
lastError = error instanceof Error ? error.message.slice(0, 500) : "Managed Workflow Harness tick failed.";
|
|
647
|
+
throw error;
|
|
617
648
|
}
|
|
618
|
-
return result;
|
|
619
649
|
};
|
|
620
650
|
return {
|
|
621
651
|
start() {
|
|
@@ -630,10 +660,58 @@ export async function createConfiguredWorkflowHarness(input) {
|
|
|
630
660
|
if (timer)
|
|
631
661
|
clearInterval(timer);
|
|
632
662
|
timer = undefined;
|
|
663
|
+
await managedEvaluator?.close();
|
|
664
|
+
},
|
|
665
|
+
async status() {
|
|
666
|
+
return {
|
|
667
|
+
moduleDigestSha256: input.config.schemaVersion === MANAGED_WORKFLOW_HARNESS_SCHEMA ? input.config.evaluatorModuleSha256 : input.config.evaluatorContractSha256,
|
|
668
|
+
evaluatorContractSha256: input.config.evaluatorContractSha256,
|
|
669
|
+
workerReady: !closing && !lastError,
|
|
670
|
+
...(lastTickAt ? { lastTickAt } : {}),
|
|
671
|
+
...(lastError ? { lastError } : {}),
|
|
672
|
+
};
|
|
633
673
|
},
|
|
634
674
|
tick,
|
|
635
675
|
};
|
|
636
676
|
}
|
|
677
|
+
async function startManagedLocalEvaluator(directory, config, evaluatorKit) {
|
|
678
|
+
const repository = resolve(directory, "..", "..");
|
|
679
|
+
const modulePath = resolve(repository, config.evaluatorModulePath);
|
|
680
|
+
const repositoryRelative = relative(repository, modulePath);
|
|
681
|
+
if (!repositoryRelative || repositoryRelative.startsWith("..") || resolve(repository, repositoryRelative) !== modulePath) {
|
|
682
|
+
throw new Error("Managed evaluator module escaped the Agent repository.");
|
|
683
|
+
}
|
|
684
|
+
const [realRepository, realModulePath] = await Promise.all([realpath(repository), realpath(modulePath)]);
|
|
685
|
+
const realRelative = relative(realRepository, realModulePath);
|
|
686
|
+
if (!realRelative || realRelative.startsWith("..") || resolve(realRepository, realRelative) !== realModulePath) {
|
|
687
|
+
throw new Error("Managed evaluator module symlink escaped the Agent repository.");
|
|
688
|
+
}
|
|
689
|
+
const source = await readFile(modulePath);
|
|
690
|
+
if (createHash("sha256").update(source).digest("hex") !== config.evaluatorModuleSha256) {
|
|
691
|
+
throw new Error("Managed evaluator module digest did not match workflow-harness.json.");
|
|
692
|
+
}
|
|
693
|
+
const imported = await import(`${pathToFileURL(modulePath).href}?sha256=${config.evaluatorModuleSha256}`);
|
|
694
|
+
if (typeof imported.createWitnoraBusinessTaskEvaluatorOptions !== "function") {
|
|
695
|
+
throw new Error("Managed evaluator module did not export createWitnoraBusinessTaskEvaluatorOptions().");
|
|
696
|
+
}
|
|
697
|
+
const customerOptions = await imported.createWitnoraBusinessTaskEvaluatorOptions({
|
|
698
|
+
repository,
|
|
699
|
+
dataDirectory: join(directory, "data", "business-task-evaluator"),
|
|
700
|
+
});
|
|
701
|
+
if (!customerOptions || typeof customerOptions !== "object" || Array.isArray(customerOptions)) {
|
|
702
|
+
throw new Error("Managed evaluator module returned invalid Evaluator Kit options.");
|
|
703
|
+
}
|
|
704
|
+
const credential = randomBytes(32).toString("base64url");
|
|
705
|
+
const evaluator = (evaluatorKit ?? await configBusinessTaskEvaluatorImport()).createBusinessTaskEvaluatorServer({
|
|
706
|
+
...customerOptions,
|
|
707
|
+
credential,
|
|
708
|
+
contractSha256: config.evaluatorContractSha256,
|
|
709
|
+
host: "127.0.0.1",
|
|
710
|
+
port: 0,
|
|
711
|
+
});
|
|
712
|
+
const started = await evaluator.start();
|
|
713
|
+
return { origin: started.origin, credential, close: () => evaluator.close() };
|
|
714
|
+
}
|
|
637
715
|
async function runtimeSandboxFixtureReady(config) {
|
|
638
716
|
try {
|
|
639
717
|
if (config.adapterId !== LOCAL_SANDBOX_ADAPTER_ID || !config.sandboxOrigin || !config.probeTargetCredentialHandle || !config.fixtureContractSha256)
|
|
@@ -1026,16 +1104,20 @@ function parseConfig(raw) {
|
|
|
1026
1104
|
}
|
|
1027
1105
|
export function parseManagedWorkflowHarnessConfig(raw) {
|
|
1028
1106
|
const value = JSON.parse(raw);
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1107
|
+
const workflowIds = value.workflowIds;
|
|
1108
|
+
const workflowIdsValid = workflowIds === undefined || (Array.isArray(workflowIds)
|
|
1109
|
+
&& workflowIds.length > 0
|
|
1110
|
+
&& workflowIds.length <= 100
|
|
1111
|
+
&& new Set(workflowIds).size === workflowIds.length
|
|
1112
|
+
&& workflowIds.every((id) => typeof id === "string" && /^[A-Za-z0-9._:-]{1,200}$/.test(id)));
|
|
1113
|
+
const external = value.schemaVersion === WORKFLOW_HARNESS_SCHEMA
|
|
1114
|
+
&& literalLoopbackOrigin(value.evaluatorOrigin)
|
|
1115
|
+
&& credentialHandle(value.evaluatorCredentialHandle ?? "")
|
|
1116
|
+
&& Array.isArray(workflowIds);
|
|
1117
|
+
const managed = value.schemaVersion === MANAGED_WORKFLOW_HARNESS_SCHEMA
|
|
1118
|
+
&& safeRelativeModulePath(value.evaluatorModulePath)
|
|
1119
|
+
&& validDigest(value.evaluatorModuleSha256 ?? "");
|
|
1120
|
+
if (value.enabled !== true || !validDigest(value.evaluatorContractSha256 ?? "") || !workflowIdsValid || (!external && !managed)) {
|
|
1039
1121
|
throw new Error("workflow-harness.json requires an enabled, digest-pinned literal-loopback evaluator and a local credential handle.");
|
|
1040
1122
|
}
|
|
1041
1123
|
if (value.pollIntervalMs !== undefined && (!Number.isInteger(value.pollIntervalMs) || value.pollIntervalMs < 1_000 || value.pollIntervalMs > 60_000)) {
|
|
@@ -1046,6 +1128,56 @@ export function parseManagedWorkflowHarnessConfig(raw) {
|
|
|
1046
1128
|
}
|
|
1047
1129
|
return value;
|
|
1048
1130
|
}
|
|
1131
|
+
export async function activateManagedWorkflowHarness(options) {
|
|
1132
|
+
const repository = resolve(options.repository ?? process.cwd());
|
|
1133
|
+
const directory = join(repository, ".witnora", "gateway");
|
|
1134
|
+
if (!await exists(join(directory, "gateway.json")))
|
|
1135
|
+
throw new Error("Initialize the customer-owned Gateway before activating its Assurance Harness.");
|
|
1136
|
+
const absoluteModulePath = resolve(repository, options.modulePath ?? "witnora.assurance-harness.mjs");
|
|
1137
|
+
const moduleRelativeToRepository = relative(repository, absoluteModulePath);
|
|
1138
|
+
if (!moduleRelativeToRepository || moduleRelativeToRepository.startsWith("..") || resolve(repository, moduleRelativeToRepository) !== absoluteModulePath) {
|
|
1139
|
+
throw new Error("The customer Assurance Harness module must remain inside the Agent repository.");
|
|
1140
|
+
}
|
|
1141
|
+
const [realRepository, realModulePath] = await Promise.all([realpath(repository), realpath(absoluteModulePath).catch(() => absoluteModulePath)]);
|
|
1142
|
+
const realRelative = relative(realRepository, realModulePath);
|
|
1143
|
+
if (realRelative.startsWith("..") || resolve(realRepository, realRelative) !== realModulePath) {
|
|
1144
|
+
throw new Error("The customer Assurance Harness module symlink must remain inside the Agent repository.");
|
|
1145
|
+
}
|
|
1146
|
+
const source = await readFile(absoluteModulePath, "utf8").catch((error) => {
|
|
1147
|
+
if (error.code === "ENOENT") {
|
|
1148
|
+
throw new Error("No customer Assurance Harness was found. Add witnora.assurance-harness.mjs through the approved Business Task integration before activation.");
|
|
1149
|
+
}
|
|
1150
|
+
throw error;
|
|
1151
|
+
});
|
|
1152
|
+
if (!source.includes("createWitnoraBusinessTaskEvaluatorOptions")) {
|
|
1153
|
+
throw new Error("The customer Assurance Harness must export createWitnoraBusinessTaskEvaluatorOptions().");
|
|
1154
|
+
}
|
|
1155
|
+
const digestSha256 = createHash("sha256").update(source).digest("hex");
|
|
1156
|
+
const evaluatorModulePath = moduleRelativeToRepository.replaceAll("\\", "/");
|
|
1157
|
+
const config = parseManagedWorkflowHarnessConfig(JSON.stringify({
|
|
1158
|
+
schemaVersion: MANAGED_WORKFLOW_HARNESS_SCHEMA,
|
|
1159
|
+
enabled: true,
|
|
1160
|
+
evaluatorModulePath,
|
|
1161
|
+
evaluatorModuleSha256: digestSha256,
|
|
1162
|
+
evaluatorContractSha256: digestSha256,
|
|
1163
|
+
...(options.workflowIds ? { workflowIds: options.workflowIds } : {}),
|
|
1164
|
+
...(options.pollIntervalMs === undefined ? {} : { pollIntervalMs: options.pollIntervalMs }),
|
|
1165
|
+
...(options.maxConcurrency === undefined ? {} : { maxConcurrency: options.maxConcurrency }),
|
|
1166
|
+
}));
|
|
1167
|
+
const path = join(directory, "workflow-harness.json");
|
|
1168
|
+
const serialized = `${JSON.stringify(config, null, 2)}\n`;
|
|
1169
|
+
let created = false;
|
|
1170
|
+
if (await exists(path)) {
|
|
1171
|
+
const current = await readFile(path, "utf8");
|
|
1172
|
+
if (current !== serialized)
|
|
1173
|
+
throw new Error("Existing workflow-harness.json differs from the generated Assurance Harness binding; refusing to overwrite customer configuration.");
|
|
1174
|
+
}
|
|
1175
|
+
else {
|
|
1176
|
+
await writeFile(path, serialized, { encoding: "utf8", mode: 0o600, flag: "wx" });
|
|
1177
|
+
created = true;
|
|
1178
|
+
}
|
|
1179
|
+
return { state: "READY_TO_START", path, modulePath: evaluatorModulePath, config, created };
|
|
1180
|
+
}
|
|
1049
1181
|
export async function configureManagedWorkflowHarness(options) {
|
|
1050
1182
|
const directory = resolve(options.repository ?? process.cwd(), options.dir ?? ".witnora/gateway");
|
|
1051
1183
|
if (!await exists(join(directory, "gateway.json")))
|
|
@@ -1081,6 +1213,12 @@ function literalLoopbackOrigin(value) {
|
|
|
1081
1213
|
return false;
|
|
1082
1214
|
}
|
|
1083
1215
|
}
|
|
1216
|
+
function safeRelativeModulePath(value) {
|
|
1217
|
+
if (typeof value !== "string" || !value || value.length > 500 || !value.endsWith(".mjs"))
|
|
1218
|
+
return false;
|
|
1219
|
+
const normalized = value.replaceAll("\\", "/");
|
|
1220
|
+
return !normalized.startsWith("/") && !/^[A-Za-z]:\//.test(normalized) && normalized.split("/").every((part) => part && part !== "." && part !== "..");
|
|
1221
|
+
}
|
|
1084
1222
|
function validateRuntimeWorkerConfig(value) {
|
|
1085
1223
|
if (value.enabled !== true || !value.adapterModulePath || !/^[a-f0-9]{64}$/.test(value.adapterModuleSha256)
|
|
1086
1224
|
|| !value.probeModulePath || !/^[a-f0-9]{64}$/.test(value.probeModuleSha256)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CustomerSourceKeyRing, type CustomerSourceSigner, type CollectorRuntimeHeartbeat, type RuntimeReadinessBinding, type RemoteCollectorAck, type RemoteTrustedSourceRecord } from "./remote-collector.js";
|
|
1
|
+
import { CustomerSourceKeyRing, type CustomerSourceSigner, type CollectorRuntimeHeartbeat, type AssuranceHarnessHeartbeat, type RuntimeReadinessBinding, type RemoteCollectorAck, type RemoteTrustedSourceRecord } from "./remote-collector.js";
|
|
2
2
|
export interface RemoteCollectorTransport {
|
|
3
3
|
registerSourceKey(input: {
|
|
4
4
|
collectorId: string;
|
|
@@ -13,6 +13,7 @@ export interface RemoteCollectorTransport {
|
|
|
13
13
|
pendingRecordCount: number;
|
|
14
14
|
lastAckSequence?: number;
|
|
15
15
|
runtime?: CollectorRuntimeHeartbeat;
|
|
16
|
+
assuranceHarness?: AssuranceHarnessHeartbeat;
|
|
16
17
|
}): Promise<Record<string, unknown>>;
|
|
17
18
|
reconcile(runId: string, receipt: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
18
19
|
proposeAction(proposal: Record<string, unknown>, idempotencyKey: string): Promise<Record<string, unknown>>;
|
|
@@ -45,6 +46,9 @@ export interface CustomerOwnedCollectorGatewayOptions {
|
|
|
45
46
|
workerReady?: boolean;
|
|
46
47
|
};
|
|
47
48
|
};
|
|
49
|
+
assuranceHarness?: {
|
|
50
|
+
status(): Promise<AssuranceHarnessHeartbeat>;
|
|
51
|
+
};
|
|
48
52
|
runtimeBinding?: RuntimeReadinessBinding;
|
|
49
53
|
}
|
|
50
54
|
export interface CustomerOwnedCollectorGateway {
|
|
@@ -67,6 +71,7 @@ export interface CollectorGatewayStatus {
|
|
|
67
71
|
lastRemoteSuccessAt?: string;
|
|
68
72
|
lastRemoteError?: string;
|
|
69
73
|
actionWorker?: Record<string, unknown>;
|
|
74
|
+
assuranceHarness?: AssuranceHarnessHeartbeat;
|
|
70
75
|
}
|
|
71
76
|
export declare function startCustomerOwnedCollectorGateway(options: CustomerOwnedCollectorGatewayOptions): Promise<CustomerOwnedCollectorGateway>;
|
|
72
77
|
//# sourceMappingURL=collector-gateway.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector-gateway.d.ts","sourceRoot":"","sources":["../../../../agentcert-sdk/src/collector-gateway.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,qBAAqB,EAGrB,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC/B,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,wBAAwB;IACvC,iBAAiB,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACjJ,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,EAAE,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAClH,SAAS,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,oBAAoB,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,yBAAyB,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"collector-gateway.d.ts","sourceRoot":"","sources":["../../../../agentcert-sdk/src/collector-gateway.ts"],"names":[],"mappings":"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"}
|
|
@@ -89,6 +89,7 @@ export async function startCustomerOwnedCollectorGateway(options) {
|
|
|
89
89
|
lastRemoteSuccessAt,
|
|
90
90
|
lastRemoteError,
|
|
91
91
|
...(options.actionWorker ? { actionWorker: await options.actionWorker.status() } : {}),
|
|
92
|
+
...(options.assuranceHarness ? { assuranceHarness: await options.assuranceHarness.status() } : {}),
|
|
92
93
|
};
|
|
93
94
|
};
|
|
94
95
|
const server = createServer(async (request, response) => {
|
|
@@ -181,6 +182,7 @@ export async function startCustomerOwnedCollectorGateway(options) {
|
|
|
181
182
|
pendingRecordCount: current.pendingRecordCount,
|
|
182
183
|
lastAckSequence: current.lastAckSequence,
|
|
183
184
|
runtime: runtimeBinding && workerStatus ? runtimeHeartbeat(runtimeBinding, workerStatus, options.actionWorker?.runtimeBinding?.fixtureReady) : undefined,
|
|
185
|
+
assuranceHarness: options.assuranceHarness ? await options.assuranceHarness.status() : undefined,
|
|
184
186
|
});
|
|
185
187
|
lastRemoteSuccessAt = new Date().toISOString();
|
|
186
188
|
lastRemoteError = undefined;
|
|
@@ -57,6 +57,13 @@ export interface CollectorRuntimeHeartbeat {
|
|
|
57
57
|
fixtureReady: boolean;
|
|
58
58
|
lastError?: string;
|
|
59
59
|
}
|
|
60
|
+
export interface AssuranceHarnessHeartbeat {
|
|
61
|
+
moduleDigestSha256: string;
|
|
62
|
+
evaluatorContractSha256: string;
|
|
63
|
+
workerReady: boolean;
|
|
64
|
+
lastTickAt?: string;
|
|
65
|
+
lastError?: string;
|
|
66
|
+
}
|
|
60
67
|
export interface RemoteCollectorClientOptions {
|
|
61
68
|
baseUrl: string;
|
|
62
69
|
projectId: string;
|
|
@@ -105,6 +112,7 @@ export declare class RemoteCollectorClient {
|
|
|
105
112
|
lastAckSequence?: number;
|
|
106
113
|
occurredAt?: string;
|
|
107
114
|
runtime?: CollectorRuntimeHeartbeat;
|
|
115
|
+
assuranceHarness?: AssuranceHarnessHeartbeat;
|
|
108
116
|
}): Promise<Record<string, unknown>>;
|
|
109
117
|
reconcile(runId: string, receipt: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
110
118
|
proposeAction(proposal: Record<string, unknown>, idempotencyKey: string): Promise<Record<string, unknown>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-collector.d.ts","sourceRoot":"","sources":["../../../../agentcert-sdk/src/remote-collector.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"remote-collector.d.ts","sourceRoot":"","sources":["../../../../agentcert-sdk/src/remote-collector.ts"],"names":[],"mappings":"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"}
|
|
@@ -105,6 +105,7 @@ export class RemoteCollectorClient {
|
|
|
105
105
|
pendingRecordCount: input.pendingRecordCount,
|
|
106
106
|
lastAckSequence: input.lastAckSequence,
|
|
107
107
|
runtime: input.runtime,
|
|
108
|
+
assuranceHarness: input.assuranceHarness,
|
|
108
109
|
};
|
|
109
110
|
const payloadSha256 = sha256(canonicalJson(payload));
|
|
110
111
|
return this.json("collector-heartbeats", {
|
package/dist/onboard.js
CHANGED
|
@@ -7,7 +7,7 @@ import { verifyControlPlaneConnection } from "./control-plane.js";
|
|
|
7
7
|
import { inferPrivateCapabilities, runPrivateCapabilityDiscovery } from "./private-discovery.js";
|
|
8
8
|
import { parseAgentTemplate, starterAdapter, starterProfile, starterTripwireConfig } from "./onboarding-templates.js";
|
|
9
9
|
import { writeTryEvidence } from "./try.js";
|
|
10
|
-
import { doctorCustomerGateway, initializeCustomerGateway, inspectLocalRuntimeBinding, inspectCustomerGatewayFiles, startManagedCustomerGateway, stopManagedCustomerGateway, upgradeCustomerGatewayRuntime, RuntimeSetupNotReadyError, } from "./gateway.js";
|
|
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
13
|
export async function runOnboard(options) {
|
|
@@ -85,6 +85,11 @@ export async function runOnboard(options) {
|
|
|
85
85
|
let gatewayMigration;
|
|
86
86
|
let managedGateway;
|
|
87
87
|
let runtimeUpgrade;
|
|
88
|
+
let assuranceHarnessReadiness = {
|
|
89
|
+
state: "WAITING_FOR_CUSTOMER_HARNESS",
|
|
90
|
+
limitation: "No approved customer Harness module is bound to this Agent repository.",
|
|
91
|
+
};
|
|
92
|
+
let assuranceHarnessChanged = false;
|
|
88
93
|
await reportInstall(requestFetch, server, token.projectId, token.apiKey, setupPlan.id, { status: "installing", attemptId });
|
|
89
94
|
try {
|
|
90
95
|
generatedFiles.push(...await generateRepositoryConfig(repositoryPath, repository.template, repository.name));
|
|
@@ -183,6 +188,24 @@ export async function runOnboard(options) {
|
|
|
183
188
|
}
|
|
184
189
|
const runtimeConfigured = await gatewayHasRuntimeWorker(repositoryPath);
|
|
185
190
|
generatedFiles.push(...await generateAutopilotFiles(repositoryPath, repository.name, runtimeConfigured));
|
|
191
|
+
try {
|
|
192
|
+
const activation = await activateManagedWorkflowHarness({ repository: repositoryPath });
|
|
193
|
+
if (activation.created)
|
|
194
|
+
generatedFiles.push(activation.path);
|
|
195
|
+
assuranceHarnessChanged = activation.created;
|
|
196
|
+
assuranceHarnessReadiness = { state: "ACTIVE" };
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
const detail = error instanceof Error ? error.message : "The customer Harness could not be activated.";
|
|
200
|
+
if (!detail.startsWith("No customer Assurance Harness was found."))
|
|
201
|
+
throw error;
|
|
202
|
+
assuranceHarnessReadiness = { state: "WAITING_FOR_CUSTOMER_HARNESS", limitation: detail };
|
|
203
|
+
}
|
|
204
|
+
if (assuranceHarnessChanged && gatewayState.status !== "absent") {
|
|
205
|
+
const stopped = await gatewayLifecycle.stop({ repository: repositoryPath, configHome: options.configHome, fetch: requestFetch });
|
|
206
|
+
if (stopped.state !== "STOPPED" && stopped.state !== "STALE")
|
|
207
|
+
throw new Error("The prior managed Gateway process did not stop before Assurance Harness activation.");
|
|
208
|
+
}
|
|
186
209
|
managedGateway = await gatewayLifecycle.start({
|
|
187
210
|
repository: repositoryPath,
|
|
188
211
|
configHome: options.configHome,
|
|
@@ -210,11 +233,14 @@ export async function runOnboard(options) {
|
|
|
210
233
|
output(runtimeReadiness.state === "LOCAL_SANDBOX_READY"
|
|
211
234
|
? "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"
|
|
212
235
|
: `Runtime: RECORDED_ONLY. ${runtimeReadiness.limitations[0]}\n`);
|
|
236
|
+
output(assuranceHarnessReadiness.state === "ACTIVE"
|
|
237
|
+
? "Assurance Harness: ACTIVE. Nora can dispatch authority-ready Replay and no-write Shadow evaluations without manual Workflow IDs, evaluator origins, credentials, or contract digests.\n"
|
|
238
|
+
: `Assurance Harness: WAITING_FOR_CUSTOMER_HARNESS. ${assuranceHarnessReadiness.limitation}\n`);
|
|
213
239
|
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");
|
|
214
240
|
return { projectId: token.projectId, connectionName: token.connectionName, credentialsPath, template: repository.template,
|
|
215
241
|
repositoryKind: repository.kind, generatedFiles, receiptPath, discovery, setupPlanId: setupPlan.id,
|
|
216
242
|
gatewayDirectory: join(repositoryPath, ".witnora", "gateway"), gatewayArchiveDirectory: gatewayMigration?.archiveDirectory,
|
|
217
|
-
gateway: managedGateway, runtimeReadiness };
|
|
243
|
+
gateway: managedGateway, runtimeReadiness, assuranceHarnessReadiness };
|
|
218
244
|
}
|
|
219
245
|
catch (error) {
|
|
220
246
|
const diagnosis = error instanceof Error ? error.message : String(error);
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export declare const PRODUCTION_EVALUATOR_OBSERVATION_VERSION: "witnora.production_evaluator_observation.v0.1";
|
|
2
|
+
export type ProductionEvaluatorTemplate = "CRM_RECORD_STATE" | "TICKET_STATUS" | "EMAIL_DELIVERY" | "DATABASE_READ_ONLY" | "WEBHOOK_DELIVERY" | "QUEUE_JOB_COMPLETION" | "PAYMENT_REFUND_RESULT" | "BROWSER_WORKFLOW_OUTCOME";
|
|
3
|
+
type SafeScalar = string | number | boolean | null;
|
|
4
|
+
type SafeFields = Record<string, SafeScalar>;
|
|
5
|
+
export interface ProductionEvaluatorRequest {
|
|
6
|
+
resourceId: string;
|
|
7
|
+
criterionId: string;
|
|
8
|
+
expected: SafeFields;
|
|
9
|
+
parameters?: SafeScalar[];
|
|
10
|
+
}
|
|
11
|
+
export interface ProductionEvaluatorObservation {
|
|
12
|
+
schemaVersion: typeof PRODUCTION_EVALUATOR_OBSERVATION_VERSION;
|
|
13
|
+
template: ProductionEvaluatorTemplate;
|
|
14
|
+
provider: string;
|
|
15
|
+
environment: "sandbox" | "staging" | "production";
|
|
16
|
+
criterion: {
|
|
17
|
+
id: string;
|
|
18
|
+
expectedDigestSha256: string;
|
|
19
|
+
};
|
|
20
|
+
scope: {
|
|
21
|
+
resourceIdSha256: string;
|
|
22
|
+
credentialHandleSha256: string;
|
|
23
|
+
};
|
|
24
|
+
result: "SATISFIED" | "NOT_SATISFIED" | "NOT_OBSERVED";
|
|
25
|
+
observation: {
|
|
26
|
+
fields: SafeFields;
|
|
27
|
+
digestSha256: string;
|
|
28
|
+
observedAt: string;
|
|
29
|
+
};
|
|
30
|
+
evaluatorIdentity?: {
|
|
31
|
+
id: string;
|
|
32
|
+
version: string;
|
|
33
|
+
digestSha256: string;
|
|
34
|
+
};
|
|
35
|
+
limitations: string[];
|
|
36
|
+
}
|
|
37
|
+
export interface ProductionOutcomeEvaluator {
|
|
38
|
+
readonly template: ProductionEvaluatorTemplate;
|
|
39
|
+
evaluate(request: ProductionEvaluatorRequest): Promise<ProductionEvaluatorObservation>;
|
|
40
|
+
}
|
|
41
|
+
interface CommonOptions {
|
|
42
|
+
provider: string;
|
|
43
|
+
environment: "sandbox" | "staging" | "production";
|
|
44
|
+
credentialHandle: string;
|
|
45
|
+
resolveCredential(handle: string): Promise<string>;
|
|
46
|
+
select(value: Record<string, unknown>): Record<string, unknown>;
|
|
47
|
+
timeoutMs?: number;
|
|
48
|
+
now?: () => Date;
|
|
49
|
+
}
|
|
50
|
+
export interface HttpProductionEvaluatorOptions extends CommonOptions {
|
|
51
|
+
allowedOrigin: string;
|
|
52
|
+
resourcePath(resourceId: string): string;
|
|
53
|
+
fetch?: typeof fetch;
|
|
54
|
+
}
|
|
55
|
+
export interface DatabaseReadOnlyEvaluatorOptions extends CommonOptions {
|
|
56
|
+
statementId: string;
|
|
57
|
+
executePrepared(input: {
|
|
58
|
+
statementId: string;
|
|
59
|
+
parameters: SafeScalar[];
|
|
60
|
+
credential: string;
|
|
61
|
+
signal: AbortSignal;
|
|
62
|
+
}): Promise<Record<string, unknown>>;
|
|
63
|
+
}
|
|
64
|
+
export interface BrowserWorkflowOutcomeEvaluatorOptions extends CommonOptions {
|
|
65
|
+
observerIdentity: {
|
|
66
|
+
id: string;
|
|
67
|
+
version: string;
|
|
68
|
+
digestSha256: string;
|
|
69
|
+
};
|
|
70
|
+
observe(input: {
|
|
71
|
+
resourceId: string;
|
|
72
|
+
credential: string;
|
|
73
|
+
signal: AbortSignal;
|
|
74
|
+
}): Promise<Record<string, unknown>>;
|
|
75
|
+
}
|
|
76
|
+
export declare const createCrmRecordStateEvaluator: (options: HttpProductionEvaluatorOptions) => ProductionOutcomeEvaluator;
|
|
77
|
+
export declare const createTicketStatusEvaluator: (options: HttpProductionEvaluatorOptions) => ProductionOutcomeEvaluator;
|
|
78
|
+
export declare const createEmailDeliveryEvaluator: (options: HttpProductionEvaluatorOptions) => ProductionOutcomeEvaluator;
|
|
79
|
+
export declare const createWebhookDeliveryEvaluator: (options: HttpProductionEvaluatorOptions) => ProductionOutcomeEvaluator;
|
|
80
|
+
export declare const createQueueJobCompletionEvaluator: (options: HttpProductionEvaluatorOptions) => ProductionOutcomeEvaluator;
|
|
81
|
+
export declare const createPaymentRefundResultEvaluator: (options: HttpProductionEvaluatorOptions) => ProductionOutcomeEvaluator;
|
|
82
|
+
export declare function createDatabaseReadOnlyEvaluator(options: DatabaseReadOnlyEvaluatorOptions): ProductionOutcomeEvaluator;
|
|
83
|
+
export declare function createBrowserWorkflowOutcomeEvaluator(options: BrowserWorkflowOutcomeEvaluatorOptions): ProductionOutcomeEvaluator;
|
|
84
|
+
export {};
|
|
85
|
+
//# sourceMappingURL=production-evaluator-kit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"production-evaluator-kit.d.ts","sourceRoot":"","sources":["../../../../onegent-runtime/src/production-evaluator-kit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { isIP } from "node:net";
|
|
3
|
+
import { canonicalJson } from "./trust-crypto.js";
|
|
4
|
+
export const PRODUCTION_EVALUATOR_OBSERVATION_VERSION = "witnora.production_evaluator_observation.v0.1";
|
|
5
|
+
export const createCrmRecordStateEvaluator = (options) => createHttpEvaluator("CRM_RECORD_STATE", options);
|
|
6
|
+
export const createTicketStatusEvaluator = (options) => createHttpEvaluator("TICKET_STATUS", options);
|
|
7
|
+
export const createEmailDeliveryEvaluator = (options) => createHttpEvaluator("EMAIL_DELIVERY", options);
|
|
8
|
+
export const createWebhookDeliveryEvaluator = (options) => createHttpEvaluator("WEBHOOK_DELIVERY", options);
|
|
9
|
+
export const createQueueJobCompletionEvaluator = (options) => createHttpEvaluator("QUEUE_JOB_COMPLETION", options);
|
|
10
|
+
export const createPaymentRefundResultEvaluator = (options) => createHttpEvaluator("PAYMENT_REFUND_RESULT", options);
|
|
11
|
+
export function createDatabaseReadOnlyEvaluator(options) {
|
|
12
|
+
validateCommon(options);
|
|
13
|
+
identifier(options.statementId, "statementId");
|
|
14
|
+
return evaluator("DATABASE_READ_ONLY", options, async (request, credential, signal) => {
|
|
15
|
+
const parameters = request.parameters ?? [request.resourceId];
|
|
16
|
+
if (parameters.length > 20 || parameters.some((value) => typeof value === "string" && value.length > 500))
|
|
17
|
+
throw new Error("Database evaluator parameters exceed the bounded contract.");
|
|
18
|
+
return options.executePrepared({ statementId: options.statementId, parameters, credential, signal });
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export function createBrowserWorkflowOutcomeEvaluator(options) {
|
|
22
|
+
validateCommon(options);
|
|
23
|
+
componentIdentity(options.observerIdentity);
|
|
24
|
+
return evaluator("BROWSER_WORKFLOW_OUTCOME", options, (request, credential, signal) => options.observe({ resourceId: request.resourceId, credential, signal }), options.observerIdentity);
|
|
25
|
+
}
|
|
26
|
+
function createHttpEvaluator(template, options) {
|
|
27
|
+
validateCommon(options);
|
|
28
|
+
const origin = safeOrigin(options.allowedOrigin);
|
|
29
|
+
const requestFetch = options.fetch ?? fetch;
|
|
30
|
+
return evaluator(template, options, async (request, credential, signal) => {
|
|
31
|
+
const path = options.resourcePath(request.resourceId);
|
|
32
|
+
if (typeof path !== "string" || !path.startsWith("/") || path.startsWith("//") || path.includes("..") || path.length > 1_000)
|
|
33
|
+
throw new Error("Evaluator resource path is outside the fixed origin contract.");
|
|
34
|
+
const url = new URL(path, origin);
|
|
35
|
+
if (url.origin !== origin)
|
|
36
|
+
throw new Error("Evaluator resource path changed the fixed origin.");
|
|
37
|
+
const response = await requestFetch(url, { method: "GET", headers: { accept: "application/json", authorization: `Bearer ${credential}` }, redirect: "error", signal });
|
|
38
|
+
if (!response.ok)
|
|
39
|
+
throw new Error(`Read-only evaluator returned HTTP ${response.status}.`);
|
|
40
|
+
const contentLength = Number(response.headers.get("content-length") ?? 0);
|
|
41
|
+
if (contentLength > 64 * 1024)
|
|
42
|
+
throw new Error("Read-only evaluator response exceeded 64 KiB.");
|
|
43
|
+
const bytes = Buffer.from(await response.arrayBuffer());
|
|
44
|
+
if (bytes.length > 64 * 1024)
|
|
45
|
+
throw new Error("Read-only evaluator response exceeded 64 KiB.");
|
|
46
|
+
const parsed = JSON.parse(bytes.toString("utf8"));
|
|
47
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
48
|
+
throw new Error("Read-only evaluator response must be a JSON object.");
|
|
49
|
+
return parsed;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function evaluator(template, options, observe, evaluatorIdentity) {
|
|
53
|
+
return Object.freeze({
|
|
54
|
+
template,
|
|
55
|
+
async evaluate(request) {
|
|
56
|
+
const resourceId = identifier(request.resourceId, "resourceId");
|
|
57
|
+
const criterionId = identifier(request.criterionId, "criterionId");
|
|
58
|
+
const expected = safeFields(request.expected, "expected");
|
|
59
|
+
const credential = await options.resolveCredential(options.credentialHandle);
|
|
60
|
+
if (typeof credential !== "string" || credential.length < 1 || credential.length > 8_192)
|
|
61
|
+
throw new Error("Read-only evaluator credential was unavailable.");
|
|
62
|
+
const timeoutMs = boundedTimeout(options.timeoutMs);
|
|
63
|
+
const raw = await observe({ ...request, resourceId, criterionId, expected }, credential, AbortSignal.timeout(timeoutMs));
|
|
64
|
+
const fields = safeFields(options.select(raw), "selected observation");
|
|
65
|
+
const result = Object.entries(expected).every(([key, value]) => Object.is(fields[key], value)) ? "SATISFIED" : "NOT_SATISFIED";
|
|
66
|
+
const observedAt = (options.now ?? (() => new Date()))().toISOString();
|
|
67
|
+
return {
|
|
68
|
+
schemaVersion: PRODUCTION_EVALUATOR_OBSERVATION_VERSION, template, provider: identifier(options.provider, "provider"), environment: options.environment,
|
|
69
|
+
criterion: { id: criterionId, expectedDigestSha256: sha256(canonicalJson(expected)) },
|
|
70
|
+
scope: { resourceIdSha256: sha256(resourceId), credentialHandleSha256: sha256(options.credentialHandle) },
|
|
71
|
+
result, observation: { fields, digestSha256: sha256(canonicalJson(fields)), observedAt },
|
|
72
|
+
...(evaluatorIdentity ? { evaluatorIdentity } : {}),
|
|
73
|
+
limitations: [
|
|
74
|
+
"This result proves one bounded read-only observation and does not authorize a write or generalize to future executions.",
|
|
75
|
+
"Credentials and raw provider payloads remain in the customer environment; only allowlisted scalar fields and digests are returned.",
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function validateCommon(options) {
|
|
82
|
+
identifier(options.provider, "provider");
|
|
83
|
+
identifier(options.credentialHandle, "credentialHandle");
|
|
84
|
+
if (!["sandbox", "staging", "production"].includes(options.environment))
|
|
85
|
+
throw new Error("environment is invalid.");
|
|
86
|
+
boundedTimeout(options.timeoutMs);
|
|
87
|
+
}
|
|
88
|
+
function safeOrigin(value) {
|
|
89
|
+
let url;
|
|
90
|
+
try {
|
|
91
|
+
url = new URL(value);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
throw new Error("Evaluator origin is invalid.");
|
|
95
|
+
}
|
|
96
|
+
const literalLoopback = (url.hostname === "127.0.0.1" || url.hostname === "[::1]") && isIP(url.hostname.replace(/^\[|\]$/g, ""));
|
|
97
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && literalLoopback))
|
|
98
|
+
throw new Error("Remote evaluator origins must use HTTPS; local development must use a literal loopback address.");
|
|
99
|
+
if (url.username || url.password || url.pathname !== "/" || url.search || url.hash)
|
|
100
|
+
throw new Error("Evaluator origin must contain only scheme, host, and port.");
|
|
101
|
+
return url.origin;
|
|
102
|
+
}
|
|
103
|
+
function safeFields(value, field) {
|
|
104
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
105
|
+
throw new Error(`${field} must be an object.`);
|
|
106
|
+
const entries = Object.entries(value);
|
|
107
|
+
if (entries.length > 32)
|
|
108
|
+
throw new Error(`${field} contains too many fields.`);
|
|
109
|
+
const result = {};
|
|
110
|
+
for (const [key, item] of entries.sort(([left], [right]) => left.localeCompare(right))) {
|
|
111
|
+
if (!/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(key) || /(secret|token|credential|password|authorization|cookie|email|phone|name|address|payload|body|text|prompt)/i.test(key))
|
|
112
|
+
throw new Error(`${field} contains an unsafe field.`);
|
|
113
|
+
if (item !== null && typeof item !== "string" && typeof item !== "number" && typeof item !== "boolean")
|
|
114
|
+
throw new Error(`${field}.${key} must be a scalar.`);
|
|
115
|
+
if (typeof item === "string" && item.length > 500 || typeof item === "number" && !Number.isFinite(item))
|
|
116
|
+
throw new Error(`${field}.${key} exceeds the bounded contract.`);
|
|
117
|
+
result[key] = item;
|
|
118
|
+
}
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
function componentIdentity(value) {
|
|
122
|
+
identifier(value.id, "observerIdentity.id");
|
|
123
|
+
identifier(value.version, "observerIdentity.version");
|
|
124
|
+
if (!/^[a-f0-9]{64}$/.test(value.digestSha256))
|
|
125
|
+
throw new Error("observerIdentity.digestSha256 is invalid.");
|
|
126
|
+
}
|
|
127
|
+
function identifier(value, field) { if (typeof value !== "string" || !value.trim() || value.length > 200 || !/^[A-Za-z0-9][A-Za-z0-9._:/@-]*$/.test(value))
|
|
128
|
+
throw new Error(`${field} is invalid.`); return value; }
|
|
129
|
+
function boundedTimeout(value = 5_000) { if (!Number.isSafeInteger(value) || value < 100 || value > 10_000)
|
|
130
|
+
throw new Error("Evaluator timeout must be from 100 to 10000 ms."); return value; }
|
|
131
|
+
function sha256(value) { return createHash("sha256").update(value).digest("hex"); }
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { SourceSigner } from "./trust-types.js";
|
|
2
|
+
export declare const SIGNED_CHANGE_MANIFEST_SCHEMA_VERSION: "witnora.signed_change_manifest.v0.1";
|
|
3
|
+
export interface ChangeManifestComponentIdentity {
|
|
4
|
+
id: string;
|
|
5
|
+
version: string;
|
|
6
|
+
digestSha256: string;
|
|
7
|
+
}
|
|
8
|
+
export interface SignedChangeManifestPayload {
|
|
9
|
+
schemaVersion: typeof SIGNED_CHANGE_MANIFEST_SCHEMA_VERSION;
|
|
10
|
+
manifestId: string;
|
|
11
|
+
projectId: string;
|
|
12
|
+
agentId: string;
|
|
13
|
+
agentVersion: string;
|
|
14
|
+
environment: "sandbox" | "staging" | "production";
|
|
15
|
+
observedAt: string;
|
|
16
|
+
modelDigest?: string;
|
|
17
|
+
promptWorkflowDigest?: string;
|
|
18
|
+
toolManifestDigest?: string;
|
|
19
|
+
policyRevision?: string;
|
|
20
|
+
evaluatorIdentity?: ChangeManifestComponentIdentity;
|
|
21
|
+
adapterIdentity?: ChangeManifestComponentIdentity;
|
|
22
|
+
previousManifestDigest?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface SignedChangeManifestEnvelope {
|
|
25
|
+
payload: SignedChangeManifestPayload;
|
|
26
|
+
signature: {
|
|
27
|
+
algorithm: "Ed25519";
|
|
28
|
+
keyId: string;
|
|
29
|
+
signature: string;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export declare function createSignedChangeManifestEnvelope(payload: SignedChangeManifestPayload, signer: SourceSigner): SignedChangeManifestEnvelope;
|
|
33
|
+
export declare function uploadSignedChangeManifest(options: {
|
|
34
|
+
baseUrl: string;
|
|
35
|
+
projectId: string;
|
|
36
|
+
apiKey: string;
|
|
37
|
+
envelope: SignedChangeManifestEnvelope;
|
|
38
|
+
fetch?: typeof fetch;
|
|
39
|
+
}): Promise<unknown>;
|
|
40
|
+
//# sourceMappingURL=signed-change-manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signed-change-manifest.d.ts","sourceRoot":"","sources":["../../../../onegent-runtime/src/signed-change-manifest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,eAAO,MAAM,qCAAqC,EAAG,qCAA8C,CAAC;AACpG,MAAM,WAAW,+BAA+B;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE;AACtG,MAAM,WAAW,2BAA2B;IAC1C,aAAa,EAAE,OAAO,qCAAqC,CAAC;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC;IAClD,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,+BAA+B,CAAC;IACpD,eAAe,CAAC,EAAE,+BAA+B,CAAC;IAClD,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AACD,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,2BAA2B,CAAC;IACrC,SAAS,EAAE;QAAE,SAAS,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CACvE;AAED,wBAAgB,kCAAkC,CAAC,OAAO,EAAE,2BAA2B,EAAE,MAAM,EAAE,YAAY,GAAG,4BAA4B,CAM3I;AAED,wBAAsB,0BAA0B,CAAC,OAAO,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,4BAA4B,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAQhM"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createPrivateKey, sign } from "node:crypto";
|
|
2
|
+
import { canonicalJson } from "./trust-crypto.js";
|
|
3
|
+
export const SIGNED_CHANGE_MANIFEST_SCHEMA_VERSION = "witnora.signed_change_manifest.v0.1";
|
|
4
|
+
export function createSignedChangeManifestEnvelope(payload, signer) {
|
|
5
|
+
if (payload.schemaVersion !== SIGNED_CHANGE_MANIFEST_SCHEMA_VERSION)
|
|
6
|
+
throw new Error("Signed Change Manifest schemaVersion is unsupported.");
|
|
7
|
+
return {
|
|
8
|
+
payload: structuredClone(payload),
|
|
9
|
+
signature: { algorithm: "Ed25519", keyId: signer.keyId, signature: sign(null, Buffer.from(canonicalJson(payload)), createPrivateKey(signer.privateKeyPem)).toString("base64url") },
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export async function uploadSignedChangeManifest(options) {
|
|
13
|
+
const response = await (options.fetch ?? fetch)(`${options.baseUrl.replace(/\/$/, "")}/v1/projects/${encodeURIComponent(options.projectId)}/change-manifests`, {
|
|
14
|
+
method: "POST", headers: { "content-type": "application/json", authorization: `Bearer ${options.apiKey}` }, body: JSON.stringify(options.envelope), redirect: "error", signal: AbortSignal.timeout(10_000),
|
|
15
|
+
});
|
|
16
|
+
const text = await response.text();
|
|
17
|
+
if (Buffer.byteLength(text) > 256 * 1024)
|
|
18
|
+
throw new Error("Witnora Change Manifest response exceeded 256 KiB.");
|
|
19
|
+
if (!response.ok)
|
|
20
|
+
throw new Error(`Witnora Change Manifest upload returned HTTP ${response.status}.`);
|
|
21
|
+
return JSON.parse(text);
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "witnora",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Independent assurance for covered agent action paths across models and frameworks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -44,6 +44,14 @@
|
|
|
44
44
|
"types": "./dist/vendor/onegent-runtime/business-task-evaluator.d.ts",
|
|
45
45
|
"import": "./dist/vendor/onegent-runtime/business-task-evaluator.js"
|
|
46
46
|
},
|
|
47
|
+
"./production-evaluator-kit": {
|
|
48
|
+
"types": "./dist/vendor/onegent-runtime/production-evaluator-kit.d.ts",
|
|
49
|
+
"import": "./dist/vendor/onegent-runtime/production-evaluator-kit.js"
|
|
50
|
+
},
|
|
51
|
+
"./change-manifest": {
|
|
52
|
+
"types": "./dist/vendor/onegent-runtime/signed-change-manifest.d.ts",
|
|
53
|
+
"import": "./dist/vendor/onegent-runtime/signed-change-manifest.js"
|
|
54
|
+
},
|
|
47
55
|
"./deployment-enforcement": {
|
|
48
56
|
"types": "./dist/internal/control-client/deployment-enforcement.d.ts",
|
|
49
57
|
"import": "./dist/internal/control-client/deployment-enforcement.js"
|