Skip to content
Merged
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
93 changes: 93 additions & 0 deletions docs/REMOTE_COMMANDER_R3_RUNTIME_QUALIFICATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# ContinuityOS Remote Commander R3 — Windows Runtime Qualification

## Baseline

R3 originally started from merged `master` `5a72da36f104421010718da96681c3304fc48fe1`.

After R24 / PR #199 merged, R3 was synchronized by a normal merge commit from new `master`:

`5e6887a3109590e190d5427a3205c3f99e9b5a3f`

No rebase or force-push was used.

Qualification was performed from a separate clean Windows checkout so the parallel R24 / PR #199 worktree and branch were not modified.

## Official tunnel-client artifact

Validated release:

- repository: `openai/tunnel-client`
- release: `v0.0.14`
- asset: `tunnel-client-v0.0.14-windows-amd64.zip`
- expected SHA-256: `784ab8da7b5a88f0109f1fd8aaf0a1c86067430b896dddf307ef7e3cc49fa1a5`
- observed SHA-256: exact match
- binary version: `0.0.14+0f870e50a973fa820d4c409000059e181e8d242b`

The official binary advertises `sample_mcp_stdio_local` and the MCP command profile contract used by ContinuityOS R2.

## Credential-free Windows result

The merged launcher `scripts/windows/ContinuityOS-RemoteTunnel.ps1` produced:

- schema: `continuityos.remote_tunnel_plan/v1`
- MCP transport: `stdio`
- MCP tool profile: `chatgpt-pro-readonly`
- public MCP listener: `false`
- health/UI listener: `127.0.0.1:8080`
- health/UI scope: `loopback`
- direct shell: `false`
- control-plane key present: `false`

The real Windows stdio MCP process was then exercised over JSON-RPC. It advertised exactly:

- `capability_status`
- `system_info`
- `fs_list`
- `fs_read`

A bounded `fs_read` of a benign repository file succeeded. A direct call to hidden write tool `remember` was rejected by the server-side profile boundary.

Observed local state after the R24 synchronization:

`LOCAL_READONLY_RUNTIME_GREEN`

The post-sync Windows regression set covering R3 Remote Commander plus the merged R24 witnessed-replay tests passed: `44 passed`.

## Fail-closed credential gate

With `CONTROL_PLANE_API_KEY` and `CONTROL_PLANE_TUNNEL_ID` absent:

- launcher `Doctor` exited non-zero and identified the missing runtime API key;
- launcher `Init` exited non-zero before creating a tunnel profile;
- no secret-like value was printed.

This is intentional. R3 does not manufacture, recover, persist, or log OpenAI runtime credentials.

## Reproducible harness

Run:

```powershell
.\scripts\windows\Test-ContinuityOS-RemoteRuntime.ps1 \
-ExpectedHead <exact-commit-sha> \
-TunnelClient C:\path\to\tunnel-client.exe
```

The harness fails closed unless the Git worktree is clean, the expected head matches when provided, the launcher plan preserves the read-only boundary, the official tunnel-client stdio sample is available, the MCP advertises exactly four read-only tools, a benign read succeeds, and a hidden write call is rejected.

## Remaining live qualification

The following is **not yet claimed**:

`Init -> Doctor -> Run -> ChatGPT connector discovery -> tools/list -> benign read through the live OpenAI tunnel`

That step requires operator-provided:

- `CONTROL_PLANE_API_KEY` with Tunnels Read + Use;
- `CONTROL_PLANE_TUNNEL_ID` for the intended OpenAI workspace.

Until those values exist at runtime, `live_tunnel_qualified=false`.

## Parallel branch isolation

R24 / PR #199 merged independently into master before R3. Its file set had zero overlap with the R3 Remote Commander files. R3 then synchronized from that merged master with a normal merge commit; R3 did not modify the historical R24 branch, rebase it, or force-push it.
153 changes: 153 additions & 0 deletions scripts/windows/Test-ContinuityOS-RemoteRuntime.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
[CmdletBinding()]
param(
[string]$RepoRoot = "",
[string]$RemoteRoot = "",
[string]$ProbeRelativePath = "README.md",
[string]$TunnelClient = "tunnel-client",
[string]$Python = "python",
[string]$ExpectedHead = ""
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

if ([string]::IsNullOrWhiteSpace($RepoRoot)) {
$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..")).Path
}

function Require-Command {
param([Parameter(Mandatory = $true)][string]$Name)
$resolved = Get-Command $Name -ErrorAction Stop
if (-not $resolved.Source) {
throw "Cannot resolve executable path for $Name"
}
return $resolved.Source
}

$repo = (Resolve-Path -LiteralPath $RepoRoot).Path
if ([string]::IsNullOrWhiteSpace($RemoteRoot)) {
$RemoteRoot = $repo
}
$root = (Resolve-Path -LiteralPath $RemoteRoot).Path
$probe = Join-Path $root $ProbeRelativePath
if (-not (Test-Path -LiteralPath $probe -PathType Leaf)) {
throw "ProbeRelativePath must identify an existing file inside RemoteRoot."
}

$pythonExe = Require-Command -Name $Python
$tunnelExe = Require-Command -Name $TunnelClient
$launcher = Join-Path $repo "scripts\windows\ContinuityOS-RemoteTunnel.ps1"
if (-not (Test-Path -LiteralPath $launcher -PathType Leaf)) {
throw "ContinuityOS Remote Tunnel launcher is missing."
}

Push-Location $repo
try {
$head = (git rev-parse HEAD).Trim()
$dirty = @(git status --porcelain)
if ($LASTEXITCODE -ne 0) {
throw "Unable to read Git baseline."
}
if ($dirty.Count -ne 0) {
throw "Runtime qualification requires a clean Git worktree."
}
if (-not [string]::IsNullOrWhiteSpace($ExpectedHead) -and $head -ne $ExpectedHead) {
throw "Git HEAD does not match ExpectedHead."
}

$plan = (
& $launcher -Mode Plan -RemoteRoot $root -TunnelClient $tunnelExe -Python $pythonExe |
Out-String
) | ConvertFrom-Json

if ($plan.schema -ne "continuityos.remote_tunnel_plan/v1") {
throw "Unexpected launcher plan schema."
}
if ($plan.mcp_transport -ne "stdio" -or
$plan.mcp_tool_profile -ne "chatgpt-pro-readonly" -or
$plan.public_mcp_listener -ne $false -or
$plan.health_listener_scope -ne "loopback" -or
$plan.direct_shell -ne $false) {
throw "Launcher plan violates the R3 safety contract."
}

$tunnelVersion = (& $tunnelExe --version 2>&1 | Select-Object -First 1).ToString().Trim()
$quickstart = (& $tunnelExe help quickstart 2>&1 | Out-String)
if ($LASTEXITCODE -ne 0 -or $quickstart -notmatch "sample_mcp_stdio_local") {
throw "tunnel-client quickstart does not advertise the local stdio sample."
}
$sample = (& $tunnelExe profiles samples show sample_mcp_stdio_local 2>&1 | Out-String)
if ($LASTEXITCODE -ne 0 -or $sample -notmatch "mcp.command|mcp-command") {
throw "tunnel-client local stdio sample contract is unavailable."
}

$requests = @(
@{jsonrpc="2.0"; id=1; method="initialize"; params=@{}},
@{jsonrpc="2.0"; id=2; method="tools/list"; params=@{}},
@{jsonrpc="2.0"; id=3; method="tools/call"; params=@{name="capability_status"; arguments=@{}}},
@{jsonrpc="2.0"; id=4; method="tools/call"; params=@{name="fs_read"; arguments=@{path=$ProbeRelativePath; max_bytes=2048}}},
@{jsonrpc="2.0"; id=5; method="tools/call"; params=@{name="remember"; arguments=@{text="must not write"}}}
)
$payload = (($requests | ForEach-Object { $_ | ConvertTo-Json -Compress -Depth 8 }) -join [Environment]::NewLine) + [Environment]::NewLine
$mcpArgs = @(
"-m", "continuityos.remote_mcp_server",
"--db", ":memory:",
"--enable-remote",
"--tool-profile", "chatgpt-pro-readonly",
"--remote-root", $root
)
$raw = $payload | & $pythonExe @mcpArgs
if ($LASTEXITCODE -ne 0) {
throw "Remote MCP stdio qualification failed."
}
$responses = @($raw | ForEach-Object { $_ | ConvertFrom-Json })
$toolsResponse = $responses | Where-Object { $_.id -eq 2 } | Select-Object -First 1
$statusResponse = $responses | Where-Object { $_.id -eq 3 } | Select-Object -First 1
$readResponse = $responses | Where-Object { $_.id -eq 4 } | Select-Object -First 1
$denyResponse = $responses | Where-Object { $_.id -eq 5 } | Select-Object -First 1

$tools = @($toolsResponse.result.tools | ForEach-Object { $_.name })
$expectedTools = @("capability_status", "system_info", "fs_list", "fs_read")
if (($tools -join ",") -ne ($expectedTools -join ",")) {
throw "Unexpected ChatGPT Pro tool surface."
}
$status = $statusResponse.result.content[0].text | ConvertFrom-Json
if ($status.mode -ne "read_only_host_surface" -or $status.mutating_execution.available -ne $false) {
throw "Capability status does not report a read-only host surface."
}
$readHasError = $readResponse.result.PSObject.Properties.Name -contains "isError"
if ($readHasError -and $readResponse.result.isError -eq $true) {
throw "Benign fs_read probe failed."
}
$hiddenWriteDenied = (
$denyResponse.result.isError -eq $true -and
$denyResponse.result.content[0].text -match "tool hidden by remote tool profile"
)
if (-not $hiddenWriteDenied) {
throw "Hidden write tool was not rejected."
}

[pscustomobject]@{
schema = "continuityos.remote_runtime_qualification/v1"
status = "LOCAL_READONLY_RUNTIME_GREEN"
git_head = $head
git_clean = $true
tunnel_client_version = $tunnelVersion
tunnel_client_stdio_sample = $true
mcp_transport = $plan.mcp_transport
mcp_tool_profile = $plan.mcp_tool_profile
advertised_tools = $tools
benign_read = "pass"
hidden_write_denied = $true
public_mcp_listener = $plan.public_mcp_listener
health_listener = $plan.health_listener
health_listener_scope = $plan.health_listener_scope
direct_shell = $plan.direct_shell
control_plane_key_present = -not [string]::IsNullOrWhiteSpace($env:CONTROL_PLANE_API_KEY)
tunnel_id_present = -not [string]::IsNullOrWhiteSpace($env:CONTROL_PLANE_TUNNEL_ID)
live_tunnel_qualified = $false
} | ConvertTo-Json -Depth 6
}
finally {
Pop-Location
}
54 changes: 54 additions & 0 deletions tests/test_remote_runtime_windows_script.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from __future__ import annotations

from pathlib import Path

import pytest


SCRIPT = (
Path(__file__).resolve().parents[1]
/ "scripts"
/ "windows"
/ "Test-ContinuityOS-RemoteRuntime.ps1"
)


def _source() -> str:
if not SCRIPT.is_file():
pytest.skip("source-tree-only Windows runtime harness is not shipped in the wheel")
return SCRIPT.read_text(encoding="utf-8")


def test_runtime_harness_requires_clean_git_baseline():
source = _source()
assert "git rev-parse HEAD" in source
assert "git status --porcelain" in source
assert "ExpectedHead" in source
assert "Runtime qualification requires a clean Git worktree." in source


def test_runtime_harness_proves_readonly_tool_boundary():
source = _source()
assert "--tool-profile" in source
assert "chatgpt-pro-readonly" in source
assert '@("capability_status", "system_info", "fs_list", "fs_read")' in source
assert 'name="remember"' in source
assert "tool hidden by remote tool profile" in source
assert "LOCAL_READONLY_RUNTIME_GREEN" in source


def test_runtime_harness_does_not_claim_live_tunnel():
source = _source()
assert "live_tunnel_qualified = $false" in source
assert "control_plane_key_present" in source
assert "tunnel_id_present" in source
assert "CONTROL_PLANE_API_KEY" in source
assert "CONTROL_PLANE_TUNNEL_ID" in source


def test_runtime_harness_keeps_public_surface_closed():
source = _source()
assert "public_mcp_listener" in source
assert "health_listener_scope" in source
assert '"loopback"' in source
assert "direct_shell" in source
Loading