#!/usr/bin/env node import fs from "node:fs"; import path from "node:path"; const DEFAULT_INDEX = "/home/shunli/Projects/faculty-daily-assistant/公司/00_保密索引/内部资料保密索引_含真实路径_不得外发.csv"; function argValue(name, fallback = null) { const prefix = `${name}=`; const found = process.argv.slice(2).find((item) => item === name || item.startsWith(prefix)); if (!found) return fallback; if (found === name) return "1"; return found.slice(prefix.length); } function parseCsvLine(line) { const cells = []; let current = ""; let quoted = false; for (let index = 0; index < line.length; index += 1) { const char = line[index]; const next = line[index + 1]; if (quoted && char === '"' && next === '"') { current += '"'; index += 1; continue; } if (char === '"') { quoted = !quoted; continue; } if (!quoted && char === ",") { cells.push(current); current = ""; continue; } current += char; } cells.push(current); return cells; } function parseCsv(content) { const lines = content.replace(/^\uFEFF/, "").split(/\r?\n/).filter(Boolean); if (!lines.length) return []; const headers = parseCsvLine(lines[0]).map((item) => item.trim()); return lines.slice(1).map((line) => { const values = parseCsvLine(line); return Object.fromEntries(headers.map((header, index) => [header, values[index] ?? ""])); }); } function mapSensitivity(level) { if (level === "S4") return "strictly_confidential"; if (level === "S3") return "confidential"; if (level === "S1") return "public_candidate"; return "internal"; } const input = argValue("--input", DEFAULT_INDEX); const limit = Number(argValue("--limit", "3")); const reportDir = argValue("--report-dir") ?? path.resolve(process.cwd(), `artifacts/qa-flow/asset-redacted-index-${new Date().toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}`); fs.mkdirSync(reportDir, { recursive: true }); const rows = parseCsv(fs.readFileSync(input, "utf8")); const selected = rows.slice(0, Number.isFinite(limit) && limit > 0 ? limit : 3); const items = selected.map((row, index) => ({ index, code: row.code || null, name: row.doc_type ? `${row.doc_type}-${row.code || index + 1}` : `电子资料-${row.code || index + 1}`, extension: row.extension || null, docType: row.doc_type || null, sourceHash: row.sha256_12 || null, sensitivityLevel: mapSensitivity(row.level), detectedCategories: row.detected_categories || null, requiredRedaction: row.required_redaction || null, rawFileImported: false, })); const bySensitivity = items.reduce((acc, item) => { acc[item.sensitivityLevel] = (acc[item.sensitivityLevel] ?? 0) + 1; return acc; }, {}); const summary = { issueId: "ASSET1", status: "PASS_REDACTED_INDEX_DRY_RUN_READY", mode: "asset-redacted-index-dry-run", input: "local_confidential_index", checkedAt: new Date().toISOString(), totalRows: rows.length, selectedRows: items.length, bySensitivity, items, boundaries: { dryRunOnly: true, noFileUpload: true, noRawContent: true, noFullPathOutput: true, noSecretOutput: true, }, }; fs.writeFileSync(path.join(reportDir, "summary.json"), `${JSON.stringify(summary, null, 2)}\n`, "utf8"); console.log(JSON.stringify(summary, null, 2));