fix: harden tenant auth and quality gates

This commit is contained in:
hectorzhao
2026-08-28 11:44:16 +08:00
parent c3bf8af3e6
commit 2744690f9f
51 changed files with 1750 additions and 466 deletions
+50
View File
@@ -0,0 +1,50 @@
import { execFileSync } from 'node:child_process';
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
const root = resolve(import.meta.dirname, '../..');
const violations = [];
const productionFiles = execFileSync('git', ['ls-files', 'src/apps/**/*.ts', 'src/apps/**/*.tsx', 'src/components/**/*.ts', 'src/components/**/*.tsx'], { cwd: root, encoding: 'utf8' })
.split(/\r?\n/).filter(Boolean);
for (const file of productionFiles) {
const content = readFileSync(resolve(root, file), 'utf8');
if (/from\s+['"]@\/mock(?:\/|['"])/.test(content)) violations.push(`${file}: production code imports @/mock`);
}
const clientControllers = execFileSync('git', ['ls-files', 'api/src/**/*.controller.ts'], { cwd: root, encoding: 'utf8' })
.split(/\r?\n/).filter(Boolean);
for (const file of clientControllers) {
const content = readFileSync(resolve(root, file), 'utf8');
const clientClassOffset = content.indexOf('export class Client');
const clientSection = clientClassOffset >= 0 ? content.slice(clientClassOffset) : content;
if (/['"]client(?:\/|['"])/.test(clientSection) && /@TenantId\(\)/.test(clientSection)) {
violations.push(`${file}: client route still reads request-controlled @TenantId()`);
}
}
const trackedBuildCaches = execFileSync('git', ['ls-files', '*.tsbuildinfo', '**/*.tsbuildinfo'], { cwd: root, encoding: 'utf8' }).trim();
if (trackedBuildCaches) violations.push(`tracked TypeScript build caches: ${trackedBuildCaches.replace(/\r?\n/g, ', ')}`);
const usersService = readFileSync(resolve(root, 'api/src/users/users.service.ts'), 'utf8');
if (/createHash\(['"]sha256['"]\)/.test(usersService)) {
violations.push('api/src/users/users.service.ts: password writes must use the versioned password hasher');
}
const authService = readFileSync(resolve(root, 'api/src/auth/auth.service.ts'), 'utf8');
if (/passwordHash\s*===|===\s*[^\n;]*passwordHash/.test(authService)) {
violations.push('api/src/auth/auth.service.ts: password hashes must not be compared directly');
}
const packageJson = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'));
if (packageJson.dependencies?.['react-router-dom'] !== '7.18.2') {
violations.push('package.json: react-router-dom must remain on the remediated 7.18.2 baseline');
}
if (packageJson.overrides?.nanoid !== '3.3.18') {
violations.push('package.json: nanoid override must remain on the remediated 3.3.18 baseline');
}
if (violations.length) {
console.error(violations.map((item) => `ERROR: ${item}`).join('\n'));
process.exit(1);
}
console.log('Code quality structural checks passed.');