microsoft / microsoft/hve-core

refactor(scripts): make lexical path-containment checks consistent across eval and marketplace helpers

Open
#2,692 0 comments 0 reactions 1 assignee View on GitHub

@WilliamBerryiii is already working on this.

Since Aug 13, 2026.

maintenance needs-triage priority-4 refactor scripts
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

  1. Build-AgentInventory.ps1 and Get-AgentDependencyMap.ps1 contain the same relativization helper duplicated. Extract it into one shared function, or at minimum make both compare with a separator-terminated prefix, matching AffectedAgents.psm1.
  2. Leave MarketplaceHelpers.psm1 and AffectedAgents.psm1 alone unless the refactor absorbs them naturally; both are already correct.
  3. Do not import the installer's Assert-WithinTargetRoot ancestor 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.md does not relativize as if it were inside <root>.
  • npm run lint:ps is clean repository-wide and npm run test:ps passes.

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.