microsoft / microsoft/hve-core
refactor(scripts): make lexical path-containment checks consistent across eval and marketplace helpers
@WilliamBerryiii is already working on this.
Since Aug 13, 2026.
- Dominant language
- Python
- Stars
- 1.5k
- Forks
- 301
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 92
Description
Summary
Four PowerShell helpers compare paths with a lexical StartsWith prefix test. This issue tracks making them consistent. It is not a security issue, and the reasoning for that conclusion is recorded below so nobody has to re-derive it.
Why this looks alarming and is not
PR #2599 fixed a genuine containment bug in the installer, where $targetFull.StartsWith($targetBase, Ordinal) passed by construction and writes escaped the target root. Anyone grepping for that expression afterwards will find these four sites and reasonably suspect the same exposure.
They were each assessed by reading the call site rather than pattern-matching the expression:
| Site | What the check actually does | Risk |
|---|---|---|
scripts/lib/Modules/MarketplaceHelpers.psm1:1202 |
Membership validation that throws on match. $root is built with a trailing /, so it is already separator-terminated. Fail-closed. |
None |
scripts/evals/Build-AgentInventory.ps1:104 |
Computes a display-relative path; returns the original path unchanged when it does not match | None; graceful fallback |
scripts/evals/Get-AgentDependencyMap.ps1:76 |
Identical relativization helper with the same fallback | None; duplicate of the above |
scripts/evals/Modules/AffectedAgents.psm1:74 |
Already appends '/' before comparing, and is guarded by IsPathRooted |
None; already correct |
None of the four gates a filesystem write or a trust decision. Two already compare with a trailing separator. The worst realistic outcome in the other two is a slightly wrong relative path string in an inventory when one directory name prefixes another, for example agents-legacy against agents.
Proposed work
Build-AgentInventory.ps1andGet-AgentDependencyMap.ps1contain the same relativization helper duplicated. Extract it into one shared function, or at minimum make both compare with a separator-terminated prefix, matchingAffectedAgents.psm1.- Leave
MarketplaceHelpers.psm1andAffectedAgents.psm1alone unless the refactor absorbs them naturally; both are already correct. - Do not import the installer's
Assert-WithinTargetRootancestor reparse-point walk here. That function exists to stop writes escaping a root; these sites do not write, and adding a filesystem walk to a string helper would be cost without benefit.
Acceptance Criteria
- The duplicated relativization logic exists in one place, or both copies compare separator-terminated.
- A test covers the sibling-prefix case, for example that
<root>-legacy/x.mddoes not relativize as if it were inside<root>. -
npm run lint:psis clean repository-wide andnpm run test:pspasses.
Notes for whoever picks this up
Watch for PSUseDeclaredVarsMoreThanAssignments if you introduce a shared helper whose return value some call sites ignore; pipe to | Out-Null where only the side effect is wanted. That rule failed the build during #2599 for exactly this reason.
Verified against main at 278eb128.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.