汇总已落盘的借款本金与还款、兼容历史编号的周期化编号、付款责任与回单核验、报销进度和排序、PWA/采购事务、错误原因与日期校验及ERP退役。 统一共享预算池锁序和锁后判断,恢复差旅原预算选择,补原因码固定夹具及反向完整性检查。 纳入配套迁移、测试、受管QA、分层验收合同、规约及任务记录;原始证据留在ignored artifacts。 关联任务:09-17-company-loan-principal-repayment、09-17-erp-exclusive-retirement、09-18-reimbursement-periodic-numbering、09-08-reimbursement-payment-closeout、09-18-local-concurrency-product-fixes、09-19-budget-pool-concurrency、09-05-error-explainability-payment-readiness。 预算补审由Claude定向验证2文件928项通过,原4446/28及r6结果仍仅对应各自历史输入;本轮未重跑测试。 完整新候选门禁、R1真实入口接入与12项公网义务仍开放。生产编号未启用、差旅仍冻结;不推送、不部署,不宣称发布资格。
92 行
3.6 KiB
JavaScript
92 行
3.6 KiB
JavaScript
#!/usr/bin/env node
|
|
// K0 only: synthetic, in-memory inputs. No env/config/backup loader or K2 entry.
|
|
const { randomBytes } = require("node:crypto");
|
|
const {
|
|
resolveFieldEncryptionKey,
|
|
encryptStringOrThrow,
|
|
decryptStringOrThrow,
|
|
} = require("../../server/src/services/crypto");
|
|
|
|
function result(status, reason) {
|
|
return { status, reason };
|
|
}
|
|
|
|
// The expected value belongs to a synthetic fixture, never a real-data probe.
|
|
// Return fixed categories only, including when crypto throws or returns null.
|
|
function checkSyntheticSample(config, encrypted, expectedPlaintext) {
|
|
try {
|
|
const key = resolveFieldEncryptionKey(config);
|
|
if (!key) return result("STOP", "KEY_UNAVAILABLE_OR_INVALID");
|
|
key.fill(0);
|
|
if (encrypted === null || encrypted === undefined || encrypted === "") {
|
|
return result("NOT_TESTED", "EMPTY_FIELD");
|
|
}
|
|
if (typeof encrypted !== "string") return result("STOP", "INVALID_PAYLOAD");
|
|
if (typeof expectedPlaintext !== "string" || !expectedPlaintext) {
|
|
return result("STOP", "SYNTHETIC_EXPECTATION_REQUIRED");
|
|
}
|
|
const plaintext = decryptStringOrThrow(config, encrypted);
|
|
if (plaintext === null) return result("STOP", "INVALID_PAYLOAD");
|
|
if (plaintext !== expectedPlaintext) return result("STOP", "PLAINTEXT_MISMATCH");
|
|
return result("PASS", "SYNTHETIC_MATCH");
|
|
} catch {
|
|
// Never call decryptStringSafe: its warning can contain a raw Error object.
|
|
return result("STOP", "DECRYPTION_FAILED");
|
|
}
|
|
}
|
|
|
|
function runSyntheticContract() {
|
|
const key = randomBytes(32);
|
|
const otherKey = Buffer.from(key);
|
|
otherKey[0] ^= 1;
|
|
try {
|
|
const config = { fieldEncryptionKey: key.toString("base64") };
|
|
const wrongConfig = { fieldEncryptionKey: otherKey.toString("base64") };
|
|
const plaintext = `synthetic-only-${randomBytes(16).toString("hex")}`;
|
|
const encrypted = encryptStringOrThrow(config, plaintext);
|
|
const parts = encrypted.split(":");
|
|
const tag = Buffer.from(parts[2], "base64url");
|
|
tag[0] ^= 1;
|
|
parts[2] = tag.toString("base64url");
|
|
const cases = [
|
|
["correct", config, encrypted, "PASS", "SYNTHETIC_MATCH"],
|
|
["missing", {}, encrypted, "STOP", "KEY_UNAVAILABLE_OR_INVALID"],
|
|
["invalid_key", { fieldEncryptionKey: "invalid" }, encrypted, "STOP", "KEY_UNAVAILABLE_OR_INVALID"],
|
|
["wrong", wrongConfig, encrypted, "STOP", "DECRYPTION_FAILED"],
|
|
["tampered", config, parts.join(":"), "STOP", "DECRYPTION_FAILED"],
|
|
["empty", config, "", "NOT_TESTED", "EMPTY_FIELD"],
|
|
["malformed", config, "v1:invalid", "STOP", "INVALID_PAYLOAD"],
|
|
];
|
|
const checks = cases.map(([category, inputConfig, payload, status, reason]) => {
|
|
const actual = checkSyntheticSample(inputConfig, payload, plaintext);
|
|
return { category, ...actual, matched: actual.status === status && actual.reason === reason };
|
|
});
|
|
return {
|
|
scope: "K0_SYNTHETIC_ONLY",
|
|
status: checks.every((check) => check.matched) ? "PASS" : "FAIL",
|
|
checks,
|
|
originalKeySource: "UNKNOWN",
|
|
custody: "NOT_TESTED",
|
|
realDataDecryption: "NOT_TESTED",
|
|
};
|
|
} finally {
|
|
key.fill(0);
|
|
otherKey.fill(0);
|
|
}
|
|
}
|
|
|
|
if (require.main === module) {
|
|
let report;
|
|
try {
|
|
report = process.argv.length === 2
|
|
? runSyntheticContract()
|
|
: { scope: "K0_SYNTHETIC_ONLY", status: "FAIL", reason: "ARGUMENTS_NOT_ALLOWED" };
|
|
} catch {
|
|
report = { scope: "K0_SYNTHETIC_ONLY", status: "FAIL", reason: "SYNTHETIC_CHECK_FAILED" };
|
|
}
|
|
process.stdout.write(`${JSON.stringify(report)}\n`);
|
|
process.exitCode = report.status === "PASS" ? 0 : 1;
|
|
}
|
|
|
|
module.exports = { checkSyntheticSample, runSyntheticContract };
|