Advance dependency roots with guarded source implementations
Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a10391-6355-7b41-b0fa-3e14e874f091
This commit is contained in:
parent
3c1b135c27
commit
53f6ea2603
3 changed files with 149 additions and 9 deletions
|
|
@ -14,7 +14,25 @@ from pathlib import Path
|
|||
from sandboxer.extensions.bwrap import BwrapExtension
|
||||
from sandboxer.models import Profile
|
||||
|
||||
PROBE = r'''
|
||||
ENTRYPOINT_PROBE = r'''
|
||||
def entrypoint_started(runtime, name, timeout=15):
|
||||
launcher = runtime / 'bin' / name
|
||||
if launcher.is_symlink() or not launcher.is_file():
|
||||
return False
|
||||
try:
|
||||
result = subprocess.run([str(launcher), '--help'], capture_output=True,
|
||||
timeout=timeout)
|
||||
except (OSError, subprocess.TimeoutExpired):
|
||||
return False
|
||||
return result.returncode == 0 and b'usage:' in result.stdout.lower()
|
||||
|
||||
|
||||
def package_inside_runtime(module, runtime):
|
||||
origin = getattr(module, '__file__', None)
|
||||
return bool(origin) and Path(origin).resolve().is_relative_to(runtime.resolve())
|
||||
'''
|
||||
|
||||
PROBE = ENTRYPOINT_PROBE + r'''
|
||||
import json, os, subprocess, sys
|
||||
from pathlib import Path
|
||||
import rein_aharness.adapter
|
||||
|
|
@ -35,9 +53,22 @@ else:
|
|||
readonly = False
|
||||
assert readonly
|
||||
assert not source.exists()
|
||||
help_result = subprocess.run(['rein-aharness', '--help'], capture_output=True, timeout=15)
|
||||
assert help_result.returncode == 0
|
||||
assert b'usage:' in help_result.stdout
|
||||
assert entrypoint_started(runtime, 'rein-aharness'), 'rein entrypoint did not start'
|
||||
owner_entrypoints_required = sys.argv[3] == 'true'
|
||||
glas_cli_started = False
|
||||
packages = [rein_aharness.adapter, llm_connect]
|
||||
if owner_entrypoints_required:
|
||||
import glas_harness
|
||||
import sandboxer
|
||||
packages.extend([glas_harness, sandboxer])
|
||||
glas_cli_started = entrypoint_started(runtime, 'glas-harness')
|
||||
assert glas_cli_started, 'glas entrypoint did not start'
|
||||
packages_inside_runtime = all(package_inside_runtime(module, runtime) for module in packages)
|
||||
assert packages_inside_runtime, 'package outside runtime'
|
||||
assert json.loads(os.environ['SANDBOXER_CREDENTIAL_ROUTE_REFS']) == []
|
||||
assert not any(name in os.environ for name in
|
||||
('ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN', 'OPENAI_API_KEY',
|
||||
'OPENROUTER_API_KEY')), 'provider credential present'
|
||||
claude_version = None
|
||||
proxy_present = False
|
||||
if sys.argv[2]:
|
||||
|
|
@ -55,6 +86,8 @@ interfaces = [line.split(':', 1)[0].strip()
|
|||
assert interfaces == ['lo']
|
||||
print(json.dumps({'rein_cli_started': True, 'adapter_imported': True,
|
||||
'runtime_readonly': readonly, 'source_absent': True,
|
||||
'owner_entrypoints_required': owner_entrypoints_required,
|
||||
'glas_cli_started': glas_cli_started, 'packages_inside_runtime': True,
|
||||
'home_outside_workspace': True, 'home_mode': '0700',
|
||||
'worktree_clean': True, 'interfaces': interfaces,
|
||||
'python_prefix': sys.prefix,
|
||||
|
|
@ -69,6 +102,8 @@ def main() -> int:
|
|||
parser.add_argument("--runtime-path", required=True)
|
||||
parser.add_argument("--runtime-sha256", required=True)
|
||||
parser.add_argument("--claude-version", default="")
|
||||
parser.add_argument("--require-owner-entrypoints", action="store_true",
|
||||
help="Require Glas and rein startup and all four owner packages")
|
||||
args = parser.parse_args()
|
||||
with tempfile.TemporaryDirectory(prefix="sandboxer-runtime-proof-") as temporary:
|
||||
root = Path(temporary)
|
||||
|
|
@ -87,11 +122,12 @@ def main() -> int:
|
|||
try:
|
||||
extension.wait_ready(handle)
|
||||
result = extension.execute(
|
||||
handle, ["python3", "-c", PROBE, str(source), args.claude_version],
|
||||
handle, ["python3", "-c", PROBE, str(source), args.claude_version,
|
||||
str(args.require_owner_entrypoints).lower()],
|
||||
credential_route_refs=[],
|
||||
execution_context={"actor": "agt", "project": "sand-boxer-runtime-proof",
|
||||
"run_id": "sand-wp-0015-proof"},
|
||||
timeout_seconds=30, max_output_bytes=65536,
|
||||
timeout_seconds=60, max_output_bytes=65536,
|
||||
)
|
||||
persistence = extension.execute(
|
||||
handle, ["python3", "-c",
|
||||
|
|
|
|||
77
tests/test_runtime_smoke.py
Normal file
77
tests/test_runtime_smoke.py
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import importlib.util
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"runtime_smoke", Path(__file__).parents[1] / "scripts/smoke-bwrap-runtime.py"
|
||||
)
|
||||
smoke = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(smoke)
|
||||
namespace = {"subprocess": subprocess, "Path": Path}
|
||||
exec(smoke.ENTRYPOINT_PROBE, namespace)
|
||||
started = namespace["entrypoint_started"]
|
||||
inside = namespace["package_inside_runtime"]
|
||||
|
||||
|
||||
def launcher(tmp_path, body):
|
||||
runtime = tmp_path / "relocated runtime"
|
||||
(runtime / "bin").mkdir(parents=True)
|
||||
entry = runtime / "bin/glas-harness"
|
||||
entry.write_text(f"#!{sys.executable}\n{body}\n")
|
||||
entry.chmod(0o755)
|
||||
return runtime, entry
|
||||
|
||||
|
||||
def test_real_relocated_launcher_help_starts(tmp_path):
|
||||
runtime, _ = launcher(tmp_path, "print('Usage: glas-harness [options]')")
|
||||
assert started(runtime, "glas-harness")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("body", [
|
||||
"print('not command help')",
|
||||
"import sys; print('usage: fixture'); sys.exit(127)",
|
||||
"import sys; print('stderr-canary', file=sys.stderr); sys.exit(1)",
|
||||
])
|
||||
def test_failed_or_non_help_launcher_is_not_evidence(tmp_path, body, capsys):
|
||||
runtime, _ = launcher(tmp_path, body)
|
||||
assert not started(runtime, "glas-harness")
|
||||
assert capsys.readouterr() == ("", "")
|
||||
|
||||
|
||||
def test_vanished_build_interpreter_and_missing_launcher_refuse(tmp_path):
|
||||
runtime, entry = launcher(tmp_path, "print('usage: fixture')")
|
||||
entry.write_text("#!/bin/sh\nexec /vanished/build/bin/python3 -c 'print(1)'\n")
|
||||
assert not started(runtime, "glas-harness")
|
||||
assert not started(runtime, "rein-aharness")
|
||||
|
||||
|
||||
def test_launcher_timeout_is_not_startup_success(tmp_path):
|
||||
runtime, _ = launcher(tmp_path, "import time; time.sleep(10)")
|
||||
assert not started(runtime, "glas-harness", timeout=0.05)
|
||||
|
||||
|
||||
def test_external_symlink_launcher_refuses_even_if_help_succeeds(tmp_path):
|
||||
runtime, entry = launcher(tmp_path, "print('usage: fixture')")
|
||||
external = tmp_path / "external"
|
||||
entry.rename(external)
|
||||
entry.symlink_to(external)
|
||||
assert not started(runtime, "glas-harness")
|
||||
|
||||
|
||||
def test_package_provenance_rejects_external_and_symlink_origins(tmp_path):
|
||||
runtime = tmp_path / "runtime"
|
||||
runtime.mkdir()
|
||||
installed = runtime / "package.py"
|
||||
installed.write_text("")
|
||||
assert inside(SimpleNamespace(__file__=str(installed)), runtime)
|
||||
external = tmp_path / "external.py"
|
||||
external.write_text("")
|
||||
installed.unlink()
|
||||
installed.symlink_to(external)
|
||||
assert not inside(SimpleNamespace(__file__=str(installed)), runtime)
|
||||
assert not inside(SimpleNamespace(__file__=str(external)), runtime)
|
||||
assert not inside(SimpleNamespace(), runtime)
|
||||
|
|
@ -9,7 +9,7 @@ flavor: implementation
|
|||
owner: codex
|
||||
topic_slug: bwrap-runtime-and-private-state
|
||||
created: "2026-09-05"
|
||||
updated: "2026-09-27"
|
||||
updated: "2026-10-04"
|
||||
state_hub_workstream_id: "d3f12387-fd23-58f0-b979-9c811507614d"
|
||||
---
|
||||
|
||||
|
|
@ -88,8 +88,8 @@ credential acquisition occurred; T04 remains waiting.
|
|||
```task
|
||||
id: SAND-WP-0015-T04
|
||||
status: wait
|
||||
blocked_on: message-from:railiance-platform
|
||||
blocking_reason: "Credential owner railiance-platform/OpenBao with rein-aharness must establish a Claude-compatible route and delivery/revocation contract."
|
||||
blocked_on: message-from:rein-aharness
|
||||
blocking_reason: "Native credential delivery/revocation succeeded in the September 27 single attempt; rein-aharness must return corrected immutable artifact/pin admission, held EUR10 reconciliation and separately authorized successful owner-runtime acceptance."
|
||||
priority: high
|
||||
state_hub_task_id: "58817ef6-76d9-5e34-908f-c024e6c99f93"
|
||||
```
|
||||
|
|
@ -309,3 +309,30 @@ admission and a separately authorized successful model/tool/commit proof remain.
|
|||
The existing SAND-WP-0015 / REINAH-WP-0003 / SECRETS-WP-0009 records retain the
|
||||
work. No new task or workplan. Detailed non-secret receipts are in rein-aharness
|
||||
`docs/evidence/2026-09-27-metered-*.json`.
|
||||
|
||||
|
||||
## 2026-10-04 offline owner startup proof preparation
|
||||
|
||||
The existing no-credential smoke command now supports
|
||||
`--require-owner-entrypoints`: the admitted digest-pinned runtime must start both
|
||||
`rein-aharness --help` and `glas-harness --help`, and imported rein, llm-connect,
|
||||
Glas and sandboxer modules must originate inside the mounted artifact. Broken or
|
||||
missing launchers, failed help, timeout and external package origins cannot be
|
||||
recorded as startup success. The default standalone mode remains supported.
|
||||
Launcher diagnostics are not copied into the receipt. Focused tests exercise
|
||||
real subprocesses, including the vanished-build-interpreter failure.
|
||||
|
||||
This is preparation for a corrected immutable candidate's independent native
|
||||
startup proof; it is not that candidate's receipt or owner acceptance. T04 stays
|
||||
`wait`, the plan stays `blocked`, and the Sept27 artifact/liability evidence
|
||||
remains intact. Replacement artifact admission and pins, explicit retained
|
||||
EUR 10 reconciliation, and a separately authorized successful model/tool/commit
|
||||
attempt remain with the existing owners. No credentials, provider request,
|
||||
queue claim, policy activation or retry authorization is supplied here.
|
||||
|
||||
2026-10-04 current blocker reconciliation: September 27 native provider/companion
|
||||
apply/verify/exec and successful revocation supersede the original missing
|
||||
platform route. The remaining owner return is rein-aharness corrected artifact/
|
||||
profile admission, retained EUR10 reconciliation and fresh retry authority.
|
||||
T04 stays wait; no renewed trial is authorized. Full owner check: lint clean,
|
||||
219 tests passed (one existing Starlette deprecation warning).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue