88Docker/VM or application CPU.
99"""
1010import argparse
11+ from contextlib import ExitStack
1112import hashlib
1213import http .client
1314import json
3839PRIVATE_TMPFS = "rw,noexec,nosuid,nodev,mode=700"
3940BUILD = re .compile (r"^(cargo|rustc|clang|clang\+\+|ld|ld64|zig|swiftc|swift-frontend|xcodebuild)$" )
4041OUTPUT_LIMIT = 2 * 1024 * 1024
42+ COMPILER_INPUT_LIMIT = 1024 * 1024
43+ COMPILER_POLL_SECONDS = 0.001
4144ACTIONS = ("up" , "ps" , "exec" , "restart" , "down" )
4245GATES = {
4346 "rounds" : 8 ,
@@ -107,23 +110,43 @@ def private_json(path, with_anchor=False):
107110 os .close (descriptor )
108111
109112
110- def command (argv , * , cwd , env , timeout , capture = None , output_limit = OUTPUT_LIMIT ):
113+ def command (argv , * , cwd , env , timeout , capture = None , output_limit = OUTPUT_LIMIT ,
114+ stdin_bytes = None , poll_seconds = 0.01 ):
111115 """wait4 isolates each terminated CLI and the children it actually reaped.
112116
113117 Keep the session leader unreaped until interruption decisions are finished.
114118 Never signal a group after successful wait4: its numeric ID may be reused.
115119 Detached engine processes are deliberately outside this accounting boundary.
116120 """
117- with tempfile .TemporaryFile () as out , tempfile .TemporaryFile () as err :
121+ if not (isinstance (poll_seconds , (int , float )) and not isinstance (poll_seconds , bool ) and
122+ math .isfinite (poll_seconds ) and 0 < poll_seconds <= 0.01 ):
123+ raise Failure ("Invalid process observation interval" )
124+ if stdin_bytes is not None and (not isinstance (stdin_bytes , bytes ) or len (stdin_bytes ) > COMPILER_INPUT_LIMIT ):
125+ raise Failure ("Compiler input exceeds its byte budget or has invalid shape" )
126+ with ExitStack () as files :
127+ out = files .enter_context (tempfile .TemporaryFile ())
128+ err = files .enter_context (tempfile .TemporaryFile ())
129+ incoming = subprocess .DEVNULL
130+ if stdin_bytes is not None :
131+ incoming = files .enter_context (tempfile .TemporaryFile ())
132+ incoming .write (stdin_bytes )
133+ incoming .seek (0 )
118134 started = time .monotonic ()
119- child = subprocess .Popen (argv , cwd = cwd , env = env , stdin = subprocess . DEVNULL ,
135+ child = subprocess .Popen (argv , cwd = cwd , env = env , stdin = incoming ,
120136 stdout = out , stderr = err , start_new_session = True )
121137 interrupted = None
122138 try :
123139 while True :
124- pid , status , usage = os .wait4 (child .pid , os .WNOHANG )
140+ # Deliver asynchronous interruption only after reaping is reflected
141+ # in the owned child object; an already-reaped PID no longer pins a group.
142+ previous_mask = signal .pthread_sigmask (signal .SIG_BLOCK , {signal .SIGINT , signal .SIGTERM })
143+ try :
144+ pid , status , usage = os .wait4 (child .pid , os .WNOHANG )
145+ if pid :
146+ child .returncode = os .waitstatus_to_exitcode (status )
147+ finally :
148+ signal .pthread_sigmask (signal .SIG_SETMASK , previous_mask )
125149 if pid :
126- child .returncode = os .waitstatus_to_exitcode (status )
127150 break
128151 if interrupted is None :
129152 if time .monotonic () - started >= timeout :
@@ -136,15 +159,19 @@ def command(argv, *, cwd, env, timeout, capture=None, output_limit=OUTPUT_LIMIT)
136159 os .killpg (child .pid , signal .SIGKILL )
137160 except ProcessLookupError :
138161 pass
139- time .sleep (0.01 )
162+ time .sleep (poll_seconds )
140163 except BaseException :
141- if child .returncode is None :
142- try :
143- os .killpg (child .pid , signal .SIGKILL )
144- except ProcessLookupError :
145- pass
146- _ , status , _ = os .wait4 (child .pid , 0 )
147- child .returncode = os .waitstatus_to_exitcode (status )
164+ previous_mask = signal .pthread_sigmask (signal .SIG_BLOCK , {signal .SIGINT , signal .SIGTERM })
165+ try :
166+ if child .returncode is None :
167+ try :
168+ os .killpg (child .pid , signal .SIGKILL )
169+ except ProcessLookupError :
170+ pass
171+ _ , status , _ = os .wait4 (child .pid , 0 )
172+ child .returncode = os .waitstatus_to_exitcode (status )
173+ finally :
174+ signal .pthread_sigmask (signal .SIG_SETMASK , previous_mask )
148175 raise
149176 wall = time .monotonic () - started
150177 out .seek (0 )
@@ -165,6 +192,85 @@ def command(argv, *, cwd, env, timeout, capture=None, output_limit=OUTPUT_LIMIT)
165192 "interrupted" : interrupted }
166193
167194
195+ def compiler_fingerprint (path , expected ):
196+ """Fence this pure measurement input; do not search PATH or follow a replacement link."""
197+ if not path .is_absolute ():
198+ raise Failure ("Compiler measurement requires an absolute executable" )
199+ try :
200+ before = path .lstat ()
201+ if not (stat .S_ISREG (before .st_mode ) and before .st_uid == os .getuid () and before .st_nlink == 1 and
202+ before .st_mode & 0o022 == 0 and before .st_mode & 0o111 ):
203+ raise Failure ("Compiler measurement executable has unsafe ownership or shape" )
204+ digest = fingerprint (path )
205+ after = path .lstat ()
206+ except (OSError , ValueError ):
207+ raise Failure ("Compiler measurement executable is unavailable" ) from None
208+ anchor = lambda value : (value .st_dev , value .st_ino , value .st_size , value .st_mtime_ns , value .st_ctime_ns , value .st_mode )
209+ if digest != expected or anchor (before ) != anchor (after ):
210+ raise Failure ("Compiler measurement executable changed" )
211+ return anchor (after )
212+
213+
214+ def compiler_sample (* , compiler , compiler_sha256 , action , input_bytes = None , input_sha256 = None ,
215+ expected_output_sha256 , cwd , timeout = 5 ):
216+ """One direct pure-compiler observation; callers own the fixed trial schedule and private report.
217+
218+ Use untimed, independently checked JSON to pin the expected canonical output.
219+ Anonymous regular stdin avoids pipe backpressure and shell wrappers. Input setup,
220+ hashing/JSON checks and this observer's CPU are outside launch-to-reap accounting.
221+ Failure rows retain real metrics; they are never successful zero samples.
222+ """
223+ if not (action in ("--protocol" , "compile" , "plan" ) and isinstance (compiler_sha256 , str ) and
224+ OBJECT_ID .fullmatch (compiler_sha256 ) and isinstance (expected_output_sha256 , str ) and
225+ OBJECT_ID .fullmatch (expected_output_sha256 ) and isinstance (timeout , (int , float )) and
226+ not isinstance (timeout , bool ) and math .isfinite (timeout ) and 0 < timeout <= 5 ):
227+ raise Failure ("Compiler measurement requires exact bounded qualification" )
228+ if action == "--protocol" :
229+ if input_bytes is not None or input_sha256 is not None :
230+ raise Failure ("Protocol measurement accepts no authored input" )
231+ elif not (isinstance (input_bytes , bytes ) and 0 < len (input_bytes ) <= COMPILER_INPUT_LIMIT and
232+ isinstance (input_sha256 , str ) and OBJECT_ID .fullmatch (input_sha256 ) and
233+ hashlib .sha256 (input_bytes ).hexdigest () == input_sha256 ):
234+ raise Failure ("Compiler measurement input does not match its frozen byte budget" )
235+ if not isinstance (compiler , (str , Path )):
236+ raise Failure ("Compiler measurement requires an absolute executable" )
237+ compiler = Path (compiler )
238+ anchor = compiler_fingerprint (compiler , compiler_sha256 )
239+ observed = command ([str (compiler ), action ], cwd = cwd ,
240+ env = {"PATH" : os .environ .get ("PATH" , "" ), "LANG" : "C" , "LC_ALL" : "C" },
241+ timeout = timeout , output_limit = COMPILER_INPUT_LIMIT , stdin_bytes = input_bytes ,
242+ poll_seconds = COMPILER_POLL_SECONDS )
243+ result = {"action" : action , "ok" : False , "exit" : observed ["exit" ], "interrupted" : observed ["interrupted" ],
244+ "wall_s" : observed ["wall_s" ], "compiler_cpu_s" : observed ["cli_cpu_s" ],
245+ "poll_seconds" : COMPILER_POLL_SECONDS , "input_sha256" : input_sha256 }
246+ try :
247+ if compiler_fingerprint (compiler , compiler_sha256 ) != anchor :
248+ raise Failure ("Compiler measurement executable changed" )
249+ except (Failure , OSError ):
250+ return {** result , "reason" : "compiler-changed" }
251+ if observed ["interrupted" ]:
252+ return {** result , "reason" : "interrupted" }
253+ if observed ["wall_s" ] >= timeout :
254+ # Reaping can win the polling race after the budget has elapsed. Keep
255+ # that observation failed without signaling an already-reaped group.
256+ return {** result , "interrupted" : "timeout" , "reason" : "interrupted" }
257+ if observed ["exit" ] != 0 :
258+ return {** result , "reason" : "nonzero-exit" }
259+ try :
260+ payload = json .loads (observed ["stdout" ])
261+ versions = ("transport_version" , "authored_version" , "plan_version" ) if action == "--protocol" else ("transport_version" ,)
262+ if not (isinstance (payload , dict ) and all (type (payload .get (key )) is int and payload [key ] == 1 for key in versions ) and
263+ (action == "--protocol" or payload .get ("ok" ) is True )):
264+ raise ValueError ("invalid envelope" )
265+ canonical = json .dumps (payload , sort_keys = True , separators = ("," , ":" ), allow_nan = False ).encode ()
266+ except (ValueError , TypeError ):
267+ return {** result , "reason" : "invalid-output" }
268+ digest = hashlib .sha256 (canonical ).hexdigest ()
269+ if digest != expected_output_sha256 :
270+ return {** result , "reason" : "output-mismatch" , "output_sha256" : digest }
271+ return {** result , "ok" : True , "output_sha256" : digest }
272+
273+
168274def fixture_documents (name , image , hostname , token ):
169275 """One workload definition feeds both authored formats; live inspect checks it again."""
170276 common = {"image" : image , "pull_policy" : "never" , "init" : True ,
0 commit comments