Scan active probe bodies for restricted content in renderer spec
Why: Probes sent with page.request do not raise page response events, so the §11-8 leak scan only covered passive page responses. Evidence: Final run 20261016T065123Z item8-scan.json counted 18 responses, all passive; probe bodies were checked only for rejection and payload. Impact: Every probe and host API body is scanned for project A names, the controlled and uncontrolled document titles and review markers. Refs: unified renderer plan Task 13 §11 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -550,7 +550,7 @@ test('§11-8 无权用户的页面与网络响应不含受限内容', async ({ b
|
||||
await page.waitForTimeout(1_500)
|
||||
await shot(page, 'item8-outsider-audit')
|
||||
const pageText = (await page.locator('body').textContent()) ?? ''
|
||||
for (const m of [A.name, A.title, ANNOTATION, REVISION_AFTER]) expect(pageText, `页面不得出现受限内容「${m}」`).not.toContain(m)
|
||||
for (const m of [A.name, A.title, UNCTRL.title, ANNOTATION, REVISION_AFTER]) expect(pageText, `页面不得出现受限内容「${m}」`).not.toContain(m)
|
||||
const passiveCount = s.net.length
|
||||
|
||||
// 主动探测:以无权用户会话直调 A 的读取与下载命令(请求中自带的 id 不算泄露)
|
||||
@@ -565,8 +565,10 @@ test('§11-8 无权用户的页面与网络响应不含受限内容', async ({ b
|
||||
...(st.submissionId ? [['rdm.render.review.view', { projectId: A.pid, submissionId: st.submissionId }] as [string, Record<string, unknown>]] : []),
|
||||
]
|
||||
const probeResults: { id: string; status: number; state: string; hasPayload: boolean }[] = []
|
||||
const probeBodies: { url: string; body: string }[] = []
|
||||
for (const [id, params] of probes) {
|
||||
const r = await command(page, id, params)
|
||||
probeBodies.push({ url: `probe:${id}`, body: r.text })
|
||||
const state = r.body?.receipt?.state ?? ''
|
||||
const payload = r.body?.payload
|
||||
const hasPayload = payload !== undefined && payload !== null && !(typeof payload === 'object' && Object.keys(payload).length === 0)
|
||||
@@ -576,6 +578,7 @@ test('§11-8 无权用户的页面与网络响应不含受限内容', async ({ b
|
||||
}
|
||||
for (const kind of ['markdown', 'docx', 'manifest']) {
|
||||
const r = await command(page, 'rdm.render.download', { projectId: A.pid, deliveryId: 'probe', kind })
|
||||
probeBodies.push({ url: `probe:rdm.render.download:${kind}`, body: r.text })
|
||||
probeResults.push({ id: `rdm.render.download:${kind}`, status: r.status, state: r.body?.receipt?.state ?? '', hasPayload: !!r.body?.payload })
|
||||
expect.soft(!r.body?.payload?.dataBase64, 'rdm.render.download 不得返回文件内容').toBe(true)
|
||||
}
|
||||
@@ -583,22 +586,25 @@ test('§11-8 无权用户的页面与网络响应不含受限内容', async ({ b
|
||||
const hostText = await hostProjects.text()
|
||||
expect.soft(hostText.includes(A.host), '宿主项目列表不得含项目 A').toBe(false)
|
||||
const hostConv = await page.request.get(`/api/projects/${A.host}/conversations`)
|
||||
const hostConvText = await hostConv.text()
|
||||
probeBodies.push({ url: '/api/projects', body: hostText }, { url: `/api/projects/${A.host}/conversations`, body: hostConvText })
|
||||
note(`宿主 A 会话列表 HTTP ${hostConv.status()}`)
|
||||
expect.soft(hostConv.status() >= 400 || !(await hostConv.text()).includes('§11'), '宿主 A 会话不得可见').toBe(true)
|
||||
expect.soft(hostConv.status() >= 400 || !hostConvText.includes('§11'), '宿主 A 会话不得可见').toBe(true)
|
||||
note(`主动探测:${JSON.stringify(probeResults)}`)
|
||||
await Promise.all(s.pending)
|
||||
|
||||
// 全部网络响应体扫描:内容标记任何响应都不得出现;A 的标识只在被动浏览响应中检查
|
||||
const contentMarkers = [A.name, A.title, ANNOTATION, REVISION_AFTER, ...(st.downloads ?? [])]
|
||||
const contentMarkers = [A.name, A.title, UNCTRL.title, ANNOTATION, REVISION_AFTER, ...(st.downloads ?? [])]
|
||||
const idMarkers = [A.pid, A.host, st.submissionId].filter(Boolean)
|
||||
const leaks: string[] = []
|
||||
s.net.forEach((n, i) => {
|
||||
for (const m of contentMarkers) if (m && n.body.includes(m)) leaks.push(`${n.url} 含「${m}」`)
|
||||
if (i < passiveCount) for (const m of idMarkers) if (n.body.includes(m)) leaks.push(`${n.url} 含标识 ${m}`)
|
||||
})
|
||||
for (const p of probeBodies) for (const m of contentMarkers) if (m && p.body.includes(m)) leaks.push(`${p.url} 含「${m}」`)
|
||||
const scanned = path.join(EVID, 'network', 'item8-scan.json')
|
||||
fs.mkdirSync(path.dirname(scanned), { recursive: true })
|
||||
fs.writeFileSync(scanned, JSON.stringify({ responses: s.net.length, passive: passiveCount, contentMarkers, idMarkers, leaks, probeResults }, null, 2))
|
||||
fs.writeFileSync(scanned, JSON.stringify({ pageResponses: s.net.length, passive: passiveCount, probeResponses: probeBodies.length, contentMarkers, idMarkers, leaks, probeResults }, null, 2))
|
||||
evidence.push(scanned)
|
||||
expect(leaks, `受限内容泄露:${leaks.join(';')}`).toEqual([])
|
||||
await s.close()
|
||||
|
||||
Reference in New Issue
Block a user