projscan 4.9.3 → 4.10.0
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/README.md +23 -1
- package/dist/analyzers/securityCheck.js +33 -15
- package/dist/analyzers/securityCheck.js.map +1 -1
- package/dist/analyzers/supplyChainCheck.js +9 -2
- package/dist/analyzers/supplyChainCheck.js.map +1 -1
- package/dist/cli/commands/bugHunt.js +3 -1
- package/dist/cli/commands/bugHunt.js.map +1 -1
- package/dist/cli/commands/ci.js +29 -13
- package/dist/cli/commands/ci.js.map +1 -1
- package/dist/cli/commands/dogfood.js +2 -0
- package/dist/cli/commands/dogfood.js.map +1 -1
- package/dist/cli/commands/feedback.js +21 -2
- package/dist/cli/commands/feedback.js.map +1 -1
- package/dist/cli/commands/init.js +3 -0
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/route.js +3 -2
- package/dist/cli/commands/route.js.map +1 -1
- package/dist/core/adoption.js +50 -21
- package/dist/core/adoption.js.map +1 -1
- package/dist/core/agentBrief.js +2 -1
- package/dist/core/agentBrief.js.map +1 -1
- package/dist/core/bugHunt.js +51 -22
- package/dist/core/bugHunt.js.map +1 -1
- package/dist/core/bugHuntHotspotFindings.js +2 -1
- package/dist/core/bugHuntHotspotFindings.js.map +1 -1
- package/dist/core/ciGate.d.ts +10 -0
- package/dist/core/ciGate.js +21 -0
- package/dist/core/ciGate.js.map +1 -0
- package/dist/core/dogfood.d.ts +1 -0
- package/dist/core/dogfood.js +42 -20
- package/dist/core/dogfood.js.map +1 -1
- package/dist/core/dogfoodDiscovery.d.ts +8 -0
- package/dist/core/dogfoodDiscovery.js +119 -0
- package/dist/core/dogfoodDiscovery.js.map +1 -0
- package/dist/core/feedback.js +73 -5
- package/dist/core/feedback.js.map +1 -1
- package/dist/core/fileInspectionReport.js +37 -0
- package/dist/core/fileInspectionReport.js.map +1 -1
- package/dist/core/intentRouterArchitectureKeywordWeights.d.ts +1 -0
- package/dist/core/intentRouterArchitectureKeywordWeights.js +69 -0
- package/dist/core/intentRouterArchitectureKeywordWeights.js.map +1 -0
- package/dist/core/intentRouterCatalog.js +85 -31
- package/dist/core/intentRouterCatalog.js.map +1 -1
- package/dist/core/intentRouterDependencyKeywordWeights.d.ts +1 -0
- package/dist/core/intentRouterDependencyKeywordWeights.js +100 -0
- package/dist/core/intentRouterDependencyKeywordWeights.js.map +1 -0
- package/dist/core/intentRouterFileImpactKeywordWeights.d.ts +1 -0
- package/dist/core/intentRouterFileImpactKeywordWeights.js +92 -0
- package/dist/core/intentRouterFileImpactKeywordWeights.js.map +1 -0
- package/dist/core/intentRouterKeywordEarlyGuards.js +8 -3
- package/dist/core/intentRouterKeywordEarlyGuards.js.map +1 -1
- package/dist/core/intentRouterKeywordSearchGuards.js +28 -24
- package/dist/core/intentRouterKeywordSearchGuards.js.map +1 -1
- package/dist/core/intentRouterKeywordToolGuards.js +43 -0
- package/dist/core/intentRouterKeywordToolGuards.js.map +1 -1
- package/dist/core/intentRouterKeywordWeights.js +40 -1222
- package/dist/core/intentRouterKeywordWeights.js.map +1 -1
- package/dist/core/intentRouterOperationalKeywordWeights.d.ts +1 -0
- package/dist/core/intentRouterOperationalKeywordWeights.js +203 -0
- package/dist/core/intentRouterOperationalKeywordWeights.js.map +1 -0
- package/dist/core/intentRouterPlanningSignals.js +4 -1
- package/dist/core/intentRouterPlanningSignals.js.map +1 -1
- package/dist/core/intentRouterPrDiffKeywords.d.ts +4 -0
- package/dist/core/intentRouterPrDiffKeywords.js +64 -0
- package/dist/core/intentRouterPrDiffKeywords.js.map +1 -0
- package/dist/core/intentRouterPrDiffSignals.js +6 -0
- package/dist/core/intentRouterPrDiffSignals.js.map +1 -1
- package/dist/core/intentRouterProductImprovementSignals.d.ts +1 -0
- package/dist/core/intentRouterProductImprovementSignals.js +48 -0
- package/dist/core/intentRouterProductImprovementSignals.js.map +1 -0
- package/dist/core/intentRouterRegressionKeywordMatches.js +3 -0
- package/dist/core/intentRouterRegressionKeywordMatches.js.map +1 -1
- package/dist/core/intentRouterRegressionKeywordWeights.d.ts +1 -0
- package/dist/core/intentRouterRegressionKeywordWeights.js +118 -0
- package/dist/core/intentRouterRegressionKeywordWeights.js.map +1 -0
- package/dist/core/intentRouterReleaseSignals.d.ts +1 -0
- package/dist/core/intentRouterReleaseSignals.js +47 -0
- package/dist/core/intentRouterReleaseSignals.js.map +1 -1
- package/dist/core/intentRouterReviewSignals.d.ts +1 -0
- package/dist/core/intentRouterReviewSignals.js +23 -1
- package/dist/core/intentRouterReviewSignals.js.map +1 -1
- package/dist/core/intentRouterSearchKeywordWeights.d.ts +1 -0
- package/dist/core/intentRouterSearchKeywordWeights.js +407 -0
- package/dist/core/intentRouterSearchKeywordWeights.js.map +1 -0
- package/dist/core/intentRouterSecurityKeywordWeights.d.ts +1 -0
- package/dist/core/intentRouterSecurityKeywordWeights.js +50 -0
- package/dist/core/intentRouterSecurityKeywordWeights.js.map +1 -0
- package/dist/core/intentRouterTrustFeedbackKeywordWeights.d.ts +1 -0
- package/dist/core/intentRouterTrustFeedbackKeywordWeights.js +222 -0
- package/dist/core/intentRouterTrustFeedbackKeywordWeights.js.map +1 -0
- package/dist/core/intentRouterUnderstandSignals.js +1 -0
- package/dist/core/intentRouterUnderstandSignals.js.map +1 -1
- package/dist/core/intentRouterWorkSignals.js +3 -0
- package/dist/core/intentRouterWorkSignals.js.map +1 -1
- package/dist/core/intentRouterWorkflowKeywordWeights.d.ts +1 -0
- package/dist/core/intentRouterWorkflowKeywordWeights.js +124 -0
- package/dist/core/intentRouterWorkflowKeywordWeights.js.map +1 -0
- package/dist/core/issueEngine.js +46 -2
- package/dist/core/issueEngine.js.map +1 -1
- package/dist/core/memory.d.ts +2 -0
- package/dist/core/memory.js +33 -1
- package/dist/core/memory.js.map +1 -1
- package/dist/core/preflightChangedFiles.d.ts +3 -0
- package/dist/core/preflightChangedFiles.js +13 -0
- package/dist/core/preflightChangedFiles.js.map +1 -1
- package/dist/core/preflightEvidence.d.ts +3 -0
- package/dist/core/preflightEvidence.js +3 -0
- package/dist/core/preflightEvidence.js.map +1 -1
- package/dist/core/privacy.d.ts +2 -0
- package/dist/core/privacy.js +10 -0
- package/dist/core/privacy.js.map +1 -1
- package/dist/core/qualityScorecard.js +25 -13
- package/dist/core/qualityScorecard.js.map +1 -1
- package/dist/core/startEvidence.js +26 -1
- package/dist/core/startEvidence.js.map +1 -1
- package/dist/core/startFixedRouteCriteria.js +5 -0
- package/dist/core/startFixedRouteCriteria.js.map +1 -1
- package/dist/core/startInputs.d.ts +3 -0
- package/dist/core/startMissionPolicy.d.ts +1 -1
- package/dist/core/startMissionPolicy.js +18 -7
- package/dist/core/startMissionPolicy.js.map +1 -1
- package/dist/core/startMode.js +17 -4
- package/dist/core/startMode.js.map +1 -1
- package/dist/core/startReportBuilder.js +1 -1
- package/dist/core/startReportBuilder.js.map +1 -1
- package/dist/core/startReviewGate.js +26 -4
- package/dist/core/startReviewGate.js.map +1 -1
- package/dist/core/startRouteActions.js +6 -0
- package/dist/core/startRouteActions.js.map +1 -1
- package/dist/core/understand.js +60 -13
- package/dist/core/understand.js.map +1 -1
- package/dist/core/workplan.js +99 -17
- package/dist/core/workplan.js.map +1 -1
- package/dist/projscan-sbom.cdx.json +6 -6
- package/dist/reporters/ciIssueDetails.d.ts +10 -0
- package/dist/reporters/ciIssueDetails.js +37 -0
- package/dist/reporters/ciIssueDetails.js.map +1 -0
- package/dist/reporters/consoleCiReporter.d.ts +2 -1
- package/dist/reporters/consoleCiReporter.js +26 -9
- package/dist/reporters/consoleCiReporter.js.map +1 -1
- package/dist/reporters/consoleFileReporter.js +10 -0
- package/dist/reporters/consoleFileReporter.js.map +1 -1
- package/dist/reporters/consoleHealthReporter.js +3 -1
- package/dist/reporters/consoleHealthReporter.js.map +1 -1
- package/dist/reporters/jsonReporter.d.ts +2 -1
- package/dist/reporters/jsonReporter.js +17 -10
- package/dist/reporters/jsonReporter.js.map +1 -1
- package/dist/reporters/markdownFileReporter.js +11 -0
- package/dist/reporters/markdownFileReporter.js.map +1 -1
- package/dist/reporters/markdownHealthReporter.d.ts +2 -1
- package/dist/reporters/markdownHealthReporter.js +5 -5
- package/dist/reporters/markdownHealthReporter.js.map +1 -1
- package/dist/reporters/scoreBreakdownReporter.d.ts +2 -0
- package/dist/reporters/scoreBreakdownReporter.js +24 -0
- package/dist/reporters/scoreBreakdownReporter.js.map +1 -0
- package/dist/tool-manifest.json +2 -2
- package/dist/types/analysis.d.ts +21 -1
- package/dist/types/bugHunt.d.ts +3 -0
- package/dist/types/config.d.ts +9 -0
- package/dist/types/dogfood.d.ts +15 -1
- package/dist/types/inspection.d.ts +3 -0
- package/dist/types/preflight.d.ts +3 -0
- package/dist/types/startMissionControl.d.ts +3 -0
- package/dist/types/startMissionReview.d.ts +2 -0
- package/dist/utils/ciFailOn.d.ts +5 -0
- package/dist/utils/ciFailOn.js +12 -0
- package/dist/utils/ciFailOn.js.map +1 -0
- package/dist/utils/config.js +3 -1
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/configBasics.d.ts +2 -0
- package/dist/utils/configBasics.js +21 -0
- package/dist/utils/configBasics.js.map +1 -1
- package/dist/utils/configIssueRules.js +64 -0
- package/dist/utils/configIssueRules.js.map +1 -1
- package/dist/utils/scoreCalculator.js +77 -16
- package/dist/utils/scoreCalculator.js.map +1 -1
- package/docs/GUIDE.md +36 -6
- package/package.json +1 -1
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
const BASE_SCORE = 100;
|
|
2
|
+
const SEVERITY_WEIGHTS = {
|
|
3
|
+
error: 20,
|
|
4
|
+
warning: 10,
|
|
5
|
+
info: 3,
|
|
6
|
+
};
|
|
1
7
|
/**
|
|
2
8
|
* Calculate a project health score (0–100) and letter grade from detected issues.
|
|
3
9
|
*
|
|
@@ -14,23 +20,78 @@
|
|
|
14
20
|
* F < 60
|
|
15
21
|
*/
|
|
16
22
|
export function calculateScore(issues) {
|
|
17
|
-
const errors = issues
|
|
18
|
-
const warnings = issues
|
|
19
|
-
const infos = issues
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
+
const errors = countSeverity(issues, 'error');
|
|
24
|
+
const warnings = countSeverity(issues, 'warning');
|
|
25
|
+
const infos = countSeverity(issues, 'info');
|
|
26
|
+
const uncappedPenalty = penaltyFor('error', errors) + penaltyFor('warning', warnings) + penaltyFor('info', infos);
|
|
27
|
+
const totalPenalty = Math.min(BASE_SCORE, uncappedPenalty);
|
|
28
|
+
const score = Math.max(0, BASE_SCORE - uncappedPenalty);
|
|
29
|
+
const grade = gradeForScore(score);
|
|
30
|
+
return {
|
|
31
|
+
score,
|
|
32
|
+
grade,
|
|
33
|
+
errors,
|
|
34
|
+
warnings,
|
|
35
|
+
infos,
|
|
36
|
+
scoreBreakdown: buildScoreBreakdown(issues, {
|
|
37
|
+
score,
|
|
38
|
+
grade,
|
|
39
|
+
errors,
|
|
40
|
+
warnings,
|
|
41
|
+
infos,
|
|
42
|
+
totalPenalty,
|
|
43
|
+
uncappedPenalty,
|
|
44
|
+
}),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function countSeverity(issues, severity) {
|
|
48
|
+
return issues.filter((issue) => issue.severity === severity).length;
|
|
49
|
+
}
|
|
50
|
+
function penaltyFor(severity, count) {
|
|
51
|
+
return count * SEVERITY_WEIGHTS[severity];
|
|
52
|
+
}
|
|
53
|
+
function gradeForScore(score) {
|
|
23
54
|
if (score >= 90)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
55
|
+
return 'A';
|
|
56
|
+
if (score >= 80)
|
|
57
|
+
return 'B';
|
|
58
|
+
if (score >= 70)
|
|
59
|
+
return 'C';
|
|
60
|
+
if (score >= 60)
|
|
61
|
+
return 'D';
|
|
62
|
+
return 'F';
|
|
63
|
+
}
|
|
64
|
+
function buildScoreBreakdown(issues, score) {
|
|
65
|
+
return {
|
|
66
|
+
baseScore: BASE_SCORE,
|
|
67
|
+
finalScore: score.score,
|
|
68
|
+
grade: score.grade,
|
|
69
|
+
totalPenalty: score.totalPenalty,
|
|
70
|
+
uncappedPenalty: score.uncappedPenalty,
|
|
71
|
+
bySeverity: {
|
|
72
|
+
error: severityBreakdown(score.errors, 'error'),
|
|
73
|
+
warning: severityBreakdown(score.warnings, 'warning'),
|
|
74
|
+
info: severityBreakdown(score.infos, 'info'),
|
|
75
|
+
},
|
|
76
|
+
byCategory: categoryBreakdown(issues),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function severityBreakdown(count, severity) {
|
|
80
|
+
const weight = SEVERITY_WEIGHTS[severity];
|
|
81
|
+
return { count, weight, penalty: count * weight };
|
|
82
|
+
}
|
|
83
|
+
function categoryBreakdown(issues) {
|
|
84
|
+
const categories = new Map();
|
|
85
|
+
for (const issue of issues) {
|
|
86
|
+
const category = issue.category || 'uncategorized';
|
|
87
|
+
const current = categories.get(category) ?? { count: 0, penalty: 0 };
|
|
88
|
+
current.count += 1;
|
|
89
|
+
current.penalty += SEVERITY_WEIGHTS[issue.severity];
|
|
90
|
+
categories.set(category, current);
|
|
91
|
+
}
|
|
92
|
+
return [...categories.entries()]
|
|
93
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
94
|
+
.map(([category, value]) => ({ category, ...value }));
|
|
34
95
|
}
|
|
35
96
|
const GRADE_COLORS = {
|
|
36
97
|
A: 'brightgreen',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scoreCalculator.js","sourceRoot":"","sources":["../../src/utils/scoreCalculator.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,cAAc,CAAC,MAAe;IAC5C,MAAM,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"scoreCalculator.js","sourceRoot":"","sources":["../../src/utils/scoreCalculator.ts"],"names":[],"mappings":"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"}
|
package/docs/GUIDE.md
CHANGED
|
@@ -551,13 +551,14 @@ Natural follow-up to `projscan hotspots` - once hotspots tells you _which_ file
|
|
|
551
551
|
projscan ci
|
|
552
552
|
```
|
|
553
553
|
|
|
554
|
-
A CI-pipeline-friendly health gate. Runs the full health check and exits with code 1 if the score falls below a threshold. No spinners or banners - clean output for CI logs.
|
|
554
|
+
A CI-pipeline-friendly health gate. Runs the full health check and exits with code 1 if the score falls below a threshold and at least one finding meets the `failOn` severity floor. No spinners or banners - clean output for CI logs.
|
|
555
555
|
|
|
556
556
|
**Options:**
|
|
557
557
|
|
|
558
558
|
| Flag | Description | Default |
|
|
559
559
|
| ------------------ | ------------------------------------------------ | ----------------------------------------------------------- |
|
|
560
560
|
| `--min-score <n>` | Minimum passing score (0–100) | `minScore` from `.projscanrc`, else 70 |
|
|
561
|
+
| `--fail-on <severity>` | Lowest severity that can fail a below-threshold gate: `info`, `warning`, or `error` | `failOn` from `.projscanrc`, else `warning` |
|
|
561
562
|
| `--changed-only` | Gate only on issues in files changed vs base ref | off |
|
|
562
563
|
| `--base-ref <ref>` | Git base ref for `--changed-only` | auto (origin/main → origin/master → main → master → HEAD~1) |
|
|
563
564
|
|
|
@@ -566,7 +567,7 @@ A CI-pipeline-friendly health gate. Runs the full health check and exits with co
|
|
|
566
567
|
```bash
|
|
567
568
|
$ projscan ci --min-score 80
|
|
568
569
|
|
|
569
|
-
projscan: B (82/100) - 0 errors, 2 warnings, 1 info - PASS (threshold: 80)
|
|
570
|
+
projscan: B (82/100) - 0 errors, 2 warnings, 1 info - PASS (threshold: 80, failOn: warning)
|
|
570
571
|
```
|
|
571
572
|
|
|
572
573
|
<img src="npx%20projscan%20ci%20--min-score%2070.gif" alt="npx projscan ci" width="700">
|
|
@@ -574,7 +575,8 @@ projscan: B (82/100) - 0 errors, 2 warnings, 1 info - PASS (threshold: 80)
|
|
|
574
575
|
**Exit codes:**
|
|
575
576
|
|
|
576
577
|
- `0` - Score meets or exceeds the threshold
|
|
577
|
-
- `
|
|
578
|
+
- `0` - Score is below the threshold but no finding meets the `failOn` floor
|
|
579
|
+
- `1` - Score is below the threshold and at least one finding meets the `failOn` floor
|
|
578
580
|
|
|
579
581
|
**JSON output** (useful for scripts):
|
|
580
582
|
|
|
@@ -582,6 +584,10 @@ projscan: B (82/100) - 0 errors, 2 warnings, 1 info - PASS (threshold: 80)
|
|
|
582
584
|
projscan ci --min-score 70 --format json
|
|
583
585
|
```
|
|
584
586
|
|
|
587
|
+
Every `ci.issues[]` item keeps the original issue fields and adds
|
|
588
|
+
annotation-friendly fields: `ruleId`, `message`, primary `location`, all
|
|
589
|
+
`locations`, and `remediation` when a fix hint is available.
|
|
590
|
+
|
|
585
591
|
**SARIF output** (for GitHub Code Scanning or any SARIF consumer):
|
|
586
592
|
|
|
587
593
|
```bash
|
|
@@ -887,6 +893,9 @@ Use it before broader rollout. The report includes feedback questions for the fi
|
|
|
887
893
|
## Health Score
|
|
888
894
|
|
|
889
895
|
Every `projscan doctor` and `projscan badge` run calculates a health score from 0 to 100 based on detected issues.
|
|
896
|
+
`doctor --format json` and `ci --format json` include `scoreBreakdown` so scripts
|
|
897
|
+
and reviewers can see the base score, per-severity weights, category penalties,
|
|
898
|
+
total penalty, final score, and grade.
|
|
890
899
|
|
|
891
900
|
**Scoring:**
|
|
892
901
|
|
|
@@ -909,7 +918,8 @@ Every `projscan doctor` and `projscan badge` run calculates a health score from
|
|
|
909
918
|
The score appears in all output formats:
|
|
910
919
|
|
|
911
920
|
- **Console**: Shown at the top of the doctor report
|
|
912
|
-
- **JSON**: Included as `health.score` and `health.
|
|
921
|
+
- **JSON**: Included as `health.score`, `health.grade`, and `health.scoreBreakdown`
|
|
922
|
+
fields. CI uses the same structure under `ci.scoreBreakdown`.
|
|
913
923
|
- **Markdown**: Shown as a heading with an auto-generated shields.io badge
|
|
914
924
|
- **HTML**: Shown in the health summary card
|
|
915
925
|
- **SARIF**: Not surfaced directly - SARIF is per-issue, not per-project. The score still drives `ci`'s exit code.
|
|
@@ -1005,6 +1015,7 @@ ProjScan loads a project-wide config from one of:
|
|
|
1005
1015
|
```json
|
|
1006
1016
|
{
|
|
1007
1017
|
"minScore": 80,
|
|
1018
|
+
"failOn": "warning",
|
|
1008
1019
|
"baseRef": "origin/main",
|
|
1009
1020
|
"ignore": ["**/fixtures/**", "**/generated/**"],
|
|
1010
1021
|
"scan": {
|
|
@@ -1013,6 +1024,9 @@ ProjScan loads a project-wide config from one of:
|
|
|
1013
1024
|
"offline": false
|
|
1014
1025
|
},
|
|
1015
1026
|
"disableRules": ["missing-editorconfig", "large-*"],
|
|
1027
|
+
"suppress": {
|
|
1028
|
+
"hardcoded-secret": ["src/firebase.ts"]
|
|
1029
|
+
},
|
|
1016
1030
|
"severityOverrides": {
|
|
1017
1031
|
"missing-prettier": "info"
|
|
1018
1032
|
},
|
|
@@ -1034,12 +1048,14 @@ ProjScan loads a project-wide config from one of:
|
|
|
1034
1048
|
| Field | Type | Effect |
|
|
1035
1049
|
| --------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1036
1050
|
| `minScore` | number (0–100) | Default threshold for `projscan ci`. Clamped to 0–100. |
|
|
1051
|
+
| `failOn` | `'info' \| 'warning' \| 'error'` | Lowest severity that can fail a below-threshold `projscan ci` gate. Default `warning`; set `info` for legacy strictness or `error` for error-only blocking. |
|
|
1037
1052
|
| `baseRef` | string | Default base ref for `--changed-only`. |
|
|
1038
1053
|
| `ignore` | string[] | Extra glob patterns added to the built-in ignore list (`node_modules`, `.git`, `dist`, `build`, `coverage`, `.next`, `.nuxt`, `.cache`, `.turbo`, `.output`). |
|
|
1039
1054
|
| `scan.includeIgnored` | boolean | Explicitly include files hidden by Git ignore rules. Default `false`. |
|
|
1040
1055
|
| `scan.scanEnvValues` | boolean | Explicitly read `.env*` contents during secret-pattern checks. Default `false`; `.env` files are path-only. |
|
|
1041
1056
|
| `scan.offline` | boolean | Block projscan network-capable features: telemetry sending, `audit`, registry checks, and optional semantic model loading. Default `false`. |
|
|
1042
1057
|
| `disableRules` | string[] | Silence rules by id. Exact match (`missing-prettier`) or wildcard prefix (`large-*`). |
|
|
1058
|
+
| `suppress` | `Record<string, string[]>` | Silence a rule only for matching paths/globs, for example `{ "hardcoded-secret": ["src/firebase.ts"] }`. Other rules still run on that file. |
|
|
1043
1059
|
| `severityOverrides` | `Record<string, 'info' \| 'warning' \| 'error'>` | Remap a rule's severity. Useful for downgrading project-specific false positives without disabling them. |
|
|
1044
1060
|
| `reportPolicies` | `Record<string, { reportScope?: string[]; redactPaths?: boolean }>` | Named evidence export presets selected with `--report-policy <name>` on `analyze`, `doctor`, and `ci`. |
|
|
1045
1061
|
| `hotspots.limit` | number (1–100) | Default limit for `projscan hotspots`. |
|
|
@@ -1047,6 +1063,12 @@ ProjScan loads a project-wide config from one of:
|
|
|
1047
1063
|
|
|
1048
1064
|
Invalid JSON in a discovered config file is a hard error - projscan exits rather than silently ignoring it.
|
|
1049
1065
|
|
|
1066
|
+
Use inline suppressions for a single confirmed false positive:
|
|
1067
|
+
|
|
1068
|
+
```ts
|
|
1069
|
+
const firebaseKey = "AIza..." // projscan-ignore-line hardcoded-secret -- Firebase web keys are public identifiers
|
|
1070
|
+
```
|
|
1071
|
+
|
|
1050
1072
|
### Embedded config in `package.json`
|
|
1051
1073
|
|
|
1052
1074
|
If you prefer to keep everything in `package.json`:
|
|
@@ -1564,8 +1586,10 @@ If you'd rather skip Code Scanning, `projscan init github-action` writes a pull-
|
|
|
1564
1586
|
The `ci` command is purpose-built for pipelines:
|
|
1565
1587
|
|
|
1566
1588
|
```bash
|
|
1567
|
-
projscan ci # Fail if score < 70
|
|
1589
|
+
projscan ci # Fail if score < 70 and warning/error findings exist
|
|
1568
1590
|
projscan ci --min-score 80 # Custom threshold
|
|
1591
|
+
projscan ci --fail-on info # Legacy strictness: info can fail the gate
|
|
1592
|
+
projscan ci --fail-on error # Only errors can fail a below-threshold gate
|
|
1569
1593
|
projscan ci --changed-only # Gate only on PR diff
|
|
1570
1594
|
projscan ci --format json # JSON output for scripts
|
|
1571
1595
|
projscan ci --format sarif > projscan.sarif # SARIF for any consumer
|
|
@@ -1577,9 +1601,15 @@ projscan ci --format sarif > projscan.sarif # SARIF for any consumer
|
|
|
1577
1601
|
result=$(projscan ci --min-score 0 --format json)
|
|
1578
1602
|
pass=$(echo "$result" | jq '.ci.pass')
|
|
1579
1603
|
score=$(echo "$result" | jq '.ci.score')
|
|
1580
|
-
echo "
|
|
1604
|
+
fail_on=$(echo "$result" | jq -r '.ci.failOn')
|
|
1605
|
+
echo "Score: $score, Pass: $pass, FailOn: $fail_on"
|
|
1581
1606
|
```
|
|
1582
1607
|
|
|
1608
|
+
For PR annotation tooling, read `.ci.issues[]`. Each issue includes `ruleId`,
|
|
1609
|
+
`severity`, `message`, primary `location`, all `locations`, and `remediation`
|
|
1610
|
+
when available. Gate metadata lives at `.ci.failOn`, `.ci.scorePass`, and
|
|
1611
|
+
`.ci.severityFloorMet`.
|
|
1612
|
+
|
|
1583
1613
|
### Tracking health over time in CI
|
|
1584
1614
|
|
|
1585
1615
|
Combine `ci` with `diff` to track regressions:
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "projscan",
|
|
3
3
|
"mcpName": "io.github.abhiyoheswaran1/projscan",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.10.0",
|
|
5
5
|
"description": "Local code intelligence for agent-assisted engineering. Focused daily workflows for repo orientation before edits, proof before handoff or commit, and release-candidate review, with AST-backed evidence through an MCP server and CLI. Runs locally by default.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|