Skip to content

Decouple G1.x wire literals from the IIS handler

Placeholder ppxd requested to merge feat/calamari-g1-generic-wire-literals into main

Summary

Architectural fix from the G1.x review. The rewriter steps had generic implementations but were silently coupled to the IIS handler via IIS-prefixed wire literals. A future RunScript / Docker / nginx handler wanting these features would have had to emit IIS-prefixed variable names — wrong on its face, and a breaking change to fix later. Fix it now.

Stacks on #366 (the H1 hardening PR). After both #365 and #366 merge, this PR's base can be retargeted at master.

SquidWeb zero-impact: the IIS editor's wire-literal arrays all reference the IIS-prefixed names; the IIS handler emits them; the Calamari step's legacy fallback reads them. The new canonical names are purely additive — for future generic handlers.

The two-halves wire contract

Each of the 3 features (SubstituteInFiles / ConfigurationTransforms / JsonConfigVariables) now has:

Half Where What new code should use Back-compat
Canonical (top-level on *VariableNames) Squid.Action.<Feature>.<Property> ✅ Yes — new handlers emit these Step reads FIRST
Legacy (nested .Legacy class) Squid.Action.IISWebSite.<Feature>.<Property> ❌ No — kept for the IIS PS1 script + saved deploys Step falls back to it when canonical is absent
// IsEnabled / Execute pattern in each step
var raw = context.Variables.Get(<Feature>VariableNames.Enabled)              // canonical first
          ?? context.Variables.Get(<Feature>VariableNames.Legacy.Enabled);   // legacy fallback

What's renamed at the wire-literal level

Feature Legacy (kept, IIS emits this) Canonical (new, generic)
SubstituteInFiles Squid.Action.IISWebSite.SubstituteInFiles.Enabled Squid.Action.SubstituteInFiles.Enabled
ConfigurationTransforms Squid.Action.IISWebSite.ConfigurationTransforms.Enabled Squid.Action.ConfigurationTransforms.Enabled
StructuredConfigurationVariables → JsonConfigVariables Squid.Action.IISWebSite.StructuredConfigurationVariables.Enabled Squid.Action.JsonConfigVariables.Enabled

The JSON-leaf feature's canonical name drops the StructuredConfigurationVariables label — aligns with the frontend's existing feature ID Squid.Features.JsonConfigurationVariables, and accurately describes the JSON-only scope.

The C# class StructuredConfigVariableNames keeps its name (no ripple-rename); new alias JsonConfigVariableNames exposes the same canonical literals for new handlers.

What's in the box

Layer File
Canonical + Legacy constants + dual-read src/Squid.Calamari/Commands/Substitution/SubstituteInFilesStep.cs
Same src/Squid.Calamari/Commands/Configuration/ConfigurationTransformsStep.cs
Same + new JsonConfigVariableNames alias src/Squid.Calamari/Commands/StructuredConfig/StructuredConfigVariablesStep.cs
Drift detector — Sub tests/Squid.UnitTests/.../IISSubstituteInFilesWireContractTests.cs (8 tests; was 4)
Drift detector — Conf tests/Squid.UnitTests/.../IISConfigurationTransformsWireContractTests.cs (6 tests; was 4)
Drift detector — Json tests/Squid.UnitTests/.../IISStructuredConfigVariablesWireContractTests.cs (8 tests; was 4)
Back-compat + precedence per-step step test files
3-step composition E2E (review gap T1) tests/Squid.Calamari.Tests/Calamari/Commands/RewriterPipelineCompositionTests.cs (new, 3 tests)

Test plan

  • Squid.Calamari.Tests: 258/258 (was 246; +12)
  • Squid.UnitTests cross-project wire-contract: 5625/5625 (was 5615; +10)
  • Build solution-wide: 0 errors
  • 3-step composition test drives all 3 steps in order using ONLY canonical literals — proves a future generic handler can use the pipeline without any IIS-specific knowledge
  • Back-compat tests drive the steps with ONLY legacy literals + real file rewriting — confirms existing IIS deploys keep working
  • Precedence test confirms canonical wins when both are set (dual-emit scenario)
  • Idempotency byte-identity test confirms running the chain twice produces no diff (review gap T2)
  • Staging: real IIS deploy with existing project definitions (IIS-prefixed variables) — backward-compat smoke
  • Staging: synthetic test with canonical-only variables driving a RunScript handler (no such handler exists yet, but the wire surface is ready)

Non-breaking guarantee

Surface Status
Existing wire literals (Squid.Action.IISWebSite.*) Preserved as .Legacy.*; same string values
IIS PS1 script Unchanged — still reads IIS-prefixed names
IISDeployProperties constants Unchanged
Frontend (DeployToIisEditor.tsx) Unchanged — arrays still reference IIS-prefixed names
Operator's existing deployment definitions in DB Unchanged behavior
SubstituteInFilesStep.EnabledVariableName etc. (internal) Value changes from IIS-prefixed to canonical — only referenced by the test file that's updated in the same PR

Merge request reports

Loading