@noopolis/daimon 0.2.1 → 0.2.2
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/dist/runtime/agentSkillsDirectory.d.ts +25 -0
- package/dist/runtime/agentSkillsDirectory.d.ts.map +1 -0
- package/dist/runtime/agentSkillsDirectory.js +101 -0
- package/dist/runtime/engineBrokerServiceConfig.d.ts +10 -2
- package/dist/runtime/engineBrokerServiceConfig.d.ts.map +1 -1
- package/dist/runtime/engineBrokerServiceConfig.js +9 -5
- package/dist/runtime/grokBrokerProjection.d.ts +17 -1
- package/dist/runtime/grokBrokerProjection.d.ts.map +1 -1
- package/dist/runtime/grokBrokerProjection.js +7 -3
- package/dist/runtime/grokWorkerAttestation.d.ts +3 -1
- package/dist/runtime/grokWorkerAttestation.d.ts.map +1 -1
- package/dist/runtime/grokWorkerAttestation.js +4 -2
- package/dist/runtime/grokWorkerHomeAttestation.d.ts +48 -4
- package/dist/runtime/grokWorkerHomeAttestation.d.ts.map +1 -1
- package/dist/runtime/grokWorkerHomeAttestation.js +95 -6
- package/dist/runtime/grokWorkerSkills.d.ts +86 -0
- package/dist/runtime/grokWorkerSkills.d.ts.map +1 -0
- package/dist/runtime/grokWorkerSkills.js +135 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +3 -0
- package/dist/runtime/productionAgentTools.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type AgentSkill } from "./grokWorkerSkills.js";
|
|
2
|
+
/**
|
|
3
|
+
* What every entry of a skills tree must satisfy beyond being a plain,
|
|
4
|
+
* non-symlink directory or regular file. Attesting a root-provisioned
|
|
5
|
+
* `$GROK_HOME/skills` sets both; reading a compiled workspace leaves them unset.
|
|
6
|
+
*/
|
|
7
|
+
export type AgentSkillsTreePolicy = Readonly<{
|
|
8
|
+
ownerUid?: number;
|
|
9
|
+
readOnly?: boolean;
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* Reads a skills tree — `<root>/<name>/SKILL.md` plus any supporting files —
|
|
13
|
+
* into the engine-neutral {@link AgentSkill} input, or `undefined` when `root`
|
|
14
|
+
* does not exist.
|
|
15
|
+
*
|
|
16
|
+
* It is the same reader for both ends of the Grok skills path: provisioning
|
|
17
|
+
* reads the compiled workspace's `.agents/skills` (the tree Codex reads in
|
|
18
|
+
* place), and the broker re-reads the rendered `$GROK_HOME/skills` before every
|
|
19
|
+
* turn under a root-owned, read-only policy. Symlinks, special files, hard
|
|
20
|
+
* links (read-only policy), non-UTF-8 content and anything past the
|
|
21
|
+
* {@link AGENT_SKILLS_BOUNDS} are refused rather than skipped, because a
|
|
22
|
+
* skipped entry would make the attested digest describe less than Grok loads.
|
|
23
|
+
*/
|
|
24
|
+
export declare function readAgentSkillsDirectory(root: string, policy?: AgentSkillsTreePolicy): Promise<readonly AgentSkill[] | undefined>;
|
|
25
|
+
//# sourceMappingURL=agentSkillsDirectory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentSkillsDirectory.d.ts","sourceRoot":"","sources":["../../src/runtime/agentSkillsDirectory.ts"],"names":[],"mappings":"AAIA,OAAO,EAAyC,KAAK,UAAU,EAAuB,MAAM,uBAAuB,CAAC;AAEpH;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAKxF;;;;;;;;;;;;GAYG;AACH,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,qBAA0B,GAAG,OAAO,CAAC,SAAS,UAAU,EAAE,GAAG,SAAS,CAAC,CAqC3I"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { lstat, open, readdir } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { AGENT_SKILLS_BOUNDS, parseAgentSkills } from "./grokWorkerSkills.js";
|
|
5
|
+
const invalid = (detail) => new TypeError(`invalid agent skills directory: ${detail}`);
|
|
6
|
+
const decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
|
7
|
+
/**
|
|
8
|
+
* Reads a skills tree — `<root>/<name>/SKILL.md` plus any supporting files —
|
|
9
|
+
* into the engine-neutral {@link AgentSkill} input, or `undefined` when `root`
|
|
10
|
+
* does not exist.
|
|
11
|
+
*
|
|
12
|
+
* It is the same reader for both ends of the Grok skills path: provisioning
|
|
13
|
+
* reads the compiled workspace's `.agents/skills` (the tree Codex reads in
|
|
14
|
+
* place), and the broker re-reads the rendered `$GROK_HOME/skills` before every
|
|
15
|
+
* turn under a root-owned, read-only policy. Symlinks, special files, hard
|
|
16
|
+
* links (read-only policy), non-UTF-8 content and anything past the
|
|
17
|
+
* {@link AGENT_SKILLS_BOUNDS} are refused rather than skipped, because a
|
|
18
|
+
* skipped entry would make the attested digest describe less than Grok loads.
|
|
19
|
+
*/
|
|
20
|
+
export async function readAgentSkillsDirectory(root, policy = {}) {
|
|
21
|
+
let top;
|
|
22
|
+
try {
|
|
23
|
+
top = await lstat(root);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (error.code === "ENOENT")
|
|
27
|
+
return undefined;
|
|
28
|
+
throw invalid("unreadable root");
|
|
29
|
+
}
|
|
30
|
+
assertEntry(top, "directory", policy, ".");
|
|
31
|
+
const names = await boundedEntries(root, AGENT_SKILLS_BOUNDS.skills);
|
|
32
|
+
const skills = [];
|
|
33
|
+
let budget = AGENT_SKILLS_BOUNDS.totalBytes;
|
|
34
|
+
for (const name of names) {
|
|
35
|
+
const directory = path.join(root, name);
|
|
36
|
+
assertEntry(await lstat(directory), "directory", policy, name);
|
|
37
|
+
const files = [];
|
|
38
|
+
const walk = async (relative, depth) => {
|
|
39
|
+
for (const child of await boundedEntries(path.join(directory, relative), AGENT_SKILLS_BOUNDS.filesPerSkill)) {
|
|
40
|
+
const childRelative = relative === "" ? child : `${relative}/${child}`;
|
|
41
|
+
const absolute = path.join(directory, childRelative);
|
|
42
|
+
const where = `${name}/${childRelative}`;
|
|
43
|
+
const entry = await lstat(absolute);
|
|
44
|
+
if (entry.isDirectory()) {
|
|
45
|
+
if (depth + 1 >= AGENT_SKILLS_BOUNDS.depth)
|
|
46
|
+
throw invalid(`too deep at ${JSON.stringify(where)}`);
|
|
47
|
+
assertEntry(entry, "directory", policy, where);
|
|
48
|
+
await walk(childRelative, depth + 1);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
assertEntry(entry, "file", policy, where);
|
|
52
|
+
if (files.length >= AGENT_SKILLS_BOUNDS.filesPerSkill)
|
|
53
|
+
throw invalid(`too many files in ${JSON.stringify(name)}`);
|
|
54
|
+
const content = await readPinnedFile(absolute, where, entry, Math.min(AGENT_SKILLS_BOUNDS.fileBytes, budget));
|
|
55
|
+
budget -= Buffer.byteLength(content, "utf8");
|
|
56
|
+
files.push({ path: childRelative, content });
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
await walk("", 0);
|
|
60
|
+
skills.push({ name, files });
|
|
61
|
+
}
|
|
62
|
+
return parseAgentSkills(skills);
|
|
63
|
+
}
|
|
64
|
+
/** `where` is the entry's path relative to the skills root, named in every refusal. */
|
|
65
|
+
function assertEntry(entry, kind, policy, where) {
|
|
66
|
+
if (entry.isSymbolicLink() || (kind === "directory" ? !entry.isDirectory() : !entry.isFile()))
|
|
67
|
+
throw invalid(`expected a plain ${kind} at ${JSON.stringify(where)}`);
|
|
68
|
+
if (policy.ownerUid !== undefined && entry.uid !== policy.ownerUid)
|
|
69
|
+
throw invalid(`unexpected owner of ${JSON.stringify(where)}`);
|
|
70
|
+
if (policy.readOnly === true && ((Number(entry.mode) & 0o7222) !== 0 || (kind === "file" && entry.nlink !== 1)))
|
|
71
|
+
throw invalid(`writable or linked entry ${JSON.stringify(where)}`);
|
|
72
|
+
}
|
|
73
|
+
async function boundedEntries(directory, limit) {
|
|
74
|
+
const entries = await readdir(directory);
|
|
75
|
+
if (entries.length > limit)
|
|
76
|
+
throw invalid(`too many entries in ${JSON.stringify(path.basename(directory))}`);
|
|
77
|
+
return entries.sort();
|
|
78
|
+
}
|
|
79
|
+
/** Opens without following links and requires the inode `lstat` saw, so a swap between the two cannot change the bytes read. */
|
|
80
|
+
async function readPinnedFile(file, where, seen, limit) {
|
|
81
|
+
if (seen.size > limit)
|
|
82
|
+
throw invalid(`file too large ${JSON.stringify(where)}`);
|
|
83
|
+
const handle = await open(file, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
84
|
+
try {
|
|
85
|
+
const opened = await handle.stat();
|
|
86
|
+
if (!opened.isFile() || opened.dev !== seen.dev || opened.ino !== seen.ino || opened.uid !== seen.uid || opened.mode !== seen.mode || opened.nlink !== seen.nlink || opened.size > limit)
|
|
87
|
+
throw invalid(`file changed while read ${JSON.stringify(where)}`);
|
|
88
|
+
const bytes = await handle.readFile();
|
|
89
|
+
if (bytes.length > limit)
|
|
90
|
+
throw invalid(`file too large ${JSON.stringify(where)}`);
|
|
91
|
+
try {
|
|
92
|
+
return decoder.decode(bytes);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
throw invalid(`file is not UTF-8 ${JSON.stringify(where)}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
await handle.close().catch(() => undefined);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -16,6 +16,13 @@ export type EngineBrokerServiceRegistration = Readonly<{
|
|
|
16
16
|
usageLedgerPath: string;
|
|
17
17
|
limits: EngineBrokerTurnLimits;
|
|
18
18
|
model: GrokBrokerModelPolicy;
|
|
19
|
+
/**
|
|
20
|
+
* Digest of the skills root provisioning rendered into `$GROK_HOME/skills`
|
|
21
|
+
* (`grokWorkerSkillsSha256`), attested before every turn. Optional in v2
|
|
22
|
+
* registrations and v3 slot policies; absent means the slot has no skills and
|
|
23
|
+
* the directory must not exist.
|
|
24
|
+
*/
|
|
25
|
+
skillsSha256?: string;
|
|
19
26
|
}>;
|
|
20
27
|
/**
|
|
21
28
|
* `inferenceLedgerPath` (v2, optional) is where evaluator inference grants
|
|
@@ -46,8 +53,9 @@ export declare const engineBrokerSealLedgerPathFor: (usageLedgerPath: string) =>
|
|
|
46
53
|
* v3 retains seven-field registrations and binds slotPolicies by slot; agent IDs
|
|
47
54
|
* may repeat, while worker UIDs, slots and ledger streams must be distinct.
|
|
48
55
|
* v2 requires every registration to declare its usage ledger, limits and model
|
|
49
|
-
* (`model.id`/`model.reasoningEffort` from the closed lists)
|
|
50
|
-
*
|
|
56
|
+
* (`model.id`/`model.reasoningEffort` from the closed lists) and may declare
|
|
57
|
+
* `skillsSha256` (v3: on its slot policy); unknown keys at any level are
|
|
58
|
+
* refused. v1 is still accepted and receives today's defaults:
|
|
51
59
|
* the container ledger, {@link DEFAULT_GROK_BROKER_TURN_LIMITS}, and
|
|
52
60
|
* `grok-4.6`/`low`.
|
|
53
61
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engineBrokerServiceConfig.d.ts","sourceRoot":"","sources":["../../src/runtime/engineBrokerServiceConfig.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgE,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAC5I,OAAO,EAAuF,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAK7J,eAAO,MAAM,wBAAwB,EAAG,0CAAmD,CAAC;AAC5F,eAAO,MAAM,wBAAwB,EAAG,0CAAmD,CAAC;AAC5F,eAAO,MAAM,wBAAwB,EAAG,0CAAmD,CAAC;AAE5F,mHAAmH;AACnH,MAAM,MAAM,+BAA+B,GAAG,QAAQ,CAAC;IACrD,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IACpI,oJAAoJ;IACpJ,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,KAAK,EAAE,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"engineBrokerServiceConfig.d.ts","sourceRoot":"","sources":["../../src/runtime/engineBrokerServiceConfig.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgE,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAC5I,OAAO,EAAuF,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAK7J,eAAO,MAAM,wBAAwB,EAAG,0CAAmD,CAAC;AAC5F,eAAO,MAAM,wBAAwB,EAAG,0CAAmD,CAAC;AAC5F,eAAO,MAAM,wBAAwB,EAAG,0CAAmD,CAAC;AAE5F,mHAAmH;AACnH,MAAM,MAAM,+BAA+B,GAAG,QAAQ,CAAC;IACrD,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IACpI,oJAAoJ;IACpJ,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,KAAK,EAAE,qBAAqB,CAAC;IAC7B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC,CAAC;AACH;;;;;;GAMG;AACH,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,SAAS,+BAA+B,EAAE,CAAC;IAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAc5O,2EAA2E;AAC3E,eAAO,MAAM,gCAAgC,GAAI,iBAAiB,MAAM,KAAG,MAAgF,CAAC;AAE5J;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,GAAI,iBAAiB,MAAM,KAAG,MAA6E,CAAC;AAEtJ;;;;;;;;;;;GAWG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,yBAAyB,CAyDxF"}
|
|
@@ -33,8 +33,9 @@ export const engineBrokerSealLedgerPathFor = (usageLedgerPath) => path.posix.joi
|
|
|
33
33
|
* v3 retains seven-field registrations and binds slotPolicies by slot; agent IDs
|
|
34
34
|
* may repeat, while worker UIDs, slots and ledger streams must be distinct.
|
|
35
35
|
* v2 requires every registration to declare its usage ledger, limits and model
|
|
36
|
-
* (`model.id`/`model.reasoningEffort` from the closed lists)
|
|
37
|
-
*
|
|
36
|
+
* (`model.id`/`model.reasoningEffort` from the closed lists) and may declare
|
|
37
|
+
* `skillsSha256` (v3: on its slot policy); unknown keys at any level are
|
|
38
|
+
* refused. v1 is still accepted and receives today's defaults:
|
|
38
39
|
* the container ledger, {@link DEFAULT_GROK_BROKER_TURN_LIMITS}, and
|
|
39
40
|
* `grok-4.6`/`low`.
|
|
40
41
|
*/
|
|
@@ -66,7 +67,7 @@ export function parseEngineBrokerServiceConfig(value) {
|
|
|
66
67
|
for (const policy of value.slotPolicies) {
|
|
67
68
|
if (!plain(policy))
|
|
68
69
|
throw invalid();
|
|
69
|
-
exact(policy, ["slot", "usageLedgerPath", "limits", "model"]);
|
|
70
|
+
exact(policy, ["slot", "usageLedgerPath", "limits", "model", ...withSkills(policy)]);
|
|
70
71
|
if (!Number.isSafeInteger(policy.slot) || policy.slot < 0 || policies.has(policy.slot))
|
|
71
72
|
throw invalid();
|
|
72
73
|
policies.set(policy.slot, policy);
|
|
@@ -77,7 +78,7 @@ export function parseEngineBrokerServiceConfig(value) {
|
|
|
77
78
|
const registrations = value.registrations.map((entry) => {
|
|
78
79
|
if (!plain(entry))
|
|
79
80
|
throw invalid();
|
|
80
|
-
exact(entry, v2 && !v3 ? V2_REGISTRATION : V1_REGISTRATION);
|
|
81
|
+
exact(entry, v2 && !v3 ? [...V2_REGISTRATION, ...withSkills(entry)] : V1_REGISTRATION);
|
|
81
82
|
const { agentId, slot, workerUid, workspace, profilePath, eventsPath, profileSha256 } = entry;
|
|
82
83
|
if (typeof agentId !== "string" || !agentId.trim() || (!v3 && seen.has(agentId)) || !Number.isSafeInteger(slot) || slot < 0 || slots.has(slot) || !Number.isSafeInteger(workerUid) || workerUid < 2200 || workers.has(workerUid) || !absolute(workspace) || !absolute(profilePath) || !absolute(eventsPath) || typeof profileSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(profileSha256) || eventsPath !== grokWorkerEventsPathFor(profilePath) || !profilePath.endsWith("/sandbox.toml"))
|
|
83
84
|
throw invalid();
|
|
@@ -104,7 +105,9 @@ export function parseEngineBrokerServiceConfig(value) {
|
|
|
104
105
|
catch {
|
|
105
106
|
throw invalid();
|
|
106
107
|
}
|
|
107
|
-
|
|
108
|
+
if (Object.hasOwn(policy, "skillsSha256") && (typeof policy.skillsSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(policy.skillsSha256)))
|
|
109
|
+
throw invalid();
|
|
110
|
+
return { ...base, usageLedgerPath, limits, model: parseServiceModel(policy.model), ...(Object.hasOwn(policy, "skillsSha256") ? { skillsSha256: policy.skillsSha256 } : {}) };
|
|
108
111
|
});
|
|
109
112
|
const base = { credentialHome: value.credentialHome, turnStore: value.turnStore, registrations,
|
|
110
113
|
...(value.runRequestStore === undefined ? {} : { runRequestStore: value.runRequestStore }),
|
|
@@ -119,6 +122,7 @@ export function parseEngineBrokerServiceConfig(value) {
|
|
|
119
122
|
throw invalid();
|
|
120
123
|
return { ...base, inferenceLedgerPath };
|
|
121
124
|
}
|
|
125
|
+
const withSkills = (value) => Object.hasOwn(value, "skillsSha256") ? ["skillsSha256"] : [];
|
|
122
126
|
const ledgerPath = (item) => absolute(item) && item.endsWith(".jsonl") && path.posix.normalize(item) === item;
|
|
123
127
|
function parseServiceModel(value) {
|
|
124
128
|
if (!plain(value))
|
|
@@ -2,6 +2,7 @@ import { GROK_BROKER_TASK_CLOCK, type GrokWorkerConfigVariant } from "../contrac
|
|
|
2
2
|
import { type EngineBrokerServiceRegistration } from "./engineBrokerServiceConfig.js";
|
|
3
3
|
import { type EngineBrokerTurnLimits } from "./engineBrokerTurnAccounting.js";
|
|
4
4
|
import type { GrokBrokerModel, GrokBrokerReasoningEffort } from "./grokBrokerModelPolicy.js";
|
|
5
|
+
import { type AgentSkill } from "./grokWorkerSkills.js";
|
|
5
6
|
import { GROK_WORKER_SANDBOX_PROFILE } from "./grokWorkerSandboxProfile.js";
|
|
6
7
|
export declare const GROK_BROKER_PROJECTION_VERSION: "noopolis.daimon.grok-broker-projection.v3";
|
|
7
8
|
/**
|
|
@@ -27,6 +28,13 @@ export type OrganizationGrokBrokerProjection = Readonly<{
|
|
|
27
28
|
timestampFilePath: string;
|
|
28
29
|
}>;
|
|
29
30
|
systemPromptSha256: string;
|
|
31
|
+
/**
|
|
32
|
+
* Digest of the declared skills rendered into `$GROK_HOME/skills`
|
|
33
|
+
* (`grokWorkerSkillsSha256`). Present only when the agent declares at least
|
|
34
|
+
* one skill, so a skill-less projection is byte-identical to one computed
|
|
35
|
+
* before skills existed.
|
|
36
|
+
*/
|
|
37
|
+
skillsSha256?: string;
|
|
30
38
|
grokCliVersion: string;
|
|
31
39
|
grokExecutableSha256: string;
|
|
32
40
|
nativeAbiVersion: number;
|
|
@@ -78,6 +86,13 @@ export type OrganizationGrokBrokerProjectionOptions = Readonly<{
|
|
|
78
86
|
seccompProfileSha256: string;
|
|
79
87
|
/** When the caller already holds a rendered profile digest, it must equal Daimon's. */
|
|
80
88
|
profileSha256?: string;
|
|
89
|
+
/**
|
|
90
|
+
* The agent's declared skills: the compiled workspace `.agents/skills` tree
|
|
91
|
+
* every engine is given (`readAgentSkillsDirectory`), which root provisioning
|
|
92
|
+
* renders into `$GROK_HOME/skills` (`renderGrokWorkerSkillsTree`). Omitted or
|
|
93
|
+
* empty means no skills.
|
|
94
|
+
*/
|
|
95
|
+
skills?: readonly AgentSkill[];
|
|
81
96
|
}>;
|
|
82
97
|
/**
|
|
83
98
|
* Resolve the public Grok broker projection for one agent.
|
|
@@ -98,7 +113,8 @@ export type OrganizationGrokBrokerProjectionOptions = Readonly<{
|
|
|
98
113
|
* this agent (realm, bootstrap, peers, and the mask covering the acceptance
|
|
99
114
|
* store) plus the caller's evaluator paths, sorted and deduplicated exactly as
|
|
100
115
|
* the profile renderer does. A supplied `profileSha256` that differs is
|
|
101
|
-
* refused.
|
|
116
|
+
* refused. Declared `skills` add `skillsSha256`, which the implied
|
|
117
|
+
* registration carries and the broker attests against `$GROK_HOME/skills`.
|
|
102
118
|
*/
|
|
103
119
|
export declare function resolveOrganizationGrokBrokerProjection(config: unknown, agentId: string, options: OrganizationGrokBrokerProjectionOptions): OrganizationGrokBrokerProjection;
|
|
104
120
|
/** sha256 over the projection's canonical JSON; what a slot preflight receipt binds. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grokBrokerProjection.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerProjection.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,KAAK,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAQ3G,OAAO,EAAkC,KAAK,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AACtH,OAAO,EAA+B,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAE3G,OAAO,KAAK,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC7F,OAAO,EAAE,2BAA2B,EAA2F,MAAM,+BAA+B,CAAC;AAGrK,eAAO,MAAM,8BAA8B,6CAAuC,CAAC;AAEnF;;;;;GAKG;AACH,MAAM,MAAM,gCAAgC,GAAG,QAAQ,CAAC;IACtD,OAAO,EAAE,OAAO,8BAA8B,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,uBAAuB,CAAC;IAC7C,SAAS,CAAC,EAAE,IAAI,CAAC,OAAO,sBAAsB,EAAE,eAAe,GAAG,mBAAmB,CAAC,GAAG,QAAQ,CAAC;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxJ,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,eAAe,CAAC;IACvB,eAAe,EAAE,yBAAyB,CAAC;IAC3C,MAAM,EAAE,sBAAsB,CAAC;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,yHAAyH;IACzH,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,QAAQ,CAAC;QAAE,QAAQ,EAAE,gBAAgB,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAC;QAAC,eAAe,EAAE,IAAI,CAAC;QAAC,WAAW,EAAE,OAAO,2BAA2B,CAAC;QAAC,cAAc,EAAE,YAAY,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjM,CAAC,CAAC;AAEH,MAAM,MAAM,uCAAuC,GAAG,QAAQ,CAAC;IAC7D,gHAAgH;IAChH,mBAAmB,CAAC,EAAE,uBAAuB,CAAC;IAC9C,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,OAAO,GAAG,KAAK,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,sBAAsB,CAAC;IAC/B;;;;;;;;;;;;;;OAcG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mFAAmF;IACnF,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,gFAAgF;IAChF,oBAAoB,EAAE,MAAM,CAAC;IAC7B,uFAAuF;IACvF,aAAa,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"grokBrokerProjection.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerProjection.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,7 @@ import { grokSandboxProtectedPaths } from "./engineDispatcher.js";
|
|
|
9
9
|
import { parseEngineBrokerServiceConfig } from "./engineBrokerServiceConfig.js";
|
|
10
10
|
import { parseEngineBrokerTurnLimits } from "./engineBrokerTurnAccounting.js";
|
|
11
11
|
import { grokBrokerWorkerConfigPins, grokBrokerWorkerConfigSha256 } from "./grokBrokerWorkerConfig.js";
|
|
12
|
+
import { grokWorkerSkillsSha256, parseAgentSkills } from "./grokWorkerSkills.js";
|
|
12
13
|
import { GROK_WORKER_SANDBOX_PROFILE, grokWorkerEventsPathFor, renderGrokWorkerSandboxProfile, grokWorkerSandboxProfileSha256 } from "./grokWorkerSandboxProfile.js";
|
|
13
14
|
import { parseOrganizationRuntimeConfig } from "./organizationRuntime.js";
|
|
14
15
|
export const GROK_BROKER_PROJECTION_VERSION = GROK_ENGINE_BROKER.projectionVersion;
|
|
@@ -31,7 +32,8 @@ export const GROK_BROKER_PROJECTION_VERSION = GROK_ENGINE_BROKER.projectionVersi
|
|
|
31
32
|
* this agent (realm, bootstrap, peers, and the mask covering the acceptance
|
|
32
33
|
* store) plus the caller's evaluator paths, sorted and deduplicated exactly as
|
|
33
34
|
* the profile renderer does. A supplied `profileSha256` that differs is
|
|
34
|
-
* refused.
|
|
35
|
+
* refused. Declared `skills` add `skillsSha256`, which the implied
|
|
36
|
+
* registration carries and the broker attests against `$GROK_HOME/skills`.
|
|
35
37
|
*/
|
|
36
38
|
export function resolveOrganizationGrokBrokerProjection(config, agentId, options) {
|
|
37
39
|
const parsed = parseOrganizationRuntimeConfig(config);
|
|
@@ -64,12 +66,13 @@ export function resolveOrganizationGrokBrokerProjection(config, agentId, options
|
|
|
64
66
|
const artifact = GROK_ENGINE_BROKER.grokCliArtifacts[options.architecture];
|
|
65
67
|
if (artifact === undefined)
|
|
66
68
|
throw new Error("Grok broker projection requires a pinned architecture");
|
|
69
|
+
const skills = parseAgentSkills(options.skills ?? []);
|
|
67
70
|
const profilePath = path.posix.join(options.workerHomePath, ".grok", "sandbox.toml");
|
|
68
71
|
const projection = {
|
|
69
72
|
version: GROK_BROKER_PROJECTION_VERSION, agentId, workspacePath: agent.workspacePath, runtimeHomePath: agent.runtimeHomePath,
|
|
70
73
|
workerUid: options.workerUid, slot: options.slot, profilePath, profileSha256, denyPaths, workerConfigSha256, workerConfigVariant,
|
|
71
74
|
...(workerConfigVariant === "clocked" ? { taskClock: { ...GROK_BROKER_TASK_CLOCK, directoryPath: path.posix.dirname(brokerTaskClockFileFor(options.slot)), timestampFilePath: brokerTaskClockFileFor(options.slot) } } : {}),
|
|
72
|
-
systemPromptSha256: GROK_ENGINE_BROKER.worker.systemPromptSha256, grokCliVersion: GROK_ENGINE_BROKER.grokCliVersion, grokExecutableSha256: artifact.sha256,
|
|
75
|
+
systemPromptSha256: GROK_ENGINE_BROKER.worker.systemPromptSha256, ...(skills.length === 0 ? {} : { skillsSha256: grokWorkerSkillsSha256(skills) }), grokCliVersion: GROK_ENGINE_BROKER.grokCliVersion, grokExecutableSha256: artifact.sha256,
|
|
73
76
|
nativeAbiVersion: GROK_ENGINE_BROKER.nativeAbiVersion, model, reasoningEffort, limits: parseEngineBrokerTurnLimits(options.limits), usageLedgerPath: options.usageLedgerPath, seccompProfileSha256: options.seccompProfileSha256,
|
|
74
77
|
attestation: { platform: "linux/landlock", enforced: true, restrictNetwork: true, profileName: GROK_WORKER_SANDBOX_PROFILE, sandboxRuntime: "bubblewrap", eventsPath: grokWorkerEventsPathFor(profilePath) }
|
|
75
78
|
};
|
|
@@ -84,7 +87,8 @@ export function grokBrokerServiceRegistrationFor(projection) {
|
|
|
84
87
|
const registration = {
|
|
85
88
|
agentId: projection.agentId, slot: projection.slot, workerUid: projection.workerUid, workspace: projection.workspacePath,
|
|
86
89
|
profilePath: projection.profilePath, eventsPath: projection.attestation.eventsPath, profileSha256: projection.profileSha256,
|
|
87
|
-
usageLedgerPath: projection.usageLedgerPath, limits: projection.limits, model: { id: projection.model, reasoningEffort: projection.reasoningEffort }
|
|
90
|
+
usageLedgerPath: projection.usageLedgerPath, limits: projection.limits, model: { id: projection.model, reasoningEffort: projection.reasoningEffort },
|
|
91
|
+
...(projection.skillsSha256 === undefined ? {} : { skillsSha256: projection.skillsSha256 })
|
|
88
92
|
};
|
|
89
93
|
parseEngineBrokerServiceConfig({ version: "noopolis.daimon.engine-broker-service.v2", credentialHome: GROK_ENGINE_BROKER.credentialHomePath, turnStore: GROK_ENGINE_BROKER.turnStorePath, registrations: [registration] });
|
|
90
94
|
return registration;
|
|
@@ -53,7 +53,8 @@ export declare function parseGrokWorkerSandboxProfile(bytes: Uint8Array, profile
|
|
|
53
53
|
* the events watermark it requires the 1.0.34 layout: events under
|
|
54
54
|
* `$GROK_HOME/sessions/` (the root `sandbox-events.jsonl` stays empty on
|
|
55
55
|
* 1.0.34), and a root-owned read-only worker home whose `config.toml` hashes to
|
|
56
|
-
* the declared renderer output
|
|
56
|
+
* the declared renderer output and whose `skills/` is exactly the declared
|
|
57
|
+
* skills (`skillsSha256`; absent for none) (`grokWorkerHomeAttestation.ts`).
|
|
57
58
|
*
|
|
58
59
|
* It also refuses a deny list bubblewrap could not materialize
|
|
59
60
|
* (`grokWorkerDenyPlacement.ts`), naming the entry and the ancestor that stops
|
|
@@ -73,6 +74,7 @@ export declare function prepareGrokWorkerAttestation(input: Readonly<{
|
|
|
73
74
|
workerGid?: number;
|
|
74
75
|
brokerGid: number;
|
|
75
76
|
configSha256: GrokWorkerConfigPins;
|
|
77
|
+
skillsSha256?: string;
|
|
76
78
|
registeredWorkers?: readonly Readonly<{
|
|
77
79
|
profilePath: string;
|
|
78
80
|
workerUid: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grokWorkerAttestation.d.ts","sourceRoot":"","sources":["../../src/runtime/grokWorkerAttestation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAOnF,OAAO,EAAwB,KAAK,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACjG,OAAO,EAAiD,KAAK,oBAAoB,EAA4B,MAAM,+BAA+B,CAAC;AAGnJ;;;;;GAKG;AACH,MAAM,MAAM,6BAA6B,GAAC,QAAQ,CAAC;IAAC,GAAG,EAAC,MAAM,CAAC;IAAA,GAAG,EAAC,MAAM,CAAC;IAAA,IAAI,EAAC,MAAM,CAAC;IAAA,SAAS,EAAC,SAAS,MAAM,EAAE,CAAC;IAAA,aAAa,CAAC,EAAC,uBAAuB,CAAA;CAAC,CAAC,CAAC;AAC3J,KAAK,QAAQ,GAAC,6BAA6B,CAAC;AAC5C,qBAAa,4BAA6B,SAAQ,KAAK;IAAe,QAAQ,CAAC,YAAY,EAAC,iBAAiB,GAAC,iBAAiB;gBAAhD,YAAY,EAAC,iBAAiB,GAAC,iBAAiB;CAA4D;AAC3L;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAC,UAAU,EAAC,aAAa,EAAC,MAAM,GAAE,SAAS,MAAM,EAAE,CAUrG;AACD
|
|
1
|
+
{"version":3,"file":"grokWorkerAttestation.d.ts","sourceRoot":"","sources":["../../src/runtime/grokWorkerAttestation.ts"],"names":[],"mappings":"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"}
|
|
@@ -64,7 +64,8 @@ export function parseGrokWorkerSandboxProfile(bytes, profileSha256) {
|
|
|
64
64
|
* the events watermark it requires the 1.0.34 layout: events under
|
|
65
65
|
* `$GROK_HOME/sessions/` (the root `sandbox-events.jsonl` stays empty on
|
|
66
66
|
* 1.0.34), and a root-owned read-only worker home whose `config.toml` hashes to
|
|
67
|
-
* the declared renderer output
|
|
67
|
+
* the declared renderer output and whose `skills/` is exactly the declared
|
|
68
|
+
* skills (`skillsSha256`; absent for none) (`grokWorkerHomeAttestation.ts`).
|
|
68
69
|
*
|
|
69
70
|
* It also refuses a deny list bubblewrap could not materialize
|
|
70
71
|
* (`grokWorkerDenyPlacement.ts`), naming the entry and the ancestor that stops
|
|
@@ -100,7 +101,8 @@ export async function prepareGrokWorkerAttestation(input, profileOwner = { uid:
|
|
|
100
101
|
if (workers.some((worker) => worker.home === undefined))
|
|
101
102
|
throw new Error("Grok worker isolation attestation unavailable");
|
|
102
103
|
await verifyGrokWorkerTmp(workers, profileOwner.tmp);
|
|
103
|
-
|
|
104
|
+
// The home's read-only files share the profile's owner (root in production: `sandbox.toml` is one of them).
|
|
105
|
+
const configVariant = await verifyGrokWorkerHome(path.dirname(input.profilePath), input.configSha256, profileOwner.uid, input.skillsSha256);
|
|
104
106
|
const events = await secureOpen(input.eventsPath, input.workerUid, input.brokerGid, 0o640, 16 * 1024 * 1024);
|
|
105
107
|
try {
|
|
106
108
|
const stat = await events.stat();
|
|
@@ -13,7 +13,7 @@ type Entry = Pick<Stats, "uid" | "mode" | "nlink"> & Partial<Pick<Stats, "dev" |
|
|
|
13
13
|
* so the directory is worker-group writable — but root-owned and sticky, so a
|
|
14
14
|
* worker can neither rename nor unlink a root-owned file in it. Every file
|
|
15
15
|
* that decides a turn's behaviour is root-owned with no write bit: `config.toml`
|
|
16
|
-
* (model, effort, MCP,
|
|
16
|
+
* (model, effort, MCP, bundled-skill toggles), `sandbox.toml`, `trusted_folders.toml` (trust
|
|
17
17
|
* would re-enable cwd `AGENTS.md` and project skills), and the managed and
|
|
18
18
|
* requirements layers that can override user config. A missing file fails
|
|
19
19
|
* too: the worker could create it.
|
|
@@ -24,9 +24,53 @@ export declare function assertGrokWorkerHomeEntries(entries: Readonly<Record<str
|
|
|
24
24
|
/** The worker's `config.toml` must be exactly the renderer's bytes for the declared policy. */
|
|
25
25
|
export declare function assertGrokWorkerConfigBytes(bytes: Uint8Array, pins: GrokWorkerConfigPins): GrokWorkerConfigVariant;
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
27
|
+
* The worker's `$GROK_HOME/skills` must be exactly the declared skills.
|
|
28
|
+
*
|
|
29
|
+
* Grok loads that directory as user-scoped skills even in an untrusted
|
|
30
|
+
* workspace, and `$GROK_HOME` is worker-group writable, so a worker could plant
|
|
31
|
+
* a skill there for its next turn. With no `skillsSha256` declared the
|
|
32
|
+
* directory must be absent (or an empty root-owned read-only directory); with
|
|
33
|
+
* one declared, every entry must be root-owned with no write bit and the tree
|
|
34
|
+
* must hash to it. A worker-created or worker-modified tree fails either way.
|
|
35
|
+
*/
|
|
36
|
+
export declare function verifyGrokWorkerSkills(grokHome: string, skillsSha256: string | undefined, rootUid?: number): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Every other skill root Grok discovers at user scope, which the worker could
|
|
39
|
+
* plant into: under `$GROK_HOME` (root-owned but worker-group writable and
|
|
40
|
+
* sticky, so the worker can create new entries) and under the worker's own
|
|
41
|
+
* `$HOME` (the launcher exports `HOME=<home>` and `GROK_HOME=<home>/.grok`;
|
|
42
|
+
* `<home>` is worker-owned). Only `$GROK_HOME/skills` may carry skills, and only
|
|
43
|
+
* the declared ones; each root here must be absent, or an empty root-owned
|
|
44
|
+
* directory with no write bit.
|
|
45
|
+
*
|
|
46
|
+
* Set from `grok inspect` with scratch `HOME`/`GROK_HOME` and no network
|
|
47
|
+
* (1.0.60: every root below listed a planted skill or command; `.codex/skills`,
|
|
48
|
+
* `.ai/skills`, `$HOME/.config/*` and `$HOME/.agents/plugins` did not) and from
|
|
49
|
+
* the pinned 1.0.34 binary's own skills table (`~/.grok/{skills,commands}`,
|
|
50
|
+
* `~/.claude/{skills,commands}`, `~/.cursor/skills`, `.agents/{skills,commands}`
|
|
51
|
+
* at each tier). `bundled/skills` is the bundled-skill cache: never created on
|
|
52
|
+
* 1.0.34 (P0 container evidence), but a skill planted there loads with a name
|
|
53
|
+
* `[skills] disabled` does not cover. `plugins/` folders load their skills and
|
|
54
|
+
* commands as trusted user plugins.
|
|
55
|
+
*/
|
|
56
|
+
export declare const GROK_WORKER_FOREIGN_SKILL_ROOTS: Readonly<{
|
|
57
|
+
grokHome: readonly ["commands", "bundled/skills", "plugins"];
|
|
58
|
+
home: readonly [".agents/skills", ".agents/commands", ".claude/skills", ".claude/commands", ".cursor/skills", ".cursor/commands"];
|
|
59
|
+
}>;
|
|
60
|
+
/**
|
|
61
|
+
* Refuses a foreign skill root (`GROK_WORKER_FOREIGN_SKILL_ROOTS`) that exists
|
|
62
|
+
* and is not an empty root-owned read-only directory. A deployment that never
|
|
63
|
+
* creates them passes unchanged. `grokHome` must be `<home>/.grok`, the
|
|
64
|
+
* launcher's layout, so `<home>` is its parent.
|
|
65
|
+
*/
|
|
66
|
+
export declare function verifyGrokWorkerForeignSkillRoots(grokHome: string, rootUid?: number): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Attests the worker home layout, that `config.toml` is exactly the
|
|
69
|
+
* renderer's bytes for the declared model policy (`configSha256`), that
|
|
70
|
+
* `skills/` is exactly the declared skills (`skillsSha256`, absent for none),
|
|
71
|
+
* and that no other user skill root holds anything
|
|
72
|
+
* (`verifyGrokWorkerForeignSkillRoots`).
|
|
29
73
|
*/
|
|
30
|
-
export declare function verifyGrokWorkerHome(grokHome: string, configSha256: GrokWorkerConfigPins, rootUid?: number): Promise<GrokWorkerConfigVariant>;
|
|
74
|
+
export declare function verifyGrokWorkerHome(grokHome: string, configSha256: GrokWorkerConfigPins, rootUid?: number, skillsSha256?: string): Promise<GrokWorkerConfigVariant>;
|
|
31
75
|
export {};
|
|
32
76
|
//# sourceMappingURL=grokWorkerHomeAttestation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grokWorkerHomeAttestation.d.ts","sourceRoot":"","sources":["../../src/runtime/grokWorkerHomeAttestation.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAKhD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"grokWorkerHomeAttestation.d.ts","sourceRoot":"","sources":["../../src/runtime/grokWorkerHomeAttestation.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAKhD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAInF,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC,CAAC;AAE9F,KAAK,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC,GAAG,QAAQ,CAAC;IAAE,MAAM,IAAI,OAAO,CAAC;IAAC,WAAW,IAAI,OAAO,CAAC;IAAC,cAAc,IAAI,OAAO,CAAA;CAAE,CAAC,CAAC;AAG9K;;;;;;;;;;;;;GAaG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,GAAG,SAAS,CAAC,CAAC,EAAE,OAAO,GAAE,MAA2B,GAAG,IAAI,CAS5I;AAED,+FAA+F;AAC/F,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,oBAAoB,GAAG,uBAAuB,CAQlH;AAED;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,GAAE,MAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAKpJ;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,+BAA+B;;;EAG1C,CAAC;AAEH;;;;;GAKG;AACH,wBAAsB,iCAAiC,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,MAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB7H;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,oBAAoB,EAAE,OAAO,GAAE,MAA2B,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAkB9L"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { constants } from "node:fs";
|
|
3
|
-
import { lstat, open } from "node:fs/promises";
|
|
3
|
+
import { lstat, open, readdir } from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { GROK_ENGINE_BROKER } from "../contracts/runtimeContractManifest.js";
|
|
6
|
+
import { readAgentSkillsDirectory } from "./agentSkillsDirectory.js";
|
|
7
|
+
import { GROK_WORKER_SKILLS_LAYOUT, grokWorkerSkillsSha256 } from "./grokWorkerSkills.js";
|
|
6
8
|
const HOME = GROK_ENGINE_BROKER.worker.home;
|
|
7
9
|
/**
|
|
8
10
|
* The worker must not be able to change what Grok reads before its next turn.
|
|
@@ -11,7 +13,7 @@ const HOME = GROK_ENGINE_BROKER.worker.home;
|
|
|
11
13
|
* so the directory is worker-group writable — but root-owned and sticky, so a
|
|
12
14
|
* worker can neither rename nor unlink a root-owned file in it. Every file
|
|
13
15
|
* that decides a turn's behaviour is root-owned with no write bit: `config.toml`
|
|
14
|
-
* (model, effort, MCP,
|
|
16
|
+
* (model, effort, MCP, bundled-skill toggles), `sandbox.toml`, `trusted_folders.toml` (trust
|
|
15
17
|
* would re-enable cwd `AGENTS.md` and project skills), and the managed and
|
|
16
18
|
* requirements layers that can override user config. A missing file fails
|
|
17
19
|
* too: the worker could create it.
|
|
@@ -41,10 +43,94 @@ export function assertGrokWorkerConfigBytes(bytes, pins) {
|
|
|
41
43
|
throw unavailable();
|
|
42
44
|
}
|
|
43
45
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
+
* The worker's `$GROK_HOME/skills` must be exactly the declared skills.
|
|
47
|
+
*
|
|
48
|
+
* Grok loads that directory as user-scoped skills even in an untrusted
|
|
49
|
+
* workspace, and `$GROK_HOME` is worker-group writable, so a worker could plant
|
|
50
|
+
* a skill there for its next turn. With no `skillsSha256` declared the
|
|
51
|
+
* directory must be absent (or an empty root-owned read-only directory); with
|
|
52
|
+
* one declared, every entry must be root-owned with no write bit and the tree
|
|
53
|
+
* must hash to it. A worker-created or worker-modified tree fails either way.
|
|
54
|
+
*/
|
|
55
|
+
export async function verifyGrokWorkerSkills(grokHome, skillsSha256, rootUid = HOME.directory.uid) {
|
|
56
|
+
if (skillsSha256 !== undefined && !/^[0-9a-f]{64}$/u.test(skillsSha256))
|
|
57
|
+
throw unavailable();
|
|
58
|
+
let skills;
|
|
59
|
+
try {
|
|
60
|
+
skills = await readAgentSkillsDirectory(path.join(grokHome, GROK_WORKER_SKILLS_LAYOUT.relativePath), { ownerUid: rootUid, readOnly: true });
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
throw unavailable();
|
|
64
|
+
}
|
|
65
|
+
if (grokWorkerSkillsSha256(skills ?? []) !== (skillsSha256 ?? grokWorkerSkillsSha256([])))
|
|
66
|
+
throw unavailable();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Every other skill root Grok discovers at user scope, which the worker could
|
|
70
|
+
* plant into: under `$GROK_HOME` (root-owned but worker-group writable and
|
|
71
|
+
* sticky, so the worker can create new entries) and under the worker's own
|
|
72
|
+
* `$HOME` (the launcher exports `HOME=<home>` and `GROK_HOME=<home>/.grok`;
|
|
73
|
+
* `<home>` is worker-owned). Only `$GROK_HOME/skills` may carry skills, and only
|
|
74
|
+
* the declared ones; each root here must be absent, or an empty root-owned
|
|
75
|
+
* directory with no write bit.
|
|
76
|
+
*
|
|
77
|
+
* Set from `grok inspect` with scratch `HOME`/`GROK_HOME` and no network
|
|
78
|
+
* (1.0.60: every root below listed a planted skill or command; `.codex/skills`,
|
|
79
|
+
* `.ai/skills`, `$HOME/.config/*` and `$HOME/.agents/plugins` did not) and from
|
|
80
|
+
* the pinned 1.0.34 binary's own skills table (`~/.grok/{skills,commands}`,
|
|
81
|
+
* `~/.claude/{skills,commands}`, `~/.cursor/skills`, `.agents/{skills,commands}`
|
|
82
|
+
* at each tier). `bundled/skills` is the bundled-skill cache: never created on
|
|
83
|
+
* 1.0.34 (P0 container evidence), but a skill planted there loads with a name
|
|
84
|
+
* `[skills] disabled` does not cover. `plugins/` folders load their skills and
|
|
85
|
+
* commands as trusted user plugins.
|
|
86
|
+
*/
|
|
87
|
+
export const GROK_WORKER_FOREIGN_SKILL_ROOTS = Object.freeze({
|
|
88
|
+
grokHome: Object.freeze(["commands", "bundled/skills", "plugins"]),
|
|
89
|
+
home: Object.freeze([".agents/skills", ".agents/commands", ".claude/skills", ".claude/commands", ".cursor/skills", ".cursor/commands"])
|
|
90
|
+
});
|
|
91
|
+
/**
|
|
92
|
+
* Refuses a foreign skill root (`GROK_WORKER_FOREIGN_SKILL_ROOTS`) that exists
|
|
93
|
+
* and is not an empty root-owned read-only directory. A deployment that never
|
|
94
|
+
* creates them passes unchanged. `grokHome` must be `<home>/.grok`, the
|
|
95
|
+
* launcher's layout, so `<home>` is its parent.
|
|
96
|
+
*/
|
|
97
|
+
export async function verifyGrokWorkerForeignSkillRoots(grokHome, rootUid = HOME.directory.uid) {
|
|
98
|
+
if (path.basename(grokHome) !== ".grok")
|
|
99
|
+
throw unavailable();
|
|
100
|
+
const home = path.dirname(grokHome);
|
|
101
|
+
const roots = [...GROK_WORKER_FOREIGN_SKILL_ROOTS.grokHome.map((root) => path.join(grokHome, root)), ...GROK_WORKER_FOREIGN_SKILL_ROOTS.home.map((root) => path.join(home, root))];
|
|
102
|
+
for (const root of roots) {
|
|
103
|
+
let entry;
|
|
104
|
+
try {
|
|
105
|
+
entry = await lstat(root);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
// Absent, or a parent that is not a directory: Grok finds nothing there either.
|
|
109
|
+
if (["ENOENT", "ENOTDIR"].includes(error.code ?? ""))
|
|
110
|
+
continue;
|
|
111
|
+
throw unavailable();
|
|
112
|
+
}
|
|
113
|
+
if (entry.isSymbolicLink() || !entry.isDirectory() || entry.uid !== rootUid || (Number(entry.mode) & 0o7222) !== 0)
|
|
114
|
+
throw unavailable();
|
|
115
|
+
let children;
|
|
116
|
+
try {
|
|
117
|
+
children = await readdir(root);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
throw unavailable();
|
|
121
|
+
}
|
|
122
|
+
if (children.length !== 0)
|
|
123
|
+
throw unavailable();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Attests the worker home layout, that `config.toml` is exactly the
|
|
128
|
+
* renderer's bytes for the declared model policy (`configSha256`), that
|
|
129
|
+
* `skills/` is exactly the declared skills (`skillsSha256`, absent for none),
|
|
130
|
+
* and that no other user skill root holds anything
|
|
131
|
+
* (`verifyGrokWorkerForeignSkillRoots`).
|
|
46
132
|
*/
|
|
47
|
-
export async function verifyGrokWorkerHome(grokHome, configSha256, rootUid = HOME.directory.uid) {
|
|
133
|
+
export async function verifyGrokWorkerHome(grokHome, configSha256, rootUid = HOME.directory.uid, skillsSha256) {
|
|
48
134
|
const entries = {};
|
|
49
135
|
for (const name of [".", HOME.sessionsDirectory.relativePath, ...HOME.readOnlyFiles.names]) {
|
|
50
136
|
try {
|
|
@@ -63,7 +149,10 @@ export async function verifyGrokWorkerHome(grokHome, configSha256, rootUid = HOM
|
|
|
63
149
|
// Same inode as the lstat above, as in `secureOpen`: a rename between the two cannot swap in other bytes.
|
|
64
150
|
if (!opened.isFile() || opened.size > 65_536 || opened.dev !== before.dev || opened.ino !== before.ino || opened.uid !== before.uid || opened.mode !== before.mode || opened.nlink !== 1)
|
|
65
151
|
throw unavailable();
|
|
66
|
-
|
|
152
|
+
const variant = assertGrokWorkerConfigBytes(await handle.readFile(), configSha256);
|
|
153
|
+
await verifyGrokWorkerSkills(grokHome, skillsSha256, rootUid);
|
|
154
|
+
await verifyGrokWorkerForeignSkillRoots(grokHome, rootUid);
|
|
155
|
+
return variant;
|
|
67
156
|
}
|
|
68
157
|
catch {
|
|
69
158
|
throw unavailable();
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where root provisioning renders the agent's declared skills inside the worker
|
|
3
|
+
* home (`$GROK_HOME/skills`), and what every entry must be: root-owned, no
|
|
4
|
+
* write bit. Grok discovers that directory as user-scoped skills even in an
|
|
5
|
+
* untrusted workspace. Absent when the registration declares no `skillsSha256`.
|
|
6
|
+
*
|
|
7
|
+
* Deliberately *not* folded into `RUNTIME_CONTRACT_MANIFEST`, as with
|
|
8
|
+
* `TURN_USAGE_LEDGER`: the manifest's canonical bytes are digest-pinned by
|
|
9
|
+
* Spawnfile and attested against the selected runtime image, so a new key
|
|
10
|
+
* there makes every pinned image fail to attest. Only Daimon reads this layout
|
|
11
|
+
* (the renderer below and the broker's pre-turn attestation); Spawnfile
|
|
12
|
+
* consumes it through `renderGrokWorkerSkillsTree`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const GROK_WORKER_SKILLS_LAYOUT: Readonly<{
|
|
15
|
+
readonly relativePath: "skills";
|
|
16
|
+
readonly uid: 0;
|
|
17
|
+
readonly gid: 0;
|
|
18
|
+
readonly directoryMode: 365;
|
|
19
|
+
readonly fileMode: 292;
|
|
20
|
+
readonly digestVersion: "noopolis.daimon.grok-worker-skills.v1";
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* One file of a declared agent skill, relative to the skill's own directory.
|
|
24
|
+
* `SKILL.md` is required; supporting files (references, scripts) are optional.
|
|
25
|
+
*/
|
|
26
|
+
export type AgentSkillFile = Readonly<{
|
|
27
|
+
path: string;
|
|
28
|
+
content: string;
|
|
29
|
+
}>;
|
|
30
|
+
/** One declared agent skill: its directory name and every file under it. */
|
|
31
|
+
export type AgentSkill = Readonly<{
|
|
32
|
+
name: string;
|
|
33
|
+
files: readonly AgentSkillFile[];
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* The engine-neutral skills input. It is the compiled workspace tree every
|
|
37
|
+
* engine is given — Spawnfile lowers declared skills (and Moltnet installs its
|
|
38
|
+
* own) into `<workspace>/.agents/skills/<name>/SKILL.md`, which Codex reads in
|
|
39
|
+
* place. A brokered Grok worker cannot read it there: its workspace stays
|
|
40
|
+
* untrusted, so root provisioning renders the same skills into
|
|
41
|
+
* `$GROK_HOME/skills` instead.
|
|
42
|
+
*/
|
|
43
|
+
export declare const AGENT_SKILLS_WORKSPACE_DIRECTORY: ".agents/skills";
|
|
44
|
+
export declare const GROK_WORKER_SKILLS_VERSION: "noopolis.daimon.grok-worker-skills.v1";
|
|
45
|
+
export declare const AGENT_SKILLS_BOUNDS: Readonly<{
|
|
46
|
+
skills: 64;
|
|
47
|
+
filesPerSkill: 64;
|
|
48
|
+
fileBytes: 262144;
|
|
49
|
+
totalBytes: 4194304;
|
|
50
|
+
depth: 8;
|
|
51
|
+
}>;
|
|
52
|
+
/**
|
|
53
|
+
* Strict, canonicalizing parser: names and path components are plain
|
|
54
|
+
* identifiers (no `.`/`..`, no hidden entries, no separators other than `/`),
|
|
55
|
+
* every skill carries `SKILL.md`, nothing collides, and the sizes are bounded.
|
|
56
|
+
* Output is sorted by name and path so equal sets digest equally.
|
|
57
|
+
*/
|
|
58
|
+
export declare function parseAgentSkills(value: unknown): readonly AgentSkill[];
|
|
59
|
+
/**
|
|
60
|
+
* sha256 over the canonical description of the rendered tree: every skill's
|
|
61
|
+
* name and, per file, its path, byte length and content digest. The broker
|
|
62
|
+
* attests `$GROK_HOME/skills` against it before every turn, and the Grok broker
|
|
63
|
+
* projection carries it, so the slot preflight receipt and every recomputed
|
|
64
|
+
* projection bind the exact skills a subject was given.
|
|
65
|
+
*/
|
|
66
|
+
export declare function grokWorkerSkillsSha256(skills: readonly AgentSkill[]): string;
|
|
67
|
+
/** One entry root provisioning creates, relative to `$GROK_HOME`, owned `uid:gid`. */
|
|
68
|
+
export type GrokWorkerSkillsEntry = Readonly<{
|
|
69
|
+
path: string;
|
|
70
|
+
kind: "directory" | "file";
|
|
71
|
+
uid: number;
|
|
72
|
+
gid: number;
|
|
73
|
+
mode: number;
|
|
74
|
+
content?: string;
|
|
75
|
+
}>;
|
|
76
|
+
/**
|
|
77
|
+
* Every directory and file root provisioning writes for these skills, parents
|
|
78
|
+
* before children: `skills/` itself, each `skills/<name>/`, any intermediate
|
|
79
|
+
* directory, and each file. Directories are `root:root 0555` and files
|
|
80
|
+
* `root:root 0444` (single link), so a worker-uid process can read them but
|
|
81
|
+
* neither change nor replace them; `$GROK_HOME` is root-owned and sticky, so the
|
|
82
|
+
* worker cannot rename `skills/` away either. No skills renders nothing: the
|
|
83
|
+
* directory must then be absent, exactly as before this layout existed.
|
|
84
|
+
*/
|
|
85
|
+
export declare function renderGrokWorkerSkillsTree(skills: readonly AgentSkill[]): readonly GrokWorkerSkillsEntry[];
|
|
86
|
+
//# sourceMappingURL=grokWorkerSkills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grokWorkerSkills.d.ts","sourceRoot":"","sources":["../../src/runtime/grokWorkerSkills.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB;;;;;;;EAE3B,CAAC;AAGZ;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AACzE,4EAA4E;AAC5E,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,cAAc,EAAE,CAAA;CAAE,CAAC,CAAC;AAEtF;;;;;;;GAOG;AACH,eAAO,MAAM,gCAAgC,EAAG,gBAAyB,CAAC;AAC1E,eAAO,MAAM,0BAA0B,yCAAuB,CAAC;AAC/D,eAAO,MAAM,mBAAmB;;;;;;EAAwG,CAAC;AASzI;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,UAAU,EAAE,CA6BtE;AAID;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAO5E;AAED,sFAAsF;AACtF,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAErJ;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,SAAS,qBAAqB,EAAE,CAiB1G"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { canonicalJson } from "../contracts/canonicalJson.js";
|
|
3
|
+
/**
|
|
4
|
+
* Where root provisioning renders the agent's declared skills inside the worker
|
|
5
|
+
* home (`$GROK_HOME/skills`), and what every entry must be: root-owned, no
|
|
6
|
+
* write bit. Grok discovers that directory as user-scoped skills even in an
|
|
7
|
+
* untrusted workspace. Absent when the registration declares no `skillsSha256`.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately *not* folded into `RUNTIME_CONTRACT_MANIFEST`, as with
|
|
10
|
+
* `TURN_USAGE_LEDGER`: the manifest's canonical bytes are digest-pinned by
|
|
11
|
+
* Spawnfile and attested against the selected runtime image, so a new key
|
|
12
|
+
* there makes every pinned image fail to attest. Only Daimon reads this layout
|
|
13
|
+
* (the renderer below and the broker's pre-turn attestation); Spawnfile
|
|
14
|
+
* consumes it through `renderGrokWorkerSkillsTree`.
|
|
15
|
+
*/
|
|
16
|
+
export const GROK_WORKER_SKILLS_LAYOUT = Object.freeze({
|
|
17
|
+
relativePath: "skills", uid: 0, gid: 0, directoryMode: 0o555, fileMode: 0o444, digestVersion: "noopolis.daimon.grok-worker-skills.v1"
|
|
18
|
+
});
|
|
19
|
+
const LAYOUT = GROK_WORKER_SKILLS_LAYOUT;
|
|
20
|
+
/**
|
|
21
|
+
* The engine-neutral skills input. It is the compiled workspace tree every
|
|
22
|
+
* engine is given — Spawnfile lowers declared skills (and Moltnet installs its
|
|
23
|
+
* own) into `<workspace>/.agents/skills/<name>/SKILL.md`, which Codex reads in
|
|
24
|
+
* place. A brokered Grok worker cannot read it there: its workspace stays
|
|
25
|
+
* untrusted, so root provisioning renders the same skills into
|
|
26
|
+
* `$GROK_HOME/skills` instead.
|
|
27
|
+
*/
|
|
28
|
+
export const AGENT_SKILLS_WORKSPACE_DIRECTORY = ".agents/skills";
|
|
29
|
+
export const GROK_WORKER_SKILLS_VERSION = LAYOUT.digestVersion;
|
|
30
|
+
export const AGENT_SKILLS_BOUNDS = Object.freeze({ skills: 64, filesPerSkill: 64, fileBytes: 262_144, totalBytes: 4_194_304, depth: 8 });
|
|
31
|
+
const COMPONENT = /^[A-Za-z0-9_][A-Za-z0-9._-]{0,127}$/u;
|
|
32
|
+
const invalid = (detail) => new TypeError(`invalid agent skills: ${detail}`);
|
|
33
|
+
const plain = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
34
|
+
const exact = (value, keys) => Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
35
|
+
const byteLength = (content) => Buffer.byteLength(content, "utf8");
|
|
36
|
+
/**
|
|
37
|
+
* Strict, canonicalizing parser: names and path components are plain
|
|
38
|
+
* identifiers (no `.`/`..`, no hidden entries, no separators other than `/`),
|
|
39
|
+
* every skill carries `SKILL.md`, nothing collides, and the sizes are bounded.
|
|
40
|
+
* Output is sorted by name and path so equal sets digest equally.
|
|
41
|
+
*/
|
|
42
|
+
export function parseAgentSkills(value) {
|
|
43
|
+
if (!Array.isArray(value) || value.length > AGENT_SKILLS_BOUNDS.skills)
|
|
44
|
+
throw invalid("expected a bounded array");
|
|
45
|
+
let total = 0;
|
|
46
|
+
const names = new Set();
|
|
47
|
+
const skills = value.map((entry) => {
|
|
48
|
+
if (!plain(entry) || !exact(entry, ["name", "files"]) || typeof entry.name !== "string" || !COMPONENT.test(entry.name))
|
|
49
|
+
throw invalid(`skill name ${plain(entry) && typeof entry.name === "string" ? JSON.stringify(entry.name) : "(missing)"}`);
|
|
50
|
+
if (names.has(entry.name))
|
|
51
|
+
throw invalid(`duplicate skill ${entry.name}`);
|
|
52
|
+
names.add(entry.name);
|
|
53
|
+
if (!Array.isArray(entry.files) || entry.files.length === 0 || entry.files.length > AGENT_SKILLS_BOUNDS.filesPerSkill)
|
|
54
|
+
throw invalid(`files of ${entry.name}`);
|
|
55
|
+
const paths = new Set();
|
|
56
|
+
const files = entry.files.map((file) => {
|
|
57
|
+
if (!plain(file) || !exact(file, ["path", "content"]) || typeof file.path !== "string" || typeof file.content !== "string")
|
|
58
|
+
throw invalid(`file ${plain(file) && typeof file.path === "string" ? JSON.stringify(`${entry.name}/${file.path}`) : `of ${entry.name}`}`);
|
|
59
|
+
const parts = file.path.split("/");
|
|
60
|
+
if (parts.length > AGENT_SKILLS_BOUNDS.depth || parts.some((part) => !COMPONENT.test(part)))
|
|
61
|
+
throw invalid(`path ${JSON.stringify(`${entry.name}/${file.path}`)}`);
|
|
62
|
+
const bytes = byteLength(file.content);
|
|
63
|
+
if (bytes > AGENT_SKILLS_BOUNDS.fileBytes)
|
|
64
|
+
throw invalid(`size of ${entry.name}/${file.path}`);
|
|
65
|
+
total += bytes;
|
|
66
|
+
if (paths.has(file.path))
|
|
67
|
+
throw invalid(`duplicate path ${entry.name}/${file.path}`);
|
|
68
|
+
paths.add(file.path);
|
|
69
|
+
try {
|
|
70
|
+
canonicalJson(file.content);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
throw invalid(`content of ${entry.name}/${file.path} is not Unicode text`);
|
|
74
|
+
}
|
|
75
|
+
return Object.freeze({ path: file.path, content: file.content });
|
|
76
|
+
});
|
|
77
|
+
// A file may not also be the directory of another file.
|
|
78
|
+
for (const candidate of paths)
|
|
79
|
+
if ([...paths].some((other) => other.startsWith(`${candidate}/`)))
|
|
80
|
+
throw invalid(`path collision ${entry.name}/${candidate}`);
|
|
81
|
+
if (!paths.has("SKILL.md"))
|
|
82
|
+
throw invalid(`${entry.name} has no SKILL.md`);
|
|
83
|
+
return Object.freeze({ name: entry.name, files: Object.freeze(files.sort((a, b) => compare(a.path, b.path))) });
|
|
84
|
+
});
|
|
85
|
+
if (total > AGENT_SKILLS_BOUNDS.totalBytes)
|
|
86
|
+
throw invalid("total size");
|
|
87
|
+
return Object.freeze(skills.sort((a, b) => compare(a.name, b.name)));
|
|
88
|
+
}
|
|
89
|
+
const compare = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
90
|
+
/**
|
|
91
|
+
* sha256 over the canonical description of the rendered tree: every skill's
|
|
92
|
+
* name and, per file, its path, byte length and content digest. The broker
|
|
93
|
+
* attests `$GROK_HOME/skills` against it before every turn, and the Grok broker
|
|
94
|
+
* projection carries it, so the slot preflight receipt and every recomputed
|
|
95
|
+
* projection bind the exact skills a subject was given.
|
|
96
|
+
*/
|
|
97
|
+
export function grokWorkerSkillsSha256(skills) {
|
|
98
|
+
const parsed = parseAgentSkills(skills);
|
|
99
|
+
const description = { version: GROK_WORKER_SKILLS_VERSION, skills: parsed.map((skill) => ({
|
|
100
|
+
name: skill.name,
|
|
101
|
+
files: skill.files.map((file) => ({ path: file.path, bytes: byteLength(file.content), sha256: createHash("sha256").update(file.content, "utf8").digest("hex") }))
|
|
102
|
+
})) };
|
|
103
|
+
return createHash("sha256").update(canonicalJson(description)).digest("hex");
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Every directory and file root provisioning writes for these skills, parents
|
|
107
|
+
* before children: `skills/` itself, each `skills/<name>/`, any intermediate
|
|
108
|
+
* directory, and each file. Directories are `root:root 0555` and files
|
|
109
|
+
* `root:root 0444` (single link), so a worker-uid process can read them but
|
|
110
|
+
* neither change nor replace them; `$GROK_HOME` is root-owned and sticky, so the
|
|
111
|
+
* worker cannot rename `skills/` away either. No skills renders nothing: the
|
|
112
|
+
* directory must then be absent, exactly as before this layout existed.
|
|
113
|
+
*/
|
|
114
|
+
export function renderGrokWorkerSkillsTree(skills) {
|
|
115
|
+
const parsed = parseAgentSkills(skills);
|
|
116
|
+
if (parsed.length === 0)
|
|
117
|
+
return Object.freeze([]);
|
|
118
|
+
const directory = (relative) => Object.freeze({ path: relative, kind: "directory", uid: LAYOUT.uid, gid: LAYOUT.gid, mode: LAYOUT.directoryMode });
|
|
119
|
+
const entries = [directory(LAYOUT.relativePath)];
|
|
120
|
+
const seen = new Set([LAYOUT.relativePath]);
|
|
121
|
+
for (const skill of parsed) {
|
|
122
|
+
for (const file of skill.files) {
|
|
123
|
+
const parts = [LAYOUT.relativePath, skill.name, ...file.path.split("/")];
|
|
124
|
+
for (let depth = 2; depth < parts.length; depth += 1) {
|
|
125
|
+
const relative = parts.slice(0, depth).join("/");
|
|
126
|
+
if (!seen.has(relative)) {
|
|
127
|
+
seen.add(relative);
|
|
128
|
+
entries.push(directory(relative));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
entries.push(Object.freeze({ path: parts.join("/"), kind: "file", uid: LAYOUT.uid, gid: LAYOUT.gid, mode: LAYOUT.fileMode, content: file.content }));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return Object.freeze(entries);
|
|
135
|
+
}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -18,6 +18,9 @@ export { GROK_INFERENCE_AUTH_STALE_BODY } from "./grokInferenceProxy.js";
|
|
|
18
18
|
export { assertGrokWorkerDenyPathPlacement, assertGrokWorkerDenyPathShape, assertGrokWorkerDenyPathsPlaceable, GROK_WORKER_BASE_PROFILE_GRANTS, grokWorkerCanSearch, grokWorkerDenyPathChain, GrokWorkerDenyPlacementError, readGrokWorkerDenyPathChain } from "./grokWorkerDenyPlacement.js";
|
|
19
19
|
export type { GrokWorkerDenyPathEntry, GrokWorkerDenyPathStep, GrokWorkerDenyPathWorker } from "./grokWorkerDenyPlacement.js";
|
|
20
20
|
export { grokWorkerSandboxProfileSha256, renderGrokWorkerSandboxProfile } from "./grokWorkerSandboxProfile.js";
|
|
21
|
+
export { AGENT_SKILLS_BOUNDS, AGENT_SKILLS_WORKSPACE_DIRECTORY, GROK_WORKER_SKILLS_LAYOUT, GROK_WORKER_SKILLS_VERSION, grokWorkerSkillsSha256, parseAgentSkills, renderGrokWorkerSkillsTree, type AgentSkill, type AgentSkillFile, type GrokWorkerSkillsEntry } from "./grokWorkerSkills.js";
|
|
22
|
+
export { readAgentSkillsDirectory, type AgentSkillsTreePolicy } from "./agentSkillsDirectory.js";
|
|
23
|
+
export { GROK_WORKER_FOREIGN_SKILL_ROOTS, verifyGrokWorkerForeignSkillRoots, verifyGrokWorkerSkills } from "./grokWorkerHomeAttestation.js";
|
|
21
24
|
export { ENGINE_BROKER_SERVICE_V3, engineBrokerRequestLedgerPathFor, engineBrokerSealLedgerPathFor, parseEngineBrokerServiceConfig, type EngineBrokerServiceConfig, type EngineBrokerServiceRegistration } from "./engineBrokerServiceConfig.js";
|
|
22
25
|
export { TURN_SEAL_LEDGER, TURN_SEAL_LEDGER_VERSION } from "./engineBrokerSealLedger.js";
|
|
23
26
|
export { DEFAULT_GROK_BROKER_TURN_LIMITS, ENGINE_BROKER_LIMIT_REASONS, type EngineBrokerLimitReason, type EngineBrokerTurnAccounting, type EngineBrokerTurnLimits, type EngineBrokerTurnUsage } from "./engineBrokerTurnAccounting.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,mCAAmC,EAAE,gCAAgC,EAAE,KAAK,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAClL,cAAc,0BAA0B,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAC/F,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpE,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAE,oCAAoC,EAAE,MAAM,iCAAiC,CAAC;AACvF,OAAO,EAAE,gCAAgC,EAAE,yCAAyC,EAClF,KAAK,kCAAkC,EAAE,MAAM,6BAA6B,CAAC;AAC/E,OAAO,EAAE,8BAA8B,EAAE,0BAA0B,EAAE,gCAAgC,EAAE,uCAAuC,EAC5I,6CAA6C,EAAE,KAAK,gCAAgC,EAAE,KAAK,uCAAuC,EAAE,MAAM,2BAA2B,CAAC;AACxK,OAAO,EAAE,2BAA2B,EAAE,6BAA6B,EAAE,8BAA8B,EAAE,6BAA6B,EAAE,KAAK,0BAA0B,EACjK,8BAA8B,EAAE,KAAK,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACvG,OAAO,EAAE,4BAA4B,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAC;AACzG,OAAO,EAAE,8BAA8B,EAAE,wBAAwB,EAAE,+BAA+B,EAAE,+BAA+B,EAAE,yCAAyC,EAAE,KAAK,8BAA8B,EAAE,MAAM,gCAAgC,CAAC;AAC5P,OAAO,EAAE,6BAA6B,EAAE,qCAAqC,EAAE,KAAK,gCAAgC,EAAE,MAAM,oCAAoC,CAAC;AACjK,OAAO,EAAE,wBAAwB,EAAE,8BAA8B,EAAE,uBAAuB,EAAE,KAAK,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACzJ,OAAO,EAAE,8BAA8B,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAAE,iCAAiC,EAAE,6BAA6B,EAAE,kCAAkC,EAAE,+BAA+B,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC9R,YAAY,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAC9H,OAAO,EAAE,8BAA8B,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAC/G,OAAO,EAAE,mBAAmB,EAAE,gCAAgC,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC7R,OAAO,EAAE,wBAAwB,EAAE,KAAK,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACjG,OAAO,EAAE,+BAA+B,EAAE,iCAAiC,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAC5I,OAAO,EAAE,wBAAwB,EAAE,gCAAgC,EAAE,6BAA6B,EAAE,8BAA8B,EAAE,KAAK,yBAAyB,EAAE,KAAK,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AACjP,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACzF,OAAO,EAAE,+BAA+B,EAAE,2BAA2B,EAAE,KAAK,uBAAuB,EAAE,KAAK,0BAA0B,EAClI,KAAK,sBAAsB,EAAE,KAAK,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,EACL,mCAAmC,EACnC,qCAAqC,EACrC,8BAA8B,EAC9B,yCAAyC,EACzC,2CAA2C,EAC3C,2CAA2C,EAC3C,8BAA8B,EAC9B,KAAK,4BAA4B,EACjC,KAAK,mDAAmD,EACxD,KAAK,sCAAsC,EAC3C,KAAK,2CAA2C,EAChD,KAAK,sCAAsC,EAC3C,KAAK,sCAAsC,EAC3C,KAAK,qCAAqC,EAC3C,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,yBAAyB,EACzB,gCAAgC,EAChC,uBAAuB,EACvB,8BAA8B,EAC9B,2BAA2B,EAC3B,0BAA0B,EAC1B,eAAe,EACf,0BAA0B,EAC1B,oBAAoB,EACpB,KAAK,iCAAiC,EACtC,KAAK,wCAAwC,EAC7C,KAAK,uCAAuC,EAC5C,KAAK,oCAAoC,EACzC,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,8BAA8B,EAAE,iCAAiC,EAAE,MAAM,iCAAiC,CAAC;AACzH,OAAO,EAAE,yBAAyB,EAAE,iCAAiC,EAAE,KAAK,0BAA0B,EAAE,KAAK,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAC7K,YAAY,EAAE,kCAAkC,EAAE,MAAM,8BAA8B,CAAC"}
|
package/dist/runtime/index.js
CHANGED
|
@@ -17,6 +17,9 @@ export { dedupeInferenceUsageRows, INFERENCE_USAGE_LEDGER_VERSION, GROK_INFERENC
|
|
|
17
17
|
export { GROK_INFERENCE_AUTH_STALE_BODY } from "./grokInferenceProxy.js";
|
|
18
18
|
export { assertGrokWorkerDenyPathPlacement, assertGrokWorkerDenyPathShape, assertGrokWorkerDenyPathsPlaceable, GROK_WORKER_BASE_PROFILE_GRANTS, grokWorkerCanSearch, grokWorkerDenyPathChain, GrokWorkerDenyPlacementError, readGrokWorkerDenyPathChain } from "./grokWorkerDenyPlacement.js";
|
|
19
19
|
export { grokWorkerSandboxProfileSha256, renderGrokWorkerSandboxProfile } from "./grokWorkerSandboxProfile.js";
|
|
20
|
+
export { AGENT_SKILLS_BOUNDS, AGENT_SKILLS_WORKSPACE_DIRECTORY, GROK_WORKER_SKILLS_LAYOUT, GROK_WORKER_SKILLS_VERSION, grokWorkerSkillsSha256, parseAgentSkills, renderGrokWorkerSkillsTree } from "./grokWorkerSkills.js";
|
|
21
|
+
export { readAgentSkillsDirectory } from "./agentSkillsDirectory.js";
|
|
22
|
+
export { GROK_WORKER_FOREIGN_SKILL_ROOTS, verifyGrokWorkerForeignSkillRoots, verifyGrokWorkerSkills } from "./grokWorkerHomeAttestation.js";
|
|
20
23
|
export { ENGINE_BROKER_SERVICE_V3, engineBrokerRequestLedgerPathFor, engineBrokerSealLedgerPathFor, parseEngineBrokerServiceConfig } from "./engineBrokerServiceConfig.js";
|
|
21
24
|
export { TURN_SEAL_LEDGER, TURN_SEAL_LEDGER_VERSION } from "./engineBrokerSealLedger.js";
|
|
22
25
|
export { DEFAULT_GROK_BROKER_TURN_LIMITS, ENGINE_BROKER_LIMIT_REASONS } from "./engineBrokerTurnAccounting.js";
|
|
@@ -226,7 +226,7 @@ function moltnetTool(agent, wakeContext) {
|
|
|
226
226
|
}
|
|
227
227
|
async function connect(agent, server) {
|
|
228
228
|
taskClockChildEnvironment(server.env);
|
|
229
|
-
const client = new Client({ name: "daimon-production", version: "0.2.
|
|
229
|
+
const client = new Client({ name: "daimon-production", version: "0.2.2" });
|
|
230
230
|
const headers = server.authSecretEnv === undefined ? {} : { authorization: `Bearer ${requiredSecret(server.authSecretEnv)}` };
|
|
231
231
|
const transport = server.transport === "stdio"
|
|
232
232
|
? new StdioClientTransport({ command: server.command, args: [...server.args], env: stringEnvironment(readyTaskClockEnvironment({ ...server.env, ...cliChildEnvironment([], agent.runtimeHomePath, { executablePath: server.command }) })) })
|