fix(agent-browser): preserve preview injection origin
This commit is contained in:
@@ -0,0 +1,95 @@
|
|||||||
|
# Task: Remediate X-01 preview data injection target
|
||||||
|
|
||||||
|
## Identity
|
||||||
|
|
||||||
|
- Task ID: 20260827-x01-preview-injection-9c4e2a71
|
||||||
|
- Mode: Feature
|
||||||
|
- Branch: codex/20260827-x01-preview-injection-9c4e2a71-x01-preview-injection-9c4e2a71
|
||||||
|
- Worktree: D:\Datas\OthersProjects\makelore-x01-preview-injection-9c4e2a71
|
||||||
|
- Base commit: 2f346687b173137135dbd5259511d23505ff08dd
|
||||||
|
- Owner: codex
|
||||||
|
- Status: Ready for Integration
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
- X-01 live-acceptance remediation on exact client coordinator HEAD
|
||||||
|
`2f346687b173137135dbd5259511d23505ff08dd`.
|
||||||
|
- Fix the confirmed root `injectProjectData` preview failure in
|
||||||
|
`electron/agent-browser/module.ts` by passing the intended preview target
|
||||||
|
Origin explicitly into root preview-data installation.
|
||||||
|
- Add the narrow Agent Browser regression test and this task-scoped record only.
|
||||||
|
|
||||||
|
## Intent And Constraints
|
||||||
|
|
||||||
|
- Follow Data Service P0 spec §10.4 and §14 groups 2 and 13, plus the X-01
|
||||||
|
remediation finding. Preserve explicit opt-in, exact-Origin capability
|
||||||
|
binding, child/sessionRef behavior, lifecycle cleanup, and ordinary browser
|
||||||
|
navigation without data injection.
|
||||||
|
- The confirmed cause is that `open()` initializes `record.url` to the target,
|
||||||
|
prime navigation to `about:blank` mutates it, and root installation later
|
||||||
|
derives Origin from the mutated URL. The fix must carry the target URL
|
||||||
|
directly; it must not weaken Origin checks or add a second browser/preload.
|
||||||
|
- Only this task worktree may be modified. The occupied coordinator worktree,
|
||||||
|
its untracked X-01 probe scripts, all other source files, and the prior ML-09
|
||||||
|
source worktree are read-only context.
|
||||||
|
- Do not alter child/sessionRef installation semantics, route behavior, server
|
||||||
|
code, unrelated E2E selectors, or canonical project memory.
|
||||||
|
|
||||||
|
## Planning Gate
|
||||||
|
|
||||||
|
- Result: Passed on 2026-08-27.
|
||||||
|
- Concurrent gate ran `check_project_docs.py`, then
|
||||||
|
`task_context.py start` against the occupied coordinator worktree with
|
||||||
|
`--base-ref 2f346687b173137135dbd5259511d23505ff08dd`; status JSON verified
|
||||||
|
this task ID, feature mode, absolute worktree/branch, and exact base.
|
||||||
|
- Read the required MakeLore project-memory startup set, the coordinator task
|
||||||
|
record, Agent Browser architecture/data-flow seams, and the X-01 scope. The
|
||||||
|
coordinator owns the parent worktree and its live probes; this task owns only
|
||||||
|
the isolated module/test/record paths, with no unresolved semantic conflict.
|
||||||
|
|
||||||
|
## Outcome
|
||||||
|
|
||||||
|
- Passed the intended `targetUrl` explicitly to the root preview-data
|
||||||
|
installation call. Root session Origin now derives from that stable target
|
||||||
|
URL even when the prime `about:blank` navigation updates `record.url`;
|
||||||
|
child/sessionRef installation remains on its existing call path.
|
||||||
|
- Added a narrow Agent Browser regression whose fake prime navigation emits
|
||||||
|
`did-navigate` for `about:blank`. Before the fix it observed `origin: "null"`;
|
||||||
|
after the fix it observes `http://127.0.0.1:4173`.
|
||||||
|
|
||||||
|
## Plan
|
||||||
|
|
||||||
|
1. Inspect the current root/child preview installation seam and add a failing
|
||||||
|
regression proving a prime `about:blank` navigation cannot change the Origin
|
||||||
|
used for root injection.
|
||||||
|
2. Pass the intended target URL through root installation with the smallest
|
||||||
|
signature/call-site change; keep child/sessionRef handling unchanged.
|
||||||
|
3. Run focused Agent Browser/preview tests, typecheck, scoped lint and diff/doc
|
||||||
|
gates, then commit once with a clean isolated worktree.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- Red-first regression:
|
||||||
|
`pnpm exec vitest run tests/unit/agent-browser-core.test.ts -t "uses the
|
||||||
|
target Origin when the prime navigation reports about:blank" --maxWorkers=1`
|
||||||
|
failed as expected before the implementation (`received origin: "null"`).
|
||||||
|
- Focused tests:
|
||||||
|
`pnpm exec vitest run tests/unit/agent-browser-core.test.ts
|
||||||
|
tests/unit/preview-data-session.test.ts --maxWorkers=1` — 2 files, 84 tests
|
||||||
|
passed.
|
||||||
|
- `pnpm run typecheck` — passed.
|
||||||
|
- `pnpm exec eslint electron/agent-browser/module.ts
|
||||||
|
tests/unit/agent-browser-core.test.ts` — passed.
|
||||||
|
- `git diff --check` — passed.
|
||||||
|
- No Electron E2E or live X-01 acceptance was run in this narrow remediation;
|
||||||
|
the coordinator must rerun live acceptance after integration.
|
||||||
|
|
||||||
|
## Follow-ups
|
||||||
|
|
||||||
|
- Parent coordinator should integrate the single commit and rerun X-01 with
|
||||||
|
the real PostgreSQL and signed-in MakeLore preview. Do not treat this
|
||||||
|
repository-local focused verification as live acceptance.
|
||||||
|
|
||||||
|
## Promotion Candidates
|
||||||
|
|
||||||
|
- None recorded.
|
||||||
@@ -391,7 +391,7 @@ export class AgentBrowserModule {
|
|||||||
this.attachDebugger(record, false),
|
this.attachDebugger(record, false),
|
||||||
OPEN_TIMEOUT_MS,
|
OPEN_TIMEOUT_MS,
|
||||||
);
|
);
|
||||||
if (injectProjectData) await this.installPreviewData(record);
|
if (injectProjectData) await this.installPreviewData(record, undefined, targetUrl);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await this.closeInternal(record);
|
await this.closeInternal(record);
|
||||||
throw toFault(
|
throw toFault(
|
||||||
@@ -796,6 +796,7 @@ export class AgentBrowserModule {
|
|||||||
private async installPreviewData(
|
private async installPreviewData(
|
||||||
record: BrowserRecord,
|
record: BrowserRecord,
|
||||||
sessionRef?: string,
|
sessionRef?: string,
|
||||||
|
targetUrl?: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (record !== this.record || record.view.webContents.isDestroyed()) {
|
if (record !== this.record || record.view.webContents.isDestroyed()) {
|
||||||
throw new AgentBrowserFault(
|
throw new AgentBrowserFault(
|
||||||
@@ -814,7 +815,7 @@ export class AgentBrowserModule {
|
|||||||
if (!sessionRef) {
|
if (!sessionRef) {
|
||||||
const openInput: PreviewDataSessionOpenInput = {
|
const openInput: PreviewDataSessionOpenInput = {
|
||||||
projectPath: record.projectPath,
|
projectPath: record.projectPath,
|
||||||
origin: new URL(record.url).origin,
|
origin: new URL(targetUrl ?? record.url).origin,
|
||||||
browserGeneration: record.generation,
|
browserGeneration: record.generation,
|
||||||
};
|
};
|
||||||
const session = await previewDataSession.open(openInput);
|
const session = await previewDataSession.open(openInput);
|
||||||
|
|||||||
@@ -609,6 +609,33 @@ describe('AgentBrowserModule', () => {
|
|||||||
expect(externalGlobal.__MAKELORE_DATA__).toBeUndefined();
|
expect(externalGlobal.__MAKELORE_DATA__).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('uses the target Origin when the prime navigation reports about:blank', async () => {
|
||||||
|
const adapter = new FakeAdapter();
|
||||||
|
const preview = new FakePreviewDataSession();
|
||||||
|
adapter.onCreate = (view) => {
|
||||||
|
view.webContents.loadHandler = async (url) => {
|
||||||
|
view.webContents.emit('did-navigate', {}, url);
|
||||||
|
};
|
||||||
|
view.webContents.debugger.responders.set('Page.addScriptToEvaluateOnNewDocument', async () => ({
|
||||||
|
identifier: 'script-root',
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
const module = new AgentBrowserModule(adapter, { previewDataSession: preview });
|
||||||
|
|
||||||
|
await module.open({
|
||||||
|
projectId: 'clock',
|
||||||
|
projectPath,
|
||||||
|
url: 'http://127.0.0.1:4173/',
|
||||||
|
injectProjectData: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(preview.opens).toEqual([{
|
||||||
|
projectPath,
|
||||||
|
origin: 'http://127.0.0.1:4173',
|
||||||
|
browserGeneration: 1,
|
||||||
|
}]);
|
||||||
|
});
|
||||||
|
|
||||||
it('fails and tears down before target load when preview session setup fails', async () => {
|
it('fails and tears down before target load when preview session setup fails', async () => {
|
||||||
const adapter = new FakeAdapter();
|
const adapter = new FakeAdapter();
|
||||||
const preview = new FakePreviewDataSession();
|
const preview = new FakePreviewDataSession();
|
||||||
|
|||||||
Reference in New Issue
Block a user