agentcert 0.2.7 → 0.3.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/README.md +25 -0
- package/dist/cli.js +8 -0
- package/dist/command-help.js +2 -0
- package/dist/index.js +1 -0
- package/dist/sandbox.js +258 -0
- package/dist/vendor/onegent-runtime/mock-procurement.d.ts +6 -0
- package/dist/vendor/onegent-runtime/mock-procurement.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/mock-procurement.js +33 -0
- package/dist/vendor/onegent-runtime/policies.d.ts +6 -0
- package/dist/vendor/onegent-runtime/policies.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/policies.js +109 -0
- package/dist/vendor/onegent-runtime/risk.d.ts +3 -0
- package/dist/vendor/onegent-runtime/risk.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/risk.js +54 -0
- package/dist/vendor/onegent-runtime/sandbox-adapter-kit.d.ts +45 -0
- package/dist/vendor/onegent-runtime/sandbox-adapter-kit.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/sandbox-adapter-kit.js +148 -0
- package/dist/vendor/onegent-runtime/sandbox-harness.d.ts +167 -0
- package/dist/vendor/onegent-runtime/sandbox-harness.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/sandbox-harness.js +729 -0
- package/dist/vendor/onegent-runtime/sandbox-hosted.d.ts +76 -0
- package/dist/vendor/onegent-runtime/sandbox-hosted.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/sandbox-hosted.js +129 -0
- package/dist/vendor/onegent-runtime/sdk.d.ts +29 -0
- package/dist/vendor/onegent-runtime/sdk.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/sdk.js +140 -0
- package/dist/vendor/onegent-runtime/service.d.ts +27 -0
- package/dist/vendor/onegent-runtime/service.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/service.js +421 -0
- package/dist/vendor/onegent-runtime/store.d.ts +16 -0
- package/dist/vendor/onegent-runtime/store.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/store.js +29 -0
- package/dist/vendor/onegent-runtime/types.d.ts +284 -0
- package/dist/vendor/onegent-runtime/types.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/types.js +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -57,6 +57,31 @@ or mismatched artifacts remain observable as `partial` or `rejected`.
|
|
|
57
57
|
Project API keys can create runs, record events, and upload evidence, but
|
|
58
58
|
cannot approve their own runtime actions.
|
|
59
59
|
|
|
60
|
+
## Sandbox onboarding
|
|
61
|
+
|
|
62
|
+
Create and certify a synthetic SandboxSystem adapter with the same public CLI:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx agentcert sandbox init
|
|
66
|
+
npx agentcert sandbox certify --adapter ./agentcert.sandbox.mjs
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The first command writes one dependency-free JavaScript file. The second runs
|
|
70
|
+
the bundled deterministic adapter contract and writes
|
|
71
|
+
`.agentcert/sandbox/sandbox-adapter-conformance.json`. No `@agentcert` scoped
|
|
72
|
+
package is required.
|
|
73
|
+
|
|
74
|
+
After `agentcert connect`, certify and upload in one command:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npx agentcert sandbox push --adapter ./agentcert.sandbox.mjs
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Passing and failing reports are both retained for review, while failed
|
|
81
|
+
certifications return a non-zero exit status. The generated template is
|
|
82
|
+
synthetic and network-denied; it must not contain production credentials or
|
|
83
|
+
connect to live systems.
|
|
84
|
+
|
|
60
85
|
Review/export helpers:
|
|
61
86
|
|
|
62
87
|
```bash
|
package/dist/cli.js
CHANGED
|
@@ -22,6 +22,7 @@ import { parseSchemaId, validateAgentCertSchema } from "./schema-validator.js";
|
|
|
22
22
|
import { applyRunOverrides, loadRunProfile, profileFromArtifactFlags, renderRunSummary, runAgentCertProfile, } from "./runner.js";
|
|
23
23
|
import { buildRobustnessLabSnapshot, readRobustnessLabConfig, renderRobustnessLabSummary, writeRobustnessLabSnapshot } from "./lab.js";
|
|
24
24
|
import { renderCommandHelp } from "./command-help.js";
|
|
25
|
+
import { runSandboxCommand } from "./sandbox.js";
|
|
25
26
|
process.on("uncaughtException", reportFatalError);
|
|
26
27
|
process.on("unhandledRejection", reportFatalError);
|
|
27
28
|
const command = process.argv[2] ?? "help";
|
|
@@ -120,6 +121,10 @@ Saved connections are reused by agentcert push and agentcert run --push.
|
|
|
120
121
|
process.stdout.write(`Credentials: ${path}\n`);
|
|
121
122
|
}
|
|
122
123
|
}
|
|
124
|
+
else if (command === "sandbox") {
|
|
125
|
+
const result = await runSandboxCommand(process.argv.slice(3));
|
|
126
|
+
process.exitCode = result.exitCode;
|
|
127
|
+
}
|
|
123
128
|
else if (command === "report") {
|
|
124
129
|
const config = await loadConfig(readFlag("--config"));
|
|
125
130
|
const subject = readFlag("--subject") ?? config?.subject.name ?? "agentcert-subject";
|
|
@@ -546,6 +551,9 @@ else {
|
|
|
546
551
|
process.stdout.write(`Usage:
|
|
547
552
|
agentcert init --subject my-browser-agent
|
|
548
553
|
agentcert connect --server https://agentcert-control-plane.onrender.com --project <project-id>
|
|
554
|
+
agentcert sandbox init
|
|
555
|
+
agentcert sandbox certify --adapter ./agentcert.sandbox.mjs
|
|
556
|
+
agentcert sandbox push --adapter ./agentcert.sandbox.mjs
|
|
549
557
|
agentcert init --out agentcert.config.json --tripwire-config tripwire.yml --force
|
|
550
558
|
agentcert init --subject my-browser-agent --github-action
|
|
551
559
|
agentcert report --mcpbench .mcpbench/latest/results.json --tripwire .tripwire/latest/tripwire-result.json --onegent .onegent/procurement/audit-packet.json --out .agentcert/latest --subject my-agent
|
package/dist/command-help.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export * from "./bundle.js";
|
|
|
2
2
|
export * from "./corpus.js";
|
|
3
3
|
export * from "./corpus-store.js";
|
|
4
4
|
export * from "./control-plane.js";
|
|
5
|
+
export * from "./sandbox.js";
|
|
5
6
|
export * from "./conformance.js";
|
|
6
7
|
export * from "./credentials.js";
|
|
7
8
|
export * from "./failure-review.js";
|
package/dist/sandbox.js
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { resolveConnection } from "./credentials.js";
|
|
5
|
+
const DEFAULT_ADAPTER_PATH = "agentcert.sandbox.mjs";
|
|
6
|
+
const DEFAULT_REPORT_PATH = ".agentcert/sandbox/sandbox-adapter-conformance.json";
|
|
7
|
+
export async function runSandboxCommand(args) {
|
|
8
|
+
const action = args[0] ?? "help";
|
|
9
|
+
if (action === "help" || args.includes("--help") || args.includes("-h")) {
|
|
10
|
+
process.stdout.write(renderSandboxHelp(action === "help" ? undefined : action));
|
|
11
|
+
return { exitCode: 0 };
|
|
12
|
+
}
|
|
13
|
+
if (action === "init")
|
|
14
|
+
return initializeSandboxAdapter(args.slice(1));
|
|
15
|
+
if (action === "certify")
|
|
16
|
+
return certifySandboxAdapter(args.slice(1));
|
|
17
|
+
if (action === "push")
|
|
18
|
+
return pushSandboxCertification(args.slice(1));
|
|
19
|
+
throw new Error(`Unknown sandbox command ${JSON.stringify(action)}. Run \`npx agentcert sandbox --help\`.`);
|
|
20
|
+
}
|
|
21
|
+
export async function initializeSandboxAdapter(args) {
|
|
22
|
+
const requestedPath = flag(args, "--adapter") ?? flag(args, "--out") ?? DEFAULT_ADAPTER_PATH;
|
|
23
|
+
const outPath = resolve(requestedPath);
|
|
24
|
+
await writeStarterFile(outPath, sandboxAdapterTemplate(), args.includes("--force"));
|
|
25
|
+
process.stdout.write(`Wrote ${outPath}\n\nNext:\n`);
|
|
26
|
+
process.stdout.write(` npx agentcert sandbox certify --adapter ${JSON.stringify(requestedPath)}\n`);
|
|
27
|
+
process.stdout.write("\nReplace the in-memory handlers with your sandbox implementation. Keep production credentials and live systems out of this adapter.\n");
|
|
28
|
+
return { exitCode: 0 };
|
|
29
|
+
}
|
|
30
|
+
export async function certifySandboxAdapter(args, runtimeOverride) {
|
|
31
|
+
const runtime = runtimeOverride ?? await loadSandboxRuntime();
|
|
32
|
+
const adapterPath = resolve(flag(args, "--adapter") ?? DEFAULT_ADAPTER_PATH);
|
|
33
|
+
const reportPath = resolve(flag(args, "--out") ?? DEFAULT_REPORT_PATH);
|
|
34
|
+
const system = await loadSandboxAdapter(adapterPath);
|
|
35
|
+
const report = await runtime.runSandboxAdapterConformanceSuite({
|
|
36
|
+
system,
|
|
37
|
+
implementation: flag(args, "--implementation"),
|
|
38
|
+
targetSystem: flag(args, "--target-system"),
|
|
39
|
+
});
|
|
40
|
+
await runtime.writeSandboxAdapterConformanceReport(report, reportPath);
|
|
41
|
+
renderCertificationResult(report, reportPath);
|
|
42
|
+
return { exitCode: report.verdict.passed ? 0 : 1, reportPath, report };
|
|
43
|
+
}
|
|
44
|
+
export async function pushSandboxCertification(args, runtimeOverride) {
|
|
45
|
+
const runtime = runtimeOverride ?? await loadSandboxRuntime();
|
|
46
|
+
const certified = await certifySandboxAdapter(args, runtime);
|
|
47
|
+
if (!certified.report || !certified.reportPath)
|
|
48
|
+
throw new Error("Sandbox certification did not produce a report.");
|
|
49
|
+
const connection = await resolveConnection({
|
|
50
|
+
name: flag(args, "--connection"),
|
|
51
|
+
server: flag(args, "--server"),
|
|
52
|
+
projectId: flag(args, "--project"),
|
|
53
|
+
apiKey: flag(args, "--api-key"),
|
|
54
|
+
});
|
|
55
|
+
const uploaded = await runtime.uploadSandboxCertificationReport(certified.report, {
|
|
56
|
+
baseUrl: connection.server,
|
|
57
|
+
projectId: connection.projectId,
|
|
58
|
+
apiKey: connection.apiKey,
|
|
59
|
+
externalId: flag(args, "--external-id"),
|
|
60
|
+
});
|
|
61
|
+
process.stdout.write(`Hosted sandbox run: ${String(uploaded.run.id ?? "created")}\n`);
|
|
62
|
+
process.stdout.write(`Hosted evidence: ${String(uploaded.evidence.id ?? "created")}\n`);
|
|
63
|
+
return certified;
|
|
64
|
+
}
|
|
65
|
+
export async function loadSandboxAdapter(adapterPath) {
|
|
66
|
+
let module;
|
|
67
|
+
try {
|
|
68
|
+
module = await import(pathToFileURL(adapterPath).href);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
72
|
+
throw new Error(`Could not load sandbox adapter ${adapterPath}: ${message}`);
|
|
73
|
+
}
|
|
74
|
+
const candidate = module.sandboxSystem ?? module.default ?? module.system;
|
|
75
|
+
if (!isSandboxSystem(candidate)) {
|
|
76
|
+
throw new Error(`Sandbox adapter ${adapterPath} must export \`sandboxSystem\`, \`system\`, or a default SandboxSystem object.`);
|
|
77
|
+
}
|
|
78
|
+
return candidate;
|
|
79
|
+
}
|
|
80
|
+
export function renderSandboxHelp(action) {
|
|
81
|
+
if (action === "init")
|
|
82
|
+
return `Usage:
|
|
83
|
+
agentcert sandbox init [--adapter agentcert.sandbox.mjs] [--force]
|
|
84
|
+
|
|
85
|
+
Writes one dependency-free synthetic SandboxSystem adapter template.
|
|
86
|
+
`;
|
|
87
|
+
if (action === "certify")
|
|
88
|
+
return `Usage:
|
|
89
|
+
agentcert sandbox certify --adapter ./my-sandbox-adapter.js [--out .agentcert/sandbox/report.json]
|
|
90
|
+
|
|
91
|
+
Runs the deterministic sandbox adapter conformance suite locally.
|
|
92
|
+
`;
|
|
93
|
+
if (action === "push")
|
|
94
|
+
return `Usage:
|
|
95
|
+
agentcert sandbox push --adapter ./my-sandbox-adapter.js
|
|
96
|
+
|
|
97
|
+
Runs certification, writes the local report, and uploads it through the saved AgentCert connection.
|
|
98
|
+
Use \`agentcert connect\` first, or pass --server, --project, and --api-key.
|
|
99
|
+
`;
|
|
100
|
+
return `Usage:
|
|
101
|
+
agentcert sandbox init [--adapter agentcert.sandbox.mjs]
|
|
102
|
+
agentcert sandbox certify --adapter ./my-sandbox-adapter.js
|
|
103
|
+
agentcert sandbox push --adapter ./my-sandbox-adapter.js
|
|
104
|
+
|
|
105
|
+
Commands:
|
|
106
|
+
init Write one dependency-free adapter template
|
|
107
|
+
certify Run deterministic local conformance checks
|
|
108
|
+
push Certify and upload the report to AgentCert Hosted
|
|
109
|
+
|
|
110
|
+
Common options:
|
|
111
|
+
--adapter <path> Adapter module (default: agentcert.sandbox.mjs)
|
|
112
|
+
--out <path> Local report path
|
|
113
|
+
--implementation <id> Stable adapter implementation name
|
|
114
|
+
--target-system <name> Target system exercised by the suite
|
|
115
|
+
`;
|
|
116
|
+
}
|
|
117
|
+
async function loadSandboxRuntime() {
|
|
118
|
+
const adapterKitUrl = new URL("./vendor/onegent-runtime/sandbox-adapter-kit.js", import.meta.url);
|
|
119
|
+
const hostedUrl = new URL("./vendor/onegent-runtime/sandbox-hosted.js", import.meta.url);
|
|
120
|
+
try {
|
|
121
|
+
const [adapterKit, hosted] = await Promise.all([import(adapterKitUrl.href), import(hostedUrl.href)]);
|
|
122
|
+
return { ...adapterKit, ...hosted };
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
const code = error && typeof error === "object" && "code" in error ? String(error.code) : undefined;
|
|
126
|
+
if (code === "ERR_MODULE_NOT_FOUND") {
|
|
127
|
+
throw new Error("AgentCert sandbox runtime is missing. Reinstall the agentcert package and retry.");
|
|
128
|
+
}
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function isSandboxSystem(value) {
|
|
133
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
134
|
+
return false;
|
|
135
|
+
const system = value;
|
|
136
|
+
const safety = system.safety;
|
|
137
|
+
return typeof system.name === "string"
|
|
138
|
+
&& safety?.mode === "sandbox"
|
|
139
|
+
&& safety.networkAccess === false
|
|
140
|
+
&& safety.syntheticDataOnly === true
|
|
141
|
+
&& Array.isArray(safety.allowedTargetSystems)
|
|
142
|
+
&& ["createTenant", "deleteTenant", "resetTenant", "seedTenant", "hasTenant", "snapshotTenant", "adapterForTenant"]
|
|
143
|
+
.every((method) => typeof system[method] === "function");
|
|
144
|
+
}
|
|
145
|
+
function flag(args, name) {
|
|
146
|
+
const index = args.indexOf(name);
|
|
147
|
+
return index >= 0 ? args[index + 1] : undefined;
|
|
148
|
+
}
|
|
149
|
+
async function writeStarterFile(path, content, force) {
|
|
150
|
+
await mkdir(dirname(path), { recursive: true });
|
|
151
|
+
try {
|
|
152
|
+
await writeFile(path, content, { flag: force ? "w" : "wx" });
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
if (error && typeof error === "object" && "code" in error && error.code === "EEXIST") {
|
|
156
|
+
throw new Error(`${path} already exists. Re-run with --force to overwrite it.`);
|
|
157
|
+
}
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function renderCertificationResult(report, reportPath) {
|
|
162
|
+
process.stdout.write(`${report.verdict.passed ? "PASS" : "FAIL"} ${report.verdict.score}/100 sandbox adapter conformance\n`);
|
|
163
|
+
for (const check of report.checks) {
|
|
164
|
+
process.stdout.write(`- ${check.status === "passed" ? "PASS" : "FAIL"} ${check.id}: ${check.message}\n`);
|
|
165
|
+
}
|
|
166
|
+
process.stdout.write(`Report: ${reportPath}\n`);
|
|
167
|
+
}
|
|
168
|
+
function sandboxAdapterTemplate() {
|
|
169
|
+
return `// Synthetic local state only. Do not import production credentials or call live systems here.
|
|
170
|
+
const tenants = new Map();
|
|
171
|
+
|
|
172
|
+
export const sandboxSystem = {
|
|
173
|
+
name: "my-sandbox-adapter",
|
|
174
|
+
safety: {
|
|
175
|
+
mode: "sandbox",
|
|
176
|
+
networkAccess: false,
|
|
177
|
+
syntheticDataOnly: true,
|
|
178
|
+
allowedTargetSystems: ["MySandboxSystem"],
|
|
179
|
+
},
|
|
180
|
+
createTenant(input) {
|
|
181
|
+
if (input.synthetic !== true) throw new Error("Synthetic tenants only.");
|
|
182
|
+
if (tenants.has(input.id)) throw new Error(\`Tenant \${input.id} already exists.\`);
|
|
183
|
+
const seed = syntheticSeed(input.seed ?? {});
|
|
184
|
+
tenants.set(input.id, { seed, state: structuredClone(seed) });
|
|
185
|
+
},
|
|
186
|
+
deleteTenant(tenantId) {
|
|
187
|
+
tenants.delete(tenantId);
|
|
188
|
+
},
|
|
189
|
+
resetTenant(tenantId) {
|
|
190
|
+
const tenant = requiredTenant(tenantId);
|
|
191
|
+
tenant.state = structuredClone(tenant.seed);
|
|
192
|
+
},
|
|
193
|
+
seedTenant(tenantId, seed) {
|
|
194
|
+
const tenant = requiredTenant(tenantId);
|
|
195
|
+
tenant.seed = syntheticSeed(seed);
|
|
196
|
+
tenant.state = structuredClone(seed);
|
|
197
|
+
},
|
|
198
|
+
hasTenant(tenantId) {
|
|
199
|
+
return tenants.has(tenantId);
|
|
200
|
+
},
|
|
201
|
+
snapshotTenant(tenantId) {
|
|
202
|
+
return structuredClone(requiredTenant(tenantId).state);
|
|
203
|
+
},
|
|
204
|
+
adapterForTenant(tenantId) {
|
|
205
|
+
requiredTenant(tenantId);
|
|
206
|
+
return {
|
|
207
|
+
name: \`my-sandbox-adapter:\${tenantId}\`,
|
|
208
|
+
safety: { mode: "sandbox", networkAccess: false, allowedTargetSystems: ["MySandboxSystem"] },
|
|
209
|
+
execute(action) {
|
|
210
|
+
const tenant = requiredTenant(tenantId);
|
|
211
|
+
const previousState = structuredClone(tenant.state[action.businessObjectId] ?? action.beforeState);
|
|
212
|
+
const observedState = structuredClone(action.proposedAfterState);
|
|
213
|
+
tenant.state[action.businessObjectId] = observedState;
|
|
214
|
+
return { method: "SYNTHETIC_SANDBOX", targetSystem: action.targetSystem, previousState, observedState };
|
|
215
|
+
},
|
|
216
|
+
rollback(action, execution) {
|
|
217
|
+
const restored = structuredClone(execution.previousState ?? action.beforeState);
|
|
218
|
+
requiredTenant(tenantId).state[action.businessObjectId] = restored;
|
|
219
|
+
return { success: true, observedState: restored };
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
export default sandboxSystem;
|
|
226
|
+
|
|
227
|
+
function requiredTenant(tenantId) {
|
|
228
|
+
const tenant = tenants.get(tenantId);
|
|
229
|
+
if (!tenant) throw new Error(\`Tenant \${tenantId} does not exist.\`);
|
|
230
|
+
return tenant;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function syntheticSeed(value) {
|
|
234
|
+
assertSynthetic(value, "seed", new Set());
|
|
235
|
+
return structuredClone(value);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function assertSynthetic(value, path, seen) {
|
|
239
|
+
if (value === null || ["boolean", "number"].includes(typeof value)) return;
|
|
240
|
+
if (typeof value === "string") {
|
|
241
|
+
if (/^(?:sk-(?:proj-)?|npm_|gh[pousr]_)[A-Za-z0-9_-]{16,}$/.test(value)) {
|
|
242
|
+
throw new Error(\`Credential-like value is not allowed at \${path}.\`);
|
|
243
|
+
}
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (typeof value !== "object") throw new Error(\`Synthetic data must be JSON-compatible at \${path}.\`);
|
|
247
|
+
if (seen.has(value)) throw new Error(\`Synthetic data cannot contain cycles at \${path}.\`);
|
|
248
|
+
seen.add(value);
|
|
249
|
+
for (const [key, item] of Object.entries(value)) {
|
|
250
|
+
if (/(?:password|passwd|secret|token|api[_-]?key|credential|authorization|cookie)/i.test(key)) {
|
|
251
|
+
throw new Error(\`Credential-like field \${path}.\${key} is not allowed.\`);
|
|
252
|
+
}
|
|
253
|
+
assertSynthetic(item, \`\${path}.\${key}\`, seen);
|
|
254
|
+
}
|
|
255
|
+
seen.delete(value);
|
|
256
|
+
}
|
|
257
|
+
`;
|
|
258
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ActionIntent, MockPurchaseOrder } from "./types.js";
|
|
2
|
+
export declare const PROCUREMENT_DEMO_PO_ID = "PO-DEMO-4850";
|
|
3
|
+
export declare function createProcurementDemoPurchaseOrder(): MockPurchaseOrder;
|
|
4
|
+
export declare function getPurchaseOrder(id: string): MockPurchaseOrder | undefined;
|
|
5
|
+
export declare function submitMockPurchaseOrder(action: ActionIntent): MockPurchaseOrder;
|
|
6
|
+
//# sourceMappingURL=mock-procurement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-procurement.d.ts","sourceRoot":"","sources":["../../../../onegent-runtime/src/mock-procurement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGlE,eAAO,MAAM,sBAAsB,iBAAiB,CAAC;AAErD,wBAAgB,kCAAkC,IAAI,iBAAiB,CActE;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAE1E;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,YAAY,GAAG,iBAAiB,CAc/E"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { nowIso, store } from "./store.js";
|
|
2
|
+
export const PROCUREMENT_DEMO_PO_ID = "PO-DEMO-4850";
|
|
3
|
+
export function createProcurementDemoPurchaseOrder() {
|
|
4
|
+
const purchaseOrder = {
|
|
5
|
+
id: PROCUREMENT_DEMO_PO_ID,
|
|
6
|
+
vendor: "Acme Industrial Supply",
|
|
7
|
+
amount: 4_850,
|
|
8
|
+
currency: "USD",
|
|
9
|
+
status: "DRAFT",
|
|
10
|
+
vendorApproved: true,
|
|
11
|
+
lineItem: "Replacement conveyor motor assembly",
|
|
12
|
+
lastUpdatedAt: nowIso(),
|
|
13
|
+
};
|
|
14
|
+
store.purchaseOrders.set(purchaseOrder.id, purchaseOrder);
|
|
15
|
+
return purchaseOrder;
|
|
16
|
+
}
|
|
17
|
+
export function getPurchaseOrder(id) {
|
|
18
|
+
return store.purchaseOrders.get(id);
|
|
19
|
+
}
|
|
20
|
+
export function submitMockPurchaseOrder(action) {
|
|
21
|
+
const purchaseOrder = store.purchaseOrders.get(action.businessObjectId);
|
|
22
|
+
if (!purchaseOrder) {
|
|
23
|
+
throw new Error(`Mock purchase order ${action.businessObjectId} was not found.`);
|
|
24
|
+
}
|
|
25
|
+
const updated = {
|
|
26
|
+
...purchaseOrder,
|
|
27
|
+
status: "SUBMITTED",
|
|
28
|
+
lastUpdatedAt: nowIso(),
|
|
29
|
+
actionIntentId: action.id,
|
|
30
|
+
};
|
|
31
|
+
store.purchaseOrders.set(updated.id, updated);
|
|
32
|
+
return updated;
|
|
33
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ActionIntent, PolicyEvaluation, PolicyRule, RiskAssessment } from "./types.js";
|
|
2
|
+
export declare const DEFAULT_POLICY_RULES: PolicyRule[];
|
|
3
|
+
export declare function evaluatePolicy(action: ActionIntent, risk: RiskAssessment, policyRules?: PolicyRule[]): PolicyEvaluation;
|
|
4
|
+
export declare function getPolicyRules(ids: string[], policyRules?: PolicyRule[]): PolicyRule[];
|
|
5
|
+
export declare function matchesRule(action: ActionIntent, rule: PolicyRule): boolean;
|
|
6
|
+
//# sourceMappingURL=policies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policies.d.ts","sourceRoot":"","sources":["../../../../onegent-runtime/src/policies.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAmB,gBAAgB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE9G,eAAO,MAAM,oBAAoB,EAAE,UAAU,EAmC5C,CAAC;AAEF,wBAAgB,cAAc,CAC5B,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,cAAc,EACpB,WAAW,GAAE,UAAU,EAAyB,GAC/C,gBAAgB,CA6ClB;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,WAAW,GAAE,UAAU,EAAyB,GAAG,UAAU,EAAE,CAG5G;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAQ3E"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
export const DEFAULT_POLICY_RULES = [
|
|
2
|
+
{
|
|
3
|
+
id: "po-over-1000-requires-approval",
|
|
4
|
+
name: "Purchase orders over $1,000 require approval",
|
|
5
|
+
description: "High-value purchase order submissions must be reviewed before mock execution.",
|
|
6
|
+
actionTypes: ["SUBMIT"],
|
|
7
|
+
effect: "REQUIRE_APPROVAL",
|
|
8
|
+
enabled: true,
|
|
9
|
+
conditions: [{ field: "amount", operator: "greaterThan", value: 1_000 }],
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
id: "payment-actions-require-approval",
|
|
13
|
+
name: "Payment actions require approval",
|
|
14
|
+
description: "The demo runtime never executes real payments and requires approval for mock payment actions.",
|
|
15
|
+
actionTypes: ["PAY"],
|
|
16
|
+
effect: "REQUIRE_APPROVAL",
|
|
17
|
+
enabled: true,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: "external-send-requires-approval",
|
|
21
|
+
name: "External send actions require approval",
|
|
22
|
+
description: "Outbound communications to non-demo recipients require approval.",
|
|
23
|
+
actionTypes: ["SEND"],
|
|
24
|
+
effect: "REQUIRE_APPROVAL",
|
|
25
|
+
enabled: true,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: "production-actions-blocked-in-demo",
|
|
29
|
+
name: "Production actions are blocked in demo mode",
|
|
30
|
+
description: "This package is local-only and will not perform production actions.",
|
|
31
|
+
actionTypes: ["SUBMIT", "PAY", "SEND", "UPDATE"],
|
|
32
|
+
effect: "BLOCK",
|
|
33
|
+
enabled: true,
|
|
34
|
+
conditions: [{ field: "environment", operator: "equals", value: "production" }],
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
export function evaluatePolicy(action, risk, policyRules = DEFAULT_POLICY_RULES) {
|
|
38
|
+
if (action.environment === "production") {
|
|
39
|
+
const productionBlock = policyRules.find((rule) => rule.id === "production-actions-blocked-in-demo") ??
|
|
40
|
+
DEFAULT_POLICY_RULES.find((rule) => rule.id === "production-actions-blocked-in-demo");
|
|
41
|
+
return {
|
|
42
|
+
effect: "BLOCK",
|
|
43
|
+
triggeredPolicies: productionBlock ? [productionBlock.id] : [],
|
|
44
|
+
reasons: [productionBlock?.description ?? "Production actions are blocked in this local demo runtime."],
|
|
45
|
+
requiresHumanApproval: false,
|
|
46
|
+
blocked: true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const triggeredRules = policyRules.filter((rule) => matchesRule(action, rule));
|
|
50
|
+
const blockRules = triggeredRules.filter((rule) => rule.effect === "BLOCK");
|
|
51
|
+
if (blockRules.length > 0) {
|
|
52
|
+
return {
|
|
53
|
+
effect: "BLOCK",
|
|
54
|
+
triggeredPolicies: blockRules.map((rule) => rule.id),
|
|
55
|
+
reasons: blockRules.map((rule) => rule.description),
|
|
56
|
+
requiresHumanApproval: false,
|
|
57
|
+
blocked: true,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const approvalRules = triggeredRules.filter((rule) => rule.effect === "REQUIRE_APPROVAL");
|
|
61
|
+
if (approvalRules.length > 0) {
|
|
62
|
+
return {
|
|
63
|
+
effect: "REQUIRE_APPROVAL",
|
|
64
|
+
triggeredPolicies: approvalRules.map((rule) => rule.id),
|
|
65
|
+
reasons: approvalRules.map((rule) => rule.description),
|
|
66
|
+
requiresHumanApproval: true,
|
|
67
|
+
blocked: false,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
effect: "ALLOW",
|
|
72
|
+
triggeredPolicies: triggeredRules.map((rule) => rule.id),
|
|
73
|
+
reasons: risk.reasons,
|
|
74
|
+
requiresHumanApproval: false,
|
|
75
|
+
blocked: false,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export function getPolicyRules(ids, policyRules = DEFAULT_POLICY_RULES) {
|
|
79
|
+
const idSet = new Set(ids);
|
|
80
|
+
return policyRules.filter((rule) => idSet.has(rule.id));
|
|
81
|
+
}
|
|
82
|
+
export function matchesRule(action, rule) {
|
|
83
|
+
if (!rule.enabled || !rule.actionTypes.includes(action.actionType)) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
if (!rule.conditions || rule.conditions.length === 0) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
return rule.conditions.every((condition) => matchesCondition(action, condition));
|
|
90
|
+
}
|
|
91
|
+
function matchesCondition(action, condition) {
|
|
92
|
+
const actual = action[condition.field];
|
|
93
|
+
switch (condition.operator) {
|
|
94
|
+
case "equals":
|
|
95
|
+
return actual === condition.value;
|
|
96
|
+
case "notEquals":
|
|
97
|
+
return actual !== condition.value;
|
|
98
|
+
case "greaterThan":
|
|
99
|
+
return typeof actual === "number" && typeof condition.value === "number" && actual > condition.value;
|
|
100
|
+
case "greaterThanOrEqual":
|
|
101
|
+
return typeof actual === "number" && typeof condition.value === "number" && actual >= condition.value;
|
|
102
|
+
case "lessThan":
|
|
103
|
+
return typeof actual === "number" && typeof condition.value === "number" && actual < condition.value;
|
|
104
|
+
case "lessThanOrEqual":
|
|
105
|
+
return typeof actual === "number" && typeof condition.value === "number" && actual <= condition.value;
|
|
106
|
+
case "includes":
|
|
107
|
+
return typeof actual === "string" && typeof condition.value === "string" && actual.includes(condition.value);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk.d.ts","sourceRoot":"","sources":["../../../../onegent-runtime/src/risk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAa,MAAM,YAAY,CAAC;AAK1E,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,cAAc,CAsD/D"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { nextId, nowIso } from "./store.js";
|
|
2
|
+
const PURCHASE_ORDER_APPROVAL_THRESHOLD = 1_000;
|
|
3
|
+
export function assessRisk(action) {
|
|
4
|
+
const reasons = [];
|
|
5
|
+
const triggeredPolicies = [];
|
|
6
|
+
let riskLevel = "LOW";
|
|
7
|
+
let riskScore = 20;
|
|
8
|
+
if (action.actionType === "PAY") {
|
|
9
|
+
riskLevel = "HIGH";
|
|
10
|
+
riskScore = 85;
|
|
11
|
+
reasons.push("Payment actions can move money and require human approval in the demo runtime.");
|
|
12
|
+
triggeredPolicies.push("payment-actions-require-approval");
|
|
13
|
+
}
|
|
14
|
+
if (action.actionType === "SEND" && action.recipient && !action.recipient.endsWith("@example.local")) {
|
|
15
|
+
riskLevel = maxRisk(riskLevel, "HIGH");
|
|
16
|
+
riskScore = Math.max(riskScore, 75);
|
|
17
|
+
reasons.push("External send actions can disclose business data and require human approval.");
|
|
18
|
+
triggeredPolicies.push("external-send-requires-approval");
|
|
19
|
+
}
|
|
20
|
+
if (action.actionType === "SUBMIT" && (action.amount ?? 0) > PURCHASE_ORDER_APPROVAL_THRESHOLD) {
|
|
21
|
+
riskLevel = maxRisk(riskLevel, "HIGH");
|
|
22
|
+
riskScore = Math.max(riskScore, 80);
|
|
23
|
+
reasons.push("Purchase orders over $1,000 require human approval.");
|
|
24
|
+
triggeredPolicies.push("po-over-1000-requires-approval");
|
|
25
|
+
}
|
|
26
|
+
if (action.actionType === "UPDATE" && action.fieldsChanged.length > 0) {
|
|
27
|
+
riskLevel = maxRisk(riskLevel, "MEDIUM");
|
|
28
|
+
riskScore = Math.max(riskScore, 45);
|
|
29
|
+
reasons.push("Update actions modify business records and require verification.");
|
|
30
|
+
}
|
|
31
|
+
if (action.environment === "production") {
|
|
32
|
+
riskLevel = maxRisk(riskLevel, "CRITICAL");
|
|
33
|
+
riskScore = Math.max(riskScore, 95);
|
|
34
|
+
reasons.push("Production actions are blocked in this local demo runtime.");
|
|
35
|
+
triggeredPolicies.push("production-actions-blocked-in-demo");
|
|
36
|
+
}
|
|
37
|
+
if (reasons.length === 0) {
|
|
38
|
+
reasons.push("No high-risk demo policy matched this action.");
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
id: nextId("risk"),
|
|
42
|
+
actionIntentId: action.id,
|
|
43
|
+
riskLevel,
|
|
44
|
+
riskScore,
|
|
45
|
+
reasons,
|
|
46
|
+
triggeredPolicies,
|
|
47
|
+
requiresHumanApproval: riskLevel === "HIGH" || riskLevel === "CRITICAL",
|
|
48
|
+
createdAt: nowIso(),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function maxRisk(left, right) {
|
|
52
|
+
const order = ["LOW", "MEDIUM", "HIGH", "CRITICAL"];
|
|
53
|
+
return order[Math.max(order.indexOf(left), order.indexOf(right))];
|
|
54
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type SandboxCertificationCheck, type SandboxCertificationReport, type SandboxSeed, type SandboxSystem, type SandboxTenantInput } from "./sandbox-harness.js";
|
|
2
|
+
import type { LocalActionAdapter } from "./types.js";
|
|
3
|
+
export declare const SANDBOX_ADAPTER_CONFORMANCE_SCHEMA_VERSION: "agentcert.sandbox_adapter_conformance.v0.2";
|
|
4
|
+
export interface SandboxSystemAdapterHandlers {
|
|
5
|
+
createTenant(input: SandboxTenantInput): void | Promise<void>;
|
|
6
|
+
deleteTenant(tenantId: string): void | Promise<void>;
|
|
7
|
+
resetTenant(tenantId: string): void | Promise<void>;
|
|
8
|
+
seedTenant(tenantId: string, seed: SandboxSeed): void | Promise<void>;
|
|
9
|
+
hasTenant(tenantId: string): boolean | Promise<boolean>;
|
|
10
|
+
snapshotTenant(tenantId: string): SandboxSeed | Promise<SandboxSeed>;
|
|
11
|
+
adapterForTenant(tenantId: string): LocalActionAdapter;
|
|
12
|
+
}
|
|
13
|
+
export interface SandboxSystemAdapterDefinition {
|
|
14
|
+
name: string;
|
|
15
|
+
allowedTargetSystems: string[];
|
|
16
|
+
handlers: SandboxSystemAdapterHandlers;
|
|
17
|
+
}
|
|
18
|
+
export interface SandboxAdapterConformanceReport {
|
|
19
|
+
schemaVersion: typeof SANDBOX_ADAPTER_CONFORMANCE_SCHEMA_VERSION;
|
|
20
|
+
kind: "agentcert.sandbox_adapter_conformance";
|
|
21
|
+
implementation: string;
|
|
22
|
+
generatedAt: string;
|
|
23
|
+
verdict: {
|
|
24
|
+
passed: boolean;
|
|
25
|
+
score: number;
|
|
26
|
+
};
|
|
27
|
+
summary: {
|
|
28
|
+
passed: number;
|
|
29
|
+
failed: number;
|
|
30
|
+
total: number;
|
|
31
|
+
};
|
|
32
|
+
checks: SandboxCertificationCheck[];
|
|
33
|
+
certification?: SandboxCertificationReport;
|
|
34
|
+
disclaimer: string;
|
|
35
|
+
}
|
|
36
|
+
export interface SandboxAdapterConformanceOptions {
|
|
37
|
+
system: SandboxSystem;
|
|
38
|
+
implementation?: string;
|
|
39
|
+
targetSystem?: string;
|
|
40
|
+
now?: () => Date;
|
|
41
|
+
}
|
|
42
|
+
export declare function createSandboxSystemAdapter(definition: SandboxSystemAdapterDefinition): SandboxSystem;
|
|
43
|
+
export declare function runSandboxAdapterConformanceSuite(options: SandboxAdapterConformanceOptions): Promise<SandboxAdapterConformanceReport>;
|
|
44
|
+
export declare function writeSandboxAdapterConformanceReport(report: SandboxAdapterConformanceReport, filePath: string): Promise<string>;
|
|
45
|
+
//# sourceMappingURL=sandbox-adapter-kit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-adapter-kit.d.ts","sourceRoot":"","sources":["../../../../onegent-runtime/src/sandbox-adapter-kit.ts"],"names":[],"mappings":"AAIA,OAAO,EAIL,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAC/B,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,eAAO,MAAM,0CAA0C,EAAG,4CAAqD,CAAC;AAEhH,MAAM,WAAW,4BAA4B;IAC3C,YAAY,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACrE,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAAC;CACxD;AAED,MAAM,WAAW,8BAA8B;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,QAAQ,EAAE,4BAA4B,CAAC;CACxC;AAED,MAAM,WAAW,+BAA+B;IAC9C,aAAa,EAAE,OAAO,0CAA0C,CAAC;IACjE,IAAI,EAAE,uCAAuC,CAAC;IAC9C,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,MAAM,EAAE,yBAAyB,EAAE,CAAC;IACpC,aAAa,CAAC,EAAE,0BAA0B,CAAC;IAC3C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gCAAgC;IAC/C,MAAM,EAAE,aAAa,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,8BAA8B,GAAG,aAAa,CA8BpG;AAED,wBAAsB,iCAAiC,CACrD,OAAO,EAAE,gCAAgC,GACxC,OAAO,CAAC,+BAA+B,CAAC,CAmF1C;AAED,wBAAsB,oCAAoC,CACxD,MAAM,EAAE,+BAA+B,EACvC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAMjB"}
|