Skip to content
Draft
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ All notable changes to OriginWeave are documented in this file. The format follo
- 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.
- Pinned Chrome-for-Testing Agent Task semantic-observation evidence is now canonicalized as compact sorted-key UTF-8 JSON and capped at 4,096 bytes, accepting the exact limit while failing closed on empty, non-object, or oversized observations before they enter successful trial evidence.
- Pinned Chrome-for-Testing forced-close recovery evidence now closes a disposable controlled browsing context, requires structured exact `no such window` failure on the next current-context command, proves a separate survivor context remains usable in the same WebDriver session, repeats the probe with isolated profile cleanup, and fails closed on substring lookalikes or malformed error framing.
- 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,
}
Comment on lines +294 to +329

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Ambient-state probe is origin-scoped only

_probe_agent_task_ambient_state reads cookies via GET /cookie and Web Storage from the current document, both scoped to the fixture origin. State belonging to other origins in a reused profile goes undetected. Harmless here since the profile is a fresh empty tempdir enforced by _require_pristine_agent_task_profile, and the PR's Truth boundary acknowledges this limit.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.



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