Skip to content

docs: add sandbox config floors feature spec - #779

Open
Alexander Sklar (asklar) wants to merge 1 commit into
mainfrom
user/asklar/sandbox-tool-config-floors
Open

docs: add sandbox config floors feature spec#779
Alexander Sklar (asklar) wants to merge 1 commit into
mainfrom
user/asklar/sandbox-tool-config-floors

Conversation

@asklar

@asklar Alexander Sklar (asklar) commented Aug 8, 2026

Copy link
Copy Markdown
Member

📖 Description

Design review requested. No implementation in this PR.

Adds a feature spec (docs/sandbox-config-floors.md) proposing config floors: a repository-hosted table describing the minimal access a developer tool needs in order to function, plus an SDK resolver that reads it.

Today every host discovers this independently, by hand, and hardcodes it in its own source tree. For agents it's structural rather than tedious — an LLM-driven caller picks tools at runtime, so the host author can't enumerate them ahead of time.

🎯 Scope

  • SDK-library-only per docs/authoring-a-new-feature.md. No change to Policy, ContainerConfig, or executor behavior.
  • One new exported function, getSandboxConfigForTool, returning an existing type.
  • Floors only ever narrow. Adopting this can make a previously-failing tool succeed; it can never make a previously-contained tool less contained.

🔍 Where review effort is best spent

  • §2.1 — a floor and a policy are the same type, so a host can use a floor as its policy. The spec concedes this rather than pretending the layering forbids it, and argues the real cost is misplaced authorship rather than an over-permissive sandbox. If that argument is wrong, the design is wrong.
  • §3.1 — keying on invocation name is the weakest part of the design. Section leads with that rather than burying it.
  • §7 — trust model. Floor data is community-contributed, unsigned, and unwarranted; the spec's claim is that this is safe because no security decision is delegated.
  • §9 — three genuinely open questions, plus a list of what's already settled so reviewers don't re-derive it.

🔗 Related

✅ Validation

Design-only, so no automated coverage. Checked on the document: all JSON examples parse (including the §3.2 schema, $defs fully connected), all internal § references resolve, all external links resolve.

§8 is the test plan for the eventual implementation.

✅ Checklist

📋 Issue Type

  • Bug fix
  • Feature
  • Task

GitHub Actions runs the PR validation build automatically. The ADO pipeline
(MXC-PR-Build) is the Azure version of the PR pipeline, kept in parity with the GitHub
Actions build; it runs on merge to main, and Microsoft reviewers with write access can trigger it
on a PR with /azp run. See docs/pull-requests.md.

If the dependency-feed-check check fails on a new dependency, the crate must be added to
the feed before the PR can pass. See docs/pull-requests.md
for the steps.

Microsoft Reviewers: Open in CodeFlow

Proposes config floors: a repository-hosted table describing the minimal
filesystem and network access a developer tool needs to function, plus an
SDK resolver that reads it.

Today every host discovers a tool's sandbox requirements independently, by
hand, and hardcodes the result in its own source tree. For agents this is
structural rather than tedious -- an LLM-driven caller selects tools at
runtime, so the host author cannot enumerate them in advance.

Design summary:

- A floor IS a Policy -- same type, same schema, same vocabulary. What
  distinguishes it is the direction of the bound: a policy is an upper
  bound stated by the host, a floor is a lower bound stated by the tool
  ecosystem.
- An entry is an envelope identifying a tool, wrapping a verbatim
  SandboxPolicy. The inner object is not a new type, so floors express new
  Policy fields the day they ship, and validation is inherited.
- Spawn requirements live in the envelope via `requires`, never in the
  inner Policy. SandboxPolicy has no process/spawn field and this spec does
  not propose adding one.
- Identity is name-first and layered: a predicate must be falsifiable
  against a local artifact. Identity is a precision mechanism, not a
  security boundary.
- getSandboxConfigForTool returns SandboxPolicy | undefined. `undefined`
  rather than an empty Policy, so absence of data cannot be confused with a
  claim of zero requirement.

Design only -- no implementation, no schema changes. Per
docs/authoring-a-new-feature.md this is SDK-library-only: it adds neither a
cross-platform security restriction nor backend-specific configuration.

Builds on #673 (dev-tool cache discovery; its security properties are
carried forward) and #748 (captureDenials on the typed SandboxPolicy, which
the authoring pipeline in section 5.1 consumes).
@asklar
Alexander Sklar (asklar) requested a review from a team as a code owner August 8, 2026 02:51
Copilot AI balanced review requested due to automatic review settings August 8, 2026 02:51
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a design specification for repository-hosted sandbox configuration floors and SDK-based resolution.

Changes:

  • Defines floor data, identity, dependency, and symbolic-path models.
  • Proposes TypeScript and Rust resolver APIs.
  • Documents authoring, trust, compatibility, and testing plans.
Show a summary per file
File Description
docs/sandbox-config-floors.md Introduces the config floors feature specification.

Review details

Tip

Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Suppressed comments (5)

docs/sandbox-config-floors.md:261

  • Neither SDK currently has generic SandboxPolicy merge semantics; the existing helpers only return filesystem fragments for callers to concatenate (sdk/node/src/policy.ts:19-27, mxc_engine/src/policy.rs:27-35). This also cannot be inferred as a simple union: allow lists broaden by union, deny lists narrow by union, and timeoutMs, tempDir, and clipboard values need explicit conflict rules. Define a merge algebra/API or restrict floor fields before making dependency closure depend on it.
**Composition.** A command line that invokes several tools resolves to the union
of their policies. `npm install && npm test` composes cleanly. Union is over
Policy objects using the SDK's existing merge semantics — not a floor-specific
rule.

docs/sandbox-config-floors.md:832

  • For ['npm', 'unknown'], this return is indistinguishable from resolving ['npm'], so the caller cannot know the floor is incomplete. Logging is insufficient because SDK diagnostics are best-effort and disabled by default (sdk/node/src/diagnostic.ts:119-137). Return matched/unmatched tools (and resolution warnings) alongside the policy, or return per-tool results, so hosts can safely refuse or warn.
When *some* tools match and others do not, the function returns the union of the
floors that did match. A tool with no entry contributes nothing, which is the same
result as a tool whose floor is empty — correctly, since neither asserts a
requirement. Only the all-unmatched case is distinguishable, and it is the one
that matters: `undefined` rather than a policy.

docs/sandbox-config-floors.md:876

  • Current denial capture does not report network endpoints. learning_mode_core/src/model.rs:53-54 reserves ResourceType::Network for future capture, and the Windows extractor only emits files, registry/other, and capabilities (learning_mode/windows/src/extractors.rs:25-32,167-172). It therefore cannot derive allowedHosts or configured-registry floors. Scope this pipeline to filesystem/capability data, or acknowledge network capture as a new prerequisite rather than claiming the existing capability is sufficient.
- **Denials are raw.** Capture reports the paths and endpoints a specific run
  touched. A floor is the *minimal generalized* requirement. Going from one to
  the other is a human judgement, made by the contributor before submission.

docs/sandbox-config-floors.md:952

  • This safety claim contradicts the supported direct-adoption path in §2.1. Because the resolver returns a SandboxPolicy, a host can use a malicious floor directly; broad filesystem/network requirements then become granted authority and can enable data access or exfiltration, not merely rejection. Either make composition with a host-authored policy part of the API contract/enforcement, or classify direct floor adoption as unsafe and remove the claims that adoption can never reduce containment.
This is safe because of §2: a floor is a hint used to construct a request, not a
grant of authority. A malicious or wrong floor can ask for anything; policy
still decides, and the enforcement boundary is untouched. The worst outcome from
bad floor data is a tool that fails to run, or a host that constructs a request
policy then rejects.

docs/sandbox-config-floors.md:661

  • tempDir is not a field of either current SDK return type: TypeScript SandboxPolicy.filesystem has clearPolicyOnExit instead (sdk/node/src/types.ts:346-359), and Rust FilesystemSection has the same shape (mxc_engine/src/policy.rs:425-434). A resolver returning this field therefore cannot satisfy the promised existing SandboxPolicy type without a Policy API change. Remove it from the floor vocabulary or explicitly include the required Policy changes in scope.
            "tempDir": { "enum": ["shared", "isolated"] }
  • Files reviewed: 1/1 changed files
  • Comments generated: 3
  • Review effort level: Balanced

Comment on lines +248 to +252
**Per-entry policy versioning.** Because the embedded object carries its own
`version`, entries authored against different Policy versions coexist in one
table. An entry pinned to `0.6.0-alpha` stays valid when the current version moves
on. This is the existing versioning design (`docs/versioning.md`) doing its job,
not a new mechanism.
Comment on lines +449 to +453
"tool": "some-mcp-server",
"identity": [
{ "kind": "npm-package", "name": "@vendor/some-mcp-server" }
],
"requires": [
Comment on lines +778 to +780
| OS well-known folders | `${localappdata}` | environment variable, or the platform's folder API |
| Tool configuration | `${npm_prefix}`, `${npm_cache}`, the configured registry | the tool's own config chain — `npm config get`, `.npmrc`, `NPM_CONFIG_*` — where an environment variable is only one of several layers, and not the one that usually wins |
| Request-relative | `./package.json` | `projectRoot`, defaulting to cwd |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants