Skip to content

fix(browser): resolve clipboard imports safely in bytecode builds - #1887

Open
damianvtran wants to merge 4 commits into
mainfrom
fix/secure-copy-bytecode
Open

damianvtran wants to merge 4 commits into
mainfrom
fix/secure-copy-bytecode

Conversation

@damianvtran

@damianvtran damianvtran commented Nov 12, 2026 •

Copy link
Copy Markdown
Owner

Summary

Fix the packaged desktop browser's secure copy action and page-initiated clipboard writes failing at the Electron import boundary. Keep Electron resolution lazy for node-only consumers, but use CommonJS require("electron") instead of dynamic import() in both clipboard callbacks. No permission, gesture, receipt, version or UI layout changes.

Root cause

The installed desktop app (0.54.3, manager verified) rejects browser action=copy with A dynamic import callback was not specified. Both callbacks used dynamic Electron imports; the packaged bytecode VM has no dynamic-import callback. Existing tests alias/integrate Electron into an ESM bundle and therefore missed the external import boundary. New tests externalize Electron, rehydrate V8 cached data and run the emitted CommonJS wrapper without that callback, preserving lazy-load and gesture-denial controls.

Evidence

All live reproduction used a new owned desktop browser tab (ui:22) and a disposable loopback fixture, with a randomly generated value in a password field. No production sites, production credentials, copied bytes in tool output, or existing tabs were used.

Surface Command/action Actual result
Installed secure copy, before browser action=copy selector=#disposable FAIL: A dynamic import callback was not specified
Installed page Copy, before Click #copy, then snapshot FAIL: NotAllowedError: the host did not allow the clipboard write
Baseline negative control Temporarily restore the two source files from base b0edf02e5d37db5c5527cf66465131a4019fed10; run node scripts/run-desktop-tests.mjs --test-name-pattern='cached-data loader' scripts/browser-clipboard-copy.test.mjs; restore patched bytes in finally Both new tests FAIL: secure copy raises ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING; armed page write acks false
Patched targeted suite node scripts/run-desktop-tests.mjs scripts/browser-clipboard-copy.test.mjs PASS: 29 tests, 0 failures; includes externalized cached-data secure copy, armed page write and unarmed refusal
Scoped static check biome check src/main/browser/actions/page.ts src/main/browser/actions/clipboard-shim.ts scripts/browser-clipboard-copy.test.mjs PASS; five pre-existing top-level-regex warnings in existing tests
Whitespace git diff --check PASS
Actual packaged post-fix browser/OS clipboard and isolated encrypted-store authentication roundtrip Not dispatched BLOCKED by active disk-recovery/build hold. Node V8 cached-data contract tests are NOT native Electron proof.

Resource/isolation limits

No dependency installs, clones or full builds. Primary stale detached checkout and its untracked work remain untouched. Worktree uses a source/tests-only sparse checkout after a normal checkout failed ENOSPC; dependencies are shared from an existing worktree with a byte-identical lockfile. Disk headroom is volatile and the disk recovery owner has not cleared packaged evidence.

Push used the documented PREPUSH_BYPASS with the explicit disk-hold/sparse-checkout reason after scoped tests and Biome; whole type/build legs were NOT run locally. CI and independent code/QA rounds remain outstanding. Do not merge or release yet.

Provenance

Implementation started on anthropic/claude-opus-5-5; provider quota triggered the harness fallback to openai/gpt-6.1-sol, which implemented and tested this patch. No role/model configuration was changed.

Targeted test evidence — native artifact plumbing

Artifact-only delta: 0190c4a81e74508e53cff18f5d85bd560a4aa068..1e5ca178525c00b8250fdcfadf0be983805ed595. The two clipboard fixes/tests are unchanged by this delta; the manager reports their round-1 code review clean. This CI support change still needs independent delta review. No merge/release authorization and no native success claim.

Compatibility and cost

The previous Bytecode Build Check ran Ubuntu x64, which cannot supply the darwin arm64 bytecode needed by the pinned Electron 45.1.0 native host. The repository's electron.vite.config.js documents exact Electron/V8 identity; scripts/mac-build-arch.test.mjs documents host-architecture bytecode incompatibility. The same existing job now has Ubuntu + macos-15 legs, with fail-fast disabled so the new leg cannot cancel the old gate. GitHub's hosted-runner reference identifies macos-15 as arm64. This adds one hosted macOS install/build per selected CI run; no fourth local build, dependency install, clone, packaging or signing was performed. Linux keeps its merge-ref integration gate; Mac checks out the immutable source head directly.

Artifact contract and security boundary

  • Workflow .github/workflows/ci.yml, job bytecode-build, macOS leg only, after its existing pnpm build and .jsc assertion.
  • Name: ui-native-bytecode-darwin-arm64-<sourceHead>-<runId>-<attempt>, retention 1 day.
  • Upload root ${{ runner.temp }}/ui-native-bytecode/: all ordinary out/ files (main bytecode + loader, all preloads, renderer HTML/assets including browser-approvals-overlay.html), public package.json, manifest.json.
  • Manifest schema 1: exact sourceHead == checkout, run/workflow/repository identity, actual Electron/Node/V8 versions, darwin/arm64, V8 cached-data tag, per-file relative path/size/SHA256. Missing expected compiled surfaces, source-head mismatch, symlinks and .env* in output fail closed.
  • No node_modules, native libraries, backend seed, source checkout, environment files, credentials or profiles. OAuth bindings are CI dummy placeholders; shipped public metadata/config defaults are not personal secrets.
  • Compile-time renderer API binding is http://127.0.0.1:9, NOT live port 1111 or a customer remote. Backend manager is disabled (true); Radient and PostHog hosts also bind to that inert loopback address. Manifest records these bindings. Runtime env cannot rewrite the compiled renderer URL. A consumer needs its own compatible fixture or must treat API-dependent states as unavailable; main also requires the recorded runtime API/disable-manager bindings, isolated HOME/config and a disposable profile. Backend discovery safety must still be checked by consumer QA; this artifact is not a sandbox or standalone app.
  • Consumer must separately supply compatible dependencies and the exact pinned Electron runtime, verify every manifest hash/head tuple, then execute native tests. A matching manifest or a green CI build is not proof that secure copy/native card composition works. No artifact was fetched or app launched in this delta.
Surface Command Actual output/result
Workflow staging positive and negative controls node --test scripts/native-bytecode-artifact.test.mjs PASS: 6 tests, 0 failures. Executes the actual inline staging code with synthetic outputs; verifies all hashes/head/runtime metadata and refuses missing approvals HTML, wrong head, symlink escape, output .env. No Electron launched.
Existing targeted workflow contracts `node --test --test-name-pattern='^A1: ^A2:
Build environment contract node scripts/check-build-env.mjs PASS: 13 build steps carry all 4 required variables. No build performed.
Targeted lint / whitespace biome check --write scripts/native-bytecode-artifact.test.mjs; git diff --check PASS, no final warnings; whitespace clean.
Real push gate (supersedes the earlier push-bypass note for this head) git push origin HEAD:fix/secure-copy-bytecode PASS, no bypass: scripts lint, changed source lint, serial tsconfig.node.json + tsconfig.app.json typechecks. Type leg reported 38.1 s. No native build.
New artifact / native test CI run 43318034632 PENDING at readback; head 1e5ca178525c00b8250fdcfadf0be983805ed595. Artifact not yet produced/consumed. Per manager, native setup/build exhausted 3 attempts; artifact is supporting evidence, not a substitute native test.

Implementation model: started anthropic/claude-opus-5-5; provider quota switched this child to openai/gpt-6.1-sol before implementation. No role/model pins or tool configuration changed.

Targeted test evidence — round 2 remediation

Agent review remediation — round 2

Implementer: coder / openai/gpt-6.1-sol (provider-quota fallback disclosed previously; no model/tool configuration changes).
Scope: 1e5ca178525c00b8250fdcfadf0be983805ed595..47a3d421faa0822a8f6d035dc521f1275dbbaeae.

  • R2-1 — fixed in 47a3d421faa0822a8f6d035dc521f1275dbbaeae. Added scripts/native-bytecode-artifact.test.mjs to the existing JOB_COMMANDS["check-types"] release-contract command in scripts/ci-scope.mjs, matching the CI workflow command exactly. The parity assertion is unchanged. One-line mapping change only; no workflow/product/version change in this remediation.
  • Reproduced before editing: node --test --test-name-pattern="^A11: every job's local commands" scripts/ci-scope.test.mjs → tests 1, pass 0, fail 1, with CI runs a longer list than the local gate naming the omitted native artifact test.
  • Same exact command after editing → tests 1, pass 1, fail 0.
  • node --test scripts/native-bytecode-artifact.test.mjs → tests 6, pass 6, fail 0. Actual inline staging code re-executed on synthetic fixtures; no Electron/native build/download.
  • biome check scripts/ci-scope.mjs → Checked 1 file; no fixes applied; git diff --check passed.
  • Real push hook passed without bypass: scoped scripts/source lint and both serial typechecks (types leg reported 31.9 s).

Current head: 47a3d421faa0822a8f6d035dc521f1275dbbaeae.
Next CI run 43319106365 was pending at metadata readback. Prior run 43318034632 is cancelled/superseded, not passing evidence. Native artifact name for this run is ui-native-bytecode-darwin-arm64-47a3d421faa0822a8f6d035dc521f1275dbbaeae-43319106365-<attempt>; the unchanged manifest mechanism requires sourceHead == checkout == this new head. Artifact generation/consumption and native secure-copy proof remain pending, not inferred from these tests. No merge or release.

Targeted test evidence — required macOS CI heap repair

CI-only delta: 47a3d421faa0822a8f6d035dc521f1275dbbaeae..7d4a31c55c435466e61780cee14da33699d41a8d. No product bytes, version, bytecode configuration, build count or Linux heap policy changed.

Re-read the actual failed macOS CI job and sanitized job logs using gh api .../actions/jobs/131554409741/logs --allow-escape-sequences: 8422 renderer modules transformed, Mark-Compact at 1995.7 MB, FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory, exit 134. Bytecode assertion/runtime/staging/upload steps were skipped; no artifact or native-success claim.

The Mac build step now gets --max-old-space-size=4096, matching the existing publish/candidate budget. GitHub runner specifications list macos-15 as arm64, 3 M1 CPUs, 7 GB RAM. 4096 MiB old-space leaves nominal roughly 3 GB for OS/non-heap allocations (not a total-process memory guarantee). The environment is restricted to the single build step: neither later Electron runtime probes nor shipped app inherit it; Linux receives no Node heap flag.

Scoped check Actual result
node --test scripts/native-bytecode-artifact.test.mjs PASS: 7/7 (existing six artifact contracts plus actual workflow heap budget/scope assertion)
node --test --test-name-pattern='A11' scripts/ci-scope.test.mjs PASS: 2/2, including command parity and wiring mutants
node node_modules/@biomejs/biome/bin/biome check scripts/native-bytecode-artifact.test.mjs PASS: 1 file, no fixes
git diff --check PASS
New hosted Mac build/artifact PENDING; push dispatched CI, not yet validated

pnpm exec biome ... failed before running Biome due to ERR_PNPM_LOCKFILE_CONFIG_MISMATCH; no install/lockfile changes were made. Used the existing repository Biome binary directly for the passing scoped check. Push used disclosed PREPUSH_BYPASS under the existing resource/local-build hold; local typecheck/build were not run. No fourth local build, dependency install, extra hosted build step, app launch, credentials, reviewer request or release action. Independent delta review and required CI remain pending.

Implementation model: openai/gpt-6.1-sol after automatic provider-quota fallback from anthropic/claude-opus-5-5; no role/model settings changed.

@damianvtran damianvtran self-assigned this Nov 12, 2026
@damianvtran

Copy link
Copy Markdown
Owner Author

Agent review — round 1

Reviewer: independent reviewer agent — openai/gpt-6.1-sol (temporary fallback after anthropic/claude-opus-5-5 provider quota failure; initial diff/guidance reads preceded the switch)
Scope: b0edf02..0190c4a

Intent reviewed: minimal packaged-VM Electron resolution fix for secure action copy and page-button writes; preserve node-only imports and existing permission/gesture/privacy controls. No install, native build, full suite, or unrelated browser changes.

Findings: no BLOCKER, MAJOR, MINOR, or NIT findings. Verdict: clean (terminal code-review round).

Evidence derived independently at the pushed head in the manager-owned read-only worktree:

  • Inspected all three changed files and direct clipboard call neighbors. Both Electron resolutions remain inside their callbacks, using synchronous require with an erased TypeScript type assertion. Existing awaited write/read behavior, authorization/activation checks, size limits, acknowledgement behavior, and payload-free success logs are unchanged; the diff adds no payload logging.
  • Verified production semantics against this checkout's electron.vite.config.js:25,38,58-63, package metadata (no type: module; main ./out/main/index.js), and installed electron-vite 3.1.0 implementation: dist/chunks/lib-D9_OPmIh.cjs:267-307 defaults this main bundle to CommonJS and externalizes Electron; dist/index.cjs:128-156 constructs vm.Script without a dynamic-import callback and explicitly passes a module-backed require into the compiled wrapper. Thus the substitution matches the actual loader contract, not merely an assumption about esbuild output.
  • Ran node --test scripts/browser-clipboard-copy.test.mjs with isolated scratch HOME/config and inherited CMUX_* removed: 29 tests, 29 pass, 0 fail, duration_ms 6244.382375, exit 0. Both new cached-data cases passed; they execute the production callbacks with Electron external, assert cached-data acceptance and lazy resolution, verify a receipt without copied bytes, and exercise refused-unarmed versus successful-armed page writes.
  • Independently ran the same changed test body with an in-memory esbuild onLoad overlay reading only page.ts and clipboard-shim.ts from the base SHA via git show; worktree files were not modified. Actual output: 29 tests, 27 pass, 2 fail, exit 1. The only failures were cached-data loader without a dynamic-import callback supports secure copy and cached-data loader admits armed page writes and still refuses unarmed writes; secure copy reported ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING: A dynamic import callback was not specified. This proves the added regression discriminates the original implementation from the fix, beyond its standalone legacy-import negative control.
  • Rechecked HEAD and clean git status --short after execution. No app/server/browser was launched; synthetic fixtures only, no actual clipboard access or transcript/log payload inspection.

Evidence boundary: this is Node/V8 cached-data loader-contract proof with an Electron stub, not rebuilt/installed Electron or OS clipboard proof. Native post-fix proof remains BLOCKED by the disk-owner build hold, as briefed; no claim that the installed application has been repaired or native-validated. That separate QA/release decision is not supplied by this clean code review.

@damianvtran

Copy link
Copy Markdown
Owner Author

QA report — round 1

QA: independent qa-tester · Model: anthropic/claude-opus-5-5 (current served model; the earlier preflight report's openai/gpt-6.1-sol fallback attribution was not supported by this session's model context and is corrected here).

Head: 0190c4a81e74508e53cff18f5d85bd560a4aa068
Scope: b0edf02e5d37db5c5527cf66465131a4019fed10..0190c4a81e74508e53cff18f5d85bd560a4aa068
Worktree: ~/local-operator-ui/.worktrees/secure-copy-regression

Verdict: BLOCKED — no native PASS claim. Evidence attempt 1 stopped at build prerequisite; no app launched.

Intent: validate both lazy Electron clipboard callbacks in production V8 bytecode through the real desktop host, with only disposable synthetic data. Non-goals: full installer validation, production app/credentials, dependency installation/downloads, broad suites.

Executed matrix

Surface Command/check Actual output Result
Head / clean tree git rev-parse HEAD; git status --porcelain before and after Expected full head; empty status both times PASS
Conditional disk admission df -k immediately before dispatch 9,414,656 KiB = 8.979 GiB free, above 5 GiB PASS
Build isolation Explicit scratch HOME/config/log/TMPDIR; stripped CMUX_/LOP_ and XPC_FLAGS; NO_BYTECODE unset Isolated paths under session scratch; existing shared dependencies only PASS for invocation configuration
Production-bytecode build run_bounded.py --timeout 600 -- /bin/zsh -c 'unset LOCAL_OPERATOR_UI_NO_BYTECODE; pnpm build' Corepack/pnpm bootstrap downloaded pnpm 12.6.0, then ERR_PNPM_LOCKFILE_CONFIG_MISMATCH: current overrides do not match lockfile. Exit 1, 11.3 s. BLOCKED
No-download prerequisite Same invocation Unexpected package-manager auto-bootstrap download occurred before compile, contrary to the authorized no-download constraint FAIL — QA setup incident, not a product defect
Compiled identity Inspect worktree out out absent; no .jsc generated BLOCKED
Real-host agent copy → OS clipboard → isolated encrypted store → local 401/200/wrong-401 Not dispatched after build failure No host, copy, secret or HTTP auth operation executed BLOCKED
Real-host page-owned Copy → same store/auth path Not dispatched No browser tab opened BLOCKED
Clipboard read/no-gesture denial Not dispatched No native evidence BLOCKED
Packaged baseline-negative control Not dispatched No baseline-negative proof BLOCKED
Tool/host copied-byte non-disclosure Not dispatched No payload generated or copied; zero-occurrence validation not claimed BLOCKED
Screenshots Not dispatched No rendered evidence BLOCKED
Process cleanup Exact owned group TERM/KILL cleanup + leader existence check Build exit 1; group_leader_reaped=True; no app process started PASS

Disk / artifact receipts

The bounded wrapper measured 9,585,889,280 bytes free before build setup and 9,489,711,104 after cleanup: a filesystem delta of 96,178,176 bytes (~91.7 MiB). This is filesystem drift, not a precise attribution of all concurrent writes. The isolated scratch tree later measured 47,984,640 allocated bytes. Final df -k recheck: 8,198,432 KiB (~7.819 GiB) free; later drift was after the build exited. No output directory was produced. The wrapper monitored <2 GiB free / >1 GiB free-space consumption while running and neither stop condition triggered.

Only tracked sparse build inputs were materialized: renderer, preload, bin, build, and top-level resource PNGs. No source edits, lockfile edits, dependency-tree replacement or app launch occurred. Build log and summary retained in session scratch at native-round1/build.log and native-round1/build-summary.json.

Q1 — blocked build prerequisite / setup incident

The isolated HOME caused the bare pnpm build entrypoint to bootstrap a package manager rather than immediately use an established local binary. Its attempted frozen setup then rejected the existing lockfile's overrides. Repro is the exact command above in the described isolated environment. This is not proof that the callback change fails.

Bounded repair requiring a new authorized attempt: identify an already present package-manager/build executable compatible with the lockfile and invoke it explicitly without bootstrap/install; validate that prerequisite before dispatch. Do not run the error's suggested pnpm install --no-frozen-lockfile. No alternate mechanism or retry was attempted here.

This report covers existing-runtime production-bytecode validation intent only; full electron-builder/installer validation and the currently installed app remain untested. No production/KOHO/Minerva tab or credential was accessed. No human reviewers requested or tagged.

@damianvtran

Copy link
Copy Markdown
Owner Author

Agent review — round 2

Reviewer: independent reviewer agent, openai/gpt-6.1-sol (actual fallback after anthropic/claude-opus-5-5 quota/provider failure).
Scope: 0190c4a..1e5ca17

Reviewed the complete workflow/artifact-test delta only, against the brief's authorized exact-head hosted macOS arm64 production-bytecode artifact. Unchanged secure-copy callbacks retain the prior round; no native build, app launch, install, artifact download, or real credentials were used.

R2-1 — MAJOR — .github/workflows/ci.yml:489 / scripts/ci-scope.mjs:645: the appended artifact test breaks the existing mandatory command-parity contract. CI now appends scripts/native-bytecode-artifact.test.mjs, but JOB_COMMANDS["check-types"] still ends its corresponding command at scripts/ci-scope.test.mjs. Executing A11: every job's local commands exist and match the workflow's own steps fails with: CI runs a longer list than the local gate, so the local gate is green about a subset of what gates the merge. This same test runs in the modified CI command, so the check-types job fails deterministically, independent of the pending hosted build. A read-only control using the real parsed workflow and real JOB_COMMANDS passes on 0190c4a and fails on 1e5ca17. Fix: append the new test to the corresponding JOB_COMMANDS command too; rerun A11 plus the artifact tests. Do not weaken the parity assertion.

Evidence executed on the briefed clean worktree with isolated HOME/config and an allowlisted environment:

  • node --test scripts/native-bytecode-artifact.test.mjs: 6/6 PASS. Executes the workflow's actual inline staging code: hashes/sizes and metadata on inert output; missing approvals, head mismatch, symlink escape, and output .env.local are refused.
  • node --test --test-name-pattern='^(A11:|A11 wiring mutants:|A25:|A18: CI Gate)' scripts/ci-scope.test.mjs: 3 PASS, 1 FAIL (A11 above).
  • node --test --test-name-pattern='^A12:' scripts/ci-scope.test.mjs: 1/1 PASS. Total targeted workflow contracts: 4 PASS, 1 FAIL.
  • git diff --check 0190c4a81e74..1e5ca178525c: PASS; worktree remains clean.

Other reviewed paths: macOS checkout binds the immutable PR head and staging compares it to actual git HEAD; Ubuntu retains github.sha integration checkout, pnpm build and the .jsc assertion; fail-fast is false and CI Gate still depends on the whole matrix. GitHub's current runner reference explicitly maps macos-15 to arm64, additionally enforced by the runtime step. Electron is checked against the exact package pin and the manifest records Electron/V8/runtime cached-data identity. Inventory covers all of out plus package metadata, hashes every ordinary file, and rejects descendant symlinks/environment filenames; upload is limited to the staged directory with one-day retention. Backend-manager-disabled/loopback port-9 compile bindings are recorded with required runtime bindings; no new raw user-input shell interpolation, repository-secret access, dependency upload, or live-backend binding was introduced in this delta. The artifact is explicitly not self-contained or native behavioral proof.

CI run 43318034632 was read once: pending, no jobs yet, headSha 1e5ca17. This is not a CI-success claim. Native import/secure-copy behavior remains unproved by this review and by the artifact contracts.

Verdict: not clean — one MAJOR (R2-1), no additional findings.

@damianvtran

Copy link
Copy Markdown
Owner Author

Agent review remediation — round 2

Implementer: coder / openai/gpt-6.1-sol (provider-quota fallback disclosed previously; no model/tool configuration changes).
Scope: 1e5ca178525c00b8250fdcfadf0be983805ed595..47a3d421faa0822a8f6d035dc521f1275dbbaeae.

  • R2-1 — fixed in 47a3d421faa0822a8f6d035dc521f1275dbbaeae. Added scripts/native-bytecode-artifact.test.mjs to the existing JOB_COMMANDS["check-types"] release-contract command in scripts/ci-scope.mjs, matching the CI workflow command exactly. The parity assertion is unchanged. One-line mapping change only; no workflow/product/version change in this remediation.
  • Reproduced before editing: node --test --test-name-pattern="^A11: every job's local commands" scripts/ci-scope.test.mjs → tests 1, pass 0, fail 1, with CI runs a longer list than the local gate naming the omitted native artifact test.
  • Same exact command after editing → tests 1, pass 1, fail 0.
  • node --test scripts/native-bytecode-artifact.test.mjs → tests 6, pass 6, fail 0. Actual inline staging code re-executed on synthetic fixtures; no Electron/native build/download.
  • biome check scripts/ci-scope.mjs → Checked 1 file; no fixes applied; git diff --check passed.
  • Real push hook passed without bypass: scoped scripts/source lint and both serial typechecks (types leg reported 31.9 s).

Current head: 47a3d421faa0822a8f6d035dc521f1275dbbaeae.
Next CI run 43319106365 was pending at metadata readback. Prior run 43318034632 is cancelled/superseded, not passing evidence. Native artifact name for this run is ui-native-bytecode-darwin-arm64-47a3d421faa0822a8f6d035dc521f1275dbbaeae-43319106365-<attempt>; the unchanged manifest mechanism requires sourceHead == checkout == this new head. Artifact generation/consumption and native secure-copy proof remain pending, not inferred from these tests. No merge or release.

@damianvtran

Copy link
Copy Markdown
Owner Author

Agent review — round 3

Reviewer: independent reviewer agent, anthropic/claude-opus-5-5 (actual model this round; no fallback used this round).
Scope: 1e5ca17..47a3d42

Retest: R2-1 only, plus the directly associated artifact contracts. This round is justified by the named open MAJOR from round 2. Reviewed the complete delta: exactly one command-mapping line in scripts/ci-scope.mjs:645, appending scripts/native-bytecode-artifact.test.mjs to the matching local command. No workflow or product implementation bytes changed.

R2-1 resolved. The existing A11 assertion is byte-identical and now passes without weakening it. A separate exact-string comparison between the actual parsed workflow's release-contract command and JOB_COMMANDS["check-types"] also passes.

Executed on the clean manager-owned worktree at the pushed head, with isolated HOME/config and an allowlisted environment:

node --test --test-name-pattern="^(A11:|native artifact |staging )" scripts/ci-scope.test.mjs scripts/native-bytecode-artifact.test.mjs

Actual result: 7 tests, 7 pass, 0 fail — A11 plus all six artifact contracts, including execution of the unchanged workflow's actual inline staging code and its negative cases. git diff --check 1e5ca178525c..47a3d421faa0 also passes; worktree remains clean.

Retention proof: git diff --quiet 1e5ca178525c..47a3d421faa0 -- .github/workflows/ci.yml scripts/ci-scope.test.mjs scripts/native-bytecode-artifact.test.mjs returns 0. The full delta contains only the mapping line, so round-2 security/provenance/artifact-compatibility analysis is retained on byte-identical surfaces; unchanged callbacks were not re-audited.

CI run 43319106365 read once: pending, headSha 47a3d42. No CI-success claim. No build, install, download, app launch, or real credentials used. Consumer QA remains blocked on artifact availability per the brief; this review provides no native import/secure-copy behavioral proof and does not lift that QA limitation.

Verdict: clean — no BLOCKER or MAJOR remains in this delta. Terminal code-review round.

@damianvtran

Copy link
Copy Markdown
Owner Author

CI remediation — required macOS build OOM

Implementer: coder agent, openai/gpt-6.1-sol (automatic quota fallback).
Scope: 47a3d42..7d4a31c

Fixed in 7d4a31c: required Mac job failure, verified from actual logs as renderer heap exhaustion at ~1995 MB, exit 134. Set a 4096 MiB old-space budget only on the Mac CI build step, matching publish/candidate and leaving nominal OS/native headroom on GitHub's documented 7 GB arm64 runner. Linux unchanged; Electron identity probe and shipped runtime do not inherit NODE_OPTIONS. Added a regression assertion against parsed workflow budget and step-only scope; bytecode remains enabled and build count remains one per leg.

Executed: artifact contracts 7/7; A11 command parity/wiring mutants 2/2; direct existing Biome binary passes; whitespace clean. pnpm exec biome could not run due to lockfile configuration mismatch, so used existing Biome directly without installing/changing dependencies. Detailed commands and actual results are in the PR's appended Targeted test evidence section. Documented PREPUSH_BYPASS used under existing resource/local-build hold; no typecheck or fourth local build.

Pending: independent CI-only delta review and hosted CI/artifact result. Existing clean product/artifact reviews are retained for unchanged bytes; this comment does not claim independent approval, native success, or lift the manager's merge/release hold.

@damianvtran

Copy link
Copy Markdown
Owner Author

Agent review — round 4

Reviewer: independent reviewer agent, anthropic/claude-opus-5-5 (actual model; no fallback this round).
Scope: 47a3d42..7d4a31c

Retest: required-CI heap failure only. Reviewed the entire two-file delta: macOS build-step-only heap configuration and its focused regression test. This post-clean round is justified by the failed required macOS build, not a new product finding or expanded review scope.

Failure independently verified: job 131554409741 is Bytecode Build Check (macos-15), conclusion failure, failing step Build main with V8 bytecode. Read the completed job's actual logs through the jobs/logs API (the run-level CLI log reader refused while the overall run remained in progress): 8422 modules transformed; final GC 1995.7 (2095.3) -> 1983.7 (2099.5) MB; FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory; exit code 134. The heap-cap explanation is supported by the failure, not inferred from a generic red status.

The remediation raises old-space to 4096 MiB only for the macos-15 build step. This matches .github/workflows/publish.yml:43. GitHub's runner reference specifies 7 GB RAM, arm64 for macos-15. That is nominal runner headroom, not proof of peak RSS or a total-process-memory cap; successful execution still requires the pending hosted build. The expression leaves Linux with empty NODE_OPTIONS/default behavior, and the new flag is absent from workflow/job scope and every other step, including the Electron runtime identity probe. pnpm build, production bytecode assertions, matrix/gates, checkout provenance, runtime probe and staging logic remain unchanged. No product implementation bytes changed.

Executed with isolated HOME/config and an allowlisted environment on the clean manager-owned worktree at the pushed head:

node --test --test-name-pattern='^(A11:|A11 wiring mutants:|Mac CI build |native artifact |staging )' scripts/ci-scope.test.mjs scripts/native-bytecode-artifact.test.mjs

Actual result: 9 tests, 9 pass, 0 fail — seven artifact/workflow tests (including actual inline staging execution and new flag-scope assertion), plus both A11 parity contracts. git diff --check 47a3d421faa0..7d4a31c55c43 passes; worktree remains clean. Diff inspection and a zero-exit comparison of src, electron.vite.config.js, scripts/ci-scope.mjs, and scripts/ci-scope.test.mjs establish byte compatibility; prior clean callback/artifact security review is retained without re-auditing unchanged code. Earlier push bypass is disclosed by the brief; this review independently executes only the leased targeted tests and does not substitute for CI.

CI run 43333806500 read once: pending, headSha 7d4a31c. No local build, dependency install, artifact download or app launch. No claim that the new budget has yet produced an artifact or resolved the hosted build. Consumer QA/native import and secure-copy proof remain outstanding; no QA hold is lifted here.

Verdict: clean — no BLOCKER or MAJOR in this delta. Terminal code-review round; required CI and native evidence remain separate gates.

@damianvtran

Copy link
Copy Markdown
Owner Author

QA report — round 2

QA: independent qa-tester · Actual served model: anthropic/claude-opus-5-5.

Head: 7d4a31c55c435466e61780cee14da33699d41a8d
Scope: CI-built production-bytecode host validation; retained callback source from 0190c4a81e74508e53cff18f5d85bd560a4aa068 is byte-identical on this head (verified with git diff of both callback files).
Worktree: ~/local-operator-ui/.worktrees/secure-copy-regression, clean before/after.

Verdict: BLOCKED at required dependency prerequisite. No artifact download, runtime probe or app launch.

Requested artifact (from manager's authorization, not independently downloaded/audited here): ui-native-bytecode-darwin-arm64-7d4a31c55c435466e61780cee14da33699d41a8d-43333806500-1, digest sha256:2c24eb4a9bf0fbb346fb43789142dbc02e84d60fa7aa9dbae663d8cf3b19d857, 14,567,219 bytes, job 131621450972. No artifact provenance/content PASS claimed.

Surface Executed command/check ACTUAL output Result
Head/clean tree git rev-parse HEAD; git status --porcelain before and after Exact reviewed head above; status empty PASS
Callback compatibility git diff 0190c4a81e74..7d4a31c55c43 -- src/main/browser/actions/page.ts src/main/browser/actions/clipboard-shim.ts Empty diff PASS; prior source/loader-contract evidence retained, not rerun
Disk admission df -k Before: 18,483,504 KiB free; after: 18,468,952 KiB free; >=5GiB PASS
Planned dependency tree Resolve worktree node_modules symlink, inspect target and target parent Symlink ../google-signin-secure/node_modules; target tree absent AND owner worktree absent BLOCKED (Q2)
Nonleased existing-tree control Inspect primary checkout node_modules + compare lockfiles + Electron package metadata Primary tree exists, not a symlink, but lockfile mismatches reviewed worktree and Electron is44.3.0, not45.1.0 BLOCKED; not substituted
Artifact download/path/hash/manifest audit Not dispatched after failed prerequisite No download or extraction BLOCKED
Actual existing runtime/V8/cache-tag comparison Not dispatched Required45.1.0 runtime unavailable through the approved matching dependency tree BLOCKED
CI production-bytecode host identity Not dispatched No host PID/instance or loaded .jsc BLOCKED
Agent copy -> OS clipboard -> isolated lop secret set -> local auth401/200/wrong401 Not dispatched No payload generated, browser/clipboard/store/auth action BLOCKED
Page-owned Copy -> same chain Not dispatched No browser tab or page interaction BLOCKED
Page read denied / write without gesture refused Not dispatched No native evidence BLOCKED
Private tool/host log payload scan Not dispatched No payload or host/tool capture; zero-occurrence PASS not inferred BLOCKED
Cleanup/slot release No process/tab/server/fixture was started; manager notified immediately No process group existed to reap; no clipboard/output cleanup required PASS for zero-start end state; slot released

Q2 — missing approved dependencies/runtime (environment prerequisite)

Repro: read the PR worktree's node_modules symlink; Path.exists() is false for its resolved target, and for its parent owner worktree. This confirms the missing tree rather than merely a missing package. Checked the nonleased primary checkout as a control, but its lockfile does not match and its Electron version is wrong. No install, rebuild, alternate borrowed tree or shim invocation attempted.

Required repair is an explicitly authorized stable dependency/runtime source whose lockfile and Electron45.1.0 runtime are proven compatible, or a revised self-contained evidence artifact. Do not restore a borrowed owner lease implicitly or install dependencies under this slot. This is not a product callback failure.

Local build attempts remain exhausted 3/3. Artifact-host lane stopped at preflight before any native process. Exclusive slot was returned immediately so the waiting lane can proceed. No production page, KOHO tab, real credential or clipboard content accessed.

This intended proof is CI-built production bytecode on an existing compatible runtime, NOT a full installer and NOT the installed application. Neither native behavior nor installed-app remediation is claimed. No new tests/builds ran. Receipt retained in session scratch: qa-round2-artifact-host.md.

@damianvtran

Copy link
Copy Markdown
Owner Author

QA report — round 3

QA: independent qa-tester · Actual served model: anthropic/claude-opus-5-5.
Head: 7d4a31c55c435466e61780cee14da33699d41a8d
Scope: execute the audited CI-built production bytecode on the existing leased Electron45.1.0 runtime; re-test blocked native surfaces. Clipboard callback source is byte-identical to0190c4a81e74508e53cff18f5d85bd560a4aa068 (verified); unchanged source/loader-contract review evidence retained, not rerun.
Worktree: ~/local-operator-ui/.worktrees/secure-copy-regression, clean at admitted head.

Verdict: BLOCKED — real production-bytecode host started, but the first real Python browser-tool open stalled on loadURL(about:blank). No copy/auth PASS claimed.

Executed matrix

Surface Command / real path ACTUAL result Status
Head/callback identity git rev-parse, git status, diff of both callbacks vs0190 Exact head; clean; empty callback diff PASS
Dependency lease Lockfile byte comparison; Electron package/version marker; own worktree symlink temporarily pointed to profile-proposals tree Lockfiles identical; Electron45.1.0; old link recorded; no package manager/build/install/prune PASS
Artifact provenance GitHub run/artifact/job metadata + streamed artifact API download Artifact14002674200; run43333806500 attempt1; job131621450972 success; exact named head; ZIP14,567,219 bytes; SHA2562c24eb4a9bf0fbb346fb43789142dbc02e84d60fa7aa9dbae663d8cf3b19d857 PASS
Manifest / extraction safety Python zipfile central-directory validation, manifest inventory, SHA256 every file, compare package.json to head schema1; darwin/arm64;189 inventoried files;38,566,651 uncompressed bytes; exact inventory; no symlinks/traversal/.env/dependency tree/native.node; inert loopback bindings PASS
Actual existing runtime compatibility Existing Electron binary with ELECTRON_RUN_AS_NODE=1 emits versions and v8.cachedDataVersionTag; compare against CI manifest Electron45.1.0, Node24.22.1, V815.6.75.19-electron.0, darwin/arm64, cachedDataVersionTag1173005779 — all match PASS
Production bytecode startup Existing binary launches audited artifact app with --window-mode=headless --use-mock-keychain and disposable profile/HOME/config HostPID/PGID42121 published instance3db8b3fd-d6ae-4025-8789-94eb4322bf2e on isolated port65073; .jsc loader executed; no cachedDataRejected PASS
Hidden/no-focus state Inspect actual host log visible=false focused=false focusable=false; headless window never shown; isolated profile in discovery PASS
Real Python browser-tool open local_operator.tools.builtin.execute_browser with synthetic ToolContext/BrowserSurface; action=open, backend=ui, URL=owned127.0.0.1 fixture the Local Operator desktop app's browser host stalled on loadURL(about:blank) and gave up on this command BLOCKED (Q3)
Agent copy -> OS clipboard -> isolated lop secret set -> local401/200/wrong401 Not reached after open failure No copy, stored value or authenticated request executed BLOCKED
Page-owned Copy -> same chain Not reached No page click executed BLOCKED
Page clipboard read denied / no-gesture write refused Fixture prepared in memory, but never reached by browser No native denial assertions executed BLOCKED
Payload exposure scan Private comparison against every captured tool-result serialization and host log tool_results_no_payload=true; host_log_no_payload=true. This covers the failed open/startup only, NOT a successful copy flow PASS limited scan; full copy-flow evidence BLOCKED
Rendered fixture states Not reached No loading/empty/error/success screenshots; no visual PASS BLOCKED
Process reap Same controller's finally handles both runtime probe and host; independent ps pid/pgid check ProbePID41936 and hostPID42121 leaders reaped; both groups have zero members; host required SIGKILL after graceful wait PASS
Lease restore/end identity Restore original worktree symlink; compare lock SHA256 and Electron metadata before/after Original ../google-signin-secure/node_modules restored; lease lock SHA256e6848e378a64cf0c855305772ddcd7bbb7a5f81b55f9c64f5d7a1264fed4ea67 unchanged; Electron45.1.0 unchanged; git status empty PASS

Q3 — first browser tab cannot complete about:blank load

The real Python browser tool reached the isolated host and returned its typed loadURL(about:blank) timeout before the disposable fixture could load. A second inspection confirmed the host had actually started and remained hidden; the discovery instance/pid/profile are this lane's, and logs show backend discovery attempting only the intentionally inert127.0.0.1:9. No retry, alternate browser engine, direct-CDP input or production app restart was attempted.

Root cause is not established. The later network-service/GPU termination log entries coincide with our teardown and are not claimed as the cause of the earlier stall. This is a blocked host interaction prerequisite, not evidence that either clipboard callback failed. A separately authorized host/tab diagnosis or compatible pre-exercised artifact/environment is required before another native flow attempt.

Artifact/bytecode identity

  • index.jsc:9,743,080 bytes, SHA256f3d77e63a7675a4ca19c5239a476823b56306c1d07b2979b3055b82f539ff19f.
  • main index.js loader:72 bytes, SHA2569a0e2c5478d7c4b8188f0f9e27b5776453db3b6748d7a3ef735ee37132205046.
  • bytecode-loader.cjs:2,308 bytes, SHA256cdcfbe2ab18e7ce3fd8c143e6183fafbcf802508465003549de0075833224c22.

This is CI-built production bytecode on an existing runtime, NOT a full installer, NOT the installed app, and NOT a successful secure-copy native pass.

Resource/cleanup receipt

Fresh initial df15,230,400KiB available (>=5GiB); immediately before host controller14,373,257,216 bytes free; after exact reap15,427,125,248 bytes free. Peak measured owned retained+scratch allocation123,752,448 bytes, below752MiB; no cap/minimum-free violation. Shared free-space increases are not attributed to this lane.

After preserving artifact manifest, hash/runtime audit, redacted tool results, host log and native summary, removed ONLY owned downloaded ZIP, extracted artifact app and disposable profile/config/HOME. Removed the scratch dependency symlink without touching its leased target. Final cleanup df15,035,552KiB free. Both process groups independently empty after cleanup. No synthetic copied value remained on the clipboard; no secret was written. The random fixture value was never printed.

Slot and read-only dependency lease released, manager notified immediately after exact reap so #1888 can proceed. Local-build count remains3/3 exhausted; this lane performed NO build of any kind. No production page, KOHO tab or real credential accessed.

Durable session receipts: artifact-round3/audit.json, artifact-manifest.json, native-summary.json, tool-results.json, host.log; qa-round3-native-artifact.md. No fixture payload/profile/archive retained.

@damianvtran

Copy link
Copy Markdown
Owner Author

Merge disposition: native proof not obtained

This PR merges on non-native evidence, by the delegator's capped decision (Aida, 2026-11-13). Native proof is missing.

What is proven at head 7d4a31c55c43

  • Before the fix, the installed app (0.54.3) reproduced both failures on a disposable localhost page. The agent copy threw A dynamic import callback was not specified, and the page's own Copy button got NotAllowedError: the host did not allow the clipboard write.
  • The fix: both clipboard callbacks resolve Electron with a lazy require. The production main bundle is CommonJS, and its cached-data loader passes require but supplies no dynamic-import callback (electron-vite 3.1.0 loader source).
  • New tests run the production callbacks under the bytecode/cached-data loader with Electron external: on the old code 27 pass, 2 fail, with exactly ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING; on the fix 29/29 pass.
  • Code review rounds 1–4 are clean and terminal, covering the callback fix, the macOS bytecode artifact, CI command parity and the Mac build heap.
  • The macOS arm64 production-bytecode artifact from CI matches the local Electron 45.1.0 runtime: manifest, 189 file hashes, V8 15.6.75.19-electron.0 and cached-data tag 1173005779.

What is NOT proven

  • No run has shown either copy path succeeding end to end on a real host: OS clipboard → secret store → authenticated use.
  • QA round 3 started the CI-built bytecode host hidden, but the first browser open stalled on loadURL(about:blank), so the copy matrix never ran.
  • Diagnosis (read-only): the stall is in cdp.ts:311-326, before debugger.attach, and so before this PR's shim installs (cdp.ts:422-432). It hit the approvals overlay's first load as well, so it is host-wide rather than specific to the agent view or this change. The cause is unconfirmed: either load starvation (machine load average 44–61) or an Electron 45 first-load issue in a hidden host. It now belongs to the browser-availability lane as a separate issue.

Follow-up commitment. After this ships, we verify with a real Copy click and an agent copy → lop secret on the installed app, using disposable data. If either still fails, we revert this PR.

@damianvtran damianvtran added the ready-to-merge Full suite requested on this head - re-arm with pnpm merge-gate <n> label Nov 13, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Full suite requested on this head - re-arm with pnpm merge-gate <n>

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant