Skip to content

fix(cli): keep published files inside the entry directory - #1838

Merged
Lorenzobattistela merged 5 commits into
bendlang:mainfrom
oxura:fix/1836-publish-boundary-20261024
Oct 23, 2026
Merged

Lorenzobattistela merged 5 commits into
bendlang:mainfrom
oxura:fix/1836-publish-boundary-20261024

Conversation

@oxura

@oxura oxura commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1836.

--publish could follow a foreign-file or LICENSE symlink, or a ../ climb, and upload a file from outside the entry directory.

The entry's directory is now dirname(realpath(entry)), the directory the loader roots namespaces at. Every published file must stay inside it, both by its published path and by its real target:

  • a .bend file is published at its namespace, and a foreign .c/.js file at its import's own path, normalized as text (as an importer resolves it inside the package);
  • ../ climbs that leave the directory, file and directory symlinks out of it, and an automatic LICENSE that links out are refused before mining, with no hub request;
  • a climb that leaves and comes back in (../back/ok.c from back/) is refused too: the published source would name a file the package lacks;
  • an entry linked from another directory, and an entry at /, are refused;
  • links that stay inside still publish, under the link's name.

The old ancestor re-rooting of climbing imports is gone. This intentionally stops publishing shared sources above the entry directory: move them under it first. Checking and running local programs are unchanged.

Behaviour changes for the release notes: shared sources above the entry directory, LICENSE symlinks pointing out of it, and an entry file symlinked from another directory no longer publish.

Tests: gates/ping.ts publishes against its localhost hub: a climb, a climb back in, a file link, a directory link, a LICENSE link, a linked entry and a climbing .bend import are each refused before mining; a link inside and a nested file's ../ that stays inside publish with the expected hash.

  • bun gates/repo.ts: 54/54
  • bun gates/ping.ts: 81/81

Known limits, not addressed here: hard links to outside files (realpath does not see them; git clones never create them), and a file swapped between the check and the read.

@oxura

oxura commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

@Viana-SSJ confirmed the git-clone repro and all five cases on this head: verification.

Release-note heads-up: an entry-file symlink pointing outside its directory is now refused too. Hard-link provenance is not covered by this guard; git clone does not preserve that aliasing.

Lorenzobattistela and others added 3 commits October 23, 2026 17:54
The entry's directory is now dirname(realpath(entry)), the directory the
loader roots namespaces at, and every source is published at its path
relative to it. Each published path and its real target must stay inside,
so the old ancestor re-rooting is gone: a climb that came back inside no
longer pushed the whole package under the entry's directory name.

An entry linked from another directory and an entry at / are refused, the
LICENSE refusal says it was the LICENSE beside a source, and the CLI help
drops the publish note. gates/ping.ts covers climbs, file, directory,
LICENSE and entry links out, a link inside and a climb back in.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A foreign file's published path is its import normalized as text, as an
importer resolves it inside the package. Resolving it against the absolute
path collapsed a climb back in (../back/ok.c from back/) to ok.c, which
the published source still names as ../back/ok.c, so the package broke on
import; that climb is now refused. gates/ping.ts expects the refusal and
publishes a nested file whose ../ok.c stays inside.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A foreign import that climbs out of the package, even back into the
entry's directory, is refused for what it is: its import climbs out
(../back/ok.c), so write a path that stays inside; "it is outside" is
kept for a file whose real path leaves the directory. The p === ".."
guard and the non-prefix fallback could not occur: every foreign file's
.bend is checked inside the directory first. gates/ping.ts expects each
refusal's own reason.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@Lorenzobattistela Lorenzobattistela left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved at add9b8d. Publishing is confined to the loader's root: every published path and its real target must stay inside the entry's directory. bun gates/repo.ts 54/54, bun gates/ping.ts 81/81.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Lorenzobattistela
Lorenzobattistela merged commit 05d33b3 into bendlang:main Oct 23, 2026
1 check passed
@Lorenzobattistela Lorenzobattistela mentioned this pull request Oct 23, 2026
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.

Security: bend --publish reads and uploads files outside the project directory via climbing foreign imports

2 participants