witnora 0.20.14 → 0.20.16

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.
@@ -68,7 +68,8 @@ export function resolveOnboardServer(options) {
68
68
  const server = env.WITNORA_BASE_URL ?? env.AGENTCERT_BASE_URL;
69
69
  const projectId = env.WITNORA_BASE_URL !== undefined ? env.WITNORA_PROJECT_ID : env.AGENTCERT_PROJECT_ID;
70
70
  if (server && projectId && projectId !== options.projectId) {
71
- throw new Error(`Onboarding project "${options.projectId}" differs from environment project "${projectId}". Pass --server <url> explicitly to choose the intended server; no authorization request was sent.`);
71
+ const projectVariable = env.WITNORA_BASE_URL !== undefined ? "WITNORA_PROJECT_ID" : "AGENTCERT_PROJECT_ID";
72
+ throw new Error(`Onboarding project "${options.projectId}" differs from environment project "${projectId}". Update or unset ${projectVariable}, or pass --server <url> explicitly to choose the intended server; no authorization request was sent.`);
72
73
  }
73
74
  return normalizeServer(server ?? DEFAULT_WITNORA_SERVER);
74
75
  }
@@ -89,7 +90,8 @@ function validateConnection(input) {
89
90
  throw new Error("Witnora project ID is required.");
90
91
  if (!apiKey.startsWith("ac_live_"))
91
92
  throw new Error("Witnora API key must start with ac_live_.");
92
- return { server: normalizeServer(input.server), projectId, apiKey };
93
+ const approvedSetupPlanId = input.approvedSetupPlanId?.trim();
94
+ return { server: normalizeServer(input.server), projectId, apiKey, ...(approvedSetupPlanId ? { approvedSetupPlanId } : {}) };
93
95
  }
94
96
  function normalizeServer(value) {
95
97
  let url;
@@ -25,6 +25,7 @@ export async function authorizeProjectConnection(options) {
25
25
  server,
26
26
  projectId: token.projectId,
27
27
  apiKey: token.apiKey,
28
+ approvedSetupPlanId: token.approvedSetupPlanId,
28
29
  }, { configHome: options.configHome });
29
30
  return { ...token, server, credentialsPath };
30
31
  }
package/dist/onboard.js CHANGED
@@ -48,18 +48,19 @@ export async function runOnboard(options) {
48
48
  configHome: options.configHome,
49
49
  });
50
50
  if (reusableConnection)
51
- output("Reusing the previously approved project-scoped setup connection; no new browser approval is required.\n");
51
+ output("Reusing this Agent's previously approved setup connection; verifying its exact Setup Plan.\n");
52
52
  const credentialsPath = token.credentialsPath;
53
53
  await verifyControlPlaneConnection({ baseUrl: server, projectId: token.projectId, apiKey: token.apiKey, fetch: requestFetch });
54
- const planSnapshot = await jsonRequest(requestFetch, `${server}/v1/projects/${encodeURIComponent(token.projectId)}/setup-plans`, {
54
+ const planQuery = token.approvedSetupPlanId ? `?setupPlanId=${encodeURIComponent(token.approvedSetupPlanId)}` : "";
55
+ const planSnapshot = await jsonRequest(requestFetch, `${server}/v1/projects/${encodeURIComponent(token.projectId)}/setup-plans${planQuery}`, {
55
56
  method: "GET", headers: { authorization: `Bearer ${token.apiKey}` },
56
57
  });
57
58
  const setupPlan = planSnapshot.plan;
58
- if (!setupPlan || !setupPlan.authorizedOperations.some((item) => item.kind === "authorize_install")) {
59
+ if (!setupPlan || (token.approvedSetupPlanId && setupPlan.id !== token.approvedSetupPlanId) || !setupPlan.authorizedOperations.some((item) => item.kind === "authorize_install")) {
59
60
  throw new Error("Confirm the Setup Plan and authorize installation in the Witnora Workspace before running onboard.");
60
61
  }
61
62
  let localRuntime = await discoverRuntimeReferences({
62
- repository: repositoryPath, configHome: options.configHome, projectId: token.projectId, server, env: options.env ?? process.env,
63
+ repository: repositoryPath, configHome: options.configHome, projectId: token.projectId, setupPlanId: setupPlan.id, server, env: options.env ?? process.env,
63
64
  });
64
65
  let runtimeLimitation = localRuntime.limitation;
65
66
  let runtimeBootstrapRequired = !localRuntime.references;
@@ -205,7 +206,7 @@ export async function runOnboard(options) {
205
206
  else {
206
207
  const binding = await inspectGatewayBinding(gatewayState.directory, token.projectId, server);
207
208
  if (binding.matches) {
208
- await saveConnection(binding.connectionName, { server, projectId: token.projectId, apiKey: token.apiKey }, { configHome: options.configHome });
209
+ await saveConnection(binding.connectionName, { server, projectId: token.projectId, apiKey: token.apiKey, approvedSetupPlanId: setupPlan.id }, { configHome: options.configHome });
209
210
  if (localRuntime.references) {
210
211
  try {
211
212
  runtimeUpgrade = await prepareRuntime(() => upgradeCustomerGatewayRuntime({ repository: repositoryPath, authorization: token, runtimeReferences: localRuntime.references, agentIdentity, configHome: options.configHome, fetch: requestFetch }));
@@ -3,7 +3,7 @@ import { chmod, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises"
3
3
  import { dirname, join } from "node:path";
4
4
  import { fileURLToPath, pathToFileURL } from "node:url";
5
5
  import { credentialsPath } from "./credentials.js";
6
- import { saveRuntimeReferenceManifest } from "./runtime-sandbox-kit.js";
6
+ import { runtimeReferenceManifestPath, saveRuntimeReferenceManifest } from "./runtime-sandbox-kit.js";
7
7
  const SCHEMA_VERSION = "witnora.runtime_bootstrap.v0.1";
8
8
  const ENVELOPE_ALGORITHM = "X25519-HKDF-SHA256-A256GCM";
9
9
  const PROBE_SCOPES = ["outcomes:verify"];
@@ -85,6 +85,7 @@ export async function bootstrapLocalRuntime(input) {
85
85
  await acknowledge(requestFetch, endpoint, input.apiKey, issued.bootstrapId, issued.envelope.digestSha256);
86
86
  const manifestPath = join(dirname(credentialsPath({ configHome: input.configHome })), "runtime-references.json");
87
87
  await saveRuntimeReferenceManifest(manifestPath, input.projectId, server, references);
88
+ await saveRuntimeReferenceManifest(runtimeReferenceManifestPath({ ...input, server, setupPlanId: input.planId }), input.projectId, server, references);
88
89
  await rm(attemptPath, { force: true });
89
90
  return { references, bootstrapId: issued.bootstrapId };
90
91
  }
@@ -16,15 +16,26 @@ export async function discoverRuntimeReferences(input) {
16
16
  runtimeKeyId: input.env.WITNORA_RUNTIME_KEY_ID?.trim(),
17
17
  runtimeSigningKeyHandle: input.env.WITNORA_RUNTIME_SIGNING_KEY_HANDLE?.trim(),
18
18
  };
19
- const manifestPath = join(dirname(credentialsPath({ configHome: input.configHome })), "runtime-references.json");
20
- const manifest = await optionalJson(manifestPath);
19
+ const manifestPath = runtimeReferenceManifestPath(input);
20
+ const legacyManifestPath = join(dirname(credentialsPath({ configHome: input.configHome })), "runtime-references.json");
21
+ const gateway = input.setupPlanId ? await optionalJson(join(input.repository, ".witnora", "gateway", "gateway.json")) : undefined;
22
+ const worker = object(gateway?.runtimeWorker);
23
+ const gatewayReferences = gateway?.projectId === input.projectId && gateway.server === input.server && worker.runtimeSetupPlanId === input.setupPlanId
24
+ ? completeReferences({ ...worker, setupPlanId: worker.runtimeSetupPlanId, bootstrapId: worker.runtimeBootstrapId,
25
+ adapterDigestSha256: worker.adapterModuleSha256, probeDigestSha256: worker.probeModuleSha256, fixtureContractDigestSha256: worker.fixtureContractSha256 })
26
+ : undefined;
27
+ const manifest = await optionalJson(manifestPath) ?? (gatewayReferences
28
+ ? { schemaVersion: "witnora.runtime_references.v0.1", projectId: input.projectId, server: input.server, references: gatewayReferences }
29
+ : await optionalJson(legacyManifestPath));
21
30
  const manifestReferences = manifest?.schemaVersion === "witnora.runtime_references.v0.1" && manifest.projectId === input.projectId && manifest.server === input.server
22
31
  ? completeReferences(manifest.references)
23
32
  : undefined;
33
+ const matchingReferences = !input.setupPlanId || !manifestReferences?.probeApiKeyId || manifestReferences.setupPlanId === input.setupPlanId
34
+ ? manifestReferences : undefined;
24
35
  const environmentOverrides = Object.fromEntries(Object.entries(entries).filter(([, value]) => value));
25
- const configuredReferences = completeReferences({ ...manifestReferences, ...environmentOverrides });
36
+ const configuredReferences = completeReferences({ ...matchingReferences, ...environmentOverrides });
26
37
  if (configuredReferences) {
27
- if (Object.keys(environmentOverrides).length > 0)
38
+ if (input.setupPlanId || Object.keys(environmentOverrides).length > 0)
28
39
  await saveRuntimeReferenceManifest(manifestPath, input.projectId, input.server, configuredReferences);
29
40
  return { references: configuredReferences, manifestPath };
30
41
  }
@@ -48,6 +59,13 @@ export async function discoverRuntimeReferences(input) {
48
59
  ? `Local sandbox Runtime references are incomplete (${present.join(", ")} present). Existing Gateway setup remains RECORDED_ONLY.`
49
60
  : "No existing private Witnora Runtime reference manifest was found. Gateway setup remains RECORDED_ONLY until Hosted bootstrap can issue one-time Runtime references." };
50
61
  }
62
+ export function runtimeReferenceManifestPath(input) {
63
+ const root = dirname(credentialsPath({ configHome: input.configHome }));
64
+ if (!input.setupPlanId)
65
+ return join(root, "runtime-references.json");
66
+ const bindingId = createHash("sha256").update(JSON.stringify([normalizeServer(input.server), input.projectId, input.setupPlanId])).digest("hex");
67
+ return join(root, "runtime-bootstrap", bindingId, "runtime-references.json");
68
+ }
51
69
  function completeReferences(value) {
52
70
  const mandateId = text(value.mandateId);
53
71
  const runtimeIdentityId = text(value.runtimeIdentityId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "witnora",
3
- "version": "0.20.14",
3
+ "version": "0.20.16",
4
4
  "description": "Independent assurance for covered agent action paths across models and frameworks.",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",