| name | generate-enforcer-policy |
| description | Generate mitmproxy enforcer.py network policies from plain-language requirements. Takes domain names, HTTP methods, and path patterns to produce RULES entries for the ccdc sandbox enforcer. Trigger keywords - enforcer policy, network policy, allow domain, block domain, enforcer rules, add domain, mitmproxy rules, access control, enforcer.py, domain allowlist. |
Generate Enforcer Policy
Generate mitmproxy enforcer.py RULES entries from plain-language user requirements for ccdc sandboxed environments.
Overview
This skill translates a user's plain-language network access intent into valid enforcer.py RULES entries. The enforcer is a mitmproxy addon that controls which domains, HTTP methods, and URL paths are allowed from the sandboxed dev container.
The output is a Python dict entry (or full RULES block) that can be added to .ccdc/proxy/enforcer.py.
Step 1: Gather Inputs
Determine the Detail Tier
| Tier | User provides | What you generate |
|---|
| Minimal | Domain name + broad intent ("allow npm registry") | "domain": "allow_all" or method-only restriction |
| Moderate | Domain + specific methods/paths ("GET only on api.github.com, POST on /graphql") | Explicit method/path rules |
| Full | Complete API endpoint list or docs | Fine-grained per-endpoint rules |
Access Intent Mapping
| User says | Rule type |
|---|
| "allow", "full access", "unrestricted" | "allow_all" |
| "read only", "GET only", "browse" | [{"method": "GET"}] |
| "read + write", "GET and POST" | [{"method": "GET"}, {"method": "POST"}] |
| Specific paths mentioned | [{"method": "X", "path": "/pattern"}] |
Step 2: Clarify Scope
Before generating rules, ask clarifying questions when needed:
| Missing info | Question to ask |
|---|
| Access level unclear | "Should this domain allow all traffic, or do you want to restrict by HTTP method (e.g., GET only)?" |
| "allow_all" on a broad domain | "This allows all HTTP methods and paths on this domain. Do you need POST/PUT/DELETE, or would GET-only be safer?" |
| Git push/pull for GitHub | "Which org/repo needs push access? I'll add POST rules for the specific git endpoints." |
| API with many endpoints | "Do you have the API docs? I can generate tighter rules per endpoint." |
Do not over-interrogate. If the user gives a clear request like "allow registry.npmjs.org", generate "allow_all" without asking further questions.
Step 3: Understand the Rule Format
enforcer.py RULES Structure
RULES = {
"domain.com": "allow_all",
"api.example.com": [
{"method": "GET"},
],
"api.example.com": [
{"method": "GET"},
{"method": "POST", "path": "/api/v1/data"},
{"method": "POST", "path": "/api/v1/uploads/*"},
],
}
Path Matching
| Pattern | Matches | Example |
|---|
/foo | Exact path only | /foo matches, /foo/bar does not |
/foo/* | Prefix match (anything starting with /foo/) | /foo/bar, /foo/bar/baz all match |
/foo/**suffix | Prefix + suffix | /foo/abc/suffix matches, /foo/abc does not |
Important: * vs **
/api/* — matches /api/anything and /api/a/b/c (prefix match, crosses / boundaries)
/** is used for prefix + suffix patterns only
This is NOT standard glob — /* is a prefix match in the enforcer.
Step 4: Generate the Rules
Default Domains (already included by ccdc init)
These are generated by default. Do not duplicate them:
"github.com": [{"method": "GET"}],
"api.github.com": [{"method": "GET"}, {"method": "POST", "path": "/graphql"}],
"raw.githubusercontent.com": "allow_all",
"registry.npmjs.org": "allow_all",
"npm.pkg.github.com": "allow_all",
"rubygems.org": "allow_all",
"bundler.io": "allow_all",
"pypi.org": "allow_all",
"files.pythonhosted.org": "allow_all",
"claude.ai": "allow_all",
"platform.claude.com": "allow_all",
"api.anthropic.com": "allow_all",
"statsig.anthropic.com": "allow_all",
"sentry.io": "allow_all",
Common Patterns
Git push/pull for a specific repo
"github.com": [
{"method": "GET"},
{"method": "POST", "path": "/OrgName/RepoName.git/**"},
],
The /** pattern covers both git-upload-pack and git-receive-pack endpoints.
GitHub API with write access
"api.github.com": [
{"method": "GET"},
{"method": "POST", "path": "/graphql"},
{"method": "POST", "path": "/repos/OrgName/RepoName/*"},
{"method": "PUT", "path": "/repos/OrgName/RepoName/*"},
{"method": "PATCH", "path": "/repos/OrgName/RepoName/*"},
],
External API (read-only)
"api.example.com": [
{"method": "GET"},
],
External API (specific endpoints)
"api.example.com": [
{"method": "GET", "path": "/api/v1/models"},
{"method": "POST", "path": "/api/v1/completions"},
],
Wildcard subdomain (not supported)
The enforcer matches exact domain names. If you need *.example.com, add each subdomain explicitly.
Step 5: Validate and Warn
Validation Checks
Breadth Warnings
| Condition | Warning |
|---|
"allow_all" on a non-registry domain | "This allows all HTTP methods and paths. Consider restricting to specific methods if you only need read access." |
| No path restriction on POST/PUT/DELETE | "POST is allowed on all paths. If you know the specific API endpoints, adding path restrictions reduces the attack surface." |
Many domains as "allow_all" | "Multiple domains have unrestricted access. Review whether any can be narrowed to GET-only." |
Step 6: Determine Output Mode
| Signal | Action |
|---|
User has an existing enforcer.py | Read the file, add/modify rules in the existing RULES dict |
| User says "add domain X" | Insert a new entry into the existing RULES dict |
| User says "generate enforcer" | Generate the complete RULES dict |
| No file context | Present the rules and ask if the user wants them applied |
Applying Changes
When modifying an existing enforcer.py:
- Read the current file to understand existing rules
- Check for conflicts — does the domain already have rules?
- Insert or replace the rule in the appropriate section (GitHub, registries, Claude Code, or custom)
- Preserve comments and formatting
The enforcer hot-reloads on save — no container restart needed.
Step 7: Confirm and Refine
After generating or applying rules, ask if the user wants to:
- Tighten or loosen any rules
- Add more domains
- Test by checking proxy logs (
docker compose -f .ccdc/compose.yaml logs proxy -f)
Quick Reference
"domain.com": "allow_all",
"domain.com": [{"method": "GET"}],
"domain.com": [
{"method": "GET"},
{"method": "POST", "path": "/api/endpoint"},
],
"github.com": [
{"method": "GET"},
{"method": "POST", "path": "/Org/Repo.git/**"},
],
Companion Skills
| Skill | When to use |
|---|
ccdc-cli | Setting up and managing the ccdc environment (init, build, connect, troubleshoot) |