1f36d53f7b
test / run tests/run_tests.py (pull_request) Successful in 14s
Replace the TypedDict + 14 manifest_* free functions with frozen dataclasses (SshEntry, BottleEgress, Bottle, Agent, Manifest) carrying their own validators and constructors. Call sites import Manifest and chain attribute access; the manifest_* helpers and manifest_validate are gone. Behavior changes worth flagging: - Agent.bottle is now required (was optional with a "(none)" fallback). Manifest.from_json_obj dies if any agent lacks a 'bottle' field or references an undefined bottle, where previously start.py raised the error lazily for the specific agent being launched. - ssh.py now takes SshEntry instances; Host/IdentityFile shape checks moved upstream into Manifest construction, leaving only the IdentityFile filesystem-existence check in ssh_validate_entries. - pipelock_bottle_allowlist's per-element string check is dropped — the Manifest validator enforces it at load. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Tests
Plain-Python test suite using stdlib unittest. No external
dependencies. Unit tests run anywhere Python 3 is present; integration
tests need Docker and skip cleanly otherwise.
Layout
tests/
run_tests.py # entry point
fixtures.py # JSON manifest builders
_docker.py # docker-availability skip helper
test_pipelock_naming.py # unit
test_pipelock_classify.py # unit
test_pipelock_allowlist.py # unit
test_pipelock_yaml.py # unit
test_pipelock_image.py # integration
test_pipelock_sidecar_smoke.py # integration
test_dry_run_plan.py # integration
test_orphan_cleanup.py # integration
Running
tests/run_tests.py # everything
tests/run_tests.py unit # unit only
tests/run_tests.py integration # integration only
tests/run_tests.py tests/test_pipelock_yaml.py # one file
You can also run via python -m unittest:
python -m unittest discover -s tests
python -m unittest tests.test_pipelock_yaml
What the integration tests cover
test_pipelock_image.py— the pinned digest is reachable, ENTRYPOINT is/pipelock, andCMDincludesrun.test_pipelock_sidecar_smoke.py—docker create+docker cpthe generated YAML to/etc/pipelock.yaml+docker start, then probe/health.test_dry_run_plan.py—cli.py start --dry-runshows the resolved egress allowlist and creates zero docker resources.test_orphan_cleanup.py— network_remove and pipelock_stop are idempotent against missing resources, so the EXIT trap can call them unconditionally.
What's NOT covered
claude_bottle/ssh.pyend-to-end (would need a fake SSH host inside the container).- A live SSH-through-pipelock tunnel against a real Tailscale-style IP.
- DLP false-positive measurements.
- TLS handling / cert pinning behavior.
Adding a test
- Pick a filename:
test_<topic>.py. Add it toINTEGRATION_NAMESinrun_tests.pyif it needs Docker. - Boilerplate:
import unittest from claude_bottle.<module> import <symbol> class TestThing(unittest.TestCase): def test_x(self): ... if __name__ == "__main__": unittest.main() - For Docker-dependent tests, decorate the class with
@skip_unless_docker()fromtests._docker.