fix(path): normalize package-relative path joins#128
Merged
Conversation
Output and fs paths declared relative to a package were joined with a
bare `format!("{pkg}/{rel}")`, leaving `.` and `..` segments in the
result. A `./`-prefixed output surfaced as `pkg/./sub/file` — visible in
the generated .gitignore, but a general normalization gap across every
package-relative join site.
Add `hmodel::htpkg::join_rel_checked`, a single lexical-normalizing join
(collapse `.`/empty, resolve `..`, preserve trailing slash + glob
metachars) that hard-errors when a `..` escapes the workspace root.
Route all three join sites through it:
- plugin-exec `spec_path_to_target_path` (the output-path producer)
- plugin-buildfile `resolve_fs_path` (heph.file / heph.glob)
- builtins `heph.fs.glob` (replaces its local format!+normalize_path)
Escaping the workspace root is now a hard error everywhere, not a
silently-mangled path. Derive `Debug` on the public `path::Path` /
`Content` types per the Debug-on-public-types guideline.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
raphaelvigee
added a commit
to hephbuild/hephbuild.github.io
that referenced
this pull request
Jun 25, 2026
Paths passed to file(), glob(), out, and support_files are now lexically normalized and hard-error when .. escapes the workspace root (hephbuild/heph#128). Document this behavior in buildfile.md and exec.md to match the existing note in fs.md.
raphaelvigee
added a commit
to hephbuild/hephbuild.github.io
that referenced
this pull request
Jun 25, 2026
Paths passed to file(), glob(), out, and support_files are now lexically normalized and hard-error when .. escapes the workspace root (hephbuild/heph#128). Document this behavior in buildfile.md and exec.md to match the existing note in fs.md.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Spotted in a generated
.gitignore:The stray
./mid-path is a path-normalization smell. Root cause is not gitignore-specific: package-relative paths were joined with a bareformat!("{pkg}/{rel}")that left./..segments intact. A./openapi/...output declared in a BUILD file becamepkg/./openapi/...and flowed straight through to every consumer (gitignore just rendered it visibly).Fix
Single normalizing join helper in
hmodel::htpkg:join_rel_checked(pkg, rel)— lexically normalizes (drop./empty, resolve..), preserves a trailing slash (DirPath classification) and glob metacharacters, and hard-errors when a..escapes the workspace root.Routed all three package-relative join sites through it:
plugin-execspec_path_to_target_path— the output/support-path producer (the reported bug)plugin-buildfileresolve_fs_path—heph.file/heph.globbuiltinsheph.fs.glob— replaces its localformat!+normalize_pathDeclaring a path outside the workspace root is now a hard error at every site, rather than a silently-mangled path.
Also derives
Debugon the publicpath::Path/Contenttypes (per the Debug-on-public-types guideline; needed forResultassertions in tests).Tests
hmodel::htpkgunit tests:./empty collapse,..resolution, trailing-slash + glob-metachar preservation, root-escape error.plugin-exectest freezingspec_path_to_target_pathnormalization, File/Dir/Glob classification, and the escape hard-error.All touched-crate tests pass;
cargo clippy -- -D warningsclean; full workspace builds.🤖 Generated with Claude Code