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
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ OPENCODE_RESUME_E2E_VERSION := 1.18.18
help: ## Show available targets
@awk 'BEGIN {FS = ":.*##"} /^[a-zA-Z0-9_-]+:.*##/ {printf "%-14s %s\n", $$1, $$2}' $(MAKEFILE_LIST)

PYTHON_TARGETS := data-lifecycle-help validate build-agents build-agents-check build-agents-prune release-index-update docs-automation-summary-update docs-automation-check pages-readiness-check release-note-validation-check release-note-quality-check plan-hygiene-check wave-linkage-check wave-handoff-summary wave-completion-update quality-fast quality-strict quality-off quality-status tasker-production-live-smoke rolling-decomposition-live gateway-status gateway-enable gateway-disable gateway-doctor gateway-secret-redaction-smoke gateway-v2-dependency-probe gateway-v2-dependency-profile-probe gateway-v2-slice-smoke gateway-resume-redaction-e2e gateway-resume-redaction-e2e-prebuilt gateway-execution-status-live-smoke gateway-turn-watch gateway-turn-watch-webhook harness-wave2-task4-smoke notify-icons-generate notify-icons-select reservation-status task-lease-status selftest doctor doctor-json sqlite-doctor sqlite-doctor-json devtools-status hooks-install install-test install-test-full release-check release
PYTHON_TARGETS := data-lifecycle-help validate build-agents build-agents-check build-agents-prune release-index-update docs-automation-summary-update docs-automation-check pages-readiness-check release-note-validation-check release-note-quality-check plan-hygiene-check wave-linkage-check wave-handoff-summary wave-completion-update quality-fast quality-strict quality-off quality-status tasker-production-live-smoke rolling-decomposition-live gateway-status gateway-enable gateway-disable gateway-doctor gateway-secret-redaction-smoke gateway-v2-dependency-probe gateway-v2-dependency-profile-probe gateway-v2-auxiliary-redaction-probe gateway-v2-slice-smoke gateway-resume-redaction-e2e gateway-resume-redaction-e2e-prebuilt gateway-execution-status-live-smoke gateway-turn-watch gateway-turn-watch-webhook harness-wave2-task4-smoke notify-icons-generate notify-icons-select reservation-status task-lease-status selftest doctor doctor-json sqlite-doctor sqlite-doctor-json devtools-status hooks-install install-test install-test-full release-check release

$(PYTHON_TARGETS): python-check

Expand Down Expand Up @@ -113,6 +113,11 @@ gateway-v2-dependency-probe: python-check ## Measure native V2 shell boundaries
gateway-v2-dependency-profile-probe: ## Qualify isolated V2 profile boundaries without dependency authority
$(PYTHON) scripts/gateway_v2_dependency_profile_probe.py --opencode-bin "$(OPENCODE_BIN)"

.PHONY: gateway-v2-auxiliary-redaction-probe
gateway-v2-auxiliary-redaction-probe: python-check ## Measure four V2 request kinds without gateway authority
npm --prefix plugin/gateway-core run build
$(PYTHON) scripts/gateway_v2_auxiliary_redaction_probe.py --opencode-bin "$(OPENCODE_BIN)"

gateway-v2-slice-smoke: ## Test experimental V2 security adapters against localhost (not full gateway parity)
npm --prefix plugin/gateway-core run build
$(PYTHON) scripts/gateway_v2_context_live_smoke.py
Expand Down
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ This repo-local index exists because `AGENTS.md` and related startup docs refere
- `plan/opencode-reliability-review-runbook.md`: reusable reliability/E2E review campaign runbook
- `specs/e8-plan-handoff-continuity-mapping.md`: continuity and handoff semantics
- `specs/opencode-v2-owner-admission-proposal.md`: non-operational owner-bound execution requirements
- `specs/opencode-v2-auxiliary-redaction-probe.md`: bounded synthetic measurement of four V2 request kinds
- `specs/background-artifact-authority.md`: design-only no-clobber and provenance requirements for background state
- `plugin-gateway-plan.md`: gateway/plugin architecture and follow-up planning
- `readme-deep-notes.md`: deeper architecture and release-history notes
Expand Down
2 changes: 2 additions & 0 deletions docs/plan/doing/opencode-v2-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,6 @@ The legacy `/mcp` helper refuses an observed native or ambiguous `mcp.servers` l

The legacy `/plugin` helper similarly refuses an observed native or ambiguous `plugins` key, including during locked mutations. Its results describe only helper-resolved legacy configuration, not loaded plugins or active gateway hooks; it does not port V2 plugin management.

The [auxiliary redaction probe](../../specs/opencode-v2-auxiliary-redaction-probe.md) exercises native context, title, generate and compaction request hooks against an owned localhost provider, with unprotected controls and separate system/message canaries. It measures those synthetic requests only; it does not verify compaction completion, other transports, later-hook ordering or gateway protection.

Reference: <https://opencode.ai/v2/docs/migrate-v1> and <https://opencode.ai/v2/docs/build/plugins/migrate-v1>.
75 changes: 75 additions & 0 deletions docs/specs/opencode-v2-auxiliary-redaction-probe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# V2 auxiliary request redaction probe

Status: **synthetic measurement only**. This probe does not install or configure
the gateway, establish a security boundary, or grant authority. The V2 gateway
and dependency profile remain **unqualified**.

## Run

With Python 3.11+, an existing gateway build environment, and OpenCode 2.2.5:

```sh
make gateway-v2-auxiliary-redaction-probe OPENCODE_BIN=/path/to/opencode
```

The target builds `plugin/gateway-core` and runs the probe. It does not install
dependencies. To select a private fixture parent, invoke the script directly
after the build with `--temp-parent <directory>`. A disposable home is not an OS
sandbox; choose an isolated environment when preserving local data is critical.

## What it measures

Two separate private authenticated runtimes use an owned local plugin and a
synthetic OpenAI-compatible provider listening on loopback. Each case uses
different random provider and trace credentials. The control does not register the
redactor; the protected case registers only the existing experimental context
redactor. For each native `context`, `title`, `generate`, and `compaction` hook,
the fixture introduces a synthetic system canary and supplies a separate
synthetic message canary. It checks the hook inputs and outputs, then independently
checks the provider's received request for both canaries and positive markers.

The control must deliver both canaries for every kind. The protected case must
remove both and retain redaction and positive markers for every observed request.
Unknown, duplicated hook, missing, malformed, or ambiguous evidence is a failure.
More than one provider request per hook is allowed; each is checked.
The report contains counts, finite reason codes, fixture basenames, and the
selected executable's SHA-256, not request bodies, session IDs, or canary values.

The probe awaits location activation and confirms its local plugin before creating
a synthetic session. It distinguishes admitting compaction from observing a
compaction request: receipt of that request does **not** establish that compaction
completed. It uses fresh HOME/XDG/DB paths, an environment allowlist, a private
server password, PID checks before API mutations, bounded output/requests/time,
package-manager stubs that exit without writing, and owned-process teardown. The
stubs only cover the listed commands found through the child `PATH`; they do not
detect every attempted installation or replace network isolation. System or
ancestor OpenCode configuration causes preflight refusal. All fixture roots,
including version probes, are retained under the selected temporary parent;
the probe's unit tests also retain their temporary fixture roots. Teardown reports
whether owned processes and sockets settled. Retained fixtures contain synthetic
prompts and may contain local runtime metadata; inspect them before sharing or
cleaning them up. The selected executable is version-checked
and its identity is compared before and after; that does not prevent a transient
swap. Hook witnesses travel over an authenticated localhost channel, not a trace
file; its key is present in the retained synthetic plugin, and the provider key
is present in its retained configuration. Fixture paths, channel authentication,
and metadata checks do not establish protection against a hostile process with
the same user identity.

## Observed result and limits

On 2026-11-06, one local executable reporting `opencode v2.2.5` produced one
context, one title, one generate, and two compaction provider requests in each
case. Its SHA-256 was
`abe4d88594bffb12b364375b8a6732d2d1f7a977195ed1a35c5c76f8e89c9e0e`.
Both canaries reached the control provider and were absent from every protected
observation. These results describe that executable and synthetic run, not every
binary reporting the same version or other versions.

The probe does not test a later hook changing content after redaction, transport
hook ordering, WebSocket, streaming semantics, other providers or encodings,
images, large or resumed histories, or the complete secret detector. It does not
prove event completeness or production isolation. The separate
[owner-bound admission proposal](opencode-v2-owner-admission-proposal.md) and
[dependency-profile measurement](opencode-v2-dependency-profile.md) retain their
unresolved activation gates.
45 changes: 45 additions & 0 deletions scripts/config_writer_sink_manifest.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,49 @@
[
{
"language": "python",
"file": "gateway_v2_auxiliary_redaction_probe.py",
"function": "prepare_fixture",
"kind": "path.mkdir",
"destination": "root / name",
"count": 1,
"classification": "isolated_fixture_exemption"
},
{
"language": "python",
"file": "gateway_v2_auxiliary_redaction_probe.py",
"function": "write_fixture",
"kind": "os.mkdir",
"destination": "part",
"count": 1,
"classification": "isolated_fixture_exemption"
},
{
"language": "python",
"file": "gateway_v2_auxiliary_redaction_probe.py",
"function": "write_fixture",
"kind": "os.open",
"destination": "part",
"count": 1,
"classification": "isolated_fixture_exemption"
},
{
"language": "python",
"file": "gateway_v2_auxiliary_redaction_probe.py",
"function": "write_fixture",
"kind": "os.open",
"destination": "path.parts[-1]",
"count": 1,
"classification": "isolated_fixture_exemption"
},
{
"language": "python",
"file": "gateway_v2_auxiliary_redaction_probe.py",
"function": "write_fixture",
"kind": "os.open",
"destination": "root",
"count": 1,
"classification": "isolated_fixture_exemption"
},
{
"language": "python",
"file": "gateway_v2_dependency_profile_probe.py",
Expand Down
Loading
Loading