Installer: optional custom data/log file locations (#768)#1124
Merged
Conversation
#768) Add optional --data-path / --log-path CLI flags so the installer can place the PerformanceMonitor data (.mdf) and log (.ldf) files in caller-specified server-side directories. When omitted, behavior is unchanged: the database is created using SERVERPROPERTY('InstanceDefaultDataPath'/'InstanceDefaultLogPath'). - 01_install_database.sql declares @data_path_override/@log_path_override and an inert comment token the installer replaces with SET statements. The CREATE DATABASE step uses the override when present, else the instance default. Only applies on first creation (guarded by IF DB_ID(...) IS NULL); ignored if the database already exists. Managed Instance (engine edition 8) is unaffected. - Injection safety is two-layer: PathValidation rejects relative paths, control characters (CR/LF/tab), and "<>|*? plus a length cap; the C# layer doubles single quotes when building the SET literal; and the SQL builds the FILENAME literal via REPLACE(@path, N'''', N''''''). BuildFilePathOverrideSql re-validates so the Core API is self-defending regardless of caller. - New PathValidation class (Installer.Core) with 34 unit tests; help text, usage doc, and README options table updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Closes #768. The installer always created the
PerformanceMonitordatabase in the instance default data/log directories (SERVERPROPERTY('InstanceDefaultDataPath')/InstanceDefaultLogPath). There was no way to put the.mdf/.ldfon a specific volume at install time.New flags + usage
Two optional CLI flags, appended to the existing positional
<server> [username] [password]contract (positional parsing is unchanged):--data-path DIR.mdf) file--log-path DIR.ldf) fileBoth
--data-path D:\SQLDataand--data-path=D:\SQLDataforms are accepted (mirrors--encrypt). Either flag is independent; an omitted one falls back to the instance default. Example:Help text (
--help), the top-of-Mainoptions comment, and the README options table + a usage example are updated.How CREATE DATABASE now branches
install/01_install_database.sql(inside the existingIF DB_ID(N'PerformanceMonitor') IS NULLguard):@data_path_override/@log_path_overridevariables (declared empty) and an inert comment token/*__PM_FILE_PATH_OVERRIDES__*/(file lines 40-51).IF LEN(@data_path_override) > 0 SET @data_path = @data_path_override + N'PerformanceMonitor.mdf' ELSE SET @data_path = CONVERT(..., SERVERPROPERTY('InstanceDefaultDataPath')) + ...(lines 82-106). Same for the log path.SET @..._override = N'...';statements only when a path is supplied (InstallationService.ExecuteInstallationAsync, file01_handling). When run without the flags, or outside the installer, the token stays an inert comment and the SERVERPROPERTY defaults are used exactly as before.CREATE DATABASEand ignores the overrides (MI doesn't support file specs).Injection safety
The path is user input flowing into a
FILENAME = N'...'literal (FILENAME cannot be parameterized inCREATE DATABASE, so the value must be concatenated into dynamic SQL). Defense is layered:Installer.Core/PathValidation.cs): rejects empty/relative paths, control characters (CR/LF/tab — so no extra statements/batches can be smuggled), the chars" < > | * ?, and caps length at 480. Requires an absolute Windows drive / UNC / Linux path. Single quote is intentionally allowed (legal in Windows paths) and handled by escaping.SET @override = N'...'literal, single quotes are doubled (EscapeSqlStringLiteral).BuildFilePathOverrideSqlre-validates each path so the Core API is self-defending even if a future caller bypasses the CLI.CREATE DATABASEbuilds the FILENAME literal viaREPLACE(@data_path, N'''', N'''''')(both the primary and the model-resize retry blocks), doubling quotes again at runtime.A security review traced quote-doubling, control characters, truncation desync, and the GO/
:rpost-processing and found no breakout.Idempotency / already-exists behavior
The DB-creation block is guarded by
IF DB_ID(N'PerformanceMonitor') IS NULL, so re-running the installer is a no-op for creation. The custom paths therefore apply only on first creation — if the database already exists they are ignored (documented in--help, the README, and the install echo). This is install-only behavior, so noupgrades/script is needed.Validation
dotnet build Installer/PerformanceMonitorInstaller.csproj -c Debug→ Build succeeded, 0 errors, 0 warnings.dotnet test Installer.Tests --filter "Category!=Integration"→ 61 passed, 0 failed (34 newPathValidationTests). Integration tests (which require a live SQL Server) were not run.Risk note
--data-path/--log-pathare server-side directories. They must already exist on the SQL Server host and the SQL Server service account must have write permission, orCREATE DATABASEwill fail (SQL Server does not create directories for data files). The installer validates only path shape on the client, not existence on the server.🤖 Generated with Claude Code