@frockbot/plugin-audit 0.3.6 → 0.3.8
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/package.json +6 -6
- package/src/classify.test.ts +7 -4
- package/src/classify.ts +19 -4
- package/src/client/AuditSection.vue +2 -0
- package/src/shared.ts +11 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frockbot/plugin-audit",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
"typecheck": "vue-tsc --noEmit -p tsconfig.json"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@frockbot/client-core": "0.3.
|
|
29
|
-
"@frockbot/client-ui": "0.3.
|
|
30
|
-
"@frockbot/kernel-contracts": "0.3.
|
|
31
|
-
"@frockbot/plugin-shell": "0.3.
|
|
32
|
-
"@frockbot/secret-shapes": "0.3.
|
|
28
|
+
"@frockbot/client-core": "0.3.8",
|
|
29
|
+
"@frockbot/client-ui": "0.3.8",
|
|
30
|
+
"@frockbot/kernel-contracts": "0.3.8",
|
|
31
|
+
"@frockbot/plugin-shell": "0.3.8",
|
|
32
|
+
"@frockbot/secret-shapes": "0.3.8",
|
|
33
33
|
"cordis": "4.0.0-rc.8",
|
|
34
34
|
"vue": "3.5.41"
|
|
35
35
|
},
|
package/src/classify.test.ts
CHANGED
|
@@ -27,9 +27,11 @@ describe("the classifier table", () => {
|
|
|
27
27
|
"computer",
|
|
28
28
|
],
|
|
29
29
|
["computer_process_poll", { processId: "p1" }, "process", "computer"],
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
["
|
|
30
|
+
// Memory and Skills are the Workspace, not the Computer: they are
|
|
31
|
+
// written while it is hibernated and by Bots that have none.
|
|
32
|
+
["memory_write", { text: "a fact" }, "file", "workspace"],
|
|
33
|
+
["skill_write", { path: "a.md" }, "file", "workspace"],
|
|
34
|
+
["package_author", { packageId: "x" }, "file", "workspace"],
|
|
33
35
|
["mcp__example__echo", { message: "hi" }, "mcp", "remote:example"],
|
|
34
36
|
["mcp__beeper__send_message", {}, "mcp", "remote:beeper"],
|
|
35
37
|
// Read-only and product tools perform no audited effect at all. An audit
|
|
@@ -139,7 +141,8 @@ describe("the classifier table", () => {
|
|
|
139
141
|
toolName: "package_author",
|
|
140
142
|
input: { packageId: "acme" },
|
|
141
143
|
}),
|
|
142
|
-
|
|
144
|
+
// `package_author` writes the Workspace, not the Computer.
|
|
145
|
+
).toEqual({ kind: "file", target: "workspace" });
|
|
143
146
|
// A wrapper that names nothing resolvable stays the wrapper, and the
|
|
144
147
|
// wrapper is not an audited effect.
|
|
145
148
|
expect(auditKindForToolV1("call_dynamic_tool", {})).toBeUndefined();
|
package/src/classify.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
AUDIT_TARGET_COMPUTER_V1,
|
|
20
20
|
AUDIT_TARGET_MACHINE_PREFIX_V1,
|
|
21
21
|
AUDIT_TARGET_REMOTE_PREFIX_V1,
|
|
22
|
+
AUDIT_TARGET_WORKSPACE_V1,
|
|
22
23
|
type AuditKindV1,
|
|
23
24
|
} from "./shared.js";
|
|
24
25
|
|
|
@@ -41,10 +42,6 @@ export interface AuditClassificationV1 {
|
|
|
41
42
|
* costs one table row and no new authority.
|
|
42
43
|
*/
|
|
43
44
|
const FILE_TOOLS = new Set([
|
|
44
|
-
"memory_write",
|
|
45
|
-
"memory_forget",
|
|
46
|
-
"skill_write",
|
|
47
|
-
"package_author",
|
|
48
45
|
// The registered machine's file verbs (register rows 48, 49). They are file
|
|
49
46
|
// effects on "a separate filesystem" — the User's own laptop — which is why
|
|
50
47
|
// their target is `machine:<id>` and never `computer`.
|
|
@@ -53,6 +50,21 @@ const FILE_TOOLS = new Set([
|
|
|
53
50
|
"machine_copy_from_computer",
|
|
54
51
|
]);
|
|
55
52
|
|
|
53
|
+
/**
|
|
54
|
+
* File effects that land in the User's Workspace, not on the Computer.
|
|
55
|
+
*
|
|
56
|
+
* Memory and Skills are object storage: they are written while the Computer is
|
|
57
|
+
* hibernated, and by Bots whose User has no Computer configured at all. Their
|
|
58
|
+
* rows said "This Computer", which named the wrong place and, in the case we
|
|
59
|
+
* saw, a place that did not exist.
|
|
60
|
+
*/
|
|
61
|
+
const WORKSPACE_FILE_TOOLS = new Set([
|
|
62
|
+
"memory_write",
|
|
63
|
+
"memory_forget",
|
|
64
|
+
"skill_write",
|
|
65
|
+
"package_author",
|
|
66
|
+
]);
|
|
67
|
+
|
|
56
68
|
/**
|
|
57
69
|
* The registered machine's shell verb.
|
|
58
70
|
*
|
|
@@ -192,6 +204,9 @@ export function auditKindForToolV1(
|
|
|
192
204
|
if (name.startsWith(MACHINE_MESSAGES_PREFIX)) {
|
|
193
205
|
return { kind: "mcp", target: onComputer };
|
|
194
206
|
}
|
|
207
|
+
if (WORKSPACE_FILE_TOOLS.has(name)) {
|
|
208
|
+
return { kind: "file", target: AUDIT_TARGET_WORKSPACE_V1 };
|
|
209
|
+
}
|
|
195
210
|
if (FILE_TOOLS.has(name)) return { kind: "file", target: onComputer };
|
|
196
211
|
const mcp = MCP_TOOL.exec(name);
|
|
197
212
|
if (mcp) {
|
|
@@ -56,6 +56,8 @@ function selectKind(kind: AuditKindV1 | undefined): void {
|
|
|
56
56
|
/** Where the effect ran, in words rather than in the wire shape. */
|
|
57
57
|
function target(entry: AuditEntryV1): string {
|
|
58
58
|
if (entry.target === "computer") return "This Computer";
|
|
59
|
+
// Memory and Skills are files in the Workspace, not on the Computer.
|
|
60
|
+
if (entry.target === "workspace") return "Workspace";
|
|
59
61
|
if (entry.target.startsWith("machine:")) {
|
|
60
62
|
return `Machine ${entry.target.slice("machine:".length)}`;
|
|
61
63
|
}
|
package/src/shared.ts
CHANGED
|
@@ -88,6 +88,16 @@ export const AUDIT_OUTCOMES_V1: readonly AuditOutcomeV1[] = [
|
|
|
88
88
|
|
|
89
89
|
/** The Bot's own Computer — the default target for every Computer effect. */
|
|
90
90
|
export const AUDIT_TARGET_COMPUTER_V1 = "computer";
|
|
91
|
+
/**
|
|
92
|
+
* The User's Workspace in object storage.
|
|
93
|
+
*
|
|
94
|
+
* Memory and Skills live here, not on the Computer, and they are written
|
|
95
|
+
* while it is hibernated — a Bot with no Computer configured at all still
|
|
96
|
+
* writes Memory. Rows for those writes said "This Computer", which named a
|
|
97
|
+
* machine that had nothing to do with the effect and, in the case we saw, did
|
|
98
|
+
* not exist.
|
|
99
|
+
*/
|
|
100
|
+
export const AUDIT_TARGET_WORKSPACE_V1 = "workspace";
|
|
91
101
|
/** A registered machine of the User's, `machine:<id>` (parity register §2.16). */
|
|
92
102
|
export const AUDIT_TARGET_MACHINE_PREFIX_V1 = "machine:";
|
|
93
103
|
/** A remote MCP server, `remote:<host>`. */
|
|
@@ -269,6 +279,7 @@ export function decodeAuditOccurrenceIdV1(value: unknown): {
|
|
|
269
279
|
/** Whether a string is one of the three target shapes this schema allows. */
|
|
270
280
|
export function isAuditTargetV1(value: string): boolean {
|
|
271
281
|
if (value === AUDIT_TARGET_COMPUTER_V1) return true;
|
|
282
|
+
if (value === AUDIT_TARGET_WORKSPACE_V1) return true;
|
|
272
283
|
if (value.length > MAX_TARGET_LENGTH) return false;
|
|
273
284
|
if (value.startsWith(AUDIT_TARGET_MACHINE_PREFIX_V1)) {
|
|
274
285
|
return /^machine:[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(value);
|