Skip to content

fix(build): verify the PSGallery source before installing from it - #51

Merged
tablackburn merged 3 commits into
mainfrom
fix/verify-psgallery-source
Aug 18, 2026
Merged

fix(build): verify the PSGallery source before installing from it#51
tablackburn merged 3 commits into
mainfrom
fix/verify-psgallery-source

Conversation

@tablackburn

@tablackburntablackburn commented Aug 18, 2026

Copy link
Copy Markdown
Owner

A repository named PSGallery is not necessarily the PowerShell Gallery. build.ps1 accepted any existing registration on the strength of its name and then installed every dependency in build.depend.psd1 from it. A registration pointing elsewhere — a mirror, a proxy, or something deliberately placed — would have supplied all of them silently.

What it checks

The source location is parsed and compared on scheme, host and port:

$expectedSource= [Uri]'https://www.powershellgallery.com/api/v2'$actualSource=$psGallery.SourceLocation-as [Uri]
$sourceIsExpected=$null-ne$actualSource-and$actualSource.Scheme-eq$expectedSource.Scheme-and$actualSource.Host-eq$expectedSource.Host-and$actualSource.Port-eq$expectedSource.Port
Source locationAcceptedWhy
https://www.powershellgallery.com/api/v2yescanonical
https://WWW.PowerShellGallery.com/api/V2yeshost names are case-insensitive
https://www.powershellgallery.com:443/api/v2yes443 is the https default
https://www.powershellgallery.com/other-pathyessame host, see below
https://www.powershellgallery.com:444/api/v2nodifferent listener
http://www.powershellgallery.com/api/v2nowrong scheme
https://evil.example.com/api/v2nodifferent host
not-a-urinounparseable

Not a string comparison.-ne is case-insensitive, so a differently cased value slipped through; -cne would be wrong in the other direction, rejecting https://WWW.PowerShellGallery.com/api/v2, which is the real gallery.

Path deliberately not compared. The gallery serves both /api/v2 and /api/v3, and any path on the genuine host is still the genuine host. Host and port are the trust boundary; pinning the path would only add a false rejection.

Provenance

Found by review on SrrDBAutomationToolkit #36 and already shipped there and in ScheduledTasksManager. This propagates it to the remaining four, whose build.ps1 files were byte-identical (sha1 d6e2a118) — verified by diff before copying.

Behavioural note

This throws rather than warning. A build environment with PSGallery registered against a different host or port now fails instead of quietly installing from it. Verified against a normal registration: JsmOperations 118 passed, YouTubeMusicPS 323 passed, and the rendered template 30 passed, with the check inert.

No CHANGELOG.md entry: build tooling, not user-facing.

🤖 Generated with Claude Code

https://claude.ai/code/session_01G1CarQG8VibNFxw4cN53Zs

Summary by CodeRabbit

  • Bug Fixes
    • Setup now verifies that the PowerShell Gallery is configured with the official source before continuing.
    • Setup stops with a clear error when the repository is missing or points to an unexpected source.
    • This helps prevent bootstrapping from using an incorrect or untrusted package source.

A repository named PSGallery is not necessarily the PowerShell Gallery.
build.ps1 accepted any existing registration on the strength of its name and
then installed every dependency in build.depend.psd1 from it. A registration
pointing at another SourceLocation -- a mirror, a proxy, or something
deliberately placed -- would have supplied all of them silently.
The source URL is now compared against the canonical one and a mismatch
throws.
Found by review on SrrDBAutomationToolkit and already shipped there and in
ScheduledTasksManager. build.ps1 is byte-identical across the remaining four
repositories, and this change is a pure ten-line addition to each with
nothing else touched.
Unsigned at the author's request -- 1Password is unavailable this session.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G1CarQG8VibNFxw4cN53Zs
CopilotAI lite review requested due to automatic review settings August 18, 2026 00:26
@coderabbitai

coderabbitaiBot commented Aug 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 42a9ec1f-78a7-47ca-ba10-944266719d50

📥 Commits

Reviewing files that changed from the base of the PR and between 0e4a588 and c9f5aa9.

📒 Files selected for processing (1)
  • build.ps1
🚧 Files skipped from review as they are similar to previous changes (1)
  • build.ps1

Included review availability: Your plan includes up to 1 review per rolling hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The bootstrap script validates the registered PSGallery source before installing dependencies. It rejects missing or unexpected repository endpoints while allowing valid gallery paths.

Changes

Bootstrap validation

Layer / File(s)Summary
PSGallery source validation
build.ps1
The bootstrap script validates the repository scheme, host, and port, then stops dependency installation when the source is unexpected.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk:⚪ Minimal · up to c9f5a

The build now rejects a PSGallery registration that points to an unexpected source, preventing dependencies from being installed from an unintended repository; no actionable merge-blocking risk remains after normal checks and review.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly and concisely describes the main change: validating the PSGallery source before dependency installation.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/verify-psgallery-source

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the build bootstrap process by ensuring that the PSGallery repository name actually points to the official PowerShell Gallery endpoint before any build dependencies are installed from it. This prevents a locally-registered repository named PSGallery (but backed by a different URL) from silently supplying all modules listed in build.depend.psd1.

Changes:

  • Adds a strict SourceLocation verification for the PSGallery PSRepository during -Bootstrap.
  • Throws with a clear error message if PSGallery is registered to an unexpected URL.
  • Ensures dependency installation only proceeds when the repository identity (URL) matches the expected PowerShell Gallery endpoint.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Review pointed out that -ne is case-insensitive, so a source location
differing only in case would pass the check, and suggested -cne.
-cne would be wrong in the other direction. Host names are case-insensitive
by definition, so a strict comparison rejects
https://WWW.PowerShellGallery.com/api/v2 -- which is the real gallery. The
identifying part is the host, and a repository standing in for the gallery
would differ there, not in casing.
The source location is now parsed and its scheme and host compared, which
accepts any casing of the genuine host and rejects a different one.
Unparseable values are rejected too, where the previous string comparison
would have thrown on a null SourceLocation instead.
Verified:
https://www.powershellgallery.com/api/v2 accepted
https://WWW.PowerShellGallery.com/api/V2 accepted
https://evil.example.com/api/v2 rejected
not-a-uri rejected
Unsigned at the author's request -- 1Password is unavailable this session.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G1CarQG8VibNFxw4cN53Zs
@tablackburn
tablackburn requested a lite review from CopilotAugust 18, 2026 03:48
@tablackburn

Copy link
Copy Markdown
OwnerAuthor

@coderabbitai full review

@coderabbitai

coderabbitaiBot commented Aug 18, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 59 minutes.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Review noted that comparing scheme and host alone accepts
https://www.powershellgallery.com:444/api/v2. A non-default port on the same
name reaches a different listener, so that is a real gap. Port is now
compared too; [Uri] supplies 443 for https when none is given, so the
canonical URL and an explicit :443 both match.
The path is still deliberately not compared, and the comment now says why:
the gallery serves both /api/v2 and /api/v3, and any path on the genuine
host is still the genuine host. Host and port are the trust boundary, so
pinning the path would only add a false rejection for a legitimate
registration.
The three stacked comment blocks this accumulated over successive reviews
are consolidated into one.
Verified:
https://www.powershellgallery.com/api/v2 accepted
https://WWW.PowerShellGallery.com/api/V2 accepted
https://www.powershellgallery.com:443/api/v2 accepted
https://www.powershellgallery.com/other-path accepted
https://www.powershellgallery.com:444/api/v2 rejected
http://www.powershellgallery.com/api/v2 rejected
https://evil.example.com/api/v2 rejected
not-a-uri rejected
Unsigned at the author's request -- 1Password is unavailable this session.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G1CarQG8VibNFxw4cN53Zs
@tablackburn
tablackburn merged commit ae8d488 into mainAug 18, 2026
11 checks passed
@tablackburn
tablackburn deleted the fix/verify-psgallery-source branch August 18, 2026 15:56
Sign up for freeto 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.

2 participants

@tablackburn