Skip to content

Add .NET Configuration Variables rewriter to IIS deploy (Phase 6)

Placeholder ppxd requested to merge feat/iis-deploy-config-variables into main

Summary

Mirrors Octopus's Octopus.Features.ConfigurationVariables feature (Calamari.Common/Features/Behaviours/ConfigurationVariablesBehaviour.cs:15-81) — the agent walks every *.config file under WebRoot and replaces matching appSettings, applicationSettings, and connectionStrings entries with values from the deployment's variable set.

This is the operator-facing ".NET Configuration Variables" checkbox on the Octopus IIS step UI. After Phase 6, 5 of 7 UI sections from the Octopus IIS step are end-to-end covered by Squid:

UI section Status
Web Site ✅ Phase 1
Application Pool ✅ Phase 1 + 3.5
Bindings ✅ Phase 1 + 2 + 3.5
IIS Authentication ✅ Phase 3
.NET Configuration Variables ✅ Phase 6
Package selection ❌ Phase 10
Physical path "Package installation directory" mode ❌ Phase 10

What ships

Production (+175 LOC across 4 files)

File Change
IISDeployProperties.cs New ConfigurationVariablesEnabled constant — matches operator-facing UI checkbox
IISDeployScriptBuilder.cs New Build(action, variables) overload — ships deployment variable set as $SquidVariables hashtable. Always emitted (even when empty) so future features (SubstituteInFiles, StructuredConfigurationVariables) reuse the same channel
IISDeployActionHandler.cs DescribeIntentAsync now passes ctx.Variables through to the builder
DeployToIISWebSite.ps1 New Update-IISConfigurationVariables function with 3 XPath probes (appSettings/add@key, connectionStrings/add@name, applicationSettings//setting@name). Runs AFTER PreDeploy + BEFORE IIS configure dispatch

Test code (+466 LOC, 11 new tests across 3 tiers)

Tier New What
Drift detector 1 Pins Update-IISConfigurationVariables function + all 3 XPath probes + enablement-gate placement (after PreDeploy, before IIS configure)
Unit 5 $SquidVariables hashtable emission (empty + populated); positional ordering; escape rules for variable values; empty-name defensive skip
Pipeline E2E 1 Theory × 2 + 1 Fact Variables flow through pipeline → captured request (incl. sensitive); $SquidVariables always ships (even when feature off) so future phases reuse
Real-host 4 Real web.config stage → deploy → assert XML attribute replaced: appSettings value, connectionString value (sibling providerName survives), feature-disabled gate, no-matching-variable orphan pass-through

Octopus alignment notes

The agent-side rewriter mirrors ConfigurationVariablesBehaviour.cs:15-81 semantically. Same 3 XPath probes, same key/name match against variable set, same replacement scope. Squid embeds the rewriter inside the IIS deploy script (no DeployPackageCommand orchestrator yet); Octopus runs it as a separate convention. Operator-facing contract is byte-identical — operators carrying Octopus variable specs see same behaviour.

Sensitive variables flow through plaintext — same as Octopus. Script body is encrypted in Halibut TLS transit; rendered config file on disk contains plaintext. Log masking (Squid's Serilog masker) handles the sensitive-in-logs case separately.

Cumulative coverage state

  • Unit: 56 → 63 (+7)
  • Pipeline E2E: 9 → 12 (+3)
  • Real-host: 36 → 40 (+4)

Test plan

  • dotnet test --filter FullyQualifiedName~IISDeploy on macOS — 63 unit tests green
  • dotnet test --filter Category=IISDeployE2E on macOS — 40 real-host tests skip cleanly
  • dotnet build 0 errors
  • CI run on windows-latest: 4 new real-host tests against real web.config files

Out of scope (remaining phases)

Phase Scope
7 XML config transforms (XDT) — web.Release.config
8 Variable substitution INTO files (SubstituteInFiles) — #{X} tokens
9 JSON/YAML structured configuration variables
10 Package extraction (NuGet/Zip) — unblocks Physical path "Package installation directory" UI mode
11 Custom installation directory + purge
12 IIS certificate auto-import + private-key ACL

Breaking-change risk

None. Pure additive: new property, new builder overload (1-arg preserved), new PS1 function + gate (no-op when disabled). All existing tests unchanged.

Merge request reports

Loading