fix(GOV-007): 收紧 Schema 基线安全门禁
This commit is contained in:
@@ -130,9 +130,12 @@ function assertSchemaHasNoSensitiveOrDataStatements(sql) {
|
||||
const sqlWithoutStringLiterals = sql.replace(/'(?:''|\\.|[^'\\])*'/gs, "''");
|
||||
const prohibitedPatterns = [
|
||||
[sqlWithoutStringLiterals, /\bDEFINER\s*=/i, 'DEFINER'],
|
||||
[sql, /^--\s*MySQL dump\b/im, 'MySQL dump 头'],
|
||||
[sql, /--\s*Dump completed on/i, '导出完成时间'],
|
||||
[sql, /--\s*Host:/i, '连接主机注释'],
|
||||
[sql, /\bpassword\s*=/i, '疑似密码'],
|
||||
[sql, /\b(?:password|passwd|pwd|api[_-]?key|api[_-]?token|access[_-]?token|client[_-]?secret|secret)\s*[:=]/i, '疑似凭据'],
|
||||
[sql, /\b(?:mysql|mariadb):\/\/[^\s'"`]+/i, '数据库连接串'],
|
||||
[sql, /\b(?:production|prod)[-_\s]*(?:host|db|database)?\s*[:=]\s*[^\s'"`]+/i, '疑似生产主机'],
|
||||
];
|
||||
for (const [content, pattern, label] of prohibitedPatterns) {
|
||||
if (pattern.test(content)) {
|
||||
@@ -156,11 +159,16 @@ function assertSchemaHasNoSensitiveOrDataStatements(sql) {
|
||||
);
|
||||
}
|
||||
const dataStatement = candidates.find((candidate) =>
|
||||
/^(?:INSERT\s+INTO|REPLACE\s+INTO)\b/i.test(candidate),
|
||||
/^(?:INSERT\s+INTO|REPLACE\s+INTO|UPDATE\b|DELETE\s+FROM\b|TRUNCATE(?:\s+TABLE)?\b|LOAD\s+(?:DATA|XML)\b)/i.test(
|
||||
candidate,
|
||||
),
|
||||
);
|
||||
if (dataStatement) {
|
||||
const operation = dataStatement.match(
|
||||
/^(?:INSERT\s+INTO|REPLACE\s+INTO|UPDATE|DELETE\s+FROM|TRUNCATE(?:\s+TABLE)?|LOAD\s+(?:DATA|XML))/i,
|
||||
)[0];
|
||||
throw new Error(
|
||||
`Schema SQL 包含禁止的数据写入:${dataStatement.match(/^(?:INSERT\s+INTO|REPLACE\s+INTO)/i)[0]}`,
|
||||
`Schema SQL 包含禁止的数据操作:${operation}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -629,13 +637,31 @@ export function getCurrentReleasedVersion(repositoryRoot) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* not_applicable 清单只记录生成当时 MySQL 未启用,不能永久替代真实结构基线。
|
||||
* 每次校验都重新读取固定开发环境配置;一旦开发库启用,旧清单立即失效,强制
|
||||
* 下一版本开发开始前先从开发库生成 captured 基线。
|
||||
*/
|
||||
export function assertNotApplicableMatchesDevelopmentConfiguration(repositoryRoot, result) {
|
||||
if (result.status !== 'not_applicable') return result;
|
||||
|
||||
const config = assertSafeDevelopmentConfiguration(
|
||||
parseEnvironmentFile(readFileSync(resolveFixedDevelopmentEnv(repositoryRoot), 'utf8')),
|
||||
);
|
||||
if (config.MYSQL_ENABLED) {
|
||||
throw new Error('当前开发环境已启用 MySQL,不能继续使用 not_applicable Schema 基线');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function assertCurrentReleasedBaseline(repositoryRoot) {
|
||||
const { applicationVersion, gitCommit } = getCurrentReleasedVersion(repositoryRoot);
|
||||
return verifyBaselineDirectory(
|
||||
const result = verifyBaselineDirectory(
|
||||
path.join(repositoryRoot, 'database', 'schema-baselines', applicationVersion),
|
||||
applicationVersion,
|
||||
gitCommit,
|
||||
);
|
||||
return assertNotApplicableMatchesDevelopmentConfiguration(repositoryRoot, result);
|
||||
}
|
||||
|
||||
function runGitLines(repositoryRoot, args) {
|
||||
@@ -660,6 +686,7 @@ export function assertCurrentReleasedBaselinePublished(repositoryRoot) {
|
||||
release.applicationVersion,
|
||||
release.gitCommit,
|
||||
);
|
||||
assertNotApplicableMatchesDevelopmentConfiguration(repositoryRoot, result);
|
||||
const trackedFiles = new Set(
|
||||
runGitLines(repositoryRoot, ['ls-files', '--', relativeDirectory]),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user