107 lines
4.0 KiB
Markdown
107 lines
4.0 KiB
Markdown
# PRD 0037: Pipelock YAML Render Contract
|
|
|
|
- **Status:** Draft
|
|
- **Author:** didericis-codex
|
|
- **Created:** 2026-06-02
|
|
- **Issue:** #130
|
|
|
|
## Summary
|
|
|
|
Lock down the contract between `pipelock_build_config` and
|
|
`pipelock_render_yaml` so hand-rendered pipelock YAML stays aligned with the
|
|
structured config bot-bottle builds. Keep the stdlib-only renderer, but add
|
|
shape validation and semantic tests for every supported section.
|
|
|
|
## Problem
|
|
|
|
`bot_bottle/pipelock.py` builds a structured dict and then renders a fixed YAML
|
|
shape by hand. This avoids a runtime YAML dependency, but it also means the
|
|
renderer directly indexes expected keys. If `pipelock_build_config` adds,
|
|
renames, or conditionalizes a section, rendering can fail at runtime or emit
|
|
YAML that no longer matches the config semantics.
|
|
|
|
Existing tests assert important rendered fragments, but they do not fully lock
|
|
the build/render contract or optional-section combinations. A mismatch here can
|
|
weaken DLP enforcement or break bottle launch after a future pipelock policy
|
|
change.
|
|
|
|
## Goals / Success Criteria
|
|
|
|
- Keep the renderer stdlib-only.
|
|
- Define the supported pipelock config shape in one place.
|
|
- Fail clearly when `pipelock_render_yaml` receives an unsupported or malformed
|
|
config shape.
|
|
- Add tests covering all supported sections:
|
|
- base allowlist and forward proxy.
|
|
- seed phrase detection toggle.
|
|
- DLP and request-body/header scanning.
|
|
- TLS interception and passthrough domains.
|
|
- SSRF IP allowlist.
|
|
- Add semantic tests that compare structured config values to rendered YAML
|
|
output without relying only on brittle substring assertions.
|
|
- Preserve current rendered YAML for existing configs unless a clearer failure
|
|
path requires an error message change.
|
|
|
|
## Non-goals
|
|
|
|
- No PyYAML or other runtime dependency.
|
|
- No change to pipelock policy defaults.
|
|
- No change to egress-to-pipelock topology.
|
|
- No change to pipelock image version or config schema beyond validation of the
|
|
shape bot-bottle already emits.
|
|
|
|
## Scope
|
|
|
|
In scope:
|
|
|
|
- `bot_bottle/pipelock.py` render helpers and validation.
|
|
- Unit tests in `tests/unit/test_pipelock_yaml.py` and related focused
|
|
pipelock tests.
|
|
- Small helper functions for typed access to config sections, if useful.
|
|
|
|
Out of scope:
|
|
|
|
- Launch/backend changes.
|
|
- Integration tests that start a real pipelock container.
|
|
- Changing the manifest schema for route-level pipelock policy.
|
|
|
|
## Design
|
|
|
|
Treat `pipelock_render_yaml` as a serializer for the narrow config shape
|
|
produced by `pipelock_build_config`, not as a generic YAML renderer. Before
|
|
rendering a section, validate that required keys exist with the expected
|
|
primitive/list/dict types. Missing or unsupported shapes should raise a clear
|
|
`ValueError` naming the section and key.
|
|
|
|
Tests should cover both normal output and failure cases. Because the project is
|
|
stdlib-only, semantic tests can use a small purpose-built parser for the exact
|
|
rendered shape or compare rendered lines to values from the structured config
|
|
through helper assertions. The goal is to detect drift between config dict and
|
|
YAML without adding a general YAML dependency.
|
|
|
|
Optional sections should be exercised in combinations:
|
|
|
|
- no TLS and no SSRF.
|
|
- TLS enabled with empty and non-empty passthrough domains.
|
|
- SSRF enabled with one or more IP/CIDR entries.
|
|
- all optional sections enabled together.
|
|
|
|
## Testing Strategy
|
|
|
|
- Extend `tests/unit/test_pipelock_yaml.py` with semantic assertions tying each
|
|
rendered section back to the config dict.
|
|
- Add malformed-config tests for missing required keys and wrong section types.
|
|
- Keep existing render fragment tests where they protect exact pipelock syntax.
|
|
|
|
Run:
|
|
|
|
- `python3 -m unittest tests.unit.test_pipelock_yaml`
|
|
- `python3 -m unittest tests.unit.test_pipelock_allowlist`
|
|
- `python3 -m unittest discover -s tests/unit`
|
|
|
|
## Open Questions
|
|
|
|
- Should malformed config errors be `ValueError`, matching current
|
|
`pipelock_build_config` validation, or a new internal exception type? Prefer
|
|
`ValueError` unless a caller needs to distinguish serializer errors.
|