maka-agent 0.2.0-dev.3.20260830 → 0.2.0-dev.5.20260830

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/cli-core.js +1 -0
  2. package/dist/eval-bundle-path.js +1 -1
  3. package/dist/pi-tui-runner.js +3 -1
  4. package/dist/runtime-host-cli.js +37 -3
  5. package/dist/runtime-host-onboarding.js +10 -1
  6. package/dist/runtime-host-peer-mesh-management-command.js +17 -0
  7. package/dist/runtime-host-setup-command.js +33 -15
  8. package/dist/runtime-host-systemd-service.js +9 -3
  9. package/dist/runtime-host-tui-context.js +2 -6
  10. package/native/runtime-host-peer/prebuilds/darwin-arm64/maka_runtime_host_peer.node +0 -0
  11. package/native/runtime-host-peer/prebuilds/linux-arm64/maka_runtime_host_peer.node +0 -0
  12. package/native/runtime-host-peer/prebuilds/linux-x64/maka_runtime_host_peer.node +0 -0
  13. package/native/runtime-host-peer/prebuilds/win32-x64/maka_runtime_host_peer.node +0 -0
  14. package/node_modules/@maka/eval/dist/external-subject.js +1 -1
  15. package/node_modules/@maka/eval/dist/harbor-external-subject.js +2 -2
  16. package/node_modules/@maka/runtime/dist/sandbox/macos-seatbelt.js +68 -9
  17. package/node_modules/@maka/runtime-host/dist/client/peer-client.js +22 -3
  18. package/node_modules/@maka/runtime-host/dist/operator/peer-mesh-management-frame.js +14 -0
  19. package/{packages/eval/dist/index.js → node_modules/@maka/runtime-host/dist/peer-mesh/display-name.js} +12 -10
  20. package/node_modules/@maka/runtime-host/dist/peer-mesh/model.js +32 -21
  21. package/node_modules/@maka/runtime-host/dist/peer-mesh/node.js +207 -47
  22. package/node_modules/@maka/runtime-host/dist/peer-mesh/owner.js +2 -0
  23. package/node_modules/@maka/runtime-host/dist/peer-mesh/store.js +18 -5
  24. package/node_modules/@maka/runtime-host/dist/protocol/index.js +5 -1
  25. package/node_modules/@maka/runtime-host/dist/protocol/peer-mesh.js +59 -2
  26. package/node_modules/@maka/runtime-host/dist/server/access-authority.js +11 -7
  27. package/node_modules/@maka/runtime-host/dist/server/connection-session.js +3 -0
  28. package/node_modules/@maka/runtime-host/dist/server/execution-service.js +1 -0
  29. package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +1 -1
  30. package/node_modules/@maka/runtime-host/dist/server/peer-mesh-authority.js +19 -0
  31. package/package.json +1 -2
  32. package/packages/eval/dist/attempt-store.js +0 -138
  33. package/packages/eval/dist/cli.js +0 -119
  34. package/packages/eval/dist/experiment-directory.js +0 -59
  35. package/packages/eval/dist/experiment.js +0 -49
  36. package/packages/eval/dist/external-subject.js +0 -488
  37. package/packages/eval/dist/harbor-external-subject.js +0 -929
  38. package/packages/eval/dist/harbor-maka-subject.js +0 -83
  39. package/packages/eval/dist/harness-environment.js +0 -80
  40. package/packages/eval/dist/harness-executor.js +0 -1013
  41. package/packages/eval/dist/install-preflight.js +0 -201
  42. package/packages/eval/dist/maka-artifacts.js +0 -126
  43. package/packages/eval/dist/maka-runtime-policy.js +0 -42
  44. package/packages/eval/dist/maka-subject.js +0 -268
  45. package/packages/eval/dist/metering-checkpoint.js +0 -80
  46. package/packages/eval/dist/provider-admission.js +0 -39
  47. package/packages/eval/dist/provider-metering.js +0 -67
  48. package/packages/eval/dist/provider-web-tool-surface.js +0 -74
  49. package/packages/eval/dist/relay-result-frame.js +0 -38
  50. package/packages/eval/dist/result.js +0 -94
  51. package/packages/eval/dist/runner.js +0 -290
  52. package/packages/eval/dist/spec.js +0 -135
  53. package/packages/eval/dist/toolchain-verification.js +0 -130
  54. package/packages/eval/harbor/deepseek-codex-models.json +0 -69
  55. package/packages/eval/harbor/deepseek-harness-profile/cordis.patch.yml +0 -140
  56. package/packages/eval/harbor/deepseek-harness-profile/cordis.yml +0 -18
  57. package/packages/eval/harbor/deepseek-harness-profile/package.json +0 -10
  58. package/packages/eval/harbor/docker-compose-egress-proxy.yaml +0 -57
  59. package/packages/eval/harbor/egress-proxy/Dockerfile +0 -25
  60. package/packages/eval/harbor/egress-proxy/entrypoint.sh +0 -62
  61. package/packages/eval/harbor/egress-proxy/network-policy +0 -148
  62. package/packages/eval/harbor/egress_filter.py +0 -435
  63. package/packages/eval/harbor/eval_framework.py +0 -40
  64. package/packages/eval/harbor/relay_agent.py +0 -686
  65. package/packages/eval/harbor/run_trial.py +0 -223
  66. package/packages/eval/package.json +0 -20
@@ -1,686 +0,0 @@
1
- # Licensed to the Apache Software Foundation (ASF) under one
2
- # or more contributor license agreements. See the NOTICE file
3
- # distributed with this work for additional information
4
- # regarding copyright ownership. The ASF licenses this file
5
- # to you under the Apache License, Version 2.0 (the
6
- # "License"); you may not use this file except in compliance
7
- # with the License. You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing,
12
- # software distributed under the License is distributed on an
13
- # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
- # KIND, either express or implied. See the License for the
15
- # specific language governing permissions and limitations
16
- # under the License.
17
-
18
- """One-shot Harbor/Pier Agent that delegates one subject execution to @maka/eval."""
19
-
20
- from __future__ import annotations
21
-
22
- import asyncio
23
- import base64
24
- import contextlib
25
- import hashlib
26
- import json
27
- import os
28
- import re
29
- import shlex
30
- import tempfile
31
- from pathlib import Path
32
- from typing import Any
33
-
34
- from eval_framework import selected
35
-
36
- framework = selected()
37
- if framework == "harbor":
38
- from harbor.agents.base import BaseAgent
39
- else:
40
- from pier.agents.base import BaseAgent
41
-
42
-
43
- class RelayTransportClosed(RuntimeError):
44
- pass
45
-
46
-
47
- RESULT_FRAME_PREFIX = "MAKA-EVAL-RESULT-V1"
48
- SCOPE_ERROR_PREFIX = "MAKA-EVAL-SCOPE-ERROR-V1"
49
- RESULT_PAYLOAD_LIMIT_BYTES = 2 * 1024
50
- RESULT_CARRIER_LIMIT_BYTES = 64 * 1024
51
- SUBJECT_STDOUT_PATH = "/logs/artifacts/maka-subject.stdout.txt"
52
- SUBJECT_STDERR_PATH = "/logs/artifacts/maka-subject.stderr.txt"
53
- CAPABILITY_PREFIX = "MAKA-EVAL-CAPABILITIES-V1 "
54
- NAMESPACE_PREFIX = "MAKA-EVAL-POLICY-NAMESPACE-V1 "
55
- # The egress policy only constrains what the IP output hooks can see. NET_RAW
56
- # grants an AF_PACKET socket that writes beneath them, and NET_ADMIN grants the
57
- # ability to delete the ruleset outright. The overlay drops NET_RAW, but a
58
- # task's own compose can add either back, and a `cap_add` wins over an
59
- # overlay's `cap_drop`.
60
- BYPASS_CAPABILITIES = {"NET_RAW": 1 << 13, "NET_ADMIN": 1 << 12}
61
- # Every set is read, not just the effective one: a non-root subject reports an
62
- # empty effective set while a file-capability executable still reacquires
63
- # anything the bounding set kept, and the permitted, inheritable and ambient
64
- # sets each raise into the effective set without an exec at all.
65
- CAPABILITY_FIELDS = ("CapEff", "CapPrm", "CapBnd")
66
- # Harbor installs the policy by running `network-policy` inside this service, so
67
- # its network namespace is what "the namespace the policy was applied to" means.
68
- # Reading the identity from both sides answers that question directly, rather
69
- # than inferring it from something only the shared namespace would expose.
70
- POLICY_SERVICE = "harbor-docker-egress-control-sidecar"
71
- NAMESPACE_PROBE = f"printf %s {shlex.quote(NAMESPACE_PREFIX)}; readlink /proc/self/ns/net"
72
- PROXY_IPV4_PATH = "/opt/maka-egress/proxy-ipv4"
73
- PROXY_HOSTS_PREFIX = "MAKA-EVAL-PROXY-HOST-V1 "
74
- # The kernel's own form for a namespace link target. Matching it keeps an
75
- # unexpected answer from being compared as if it were an identity.
76
- NAMESPACE_IDENTITY = re.compile(r"^net:\[[0-9]+\]$")
77
-
78
- _host_teardown_requested = False
79
-
80
-
81
- def request_host_teardown() -> None:
82
- global _host_teardown_requested
83
- _host_teardown_requested = True
84
-
85
-
86
- class RelayAgent(BaseAgent):
87
- def __init__(
88
- self,
89
- *args: Any,
90
- relay_host: str,
91
- relay_port: int,
92
- relay_token: str,
93
- teardown_timeout_ms: int,
94
- **kwargs: Any,
95
- ):
96
- super().__init__(*args, **kwargs)
97
- self._host = relay_host
98
- self._port = relay_port
99
- self._token = relay_token
100
- if not isinstance(teardown_timeout_ms, int) or teardown_timeout_ms <= 0:
101
- raise RuntimeError("Maka Eval teardown timeout is invalid")
102
- self._teardown_timeout = teardown_timeout_ms / 1000
103
-
104
- @staticmethod
105
- def name() -> str:
106
- return "maka-eval-relay"
107
-
108
- def version(self) -> str:
109
- return "1"
110
-
111
- async def setup(self, environment: Any) -> None:
112
- return None
113
-
114
- async def run(self, instruction: str, environment: Any, context: Any) -> None:
115
- reader, writer = await asyncio.open_connection(self._host, self._port)
116
- execution: asyncio.Task[Any] | None = None
117
- decision: asyncio.Task[dict[str, Any]] | None = None
118
- request: dict[str, Any] | None = None
119
- execution_reported = False
120
- scope_path = f"/logs/agent/.maka-eval-{self._token}.pid"
121
- environment_path = f"/tmp/maka-eval-{self._token}.env"
122
- try:
123
- cwd_prefix = f"MAKA-EVAL-CWD-V1 {self._token} "
124
- working_directory = await environment.exec(
125
- f"printf {shlex.quote(cwd_prefix)}; pwd 2>/dev/null"
126
- )
127
- cwd_lines = [
128
- line[len(cwd_prefix) :]
129
- for line in str(working_directory.stdout or "").splitlines()
130
- if line.startswith(cwd_prefix)
131
- ]
132
- cwd = cwd_lines[0] if len(cwd_lines) == 1 else ""
133
- if working_directory.return_code != 0 or not cwd.startswith("/") or "\x00" in cwd:
134
- raise RuntimeError("Maka Eval could not resolve the task working directory")
135
- await _require_constrained_subject(environment)
136
- if not await _send(
137
- writer,
138
- {
139
- "token": self._token,
140
- "kind": "ready",
141
- "instruction": instruction,
142
- "cwd": cwd,
143
- },
144
- ):
145
- raise RelayTransportClosed("Maka Eval relay transport closed before ready")
146
- request = await _receive(reader)
147
- _require_message(request, self._token, "execute")
148
- command = await _prepare_command(environment, request, self._token, scope_path)
149
- execution = asyncio.create_task(environment.exec(command, cwd=cwd))
150
- decision = asyncio.create_task(_receive(reader))
151
- done, _ = await asyncio.wait({execution, decision}, return_when=asyncio.FIRST_COMPLETED)
152
- if decision in done and execution not in done:
153
- decision.result()
154
- raise RelayTransportClosed("Maka Eval relay received control before execution")
155
- result = execution.result()
156
- await _persist_subject_outputs(environment, result)
157
- stdout, diagnostic = _project_result(result, request)
158
- # A subject that exited on its own leaves the shared environment as
159
- # it left it, and the verifier reads that environment. Nothing is
160
- # waiting on those processes here — `environment.exec` has already
161
- # returned — so tearing them down would not unblock anything; it
162
- # would only edit the thing about to be measured, and edit it for
163
- # some subjects and not others. Cancellation still quiesces, because
164
- # there the subject has not stopped and the trial is being abandoned.
165
- if not await _send(
166
- writer,
167
- {
168
- "token": self._token,
169
- "kind": "executed",
170
- "termination": "exited",
171
- "exitCode": result.return_code,
172
- "stdout": stdout,
173
- "diagnostic": diagnostic,
174
- },
175
- ):
176
- raise RelayTransportClosed("Maka Eval relay transport closed before result")
177
- execution_reported = True
178
- _require_message(
179
- decision.result() if decision.done() else await decision,
180
- self._token,
181
- "verify",
182
- )
183
- except asyncio.CancelledError:
184
- if request is not None and execution is not None:
185
- execution_terminal = execution.done() and not execution.cancelled()
186
- terminal_projection = None
187
- if execution_terminal:
188
- terminal_result = execution.result()
189
- terminal_projection = _project_result(terminal_result, request)
190
- # A subject that already exited has nothing left to settle, and
191
- # tearing its scope down here would remove what the verifier is
192
- # about to score -- the same environment edit this relay stopped
193
- # making on the ordinary path. Only a subject still running is
194
- # brought to a stop.
195
- if terminal_projection is not None:
196
- result = terminal_result
197
- else:
198
- result = await _settle_or_destroy(
199
- environment, cwd, scope_path, execution, self._teardown_timeout
200
- )
201
- if result is not None:
202
- await _persist_subject_outputs(environment, result)
203
- if (
204
- result is not None
205
- and not execution_reported
206
- and (execution_terminal or not _host_teardown_requested)
207
- ):
208
- stdout, diagnostic = terminal_projection or _project_result(result, request)
209
- with contextlib.suppress(Exception):
210
- await _send(
211
- writer,
212
- {
213
- "token": self._token,
214
- "kind": "executed",
215
- "termination": "exited" if execution_terminal else "framework_timeout",
216
- "exitCode": result.return_code if execution_terminal else 124,
217
- "stdout": stdout,
218
- "diagnostic": diagnostic,
219
- },
220
- )
221
- elif not execution_reported and not _host_teardown_requested:
222
- with contextlib.suppress(Exception):
223
- await _send(
224
- writer,
225
- {
226
- "token": self._token,
227
- "kind": "executed",
228
- "termination": "framework_timeout",
229
- "exitCode": 124,
230
- "stdout": "",
231
- "diagnostic": (
232
- _carrier_diagnostic("result-frame-missing", b"")
233
- if request.get("captureStdout", True)
234
- else {"category": "none"}
235
- ),
236
- },
237
- )
238
- raise
239
- except RelayTransportClosed:
240
- if request is not None and execution is not None:
241
- result = await _settle_or_destroy(
242
- environment, cwd, scope_path, execution, self._teardown_timeout
243
- )
244
- if result is not None:
245
- with contextlib.suppress(Exception):
246
- await _persist_subject_outputs(environment, result)
247
- except BaseException:
248
- if request is not None and execution is not None:
249
- result = await _settle_or_destroy(
250
- environment, cwd, scope_path, execution, self._teardown_timeout
251
- )
252
- if result is not None:
253
- with contextlib.suppress(Exception):
254
- await _persist_subject_outputs(environment, result)
255
- raise
256
- finally:
257
- if decision is not None and not decision.done():
258
- decision.cancel()
259
- with contextlib.suppress(BaseException):
260
- await decision
261
- if request is not None:
262
- with contextlib.suppress(Exception):
263
- await asyncio.wait_for(
264
- environment.exec(
265
- f"rm -f -- {shlex.quote(scope_path)} {shlex.quote(environment_path)}",
266
- cwd=cwd,
267
- timeout_sec=1,
268
- ),
269
- timeout=1,
270
- )
271
- with contextlib.suppress(BrokenPipeError, ConnectionError, RuntimeError, TimeoutError):
272
- writer.close()
273
- await asyncio.wait_for(writer.wait_closed(), timeout=1)
274
-
275
-
276
- async def _prepare_command(
277
- environment: Any,
278
- request: dict[str, Any],
279
- token: str,
280
- scope_path: str,
281
- ) -> str:
282
- credentials = request.get("credentials")
283
- public_environment = request.get("environment", {})
284
- if not isinstance(credentials, dict) or not all(
285
- isinstance(key, str) and isinstance(value, str) for key, value in credentials.items()
286
- ):
287
- raise RuntimeError("invalid Maka Eval credentials")
288
- if not isinstance(public_environment, dict) or not all(
289
- isinstance(key, str) and isinstance(value, str)
290
- for key, value in public_environment.items()
291
- ):
292
- raise RuntimeError("invalid Maka Eval environment")
293
- if set(credentials) & set(public_environment):
294
- raise RuntimeError("Maka Eval environment overlaps credentials")
295
- capture_stdout = request.get("captureStdout", True)
296
- if not isinstance(capture_stdout, bool):
297
- raise RuntimeError("invalid Maka Eval stdout policy")
298
- result_token = request.get("resultToken")
299
- if not isinstance(result_token, str) or re.fullmatch(r"[0-9a-f]{32}", result_token) is None:
300
- raise RuntimeError("invalid Maka Eval result token")
301
- if "MAKA_EVAL_RESULT_TOKEN" in credentials or "MAKA_EVAL_RESULT_TOKEN" in public_environment:
302
- raise RuntimeError("Maka Eval environment contains a reserved name")
303
- for label, values in (("environment", public_environment), ("credential", credentials)):
304
- if any(re.fullmatch(r"[A-Za-z_][A-Za-z0-9_]*", key) is None for key in values):
305
- raise RuntimeError(f"invalid Maka Eval {label} name")
306
-
307
- container_path = f"/tmp/maka-eval-{token}.env"
308
- secret_path = None
309
- try:
310
- with tempfile.NamedTemporaryFile("w", encoding="utf-8", delete=False) as secret:
311
- secret_path = Path(secret.name)
312
- os.chmod(secret_path, 0o600)
313
- for key, value in {
314
- **public_environment,
315
- **credentials,
316
- "MAKA_EVAL_RESULT_TOKEN": result_token,
317
- }.items():
318
- secret.write(f"export {key}={shlex.quote(value)}\n")
319
- await environment.upload_file(secret_path, container_path)
320
- finally:
321
- if secret_path is not None:
322
- secret_path.unlink(missing_ok=True)
323
- subject = shlex.join([request["command"], *request["args"]])
324
- output_redirect = "" if capture_stdout else " >/dev/null"
325
- scope_error = shlex.quote(f"{SCOPE_ERROR_PREFIX} {result_token}\\n")
326
- inner = (
327
- "umask 077; "
328
- f"{{ echo $$ > {shlex.quote(scope_path)}; }} 2>/dev/null || "
329
- f"{{ printf {scope_error}; exit 111; }}; "
330
- f". {shlex.quote(container_path)}; command -p rm -f {shlex.quote(container_path)}; "
331
- f"exec {subject}{output_redirect}"
332
- )
333
- return f"setsid --wait sh -c {shlex.quote(inner)}"
334
-
335
-
336
- async def _require_constrained_subject(environment: Any) -> None:
337
- """Refuse to start the subject unless the egress policy actually governs it.
338
-
339
- Runs after the policy is applied and before the subject exists, so a task
340
- that keeps a capability the policy cannot see, or that keeps the subject out
341
- of the namespace the policy was applied to, fails the attempt instead of
342
- producing a result the isolation contract never actually covered.
343
- """
344
- if os.environ.get("MAKA_EVAL_EGRESS_REQUIRED") != "1":
345
- return
346
- probe = await environment.exec(
347
- f"printf %s {shlex.quote(CAPABILITY_PREFIX)}; "
348
- r"sed -n 's/^\(Cap[A-Za-z]*\):[[:space:]]*/\1=/p' /proc/self/status | tr '\n' ' '; "
349
- "echo; " + NAMESPACE_PROBE
350
- )
351
- policy = await environment.service_exec(NAMESPACE_PROBE, service=POLICY_SERVICE)
352
- if probe.return_code != 0 or policy.return_code != 0:
353
- raise RuntimeError("Maka Eval could not read the subject isolation evidence")
354
- capabilities = _sole_probe_line(probe, CAPABILITY_PREFIX)
355
- namespace = _sole_probe_line(probe, NAMESPACE_PREFIX)
356
- policy_namespace = _sole_probe_line(policy, NAMESPACE_PREFIX)
357
- if not all(NAMESPACE_IDENTITY.match(value) for value in (namespace, policy_namespace)):
358
- raise RuntimeError("Maka Eval could not read the subject isolation evidence")
359
- reported: dict[str, int] = {}
360
- for field in capabilities.split():
361
- name, _, value = field.partition("=")
362
- try:
363
- reported[name] = int(value, 16)
364
- except ValueError:
365
- raise RuntimeError("Maka Eval could not read the subject capability set") from None
366
- if not all(field in reported for field in CAPABILITY_FIELDS):
367
- raise RuntimeError("Maka Eval could not read the subject capability set")
368
- granted = 0
369
- for value in reported.values():
370
- granted |= value
371
- held = sorted(name for name, bit in BYPASS_CAPABILITIES.items() if granted & bit)
372
- if held:
373
- raise RuntimeError(
374
- "the subject holds "
375
- + ", ".join(held)
376
- + ", which bypasses the Eval egress policy; remove it from the task"
377
- )
378
- if namespace != policy_namespace:
379
- raise RuntimeError(
380
- "the subject does not share the network namespace the Eval egress policy "
381
- "was applied to; remove the task's own networking on the subject service"
382
- )
383
- await _pin_proxy_hostname(environment)
384
-
385
-
386
- HOSTS_ALIAS_AWK = r"""
387
- /^[[:space:]]*#/ { print; next }
388
- {
389
- for (i = 2; i <= NF; i++) {
390
- if ($i == host) next
391
- }
392
- print
393
- }
394
- """
395
-
396
- # Four decimal octets 0-255, no empty fields and no leading zeros. The same
397
- # program is embedded in egress-proxy/network-policy; the contract test
398
- # requires the two copies to stay identical.
399
- IPV4_OCTET_AWK = r"""
400
- BEGIN { FS = "." }
401
- NF != 4 { exit 1 }
402
- {
403
- for (i = 1; i <= 4; i++) {
404
- if ($i !~ /^(0|[1-9][0-9]*)$/ || $i + 0 > 255) exit 1
405
- }
406
- }
407
- """
408
-
409
- _PUBLISHED_IPV4 = re.compile(
410
- r"^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}"
411
- r"(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$"
412
- )
413
-
414
-
415
- def _valid_egress_proxy_host(host: str) -> bool:
416
- if not host or host.startswith(".") or host.endswith(".") or ".." in host:
417
- return False
418
- # Match the pin script's `*[!A-Za-z0-9.-]*` class. str.isalnum() also
419
- # accepts Unicode letters, which the shell would later reject as a pin
420
- # failure instead of an invalid host.
421
- return all(
422
- (character.isalnum() and character.isascii()) or character in ".-"
423
- for character in host
424
- )
425
-
426
-
427
- def _valid_published_ipv4(ip: str) -> bool:
428
- return bool(_PUBLISHED_IPV4.fullmatch(ip))
429
-
430
-
431
- async def _pin_proxy_hostname(environment: Any) -> None:
432
- """Point the proxy hostname at the published IPv4 so Docker DNS can be refused.
433
-
434
- The subject only needs that one name, because the HTTP proxy does remote
435
- resolution itself. Pinning it in /etc/hosts lets the namespace policy reject
436
- 127.0.0.11:53 without breaking HTTPS_PROXY.
437
- """
438
- host = os.environ.get("MAKA_EVAL_EGRESS_ALLOWED_HOST") or "maka-eval-mitmproxy"
439
- if not _valid_egress_proxy_host(host):
440
- raise RuntimeError("Eval egress proxy host is invalid")
441
- script = f"""
442
- set -eu
443
- path={shlex.quote(PROXY_IPV4_PATH)}
444
- host={shlex.quote(host)}
445
- case "$host" in
446
- ""|.*|*..*|*.) exit 1 ;;
447
- *[!A-Za-z0-9.-]*) exit 1 ;;
448
- esac
449
- test -f "$path"
450
- ip=$(tr -d ' \\t\\r\\n' < "$path")
451
- case "$ip" in
452
- ""|*.*.*.*.*|*[!0-9.]*) exit 1 ;;
453
- esac
454
- if ! printf '%s\\n' "$ip" | awk {shlex.quote(IPV4_OCTET_AWK)}; then
455
- exit 1
456
- fi
457
- tmp=$(mktemp)
458
- trap 'rm -f "$tmp"' EXIT
459
- if [ -f /etc/hosts ]; then
460
- awk -v host="$host" {shlex.quote(HOSTS_ALIAS_AWK)} /etc/hosts > "$tmp"
461
- fi
462
- printf '%s %s\\n' "$ip" "$host" >> "$tmp"
463
- cat "$tmp" > /etc/hosts
464
- printf %s {shlex.quote(PROXY_HOSTS_PREFIX)}
465
- printf '%s %s\\n' "$ip" "$host"
466
- """
467
- # Harbor 0.20.0 BaseEnvironment.exec and DockerEnvironment.exec take user=;
468
- # DockerEnvironment._compose_exec forwards it as `docker compose exec -u`.
469
- probe = await environment.exec(script, user="root")
470
- if probe.return_code != 0:
471
- raise RuntimeError("Maka Eval could not pin the Eval egress proxy hostname")
472
- reported = _sole_probe_line(probe, PROXY_HOSTS_PREFIX)
473
- ip, _, pinned = reported.partition(" ")
474
- if pinned != host or not _valid_published_ipv4(ip):
475
- raise RuntimeError("Maka Eval could not pin the Eval egress proxy hostname")
476
-
477
-
478
- def _sole_probe_line(probe: Any, prefix: str) -> str:
479
- reported = [
480
- line[len(prefix) :]
481
- for line in str(probe.stdout or "").splitlines()
482
- if line.startswith(prefix)
483
- ]
484
- if len(reported) != 1:
485
- raise RuntimeError("Maka Eval could not read the subject isolation evidence")
486
- return reported[0].strip()
487
-
488
-
489
- async def _persist_subject_outputs(environment: Any, result: Any) -> None:
490
- with tempfile.TemporaryDirectory() as directory:
491
- root = Path(directory)
492
- stdout = root / "stdout"
493
- stderr = root / "stderr"
494
- stdout.write_text(str(getattr(result, "stdout", "") or ""), encoding="utf-8")
495
- stderr.write_text(str(getattr(result, "stderr", "") or ""), encoding="utf-8")
496
- prepared = await environment.exec("mkdir -p /logs/artifacts && chmod 700 /logs/artifacts")
497
- if prepared.return_code != 0:
498
- raise RuntimeError("Maka Eval could not prepare subject artifact output")
499
- await environment.upload_file(stdout, SUBJECT_STDOUT_PATH)
500
- await environment.upload_file(stderr, SUBJECT_STDERR_PATH)
501
-
502
-
503
- def _decode_result_carrier(carrier: str, token: str) -> tuple[str, dict[str, Any]]:
504
- raw = carrier.encode("utf-8", errors="replace")
505
- if len(raw) > RESULT_CARRIER_LIMIT_BYTES:
506
- return "", _carrier_diagnostic("result-frame-oversize", raw)
507
- prefix = f"{RESULT_FRAME_PREFIX} {token} "
508
- candidates = [line for line in carrier.splitlines(keepends=True) if line.startswith(prefix)]
509
- if len(candidates) != 1:
510
- category = "result-frame-missing" if not candidates else "result-frame-ambiguous"
511
- return "", _carrier_diagnostic(category, raw)
512
- frame = candidates[0]
513
- fields = frame.rstrip("\r\n").split(" ", 4)
514
- if len(fields) != 5:
515
- return "", _carrier_diagnostic("result-frame-invalid", raw)
516
- _, framed_token, length_text, digest, encoded = fields
517
- try:
518
- length = int(length_text)
519
- padding = "=" * (-len(encoded) % 4)
520
- payload = base64.b64decode(encoded + padding, altchars=b"-_", validate=True)
521
- except (ValueError, base64.binascii.Error):
522
- return "", _carrier_diagnostic("result-frame-invalid", raw)
523
- if (
524
- framed_token != token
525
- or length < 0
526
- or length > RESULT_PAYLOAD_LIMIT_BYTES
527
- or len(payload) != length
528
- or not re.fullmatch(r"[0-9a-f]{64}", digest)
529
- or hashlib.sha256(payload).hexdigest() != digest
530
- ):
531
- return "", _carrier_diagnostic("result-frame-invalid", raw)
532
- noise = carrier.replace(frame, "", 1).encode("utf-8", errors="replace")
533
- diagnostic = (
534
- {"category": "none"}
535
- if not noise
536
- else _carrier_diagnostic("unstructured-output", noise)
537
- )
538
- try:
539
- decoded = payload.decode("utf-8", errors="strict")
540
- except UnicodeDecodeError:
541
- return "", _carrier_diagnostic("result-frame-invalid", raw)
542
- return decoded, diagnostic
543
-
544
-
545
- def _project_result(result: Any, request: dict[str, Any]) -> tuple[str, dict[str, Any]]:
546
- carrier = str(getattr(result, "stdout", "") or "")
547
- scope_error = f"{SCOPE_ERROR_PREFIX} {request['resultToken']}"
548
- if carrier == f"{scope_error}\n":
549
- return "", _carrier_diagnostic("execution-scope-unavailable", carrier.encode())
550
- if not request.get("captureStdout", True):
551
- return "", {"category": "none"}
552
- return _decode_result_carrier(carrier, request["resultToken"])
553
-
554
-
555
- def _carrier_diagnostic(category: str, value: bytes) -> dict[str, Any]:
556
- return {
557
- "category": category,
558
- "bytes": len(value),
559
- "sha256": hashlib.sha256(value).hexdigest(),
560
- }
561
-
562
-
563
- async def _settle(environment: Any, cwd: str, scope_path: str, execution: Any) -> Any:
564
- if execution.cancelled():
565
- raise RuntimeError("Maka Eval subject execution was cancelled")
566
- if execution.done():
567
- result = execution.result()
568
- else:
569
- result = None
570
- for signal, timeout in (("TERM", 20), ("KILL", 10)):
571
- await _signal(environment, cwd, scope_path, signal)
572
- try:
573
- result = await asyncio.wait_for(asyncio.shield(execution), timeout=timeout)
574
- break
575
- except asyncio.CancelledError:
576
- if execution.cancelled():
577
- raise RuntimeError("Maka Eval subject execution was cancelled") from None
578
- raise
579
- except TimeoutError:
580
- pass
581
- if result is None:
582
- raise RuntimeError("Maka Eval subject did not settle")
583
- await _quiesce_scope(environment, cwd, scope_path)
584
- return result
585
-
586
-
587
- async def _settle_or_destroy(
588
- environment: Any,
589
- cwd: str,
590
- scope_path: str,
591
- execution: Any,
592
- timeout: float,
593
- ) -> Any | None:
594
- loop = asyncio.get_running_loop()
595
- deadline = loop.time() + timeout
596
- stop_reserve = min(20.0, timeout * 0.2)
597
- try:
598
- return await asyncio.wait_for(
599
- _settle(environment, cwd, scope_path, execution),
600
- timeout=max(0.001, deadline - loop.time() - stop_reserve),
601
- )
602
- except Exception:
603
- try:
604
- remaining = max(0.001, deadline - loop.time())
605
- await asyncio.wait_for(environment.stop(delete=True), timeout=remaining)
606
- except Exception:
607
- pass
608
- finally:
609
- if not execution.done():
610
- execution.cancel()
611
- with contextlib.suppress(asyncio.CancelledError, Exception):
612
- remaining = max(0.001, deadline - loop.time())
613
- await asyncio.wait_for(execution, timeout=remaining)
614
- return None
615
-
616
-
617
- async def _signal(environment: Any, cwd: str, scope_path: str, signal: str) -> None:
618
- command = (
619
- f"pgid=$(cat {shlex.quote(scope_path)} 2>/dev/null) || exit 0; "
620
- "case $pgid in ''|0|*[!0-9]*) exit 0;; esac; "
621
- f"kill -{signal} -- \"-$pgid\""
622
- )
623
- with contextlib.suppress(Exception):
624
- await environment.exec(
625
- command,
626
- cwd=cwd,
627
- timeout_sec=5,
628
- )
629
-
630
-
631
- async def _quiesce_scope(environment: Any, cwd: str, scope_path: str) -> None:
632
- if not await _scope_active(environment, cwd, scope_path):
633
- return
634
- for signal, timeout in (("TERM", 10), ("KILL", 5)):
635
- await _signal(environment, cwd, scope_path, signal)
636
- deadline = asyncio.get_running_loop().time() + timeout
637
- while asyncio.get_running_loop().time() < deadline:
638
- if not await _scope_active(environment, cwd, scope_path):
639
- return
640
- await asyncio.sleep(0.1)
641
- raise RuntimeError("Maka Eval execution scope did not quiesce")
642
-
643
-
644
- async def _scope_active(environment: Any, cwd: str, scope_path: str) -> bool:
645
- result = await environment.exec(
646
- f"pgid=$(cat {shlex.quote(scope_path)} 2>/dev/null) || exit 4; "
647
- "case $pgid in ''|0|*[!0-9]*) exit 4;; esac; "
648
- "kill -0 -- \"-$pgid\" 2>/dev/null; status=$?; "
649
- "if [ $status -eq 0 ]; then exit 0; fi; exit 3",
650
- cwd=cwd,
651
- timeout_sec=5,
652
- )
653
- if result.return_code == 0:
654
- return True
655
- if result.return_code == 3:
656
- return False
657
- raise RuntimeError("Maka Eval execution scope evidence was unavailable")
658
-
659
-
660
- def _require_message(value: dict[str, Any], token: str, kind: str) -> None:
661
- if value.get("token") != token or value.get("kind") != kind:
662
- raise RuntimeError("invalid Maka Eval relay message")
663
-
664
-
665
- async def _receive(reader: asyncio.StreamReader) -> dict[str, Any]:
666
- try:
667
- raw = await reader.readline()
668
- if not raw:
669
- raise RelayTransportClosed("Maka Eval relay peer closed")
670
- value = json.loads(raw)
671
- except (ConnectionError, json.JSONDecodeError, ValueError) as error:
672
- raise RelayTransportClosed("Maka Eval relay message was unavailable") from error
673
- if not isinstance(value, dict):
674
- raise RelayTransportClosed("Maka Eval relay message was invalid")
675
- return value
676
-
677
-
678
- async def _send(writer: asyncio.StreamWriter, value: object) -> bool:
679
- if writer.is_closing():
680
- return False
681
- try:
682
- writer.write((json.dumps(value, separators=(",", ":")) + "\n").encode())
683
- await writer.drain()
684
- return True
685
- except (BrokenPipeError, ConnectionError, RuntimeError):
686
- return False