Repository navigation
feat(mitmproxy): predefined network allowlist presets - #105
Merged
Merged
Conversation
Closes #2. A `network` entry of `{"preset": "<name>"}` now expands, in place, to a predefined group of allow rules — so tightening a policy no longer means hand-maintaining every registry host per ecosystem. Expansion preserves rule order (first-match-wins works across presets: a deny placed before a preset shadows its hosts), a preset entry must carry the `preset` key alone, and an unknown name raises at load() so the proxy fails to start instead of silently running a different policy than asked for. Presets (host-only, modeled on the domain-level allowlists from the issue — agent-sandbox's enforcer and tsk's squid.conf): one per `sandcat init` stack (python, node, java, scala, go, rust, ruby, dotnet, zig — kept in sync with STACK_NAMES by a test), plus nix (runtime devbox installs), vscode, jetbrains, github, anthropic, openai. Ecosystem presets are self-contained (scala repeats the Maven hosts) so a single preset never has a hidden dependency; duplicates across presets are harmless under first-match-wins. Docs: new "Network presets" section; the hand-maintained per-stack domain table is replaced by a pointer to it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
3 tasks done
shejnowicz
added a commit
that referenced
this pull request
Sep 7, 2026
…ildcard Builds on the network presets (#2/#105). `sandcat init --features strict-network` (or SANDCAT_STRICT_NETWORK=true) generates project settings whose `network` list holds one `{"preset": "<stack>"}` entry per resolved stack and no allow-all-GET wildcard, so anything beyond the stack registries and the user-settings layer (the agent's own API hosts) is denied by default — including DNS resolution. Kept opt-in on purpose: flipping the default would surprise every new project with "sandcat blocks the internet"; the summary line now states which policy the project got and how to switch. `init settings` grows --strict-network/--stacks flags; with no stacks the strict list is empty (user-settings layer only). Preset names are expanded by the addon at proxy start, so domain lists update with the sandcat version instead of freezing in the project file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
adamw
pushed a commit
that referenced
this pull request
Sep 7, 2026
…ildcard (#106) Stacked on #105 (network presets) — the base branch is `feat/2-network-presets`; retarget to master after #105 merges. Follow-up to #2; no separate issue, so no close keyword. ## Summary `sandcat init --features strict-network` (or `SANDCAT_STRICT_NETWORK=true`) generates project settings whose `network` list holds one `{"preset": "<stack>"}` entry per resolved stack and **no allow-all-GET wildcard**. Everything beyond the stack registries and the user-settings layer (the agent's own API hosts) is then denied by default — including DNS resolution, so blocked hosts never even resolve. - Opt-in by design: flipping the default would surprise every new project with "sandcat blocks the internet". The init summary states which policy the project got (`Network: strict — stack presets: python, java` vs `default (allow all GET; tighten with --features strict-network)`). - `init settings` grows `--strict-network` / `--stacks` flags; with no stacks the strict list is empty (user-settings layer only). - Only preset *names* land in the project file — the addon expands them at proxy start, so domain lists update with the sandcat version instead of freezing per project. - `scala` resolves to `java scala` via the existing stack-deps mechanism, so both presets are seeded. ## Test plan - [x] bats: init 167/167 (new: feature parsing incl. error-message listing, strict/default summary lines, settings --strict-network seeding, empty-stacks case, unknown-option rejection; interactive stubs updated for the new feature label) - [x] Full bats: 16/16 suites - [x] Hands-on integration in a real container: `init --stacks python --features strict-network` generates `{\"network\":[{\"preset\":\"python\"}]}` (no wildcard); stack healthy; pypi.org **200** (stack preset), www.anthropic.com + github.com **200** (presets expanded from the *user-settings layer* — expansion works across layers), example.com **DNS REFUSED** (rc=6 before HTTP); real PyPI package fetch end-to-end through the proxy (JSON API → wheel from files.pythonhosted.org, valid zip). Note: `pip download` itself is unavailable in the devbox/nix python (no ensurepip) — toolchain quirk, not policy; the fetch above covers the network path. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2.
Summary
Adds network presets —
{"preset": "<name>"}entries in thenetworkpolicy that expand in place to predefined allow-rule groups, as requested in #2 (modeled on agent-sandbox's enforcer lists and tsk's squid.conf).denybefore a preset shadows its hosts).presetcombined with other keys raises atload()— the proxy refuses to start rather than run a policy different from the one asked for.initstack (python/node/java/scala/go/rust/ruby/dotnet/zig — a test keeps this in sync withSTACK_NAMES), plusnix,vscode,jetbrains,github,anthropic,openai.scalarepeats Maven hosts); duplicates across combined presets are harmless under first-match-wins.This PR does not change the default policy — the project template keeps
allow * GET. A follow-up PR will add an opt-in strict mode that replaces the wildcard with stack presets.Test plan
{"preset":"python"}, {"preset":"github"}(no wildcard) →pip downloadfrom pypi succeeds through the proxy,curl https://example.com→ 403, DNS for non-preset hosts REFUSED; unknown preset → mitmproxy fails to become healthy (fail-loud verified live)🤖 Generated with Claude Code