Skip to content

fix: harden SQL Server 2025 installer downloads - #296

Open
cheenamalhotra wants to merge 1 commit into
tediousjs:masterfrom
cheenamalhotra:dev/cheena/potential-meme
Open

cheenamalhotra wants to merge 1 commit into
tediousjs:masterfrom
cheenamalhotra:dev/cheena/potential-meme

Conversation

@cheenamalhotra

@cheenamalhotra cheenamalhotra commented Oct 6, 2026 •

Copy link
Copy Markdown

Documents and improves SQL Server 2025 install support.

Changes

  • SSEI bootstrapper now downloads media into its own temp folder, so other .exe files in the download dir can't be picked by mistake.
  • Quote /MediaPath so paths with spaces work.
  • Fail clearly if the bootstrapper produces no installer or more than one.
  • Add sql-2025 to the CI runaction matrix.
  • List supported versions in action.yml input and add a SQL 2025 section to README.
  • Add tests for 2025 version aliases, caching, path quoting and error cases.

Testing

  • npm run test: 92 passing
  • npm run lint, npm run build: clean

cc @arthurschreiber @saurabh500 @David-Engel

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@cheenamalhotra
cheenamalhotra marked this pull request as ready for review October 6, 2026 05:45
@dhensby
dhensby requested a balanced review from Copilot October 6, 2026 09:47

Copilot AI 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.

Copilot review overview

🟢 Approval recommended

The implementation is focused and well tested, with only a non-blocking import-order issue.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
What changed in this PR

Hardens SQL Server 2025 media downloads and documents/tests the supported workflow.

Changes:

  • Isolates SSEI downloads, quotes paths, and validates installer output.
  • Adds SQL Server 2025 documentation and CI coverage.
  • Expands tests for aliases, caching, paths, and failures.
File Description
src/​utils.ts Hardens SSEI media handling.
test/​utils.ts Tests download behavior and errors.
test/​install.ts Tests cached SSEI media.
action.yml Documents supported versions.
README.md Adds SQL Server 2025 guidance.
.github/​workflows/​release.yml Adds SQL 2025 integration coverage.
.github/​copilot-instructions.md Documents isolated media handling.

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

Comment thread src/utils.ts

@dhensby dhensby left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks @cheenamalhotra, this looks good.

Downloading the SSEI media into its own temp directory and requiring exactly one installer is sensible hardening. CI also confirms the bootstrapper accepts the quoted /MediaPath on a real runner: the windows-2025/sql-2025 job ran with /MediaPath="D:\a\_temp\sqlserver-media-3KLYYW" and got a single SQLServer2025-STDDEV-x64-ENU.exe. Adding sql-2025 to the matrix also restores our existing convention of testing sql-latest alongside each explicit version, which got missed when 2025 support was added.

I've left a couple of small docs nits inline. There are also two suggestions for bringing the rest of the code in line with what you've done here: quoting the other install paths, and isolating the box installer's extraction in the same way. Either can be done here or in a follow-up, whichever you prefer.

Heads-up: this conflicts with #295 (README, the node:fs/promises import in src/utils.ts, the module mocks in test/utils.ts, and lib/). Whichever PR lands second will need a rebase and a fresh npm run build.

Comment thread README.md
Comment on lines +55 to +56
The action downloads the installation media using Microsoft's SSEI bootstrapper
and caches the extracted installer for subsequent runs.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: GitHub-hosted runners start every job on a fresh VM, so the cached installer is only reused when the runner persists (e.g. self-hosted runners). Maybe soften this to say it attempts to cache?

Suggested change
The action downloads the installation media using Microsoft's SSEI bootstrapper
and caches the extracted installer for subsequent runs.
The action downloads the installation media using Microsoft's SSEI bootstrapper
and attempts to cache the extracted installer for subsequent runs.

**Installer abstraction:** `src/installers/` contains a base `Installer` class and `MsiInstaller` subclass used by the native client and ODBC installations. SQL Server itself uses direct exe/box download logic or the SSEI bootstrapper (for 2025+) in `src/utils.ts`.

**Version registry:** `src/versions.ts` defines a `Map<string, VersionConfig>` with download URLs (exe/box or SSEI), optional update URLs, and OS compatibility constraints for each supported SQL Server version (2008–2025). SQL Server 2025+ uses the SSEI bootstrapper model (`sseiUrl`) instead of direct exe/box downloads.
**Version registry:** `src/versions.ts` defines a `Map<string, VersionConfig>` with download URLs (exe/box or SSEI), optional update URLs, and OS compatibility constraints for each supported SQL Server version (2008–2025). SQL Server 2025+ uses the SSEI bootstrapper model (`sseiUrl`) instead of direct exe/box downloads. Its media is downloaded into an isolated temporary directory before extracting and caching the installer.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: "Its" here reads as if it refers to the version registry, but the behaviour lives in downloadSseiInstaller() in src/utils.ts. Maybe something like:

Suggested change
**Version registry:** `src/versions.ts` defines a `Map<string, VersionConfig>` with download URLs (exe/box or SSEI), optional update URLs, and OS compatibility constraints for each supported SQL Server version (2008–2025). SQL Server 2025+ uses the SSEI bootstrapper model (`sseiUrl`) instead of direct exe/box downloads. Its media is downloaded into an isolated temporary directory before extracting and caching the installer.
**Version registry:** `src/versions.ts` defines a `Map<string, VersionConfig>` with download URLs (exe/box or SSEI), optional update URLs, and OS compatibility constraints for each supported SQL Server version (2008–2025). SQL Server 2025+ uses the SSEI bootstrapper model (`sseiUrl`) instead of direct exe/box downloads. For SSEI versions, `downloadSseiInstaller()` downloads the media into an isolated temporary directory before extracting and caching the installer.

Comment thread src/utils.ts
await exec.exec(`"${sseiPath}"`, [
'/Action=Download',
`/MediaPath=${mediaDir}`,
`/MediaPath="${mediaDir}"`,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It'd be good to quote the other paths we pass with windowsVerbatimArguments: true in the same way, so the action handles spaces consistently. These are currently unquoted:

  • /UpdateSource=${dirname(updatePath)} in src/install.ts
  • the .msi path after /i in src/installers/msi-installer.ts

Comment thread src/utils.ts
}
// use the bootstrapper to download the actual media
const mediaDir = dirname(sseiPath);
const mediaDir = await mkdtemp(joinPaths(dirname(sseiPath), 'sqlserver-media-'));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It'd be good to bring downloadBoxInstaller in line with this too. It still extracts into dirname(exePath) (the shared runner temp directory) and caches <temp>/setup, so the box and SSEI paths now behave differently. Giving the box extraction its own mkdtemp directory, perhaps via a small shared helper, would keep the two aligned.

Sign up for free to 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.

3 participants