Development Guide

June 28, 2026 · View on GitHub

This document covers local development, testing, and the project structure of Buildcage.

Local Usage

You can run Buildcage locally without GitHub Actions using Docker Compose and Make.

GitHub Actions inputs use lowercase names (e.g., proxy_mode), while environment variables for local usage use uppercase (e.g., PROXY_MODE).

Starting the Builder

Audit mode (log all connections):

make run_audit_mode

Restrict mode (allowlist-based):

make run_restrict_mode

Start with custom domains:

ALLOWED_HTTPS_RULES="github.com:443 npmjs.org:443 example.com:443" make run_restrict_mode

End-to-End Workflow

# 1. Start Buildcage
make run_audit_mode

# 2. Build
docker buildx build --builder buildcage --progress=plain -f Dockerfile .

# 3. View report
docker compose logs builder

# 4. Clean up
make clean

Testing

# Audit mode test (start → build → verify → clean up)
make test_audit_mode

# Restrict mode test (start → build → verify → clean up)
make test_restrict_mode

Local Development

Image provenance verification bypass

When running the setup action locally against a branch ref or a local ./setup path, the action cannot resolve the ref to a published release. Because the setup action is fail-closed by default, it will exit with an error for such "unverifiable" refs.

For development use, you can allow the action to pull the image without verification by setting:

BUILDCAGE_ALLOW_UNVERIFIED=1

⚠ This flag is for local development only. Never use it in CI or production workflows. It is active only for unverifiable refs (branch names, local paths); version tags and commit SHAs always go through full Sigstore verification regardless of this flag.

See security.md for more details.

Viewing Logs

# All communication logs
docker compose logs builder

# Real-time log monitoring
docker compose logs -f builder

Log format:

[28/Feb/2026:10:15:30 +0000] buildcage [ALLOWED] "github.com:443" -
[28/Feb/2026:10:15:31 +0000] buildcage [BLOCKED] "malicious.com:443" not-allowed
[28/Feb/2026:10:15:32 +0000] buildcage [AUDIT] "npmjs.org:80" -

Fields: [timestamp] buildcage [status] "domain:port" reason

Makefile Commands

CommandDescription
make helpShow available commands
make run_audit_modeStart in audit mode
make run_restrict_modeStart in restrict mode (default domains)
make test_audit_modeRun audit mode tests (start → build → verify → clean up)
make test_restrict_modeRun restrict mode tests (start → build → verify → clean up)
make test_unitRun unit tests
make cleanRemove all resources

Directory Structure

.
├── setup/                       # GitHub Actions setup
│   ├── action.yml               # Action entry (node24 → dist/main.cjs, dist/post.cjs)
│   ├── compose.yaml             # Compose config for GitHub Actions (with image tag)
│   ├── src/                     # Source (ESM)
│   │   ├── main.js              # Verify image provenance, resolve image ref, compose up
│   │   ├── post.js              # Post-action cleanup
│   │   └── lib/                 # Helpers: OCI registry, Sigstore verification, error types
│   └── dist/                    # Bundled output (rollup → CommonJS)
│       ├── main.cjs
│       └── post.cjs
├── report/                      # GitHub Actions report
│   ├── action.yml               # Action entry (node24 → dist/main.cjs)
│   ├── src/                     # Source (ESM)
│   │   ├── main.js              # Log analysis and Job Summary output
│   │   └── lib/                 # Helpers: Job Summary rendering
│   └── dist/                    # Bundled output (rollup → CommonJS)
│       └── main.cjs
├── docker/
│   ├── Dockerfile               # Multi-stage BuildKit + haproxy + dnsmasq + s6-overlay
│   └── files/
│       ├── buildkitd.toml       # BuildKit config
│       ├── cni.conflist         # CNI config (isolated-net)
│       ├── dnsmasq.conf         # DNS config (all domains → gateway)
│       ├── haproxy.cfg.template # Dynamic HAProxy config (HTTP/HTTPS)
│       ├── s6-rc.d/             # s6-overlay service definitions
│       ├── s6-scripts/          # s6-overlay init scripts
│       └── tools/               # QuickJS scripts (run inside container)
│           ├── convert-rule.js  # stdin wildcard → stdout regex filter
│           ├── report.js        # Parse HAProxy logs → structured JSON
│           └── lib/
│               ├── rules.js         # Wildcard → regex conversion
│               ├── rules.test.js
│               ├── log-parser.js    # Log parsing and aggregation
│               ├── log-parser.test.js
│               └── test-shim.js     # Minimal test runner for QuickJS
├── docs/
│   ├── development.md           # Development guide
│   ├── rules.md                 # Rule format reference
│   ├── security.md              # Security design
│   └── self-hosting.md          # Self-hosting guide
├── test/
│   ├── Dockerfile.audit         # Audit mode test
│   ├── Dockerfile.restrict      # Restrict mode test
│   ├── assert-audit-mode.sh     # Audit mode verification script
│   ├── assert-restrict-mode.sh  # Restrict mode verification script
│   ├── helpers.sh               # Test helpers
│   ├── test-server/             # Test HTTP server
│   └── test-dns/                # Test DNS server
├── compose.yaml                 # Docker Compose config
├── compose.test.yaml            # Test override config
└── Makefile                     # Operational commands