Skip to content

v0.5.2 — Workbench security hardening and Fable implementation pack

Choose a tag to compare

@EfeAydinalp EfeAydinalp released this 03 Jul 17:07
· 94 commits to master since this release
5701ab1

vibe-council v0.5.2 — Workbench security-hardening patch (+ implementation-pack docs)

Ready for the v0.5.2 tag — not yet tagged. The version bump (backend/__init__.py,
pyproject.toml, uv.lock) and the dated CHANGELOG.md section are done
(chore: prepare v0.5.2 release); the repo now reports 0.5.2. The git tag and the GitHub
Release are still a separate, manual step
— see §"Final release checklist" below and
docs/release-checklist.md.

A small patch release on top of the v0.5.0/v0.5.1 AI Council Workbench: one DNS-rebinding-class
security hardening on the localhost panel (PR #92) plus a docs-only implementation pack for planning
v0.6+ (PR #93). No executor/trust/payload/allowlist behavior change, no new product surface, no new
dependency.
Based on and crediting
karpathy/llm-council.

No commercial-clearance claim. License/provenance remains an unresolved "Question 0"
commercial gate; no LICENSE is added.

What this release covers

Workbench Host-header validation + /api/state token gate (PR #92)

A Fable architecture review flagged a DNS-rebinding class gap ahead of the v0.6 agent-proposal
bridge. The panel already binds 127.0.0.1, but localhost binding alone does not stop a malicious
page whose domain re-resolves to 127.0.0.1 — the browser still sends that page's original Host
header. This release closes that gap:

  • Host-header validation on every request. A request's Host header must name a literal loopback
    host — 127.0.0.1, localhost, or ::1 (any port). A missing, malformed, or multiple/ambiguous
    Host header fails closed
    (a >1 Host count is rejected outright). Enforced before routing on
    GET /, GET /api/state, and all POST endpoints via a pure, unit-tested host_header_is_local()
    helper.
  • GET /api/state is now token-gated. It exposes runtime tasks/approvals/actions and was
    previously unauthenticated; it now requires the same startup token as the POST endpoints,
    accepted via the X-Workbench-Token header or the ?token= query the panel URL already carries.
    The token is never echoed into the /api/state JSON body.
  • GET / behavior is unchanged — it stays tokenless so the panel URL loads normally; Host
    validation is its guard. (The token remains embedded in the returned HTML for the panel's own
    POSTs, exactly as before.)

The panel JS never fetched /api/state (state is server-rendered into GET /), so nothing in the
panel UI changed. Added tests cover loopback/non-loopback Host acceptance, invalid-Host rejection on
/, /api/state, and POST (even with a valid token), the /api/state token gate, multiple Host
headers rejected (raw-socket test), and the token never leaking into the state JSON.

Fable implementation pack docs (PR #93)

A docs-only, phase-by-phase implementation pack under docs/fable/ for driving
future work with a long-running model (Fable 5 / Opus / Claude Code) without losing the product or
security direction: current-state baseline, operating rules, product vision, the non-negotiable
security invariants, the v0.5.2→v0.9+ roadmap, the v0.6 agent-to-Workbench bridge design + a
concrete proposal schema, onboarding/session launcher, the Obsidian-like project vault (extend
docs/context/, not a new .vibe/), cross-project onboarding, the tighten-only personalization
layer, website positioning, the open-core commercial path, an implementation playbook, and copy-paste
prompt templates. No code, tests, dependencies, or behavior change — the v0.6 bridge is designed
here, not built.

Security posture — unchanged from v0.5.1 (only strengthened)

Nothing in this patch relaxes or expands the security model; the panel is strictly more locked down:

  • Approval is separate from execution — approving only records a decision; it never writes a
    file, edits a file, or runs a command.
  • The panel is localhost-only (127.0.0.1), POSTs are token-gated, and now /api/state is
    token-gated
    and all requests are Host-header validated — no LAN/mobile/remote surface, no
    CORS widening.
  • Payload artifacts stay local and gitignored, write-once, hash/scope-verified before every real
    execution.
  • Command execution is fixed argv + shell=False, always — no dynamic arguments, no shell.
  • The deterministic trust boundary re-runs at execution time; the advisory Approval Auditor still
    cannot relax a block.
  • No new command allowlist entries — still the same verification/status-only allowlist as v0.5.0.
  • No executor/trust/payload behavior changed — this patch only tightens the panel's request
    admission (Host + /api/state token).

Explicit non-goals (deferred, not started in this release)

No v0.6 implementation · no proposal importer · no new network endpoint · no LAN/mobile/hosted/voice ·
no command-allowlist expansion · no arbitrary shell · no new provider/model/network call from the
executor · no dependency changes. The docs/fable/ pack plans v0.6+ but implements none of it.

Release checklist (must be clean before tagging)

  • python -m unittest discover -s tests -t . is green (587 tests).
  • uv run python -m backend.cli --version prints vibe-council 0.5.2.
  • vibe lint --redaction reports 0 critical findings.
  • vibe decisions lint passes.
  • vibe context check scores 21/21.
  • vibe mcp inspect --context --health scores 21/21.
  • uv sync produces no uv.lock diff beyond the intentional self-version sync in this PR.
  • No .council/ artifact (including .council/runtime/payloads/) staged/committed.
  • No private/local plan file staged/committed.

Final release checklist (manual steps, after this PR merges)

These are not automated by this PR — a maintainer performs them once the checklist above is clean
on master:

  • Merge this PR (chore: prepare v0.5.2 release) into master.
  • On the merged master, re-confirm: tests green, redaction lint 0 critical, decisions lint
    passes, context check 21/21, MCP health 21/21.
  • Verify git status --short and the merged diff carry no private/local artifacts
    (.council/, the two untracked private plan files, .env/.venv//data/, secrets,
    generated packs/exports).
  • vibe --version on master prints vibe-council 0.5.2.
  • Create an annotated git tag: git tag -a v0.5.2 -m "vibe-council v0.5.2" on the merge
    commit, then git push origin v0.5.2.
  • Create the GitHub Release for v0.5.2 manually, using this document
    (docs/releases/v0.5.2.md) as the release-notes body.

Known limitations (unchanged from v0.5.1)

  • Intentionally local-only — no LAN/mobile/remote access; the panel binds 127.0.0.1 only.
  • Intentionally tiny command allowlist (verification/status commands only); not meant to grow
    casually.
  • No hosted/team/mobile/voice yet — deferred to v0.6+ at the earliest.
  • The panel is intentionally simple — no framework, no rich UI, no persistence beyond the runtime
    JSON store.
  • The demo still seeds no executable Action (a deliberate v0.5.0/PR #77 safety choice) — real
    execution dogfood requires manual seeding in a temp/safe project.

Next after v0.5.2

Cut the v0.5.2 tag/GitHub Release, then begin v0.6.0 — the agent-to-Workbench bridge (file/CLI
proposal intake, no new network endpoint) per
docs/fable/05-v0.6-agent-bridge.md and
docs/fable/06-proposal-schema.md. Mobile/LAN/voice (v0.8) and
hosted/team (v0.9+) stay deferred behind the local core.