Skip to content

feat: gate releases on verification + test-parity fixes - #13

Open
abienkowski wants to merge 3 commits into
mainfrom
feat/release-verification-gate
Open

feat: gate releases on verification + test-parity fixes#13
abienkowski wants to merge 3 commits into
mainfrom
feat/release-verification-gate

Conversation

@abienkowski

@abienkowski abienkowski commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Gates the release pipeline on full verification before tagging artifacts, closes the test-parity gaps found while auditing coverage, and enforces the Unix-socket security boundary across the sock integration suite.

Part 1 — Release verification gate

  • Makefile: backend-parameterized verify (BACKEND=), new ci-verify (Quint TS backend) and release-verify (Quint Rust backend) aggregate targets
  • CI: runs on pull requests only (drops duplicate push-to-main runs); jobs reuse Make targets
  • Release: new release-verify gate job blocking tag creation; version job creates a draft prerelease; new publish-release job flips draft → published only after all three artifact jobs succeed
  • docs/release.md: documents local gates

Closes part of #6 and #8.

Part 2 — Test-parity fixes (audit follow-up)

Go

  • Image prefix matching respects namespace boundaries — chainsafe/lodestar no longer matches evilfoo-lodestar or lodestar-backup (manager.go)
  • New readonly + validation-path middleware tests (chain_test.go)

Rust

  • Forwarded Content-Length is rewritten to match the (possibly mutated) body length — fixes daemon-side JSON truncation (handler.rs)

TypeScript

  • Flags honor the --flag=value form (new flags.ts module + tests)
  • Proxy actually listens on the parsed TCP host/port — the old string overload was a no-op (index.ts)
  • Content-Length derived from the bytes actually forwarded (transport.ts)
  • Handler tests ported to match Go/Rust (handler.test.ts)

Integration / CI

  • Compose build context + project name parameterized by IMPL (go/rs/ts)
  • --build on integration runs; new test-integration-rs / test-integration-ts targets
  • CI runs all three integration suites
  • Numeric user: "0:0" for scratch-based Rust/TS images

Spec & config

  • Route POST /containers/:name/pause to allowAction; README documents 9 invariants (6 P0 / 3 P1)
  • Beacon sample policy pins the host systemd account to uid/gid 100 (system user), independent of the in-container user

Part 3 — Unix-socket security boundary (403 on socket permission denial)

The group-restricted Docker Unix socket is the security model; connecting under a group that lacks access must surface as 403 Forbidden, indistinguishable from a middleware policy denial:

  • Go: ReverseProxy ErrorHandler maps EACCES/EPERM on the socket dial → 403 (transport.go); tests for 502 (missing socket), 403 (permission), and errno unwrapping
  • Rust: new TransportError::SocketPermission variant → 403 in the handler; transport + handler tests for both 403 and 502 paths
  • TS: Transport emits 403 on EACCES/EPERM (transport.ts, isPermissionDenied helper)
  • TS --docker-host: accepts a Unix socket path only — rejects tcp:///http:///unix:// schemes so all three implementations run the sock suite over a real socket
  • Makefile: test-integration-sock parameterized by IMPL with --build + -rs/-ts variants
  • Removed docker-compose.tcp.yml + test-integration-tcp: TCP forwarding bypasses user/group socket ownership, and the dial path was already unix-only (broken) for Go/Rust
  • Audit-log tests in all three languages (temp-file JSON round-trip for allow/deny)

Verification

  • Go: 74 unit tests + go vet clean
  • Rust: 112 unit tests + cargo check clean
  • TS: 108 unit tests + tsc clean
  • Integration: 26/26 (go, rs) via compose + ts 26/26 natively with the new --docker-host flag
  • Sock suite: 8/8 for go and rs — denied proxy returns 403 on every route
  • Quint: typecheck + 9-invariant simulation with no violations (unchanged)

- Add ci-verify and release-verify Make targets with backend-parameterized quint verify
- CI runs on pull requests only, reusing Make targets per job
- Release workflow gates tag creation on release-verify, publishes draft prerelease,
  then flips to release only after all artifacts upload
- Document local verification gates in docs/release.md
@abienkowski abienkowski self-assigned this Aug 10, 2026
Cross-language parity fixes surfaced by auditing test coverage and
running the full suite from a clean checkout:

- Go: match image prefixes only on namespace boundaries, so
  'evilfoo/bar' or 'foo-backup' can no longer match a 'foo' prefix;
  add readonly and validation-path middleware tests
- Rust: rewrite the forwarded Content-Length to match the (possibly
  mutated) body length, preventing daemon-side JSON truncation
- TS: honor --flag=value form; listen on the parsed host/port (the old
  string overload made the listen a no-op); set Content-Length from the
  actual forwarded body bytes; port handler tests to match Go/Rust
- Integration: parameterize compose build context and project name by
  IMPL (go/rs/ts), rebuild images with --build, add -rs/-ts targets, run
  all three in CI; use numeric user uid:gid for scratch-based images
- Spec: route pause to allowAction and record 9 invariants in README
- Beacon sample policy: pin the host systemd account to uid/gid 100
  (system user), independent of the in-container user
@abienkowski abienkowski changed the title feat: gate releases on quint verification and full test suite feat: gate releases on verification + test-parity fixes Aug 11, 2026
…t tests

The group-restricted Unix socket is the security boundary, so a connect
that fails with EACCES/EPERM must be indistinguishable from a middleware
policy denial: return 403 Forbidden instead of 502 Bad Gateway.

- Go: ReverseProxy ErrorHandler maps EACCES/EPERM on the socket dial to
  403 (transport.go); add transport tests (502 for missing socket, 403
  for permission, errno unwrapping)
- Rust: new TransportError::SocketPermission variant mapped to 403 in the
  handler; transport + handler tests for both 403 and 502 paths
- TS: Transport emits 403 for EACCES/EPERM; new isPermissionDenied helper
  with tests
- TS --docker-host flag accepts only a Unix socket path (rejects tcp/http/
  unix schemes) so all three implementations run the sock integration suite
- Makefile: parameterize test-integration-sock by IMPL with --build, add
  -rs/-ts variants; remove the TCP variant (docker-compose.tcp.yml) —
  TCP bypasses user/group socket ownership and its dial was already broken
  for Go/Rust which are unix-only
- Add audit-log unit tests in all three languages (temp-file JSON round-trip)
- AGENTS.md: update test counts (Go 74, Rust 112, TS 108)

Verified: unit suites green; sock suite 8/8 for go and rs (403 on denied
socket); main integration 26/26 for go, rs, and native ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant