chore(scripts): 侧车导出加固——site-id UUID 校验与 audit 非 CDATA 匹配

评审两条非阻塞加固:--site-id 拼入 SQL 前过 UUID 形态白名单(非 UUID 拒绝并
明确报错);--audit 的 attachment_url 抽取正则同时匹配 CDATA 与裸文本两形态。
对真实数据重跑数字不变(859 条 / 855 对 836 命中,输出哈希一致)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-10-21 15:12:41 +08:00
parent 25dcdf0a4d
commit a185254e19
+13 -4
View File
@@ -37,7 +37,14 @@ const DEFAULT_CONTAINER = 'infrastructure-postgres-1'
const DEFAULT_USER = 'cms' const DEFAULT_USER = 'cms'
const DEFAULT_DB = 'cms' const DEFAULT_DB = 'cms'
/** 唯一一条对 cms 执行的 SQL(只读 SELECT;source_url IS NOT NULL——867 中 8 行 NULL 不带出) */ /** site-id 白名单校验:UUID 形态(评审加固)——SQL 里 site_id 以字面量内插,非 UUID 输入在拼 SQL 前拒绝 */
function assertValidSiteId(siteId) {
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(siteId)) {
throw new Error(`--site-id 不是合法 UUID(36 位形态):${siteId}`)
}
}
/** 唯一一条对 cms 执行的 SQL(只读 SELECT;site_id 已过 UUID 校验;source_url IS NOT NULL——867 中 8 行 NULL 不带出) */
function exportSql(siteId) { function exportSql(siteId) {
return ( return (
`SELECT source_url, file_path FROM media_assets ` + `SELECT source_url, file_path FROM media_assets ` +
@@ -90,9 +97,10 @@ async function auditAgainstWxr(mapPath, wxrPath) {
const sidecarByExact = new Set(map.map((e) => e.sourceUrl)) const sidecarByExact = new Set(map.map((e) => e.sourceUrl))
const sidecarByNormalized = new Set(map.map((e) => normalizeUrl(e.sourceUrl))) const sidecarByNormalized = new Set(map.map((e) => normalizeUrl(e.sourceUrl)))
const wxr = await readFile(wxrPath, 'utf8') const wxr = await readFile(wxrPath, 'utf8')
const attachmentUrls = [...wxr.matchAll(/<wp:attachment_url><!\[CDATA\[([^\]]*)\]\]><\/wp:attachment_url>/g)].map( // CDATA 与裸文本两种形态都匹配(评审加固:WXR 导出器未必总包 CDATA);分支互斥,m[1] ?? m[2]
(m) => m[1], const attachmentUrls = [
) ...wxr.matchAll(/<wp:attachment_url>(?:<!\[CDATA\[([^\]]*)\]\]>|([^<]*))<\/wp:attachment_url>/g),
].map((m) => m[1] ?? m[2] ?? '')
const seen = new Set() const seen = new Set()
const hitsExact = [] // 归一前即完全相等 const hitsExact = [] // 归一前即完全相等
const hitsNormalized = [] // 仅归一后相等(大小写/尾斜杠救回) const hitsNormalized = [] // 仅归一后相等(大小写/尾斜杠救回)
@@ -156,6 +164,7 @@ function parseArgs(argv) {
async function main() { async function main() {
const args = parseArgs(process.argv.slice(2)) const args = parseArgs(process.argv.slice(2))
assertValidSiteId(args.siteId)
const sql = exportSql(args.siteId) const sql = exportSql(args.siteId)
process.stderr.write(`[export-media-map] 只读查询:docker exec ${args.container} psql -U ${args.user} -d ${args.db}\n`) process.stderr.write(`[export-media-map] 只读查询:docker exec ${args.container} psql -U ${args.user} -d ${args.db}\n`)