Measured
load resolves each [inherit] paths entry as root.join(relative) and reads it with no containment check (src/config.rs:1785-1787, at v1.22.0). Inherit::paths is documented as "repository-relative" (src/config.rs:340-343), and docs/REFERENCE.md says the same, but nothing enforces it: paths = ["../policy/rules.toml"] loads a file outside the repository, and an absolute path replaces the root entirely, because Path::join with an absolute argument discards the base.
Why it matters
This is the upward borrow the engine refuses everywhere else. discover stops at the repository boundary and no_policy_here says an enclosing superproject's policy is not borrowed (src/main.rs:230-273); tests/root_cli.rs:103 holds that line. inherit.paths is the one road around it, and it looks like an ordinary policy line.
A member of a superproject that inherits ../policy/rules.toml passes inside the superproject and fails fatally in a standalone clone of the member, where read_to_string finds nothing at that path. The member's verdict then depends on where it was cloned, which is a report about something other than the repository.
The same root.join shape applies to include roots, which Selection::build already refuses when they point outside the tree; inherit.paths has no such refusal.
Done when
- An
[inherit] paths entry that is absolute, or that resolves outside the repository root (after .. components and symlinks), is refused at load, exit 2, with a message naming the entry and the direction rule: a repository's policy is its own, and a member does not borrow upward from what encloses it.
- A CLI test in
tests/ on a scratch superproject (support::scratch) with a member whose policy inherits ../policy/rules.toml asserts the refusal and the message, and a second case asserts a path inside the repository still loads.
docs/REFERENCE.md, at the inherit.paths paragraph, says a path must stay inside the repository and why.
Measured
loadresolves each[inherit] pathsentry asroot.join(relative)and reads it with no containment check (src/config.rs:1785-1787, at v1.22.0).Inherit::pathsis documented as "repository-relative" (src/config.rs:340-343), anddocs/REFERENCE.mdsays the same, but nothing enforces it:paths = ["../policy/rules.toml"]loads a file outside the repository, and an absolute path replaces the root entirely, becausePath::joinwith an absolute argument discards the base.Why it matters
This is the upward borrow the engine refuses everywhere else.
discoverstops at the repository boundary andno_policy_heresays an enclosing superproject's policy is not borrowed (src/main.rs:230-273);tests/root_cli.rs:103holds that line.inherit.pathsis the one road around it, and it looks like an ordinary policy line.A member of a superproject that inherits
../policy/rules.tomlpasses inside the superproject and fails fatally in a standalone clone of the member, whereread_to_stringfinds nothing at that path. The member's verdict then depends on where it was cloned, which is a report about something other than the repository.The same
root.joinshape applies toincluderoots, whichSelection::buildalready refuses when they point outside the tree;inherit.pathshas no such refusal.Done when
[inherit] pathsentry that is absolute, or that resolves outside the repository root (after..components and symlinks), is refused at load, exit 2, with a message naming the entry and the direction rule: a repository's policy is its own, and a member does not borrow upward from what encloses it.tests/on a scratch superproject (support::scratch) with a member whose policy inherits../policy/rules.tomlasserts the refusal and the message, and a second case asserts a path inside the repository still loads.docs/REFERENCE.md, at theinherit.pathsparagraph, says a path must stay inside the repository and why.