Skip to content

Commit fd4efaf

Browse files
committed
sync(bfmono): fix(gambit-server): persist and catch backend errors across build/test/grade (+19 more) (bfmono@21e6b4d37)
This PR is an automated gambitmono sync of bfmono Gambit packages. - Source: `packages/gambit/` - Core: `packages/gambit-core/` - bfmono rev: 21e6b4d37 Changes: - 21e6b4d37 fix(gambit-server): persist and catch backend errors across build/test/grade - 29eaa58b7 fix(gambit): enforce inherited permissions in OpenAI compat actions - d502df5cd feat(gambit-core): add permission-gated built-in file tooling - c04141504 feat(gambit-cli): add session permission override flags - 85442ffcd test(gambit-core): add worker bootstrap permission regressions - 08bab3af1 feat(gambit-core): add worker compute runner with bridged permissions - 70ec3b942 feat(gambit): add tool-call-aware grader schemas and root-deck guards - cae381f00 feat(gambit): align scaffolds with product command and hourglass policies - 5faa48b35 feat(gambit): move bot policy to folder and enforce policy summarizer flow - 9a36c4a7e fix(gambit): align env loading with init and block .gambit env writes - dbe7c54ca feat(gambit-bot): add file actions and scenario deck structure - 855784d6b docs(gambit): add public permissions guide and API jsdoc - 8f0ca0a85 feat(gambit): trace effective permission layers at runtime - 90b4b5071 feat(gambit-core): add phase-1 permission contract primitives - df9280f6a fix(gambit): restore build-bot deck path compatibility - daca46555 feat(simulator-ui): wire build, test, and grade to workspace sessions - e404a17d7 feat(gambit): add workspace-backed serve and bot sandbox flow - 5f4fa86b9 feat(gambit): scaffold workspace defaults in init - cf9b23778 feat(gambit-core): add schema guards and model param passthrough - d0e5a9617 [gambit] move chat message into transcript so it scrolls Do not edit this repo directly; make changes in bfmono and re-run the sync.
1 parent 5356ee6 commit fd4efaf

17 files changed

Lines changed: 5876 additions & 2590 deletions

File tree

docs/external/reference/cli/commands/repl.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
+++
22
command = "repl"
33
summary = "Start an interactive REPL"
4-
usage = "gambit repl <deck.(ts|md)> [--context <json|string>] [--message <json|string>] [--model <id>] [--model-force <id>] [--responses] [--verbose]"
4+
usage = "gambit repl <deck.(ts|md)> [--context <json|string>] [--message <json|string>] [--model <id>] [--model-force <id>] [--responses] [--verbose] [-A|--allow-all|--allow-<kind>] [--sandbox|--no-sandbox]"
55
flags = [
66
"--context <json|string> Context payload (seeds gambit_context; legacy --init still works)",
77
"--message <json|string> Initial user message (sent before assistant speaks)",
88
"--model <id> Default model id",
99
"--model-force <id> Override model id",
1010
"--responses Run runtime/state in Responses mode",
1111
"--verbose Print trace events to console",
12+
"-A, --allow-all Allow all session permissions (read/write/run/net/env)",
13+
"--allow-read[=<paths>] Session read override (all when value omitted)",
14+
"--allow-write[=<paths>] Session write override (all when value omitted)",
15+
"--allow-run[=<entries>] Session run override (all when value omitted)",
16+
"--allow-net[=<hosts>] Session net override (all when value omitted)",
17+
"--allow-env[=<names>] Session env override (all when value omitted)",
18+
"--sandbox Force worker sandbox on",
19+
"--no-sandbox Force worker sandbox off",
1220
]
1321
+++
1422

docs/external/reference/cli/commands/run.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
+++
22
command = "run"
33
summary = "Run a deck once"
4-
usage = "gambit run [<deck.(ts|md)>] [--context <json|string>] [--message <json|string>] [--model <id>] [--model-force <id>] [--trace <file>] [--state <file>] [--stream] [--responses] [--verbose]"
4+
usage = "gambit run [<deck.(ts|md)>] [--context <json|string>] [--message <json|string>] [--model <id>] [--model-force <id>] [--trace <file>] [--state <file>] [--stream] [--responses] [--verbose] [-A|--allow-all|--allow-<kind>] [--sandbox|--no-sandbox]"
55
flags = [
66
"--context <json|string> Context payload (seeds gambit_context; legacy --init still works)",
77
"--message <json|string> Initial user message (sent before assistant speaks)",
@@ -12,6 +12,14 @@ flags = [
1212
"--stream Enable streaming responses",
1313
"--responses Run runtime/state in Responses mode",
1414
"--verbose Print trace events to console",
15+
"-A, --allow-all Allow all session permissions (read/write/run/net/env)",
16+
"--allow-read[=<paths>] Session read override (all when value omitted)",
17+
"--allow-write[=<paths>] Session write override (all when value omitted)",
18+
"--allow-run[=<entries>] Session run override (all when value omitted)",
19+
"--allow-net[=<hosts>] Session net override (all when value omitted)",
20+
"--allow-env[=<names>] Session env override (all when value omitted)",
21+
"--sandbox Force worker sandbox on",
22+
"--no-sandbox Force worker sandbox off",
1523
]
1624
+++
1725

packages/gambit-core/src/permissions.test.ts

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import { assert, assertEquals } from "@std/assert";
1+
import { assert, assertEquals, assertThrows } from "@std/assert";
22
import * as path from "@std/path";
33
import {
44
canReadPath,
55
canRunCommand,
66
canRunPath,
77
normalizePermissionDeclaration,
88
normalizePermissionDeclarationToSet,
9+
type PermissionDeclarationInput,
910
resolveEffectivePermissions,
1011
} from "./permissions.ts";
1112

@@ -147,22 +148,33 @@ Deno.test("run grants keep path vs command semantics separate", () => {
147148
assertEquals(canRunCommand(set, "bin/tool"), false);
148149
});
149150

150-
Deno.test("run object-form booleans honor all-access semantics", () => {
151-
const pathsTrue = normalizePermissionDeclarationToSet(
152-
{ run: { paths: true } },
151+
Deno.test("run=true grants all run access", () => {
152+
const runAll = normalizePermissionDeclarationToSet(
153+
{ run: true },
153154
"/workspace",
154155
);
155-
assert(pathsTrue, "expected normalized permission set for paths=true");
156-
assertEquals(canRunPath(pathsTrue, "/workspace/bin/anything"), true);
157-
assertEquals(canRunCommand(pathsTrue, "anything"), true);
156+
assert(runAll, "expected normalized permission set for run=true");
157+
assertEquals(canRunPath(runAll, "/workspace/bin/anything"), true);
158+
assertEquals(canRunCommand(runAll, "anything"), true);
159+
});
158160

159-
const commandsTrue = normalizePermissionDeclarationToSet(
160-
{ run: { commands: true } },
161-
"/workspace",
161+
Deno.test("run object-form booleans are rejected", () => {
162+
const invalidPaths = {
163+
run: { paths: true },
164+
} as unknown as PermissionDeclarationInput;
165+
const invalidCommands = {
166+
run: { commands: false },
167+
} as unknown as PermissionDeclarationInput;
168+
assertThrows(
169+
() => normalizePermissionDeclarationToSet(invalidPaths, "/workspace"),
170+
Error,
171+
"permissions.run.paths must be an array in object form",
172+
);
173+
assertThrows(
174+
() => normalizePermissionDeclarationToSet(invalidCommands, "/workspace"),
175+
Error,
176+
"permissions.run.commands must be an array in object form",
162177
);
163-
assert(commandsTrue, "expected normalized permission set for commands=true");
164-
assertEquals(canRunPath(commandsTrue, "/workspace/bin/anything"), true);
165-
assertEquals(canRunCommand(commandsTrue, "anything"), true);
166178
});
167179

168180
Deno.test("unspecified kinds deny by default when a layer is provided", () => {

packages/gambit-core/src/permissions.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ export type RunPermissionInput =
1111
| boolean
1212
| Array<string>
1313
| {
14-
paths?: boolean | Array<string>;
15-
commands?: boolean | Array<string>;
14+
paths?: Array<string>;
15+
commands?: Array<string>;
1616
};
1717

1818
export type PermissionDeclarationInput = Partial<{
@@ -175,19 +175,22 @@ function normalizeRun(
175175
paths?: unknown;
176176
commands?: unknown;
177177
};
178+
if (typeof record.paths === "boolean") {
179+
throw new Error(
180+
"permissions.run.paths must be an array in object form; use permissions.run=true for full run access",
181+
);
182+
}
183+
if (typeof record.commands === "boolean") {
184+
throw new Error(
185+
"permissions.run.commands must be an array in object form; use permissions.run=true for full run access",
186+
);
187+
}
178188
const pathsScope = normalizeList(record.paths, "run", baseDir, {
179189
resolvePaths: true,
180190
});
181191
const commandsScope = normalizeList(record.commands, "run", baseDir, {
182192
resolvePaths: false,
183193
});
184-
if (pathsScope.all || commandsScope.all) {
185-
return {
186-
all: true,
187-
paths: new Set<string>(),
188-
commands: new Set<string>(),
189-
};
190-
}
191194
return {
192195
all: false,
193196
paths: pathsScope.values,

0 commit comments

Comments
 (0)