Files
bot-bottle/docs/prds/0037-pipelock-yaml-render-contract.md
didericis-codex f95ef0c446
test / unit (pull_request) Successful in 33s
test / integration (pull_request) Successful in 44s
test / unit (push) Successful in 29s
test / integration (push) Successful in 47s
complete(prd): mark PRD 0037 active
2026-06-02 08:15:20 +00:00

4.3 KiB

PRD 0037: Pipelock YAML Render Contract

  • Status: Active
  • 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.

The supported top-level shape is version, mode, enforce, api_allowlist, seed_phrase_detection, forward_proxy, dlp, request_body_scanning, tls_interception, and ssrf. Required sections are validated before rendering; optional sections keep the current omission behavior. request_body_scanning.scan_headers, request_body_scanning.header_mode, and tls_interception.passthrough_domains remain optional for compatibility with parsed running configs that only contain the older rendered subset.

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

None.