pumuki-ast-hooks 5.3.18 → 5.3.19
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 +23 -25
- package/package.json +2 -2
- package/scripts/hooks-system/application/CompositionRoot.js +24 -73
- package/scripts/hooks-system/application/services/DynamicRulesLoader.js +1 -2
- package/scripts/hooks-system/application/services/GitTreeState.js +139 -13
- package/scripts/hooks-system/application/services/HookSystemScheduler.js +43 -0
- package/scripts/hooks-system/application/services/PlaybookRunner.js +1 -1
- package/scripts/hooks-system/application/services/RealtimeGuardService.js +15 -85
- package/scripts/hooks-system/application/services/guard/GuardAutoManagerService.js +2 -31
- package/scripts/hooks-system/application/services/guard/GuardConfig.js +9 -17
- package/scripts/hooks-system/application/services/guard/GuardHeartbeatMonitor.js +9 -6
- package/scripts/hooks-system/application/services/guard/GuardProcessManager.js +0 -29
- package/scripts/hooks-system/application/services/installation/GitEnvironmentService.js +1 -4
- package/scripts/hooks-system/application/services/installation/McpConfigurator.js +1 -2
- package/scripts/hooks-system/application/services/logging/AuditLogger.js +86 -1
- package/scripts/hooks-system/application/services/logging/UnifiedLogger.js +4 -13
- package/scripts/hooks-system/application/services/monitoring/EvidenceMonitor.js +1 -0
- package/scripts/hooks-system/application/services/monitoring/EvidenceMonitorService.js +3 -7
- package/scripts/hooks-system/application/services/token/TokenMetricsService.js +1 -14
- package/scripts/hooks-system/bin/__tests__/evidence-update.spec.js +49 -0
- package/scripts/hooks-system/bin/cli.js +1 -15
- package/scripts/hooks-system/domain/events/index.js +6 -32
- package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidAnalysisOrchestrator.js +2 -3
- package/scripts/hooks-system/infrastructure/ast/ast-core.js +20 -12
- package/scripts/hooks-system/infrastructure/ast/ast-intelligence.js +18 -8
- package/scripts/hooks-system/infrastructure/ast/backend/analyzers/BackendPatternDetector.js +1 -2
- package/scripts/hooks-system/infrastructure/ast/backend/ast-backend.js +8 -10
- package/scripts/hooks-system/infrastructure/ast/frontend/ast-frontend.js +196 -196
- package/scripts/hooks-system/infrastructure/ast/ios/analyzers/__tests__/iOSASTIntelligentAnalyzer.spec.js +66 -0
- package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSASTIntelligentAnalyzer.js +2 -3
- package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSArchitectureRules.js +24 -86
- package/scripts/hooks-system/infrastructure/hooks/skill-activation-prompt.js +2 -3
- package/scripts/hooks-system/infrastructure/logging/UnifiedLoggerFactory.js +5 -35
- package/scripts/hooks-system/infrastructure/orchestration/intelligent-audit.js +16 -86
- package/scripts/hooks-system/infrastructure/telemetry/metrics-server.js +2 -51
- package/scripts/hooks-system/infrastructure/validators/enforce-english-literals.js +8 -6
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
const { execSync } = require('child_process');
|
|
2
2
|
|
|
3
|
-
// Import recordMetric for prometheus metrics
|
|
4
|
-
const { recordMetric } = require('../../../infrastructure/telemetry/metrics-logger');
|
|
5
|
-
|
|
6
3
|
class TokenMetricsService {
|
|
7
4
|
constructor(cursorTokenService, thresholds, logger) {
|
|
8
5
|
this.cursorTokenService = cursorTokenService;
|
|
@@ -57,8 +54,7 @@ class TokenMetricsService {
|
|
|
57
54
|
if (untrusted) {
|
|
58
55
|
level = 'ok';
|
|
59
56
|
}
|
|
60
|
-
const
|
|
61
|
-
const forceLevel = (env.get('TOKEN_MONITOR_FORCE_LEVEL', '') || '').toLowerCase();
|
|
57
|
+
const forceLevel = (process.env.TOKEN_MONITOR_FORCE_LEVEL || '').toLowerCase();
|
|
62
58
|
if (forceLevel === 'warning' || forceLevel === 'critical' || forceLevel === 'ok') {
|
|
63
59
|
level = forceLevel;
|
|
64
60
|
}
|
|
@@ -79,15 +75,6 @@ class TokenMetricsService {
|
|
|
79
75
|
this.logger.debug('TOKEN_MONITOR_METRICS', metrics);
|
|
80
76
|
}
|
|
81
77
|
|
|
82
|
-
// Record prometheus metrics
|
|
83
|
-
recordMetric({
|
|
84
|
-
hook: 'token_monitor',
|
|
85
|
-
status: 'collect',
|
|
86
|
-
tokensUsed,
|
|
87
|
-
percentUsed: Number(percentUsed.toFixed(0)),
|
|
88
|
-
level
|
|
89
|
-
});
|
|
90
|
-
|
|
91
78
|
return metrics;
|
|
92
79
|
}
|
|
93
80
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
|
|
6
|
+
describe('ast-hooks evidence:update', () => {
|
|
7
|
+
let repoRoot;
|
|
8
|
+
let subdir;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ast-hooks-evidence-cli-'));
|
|
12
|
+
subdir = path.join(repoRoot, 'packages', 'app');
|
|
13
|
+
fs.mkdirSync(subdir, { recursive: true });
|
|
14
|
+
|
|
15
|
+
execSync('git init', { cwd: repoRoot, stdio: 'ignore' });
|
|
16
|
+
execSync('git config user.email "test@example.com"', { cwd: repoRoot, stdio: 'ignore' });
|
|
17
|
+
execSync('git config user.name "Test"', { cwd: repoRoot, stdio: 'ignore' });
|
|
18
|
+
|
|
19
|
+
fs.writeFileSync(path.join(repoRoot, 'README.md'), 'test', 'utf8');
|
|
20
|
+
execSync('git add README.md', { cwd: repoRoot, stdio: 'ignore' });
|
|
21
|
+
execSync('git commit -m "chore: init"', { cwd: repoRoot, stdio: 'ignore' });
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
fs.rmSync(repoRoot, { recursive: true, force: true });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('updates .AI_EVIDENCE.json in repo root even when executed from subdirectory', () => {
|
|
29
|
+
const cliPath = path.resolve(__dirname, '..', 'cli.js');
|
|
30
|
+
const output = execSync(`node ${cliPath} evidence:update`, {
|
|
31
|
+
cwd: subdir,
|
|
32
|
+
encoding: 'utf8',
|
|
33
|
+
env: {
|
|
34
|
+
...process.env,
|
|
35
|
+
AUTO_EVIDENCE_TRIGGER: 'test',
|
|
36
|
+
AUTO_EVIDENCE_REASON: 'test',
|
|
37
|
+
AUTO_EVIDENCE_SUMMARY: 'test'
|
|
38
|
+
}
|
|
39
|
+
}).trim();
|
|
40
|
+
|
|
41
|
+
const evidencePath = path.join(repoRoot, '.AI_EVIDENCE.json');
|
|
42
|
+
expect(fs.realpathSync(output)).toBe(fs.realpathSync(evidencePath));
|
|
43
|
+
expect(fs.existsSync(evidencePath)).toBe(true);
|
|
44
|
+
|
|
45
|
+
const json = JSON.parse(fs.readFileSync(evidencePath, 'utf8'));
|
|
46
|
+
expect(typeof json.timestamp).toBe('string');
|
|
47
|
+
expect(json.timestamp.length).toBeGreaterThan(10);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -121,21 +121,7 @@ const commands = {
|
|
|
121
121
|
},
|
|
122
122
|
|
|
123
123
|
ast: () => {
|
|
124
|
-
|
|
125
|
-
const filteredArgs = [];
|
|
126
|
-
|
|
127
|
-
for (const arg of args) {
|
|
128
|
-
if (arg === '--staged') {
|
|
129
|
-
env.STAGING_ONLY_MODE = '1';
|
|
130
|
-
} else {
|
|
131
|
-
filteredArgs.push(arg);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
execSync(
|
|
136
|
-
`node ${path.join(HOOKS_ROOT, 'infrastructure/ast/ast-intelligence.js')} ${filteredArgs.join(' ')}`,
|
|
137
|
-
{ stdio: 'inherit', env }
|
|
138
|
-
);
|
|
124
|
+
execSync(`node ${path.join(HOOKS_ROOT, 'infrastructure/ast/ast-intelligence.js')}`, { stdio: 'inherit' });
|
|
139
125
|
},
|
|
140
126
|
|
|
141
127
|
install: () => {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
const { ValidationError } = require('../errors');
|
|
2
|
-
|
|
3
1
|
class DomainEvent {
|
|
4
2
|
constructor(type, payload) {
|
|
5
3
|
this.type = type;
|
|
@@ -9,8 +7,8 @@ class DomainEvent {
|
|
|
9
7
|
}
|
|
10
8
|
|
|
11
9
|
validate() {
|
|
12
|
-
if (!this.type) throw new
|
|
13
|
-
if (!this.payload) throw new
|
|
10
|
+
if (!this.type) throw new Error('Event type is required');
|
|
11
|
+
if (!this.payload) throw new Error('Event payload is required');
|
|
14
12
|
return true;
|
|
15
13
|
}
|
|
16
14
|
|
|
@@ -31,9 +29,7 @@ class EvidenceStaleEvent extends DomainEvent {
|
|
|
31
29
|
|
|
32
30
|
validate() {
|
|
33
31
|
super.validate();
|
|
34
|
-
if (!this.payload.evidencePath)
|
|
35
|
-
throw new ValidationError('Evidence path is required', 'payload.evidencePath', this.payload.evidencePath);
|
|
36
|
-
}
|
|
32
|
+
if (!this.payload.evidencePath) throw new Error('Evidence path is required');
|
|
37
33
|
}
|
|
38
34
|
}
|
|
39
35
|
|
|
@@ -45,12 +41,8 @@ class GitFlowViolationEvent extends DomainEvent {
|
|
|
45
41
|
|
|
46
42
|
validate() {
|
|
47
43
|
super.validate();
|
|
48
|
-
if (!this.payload.branch)
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
if (!this.payload.violation) {
|
|
52
|
-
throw new ValidationError('Violation details are required', 'payload.violation', this.payload.violation);
|
|
53
|
-
}
|
|
44
|
+
if (!this.payload.branch) throw new Error('Branch name is required');
|
|
45
|
+
if (!this.payload.violation) throw new Error('Violation details are required');
|
|
54
46
|
}
|
|
55
47
|
}
|
|
56
48
|
|
|
@@ -62,9 +54,7 @@ class AstCriticalFoundEvent extends DomainEvent {
|
|
|
62
54
|
|
|
63
55
|
validate() {
|
|
64
56
|
super.validate();
|
|
65
|
-
if (!Array.isArray(this.payload.findings))
|
|
66
|
-
throw new ValidationError('Findings must be an array', 'payload.findings', this.payload.findings);
|
|
67
|
-
}
|
|
57
|
+
if (!Array.isArray(this.payload.findings)) throw new Error('Findings must be an array');
|
|
68
58
|
}
|
|
69
59
|
}
|
|
70
60
|
|
|
@@ -85,8 +75,6 @@ class AnalysisCompletedEvent extends DomainEvent {
|
|
|
85
75
|
class EventBus {
|
|
86
76
|
constructor() {
|
|
87
77
|
this.subscribers = new Map();
|
|
88
|
-
this.processedIds = new Set();
|
|
89
|
-
this.maxProcessed = 500;
|
|
90
78
|
}
|
|
91
79
|
|
|
92
80
|
subscribe(eventType, handler) {
|
|
@@ -106,25 +94,11 @@ class EventBus {
|
|
|
106
94
|
}
|
|
107
95
|
|
|
108
96
|
async publish(event) {
|
|
109
|
-
if (event?.id && this.processedIds.has(event.id)) {
|
|
110
|
-
return event;
|
|
111
|
-
}
|
|
112
97
|
const handlers = this.subscribers.get(event.type) || [];
|
|
113
98
|
const wildcardHandlers = this.subscribers.get('*') || [];
|
|
114
99
|
const allHandlers = [...handlers, ...wildcardHandlers];
|
|
115
100
|
|
|
116
101
|
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
|
-
}
|
|
128
102
|
return event;
|
|
129
103
|
}
|
|
130
104
|
|
package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidAnalysisOrchestrator.js
CHANGED
|
@@ -40,9 +40,8 @@ class AndroidAnalysisOrchestrator {
|
|
|
40
40
|
return 0.6745 * (x - med) / madValue;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
const pExtreme = env.getNumber('AST_GODCLASS_P_EXTREME', 97);
|
|
43
|
+
const pOutlier = Number(process.env.AST_GODCLASS_P_OUTLIER || 90);
|
|
44
|
+
const pExtreme = Number(process.env.AST_GODCLASS_P_EXTREME || 97);
|
|
46
45
|
|
|
47
46
|
const methods = this.godClassCandidates.map(c => c.methodsCount);
|
|
48
47
|
const props = this.godClassCandidates.map(c => c.propertiesCount);
|
|
@@ -2,7 +2,6 @@
|
|
|
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");
|
|
6
5
|
|
|
7
6
|
let SeverityEvaluator = null;
|
|
8
7
|
let severityEvaluatorInstance = null;
|
|
@@ -20,7 +19,7 @@ function getSeverityEvaluator() {
|
|
|
20
19
|
return severityEvaluatorInstance;
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
let INTELLIGENT_SEVERITY_ENABLED = env.
|
|
22
|
+
let INTELLIGENT_SEVERITY_ENABLED = process.env.INTELLIGENT_SEVERITY === 'true';
|
|
24
23
|
|
|
25
24
|
/**
|
|
26
25
|
* Get repository root directory (portable - dynamic detection)
|
|
@@ -180,18 +179,18 @@ function pushFinding(ruleId, severity, sf, node, message, findings, metrics = {}
|
|
|
180
179
|
let mappedSeverity = mapToLevel(severity);
|
|
181
180
|
const isCleanLayerMarkerRule = ruleId === 'backend.clean.domain' || ruleId === 'backend.clean.application' || ruleId === 'backend.clean.infrastructure' || ruleId === 'backend.clean.presentation';
|
|
182
181
|
let isStrictCriticalRule = false;
|
|
183
|
-
if (env.
|
|
182
|
+
if (process.env.AUDIT_STRICT === '1' && !isCleanLayerMarkerRule) {
|
|
184
183
|
const defaultStrictCriticalRegex = '(solid\\.|architecture\\.|clean\\.|cqrs\\.|tdd\\.|bdd\\.|security\\.|error\\.|testing\\.|performance\\.|metrics\\.|observability\\.|validation\\.|i18n\\.|accessibility\\.|naming\\.)';
|
|
185
184
|
const defaultStrictCriticalRegexLibrary = '(solid\\.|architecture\\.|clean\\.|cqrs\\.|tdd\\.|bdd\\.|security\\.|error\\.|testing\\.|validation\\.|naming\\.)';
|
|
186
|
-
const strictRegexSource = env.
|
|
187
|
-
env.
|
|
188
|
-
? env.
|
|
185
|
+
const strictRegexSource = process.env.AST_STRICT_CRITICAL_RULES_REGEX ||
|
|
186
|
+
(process.env.AUDIT_LIBRARY === 'true'
|
|
187
|
+
? (process.env.AST_STRICT_CRITICAL_RULES_REGEX_LIBRARY || defaultStrictCriticalRegexLibrary)
|
|
189
188
|
: defaultStrictCriticalRegex);
|
|
190
189
|
let strictRegex;
|
|
191
190
|
try {
|
|
192
191
|
strictRegex = new RegExp(strictRegexSource, 'i');
|
|
193
192
|
} catch {
|
|
194
|
-
strictRegex = new RegExp(env.
|
|
193
|
+
strictRegex = new RegExp(process.env.AUDIT_LIBRARY === 'true' ? defaultStrictCriticalRegexLibrary : defaultStrictCriticalRegex, 'i');
|
|
195
194
|
}
|
|
196
195
|
isStrictCriticalRule = strictRegex.test(ruleId);
|
|
197
196
|
if (isStrictCriticalRule) {
|
|
@@ -242,18 +241,18 @@ function pushFileFinding(ruleId, severity, filePath, line, column, message, find
|
|
|
242
241
|
let mappedSeverity = mapToLevel(severity);
|
|
243
242
|
const isCleanLayerMarkerRule = ruleId === 'backend.clean.domain' || ruleId === 'backend.clean.application' || ruleId === 'backend.clean.infrastructure' || ruleId === 'backend.clean.presentation';
|
|
244
243
|
let isStrictCriticalRule = false;
|
|
245
|
-
if (env.
|
|
244
|
+
if (process.env.AUDIT_STRICT === '1' && !isCleanLayerMarkerRule) {
|
|
246
245
|
const defaultStrictCriticalRegex = '(solid\\.|architecture\\.|clean\\.|cqrs\\.|tdd\\.|bdd\\.|security\\.|error\\.|testing\\.|performance\\.|metrics\\.|observability\\.|validation\\.|i18n\\.|accessibility\\.|naming\\.)';
|
|
247
246
|
const defaultStrictCriticalRegexLibrary = '(solid\\.|architecture\\.|clean\\.|cqrs\\.|tdd\\.|bdd\\.|security\\.|error\\.|testing\\.|validation\\.|naming\\.)';
|
|
248
|
-
const strictRegexSource = env.
|
|
249
|
-
env.
|
|
250
|
-
? env.
|
|
247
|
+
const strictRegexSource = process.env.AST_STRICT_CRITICAL_RULES_REGEX ||
|
|
248
|
+
(process.env.AUDIT_LIBRARY === 'true'
|
|
249
|
+
? (process.env.AST_STRICT_CRITICAL_RULES_REGEX_LIBRARY || defaultStrictCriticalRegexLibrary)
|
|
251
250
|
: defaultStrictCriticalRegex);
|
|
252
251
|
let strictRegex;
|
|
253
252
|
try {
|
|
254
253
|
strictRegex = new RegExp(strictRegexSource, 'i');
|
|
255
254
|
} catch {
|
|
256
|
-
strictRegex = new RegExp(env.
|
|
255
|
+
strictRegex = new RegExp(process.env.AUDIT_LIBRARY === 'true' ? defaultStrictCriticalRegexLibrary : defaultStrictCriticalRegex, 'i');
|
|
257
256
|
}
|
|
258
257
|
isStrictCriticalRule = strictRegex.test(ruleId);
|
|
259
258
|
if (isStrictCriticalRule) {
|
|
@@ -333,6 +332,15 @@ function mapToLevel(severity) {
|
|
|
333
332
|
function platformOf(filePath) {
|
|
334
333
|
const p = filePath.replace(/\\/g, "/");
|
|
335
334
|
|
|
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
|
+
|
|
336
344
|
if (p.includes("/apps/backend/") || p.includes("apps/backend/")) return "backend";
|
|
337
345
|
if (p.includes("/apps/admin/") || p.includes("/admin-dashboard/")) return "frontend";
|
|
338
346
|
if (p.includes("/apps/mobile-ios/") || p.includes("/apps/ios/")) return "ios";
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const fs = require("fs");
|
|
4
|
-
const env = require("../../config/env");
|
|
5
4
|
|
|
6
5
|
const astModulesPath = __dirname;
|
|
7
6
|
const { createProject, platformOf, mapToLevel } = require(path.join(astModulesPath, "ast-core"));
|
|
@@ -28,7 +27,13 @@ async function runASTIntelligence() {
|
|
|
28
27
|
const { getRepoRoot } = require('./ast-core');
|
|
29
28
|
const root = getRepoRoot();
|
|
30
29
|
|
|
31
|
-
const
|
|
30
|
+
const isLibraryAudit = process.env.AUDIT_LIBRARY === 'true';
|
|
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
|
+
});
|
|
32
37
|
|
|
33
38
|
const project = createProject(allFiles);
|
|
34
39
|
const findings = [];
|
|
@@ -70,9 +75,9 @@ async function runASTIntelligence() {
|
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
function runProjectHardcodedThresholdAudit(root, allFiles, findings) {
|
|
73
|
-
if (env.
|
|
78
|
+
if (process.env.AST_INSIGHTS !== '1') return;
|
|
74
79
|
|
|
75
|
-
const maxFindings = env.
|
|
80
|
+
const maxFindings = Number(process.env.AST_INSIGHTS_PROJECT_MAX || 200);
|
|
76
81
|
if (!Number.isFinite(maxFindings) || maxFindings <= 0) return;
|
|
77
82
|
|
|
78
83
|
const isExcludedPath = (filePath) => {
|
|
@@ -155,7 +160,7 @@ function runProjectHardcodedThresholdAudit(root, allFiles, findings) {
|
|
|
155
160
|
}
|
|
156
161
|
|
|
157
162
|
function runHardcodedThresholdAudit(root, findings) {
|
|
158
|
-
if (env.
|
|
163
|
+
if (process.env.AST_INSIGHTS !== '1') return;
|
|
159
164
|
|
|
160
165
|
const ruleDirs = [
|
|
161
166
|
path.join(root, 'infrastructure', 'ast'),
|
|
@@ -312,7 +317,7 @@ async function runPlatformAnalysis(project, findings, context) {
|
|
|
312
317
|
}
|
|
313
318
|
} catch (error) {
|
|
314
319
|
console.error(`[ERROR] Error processing platform ${platform}:`, error.message);
|
|
315
|
-
if (env.
|
|
320
|
+
if (process.env.DEBUG_AST) {
|
|
316
321
|
console.error(error.stack);
|
|
317
322
|
}
|
|
318
323
|
}
|
|
@@ -371,7 +376,7 @@ function generateOutput(findings, context, project, root) {
|
|
|
371
376
|
* Save detailed JSON report
|
|
372
377
|
*/
|
|
373
378
|
function saveDetailedReport(findings, levelTotals, platformTotals, project, root) {
|
|
374
|
-
const outDir = env.
|
|
379
|
+
const outDir = process.env.AUDIT_TMP || path.join(root, ".audit_tmp");
|
|
375
380
|
try {
|
|
376
381
|
fs.mkdirSync(outDir, { recursive: true });
|
|
377
382
|
|
|
@@ -527,7 +532,7 @@ function checkForMigrations(root) {
|
|
|
527
532
|
* List source files recursively
|
|
528
533
|
*/
|
|
529
534
|
function listSourceFiles(root) {
|
|
530
|
-
if (env.
|
|
535
|
+
if (process.env.STAGING_ONLY_MODE === "1") {
|
|
531
536
|
const { execSync } = require("child_process");
|
|
532
537
|
try {
|
|
533
538
|
const allStaged = execSync("git diff --cached --name-only --diff-filter=ACM", {
|
|
@@ -595,6 +600,11 @@ function listSourceFiles(root) {
|
|
|
595
600
|
function shouldIgnore(file) {
|
|
596
601
|
const p = file.replace(/\\/g, "/");
|
|
597
602
|
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;
|
|
598
608
|
if (p.includes("/.cursor/")) return true;
|
|
599
609
|
if (/\.bak/i.test(p)) return true;
|
|
600
610
|
if (p.includes("/.next/")) return true;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const env = require('../../../../config/env');
|
|
4
3
|
|
|
5
4
|
class BackendPatternDetector {
|
|
6
5
|
constructor(projectRoot) {
|
|
@@ -12,7 +11,7 @@ class BackendPatternDetector {
|
|
|
12
11
|
const fullPath = path.join(this.projectRoot, relativePath);
|
|
13
12
|
return fs.readFileSync(fullPath, 'utf-8');
|
|
14
13
|
} catch (error) {
|
|
15
|
-
if (env.
|
|
14
|
+
if (process.env.DEBUG) {
|
|
16
15
|
console.debug(`[BackendPatternDetector] Failed to read file ${relativePath}: ${error.message}`);
|
|
17
16
|
}
|
|
18
17
|
return '';
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
+
|
|
1
2
|
const path = require('path');
|
|
2
|
-
const env = require('../../../config/env');
|
|
3
3
|
const {
|
|
4
|
-
platformOf,
|
|
5
4
|
pushFinding,
|
|
6
|
-
pushFileFinding,
|
|
7
5
|
mapToLevel,
|
|
8
|
-
positionOf,
|
|
9
|
-
isTestFile,
|
|
10
6
|
SyntaxKind,
|
|
7
|
+
isTestFile,
|
|
8
|
+
platformOf,
|
|
11
9
|
hasImport,
|
|
12
10
|
hasDecorator,
|
|
13
11
|
findStringLiterals,
|
|
@@ -121,7 +119,7 @@ function runBackendIntelligence(project, findings, platform) {
|
|
|
121
119
|
const filePath = sf.getFilePath();
|
|
122
120
|
if (platformOf(filePath) !== 'backend') return;
|
|
123
121
|
if (/\/ast-[^/]+\.js$/.test(filePath)) return;
|
|
124
|
-
if (
|
|
122
|
+
if (process.env.AUDIT_LIBRARY !== 'true') {
|
|
125
123
|
if (/scripts\/hooks-system\/infrastructure\/ast\//i.test(filePath) || /\/infrastructure\/ast\//i.test(filePath)) return;
|
|
126
124
|
}
|
|
127
125
|
if (isTestFile(filePath)) return;
|
|
@@ -146,8 +144,8 @@ function runBackendIntelligence(project, findings, platform) {
|
|
|
146
144
|
|
|
147
145
|
if (metrics.length === 0) return null;
|
|
148
146
|
|
|
149
|
-
const pOutlier = env.
|
|
150
|
-
const pExtreme = env.
|
|
147
|
+
const pOutlier = Number(process.env.AST_GODCLASS_P_OUTLIER || 90);
|
|
148
|
+
const pExtreme = Number(process.env.AST_GODCLASS_P_EXTREME || 97);
|
|
151
149
|
|
|
152
150
|
const methods = metrics.map(m => m.methodsCount);
|
|
153
151
|
const props = metrics.map(m => m.propertiesCount);
|
|
@@ -204,12 +202,12 @@ function runBackendIntelligence(project, findings, platform) {
|
|
|
204
202
|
if (platformOf(filePath) !== "backend") return;
|
|
205
203
|
|
|
206
204
|
if (/\/ast-[^/]+\.js$/.test(filePath)) return;
|
|
207
|
-
if (
|
|
205
|
+
if (process.env.AUDIT_LIBRARY !== 'true') {
|
|
208
206
|
if (/scripts\/hooks-system\/infrastructure\/ast\//i.test(filePath) || /\/infrastructure\/ast\//i.test(filePath)) return;
|
|
209
207
|
}
|
|
210
208
|
|
|
211
209
|
const fullText = sf.getFullText();
|
|
212
|
-
const insightsEnabled = env.
|
|
210
|
+
const insightsEnabled = process.env.AST_INSIGHTS === '1';
|
|
213
211
|
const isSpecFile = /\.(spec|test)\.(ts|tsx|js|jsx)$/.test(filePath);
|
|
214
212
|
const secretPattern = /(password|secret|key|token)\s*[:=]\s*['"`]([^'"]{8,})['"`]/gi;
|
|
215
213
|
const matches = Array.from(fullText.matchAll(secretPattern));
|