pumuki-ast-hooks 5.3.16 → 5.3.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/VIOLATIONS_RESOLUTION_PLAN.md +95 -0
- package/docs/alerting-system.md +51 -0
- package/docs/observability.md +36 -0
- package/docs/type-safety.md +8 -0
- package/package.json +1 -1
- package/scripts/hooks-system/.AI_TOKEN_STATUS.txt +1 -1
- package/scripts/hooks-system/.audit-reports/auto-recovery.log +2 -0
- package/scripts/hooks-system/.audit-reports/install-wizard.log +8 -0
- package/scripts/hooks-system/.audit-reports/notifications.log +45 -0
- package/scripts/hooks-system/.audit-reports/token-monitor.log +174 -0
- package/scripts/hooks-system/application/CompositionRoot.js +73 -24
- package/scripts/hooks-system/application/services/DynamicRulesLoader.js +2 -1
- package/scripts/hooks-system/application/services/PlaybookRunner.js +1 -1
- package/scripts/hooks-system/application/services/RealtimeGuardService.js +85 -15
- package/scripts/hooks-system/application/services/guard/GuardAutoManagerService.js +31 -2
- package/scripts/hooks-system/application/services/guard/GuardConfig.js +17 -9
- package/scripts/hooks-system/application/services/guard/GuardHeartbeatMonitor.js +6 -9
- package/scripts/hooks-system/application/services/guard/GuardProcessManager.js +29 -0
- package/scripts/hooks-system/application/services/installation/GitEnvironmentService.js +4 -1
- package/scripts/hooks-system/application/services/installation/McpConfigurator.js +2 -1
- package/scripts/hooks-system/application/services/logging/AuditLogger.js +88 -0
- package/scripts/hooks-system/application/services/logging/UnifiedLogger.js +13 -4
- package/scripts/hooks-system/application/services/monitoring/EvidenceMonitorService.js +7 -3
- package/scripts/hooks-system/application/services/token/TokenMetricsService.js +14 -1
- package/scripts/hooks-system/bin/cli.js +15 -1
- package/scripts/hooks-system/config/env.js +33 -0
- package/scripts/hooks-system/domain/events/__tests__/EventBus.spec.js +33 -0
- package/scripts/hooks-system/domain/events/index.js +32 -6
- package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidAnalysisOrchestrator.js +3 -2
- package/scripts/hooks-system/infrastructure/ast/ast-core.js +12 -20
- package/scripts/hooks-system/infrastructure/ast/ast-intelligence.js +8 -18
- package/scripts/hooks-system/infrastructure/ast/backend/analyzers/BackendPatternDetector.js +2 -1
- package/scripts/hooks-system/infrastructure/ast/backend/ast-backend.js +10 -8
- package/scripts/hooks-system/infrastructure/ast/frontend/ast-frontend.js +196 -196
- package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSASTIntelligentAnalyzer.js +3 -2
- package/scripts/hooks-system/infrastructure/hooks/skill-activation-prompt.js +3 -2
- package/scripts/hooks-system/infrastructure/logging/UnifiedLoggerFactory.js +35 -5
- package/scripts/hooks-system/infrastructure/orchestration/intelligent-audit.js +86 -16
- package/scripts/hooks-system/infrastructure/telemetry/metrics-server.js +51 -2
- package/scripts/hooks-system/infrastructure/validators/enforce-english-literals.js +6 -8
- package/scripts/hooks-system/infrastructure/watchdog/__tests__/.audit-reports/token-monitor.log +3 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const ENV = (process.env.NODE_ENV || 'development').toLowerCase();
|
|
2
|
+
|
|
3
|
+
function normalizeBool(val, defaultValue = false) {
|
|
4
|
+
if (val === undefined) return defaultValue;
|
|
5
|
+
if (typeof val === 'boolean') return val;
|
|
6
|
+
const str = String(val).trim().toLowerCase();
|
|
7
|
+
if (str === '') return defaultValue;
|
|
8
|
+
return !(['false', '0', 'no', 'off'].includes(str));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function get(name, defaultValue = undefined) {
|
|
12
|
+
return process.env[name] !== undefined ? process.env[name] : defaultValue;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getNumber(name, defaultValue = 0) {
|
|
16
|
+
const raw = process.env[name];
|
|
17
|
+
const parsed = Number(raw);
|
|
18
|
+
return Number.isFinite(parsed) ? parsed : defaultValue;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function getBool(name, defaultValue = false) {
|
|
22
|
+
return normalizeBool(process.env[name], defaultValue);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = {
|
|
26
|
+
env: ENV,
|
|
27
|
+
isProd: ENV === 'production',
|
|
28
|
+
isStg: ENV === 'staging' || ENV === 'stage' || ENV === 'stg',
|
|
29
|
+
isDev: ENV === 'development' || ENV === 'dev',
|
|
30
|
+
get,
|
|
31
|
+
getNumber,
|
|
32
|
+
getBool,
|
|
33
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const { EventBus, DomainEvent } = require('..');
|
|
2
|
+
|
|
3
|
+
describe('EventBus', () => {
|
|
4
|
+
test('no reprocesa eventos duplicados (idempotencia por id)', async () => {
|
|
5
|
+
const bus = new EventBus();
|
|
6
|
+
const handled = [];
|
|
7
|
+
bus.subscribe('TEST_EVENT', async (evt) => {
|
|
8
|
+
handled.push(evt.id);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const evt = new DomainEvent('TEST_EVENT', { foo: 'bar' });
|
|
12
|
+
await bus.publish(evt);
|
|
13
|
+
await bus.publish(evt); // segunda vez mismo id
|
|
14
|
+
|
|
15
|
+
expect(handled).toHaveLength(1);
|
|
16
|
+
expect(handled[0]).toBe(evt.id);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('recorta processedIds al superar maxProcessed', async () => {
|
|
20
|
+
const bus = new EventBus();
|
|
21
|
+
bus.maxProcessed = 3;
|
|
22
|
+
bus.subscribe('*', async () => { });
|
|
23
|
+
|
|
24
|
+
const idsBefore = [];
|
|
25
|
+
for (let i = 0; i < 5; i++) {
|
|
26
|
+
const evt = new DomainEvent('TEST_EVENT', { seq: i });
|
|
27
|
+
idsBefore.push(evt.id);
|
|
28
|
+
await bus.publish(evt);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
expect(bus.processedIds.size).toBeLessThanOrEqual(bus.maxProcessed);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const { ValidationError } = require('../errors');
|
|
2
|
+
|
|
1
3
|
class DomainEvent {
|
|
2
4
|
constructor(type, payload) {
|
|
3
5
|
this.type = type;
|
|
@@ -7,8 +9,8 @@ class DomainEvent {
|
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
validate() {
|
|
10
|
-
if (!this.type) throw new
|
|
11
|
-
if (!this.payload) throw new
|
|
12
|
+
if (!this.type) throw new ValidationError('Event type is required', 'type', this.type);
|
|
13
|
+
if (!this.payload) throw new ValidationError('Event payload is required', 'payload', this.payload);
|
|
12
14
|
return true;
|
|
13
15
|
}
|
|
14
16
|
|
|
@@ -29,7 +31,9 @@ class EvidenceStaleEvent extends DomainEvent {
|
|
|
29
31
|
|
|
30
32
|
validate() {
|
|
31
33
|
super.validate();
|
|
32
|
-
if (!this.payload.evidencePath)
|
|
34
|
+
if (!this.payload.evidencePath) {
|
|
35
|
+
throw new ValidationError('Evidence path is required', 'payload.evidencePath', this.payload.evidencePath);
|
|
36
|
+
}
|
|
33
37
|
}
|
|
34
38
|
}
|
|
35
39
|
|
|
@@ -41,8 +45,12 @@ class GitFlowViolationEvent extends DomainEvent {
|
|
|
41
45
|
|
|
42
46
|
validate() {
|
|
43
47
|
super.validate();
|
|
44
|
-
if (!this.payload.branch)
|
|
45
|
-
|
|
48
|
+
if (!this.payload.branch) {
|
|
49
|
+
throw new ValidationError('Branch name is required', 'payload.branch', this.payload.branch);
|
|
50
|
+
}
|
|
51
|
+
if (!this.payload.violation) {
|
|
52
|
+
throw new ValidationError('Violation details are required', 'payload.violation', this.payload.violation);
|
|
53
|
+
}
|
|
46
54
|
}
|
|
47
55
|
}
|
|
48
56
|
|
|
@@ -54,7 +62,9 @@ class AstCriticalFoundEvent extends DomainEvent {
|
|
|
54
62
|
|
|
55
63
|
validate() {
|
|
56
64
|
super.validate();
|
|
57
|
-
if (!Array.isArray(this.payload.findings))
|
|
65
|
+
if (!Array.isArray(this.payload.findings)) {
|
|
66
|
+
throw new ValidationError('Findings must be an array', 'payload.findings', this.payload.findings);
|
|
67
|
+
}
|
|
58
68
|
}
|
|
59
69
|
}
|
|
60
70
|
|
|
@@ -75,6 +85,8 @@ class AnalysisCompletedEvent extends DomainEvent {
|
|
|
75
85
|
class EventBus {
|
|
76
86
|
constructor() {
|
|
77
87
|
this.subscribers = new Map();
|
|
88
|
+
this.processedIds = new Set();
|
|
89
|
+
this.maxProcessed = 500;
|
|
78
90
|
}
|
|
79
91
|
|
|
80
92
|
subscribe(eventType, handler) {
|
|
@@ -94,11 +106,25 @@ class EventBus {
|
|
|
94
106
|
}
|
|
95
107
|
|
|
96
108
|
async publish(event) {
|
|
109
|
+
if (event?.id && this.processedIds.has(event.id)) {
|
|
110
|
+
return event;
|
|
111
|
+
}
|
|
97
112
|
const handlers = this.subscribers.get(event.type) || [];
|
|
98
113
|
const wildcardHandlers = this.subscribers.get('*') || [];
|
|
99
114
|
const allHandlers = [...handlers, ...wildcardHandlers];
|
|
100
115
|
|
|
101
116
|
await Promise.all(allHandlers.map(handler => handler(event)));
|
|
117
|
+
|
|
118
|
+
if (event?.id) {
|
|
119
|
+
this.processedIds.add(event.id);
|
|
120
|
+
if (this.processedIds.size > this.maxProcessed) {
|
|
121
|
+
const iter = this.processedIds.values();
|
|
122
|
+
for (let i = 0; i < 50 && this.processedIds.size > this.maxProcessed; i++) {
|
|
123
|
+
const next = iter.next();
|
|
124
|
+
if (!next.done) this.processedIds.delete(next.value);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
102
128
|
return event;
|
|
103
129
|
}
|
|
104
130
|
|
package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidAnalysisOrchestrator.js
CHANGED
|
@@ -40,8 +40,9 @@ class AndroidAnalysisOrchestrator {
|
|
|
40
40
|
return 0.6745 * (x - med) / madValue;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
const
|
|
44
|
-
const
|
|
43
|
+
const env = require('../../../../config/env');
|
|
44
|
+
const pOutlier = env.getNumber('AST_GODCLASS_P_OUTLIER', 90);
|
|
45
|
+
const pExtreme = env.getNumber('AST_GODCLASS_P_EXTREME', 97);
|
|
45
46
|
|
|
46
47
|
const methods = this.godClassCandidates.map(c => c.methodsCount);
|
|
47
48
|
const props = this.godClassCandidates.map(c => c.propertiesCount);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const { Project, Node, SyntaxKind, ScriptTarget, ModuleKind } = require("ts-morph");
|
|
3
3
|
const path = require("path");
|
|
4
4
|
const fs = require("fs");
|
|
5
|
+
const env = require("../../config/env");
|
|
5
6
|
|
|
6
7
|
let SeverityEvaluator = null;
|
|
7
8
|
let severityEvaluatorInstance = null;
|
|
@@ -19,7 +20,7 @@ function getSeverityEvaluator() {
|
|
|
19
20
|
return severityEvaluatorInstance;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
let INTELLIGENT_SEVERITY_ENABLED =
|
|
23
|
+
let INTELLIGENT_SEVERITY_ENABLED = env.getBool('INTELLIGENT_SEVERITY', false);
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Get repository root directory (portable - dynamic detection)
|
|
@@ -179,18 +180,18 @@ function pushFinding(ruleId, severity, sf, node, message, findings, metrics = {}
|
|
|
179
180
|
let mappedSeverity = mapToLevel(severity);
|
|
180
181
|
const isCleanLayerMarkerRule = ruleId === 'backend.clean.domain' || ruleId === 'backend.clean.application' || ruleId === 'backend.clean.infrastructure' || ruleId === 'backend.clean.presentation';
|
|
181
182
|
let isStrictCriticalRule = false;
|
|
182
|
-
if (
|
|
183
|
+
if (env.get('AUDIT_STRICT', '0') === '1' && !isCleanLayerMarkerRule) {
|
|
183
184
|
const defaultStrictCriticalRegex = '(solid\\.|architecture\\.|clean\\.|cqrs\\.|tdd\\.|bdd\\.|security\\.|error\\.|testing\\.|performance\\.|metrics\\.|observability\\.|validation\\.|i18n\\.|accessibility\\.|naming\\.)';
|
|
184
185
|
const defaultStrictCriticalRegexLibrary = '(solid\\.|architecture\\.|clean\\.|cqrs\\.|tdd\\.|bdd\\.|security\\.|error\\.|testing\\.|validation\\.|naming\\.)';
|
|
185
|
-
const strictRegexSource =
|
|
186
|
-
|
|
187
|
-
?
|
|
186
|
+
const strictRegexSource = env.get('AST_STRICT_CRITICAL_RULES_REGEX',
|
|
187
|
+
env.getBool('AUDIT_LIBRARY', false)
|
|
188
|
+
? env.get('AST_STRICT_CRITICAL_RULES_REGEX_LIBRARY', defaultStrictCriticalRegexLibrary)
|
|
188
189
|
: defaultStrictCriticalRegex);
|
|
189
190
|
let strictRegex;
|
|
190
191
|
try {
|
|
191
192
|
strictRegex = new RegExp(strictRegexSource, 'i');
|
|
192
193
|
} catch {
|
|
193
|
-
strictRegex = new RegExp(
|
|
194
|
+
strictRegex = new RegExp(env.getBool('AUDIT_LIBRARY', false) ? defaultStrictCriticalRegexLibrary : defaultStrictCriticalRegex, 'i');
|
|
194
195
|
}
|
|
195
196
|
isStrictCriticalRule = strictRegex.test(ruleId);
|
|
196
197
|
if (isStrictCriticalRule) {
|
|
@@ -241,18 +242,18 @@ function pushFileFinding(ruleId, severity, filePath, line, column, message, find
|
|
|
241
242
|
let mappedSeverity = mapToLevel(severity);
|
|
242
243
|
const isCleanLayerMarkerRule = ruleId === 'backend.clean.domain' || ruleId === 'backend.clean.application' || ruleId === 'backend.clean.infrastructure' || ruleId === 'backend.clean.presentation';
|
|
243
244
|
let isStrictCriticalRule = false;
|
|
244
|
-
if (
|
|
245
|
+
if (env.get('AUDIT_STRICT', '0') === '1' && !isCleanLayerMarkerRule) {
|
|
245
246
|
const defaultStrictCriticalRegex = '(solid\\.|architecture\\.|clean\\.|cqrs\\.|tdd\\.|bdd\\.|security\\.|error\\.|testing\\.|performance\\.|metrics\\.|observability\\.|validation\\.|i18n\\.|accessibility\\.|naming\\.)';
|
|
246
247
|
const defaultStrictCriticalRegexLibrary = '(solid\\.|architecture\\.|clean\\.|cqrs\\.|tdd\\.|bdd\\.|security\\.|error\\.|testing\\.|validation\\.|naming\\.)';
|
|
247
|
-
const strictRegexSource =
|
|
248
|
-
|
|
249
|
-
?
|
|
248
|
+
const strictRegexSource = env.get('AST_STRICT_CRITICAL_RULES_REGEX',
|
|
249
|
+
env.getBool('AUDIT_LIBRARY', false)
|
|
250
|
+
? env.get('AST_STRICT_CRITICAL_RULES_REGEX_LIBRARY', defaultStrictCriticalRegexLibrary)
|
|
250
251
|
: defaultStrictCriticalRegex);
|
|
251
252
|
let strictRegex;
|
|
252
253
|
try {
|
|
253
254
|
strictRegex = new RegExp(strictRegexSource, 'i');
|
|
254
255
|
} catch {
|
|
255
|
-
strictRegex = new RegExp(
|
|
256
|
+
strictRegex = new RegExp(env.getBool('AUDIT_LIBRARY', false) ? defaultStrictCriticalRegexLibrary : defaultStrictCriticalRegex, 'i');
|
|
256
257
|
}
|
|
257
258
|
isStrictCriticalRule = strictRegex.test(ruleId);
|
|
258
259
|
if (isStrictCriticalRule) {
|
|
@@ -332,15 +333,6 @@ function mapToLevel(severity) {
|
|
|
332
333
|
function platformOf(filePath) {
|
|
333
334
|
const p = filePath.replace(/\\/g, "/");
|
|
334
335
|
|
|
335
|
-
if (p.includes("/infrastructure/ast/") && process.env.AUDIT_LIBRARY !== 'true') return null;
|
|
336
|
-
|
|
337
|
-
if (process.env.AUDIT_LIBRARY === 'true') {
|
|
338
|
-
if (p.includes("/infrastructure/ast/backend/") || p.includes("/scripts/hooks-system/infrastructure/ast/backend/")) return "backend";
|
|
339
|
-
if (p.includes("/infrastructure/ast/frontend/") || p.includes("/scripts/hooks-system/infrastructure/ast/frontend/")) return "frontend";
|
|
340
|
-
if (p.includes("/infrastructure/ast/android/") || p.includes("/scripts/hooks-system/infrastructure/ast/android/")) return "android";
|
|
341
|
-
if (p.includes("/infrastructure/ast/ios/") || p.includes("/scripts/hooks-system/infrastructure/ast/ios/")) return "ios";
|
|
342
|
-
}
|
|
343
|
-
|
|
344
336
|
if (p.includes("/apps/backend/") || p.includes("apps/backend/")) return "backend";
|
|
345
337
|
if (p.includes("/apps/admin/") || p.includes("/admin-dashboard/")) return "frontend";
|
|
346
338
|
if (p.includes("/apps/mobile-ios/") || p.includes("/apps/ios/")) return "ios";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const fs = require("fs");
|
|
4
|
+
const env = require("../../config/env");
|
|
4
5
|
|
|
5
6
|
const astModulesPath = __dirname;
|
|
6
7
|
const { createProject, platformOf, mapToLevel } = require(path.join(astModulesPath, "ast-core"));
|
|
@@ -27,13 +28,7 @@ async function runASTIntelligence() {
|
|
|
27
28
|
const { getRepoRoot } = require('./ast-core');
|
|
28
29
|
const root = getRepoRoot();
|
|
29
30
|
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
const allFiles = listSourceFiles(root).filter(f => {
|
|
33
|
-
const p = String(f || '').replace(/\\/g, '/');
|
|
34
|
-
if (!isLibraryAudit && p.includes('/infrastructure/ast/')) return false;
|
|
35
|
-
return true;
|
|
36
|
-
});
|
|
31
|
+
const allFiles = listSourceFiles(root);
|
|
37
32
|
|
|
38
33
|
const project = createProject(allFiles);
|
|
39
34
|
const findings = [];
|
|
@@ -75,9 +70,9 @@ async function runASTIntelligence() {
|
|
|
75
70
|
}
|
|
76
71
|
|
|
77
72
|
function runProjectHardcodedThresholdAudit(root, allFiles, findings) {
|
|
78
|
-
if (
|
|
73
|
+
if (env.get('AST_INSIGHTS', '0') !== '1') return;
|
|
79
74
|
|
|
80
|
-
const maxFindings =
|
|
75
|
+
const maxFindings = env.getNumber('AST_INSIGHTS_PROJECT_MAX', 200);
|
|
81
76
|
if (!Number.isFinite(maxFindings) || maxFindings <= 0) return;
|
|
82
77
|
|
|
83
78
|
const isExcludedPath = (filePath) => {
|
|
@@ -160,7 +155,7 @@ function runProjectHardcodedThresholdAudit(root, allFiles, findings) {
|
|
|
160
155
|
}
|
|
161
156
|
|
|
162
157
|
function runHardcodedThresholdAudit(root, findings) {
|
|
163
|
-
if (
|
|
158
|
+
if (env.get('AST_INSIGHTS', '0') !== '1') return;
|
|
164
159
|
|
|
165
160
|
const ruleDirs = [
|
|
166
161
|
path.join(root, 'infrastructure', 'ast'),
|
|
@@ -317,7 +312,7 @@ async function runPlatformAnalysis(project, findings, context) {
|
|
|
317
312
|
}
|
|
318
313
|
} catch (error) {
|
|
319
314
|
console.error(`[ERROR] Error processing platform ${platform}:`, error.message);
|
|
320
|
-
if (
|
|
315
|
+
if (env.getBool('DEBUG_AST', false)) {
|
|
321
316
|
console.error(error.stack);
|
|
322
317
|
}
|
|
323
318
|
}
|
|
@@ -376,7 +371,7 @@ function generateOutput(findings, context, project, root) {
|
|
|
376
371
|
* Save detailed JSON report
|
|
377
372
|
*/
|
|
378
373
|
function saveDetailedReport(findings, levelTotals, platformTotals, project, root) {
|
|
379
|
-
const outDir =
|
|
374
|
+
const outDir = env.get('AUDIT_TMP', path.join(root, ".audit_tmp"));
|
|
380
375
|
try {
|
|
381
376
|
fs.mkdirSync(outDir, { recursive: true });
|
|
382
377
|
|
|
@@ -532,7 +527,7 @@ function checkForMigrations(root) {
|
|
|
532
527
|
* List source files recursively
|
|
533
528
|
*/
|
|
534
529
|
function listSourceFiles(root) {
|
|
535
|
-
if (
|
|
530
|
+
if (env.get('STAGING_ONLY_MODE', '0') === "1") {
|
|
536
531
|
const { execSync } = require("child_process");
|
|
537
532
|
try {
|
|
538
533
|
const allStaged = execSync("git diff --cached --name-only --diff-filter=ACM", {
|
|
@@ -600,11 +595,6 @@ function listSourceFiles(root) {
|
|
|
600
595
|
function shouldIgnore(file) {
|
|
601
596
|
const p = file.replace(/\\/g, "/");
|
|
602
597
|
if (p.includes("node_modules/")) return true;
|
|
603
|
-
|
|
604
|
-
const isLibraryAudit = process.env.AUDIT_LIBRARY === 'true';
|
|
605
|
-
|
|
606
|
-
if (!isLibraryAudit && p.includes("scripts/hooks-system/")) return true;
|
|
607
|
-
if (!isLibraryAudit && p.includes("/infrastructure/ast/")) return true;
|
|
608
598
|
if (p.includes("/.cursor/")) return true;
|
|
609
599
|
if (/\.bak/i.test(p)) return true;
|
|
610
600
|
if (p.includes("/.next/")) return true;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const env = require('../../../../config/env');
|
|
3
4
|
|
|
4
5
|
class BackendPatternDetector {
|
|
5
6
|
constructor(projectRoot) {
|
|
@@ -11,7 +12,7 @@ class BackendPatternDetector {
|
|
|
11
12
|
const fullPath = path.join(this.projectRoot, relativePath);
|
|
12
13
|
return fs.readFileSync(fullPath, 'utf-8');
|
|
13
14
|
} catch (error) {
|
|
14
|
-
if (
|
|
15
|
+
if (env.getBool('DEBUG', false)) {
|
|
15
16
|
console.debug(`[BackendPatternDetector] Failed to read file ${relativePath}: ${error.message}`);
|
|
16
17
|
}
|
|
17
18
|
return '';
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
|
|
2
1
|
const path = require('path');
|
|
2
|
+
const env = require('../../../config/env');
|
|
3
3
|
const {
|
|
4
|
+
platformOf,
|
|
4
5
|
pushFinding,
|
|
6
|
+
pushFileFinding,
|
|
5
7
|
mapToLevel,
|
|
6
|
-
|
|
8
|
+
positionOf,
|
|
7
9
|
isTestFile,
|
|
8
|
-
|
|
10
|
+
SyntaxKind,
|
|
9
11
|
hasImport,
|
|
10
12
|
hasDecorator,
|
|
11
13
|
findStringLiterals,
|
|
@@ -119,7 +121,7 @@ function runBackendIntelligence(project, findings, platform) {
|
|
|
119
121
|
const filePath = sf.getFilePath();
|
|
120
122
|
if (platformOf(filePath) !== 'backend') return;
|
|
121
123
|
if (/\/ast-[^/]+\.js$/.test(filePath)) return;
|
|
122
|
-
if (
|
|
124
|
+
if (!env.getBool('AUDIT_LIBRARY', false)) {
|
|
123
125
|
if (/scripts\/hooks-system\/infrastructure\/ast\//i.test(filePath) || /\/infrastructure\/ast\//i.test(filePath)) return;
|
|
124
126
|
}
|
|
125
127
|
if (isTestFile(filePath)) return;
|
|
@@ -144,8 +146,8 @@ function runBackendIntelligence(project, findings, platform) {
|
|
|
144
146
|
|
|
145
147
|
if (metrics.length === 0) return null;
|
|
146
148
|
|
|
147
|
-
const pOutlier =
|
|
148
|
-
const pExtreme =
|
|
149
|
+
const pOutlier = env.getNumber('AST_GODCLASS_P_OUTLIER', 90);
|
|
150
|
+
const pExtreme = env.getNumber('AST_GODCLASS_P_EXTREME', 97);
|
|
149
151
|
|
|
150
152
|
const methods = metrics.map(m => m.methodsCount);
|
|
151
153
|
const props = metrics.map(m => m.propertiesCount);
|
|
@@ -202,12 +204,12 @@ function runBackendIntelligence(project, findings, platform) {
|
|
|
202
204
|
if (platformOf(filePath) !== "backend") return;
|
|
203
205
|
|
|
204
206
|
if (/\/ast-[^/]+\.js$/.test(filePath)) return;
|
|
205
|
-
if (
|
|
207
|
+
if (!env.getBool('AUDIT_LIBRARY', false)) {
|
|
206
208
|
if (/scripts\/hooks-system\/infrastructure\/ast\//i.test(filePath) || /\/infrastructure\/ast\//i.test(filePath)) return;
|
|
207
209
|
}
|
|
208
210
|
|
|
209
211
|
const fullText = sf.getFullText();
|
|
210
|
-
const insightsEnabled =
|
|
212
|
+
const insightsEnabled = env.get('AST_INSIGHTS', '0') === '1';
|
|
211
213
|
const isSpecFile = /\.(spec|test)\.(ts|tsx|js|jsx)$/.test(filePath);
|
|
212
214
|
const secretPattern = /(password|secret|key|token)\s*[:=]\s*['"`]([^'"]{8,})['"`]/gi;
|
|
213
215
|
const matches = Array.from(fullText.matchAll(secretPattern));
|