From fbc8ae61d759292eb475c1a1a6ad45b326957454 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 00:20:46 +0000 Subject: [PATCH 1/3] Initial plan From e9cd85ff3ef0f8e0ed031774dc86803f12baa749 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 00:24:12 +0000 Subject: [PATCH 2/3] Add workspace operation plane contract for governed browser actions Agent-Logs-Url: https://github.com/SourceOS-Linux/BearBrowser/sessions/406ee8a7-df14-43cd-a947-0b28497565f7 Co-authored-by: mdheller <21163552+mdheller@users.noreply.github.com> --- agentplane/registration.yaml | 17 ++++ agentplane/session-lifecycle.example.yaml | 9 ++ agentplane/workspace-operation-plane.yaml | 98 +++++++++++++++++++ automation/playwright-adapter.yaml | 23 +++++ automation/stagehand-adapter.yaml | 23 +++++ automation/terminal-browser-adapters.yaml | 23 +++++ ...gentplane-prophet-workspace-integration.md | 3 +- docs/integration-contract.md | 1 + docs/provenance-events.md | 16 ++- mounts/agent-browser-mounts.yaml | 42 ++++++++ policy/bearbrowser-contract.yaml | 25 +++++ prophet-workspace/browser-surface.yaml | 17 ++++ schemas/provenance-event.schema.json | 7 ++ scripts/bearbrowser-emit-event.py | 6 ++ scripts/verify-workspace-operation-plane.py | 64 ++++++++++++ 15 files changed, 372 insertions(+), 2 deletions(-) create mode 100644 agentplane/workspace-operation-plane.yaml create mode 100644 scripts/verify-workspace-operation-plane.py diff --git a/agentplane/registration.yaml b/agentplane/registration.yaml index 61677cd..8e015eb 100644 --- a/agentplane/registration.yaml +++ b/agentplane/registration.yaml @@ -28,6 +28,7 @@ spec: defaultTtlMinutes: 120 requiresPolicyDecision: true requiresProvenanceSink: true + operationPlaneContract: agentplane/workspace-operation-plane.yaml sessionStates: - requested - policy-pending @@ -103,6 +104,22 @@ spec: policyDecisions: PolicyFabric provenanceEvents: AgentPlane workspaceState: ProphetWorkspace + workspaceOperations: + required: true + types: + - browser.session.start + - browser.capture.create + - browser.download.create + - browser.upload.create + - browser.automation.run + - browser.diagnostics.export_redacted + operationEvents: + - start + - progress + - failure + - retry + - cancel + - complete provenanceEvents: - browser.session.started - browser.session.ended diff --git a/agentplane/session-lifecycle.example.yaml b/agentplane/session-lifecycle.example.yaml index a4ce1c6..2182399 100644 --- a/agentplane/session-lifecycle.example.yaml +++ b/agentplane/session-lifecycle.example.yaml @@ -55,3 +55,12 @@ spec: policyDecisions: PolicyFabric provenanceEvents: AgentPlane workspaceState: ProphetWorkspace + workspaceOperations: + contract: agentplane/workspace-operation-plane.yaml + types: + - browser.session.start + - browser.capture.create + - browser.download.create + - browser.upload.create + - browser.automation.run + - browser.diagnostics.export_redacted diff --git a/agentplane/workspace-operation-plane.yaml b/agentplane/workspace-operation-plane.yaml new file mode 100644 index 0000000..2c1a555 --- /dev/null +++ b/agentplane/workspace-operation-plane.yaml @@ -0,0 +1,98 @@ +apiVersion: sourceos.dev/v1alpha1 +kind: BrowserWorkspaceOperationContract +metadata: + name: bearbrowser-workspace-operation-plane + labels: + sourceos.dev/product: BearBrowser +spec: + principle: Browser side effects are WorkspaceOperations, not hidden runtime behavior. + operationTypes: + - browser.session.start + - browser.capture.create + - browser.download.create + - browser.upload.create + - browser.automation.run + - browser.diagnostics.export_redacted + artifacts: + - kind: BrowserSession + operationType: browser.session.start + - kind: WebCapture + operationType: browser.capture.create + - kind: DownloadArtifact + operationType: browser.download.create + - kind: UploadArtifact + operationType: browser.upload.create + - kind: BrowserAutomationRun + operationType: browser.automation.run + - kind: BrowserDiagnosticBundle + operationType: browser.diagnostics.export_redacted + controls: + redaction: + cookies: redact + credentials: redact + tokens: redact + authHeaders: redact + prompts: redact + sensitiveIds: redact + trustBoundaryRecords: + required: true + dimensions: + - externalSite + - connector + - authDomain + - thirdPartyAutomation + policyGates: + browser.automation.run: + decisions: + - block + - quarantine + - admit + - activate + browser.download.create: + decisions: + - block + - quarantine + - admit + - activate + browser.upload.create: + decisions: + - block + - quarantine + - admit + - activate + browser.capture.create: + decisions: + - block + - quarantine + - admit + - activate + actorAttribution: + required: true + actors: + - user + - agent + - system + - connector + operationEvents: + required: true + lifecycle: + - start + - progress + - failure + - retry + - cancel + - complete + durableStateRule: + requireOperationPlaneForDurableState: true + statement: No browser automation or capture creates durable workspace state outside the Operation Plane. + authority: + policyAuthority: PolicyFabric + statement: BearBrowser renders and obeys Policy Fabric decisions and is not policy authority. + integrationTargets: + - SocioProphet/prophet-core-contracts#1 + - SocioProphet/prophet-platform#376 + - SocioProphet/policy-fabric#46 + - SourceOS-Linux/sourceos-spec#87 + - SociOS-Linux/workstation-contracts#28 + - SourceOS-Linux/sourceos-devtools#19 + - SocioProphet/workspace-inventory#4 diff --git a/automation/playwright-adapter.yaml b/automation/playwright-adapter.yaml index 2bba055..0891d19 100644 --- a/automation/playwright-adapter.yaml +++ b/automation/playwright-adapter.yaml @@ -17,6 +17,29 @@ spec: requireSessionToken: true requireEphemeralPort: true denyCredentialExport: true + operationContract: agentplane/workspace-operation-plane.yaml + workspaceOperations: + requiredTypes: + - browser.session.start + - browser.capture.create + - browser.download.create + - browser.upload.create + - browser.automation.run + - browser.diagnostics.export_redacted + operationEvents: + - start + - progress + - failure + - retry + - cancel + - complete + trustBoundaryRecords: + required: true + dimensions: + - externalSite + - connector + - authDomain + - thirdPartyAutomation events: required: - browser.session.started diff --git a/automation/stagehand-adapter.yaml b/automation/stagehand-adapter.yaml index 64d2ed6..9f5c2c6 100644 --- a/automation/stagehand-adapter.yaml +++ b/automation/stagehand-adapter.yaml @@ -17,6 +17,29 @@ spec: requireStructuredExtractionPolicy: true denyCredentialExport: true denyPolicyBypass: true + operationContract: agentplane/workspace-operation-plane.yaml + workspaceOperations: + requiredTypes: + - browser.session.start + - browser.capture.create + - browser.download.create + - browser.upload.create + - browser.automation.run + - browser.diagnostics.export_redacted + operationEvents: + - start + - progress + - failure + - retry + - cancel + - complete + trustBoundaryRecords: + required: true + dimensions: + - externalSite + - connector + - authDomain + - thirdPartyAutomation events: required: - browser.session.started diff --git a/automation/terminal-browser-adapters.yaml b/automation/terminal-browser-adapters.yaml index 9113426..b3f3123 100644 --- a/automation/terminal-browser-adapters.yaml +++ b/automation/terminal-browser-adapters.yaml @@ -13,6 +13,29 @@ spec: denyCredentialExport: true denyAmbientHostFilesystem: true requireProvenanceEvents: true + operationContract: agentplane/workspace-operation-plane.yaml + workspaceOperations: + requiredTypes: + - browser.session.start + - browser.capture.create + - browser.download.create + - browser.upload.create + - browser.automation.run + - browser.diagnostics.export_redacted + operationEvents: + - start + - progress + - failure + - retry + - cancel + - complete + trustBoundaryRecords: + required: true + dimensions: + - externalSite + - connector + - authDomain + - thirdPartyAutomation adapters: - name: carbonyl capability: browser.terminal.carbonyl diff --git a/docs/agentplane-prophet-workspace-integration.md b/docs/agentplane-prophet-workspace-integration.md index 0abf1e3..b691f78 100644 --- a/docs/agentplane-prophet-workspace-integration.md +++ b/docs/agentplane-prophet-workspace-integration.md @@ -34,6 +34,7 @@ Commands must include or resolve: - Downloads, captures, profile state, and provenance are governed mounts. - Remote debugging is denied unless explicitly granted. - Terminal browser backends are capability classes, not authority grants. +- Durable browser automation/capture/download/upload state is admitted through Workspace Operation Plane records only. ## Prophet Workspace state @@ -79,4 +80,4 @@ Prophet Workspace adapter: ## Events -BearBrowser uses the event contract in `docs/provenance-events.md` and the lifecycle example in `agentplane/session-lifecycle.example.yaml`. +BearBrowser uses the event contract in `docs/provenance-events.md`, lifecycle example in `agentplane/session-lifecycle.example.yaml`, and the Workspace Operation Plane contract in `agentplane/workspace-operation-plane.yaml`. diff --git a/docs/integration-contract.md b/docs/integration-contract.md index 6682280..333240c 100644 --- a/docs/integration-contract.md +++ b/docs/integration-contract.md @@ -5,6 +5,7 @@ BearBrowser integrates with: - AgentPlane for runtime registration and capability discovery - PolicyFabric for network, file, credential, and capture policy - Prophet Workspace for user-visible workspace control +- Workspace Operation Plane for browser session, capture, download, upload, automation, and redacted diagnostics records - TopoLVM/local mount planning for browser state and downloads - Matrix/Hermes for command, event, and session coordination - Sherlock/Holmes where browser activity becomes inspectable operational evidence diff --git a/docs/provenance-events.md b/docs/provenance-events.md index c88f9da..46b70b8 100644 --- a/docs/provenance-events.md +++ b/docs/provenance-events.md @@ -2,6 +2,20 @@ BearBrowser emits provenance events so AgentPlane, PolicyFabric, and Prophet Workspace can reconstruct browser activity without relying on opaque agent logs. +## Workspace Operation Plane mapping + +BearBrowser browser side effects must map to WorkspaceOperations: + +- `browser.session.start` -> `BrowserSession` +- `browser.capture.create` -> `WebCapture` +- `browser.download.create` -> `DownloadArtifact` +- `browser.upload.create` -> `UploadArtifact` +- `browser.automation.run` -> `BrowserAutomationRun` +- `browser.diagnostics.export_redacted` -> `BrowserDiagnosticBundle` + +Each operation emits `OperationEvent` lifecycle states: `start`, `progress`, `failure`, `retry`, `cancel`, and `complete`. +Operation records require actor attribution (`user`, `agent`, `system`, or `connector`) and TrustBoundary metadata (`externalSite`, `connector`, `authDomain`, `thirdPartyAutomation`). + ## Event envelope Each event should include: @@ -20,7 +34,7 @@ Each event should include: - `decision` for policy events - `reason` for denied actions -Events must not contain passwords, payment card values, passkey private material, biometric material, tokens, cookies, or other secret values. +Events must not contain passwords, payment card values, passkey private material, biometric material, tokens, cookies, auth headers, prompt content, sensitive IDs, or other secret values. ## Required events diff --git a/mounts/agent-browser-mounts.yaml b/mounts/agent-browser-mounts.yaml index e7561d9..41a0f85 100644 --- a/mounts/agent-browser-mounts.yaml +++ b/mounts/agent-browser-mounts.yaml @@ -21,6 +21,14 @@ spec: provenance: emitOnCreate: browser.download.created requireSha256: true + workspaceOperationType: browser.download.create + policyGate: + required: true + decisionModes: + - block + - quarantine + - admit + - activate - name: profile mountClass: agent-profile purpose: Ephemeral browser profile state, cookies, local storage, extension state, and browser cache partition metadata. @@ -44,6 +52,36 @@ spec: provenance: emitOnCreate: browser.capture.created requireSha256: true + workspaceOperationType: browser.capture.create + policyGate: + required: true + decisionModes: + - block + - quarantine + - admit + - activate + - name: uploads + mountClass: agent-uploads + purpose: Files staged for browser upload operations under PolicyFabric control. + defaultPath: /workspace/uploads + mode: readOnly + governed: true + required: false + persistByDefault: false + restrictions: + requireExplicitGrant: true + denySymlinkEscape: true + denyDeviceFiles: true + provenance: + emitOnUse: browser.upload.created + workspaceOperationType: browser.upload.create + policyGate: + required: true + decisionModes: + - block + - quarantine + - admit + - activate - name: cache mountClass: agent-cache purpose: Disposable network and browser build/runtime cache. @@ -90,3 +128,7 @@ spec: - ~/.kube - /var/run/docker.sock - /var/run/podman/podman.sock + durableState: + operationPlaneRequired: true + operationContract: agentplane/workspace-operation-plane.yaml + statement: No browser automation or capture creates durable workspace state outside the Operation Plane. diff --git a/policy/bearbrowser-contract.yaml b/policy/bearbrowser-contract.yaml index 54c2ee5..6d7d64d 100644 --- a/policy/bearbrowser-contract.yaml +++ b/policy/bearbrowser-contract.yaml @@ -88,6 +88,7 @@ spec: noAmbientCloudCredentialAccess: true allowedMountClasses: - agent-downloads + - agent-uploads - agent-profile - agent-captures - agent-cache @@ -134,3 +135,27 @@ spec: eventSink: AgentPlane policyDecisionSink: PolicyFabric workspaceVisibilitySink: ProphetWorkspace + workspaceOperations: + required: true + operationContract: agentplane/workspace-operation-plane.yaml + requiredTypes: + - browser.session.start + - browser.capture.create + - browser.download.create + - browser.upload.create + - browser.automation.run + - browser.diagnostics.export_redacted + operationEventLifecycle: + - start + - progress + - failure + - retry + - cancel + - complete + policyAuthority: PolicyFabric + policyMediatedTypes: + - browser.capture.create + - browser.download.create + - browser.upload.create + - browser.automation.run + - browser.diagnostics.export_redacted diff --git a/prophet-workspace/browser-surface.yaml b/prophet-workspace/browser-surface.yaml index b4c2fbc..59c598e 100644 --- a/prophet-workspace/browser-surface.yaml +++ b/prophet-workspace/browser-surface.yaml @@ -57,6 +57,23 @@ spec: - viewCredentialBoundarySummary - requestSessionEnd - exportProvenanceSummary + - exportRedactedDiagnostics + workspaceOperations: + operationContract: agentplane/workspace-operation-plane.yaml + operationTypes: + - browser.session.start + - browser.capture.create + - browser.download.create + - browser.upload.create + - browser.automation.run + - browser.diagnostics.export_redacted + operationEvents: + - start + - progress + - failure + - retry + - cancel + - complete redaction: hideCredentials: true hideCookieValues: true diff --git a/schemas/provenance-event.schema.json b/schemas/provenance-event.schema.json index e419125..ad56913 100644 --- a/schemas/provenance-event.schema.json +++ b/schemas/provenance-event.schema.json @@ -56,6 +56,13 @@ "memory.rejected", "policy.decision", "runtime.health" + , + "browser.session.start", + "browser.capture.create", + "browser.download.create", + "browser.upload.create", + "browser.automation.run", + "browser.diagnostics.export_redacted" ] }, "actor": { diff --git a/scripts/bearbrowser-emit-event.py b/scripts/bearbrowser-emit-event.py index 4c6ebf7..cfeb583 100644 --- a/scripts/bearbrowser-emit-event.py +++ b/scripts/bearbrowser-emit-event.py @@ -37,6 +37,12 @@ "memory.rejected", "policy.decision", "runtime.health", + "browser.session.start", + "browser.capture.create", + "browser.download.create", + "browser.upload.create", + "browser.automation.run", + "browser.diagnostics.export_redacted", } SURFACES = { diff --git a/scripts/verify-workspace-operation-plane.py b/scripts/verify-workspace-operation-plane.py new file mode 100644 index 0000000..0720169 --- /dev/null +++ b/scripts/verify-workspace-operation-plane.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +"""Verify BearBrowser workspace operation plane contract invariants.""" +from __future__ import annotations + +import sys +from pathlib import Path + +CONTRACT = Path("agentplane/workspace-operation-plane.yaml") +REQUIRED_TEXT = { + "browser.session.start": "missing browser.session.start operation type", + "browser.capture.create": "missing browser.capture.create operation type", + "browser.download.create": "missing browser.download.create operation type", + "browser.upload.create": "missing browser.upload.create operation type", + "browser.automation.run": "missing browser.automation.run operation type", + "browser.diagnostics.export_redacted": "missing browser.diagnostics.export_redacted operation type", + "kind: BrowserSession": "missing BrowserSession artifact", + "kind: WebCapture": "missing WebCapture artifact", + "kind: DownloadArtifact": "missing DownloadArtifact artifact", + "kind: UploadArtifact": "missing UploadArtifact artifact", + "kind: BrowserAutomationRun": "missing BrowserAutomationRun artifact", + "kind: BrowserDiagnosticBundle": "missing BrowserDiagnosticBundle artifact", + "cookies: redact": "cookies must be redacted", + "credentials: redact": "credentials must be redacted", + "tokens: redact": "tokens must be redacted", + "authHeaders: redact": "auth headers must be redacted", + "prompts: redact": "prompts must be redacted", + "sensitiveIds: redact": "sensitive IDs must be redacted", + "policyAuthority: PolicyFabric": "PolicyFabric must remain policy authority", + "No browser automation or capture creates durable workspace state outside the Operation Plane.": "missing durable state hard rule", +} +REQUIRED_LIFECYCLE = {"start", "progress", "failure", "retry", "cancel", "complete"} + + +def main() -> int: + if not CONTRACT.exists(): + print(f"ERROR: missing {CONTRACT}", file=sys.stderr) + return 1 + + text = CONTRACT.read_text(encoding="utf-8") + errors: list[str] = [] + + for required, message in REQUIRED_TEXT.items(): + if required not in text: + errors.append(message) + + for state in sorted(REQUIRED_LIFECYCLE): + if f"- {state}" not in text: + errors.append(f"missing operation event lifecycle state: {state}") + + for dimension in ("externalSite", "connector", "authDomain", "thirdPartyAutomation"): + if f"- {dimension}" not in text: + errors.append(f"missing trust boundary dimension: {dimension}") + + if errors: + for error in errors: + print(f"ERROR: {error}", file=sys.stderr) + return 1 + + print("BearBrowser workspace operation plane contract verified") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From 263495e336af15bf44463be350d5577ef9c3a17b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 00:26:02 +0000 Subject: [PATCH 3/3] Address validation feedback formatting and docs wording Agent-Logs-Url: https://github.com/SourceOS-Linux/BearBrowser/sessions/406ee8a7-df14-43cd-a947-0b28497565f7 Co-authored-by: mdheller <21163552+mdheller@users.noreply.github.com> --- docs/provenance-events.md | 2 +- schemas/provenance-event.schema.json | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/provenance-events.md b/docs/provenance-events.md index 46b70b8..0dc0f91 100644 --- a/docs/provenance-events.md +++ b/docs/provenance-events.md @@ -34,7 +34,7 @@ Each event should include: - `decision` for policy events - `reason` for denied actions -Events must not contain passwords, payment card values, passkey private material, biometric material, tokens, cookies, auth headers, prompt content, sensitive IDs, or other secret values. +Events must not contain passwords, payment card values, passkeys private material, biometric material, tokens, cookies, auth headers, prompt content, sensitive IDs, or other secret values. ## Required events diff --git a/schemas/provenance-event.schema.json b/schemas/provenance-event.schema.json index ad56913..73e8006 100644 --- a/schemas/provenance-event.schema.json +++ b/schemas/provenance-event.schema.json @@ -55,8 +55,7 @@ "memory.committed", "memory.rejected", "policy.decision", - "runtime.health" - , + "runtime.health", "browser.session.start", "browser.capture.create", "browser.download.create",