Browse Source
- new src/tests/modules/punk/mix/testsuites/scriptwrap/multishell.test (9 tests, green on tcl 9.0.3 + 8.7, unix exec case constraint-gated): scriptset wrap via the module-provided punk.multishell.cmd template (payloads + _wrap.toml fixture) - output produced, MULTISHELL magic line, payloads embedded verbatim, configured win32 nextshell present, LF-only endings, byte-identical re-wrap determinism; checkfile 512-byte label/boundary validation reports no label location errors for a fresh wrap AND for the committed bin/runtime.cmd; the runtime scriptset ROUND-TRIP pin - re-wrapping src/scriptapps runtime.ps1+runtime.bash+runtime_wrap.toml reproduces bin/runtime.cmd byte for byte (verified identical before pinning), so hand-edits to the output or unregenerated payload changes both fail; execution smoke - cmd.exe runs the polyglot and dispatches the powershell payload (windows), sh payload execution gated to unix (on windows the shell layer deliberately relaunches via the win32 nextshell) - guidance strengthened so "fix bin/<name>.cmd" routes to sources: root AGENTS.md bin/ index entry now states the .cmd polyglots are scriptwrap-generated from src/scriptapps; bin/AGENTS.md gains a "Generated polyglot .cmd scripts - never edit in place" section with the 4-step fix workflow (edit payloads/toml, re-wrap with multishell -askme 0, heed checkfile ERRORs, commit source + regenerated output together); src/scriptapps/AGENTS.md documents the scriptset->bin/*.cmd relationship and regeneration command; tests index updated - context: the polyglot technique is deliberately maintained despite fragility (user direction 2026-07-10) until hiding techniques close in the underlying languages - these pins are the guardrails Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.commaster
5 changed files with 260 additions and 2 deletions
@ -0,0 +1,236 @@
|
||||
package require tcltest |
||||
|
||||
package require Thread ;#punk::fileline textinfo (used by scriptwrap checkfile) calls thread::id |
||||
package require punk::mix::commandset::scriptwrap |
||||
|
||||
#Characterization of the punk MULTISHELL polyglot build machinery |
||||
#(punk::mix::commandset::scriptwrap::multishell + checkfile) - added 2026-07-10 at the |
||||
#user's direction: the polyglot technique is deliberately maintained despite its |
||||
#fragility, so the machinery that generates bin/*.cmd (e.g bin/runtime.cmd from |
||||
#src/scriptapps/runtime.ps1 + runtime.bash + runtime_wrap.toml) needs pins. |
||||
# |
||||
#Covered: |
||||
# - wrapping a scriptset (payload scripts + <scriptset>_wrap.toml) via the module-provided |
||||
# punk.multishell.cmd template produces the polyglot with payloads embedded verbatim |
||||
# - the output is LF-only (the cmd.exe label scanner reads 512-byte chunks; the whole |
||||
# mechanism depends on unix line endings - see checkfile comments in the module) |
||||
# - wrapping is deterministic (byte-identical on re-wrap) |
||||
# - checkfile (the 512-byte label/boundary validator) reports no label location errors |
||||
# for a fresh wrap AND for the committed bin/runtime.cmd - guarding against hand-edits |
||||
# or line-ending damage to the shipped artifact |
||||
# - execution smoke: the same file runs under cmd.exe on windows (dispatching to the |
||||
# configured win32 nextshell - powershell) and under sh/bash on unix. On windows the |
||||
# shell layer deliberately relaunches via the win32 nextshell, so the sh payload is |
||||
# execution-tested only on unix (constraint-gated); its embedding is asserted |
||||
# structurally everywhere. |
||||
# |
||||
#NOTE for agents: bin/*.cmd files are GENERATED - fix the payloads under src/scriptapps/ |
||||
#(<name>.ps1/.bash/.tcl + <name>_wrap.toml) and re-wrap; do not edit the polyglot output |
||||
#(see bin/AGENTS.md and src/scriptapps/AGENTS.md). |
||||
|
||||
namespace eval ::testspace { |
||||
namespace import ::tcltest::* |
||||
variable common { |
||||
set result "" |
||||
} |
||||
|
||||
variable testdir [file dirname [file normalize [info script]]] |
||||
#<projectroot>/src/tests/modules/punk/mix/testsuites/scriptwrap -> 7 levels up |
||||
variable projectroot [file normalize [file join $testdir .. .. .. .. .. .. ..]] |
||||
|
||||
variable ps_payload {Write-Host "MARKER_POWERSHELL_OK"} |
||||
variable sh_payload {echo "MARKER_SHELL_OK"} |
||||
|
||||
#write with explicit lf translation - payload/toml files are consumed byte-wise |
||||
proc writefile_lf {path content} { |
||||
set fd [open $path w] |
||||
fconfigure $fd -translation lf |
||||
puts $fd $content |
||||
close $fd |
||||
} |
||||
variable fixdir [makeDirectory scriptwrap_fixture] |
||||
writefile_lf $fixdir/wrapset.ps1 $ps_payload |
||||
writefile_lf $fixdir/wrapset.sh $sh_payload |
||||
writefile_lf $fixdir/wrapset_wrap.toml { |
||||
[application] |
||||
template="punk.multishell.cmd" |
||||
scripts=[ |
||||
"wrapset.ps1", |
||||
"wrapset.sh" |
||||
] |
||||
default_outputfile="wrapset.cmd" |
||||
default_nextshellpath="/usr/bin/env bash" |
||||
default_nextshelltype="bash" |
||||
win32.nextshellpath="cmd.exe /c powershell -nop -nol -ExecutionPolicy bypass -File" |
||||
win32.nextshelltype="powershell" |
||||
win32.outputfile="wrapset.cmd" |
||||
} |
||||
|
||||
#wrap once at load - most tests examine this output (multishell chats on stdout; that |
||||
#output is not part of test comparisons) |
||||
variable wrapresult "" |
||||
variable outfile "" |
||||
variable wrap_ok 0 |
||||
variable startdir [pwd] |
||||
cd $fixdir |
||||
if {![catch {punk::mix::commandset::scriptwrap::multishell wrapset -outputfolder $fixdir -askme 0 -force 1} wrapresult]} { |
||||
if {[dict exists $wrapresult filename]} { |
||||
set outfile [dict get $wrapresult filename] |
||||
set wrap_ok [file exists $outfile] |
||||
} |
||||
} |
||||
cd $startdir |
||||
testConstraint wrapok $wrap_ok |
||||
testConstraint iswindows [expr {$::tcl_platform(platform) eq "windows"}] |
||||
testConstraint isunix [expr {$::tcl_platform(platform) eq "unix"}] |
||||
|
||||
proc readbytes {path} { |
||||
set fd [open $path r] |
||||
fconfigure $fd -translation binary |
||||
set data [read $fd] |
||||
close $fd |
||||
return $data |
||||
} |
||||
|
||||
test scriptwrap_multishell_wrap_produces_output {wrapping a scriptset with payloads + _wrap.toml produces the polyglot output file}\ |
||||
-setup $common -body { |
||||
variable wrapresult |
||||
variable outfile |
||||
lappend result [dict exists $wrapresult filename] |
||||
lappend result [file exists $outfile] |
||||
lappend result [file tail $outfile] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1 1 wrapset.cmd] |
||||
|
||||
test scriptwrap_multishell_output_structure {output starts with the MULTISHELL magic line, embeds both payloads verbatim between shell-payload markers, and contains the configured win32 nextshell}\ |
||||
-constraints wrapok\ |
||||
-setup $common -body { |
||||
variable outfile |
||||
variable ps_payload |
||||
variable sh_payload |
||||
set data [readbytes $outfile] |
||||
lappend result [string match {: "punk MULTISHELL*} $data] |
||||
lappend result [expr {[string first $ps_payload $data] >= 0}] |
||||
lappend result [expr {[string first $sh_payload $data] >= 0}] |
||||
lappend result [expr {[string first "#<shell-payload>" $data] >= 0}] |
||||
lappend result [expr {[string first "powershell -nop -nol -ExecutionPolicy bypass -File" $data] >= 0}] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1 1 1 1 1] |
||||
|
||||
test scriptwrap_multishell_output_lf_only {the generated polyglot uses LF line endings exclusively (cmd label scanning depends on it)}\ |
||||
-constraints wrapok\ |
||||
-setup $common -body { |
||||
variable outfile |
||||
set data [readbytes $outfile] |
||||
lappend result [expr {[string first \r $data] == -1}] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1] |
||||
|
||||
test scriptwrap_multishell_wrap_deterministic {re-wrapping the same scriptset produces byte-identical output}\ |
||||
-constraints wrapok\ |
||||
-setup $common -body { |
||||
variable fixdir |
||||
variable outfile |
||||
variable startdir |
||||
set outdir2 [makeDirectory scriptwrap_fixture_rewrap] |
||||
cd $fixdir |
||||
set res2 [punk::mix::commandset::scriptwrap::multishell wrapset -outputfolder $outdir2 -askme 0 -force 1] |
||||
cd $startdir |
||||
set outfile2 [dict get $res2 filename] |
||||
lappend result [file exists $outfile2] |
||||
lappend result [expr {[readbytes $outfile] eq [readbytes $outfile2]}] |
||||
}\ |
||||
-cleanup { |
||||
cd $startdir |
||||
}\ |
||||
-result [list 1 1] |
||||
|
||||
test scriptwrap_checkfile_generated_no_label_errors {checkfile reports no 512-byte label location errors for a fresh wrap}\ |
||||
-constraints wrapok\ |
||||
-setup $common -body { |
||||
variable outfile |
||||
set summary [punk::mix::commandset::scriptwrap::checkfile $outfile] |
||||
lappend result [string match "*ERROR: label location errors*" $summary] |
||||
#sanity: the analysis actually ran (labels enumerated) |
||||
lappend result [string match "*call-labels-found:*" $summary] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 0 1] |
||||
|
||||
test scriptwrap_checkfile_committed_runtime_cmd {the committed bin/runtime.cmd passes checkfile - no label/boundary damage from hand-edits or line-ending conversion}\ |
||||
-setup $common -body { |
||||
variable projectroot |
||||
set target [file join $projectroot bin runtime.cmd] |
||||
if {![file exists $target]} { |
||||
#not built/present in this checkout - treat as vacuous pass with marker |
||||
lappend result no_runtime_cmd |
||||
} else { |
||||
set data [readbytes $target] |
||||
#LF-only is part of the artifact's contract |
||||
lappend result [expr {[string first \r $data] == -1}] |
||||
set summary [punk::mix::commandset::scriptwrap::checkfile $target] |
||||
lappend result [string match "*ERROR: label location errors*" $summary] |
||||
} |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1 0] |
||||
|
||||
test scriptwrap_runtime_cmd_roundtrip_no_drift {re-wrapping the runtime scriptset from src/scriptapps reproduces the committed bin/runtime.cmd byte for byte - the artifact is in sync with its sources and un-hand-edited}\ |
||||
-setup $common -body { |
||||
variable projectroot |
||||
variable startdir |
||||
set target [file join $projectroot bin runtime.cmd] |
||||
set scriptapps [file join $projectroot src scriptapps] |
||||
if {![file exists $target] || ![file exists $scriptapps/runtime_wrap.toml]} { |
||||
lappend result no_runtime_sources |
||||
} else { |
||||
set outdir [makeDirectory scriptwrap_runtime_roundtrip] |
||||
cd $scriptapps |
||||
set res [punk::mix::commandset::scriptwrap::multishell runtime -outputfolder $outdir -askme 0 -force 1] |
||||
cd $startdir |
||||
set fresh [dict get $res filename] |
||||
lappend result [expr {[readbytes $fresh] eq [readbytes $target]}] |
||||
#a failure here means either bin/runtime.cmd was edited directly (fix the |
||||
#src/scriptapps payloads instead and re-wrap), or the payloads/template |
||||
#changed without regenerating bin/runtime.cmd (re-wrap and commit it) |
||||
} |
||||
}\ |
||||
-cleanup { |
||||
cd $startdir |
||||
}\ |
||||
-result [list 1] |
||||
|
||||
test scriptwrap_multishell_exec_windows_cmd {on windows, cmd.exe runs the polyglot and dispatches to the configured win32 nextshell (powershell payload executes)}\ |
||||
-constraints {wrapok iswindows}\ |
||||
-setup $common -body { |
||||
variable outfile |
||||
set comspec [expr {[info exists ::env(ComSpec)] ? $::env(ComSpec) : "cmd.exe"}] |
||||
set out "" |
||||
catch {set out [exec -ignorestderr -- $comspec /c [file nativename $outfile] << ""]} out |
||||
lappend result [string match "*MARKER_POWERSHELL_OK*" $out] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1] |
||||
|
||||
test scriptwrap_multishell_exec_unix_sh {on unix, sh/bash runs the polyglot's shell payload}\ |
||||
-constraints {wrapok isunix}\ |
||||
-setup $common -body { |
||||
variable outfile |
||||
set out "" |
||||
catch {set out [exec -ignorestderr -- sh $outfile << ""]} out |
||||
lappend result [string match "*MARKER_SHELL_OK*" $out] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1] |
||||
} |
||||
tcltest::cleanupTests ;#needed to produce test summary line. |
||||
Loading…
Reference in new issue