witnora 0.10.2 → 0.10.3

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/README.md CHANGED
@@ -26,6 +26,13 @@ boundary, writes only missing configuration, and verifies the local evidence
26
26
  path. `.witnora/onboarding/receipt.json` is synthetic: it cannot create a run,
27
27
  evidence object, release decision, or `CURRENT` assurance.
28
28
 
29
+ After the connection self-test, Hosted shows one template-specific next step.
30
+ Place the generated boundary in one meaningful sandbox workflow and run it
31
+ normally. The generated local adapter reuses the saved restricted connection;
32
+ CI and production should use the same project-scoped values from a secret
33
+ manager. The first non-synthetic run completes onboarding, but remains
34
+ `reported` evidence and does not establish a release decision or `CURRENT`.
35
+
29
36
  Without an agent repository, run `npx witnora@latest try --template workflow`
30
37
  for an offline-only sample.
31
38
 
package/dist/onboard.js CHANGED
@@ -4,7 +4,7 @@ import { access, mkdir, readFile, readdir, writeFile } from "node:fs/promises";
4
4
  import { basename, dirname, join, resolve } from "node:path";
5
5
  import { DEFAULT_WITNORA_SERVER, saveConnection } from "./credentials.js";
6
6
  import { verifyControlPlaneConnection } from "./control-plane.js";
7
- import { parseAgentTemplate, starterAdapter, starterProfile, starterTripwireConfig } from "./onboarding-templates.js";
7
+ import { parseAgentTemplate, starterAdapter, starterInstructions, starterProfile, starterTripwireConfig } from "./onboarding-templates.js";
8
8
  import { writeTryEvidence } from "./try.js";
9
9
  export async function runOnboard(options) {
10
10
  const requestFetch = options.fetch ?? fetch;
@@ -47,6 +47,7 @@ export async function runOnboard(options) {
47
47
  output(`Project: ${token.projectId}\nTemplate: ${repository.template} (${repository.kind})\n`);
48
48
  output(`Credentials: ${credentialsPath}\nSelf-test receipt: ${receiptPath}\n`);
49
49
  output("The synthetic self-test verified the local evidence path. It did not create a run, evidence object, release decision, or CURRENT assurance.\n");
50
+ output(starterInstructions(repository.template, repository.name));
50
51
  return { projectId: token.projectId, connectionName: token.connectionName, credentialsPath, template: repository.template,
51
52
  repositoryKind: repository.kind, generatedFiles, receiptPath };
52
53
  }
@@ -33,10 +33,13 @@ export function starterAdapter(template, subject) {
33
33
  return `#!/usr/bin/env node
34
34
  import { randomBytes, randomUUID } from "node:crypto";
35
35
  import { readFile } from "node:fs/promises";
36
+ import { homedir } from "node:os";
37
+ import { join } from "node:path";
36
38
 
37
- const baseUrl = brandedRequired("BASE_URL").replace(/\\\/$/, "");
38
- const projectId = brandedRequired("PROJECT_ID");
39
- const apiKey = brandedRequired("API_KEY");
39
+ const connection = await resolveHostedConnection();
40
+ const baseUrl = connection.baseUrl.replace(/\\\/$/, "");
41
+ const projectId = connection.projectId;
42
+ const apiKey = connection.apiKey;
40
43
  const agentId = branded("AGENT_ID") ?? ${JSON.stringify(subject)};
41
44
  const agentName = branded("AGENT_NAME") ?? humanize(agentId);
42
45
  const agentVersion = await discoverAgentVersion();
@@ -65,17 +68,29 @@ if (!response.ok) {
65
68
  }
66
69
  process.stdout.write(\`Recorded ${eventType} for ${subject}.\\n\`);
67
70
 
68
- function brandedRequired(suffix) {
69
- const name = \`WITNORA_\${suffix}\`;
70
- const value = process.env[name] ?? process.env[\`AGENTCERT_\${suffix}\`];
71
- if (!value) throw new Error(\`\${name} is required. Connect the Witnora CLI or set the hosted project variables. Legacy AGENTCERT_* names remain supported.\`);
72
- return value;
73
- }
74
-
75
71
  function branded(suffix) {
76
72
  return process.env[\`WITNORA_\${suffix}\`] ?? process.env[\`AGENTCERT_\${suffix}\`];
77
73
  }
78
74
 
75
+ async function resolveHostedConnection() {
76
+ const environment = {
77
+ baseUrl: branded("BASE_URL"),
78
+ projectId: branded("PROJECT_ID"),
79
+ apiKey: branded("API_KEY"),
80
+ };
81
+ if (environment.baseUrl && environment.projectId && environment.apiKey) return environment;
82
+ const configHome = process.env.WITNORA_CONFIG_HOME ?? process.env.AGENTCERT_CONFIG_HOME ?? join(homedir(), ".witnora");
83
+ try {
84
+ const credentials = JSON.parse(await readFile(join(configHome, "credentials.json"), "utf8"));
85
+ const name = process.env.WITNORA_CONNECTION ?? credentials.defaultConnection;
86
+ const saved = credentials.connections?.[name];
87
+ if (saved?.server && saved?.projectId && saved?.apiKey) {
88
+ return { baseUrl: saved.server, projectId: saved.projectId, apiKey: saved.apiKey };
89
+ }
90
+ } catch {}
91
+ throw new Error("No Witnora connection is available. Run witnora onboard --project <project-id> locally, or set WITNORA_BASE_URL, WITNORA_PROJECT_ID, and WITNORA_API_KEY in the runtime secret manager.");
92
+ }
93
+
79
94
  function humanize(value) {
80
95
  const unscoped = value.includes("/") ? value.slice(value.lastIndexOf("/") + 1) : value;
81
96
  return unscoped.replace(/[-_.]+/g, " ").replace(/\\b\\w/g, (character) => character.toUpperCase()).trim();
@@ -117,19 +132,19 @@ export function starterInstructions(template, subject) {
117
132
  Next:
118
133
  1. Edit tripwire.yml so startUrl and agent.command/agent.args match your app and browser agent.
119
134
  2. Run in CI with Kakarottoooo/agentcert/actions/tripwire@v0, or re-run init with --github-action.
120
- 3. Run: npx witnora@latest run --tripwire .tripwire/latest/tripwire-result.json --subject ${JSON.stringify(subject)} --fail-on-verdict
135
+ 3. Run: npx witnora@latest run --tripwire .tripwire/latest/tripwire-result.json --subject ${JSON.stringify(subject)} --fail-on-verdict --push
121
136
  `;
122
137
  if (template === "mcp")
123
138
  return `
124
139
  Next:
125
140
  1. Run MCPBench and write its JSON result to .mcpbench/latest/results.json.
126
- 2. Run: npx witnora@latest run --mcpbench .mcpbench/latest/results.json --subject ${JSON.stringify(subject)} --fail-on-verdict
141
+ 2. Run: npx witnora@latest run --mcpbench .mcpbench/latest/results.json --subject ${JSON.stringify(subject)} --fail-on-verdict --push
127
142
  `;
128
143
  return `
129
144
  Next:
130
145
  1. Wrap the meaningful ${template} agent boundary with witnora.adapter.mjs or copy its envelope call into your framework hook.
131
- 2. Set WITNORA_BASE_URL, WITNORA_PROJECT_ID, and WITNORA_API_KEY in your secret manager. Legacy AGENTCERT_* names remain supported.
132
- 3. Run: node witnora.adapter.mjs
146
+ 2. Run one sandbox workflow normally. For a local boundary check, run: node witnora.adapter.mjs
147
+ 3. Local runs reuse the restricted connection saved by onboard. In CI or production, set WITNORA_BASE_URL, WITNORA_PROJECT_ID, and WITNORA_API_KEY in your secret manager.
133
148
  4. Generate and push a full evidence bundle when the workflow reaches a deterministic verification point.
134
149
  `;
135
150
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "witnora",
3
- "version": "0.10.2",
3
+ "version": "0.10.3",
4
4
  "description": "Independent assurance for covered agent action paths across models and frameworks.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",