Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ All notable changes to OriginWeave are documented in this file. The format follo
- Rust 1.97.1 build contract, strict Clippy and rustdoc gates, and exact production function, line, region, and branch coverage enforcement.
- Pinned Chrome-for-Testing Agent Task evidence now captures a bounded sampled Chromium root-plus-descendant process count and RSS total from one `/proc` status sweep, with bounded failure-type diagnostics while preserving the root-only metric and making no trusted per-task attribution claim.
- Pinned Chrome-for-Testing Agent Task evidence now locates the controlled result by exact browser-computed `status`/`Task result` semantics and records only a bounded canonical SHA-256 digest plus stable field identity for the extracted synthetic value, without emitting the raw value.
- Controlled pinned-Chromium Agent Task acceptance now fails closed unless the temporary profile is pristine before launch, browser-observed cookies and Web Storage are empty, saved-credential services are disabled, extensions are disabled by launch policy, and the profile is removed afterward; bounded per-trial evidence does not claim OS- or browser-attested absence of every credential mechanism.
- Hourly bounded OpenCode product-development workflow using `NVIDIA_NIM_API_KEY`, an unprivileged disposable workspace, loopback-only model broker, independently verified patches, and publication through a dedicated `OPENCODE_PR_TOKEN` that cannot review or merge.
- Architecture, agent, security, contribution, research, database naming, roadmap, quality-gate, and TLS service-identity ADR documentation.
- Authoritative product documentation graph spanning PRD, TRD, ADR lifecycle/index, product-wide UML, conceptual ERD, requirement/decision traceability, threat modeling, product-wide test strategy, operability, API/protocol, release/rollback, and current primary-source standards doctoring, with machine-checkable repository contracts that keep conversation-derived future work distinct from protected-main implementation claims.
Expand Down
76 changes: 76 additions & 0 deletions scripts/ci/run_mv3_compatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,52 @@ def _measure_agent_task_semantic_observation_bytes(observation: dict[str, Any])
return len(encoded)


def _require_pristine_agent_task_profile(profile_dir: str) -> None:
"""Fail closed unless the controlled Agent Task profile directory is empty."""

profile_path = pathlib.Path(profile_dir)
if not profile_path.is_dir() or any(profile_path.iterdir()):
raise RuntimeError("Agent Task profile is not pristine before launch")


def _probe_agent_task_ambient_state(driver_port: int, session_id: str) -> dict[str, bool]:
"""Require no browser-visible cookies or Web Storage before the controlled action."""

cookies = _json_request(
driver_port,
"GET",
_webdriver_path(session_id, "/cookie"),
).get("value")
if not isinstance(cookies, list):
raise RuntimeError("Agent Task cookie inspection returned malformed evidence")
if cookies:
raise RuntimeError("Agent Task profile exposed ambient cookies")

storage = _execute(
driver_port,
session_id,
"""
return {
localStorageLength: window.localStorage.length,
sessionStorageLength: window.sessionStorage.length
};
""",
)
if not isinstance(storage, dict):
raise RuntimeError("Agent Task Web Storage inspection returned malformed evidence")
local_storage_length = storage.get("localStorageLength")
session_storage_length = storage.get("sessionStorageLength")
for value in (local_storage_length, session_storage_length):
if isinstance(value, bool) or not isinstance(value, int) or value < 0:
raise RuntimeError("Agent Task Web Storage inspection returned malformed evidence")
if local_storage_length or session_storage_length:
raise RuntimeError("Agent Task profile exposed ambient Web Storage")
return {
"ambient_cookies_absent": True,
"ambient_web_storage_absent": True,
}


def _parse_linux_proc_status_rss_bytes(status_text: str) -> int:
"""Parse exactly one positive Linux ``VmRSS`` kB field into bounded bytes."""

Expand Down Expand Up @@ -743,6 +789,8 @@ def _run_agent_task_browser_pass(
) -> dict[str, Any]:
"""Execute one synthetic Agent Task and measure bounded real-browser evidence."""

_require_pristine_agent_task_profile(profile_dir)
profile_pristine_before_launch = True
started = time.monotonic()
driver_port = _free_loopback_port()
session_id: str | None = None
Expand All @@ -764,6 +812,10 @@ def _run_agent_task_browser_pass(
"browserName": "chrome",
"goog:chromeOptions": {
"binary": str(chrome_bin),
"prefs": {
"credentials_enable_service": False,
"profile.password_manager_enabled": False,
},
"args": [
"--headless=new",
"--no-first-run",
Expand Down Expand Up @@ -816,6 +868,7 @@ def _run_agent_task_browser_pass(
).get("value")
if initial_url != fixture_url:
raise RuntimeError("Agent Task did not load the requested fixture URL")
ambient_state = _probe_agent_task_ambient_state(driver_port, session_id)

input_element = _find_element_by_accessible_role_name(
driver_port,
Expand Down Expand Up @@ -937,6 +990,10 @@ def _run_agent_task_browser_pass(
"structured_value_field": "task_result",
"structured_value_sha256": structured_value_sha256,
"extensions_disabled": True,
"profile_pristine_before_launch": profile_pristine_before_launch,
"ambient_cookies_absent": ambient_state["ambient_cookies_absent"],
"ambient_web_storage_absent": ambient_state["ambient_web_storage_absent"],
"saved_credential_services_disabled": True,
"browser_process_rss_bytes": browser_process_rss_bytes,
"chromium_process_count": chromium_process_count,
"chromium_process_set_rss_bytes": chromium_process_set_rss_bytes,
Expand Down Expand Up @@ -999,6 +1056,12 @@ def _run_agent_task_trial(
"structured_value_field": result["structured_value_field"],
"structured_value_sha256": result["structured_value_sha256"],
"extensions_disabled": result["extensions_disabled"],
"profile_pristine_before_launch": result["profile_pristine_before_launch"],
"ambient_cookies_absent": result["ambient_cookies_absent"],
"ambient_web_storage_absent": result["ambient_web_storage_absent"],
"saved_credential_services_disabled": result[
"saved_credential_services_disabled"
],
"browser_process_rss_bytes": result["browser_process_rss_bytes"],
"chromium_process_count": result["chromium_process_count"],
"chromium_process_set_rss_bytes": result["chromium_process_set_rss_bytes"],
Expand Down Expand Up @@ -1380,6 +1443,16 @@ def main() -> int:
agent_task_trial_pass_rate = (
agent_task_successful_trials / AGENT_TASK_REPEATABILITY_TRIALS
)
agent_task_isolation_complete = all(
trial.get("profile_pristine_before_launch") is True
and trial.get("ambient_cookies_absent") is True
and trial.get("ambient_web_storage_absent") is True
and trial.get("saved_credential_services_disabled") is True
and trial.get("extensions_disabled") is True
and trial.get("profile_cleaned") is True
for trial in agent_task_trials
if trial.get("passed") is True
)
agent_task_surfaces_complete = all(
trial.get("post_condition") is True
and trial.get("input_echo_verified") is True
Expand Down Expand Up @@ -1438,6 +1511,7 @@ def main() -> int:
"repeatability_trials": AGENT_TASK_REPEATABILITY_TRIALS,
"successful_trials": agent_task_successful_trials,
"trial_pass_rate": agent_task_trial_pass_rate,
"isolation_complete": agent_task_isolation_complete,
"trial_results": agent_task_trials,
"forced_close": {
"repeatability_trials": AGENT_TASK_REPEATABILITY_TRIALS,
Expand All @@ -1461,6 +1535,8 @@ def main() -> int:
f"{agent_task_successful_trials}/{AGENT_TASK_REPEATABILITY_TRIALS} "
"trials passed"
)
if not agent_task_isolation_complete:
raise RuntimeError("Agent Task isolation gate failed")
if not agent_task_surfaces_complete:
raise RuntimeError("Agent Task repeatability surfaces were incomplete")
if (
Expand Down
110 changes: 110 additions & 0 deletions tests/test_agent_task_pristine_profile_contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""Contract for pristine, credential-free Agent Task browser profile admission."""

from __future__ import annotations

import pathlib
import runpy
import tempfile
import unittest

ROOT = pathlib.Path(__file__).resolve().parents[1]
RUNNER = ROOT / "scripts" / "ci" / "run_mv3_compatibility.py"


class AgentTaskPristineProfileContractTests(unittest.TestCase):
"""Require explicit isolation proof before the pinned browser task can pass."""

def _namespace(self, name: str) -> dict[str, object]:
return runpy.run_path(str(RUNNER), run_name=name)

def test_runner_exposes_pristine_profile_and_ambient_state_boundaries(self) -> None:
"""Profile admission and ambient-state inspection must be explicit boundaries."""

namespace = self._namespace("agent_task_pristine_profile_contract")
self.assertIn("_require_pristine_agent_task_profile", namespace)
self.assertIn("_probe_agent_task_ambient_state", namespace)

def test_profile_admission_rejects_preexisting_state(self) -> None:
"""Any pre-existing profile entry must fail closed before Chromium starts."""

namespace = self._namespace("agent_task_pristine_profile_behavior")
require_pristine = namespace["_require_pristine_agent_task_profile"]
with tempfile.TemporaryDirectory(prefix="originweave-pristine-profile-") as profile_dir:
require_pristine(profile_dir)
pathlib.Path(profile_dir, "Cookies").write_text("preexisting", encoding="utf-8")
with self.assertRaisesRegex(RuntimeError, "not pristine"):
require_pristine(profile_dir)

def test_ambient_state_probe_rejects_cookies_or_web_storage(self) -> None:
"""Browser-visible cookie or Web Storage state must not be normalized as isolated."""

namespace = self._namespace("agent_task_ambient_state_behavior")
probe = namespace["_probe_agent_task_ambient_state"]

def no_cookies_request(
_driver_port: int,
method: str,
path: str,
_payload: object | None = None,
**_kwargs: object,
) -> dict[str, object]:
self.assertEqual(method, "GET")
self.assertTrue(path.endswith("/cookie"))
return {"value": []}

probe.__globals__["_json_request"] = no_cookies_request
probe.__globals__["_execute"] = lambda *_args, **_kwargs: {
"localStorageLength": 0,
"sessionStorageLength": 0,
}
self.assertEqual(
probe(4444, "session-a"),
{
"ambient_cookies_absent": True,
"ambient_web_storage_absent": True,
},
)

def ambient_cookie_request(
_driver_port: int,
_method: str,
_path: str,
_payload: object | None = None,
**_kwargs: object,
) -> dict[str, object]:
return {"value": [{"name": "ambient", "value": "redacted-test"}]}

probe.__globals__["_json_request"] = ambient_cookie_request
with self.assertRaisesRegex(RuntimeError, "ambient cookies"):
probe(4444, "session-a")

probe = self._namespace("agent_task_ambient_storage_behavior")[
"_probe_agent_task_ambient_state"
]
probe.__globals__["_json_request"] = no_cookies_request
probe.__globals__["_execute"] = lambda *_args, **_kwargs: {
"localStorageLength": 1,
"sessionStorageLength": 0,
}
with self.assertRaisesRegex(RuntimeError, "ambient Web Storage"):
probe(4444, "session-a")

def test_agent_task_disables_saved_credential_services_and_gates_evidence(self) -> None:
"""The acceptance runner must configure and require credential-free isolation evidence."""

runner = RUNNER.read_text(encoding="utf-8")
for expected in (
'"credentials_enable_service": False',
'"profile.password_manager_enabled": False',
'"profile_pristine_before_launch"',
'"ambient_cookies_absent"',
'"ambient_web_storage_absent"',
'"saved_credential_services_disabled"',
"Agent Task isolation gate failed",
):
with self.subTest(expected=expected):
self.assertIn(expected, runner)


if __name__ == "__main__":
unittest.main()
Loading