Skip to content

Commit 8baddf9

Browse files
committed
refactor(policy): name the Pi trust boundary in the project's own terms
Documentation review found the new text drifting from repository vocabulary. The check reported failures with "denies" where every neighbouring case says "rejects", used "writable" where the controlled term for a path that also permits reads is "read-write", and justified two manifest rules by an unnamed "v1 surface". The module summary listed four of the eight boundaries the check binds. The endpoint enforcement mode and the device-pairing rule now have the cases they were missing, and the endpoint-count rule is asserted rather than merely reached. Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
1 parent 973c35b commit 8baddf9

3 files changed

Lines changed: 50 additions & 25 deletions

File tree

scripts/checks/pi-candidate-artifacts.mts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,17 @@
1212
* candidate contract artifact name stays outside the all-agent cohort download
1313
* pattern.
1414
*
15-
* It also binds the accepted Pi trust boundary: the baseline permits only the
16-
* managed inference route from root-owned image binaries, writable paths stay
17-
* on the declared sandbox state, non-interactive runs keep passing the flag
18-
* that ignores project-local resources, and neither the project-trust store nor
19-
* the project-trust setting can travel through backup and restore.
15+
* It also binds the accepted Pi trust boundary:
16+
*
17+
* - The baseline network policy permits only the managed inference route, and
18+
* only root-owned image binaries carry network capability.
19+
* - The read-write paths stay /dev/null, /sandbox, /sandbox/.pi, and /tmp, and
20+
* Landlock stays strict so filesystem policy fails closed.
21+
* - Pi runs as the sandbox user and group.
22+
* - The headless command passes the flag that ignores project-local resources,
23+
* MCP stays disabled, and device pairing stays off.
24+
* - Neither the project-trust store nor the project-trust setting is declared
25+
* in the manifest state that backup and restore carry.
2026
*/
2127

2228
import { createHash } from "node:crypto";
@@ -324,7 +330,7 @@ function verifyFilesystemBoundary(policy: LooseRecord): string[] {
324330
const readWrite = sortedStrings(filesystem.read_write);
325331
if (!sameSet(readWrite, APPROVED_READ_WRITE_PATHS)) {
326332
failures.push(
327-
`${PI_POLICY_PATH}: writable paths must stay ${APPROVED_READ_WRITE_PATHS.join(", ")}, found ${readWrite.join(", ") || "none"}`,
333+
`${PI_POLICY_PATH}: read-write paths must stay ${APPROVED_READ_WRITE_PATHS.join(", ")}, found ${readWrite.join(", ") || "none"}`,
328334
);
329335
}
330336
if (asRecord(policy.landlock).compatibility !== REQUIRED_LANDLOCK_COMPATIBILITY) {
@@ -352,10 +358,10 @@ function verifyApprovalBoundary(manifest: LooseRecord): string[] {
352358
);
353359
}
354360
if (asRecord(manifest.mcp).support !== "disabled") {
355-
failures.push(`${PI_MANIFEST_PATH}: mcp.support must stay disabled for the accepted v1 surface`);
361+
failures.push(`${PI_MANIFEST_PATH}: mcp.support must stay disabled`);
356362
}
357363
if (manifest.device_pairing !== false) {
358-
failures.push(`${PI_MANIFEST_PATH}: device_pairing must stay false for the accepted v1 surface`);
364+
failures.push(`${PI_MANIFEST_PATH}: device_pairing must stay false`);
359365
}
360366
return failures;
361367
}

src/lib/policy/agent-base-preset.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ describe("agent base preset detection", () => {
6767
expect(isAgentBasePreset("hermes", "pypi")).toBe(true);
6868
});
6969

70-
it("keeps a catalog preset outside the Pi baseline so external access stays an explicit choice (#7924)", () => {
70+
it("reports pypi and github as non-baseline presets for the Pi policy (#7924)", () => {
7171
const piPolicy = fs.readFileSync(path.join(AGENTS_DIR, "pi", "policy-additions.yaml"), "utf8");
7272
const agent = createAgentFixture(piPolicy);
7373
vi.spyOn(registry, "getSandbox").mockReturnValue({ name: "pi", agent } as never);

test/pi-candidate-runtime-artifacts.test.ts

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -207,11 +207,11 @@ describe("Pi candidate contract validation", () => {
207207
});
208208

209209
describe("Pi runtime boundaries", () => {
210-
it("accepts the trust boundary committed in this repository (#7924)", () => {
210+
it("accepts the Pi trust boundary committed in this repository (#7924)", () => {
211211
expect(verifyPiTrustBoundary(currentSources())).toEqual([]);
212212
});
213213

214-
it("denies a direct provider endpoint added beside the managed route (#7924)", () => {
214+
it("rejects a direct provider endpoint added beside the managed route (#7924)", () => {
215215
const sources = withPolicy((policy) => {
216216
policy.network_policies.managed_inference.endpoints.push({
217217
host: "api.openai.com",
@@ -221,12 +221,13 @@ describe("Pi runtime boundaries", () => {
221221
rules: [{ allow: { method: "POST", path: "/v1/chat/completions" } }],
222222
});
223223
});
224-
expect(verifyPiTrustBoundary(sources)).toContain(
224+
expect(verifyPiTrustBoundary(sources)).toEqual([
225+
"agents/pi/policy-additions.yaml: managed_inference must declare exactly one endpoint",
225226
"agents/pi/policy-additions.yaml: the baseline permits only inference.local:443",
226-
);
227+
]);
227228
});
228229

229-
it("denies a package registry policy the baseline never selected (#7924)", () => {
230+
it("rejects a package registry policy added to the Pi baseline (#7924)", () => {
230231
const sources = withPolicy((policy) => {
231232
policy.network_policies.npm_registry = {
232233
name: "npm_registry",
@@ -238,7 +239,7 @@ describe("Pi runtime boundaries", () => {
238239
);
239240
});
240241

241-
it("denies network capability to a binary the agent can write (#7924)", () => {
242+
it("rejects an agent-writable binary in the network policy (#7924)", () => {
242243
const sources = withPolicy((policy) => {
243244
policy.network_policies.managed_inference.binaries.push({ path: "/sandbox/agent-proxy" });
244245
});
@@ -247,7 +248,7 @@ describe("Pi runtime boundaries", () => {
247248
);
248249
});
249250

250-
it("denies a rule that widens the managed route beyond its versioned paths (#7924)", () => {
251+
it("rejects a managed inference rule that allows a path outside /v1/ (#7924)", () => {
251252
const sources = withPolicy((policy) => {
252253
policy.network_policies.managed_inference.endpoints[0].rules.push({
253254
allow: { method: "GET", path: "/**" },
@@ -258,16 +259,34 @@ describe("Pi runtime boundaries", () => {
258259
);
259260
});
260261

261-
it("denies a container-runtime socket added to the writable paths (#7924)", () => {
262+
it("rejects a managed inference endpoint that is observed instead of enforced (#7924)", () => {
263+
const sources = withPolicy((policy) => {
264+
policy.network_policies.managed_inference.endpoints[0].enforcement = "observe";
265+
});
266+
expect(verifyPiTrustBoundary(sources)).toContain(
267+
"agents/pi/policy-additions.yaml: inference.local must stay enforced, not observed",
268+
);
269+
});
270+
271+
it("rejects a manifest that enables device pairing (#7924)", () => {
272+
const sources = withManifest((manifest) => {
273+
manifest.device_pairing = true;
274+
});
275+
expect(verifyPiTrustBoundary(sources)).toContain(
276+
"agents/pi/manifest.yaml: device_pairing must stay false",
277+
);
278+
});
279+
280+
it("rejects a container-runtime socket added to the read-write paths (#7924)", () => {
262281
const sources = withPolicy((policy) => {
263282
policy.filesystem_policy.read_write.push("/var/run/docker.sock");
264283
});
265284
expect(verifyPiTrustBoundary(sources).join("\n")).toContain(
266-
"writable paths must stay /dev/null, /sandbox, /sandbox/.pi, /tmp",
285+
"read-write paths must stay /dev/null, /sandbox, /sandbox/.pi, /tmp",
267286
);
268287
});
269288

270-
it("denies a relaxed Landlock compatibility that would start with policy unenforced (#7924)", () => {
289+
it("rejects a Landlock compatibility that does not fail closed (#7924)", () => {
271290
const sources = withPolicy((policy) => {
272291
policy.landlock.compatibility = "best-effort";
273292
});
@@ -276,7 +295,7 @@ describe("Pi runtime boundaries", () => {
276295
);
277296
});
278297

279-
it("denies host control by refusing a privileged process identity (#7924)", () => {
298+
it("rejects a root process identity in the Pi policy (#7924)", () => {
280299
const sources = withPolicy((policy) => {
281300
policy.process.run_as_user = "root";
282301
});
@@ -285,7 +304,7 @@ describe("Pi runtime boundaries", () => {
285304
);
286305
});
287306

288-
it("denies a non-interactive command that stops ignoring project-local resources (#7924)", () => {
307+
it("rejects a headless command that omits --no-approve (#7924)", () => {
289308
const sources = withManifest((manifest) => {
290309
manifest.runtime.headless_command = "pi --print";
291310
});
@@ -294,16 +313,16 @@ describe("Pi runtime boundaries", () => {
294313
);
295314
});
296315

297-
it("denies an MCP surface the accepted v1 scope excludes (#7924)", () => {
316+
it("rejects an enabled MCP surface in the Pi manifest (#7924)", () => {
298317
const sources = withManifest((manifest) => {
299318
manifest.mcp.support = "enabled";
300319
});
301320
expect(verifyPiTrustBoundary(sources)).toContain(
302-
"agents/pi/manifest.yaml: mcp.support must stay disabled for the accepted v1 surface",
321+
"agents/pi/manifest.yaml: mcp.support must stay disabled",
303322
);
304323
});
305324

306-
it("denies a project-trust store that a restore could carry into a new sandbox (#7924)", () => {
325+
it("rejects a manifest that declares the trust.json project-trust store (#7924)", () => {
307326
const sources = withManifest((manifest) => {
308327
manifest.state_files.push({ path: "trust.json" });
309328
});
@@ -312,7 +331,7 @@ describe("Pi runtime boundaries", () => {
312331
);
313332
});
314333

315-
it("denies a restore allowlist that could widen project trust (#7924)", () => {
334+
it("rejects defaultProjectTrust in the restore allowlist (#7924)", () => {
316335
const sources = withManifest((manifest) => {
317336
manifest.state_files[0].restore.user_keys.push({
318337
key: "defaultProjectTrust",

0 commit comments

Comments
 (0)