Skip to content

G1.4: ExtractPackageStep — pre-rewriter .nupkg/.zip extraction

Placeholder ppxd requested to merge feat/calamari-g1-4-extract-package into main

Summary

Closes the "extract before rewriter" gap. When the wire literal Squid.Action.Package.OriginalPath points at a .nupkg / .zip, the new step extracts it into context.WorkingDirectory BEFORE the rewriter pipeline runs. Standalone-script deploys (no package) keep their existing UX — the step is a no-op when the literal is unset.

Pipeline: LoadVariablesFromFiles → ExtractPackage → SubstituteInFiles → ConfigurationTransforms → JsonConfigVariables → WriteBootstrapped → Execute.

Hostile-archive safety

Defence What it catches Test
Zip-slip Entry with .. resolving outside destination Extract_ZipSlipEntry_Rejected_DestinationUntouched + 2 variants
Absolute path /etc/passwd / C:\Windows\... Extract_AbsolutePathEntry_Rejected
Per-entry size cap Single huge file Extract_EntryExceedsPerEntryCap_Rejected — reuses shared T3 env var
Total size cap (zip-bomb) Many entries summing to multi-GB Extract_TotalSizeExceedsBombCap_RejectedMidStream — 10x per-entry
Fail-closed Any single violation aborts whole extract All above — never partial extract
Overwrite Re-deploys land cleanly Extract_OverwritesExistingFiles_SecondExtractWins

What's in the box

Layer File
Pure-function extractor src/Squid.Calamari/Commands/Package/ZipExtractor.cs (new)
Pipeline step + wire literal src/Squid.Calamari/Commands/Package/ExtractPackageStep.cs (new)
Pipeline wiring src/Squid.Calamari/Commands/RunScriptCommand.cs
ZipExtractor tests (11) tests/Squid.Calamari.Tests/Calamari/Commands/Package/ZipExtractorTests.cs (new)
Step tests (12) tests/Squid.Calamari.Tests/Calamari/Commands/Package/ExtractPackageStepTests.cs (new)

Test plan

  • Squid.Calamari.Tests: 300/300 (was 277; +23)
  • Solution build: 0 errors
  • Wire literal Squid.Action.Package.OriginalPath pinned (Rule 8 drift detector)
  • Per-entry size cap reuses T3 env var SQUID_CALAMARI_REWRITER_MAX_FILE_SIZE_MB
  • Standalone-script deploys (no OriginalPath set) are zero-impact — IsEnabled short-circuits
  • Staging: actual .nupkg deploy with appsettings.json requiring token substitution post-extract

Non-breaking guarantee

Surface Status
Existing wire literals Unchanged
Standalone script deploys (no OriginalPath) Zero impact — step skips
IIS PS1 in-script extraction path Unchanged — Squid Calamari ExtractPackageStep doesn't replace it; the PS1 still handles its own extract until that's migrated separately
SquidWeb Unchanged — OriginalPath is server-emitted, not operator-facing

The IIS handler's PS1 still does its own in-script extraction; this PR adds the agent-pipeline extraction surface that future generic handlers (RunScript with package, Docker, nginx, etc.) will emit OriginalPath to drive.

Merge request reports

Loading