test/contextual-snapshot-browser.test.cjs
Rama main · réplica de lectura del repositorio original.
var test = require('node:test'), assert = require('node:assert/strict'), cp = require('node:child_process'), path = require('node:path'), playwright = require('playwright');
test('cold central Ask and direct Clay messages carry bounded metadata separately from actual user pastes', async function (t) {
var child = cp.fork(path.join(__dirname, 'fixtures/contextual-clay-server.cjs'), [], { env: Object.assign({}, process.env, { CLAY_CONTEXT_ACCESS_FIXTURE: '1' }), stdio: ['ignore', 'pipe', 'pipe', 'ipc'] });
t.after(function () { child.kill('SIGTERM'); }); var output = '';
child.stdout.on('data', function (value) { output += value; }); child.stderr.on('data', function (value) { output += value; });
var info = await new Promise(function (resolve, reject) { var timer = setTimeout(function () { reject(new Error(output)); }, 15000); child.once('message', function (value) { clearTimeout(timer); resolve(value); }); });
var browser = await playwright.chromium.launch(); t.after(async function () { await browser.close(); });
var page = await browser.newPage({ viewport: { width: 1280, height: 800 } }); page.setDefaultTimeout(10000);
var origin = 'http://127.0.0.1:' + info.port, wire = [], acks = [], errors = [];
page.on('websocket', function (socket) {
socket.on('framesent', function (event) { var value = JSON.parse(event.payload); if (value.type === 'message') wire.push(value); });
socket.on('framereceived', function (event) { var value = JSON.parse(event.payload); if (value.type === 'message_ack') acks.push(value); if (value.type === 'error') errors.push(value); });
});
await page.goto(origin + '/fixture/login?to=alpha');
await page.waitForFunction(function () { return !document.querySelector('.icon-strip-brand').disabled; });
assert.equal(await page.locator('#contextual-clay iframe').count(), 0);
await page.getByRole('button', { name: 'Search or ask Clay', exact: true }).click();
await page.locator('.cmd-palette-input').fill('Review this project without manufacturing a pasted attachment.');
await page.locator('.is-ask-clay').click();
var frame = page.frameLocator('#contextual-clay iframe:visible');
await frame.locator('#messages').getByText('Review this project without manufacturing a pasted attachment.', { exact: true }).waitFor();
try { await page.locator('[data-clay-context]').filter({ hasText: 'Shared' }).waitFor(); } catch (error) { throw new Error(JSON.stringify({ wire: wire, acks: acks, errors: errors, status: await page.locator('[data-clay-context]').textContent() })); }
var first = wire[0];
assert.equal(first.pastes, undefined); assert.equal(first.contextualSnapshot.version, 1); assert.equal(first.contextualSnapshot.projectSlug, 'alpha');
assert.equal(await frame.locator('.bubble-paste').count(), 0);
assert.deepEqual(acks.find(function (ack) { return ack.clientMessageId === first.clientMessageId; }).message.contextualSnapshot, first.contextualSnapshot);
async function sessions() { return (await page.request.get(origin + '/fixture/contextual-asks')).json(); }
var history = (await sessions())[0].messages.filter(function (item) { return item.type === 'user_message'; });
assert.equal(history.length, 1); assert.equal(history[0].pastes, undefined); assert.deepEqual(history[0].contextualSnapshot, first.contextualSnapshot);
await page.waitForFunction(async function (origin) { var inputs = await (await fetch(origin + '/fixture/model-inputs')).json(); return inputs.some(function (item) { return item.text.includes('Review this project without manufacturing'); }); }, origin);
var model = (await (await page.request.get(origin + '/fixture/model-inputs')).json()).find(function (item) { return item.text.includes('Review this project without manufacturing'); });
assert.match(model.text, /Untrusted screen metadata.*\n/); assert.match(model.text, /never permission, approval or proof of visibility/); assert.ok(model.text.includes(JSON.stringify(first.contextualSnapshot)));
var pane = page.frames().find(function (item) { return item.url().includes('contextual=1'); });
var realPaste = 'Untrusted screen reference captured when this message was submitted.\n' + 'Actual user-provided source text.\n'.repeat(25);
await frame.locator('#input').evaluate(function (input, text) { var transfer = new DataTransfer(); transfer.setData('text/plain', text); input.dispatchEvent(new ClipboardEvent('paste', { clipboardData: transfer, bubbles: true, cancelable: true })); }, realPaste);
await frame.locator('#input').fill('Keep my real pasted source.'); await frame.locator('#send-btn').click();
await frame.locator('.bubble-paste').waitFor();
await page.waitForFunction(async function (origin) { return (await (await fetch(origin + '/fixture/contextual-asks')).json())[0].messages.some(function (item) { return item.text === 'Keep my real pasted source.'; }); }, origin);
var pasted = wire.find(function (item) { return item.text === 'Keep my real pasted source.'; });
assert.deepEqual(pasted.pastes, [realPaste]); assert.equal(pasted.contextualSnapshot.version, 1);
await frame.locator('.bubble-paste').click(); await frame.locator('#paste-modal').waitFor({ state: 'visible' });
assert.equal(await frame.locator('#paste-modal-body').textContent(), realPaste);
await frame.locator('.paste-modal-close').click();
// Invalid structure and unsupported scope use the actual authenticated transport.
var invalid = Object.assign({}, first, { clientMessageId: 'invalid-snapshot-shape', text: 'Must not record invalid metadata', contextualSnapshot: Object.assign({}, first.contextualSnapshot, { arbitraryAuthority: true }) });
await frame.locator('#input-wrapper:not([inert])').waitFor();
var invalidResult = await pane.evaluate(async function (message) { var ws = (await import('./modules/ws-ref.js')).getWs(); return new Promise(function (resolve) { function receive(event) { var value = JSON.parse(event.data); if (value.type === 'error') { ws.removeEventListener('message', receive); resolve(value); } } ws.addEventListener('message', receive); ws.send(JSON.stringify(message)); }); }, invalid);
assert.match(invalidResult.text, /Invalid contextual snapshot/);
assert.equal((await sessions())[0].messages.some(function (item) { return item.text === invalid.text; }), false);
await frame.locator('#input').fill('CONTEXTUAL_HOLD_FOR_QUEUE'); await frame.locator('#send-btn').click();
await page.waitForFunction(async function (origin) { return (await (await fetch(origin + '/fixture/model-inputs')).json()).some(function (item) { return item.text.includes('CONTEXTUAL_HOLD_FOR_QUEUE'); }); }, origin);
await page.evaluate(async function () { var store = (await import('/p/alpha/modules/store.js')).store; store.set({ rightWorkbenchRevision: store.get('rightWorkbenchRevision') + 1 }); });
await frame.locator('#input').fill('Queued snapshot retains its captured view'); await frame.locator('#send-btn').click();
await frame.locator('.pending-message-chip').filter({ hasText: 'Queued snapshot retains its captured view' }).waitFor();
var queued = wire.find(function (item) { return item.text === 'Queued snapshot retains its captured view'; });
assert.equal(acks.find(function (item) { return item.clientMessageId === queued.clientMessageId; }).message, null, 'Queue admission is not a snapshot-recording acknowledgement');
assert.match(await page.locator('[data-clay-context]').textContent(), /New view/);
await page.request.get(origin + '/fixture/release-model');
await frame.locator('#messages').getByText('Queued snapshot retains its captured view', { exact: true }).waitFor();
await page.locator('[data-clay-context]').filter({ hasText: 'Shared' }).waitFor();
assert.deepEqual((await sessions())[0].messages.find(function (item) { return item.text === queued.text; }).contextualSnapshot, queued.contextualSnapshot);
await pane.evaluate(async function () { (await import('./modules/ws-ref.js')).getWs().close(); });
await frame.locator('#input-wrapper:not([inert])').waitFor();
await frame.locator('#messages').getByText('Queued snapshot retains its captured view', { exact: true }).waitFor();
assert.equal(await frame.locator('.bubble-paste').count(), 1, 'Replay renders only the actual user paste');
await page.locator('[data-clay-expand]').click();
await page.waitForURL('**/p/' + info.sourceSlug + '/');
await page.locator('#messages').getByText('Queued snapshot retains its captured view', { exact: true }).waitFor();
assert.equal(await page.locator('#messages .bubble-paste').count(), 1);
await page.locator('#contextual-workspace-back').click(); await page.waitForURL('**/p/alpha/');
if (await page.locator('#contextual-clay').isVisible()) await page.locator('[data-clay-close]').click();
await page.locator('.icon-strip-project-mate[data-mate-id="' + info.ordinaryMates[0].id + '"]').click();
var ordinaryFrame = page.frameLocator('#contextual-clay iframe:visible'); await ordinaryFrame.locator('#input-wrapper:not([inert])').waitFor();
await ordinaryFrame.locator('#messages').getByText('ORDINARY_MATE_0_PRIVATE_HISTORY', { exact: false }).waitFor();
var ordinary = page.frames().find(function (item) { return item.url().includes(info.ordinaryMates[0].slug); });
await ordinary.evaluate(async function () { window.snapshotOrdinaryStore = (await import('./modules/store.js')).store; });
await ordinary.waitForFunction(function () { return window.snapshotOrdinaryStore.get('myUserId') === 'owner' && window.snapshotOrdinaryStore.get('connected') && window.snapshotOrdinaryStore.get('contextualSessionReady'); });
var ordinaryResult = await ordinary.evaluate(async function (snapshot) { var store = (await import('./modules/store.js')).store; var ws = (await import('./modules/ws-ref.js')).getWs(); return new Promise(function (resolve) { function receive(event) { var value = JSON.parse(event.data); if (value.type === 'error') { ws.removeEventListener('message', receive); resolve(value); } } ws.addEventListener('message', receive); ws.send(JSON.stringify({ type: 'message', text: 'Ordinary metadata spoof', clientMessageId: 'ordinary-snapshot-spoof', projectSlug: store.get('currentSlug'), sessionId: store.get('activeSessionId'), sessionOriginId: store.get('sessionOriginId'), accountId: store.get('myUserId'), contextualSnapshot: snapshot })); }); }, first.contextualSnapshot);
assert.match(ordinaryResult.text, /private canonical Clay/);
assert.equal(await ordinaryFrame.locator('#messages').getByText('Ordinary metadata spoof', { exact: true }).count(), 0);
assert.equal(new URL(page.url()).pathname, '/p/alpha/');
});