mirror of
https://git.openapi.site/https://github.com/desirecore/agent-desirecore.git
synced 2026-09-05 17:43:47 +08:00
feat: 增加求解器验证书 Web (#7)
Co-authored-by: yige <yige@yigedeMacBook-Neo.local>
This commit is contained in:
132
web/solver-report/tests/public-release-policy.test.mjs
Normal file
132
web/solver-report/tests/public-release-policy.test.mjs
Normal file
@@ -0,0 +1,132 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { mkdirSync, mkdtempSync, realpathSync, rmSync, symlinkSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
import { tmpdir } from 'node:os'
|
||||
import test from 'node:test'
|
||||
import {
|
||||
assertPublicText,
|
||||
projectPublicProvenance,
|
||||
resolveSafeRemoteEntryUrl,
|
||||
resolveSafeOutputRoot,
|
||||
validatePublicReleaseAttestation,
|
||||
} from '../scripts/public-release-policy.mjs'
|
||||
|
||||
test('输出目录只能位于证据 report-web 的真实专用子目录', (context) => {
|
||||
const sandbox = mkdtempSync(join(tmpdir(), 'solver-report-path-policy-'))
|
||||
context.after(() => rmSync(sandbox, { recursive: true, force: true }))
|
||||
const roots = {
|
||||
inputRoot: join(sandbox, 'evidence'),
|
||||
codeRoot: join(sandbox, 'agent-desirecore'),
|
||||
appRoot: join(sandbox, 'desirecore-app'),
|
||||
}
|
||||
for (const path of [...Object.values(roots), join(roots.inputRoot, 'report-web')]) mkdirSync(path, { recursive: true })
|
||||
const safeOutput = join(roots.inputRoot, 'report-web', 'dist')
|
||||
assert.equal(
|
||||
resolveSafeOutputRoot({ ...roots, requestedOutputRoot: safeOutput }),
|
||||
join(realpathSync(join(roots.inputRoot, 'report-web')), 'dist')
|
||||
)
|
||||
for (const requestedOutputRoot of [
|
||||
'/',
|
||||
sandbox,
|
||||
roots.inputRoot,
|
||||
join(roots.inputRoot, 'report-web'),
|
||||
join(roots.codeRoot, 'web-output'),
|
||||
join(sandbox, 'unmanaged-report-output'),
|
||||
]) {
|
||||
assert.throws(() => resolveSafeOutputRoot({ ...roots, requestedOutputRoot: requestedOutputRoot }))
|
||||
}
|
||||
|
||||
const symlinkInputRoot = join(sandbox, 'symlink-evidence')
|
||||
const externalTarget = join(sandbox, 'external-target')
|
||||
mkdirSync(symlinkInputRoot)
|
||||
mkdirSync(externalTarget)
|
||||
symlinkSync(externalTarget, join(symlinkInputRoot, 'report-web'))
|
||||
assert.throws(() =>
|
||||
resolveSafeOutputRoot({
|
||||
inputRoot: symlinkInputRoot,
|
||||
codeRoot: roots.codeRoot,
|
||||
appRoot: roots.appRoot,
|
||||
requestedOutputRoot: join(symlinkInputRoot, 'report-web', 'dist'),
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
test('远端完整性条目不能改变 origin 或越过报告路径', () => {
|
||||
assert.equal(
|
||||
resolveSafeRemoteEntryUrl('https://build.example.com/solver-agent-team/', 'media/original/case/01@2x.png').href,
|
||||
'https://build.example.com/solver-agent-team/media/original/case/01@2x.png'
|
||||
)
|
||||
for (const path of [
|
||||
'https://127.0.0.1/private',
|
||||
'http://evil.example/private',
|
||||
'../admin',
|
||||
'/absolute',
|
||||
'media\\secret',
|
||||
'media/%2e%2e/secret',
|
||||
'media//secret',
|
||||
'media/file?redirect=http://127.0.0.1',
|
||||
]) {
|
||||
assert.throws(() => resolveSafeRemoteEntryUrl('https://build.example.com/solver-agent-team/', path))
|
||||
}
|
||||
})
|
||||
|
||||
test('provenance 使用递归数据不可穿透的字段白名单', () => {
|
||||
assert.deepEqual(
|
||||
projectPublicProvenance({
|
||||
engine_id: 'scip-build',
|
||||
request_id: 'request-1',
|
||||
endpoint: 'https://private.internal',
|
||||
nested: { access_token: 'secret-value' },
|
||||
}),
|
||||
{ engine_id: 'scip-build', request_id: 'request-1' }
|
||||
)
|
||||
})
|
||||
|
||||
test('公开文本策略拒绝身份、凭据、私有路径和私有网络地址', () => {
|
||||
assert.doesNotThrow(() => assertPublicText('SCIP 10.0.2 · request 853ca9c7-440b', 'safe'))
|
||||
for (const value of [
|
||||
'admin@example.com',
|
||||
'/Users/reviewer/private/report.json',
|
||||
'authorization: Bearer abcdefghijklmnop',
|
||||
'password=not-for-public',
|
||||
'http://192.168.1.10/private',
|
||||
]) {
|
||||
assert.throws(() => assertPublicText(value, 'unsafe'))
|
||||
}
|
||||
})
|
||||
|
||||
test('公开发布证明必须绑定全部证据根并显式通过', () => {
|
||||
const evidenceRoots = Object.fromEntries(
|
||||
[
|
||||
'publicTranscriptContentRootSha256',
|
||||
'publicScreenshotContentRootSha256',
|
||||
'screenshotPlanSha256',
|
||||
'screenshotValidationSha256',
|
||||
'screenshotPrivacyValidationSha256',
|
||||
].map((key, index) => [key, String(index + 1).repeat(64)])
|
||||
)
|
||||
const attestation = {
|
||||
schemaVersion: 'solver.public-release-attestation/v1',
|
||||
audience: 'public',
|
||||
review: {
|
||||
status: 'passed',
|
||||
reviewedAt: '2026-08-30T09:00:00.000Z',
|
||||
reviewer: 'release-review',
|
||||
methods: ['text-scan', 'visual-review'],
|
||||
assertions: {
|
||||
transcriptsContainNoSensitiveData: true,
|
||||
screenshotsContainNoSensitiveData: true,
|
||||
customerIdentifiersExcluded: true,
|
||||
},
|
||||
},
|
||||
evidence: evidenceRoots,
|
||||
metadata: { platformCommit: 'be0cc2cce', agentSkillVersion: '4.4.4', representativeStabilityPasses: 20 },
|
||||
}
|
||||
assert.equal(validatePublicReleaseAttestation(attestation, evidenceRoots), attestation)
|
||||
assert.throws(() =>
|
||||
validatePublicReleaseAttestation(
|
||||
{ ...attestation, evidence: { ...evidenceRoots, screenshotPlanSha256: '0'.repeat(64) } },
|
||||
evidenceRoots
|
||||
)
|
||||
)
|
||||
})
|
||||
86
web/solver-report/tests/source-contract.test.mjs
Normal file
86
web/solver-report/tests/source-contract.test.mjs
Normal file
@@ -0,0 +1,86 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
import test from 'node:test'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const root = join(fileURLToPath(new URL('..', import.meta.url)))
|
||||
const html = readFileSync(join(root, 'source', 'index.html'), 'utf8')
|
||||
const css = readFileSync(join(root, 'source', 'report.css'), 'utf8')
|
||||
const javascript = readFileSync(join(root, 'source', 'report.js'), 'utf8')
|
||||
const builder = readFileSync(join(root, 'scripts', 'build-report-web.mjs'), 'utf8')
|
||||
const ocrValidator = readFileSync(join(root, 'scripts', 'validate-screenshot-privacy-ocr.mjs'), 'utf8')
|
||||
const deploymentValidator = readFileSync(join(root, 'scripts', 'validate-deployed-report.mjs'), 'utf8')
|
||||
const attestationSchema = JSON.parse(
|
||||
readFileSync(join(root, 'public-release-attestation.schema.json'), 'utf8')
|
||||
)
|
||||
|
||||
test('图片查看器暴露完整的可访问缩放控制', () => {
|
||||
for (const id of [
|
||||
'lightbox-stage',
|
||||
'lightbox-canvas',
|
||||
'lightbox-zoom-out',
|
||||
'lightbox-zoom',
|
||||
'lightbox-zoom-in',
|
||||
'lightbox-fit',
|
||||
'lightbox-actual',
|
||||
]) {
|
||||
assert.match(html, new RegExp(`id="${id}"`))
|
||||
}
|
||||
assert.match(html, /aria-live="polite"/)
|
||||
assert.match(html, /aria-describedby="lightbox-zoom-hint"/)
|
||||
assert.match(javascript, /<button type="button" class="shot"/)
|
||||
assert.match(javascript, /aria-haspopup="dialog"/)
|
||||
assert.match(javascript, /event\.preventDefault\(\)/)
|
||||
})
|
||||
|
||||
test('图片查看器实现按钮、键盘、滚轮、双击和触控指针路径', () => {
|
||||
assert.match(javascript, /lightbox-zoom-in/)
|
||||
assert.match(javascript, /event\.key === '\+'/)
|
||||
assert.match(javascript, /addEventListener\(\s*'wheel'/)
|
||||
assert.match(javascript, /addEventListener\('dblclick'/)
|
||||
assert.match(javascript, /addEventListener\('pointerdown'/)
|
||||
assert.match(javascript, /viewer\.pointers\.size === 2/)
|
||||
assert.match(javascript, /viewer\.pointers\.size >= 2/)
|
||||
assert.match(javascript, /lostpointercapture/)
|
||||
assert.match(javascript, /MIN_VIEWER_ZOOM/)
|
||||
assert.match(javascript, /MAX_VIEWER_ZOOM/)
|
||||
})
|
||||
|
||||
test('响应式样式约束全屏查看器且允许平移', () => {
|
||||
assert.match(css, /\.lightbox-stage\.is-pannable/)
|
||||
assert.match(css, /touch-action:\s*none/)
|
||||
assert.match(css, /width:\s*100vw/)
|
||||
assert.match(css, /height:\s*100dvh/)
|
||||
})
|
||||
|
||||
test('构建器从 Agent 仓库读取代码、从显式目录读取证据', () => {
|
||||
assert.match(builder, /SOLVER_REPORT_INPUT_ROOT/)
|
||||
assert.match(builder, /SOLVER_REPORT_OUTPUT_ROOT/)
|
||||
assert.match(builder, /const sourceRoot = join\(codeRoot, 'source'\)/)
|
||||
assert.match(builder, /loadPublicReleaseAttestation/)
|
||||
assert.match(builder, /ajv\.compile/)
|
||||
assert.match(builder, /solver\.public-screenshot-plan\/v1/)
|
||||
assert.match(builder, /screenshot\.sourceSha256 !== sourceScenario\.screenshots\[index\]\.sha256/)
|
||||
assert.match(builder, /historicalBuildManifest\.skill\?\.version/)
|
||||
assert.match(builder, /representativeStabilityPasses = stabilityMatrix\.groups/)
|
||||
assert.doesNotMatch([html, css, javascript, builder].join('\n'), /\/Users\/|\/Volumes\//)
|
||||
})
|
||||
|
||||
test('公开发布证明 Schema 自描述关键边界', () => {
|
||||
assert.equal(attestationSchema.$schema, 'http://json-schema.org/draft-07/schema#')
|
||||
assert.match(attestationSchema.description, /public-release privacy review/)
|
||||
for (const field of Object.values(attestationSchema.properties)) assert.ok(field.description || field.type === 'object')
|
||||
})
|
||||
|
||||
test('截图隐私审计绑定全部原图哈希并复用公开文本策略', () => {
|
||||
assert.match(ocrValidator, /planned\.length !== 174/)
|
||||
assert.match(ocrValidator, /actualSha256 !== expected\.sha256/)
|
||||
assert.match(ocrValidator, /assertPublicText\(text/)
|
||||
})
|
||||
|
||||
test('公网验证器拒绝 HTTP 重定向后才读取响应', () => {
|
||||
assert.match(deploymentValidator, /redirect:\s*'manual'/)
|
||||
assert.match(deploymentValidator, /response\.status >= 300 && response\.status < 400/)
|
||||
assert.equal([...deploymentValidator.matchAll(/\bfetch\(/g)].length, 1)
|
||||
})
|
||||
Reference in New Issue
Block a user