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 +7 -0
- package/dist/onboard.js +2 -1
- package/dist/onboarding-templates.js +29 -14
- package/package.json +1 -1
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
|
|
38
|
-
const
|
|
39
|
-
const
|
|
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.
|
|
132
|
-
3.
|
|
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
|
}
|