Skip to content

fix(weave): resolve symlinks on write targets; refuse escapes from the repo root - #107

Merged
arcaven merged 1 commit into
mainfrom
fix/weave-resolve-write-targets
Aug 1, 2026
Merged

fix(weave): resolve symlinks on write targets; refuse escapes from the repo root#107
arcaven merged 1 commit into
mainfrom
fix/weave-resolve-write-targets

Conversation

@arcaven

@arcaven arcaven commented Aug 1, 2026

Copy link
Copy Markdown
Member

A weave declaration targeting a path under a runtime_links symlink (e.g. _bmad/_config/...) wrote straight through the link into the frozen store, corrupting producer-validated content shared by every repo on the machine. Verified live in a shimmed repo (bd aae-orc-a3v6); since the store freeze (#106) it fails loudly, before it it was silent.

The fix adds resolveWriteTarget: resolve the deepest existing ancestor of the target and the repo root the same way, refuse any target whose resolution lands outside the root, and surface the refusal as a Failed action naming the resolved destination (weave's existing error model). The check is by resolution, not path spelling, so legacy repos with a real _bmad/ tree (aae-orc-vaqh) weave exactly as before; ../ traversal is covered for free. Verify ops deliberately keep reading through links since checking what the repo resolves to is their job.

Applied to all three write ops (csv, memory, shim; patch is a stub). Tests: three write-through refusals against the live repro shape, legacy real-tree pass-through, resolver units (in-repo symlink allowed, missing tail, dot-dot, symlinked repo root). Additive guard; no behavior change for in-repo targets.

…e repo root

weave ops joined repoRoot with the declared target and wrote to the
result with no symlink resolution. pack.yaml runtime_links symlink
store content into repos (_bmad/_config -> the frozen store version),
so a csv_injection, memory_injection, or slash_command targeting a
path under such a link wrote THROUGH it into producer-validated store
content. Since the store freeze (#106) this failed loudly; before it,
it was silent store corruption.

resolveWriteTarget now resolves the deepest existing ancestor of the
target (the tail may not exist yet for shim creation), resolves the
repo root the same way, and refuses any target whose resolution lands
outside the root. The check is by resolution, never by path spelling:
legacy repos carrying a real _bmad/ tree resolve inside the root and
weave there exactly as before. Refusals surface as Failed actions
naming the resolved destination, consistent with the weave error
model. Also covers ../ traversal out of the declaration.

Verify ops stay unresolved-read: checking what the repo actually
resolves to is their job.

Closes: aae-orc-a3v6 (bd)
Refs: finding-002 F8, docs/sideshow-requirements.md R3
@arcaven
arcaven merged commit 503e725 into main Aug 1, 2026
@arcaven
arcaven deleted the fix/weave-resolve-write-targets branch August 1, 2026 20:58
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