Python script runner (multi-shell Calamari)
Summary
Calamari can now execute Python scripts natively. Operator names the file .py → runs through the same RunScriptCommand pipeline as bash + PowerShell (extract, rewriters, conventions, variable injection).
Clean clone of the PR-4 (#374) PowerShell pattern. Zero new NuGet deps — python3/python resolved via PATH probe.
What's in the box
| Layer | File |
|---|---|
ScriptSyntax.Python |
enum +1 value |
Detector .py → Python |
ScriptSyntaxDetector.cs |
Executor (python3 → python fallback, -u) |
PythonScriptExecutor.cs (new) |
| Adapter (registered in ScriptEngine) |
PythonScriptExecutorAdapter.cs (new) |
Bootstrapper (os.environ[...]) |
PythonVariableBootstrapper.cs (new) |
| Bootstrap step dispatch | RunScriptCommandPipeline.cs |
Variable injection
os.environ['VAR'] = 'value' preamble. Same name sanitiser as bash/PS (./-// → _) so the same operator variable resolves under any shell. Lossless single-quote escaping (\→\\, '→\', newline→\n, CR→\r, tab→\t) — multi-line PEM values round-trip + stay readable in the bootstrapped script.
Known limitation (documented)
The preamble is prepended, so from __future__ import ... (must be statement #1 (closed)) is unsupported — rare in deployment scripts; workaround is to drop it. Consistent with how bash/PS bootstrappers prepend.
Test plan
-
Squid.Calamari.Tests: 518/518 (was 504; +14) -
Build: 0 errors -
PythonVariableBootstrapperTests (7): os.environ injection, name parity, escaping (quote/backslash/newline/tab/CR), empty set -
PythonScriptExecutorTests (4): neither-binary → actionable error; -u+ script-path argv; exit-code propagation -
Detector + bootstrap-step .pydispatch -
Staging: real .pydeploy readingos.environvariables
Non-breaking guarantee
| Surface | Status |
|---|---|
| Bash + PowerShell paths | Unchanged |
| Wire literals | None added |
ScriptSyntax enum |
Additive (Python=3) |
| SquidWeb | Untouched |