Skip to main content

What You’ll Learn

  • How to create a sandbox with network={"allow_out": [...]} to restrict outbound access
  • How to write an agent that tests TCP connectivity from inside the sandbox
  • How to verify that non-allowlisted destinations are blocked
  • The pattern of combining agent execution with network-level isolation

Prerequisites

  • Declaw running locally or in the cloud (see Deployment)
  • DECLAW_API_KEY and DECLAW_DOMAIN set in your environment
This example is available in Python. TypeScript support coming soon.

Code Walkthrough

1. Create the sandbox with a network allow-list

from declaw import Sandbox

allowed_domain = "api.github.com"

sbx = Sandbox.create(
    template="python",
    timeout=300,
    network={"allow_out": [allowed_domain]},
)
The network parameter accepts an object with allow_out (list of allowed domains) or deny_out (list of denied domains). When allow_out is specified, all traffic except to listed domains is blocked. See Network Policies for full details.

2. The agent script — testing connectivity

The agent script runs inside the sandbox and tests TCP connectivity to several hosts:
AGENT_SCRIPT = textwrap.dedent("""\
    import socket
    import json

    def test_connection(host, port, timeout=5):
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(timeout)
            s.connect((host, port))
            s.close()
            return {"host": host, "port": port, "status": "CONNECTED"}
        except Exception as e:
            return {"host": host, "port": port, "status": f"BLOCKED: {e}"}

    with open("/tmp/test_plan.json") as f:
        test_plan = json.load(f)

    results = []
    for test in test_plan["targets"]:
        result = test_connection(test["host"], test["port"])
        status_icon = "OK" if result["status"] == "CONNECTED" else "XX"
        print(f"  [{status_icon}] {result['host']}:{result['port']} -> {result['status']}")
        results.append(result)

    with open("/tmp/results.json", "w") as f:
        json.dump(results, f, indent=2)
""")

3. Upload the test plan and run the agent

test_plan = {
    "targets": [
        {"host": "1.1.1.1", "port": 80, "note": "Cloudflare DNS - not in allow list"},
        {"host": "8.8.8.8", "port": 53, "note": "Google DNS - not in allow list"},
        {"host": "93.184.216.34", "port": 80, "note": "example.com - not in allow list"},
    ],
}

sbx.files.write("/tmp/agent.py", AGENT_SCRIPT)
sbx.files.write("/tmp/test_plan.json", json.dumps(test_plan, indent=2))

result = sbx.commands.run("python3 /tmp/agent.py", timeout=60)
print(result.stdout)

4. Read and analyze results

result_content = sbx.files.read("/tmp/results.json")
results = json.loads(result_content)

blocked = sum(1 for r in results if "BLOCKED" in r["status"])
connected = sum(1 for r in results if r["status"] == "CONNECTED")
print(f"Blocked: {blocked} / {len(results)}")

Expected Output

--- Creating Sandbox with Network Policy ---
  Policy: allow_out=['api.github.com']
  All other outbound traffic will be blocked.
  Sandbox created: sbx-abc123

--- Running Network Test Agent ---

  Agent output:
    === Network Connectivity Test Results ===
      [XX] 1.1.1.1:80 -> BLOCKED: [Errno 110] Connection timed out
      [XX] 8.8.8.8:53 -> BLOCKED: [Errno 110] Connection timed out
      [XX] 93.184.216.34:80 -> BLOCKED: [Errno 110] Connection timed out

    Tested 3 targets.

--- Analyzing Results ---
  Total targets tested: 3
  Blocked:              3
  Connected:            0

  [PASS] Network policy is blocking non-allowlisted traffic.

How Network Policy + Agent Isolation Work Together

Agent process (inside sandbox)

        │  TCP connect to 8.8.8.8:53

  ┌─────────────────────────────────────┐
  │  Declaw Network Namespace           │
  │                                     │
  │  iptables REDIRECT → TCP Proxy      │
  │                                     │
  │  Proxy checks: 8.8.8.8 not in       │
  │  allow_out=['api.github.com']        │
  │                                     │
  │  Action: RST (connection refused)   │
  └─────────────────────────────────────┘
The proxy enforces network policy at the TCP layer, not the application layer. This means the restriction applies to all processes inside the sandbox — not just the primary agent — regardless of what language or library they use.

Combining with SecurityPolicy

For defense-in-depth, combine network policies with a full SecurityPolicy:
from declaw import Sandbox, SecurityPolicy, PIIConfig, AuditConfig

sbx = Sandbox.create(
    template="python",
    timeout=300,
    network={"allow_out": ["api.github.com"]},
    security=SecurityPolicy(
        pii=PIIConfig(enabled=True, types=["email", "ssn"], action="redact"),
        audit=AuditConfig(enabled=True, log_request_body=True),
    ),
)
See the Secured Agent example for the full security stack.