vaspera 2.9.2 → 2.10.1
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/CHANGELOG.md +68 -0
- package/README.md +58 -1
- package/dist/__tests__/autofix/branch-manager.test.d.ts +2 -0
- package/dist/__tests__/autofix/branch-manager.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/branch-manager.test.js +60 -0
- package/dist/__tests__/autofix/branch-manager.test.js.map +1 -0
- package/dist/__tests__/autofix/commit-generator.test.d.ts +2 -0
- package/dist/__tests__/autofix/commit-generator.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/commit-generator.test.js +147 -0
- package/dist/__tests__/autofix/commit-generator.test.js.map +1 -0
- package/dist/__tests__/autofix/constitution.test.d.ts +9 -0
- package/dist/__tests__/autofix/constitution.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/constitution.test.js +421 -0
- package/dist/__tests__/autofix/constitution.test.js.map +1 -0
- package/dist/__tests__/autofix/pr-generator.test.d.ts +2 -0
- package/dist/__tests__/autofix/pr-generator.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/pr-generator.test.js +152 -0
- package/dist/__tests__/autofix/pr-generator.test.js.map +1 -0
- package/dist/__tests__/property-test-helpers.d.ts +87 -0
- package/dist/__tests__/property-test-helpers.d.ts.map +1 -0
- package/dist/__tests__/property-test-helpers.js +136 -0
- package/dist/__tests__/property-test-helpers.js.map +1 -0
- package/dist/__tests__/scanners/ai-code/ai-detector.test.d.ts +2 -0
- package/dist/__tests__/scanners/ai-code/ai-detector.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/ai-code/ai-detector.test.js +188 -0
- package/dist/__tests__/scanners/ai-code/ai-detector.test.js.map +1 -0
- package/dist/__tests__/scanners/ai-code/confidence-scorer.test.d.ts +2 -0
- package/dist/__tests__/scanners/ai-code/confidence-scorer.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/ai-code/confidence-scorer.test.js +363 -0
- package/dist/__tests__/scanners/ai-code/confidence-scorer.test.js.map +1 -0
- package/dist/__tests__/scanners/ai-code/hallucination-checker.test.d.ts +2 -0
- package/dist/__tests__/scanners/ai-code/hallucination-checker.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/ai-code/hallucination-checker.test.js +226 -0
- package/dist/__tests__/scanners/ai-code/hallucination-checker.test.js.map +1 -0
- package/dist/__tests__/scanners/ai-code/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/ai-code/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/ai-code/index.test.js +214 -0
- package/dist/__tests__/scanners/ai-code/index.test.js.map +1 -0
- package/dist/__tests__/scanners/dast/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/dast/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/dast/index.test.js +183 -0
- package/dist/__tests__/scanners/dast/index.test.js.map +1 -0
- package/dist/__tests__/scanners/dast/nuclei.test.d.ts +2 -0
- package/dist/__tests__/scanners/dast/nuclei.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/dast/nuclei.test.js +166 -0
- package/dist/__tests__/scanners/dast/nuclei.test.js.map +1 -0
- package/dist/__tests__/scanners/dast/zap.test.d.ts +2 -0
- package/dist/__tests__/scanners/dast/zap.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/dast/zap.test.js +158 -0
- package/dist/__tests__/scanners/dast/zap.test.js.map +1 -0
- package/dist/__tests__/scanners/deploy/health-checker.test.d.ts +2 -0
- package/dist/__tests__/scanners/deploy/health-checker.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/deploy/health-checker.test.js +67 -0
- package/dist/__tests__/scanners/deploy/health-checker.test.js.map +1 -0
- package/dist/__tests__/scanners/deploy/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/deploy/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/deploy/index.test.js +84 -0
- package/dist/__tests__/scanners/deploy/index.test.js.map +1 -0
- package/dist/__tests__/scanners/deploy/provider-detector.test.d.ts +2 -0
- package/dist/__tests__/scanners/deploy/provider-detector.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/deploy/provider-detector.test.js +88 -0
- package/dist/__tests__/scanners/deploy/provider-detector.test.js.map +1 -0
- package/dist/__tests__/scanners/deploy/types.test.d.ts +2 -0
- package/dist/__tests__/scanners/deploy/types.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/deploy/types.test.js +126 -0
- package/dist/__tests__/scanners/deploy/types.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-feedback.test.d.ts +2 -0
- package/dist/__tests__/scanners/fp-feedback.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-feedback.test.js +202 -0
- package/dist/__tests__/scanners/fp-feedback.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-filter.property.test.d.ts +9 -0
- package/dist/__tests__/scanners/fp-filter.property.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-filter.property.test.js +253 -0
- package/dist/__tests__/scanners/fp-filter.property.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-filter.test.d.ts +2 -0
- package/dist/__tests__/scanners/fp-filter.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-filter.test.js +234 -0
- package/dist/__tests__/scanners/fp-filter.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-tracker.test.d.ts +2 -0
- package/dist/__tests__/scanners/fp-tracker.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-tracker.test.js +262 -0
- package/dist/__tests__/scanners/fp-tracker.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.d.ts +10 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.js +238 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.d.ts +2 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.js +55 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/logic/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/index.test.js +165 -0
- package/dist/__tests__/scanners/logic/index.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/types.test.d.ts +2 -0
- package/dist/__tests__/scanners/logic/types.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/types.test.js +85 -0
- package/dist/__tests__/scanners/logic/types.test.js.map +1 -0
- package/dist/__tests__/scanners/runtime/app-launcher.test.d.ts +2 -0
- package/dist/__tests__/scanners/runtime/app-launcher.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/runtime/app-launcher.test.js +94 -0
- package/dist/__tests__/scanners/runtime/app-launcher.test.js.map +1 -0
- package/dist/__tests__/scanners/runtime/golden-path-runner.test.d.ts +2 -0
- package/dist/__tests__/scanners/runtime/golden-path-runner.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/runtime/golden-path-runner.test.js +195 -0
- package/dist/__tests__/scanners/runtime/golden-path-runner.test.js.map +1 -0
- package/dist/__tests__/scanners/runtime/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/runtime/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/runtime/index.test.js +120 -0
- package/dist/__tests__/scanners/runtime/index.test.js.map +1 -0
- package/dist/__tests__/scanners/runtime/types.test.d.ts +2 -0
- package/dist/__tests__/scanners/runtime/types.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/runtime/types.test.js +126 -0
- package/dist/__tests__/scanners/runtime/types.test.js.map +1 -0
- package/dist/__tests__/scanners/scale/bottleneck-detector.test.d.ts +2 -0
- package/dist/__tests__/scanners/scale/bottleneck-detector.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/scale/bottleneck-detector.test.js +187 -0
- package/dist/__tests__/scanners/scale/bottleneck-detector.test.js.map +1 -0
- package/dist/__tests__/scanners/scale/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/scale/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/scale/index.test.js +87 -0
- package/dist/__tests__/scanners/scale/index.test.js.map +1 -0
- package/dist/__tests__/scanners/scale/load-profiler.test.d.ts +2 -0
- package/dist/__tests__/scanners/scale/load-profiler.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/scale/load-profiler.test.js +122 -0
- package/dist/__tests__/scanners/scale/load-profiler.test.js.map +1 -0
- package/dist/__tests__/scanners/scale/types.test.d.ts +2 -0
- package/dist/__tests__/scanners/scale/types.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/scale/types.test.js +129 -0
- package/dist/__tests__/scanners/scale/types.test.js.map +1 -0
- package/dist/action/pr-comment.test.js +4 -0
- package/dist/action/pr-comment.test.js.map +1 -1
- package/dist/action/sarif-upload.test.js +4 -0
- package/dist/action/sarif-upload.test.js.map +1 -1
- package/dist/autofix/branch-manager.d.ts +115 -0
- package/dist/autofix/branch-manager.d.ts.map +1 -0
- package/dist/autofix/branch-manager.js +308 -0
- package/dist/autofix/branch-manager.js.map +1 -0
- package/dist/autofix/commit-generator.d.ts +55 -0
- package/dist/autofix/commit-generator.d.ts.map +1 -0
- package/dist/autofix/commit-generator.js +277 -0
- package/dist/autofix/commit-generator.js.map +1 -0
- package/dist/autofix/constitution.d.ts +77 -0
- package/dist/autofix/constitution.d.ts.map +1 -0
- package/dist/autofix/constitution.js +261 -0
- package/dist/autofix/constitution.js.map +1 -0
- package/dist/autofix/constitution.schema.d.ts +441 -0
- package/dist/autofix/constitution.schema.d.ts.map +1 -0
- package/dist/autofix/constitution.schema.js +144 -0
- package/dist/autofix/constitution.schema.js.map +1 -0
- package/dist/autofix/index.d.ts +13 -0
- package/dist/autofix/index.d.ts.map +1 -0
- package/dist/autofix/index.js +15 -0
- package/dist/autofix/index.js.map +1 -0
- package/dist/autofix/pr-generator.d.ts +57 -0
- package/dist/autofix/pr-generator.d.ts.map +1 -0
- package/dist/autofix/pr-generator.js +597 -0
- package/dist/autofix/pr-generator.js.map +1 -0
- package/dist/autofix/types.d.ts +151 -0
- package/dist/autofix/types.d.ts.map +1 -0
- package/dist/autofix/types.js +22 -0
- package/dist/autofix/types.js.map +1 -0
- package/dist/eval/fixtures.d.ts +20 -0
- package/dist/eval/fixtures.d.ts.map +1 -1
- package/dist/eval/fixtures.js +430 -0
- package/dist/eval/fixtures.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +874 -0
- package/dist/index.js.map +1 -1
- package/dist/install-skills.d.ts +11 -0
- package/dist/install-skills.d.ts.map +1 -0
- package/dist/install-skills.js +81 -0
- package/dist/install-skills.js.map +1 -0
- package/dist/scanners/ai-code/ai-detector.d.ts +25 -0
- package/dist/scanners/ai-code/ai-detector.d.ts.map +1 -0
- package/dist/scanners/ai-code/ai-detector.js +192 -0
- package/dist/scanners/ai-code/ai-detector.js.map +1 -0
- package/dist/scanners/ai-code/confidence-scorer.d.ts +40 -0
- package/dist/scanners/ai-code/confidence-scorer.d.ts.map +1 -0
- package/dist/scanners/ai-code/confidence-scorer.js +148 -0
- package/dist/scanners/ai-code/confidence-scorer.js.map +1 -0
- package/dist/scanners/ai-code/hallucination-checker.d.ts +36 -0
- package/dist/scanners/ai-code/hallucination-checker.d.ts.map +1 -0
- package/dist/scanners/ai-code/hallucination-checker.js +298 -0
- package/dist/scanners/ai-code/hallucination-checker.js.map +1 -0
- package/dist/scanners/ai-code/index.d.ts +30 -0
- package/dist/scanners/ai-code/index.d.ts.map +1 -0
- package/dist/scanners/ai-code/index.js +224 -0
- package/dist/scanners/ai-code/index.js.map +1 -0
- package/dist/scanners/ai-code/types.d.ts +192 -0
- package/dist/scanners/ai-code/types.d.ts.map +1 -0
- package/dist/scanners/ai-code/types.js +37 -0
- package/dist/scanners/ai-code/types.js.map +1 -0
- package/dist/scanners/cache.d.ts.map +1 -1
- package/dist/scanners/cache.js +4 -0
- package/dist/scanners/cache.js.map +1 -1
- package/dist/scanners/dast/index.d.ts +39 -0
- package/dist/scanners/dast/index.d.ts.map +1 -0
- package/dist/scanners/dast/index.js +259 -0
- package/dist/scanners/dast/index.js.map +1 -0
- package/dist/scanners/dast/nuclei.d.ts +26 -0
- package/dist/scanners/dast/nuclei.d.ts.map +1 -0
- package/dist/scanners/dast/nuclei.js +354 -0
- package/dist/scanners/dast/nuclei.js.map +1 -0
- package/dist/scanners/dast/types.d.ts +306 -0
- package/dist/scanners/dast/types.d.ts.map +1 -0
- package/dist/scanners/dast/types.js +52 -0
- package/dist/scanners/dast/types.js.map +1 -0
- package/dist/scanners/dast/zap.d.ts +26 -0
- package/dist/scanners/dast/zap.d.ts.map +1 -0
- package/dist/scanners/dast/zap.js +453 -0
- package/dist/scanners/dast/zap.js.map +1 -0
- package/dist/scanners/deploy/health-checker.d.ts +38 -0
- package/dist/scanners/deploy/health-checker.d.ts.map +1 -0
- package/dist/scanners/deploy/health-checker.js +272 -0
- package/dist/scanners/deploy/health-checker.js.map +1 -0
- package/dist/scanners/deploy/index.d.ts +44 -0
- package/dist/scanners/deploy/index.d.ts.map +1 -0
- package/dist/scanners/deploy/index.js +208 -0
- package/dist/scanners/deploy/index.js.map +1 -0
- package/dist/scanners/deploy/provider-detector.d.ts +25 -0
- package/dist/scanners/deploy/provider-detector.d.ts.map +1 -0
- package/dist/scanners/deploy/provider-detector.js +177 -0
- package/dist/scanners/deploy/provider-detector.js.map +1 -0
- package/dist/scanners/deploy/types.d.ts +406 -0
- package/dist/scanners/deploy/types.d.ts.map +1 -0
- package/dist/scanners/deploy/types.js +58 -0
- package/dist/scanners/deploy/types.js.map +1 -0
- package/dist/scanners/deploy/vercel-integration.d.ts +52 -0
- package/dist/scanners/deploy/vercel-integration.d.ts.map +1 -0
- package/dist/scanners/deploy/vercel-integration.js +280 -0
- package/dist/scanners/deploy/vercel-integration.js.map +1 -0
- package/dist/scanners/fp-feedback.d.ts +140 -0
- package/dist/scanners/fp-feedback.d.ts.map +1 -0
- package/dist/scanners/fp-feedback.js +292 -0
- package/dist/scanners/fp-feedback.js.map +1 -0
- package/dist/scanners/fp-filter.d.ts +94 -0
- package/dist/scanners/fp-filter.d.ts.map +1 -0
- package/dist/scanners/fp-filter.js +397 -0
- package/dist/scanners/fp-filter.js.map +1 -0
- package/dist/scanners/fp-tracker.d.ts +125 -0
- package/dist/scanners/fp-tracker.d.ts.map +1 -0
- package/dist/scanners/fp-tracker.js +330 -0
- package/dist/scanners/fp-tracker.js.map +1 -0
- package/dist/scanners/index.d.ts.map +1 -1
- package/dist/scanners/index.js +56 -0
- package/dist/scanners/index.js.map +1 -1
- package/dist/scanners/index.test.js +6 -6
- package/dist/scanners/index.test.js.map +1 -1
- package/dist/scanners/logic/auth-flow-analyzer.d.ts +18 -0
- package/dist/scanners/logic/auth-flow-analyzer.d.ts.map +1 -0
- package/dist/scanners/logic/auth-flow-analyzer.js +384 -0
- package/dist/scanners/logic/auth-flow-analyzer.js.map +1 -0
- package/dist/scanners/logic/endpoint-analyzer.d.ts +29 -0
- package/dist/scanners/logic/endpoint-analyzer.d.ts.map +1 -0
- package/dist/scanners/logic/endpoint-analyzer.js +528 -0
- package/dist/scanners/logic/endpoint-analyzer.js.map +1 -0
- package/dist/scanners/logic/index.d.ts +41 -0
- package/dist/scanners/logic/index.d.ts.map +1 -0
- package/dist/scanners/logic/index.js +268 -0
- package/dist/scanners/logic/index.js.map +1 -0
- package/dist/scanners/logic/types.d.ts +254 -0
- package/dist/scanners/logic/types.d.ts.map +1 -0
- package/dist/scanners/logic/types.js +142 -0
- package/dist/scanners/logic/types.js.map +1 -0
- package/dist/scanners/runtime/app-launcher.d.ts +33 -0
- package/dist/scanners/runtime/app-launcher.d.ts.map +1 -0
- package/dist/scanners/runtime/app-launcher.js +419 -0
- package/dist/scanners/runtime/app-launcher.js.map +1 -0
- package/dist/scanners/runtime/golden-path-runner.d.ts +48 -0
- package/dist/scanners/runtime/golden-path-runner.d.ts.map +1 -0
- package/dist/scanners/runtime/golden-path-runner.js +373 -0
- package/dist/scanners/runtime/golden-path-runner.js.map +1 -0
- package/dist/scanners/runtime/index.d.ts +41 -0
- package/dist/scanners/runtime/index.d.ts.map +1 -0
- package/dist/scanners/runtime/index.js +164 -0
- package/dist/scanners/runtime/index.js.map +1 -0
- package/dist/scanners/runtime/playwright-executor.d.ts +50 -0
- package/dist/scanners/runtime/playwright-executor.d.ts.map +1 -0
- package/dist/scanners/runtime/playwright-executor.js +387 -0
- package/dist/scanners/runtime/playwright-executor.js.map +1 -0
- package/dist/scanners/runtime/types.d.ts +215 -0
- package/dist/scanners/runtime/types.d.ts.map +1 -0
- package/dist/scanners/runtime/types.js +40 -0
- package/dist/scanners/runtime/types.js.map +1 -0
- package/dist/scanners/scale/bottleneck-detector.d.ts +17 -0
- package/dist/scanners/scale/bottleneck-detector.d.ts.map +1 -0
- package/dist/scanners/scale/bottleneck-detector.js +250 -0
- package/dist/scanners/scale/bottleneck-detector.js.map +1 -0
- package/dist/scanners/scale/capacity-estimator.d.ts +17 -0
- package/dist/scanners/scale/capacity-estimator.d.ts.map +1 -0
- package/dist/scanners/scale/capacity-estimator.js +197 -0
- package/dist/scanners/scale/capacity-estimator.js.map +1 -0
- package/dist/scanners/scale/index.d.ts +37 -0
- package/dist/scanners/scale/index.d.ts.map +1 -0
- package/dist/scanners/scale/index.js +101 -0
- package/dist/scanners/scale/index.js.map +1 -0
- package/dist/scanners/scale/load-profiler.d.ts +48 -0
- package/dist/scanners/scale/load-profiler.d.ts.map +1 -0
- package/dist/scanners/scale/load-profiler.js +377 -0
- package/dist/scanners/scale/load-profiler.js.map +1 -0
- package/dist/scanners/scale/types.d.ts +529 -0
- package/dist/scanners/scale/types.d.ts.map +1 -0
- package/dist/scanners/scale/types.js +57 -0
- package/dist/scanners/scale/types.js.map +1 -0
- package/dist/scanners/secrets.d.ts.map +1 -1
- package/dist/scanners/secrets.js +13 -2
- package/dist/scanners/secrets.js.map +1 -1
- package/dist/scanners/types.d.ts +1 -1
- package/dist/scanners/types.d.ts.map +1 -1
- package/dist/scanners/types.js +4 -0
- package/dist/scanners/types.js.map +1 -1
- package/package.json +8 -4
- package/skills/vaspera-add-tests/SKILL.md +102 -0
- package/skills/vaspera-ai-verify/SKILL.md +166 -0
- package/skills/vaspera-audit/SKILL.md +67 -0
- package/skills/vaspera-certify/SKILL.md +130 -0
- package/skills/vaspera-deploy/SKILL.md +152 -0
- package/skills/vaspera-fix-critical/SKILL.md +52 -0
- package/skills/vaspera-fix-high/SKILL.md +81 -0
- package/skills/vaspera-fix-medium/SKILL.md +56 -0
- package/skills/vaspera-fix-rls/SKILL.md +85 -0
- package/skills/vaspera-harden/SKILL.md +102 -0
- package/skills/vaspera-help/SKILL.md +61 -0
- package/skills/vaspera-load-test/SKILL.md +167 -0
- package/skills/vaspera-verify/SKILL.md +70 -0
- package/skills/vaspera-verify-e2e/SKILL.md +117 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* False Positive Feedback
|
|
3
|
+
*
|
|
4
|
+
* Handles user feedback on findings and maintains a feedback database
|
|
5
|
+
* for improving FP detection over time.
|
|
6
|
+
*
|
|
7
|
+
* @module scanners/fp-feedback
|
|
8
|
+
*/
|
|
9
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
10
|
+
import { join, dirname } from "path";
|
|
11
|
+
import { markFalsePositive, markTruePositive } from "./fp-tracker.js";
|
|
12
|
+
import { logger } from "../logger.js";
|
|
13
|
+
/**
|
|
14
|
+
* FP reason descriptions for UI
|
|
15
|
+
*/
|
|
16
|
+
export const FP_REASON_DESCRIPTIONS = {
|
|
17
|
+
"test-code": "Finding is in test code and doesn't affect production",
|
|
18
|
+
"false-pattern-match": "Pattern matched but context shows it's not a real issue",
|
|
19
|
+
"sanitized-elsewhere": "Input is sanitized/validated elsewhere in the codebase",
|
|
20
|
+
"intentional": "This is intentional behavior (documented risk acceptance)",
|
|
21
|
+
"vendor-code": "Third-party/vendored code that cannot be modified",
|
|
22
|
+
"generated-code": "Auto-generated code that will be regenerated",
|
|
23
|
+
"example-code": "Example/demo code not used in production",
|
|
24
|
+
"configuration": "Scanner configuration issue (rule too broad)",
|
|
25
|
+
"other": "Other reason (specify in details)",
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Get feedback file path
|
|
29
|
+
*/
|
|
30
|
+
function getFeedbackFilePath(projectPath) {
|
|
31
|
+
return join(projectPath, ".vaspera", "fp-feedback.json");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Generate unique feedback ID
|
|
35
|
+
*/
|
|
36
|
+
function generateFeedbackId() {
|
|
37
|
+
return `fb-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Load feedback database
|
|
41
|
+
*/
|
|
42
|
+
export async function loadFeedbackDatabase(projectPath) {
|
|
43
|
+
const filePath = getFeedbackFilePath(projectPath);
|
|
44
|
+
try {
|
|
45
|
+
const content = await readFile(filePath, "utf-8");
|
|
46
|
+
return JSON.parse(content);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return {
|
|
50
|
+
version: "1.0.0",
|
|
51
|
+
projectPath,
|
|
52
|
+
entries: [],
|
|
53
|
+
stats: {
|
|
54
|
+
totalFeedback: 0,
|
|
55
|
+
tpCount: 0,
|
|
56
|
+
fpCount: 0,
|
|
57
|
+
byScanner: {},
|
|
58
|
+
byReason: {},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Save feedback database
|
|
65
|
+
*/
|
|
66
|
+
export async function saveFeedbackDatabase(projectPath, db) {
|
|
67
|
+
const filePath = getFeedbackFilePath(projectPath);
|
|
68
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
69
|
+
await writeFile(filePath, JSON.stringify(db, null, 2), "utf-8");
|
|
70
|
+
logger.debug("fp_feedback.saved", { filePath, entries: db.entries.length });
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Submit feedback for a finding
|
|
74
|
+
*/
|
|
75
|
+
export async function submitFeedback(projectPath, finding, verdict, options) {
|
|
76
|
+
const db = await loadFeedbackDatabase(projectPath);
|
|
77
|
+
// Create feedback entry
|
|
78
|
+
const entry = {
|
|
79
|
+
id: generateFeedbackId(),
|
|
80
|
+
findingId: `${finding.scanner}-${finding.ruleId}-${finding.file}:${finding.line}`,
|
|
81
|
+
scanner: finding.scanner,
|
|
82
|
+
ruleId: finding.ruleId,
|
|
83
|
+
file: finding.file,
|
|
84
|
+
line: finding.line,
|
|
85
|
+
severity: finding.severity,
|
|
86
|
+
verdict,
|
|
87
|
+
reason: verdict === "fp" ? options?.reason : undefined,
|
|
88
|
+
details: options?.details,
|
|
89
|
+
submittedBy: options?.submittedBy,
|
|
90
|
+
submittedAt: new Date().toISOString(),
|
|
91
|
+
codeHash: options?.codeHash,
|
|
92
|
+
};
|
|
93
|
+
// Add to database
|
|
94
|
+
db.entries.push(entry);
|
|
95
|
+
// Update stats
|
|
96
|
+
db.stats.totalFeedback++;
|
|
97
|
+
if (verdict === "tp") {
|
|
98
|
+
db.stats.tpCount++;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
db.stats.fpCount++;
|
|
102
|
+
if (options?.reason) {
|
|
103
|
+
db.stats.byReason[options.reason] = (db.stats.byReason[options.reason] || 0) + 1;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Update scanner stats
|
|
107
|
+
if (!db.stats.byScanner[finding.scanner]) {
|
|
108
|
+
db.stats.byScanner[finding.scanner] = { tp: 0, fp: 0 };
|
|
109
|
+
}
|
|
110
|
+
db.stats.byScanner[finding.scanner][verdict]++;
|
|
111
|
+
await saveFeedbackDatabase(projectPath, db);
|
|
112
|
+
// Also update the FP tracker
|
|
113
|
+
if (verdict === "fp") {
|
|
114
|
+
await markFalsePositive(projectPath, finding.scanner, finding.ruleId, options?.reason);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
await markTruePositive(projectPath, finding.scanner, finding.ruleId);
|
|
118
|
+
}
|
|
119
|
+
logger.info("fp_feedback.submitted", {
|
|
120
|
+
id: entry.id,
|
|
121
|
+
scanner: finding.scanner,
|
|
122
|
+
ruleId: finding.ruleId,
|
|
123
|
+
verdict,
|
|
124
|
+
reason: options?.reason,
|
|
125
|
+
});
|
|
126
|
+
return entry;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Get feedback for a specific finding
|
|
130
|
+
*/
|
|
131
|
+
export async function getFeedbackForFinding(projectPath, scanner, ruleId, file, line) {
|
|
132
|
+
const db = await loadFeedbackDatabase(projectPath);
|
|
133
|
+
return db.entries.filter((entry) => {
|
|
134
|
+
const matchesScanner = entry.scanner === scanner;
|
|
135
|
+
const matchesRule = entry.ruleId === ruleId;
|
|
136
|
+
const matchesFile = entry.file === file;
|
|
137
|
+
const matchesLine = line === undefined || entry.line === line;
|
|
138
|
+
return matchesScanner && matchesRule && matchesFile && matchesLine;
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get all feedback for a rule
|
|
143
|
+
*/
|
|
144
|
+
export async function getFeedbackForRule(projectPath, scanner, ruleId) {
|
|
145
|
+
const db = await loadFeedbackDatabase(projectPath);
|
|
146
|
+
return db.entries.filter((entry) => entry.scanner === scanner && entry.ruleId === ruleId);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Check if a finding has existing feedback
|
|
150
|
+
*/
|
|
151
|
+
export async function hasFeedback(projectPath, scanner, ruleId, file, line) {
|
|
152
|
+
const feedback = await getFeedbackForFinding(projectPath, scanner, ruleId, file, line);
|
|
153
|
+
return feedback.length > 0;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get suppression suggestions based on feedback
|
|
157
|
+
*/
|
|
158
|
+
export async function getSuppressionSuggestions(projectPath, options) {
|
|
159
|
+
const minFPRate = options?.minFPRate ?? 0.5;
|
|
160
|
+
const minSampleSize = options?.minSampleSize ?? 5;
|
|
161
|
+
const db = await loadFeedbackDatabase(projectPath);
|
|
162
|
+
// Group feedback by scanner/rule
|
|
163
|
+
const ruleGroups = new Map();
|
|
164
|
+
for (const entry of db.entries) {
|
|
165
|
+
const key = `${entry.scanner}:${entry.ruleId}`;
|
|
166
|
+
const existing = ruleGroups.get(key) || [];
|
|
167
|
+
existing.push(entry);
|
|
168
|
+
ruleGroups.set(key, existing);
|
|
169
|
+
}
|
|
170
|
+
const suggestions = [];
|
|
171
|
+
for (const [key, entries] of ruleGroups) {
|
|
172
|
+
const [scanner, ruleId] = key.split(":");
|
|
173
|
+
if (entries.length < minSampleSize) {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const fpCount = entries.filter((e) => e.verdict === "fp").length;
|
|
177
|
+
const fpRate = fpCount / entries.length;
|
|
178
|
+
if (fpRate < minFPRate) {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
// Get common FP reasons
|
|
182
|
+
const reasonCounts = new Map();
|
|
183
|
+
for (const entry of entries) {
|
|
184
|
+
if (entry.verdict === "fp" && entry.reason) {
|
|
185
|
+
reasonCounts.set(entry.reason, (reasonCounts.get(entry.reason) || 0) + 1);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const commonReasons = Array.from(reasonCounts.entries())
|
|
189
|
+
.sort((a, b) => b[1] - a[1])
|
|
190
|
+
.slice(0, 3)
|
|
191
|
+
.map(([reason]) => reason);
|
|
192
|
+
// Determine suggestion
|
|
193
|
+
let suggestion;
|
|
194
|
+
if (fpRate >= 0.8) {
|
|
195
|
+
suggestion = "disable";
|
|
196
|
+
}
|
|
197
|
+
else if (fpRate >= 0.5) {
|
|
198
|
+
suggestion = "review";
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
suggestion = "keep";
|
|
202
|
+
}
|
|
203
|
+
suggestions.push({
|
|
204
|
+
scanner,
|
|
205
|
+
ruleId,
|
|
206
|
+
fpRate,
|
|
207
|
+
sampleSize: entries.length,
|
|
208
|
+
suggestion,
|
|
209
|
+
commonReasons,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
// Sort by FP rate descending
|
|
213
|
+
return suggestions.sort((a, b) => b.fpRate - a.fpRate);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Generate feedback summary report
|
|
217
|
+
*/
|
|
218
|
+
export async function generateFeedbackReport(projectPath) {
|
|
219
|
+
const db = await loadFeedbackDatabase(projectPath);
|
|
220
|
+
const suppressionSuggestions = await getSuppressionSuggestions(projectPath);
|
|
221
|
+
const totalFeedback = db.stats.totalFeedback;
|
|
222
|
+
const overallFPRate = totalFeedback > 0 ? db.stats.fpCount / totalFeedback : 0;
|
|
223
|
+
// By scanner
|
|
224
|
+
const byScanner = Object.entries(db.stats.byScanner).map(([scanner, stats]) => ({
|
|
225
|
+
scanner: scanner,
|
|
226
|
+
total: stats.tp + stats.fp,
|
|
227
|
+
tp: stats.tp,
|
|
228
|
+
fp: stats.fp,
|
|
229
|
+
fpRate: (stats.tp + stats.fp) > 0 ? stats.fp / (stats.tp + stats.fp) : 0,
|
|
230
|
+
}));
|
|
231
|
+
// Top FP reasons
|
|
232
|
+
const topFPReasons = Object.entries(db.stats.byReason)
|
|
233
|
+
.sort(([, a], [, b]) => b - a)
|
|
234
|
+
.slice(0, 5)
|
|
235
|
+
.map(([reason, count]) => ({
|
|
236
|
+
reason: reason,
|
|
237
|
+
count,
|
|
238
|
+
percentage: db.stats.fpCount > 0 ? (count / db.stats.fpCount) * 100 : 0,
|
|
239
|
+
}));
|
|
240
|
+
// Recent feedback (last 10)
|
|
241
|
+
const recentFeedback = [...db.entries]
|
|
242
|
+
.sort((a, b) => new Date(b.submittedAt).getTime() - new Date(a.submittedAt).getTime())
|
|
243
|
+
.slice(0, 10);
|
|
244
|
+
return {
|
|
245
|
+
overview: {
|
|
246
|
+
totalFeedback,
|
|
247
|
+
tpCount: db.stats.tpCount,
|
|
248
|
+
fpCount: db.stats.fpCount,
|
|
249
|
+
overallFPRate,
|
|
250
|
+
},
|
|
251
|
+
byScanner,
|
|
252
|
+
topFPReasons,
|
|
253
|
+
recentFeedback,
|
|
254
|
+
suppressionSuggestions,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Clear old feedback entries
|
|
259
|
+
*/
|
|
260
|
+
export async function pruneOldFeedback(projectPath, maxAgeDays = 90) {
|
|
261
|
+
const db = await loadFeedbackDatabase(projectPath);
|
|
262
|
+
const cutoffDate = new Date();
|
|
263
|
+
cutoffDate.setDate(cutoffDate.getDate() - maxAgeDays);
|
|
264
|
+
const originalCount = db.entries.length;
|
|
265
|
+
db.entries = db.entries.filter((entry) => {
|
|
266
|
+
return new Date(entry.submittedAt) >= cutoffDate;
|
|
267
|
+
});
|
|
268
|
+
const removedCount = originalCount - db.entries.length;
|
|
269
|
+
if (removedCount > 0) {
|
|
270
|
+
// Recalculate stats
|
|
271
|
+
db.stats = {
|
|
272
|
+
totalFeedback: db.entries.length,
|
|
273
|
+
tpCount: db.entries.filter((e) => e.verdict === "tp").length,
|
|
274
|
+
fpCount: db.entries.filter((e) => e.verdict === "fp").length,
|
|
275
|
+
byScanner: {},
|
|
276
|
+
byReason: {},
|
|
277
|
+
};
|
|
278
|
+
for (const entry of db.entries) {
|
|
279
|
+
if (!db.stats.byScanner[entry.scanner]) {
|
|
280
|
+
db.stats.byScanner[entry.scanner] = { tp: 0, fp: 0 };
|
|
281
|
+
}
|
|
282
|
+
db.stats.byScanner[entry.scanner][entry.verdict]++;
|
|
283
|
+
if (entry.verdict === "fp" && entry.reason) {
|
|
284
|
+
db.stats.byReason[entry.reason] = (db.stats.byReason[entry.reason] || 0) + 1;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
await saveFeedbackDatabase(projectPath, db);
|
|
288
|
+
logger.info("fp_feedback.pruned", { removed: removedCount, remaining: db.entries.length });
|
|
289
|
+
}
|
|
290
|
+
return removedCount;
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=fp-feedback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fp-feedback.js","sourceRoot":"","sources":["../../src/scanners/fp-feedback.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* False Positive Filter
|
|
3
|
+
*
|
|
4
|
+
* Context-aware filtering to reduce false positives from scanners.
|
|
5
|
+
* Analyzes code context, semantic patterns, and historical data.
|
|
6
|
+
*
|
|
7
|
+
* @module scanners/fp-filter
|
|
8
|
+
*/
|
|
9
|
+
import type { DeterministicFinding } from "./types.js";
|
|
10
|
+
/**
|
|
11
|
+
* Context information for filtering decisions
|
|
12
|
+
*/
|
|
13
|
+
export interface FPFilterContext {
|
|
14
|
+
/** File-level context */
|
|
15
|
+
codeContext: {
|
|
16
|
+
isTestFile: boolean;
|
|
17
|
+
isGeneratedCode: boolean;
|
|
18
|
+
isThirdPartyVendored: boolean;
|
|
19
|
+
isMockFile: boolean;
|
|
20
|
+
isFixtureFile: boolean;
|
|
21
|
+
isExampleFile: boolean;
|
|
22
|
+
};
|
|
23
|
+
/** Semantic context from code analysis */
|
|
24
|
+
semanticContext: {
|
|
25
|
+
hasValidation: boolean;
|
|
26
|
+
hasEncoding: boolean;
|
|
27
|
+
isSanitized: boolean;
|
|
28
|
+
isConstant: boolean;
|
|
29
|
+
isEnvironmentVariable: boolean;
|
|
30
|
+
};
|
|
31
|
+
/** Historical FP data */
|
|
32
|
+
historicalContext: {
|
|
33
|
+
previousFPs: string[];
|
|
34
|
+
ruleAccuracy: number;
|
|
35
|
+
suppressions: string[];
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Result of filtering decision
|
|
40
|
+
*/
|
|
41
|
+
export interface FilterResult {
|
|
42
|
+
/** Whether to filter out this finding */
|
|
43
|
+
filter: boolean;
|
|
44
|
+
/** Reason for filtering (if filtered) */
|
|
45
|
+
reason?: string;
|
|
46
|
+
/** Confidence in the filtering decision (0-100) */
|
|
47
|
+
confidence: number;
|
|
48
|
+
/** Suggested action */
|
|
49
|
+
suggestion?: "suppress" | "review" | "confirm";
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Analyze file path to determine code context
|
|
53
|
+
*/
|
|
54
|
+
export declare function analyzeFilePath(filePath: string): FPFilterContext["codeContext"];
|
|
55
|
+
/**
|
|
56
|
+
* Analyze code content for semantic context
|
|
57
|
+
*/
|
|
58
|
+
export declare function analyzeCodeContext(projectPath: string, finding: DeterministicFinding): Promise<FPFilterContext["semanticContext"]>;
|
|
59
|
+
/**
|
|
60
|
+
* Determine if a finding should be filtered as a false positive
|
|
61
|
+
*/
|
|
62
|
+
export declare function shouldFilter(finding: DeterministicFinding, context: FPFilterContext): FilterResult;
|
|
63
|
+
/**
|
|
64
|
+
* Filter findings and return filtered results with reasons
|
|
65
|
+
*/
|
|
66
|
+
export declare function filterFindings(projectPath: string, findings: DeterministicFinding[], options?: {
|
|
67
|
+
historicalData?: Map<string, {
|
|
68
|
+
fpRate: number;
|
|
69
|
+
suppressions: string[];
|
|
70
|
+
}>;
|
|
71
|
+
minConfidence?: number;
|
|
72
|
+
}): Promise<{
|
|
73
|
+
filtered: DeterministicFinding[];
|
|
74
|
+
removed: Array<{
|
|
75
|
+
finding: DeterministicFinding;
|
|
76
|
+
reason: string;
|
|
77
|
+
confidence: number;
|
|
78
|
+
}>;
|
|
79
|
+
stats: {
|
|
80
|
+
total: number;
|
|
81
|
+
kept: number;
|
|
82
|
+
filtered: number;
|
|
83
|
+
byReason: Record<string, number>;
|
|
84
|
+
};
|
|
85
|
+
}>;
|
|
86
|
+
/**
|
|
87
|
+
* Get suggested suppressions for a finding
|
|
88
|
+
*/
|
|
89
|
+
export declare function getSuppressSuggestion(finding: DeterministicFinding, context: FPFilterContext): {
|
|
90
|
+
suppressionComment: string;
|
|
91
|
+
inlineSuppress: string;
|
|
92
|
+
fileSuppress: string;
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=fp-filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fp-filter.d.ts","sourceRoot":"","sources":["../../src/scanners/fp-filter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,oBAAoB,EAAe,MAAM,YAAY,CAAC;AAGpE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,yBAAyB;IACzB,WAAW,EAAE;QACX,UAAU,EAAE,OAAO,CAAC;QACpB,eAAe,EAAE,OAAO,CAAC;QACzB,oBAAoB,EAAE,OAAO,CAAC;QAC9B,UAAU,EAAE,OAAO,CAAC;QACpB,aAAa,EAAE,OAAO,CAAC;QACvB,aAAa,EAAE,OAAO,CAAC;KACxB,CAAC;IAEF,0CAA0C;IAC1C,eAAe,EAAE;QACf,aAAa,EAAE,OAAO,CAAC;QACvB,WAAW,EAAE,OAAO,CAAC;QACrB,WAAW,EAAE,OAAO,CAAC;QACrB,UAAU,EAAE,OAAO,CAAC;QACpB,qBAAqB,EAAE,OAAO,CAAC;KAChC,CAAC;IAEF,yBAAyB;IACzB,iBAAiB,EAAE;QACjB,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,yCAAyC;IACzC,MAAM,EAAE,OAAO,CAAC;IAEhB,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IAEnB,uBAAuB;IACvB,UAAU,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC;CAChD;AAqGD;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,CAAC,aAAa,CAAC,CAYhF;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC,CAmF7C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,eAAe,GACvB,YAAY,CAyGd;AAoBD;;GAEG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,oBAAoB,EAAE,EAChC,OAAO,CAAC,EAAE;IACR,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACzE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GACA,OAAO,CAAC;IACT,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,OAAO,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,oBAAoB,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtF,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAClC,CAAC;CACH,CAAC,CAwDD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,eAAe,GACvB;IACD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB,CAmCA"}
|