projscan 4.6.0 → 4.8.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 +25 -12
- package/dist/cli/_shared.js +12 -44
- package/dist/cli/_shared.js.map +1 -1
- package/dist/cli/changedOnly.d.ts +16 -0
- package/dist/cli/changedOnly.js +28 -0
- package/dist/cli/changedOnly.js.map +1 -0
- package/dist/cli/commands/start.js +5 -28
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/startOptionsRegistration.d.ts +2 -0
- package/dist/cli/commands/startOptionsRegistration.js +29 -0
- package/dist/cli/commands/startOptionsRegistration.js.map +1 -0
- package/dist/cli/formatOptions.d.ts +4 -0
- package/dist/cli/formatOptions.js +30 -0
- package/dist/cli/formatOptions.js.map +1 -0
- package/dist/core/agentBrief.js +6 -1
- package/dist/core/agentBrief.js.map +1 -1
- package/dist/core/ast.d.ts +2 -17
- package/dist/core/ast.js +4 -33
- package/dist/core/ast.js.map +1 -1
- package/dist/core/astBodySignals.js +2 -3
- package/dist/core/astBodySignals.js.map +1 -1
- package/dist/core/astMembers.d.ts +1 -0
- package/dist/core/astMembers.js +38 -9
- package/dist/core/astMembers.js.map +1 -1
- package/dist/core/astResult.d.ts +20 -0
- package/dist/core/astResult.js +39 -0
- package/dist/core/astResult.js.map +1 -0
- package/dist/core/bugHunt.js +2 -142
- package/dist/core/bugHunt.js.map +1 -1
- package/dist/core/bugHuntHotspotFindings.d.ts +2 -0
- package/dist/core/bugHuntHotspotFindings.js +68 -0
- package/dist/core/bugHuntHotspotFindings.js.map +1 -0
- package/dist/core/bugHuntPreflightFindings.d.ts +3 -0
- package/dist/core/bugHuntPreflightFindings.js +115 -0
- package/dist/core/bugHuntPreflightFindings.js.map +1 -0
- package/dist/core/codeGraph.d.ts +2 -24
- package/dist/core/codeGraph.js +8 -119
- package/dist/core/codeGraph.js.map +1 -1
- package/dist/core/codeGraphAdapterContexts.d.ts +8 -0
- package/dist/core/codeGraphAdapterContexts.js +14 -0
- package/dist/core/codeGraphAdapterContexts.js.map +1 -0
- package/dist/core/codeGraphFileSelection.d.ts +7 -0
- package/dist/core/codeGraphFileSelection.js +19 -0
- package/dist/core/codeGraphFileSelection.js.map +1 -0
- package/dist/core/codeGraphIncremental.d.ts +17 -0
- package/dist/core/codeGraphIncremental.js +64 -0
- package/dist/core/codeGraphIncremental.js.map +1 -0
- package/dist/core/codeGraphQueries.d.ts +9 -0
- package/dist/core/codeGraphQueries.js +25 -0
- package/dist/core/codeGraphQueries.js.map +1 -0
- package/dist/core/collisionDetector.d.ts +1 -0
- package/dist/core/collisionDetector.js +3 -0
- package/dist/core/collisionDetector.js.map +1 -1
- package/dist/core/coordination.js +23 -5
- package/dist/core/coordination.js.map +1 -1
- package/dist/core/coordinationEvidence.d.ts +1 -0
- package/dist/core/coordinationEvidence.js.map +1 -1
- package/dist/core/dataflow.js +3 -338
- package/dist/core/dataflow.js.map +1 -1
- package/dist/core/dataflowDatabaseSinks.d.ts +8 -0
- package/dist/core/dataflowDatabaseSinks.js +78 -0
- package/dist/core/dataflowDatabaseSinks.js.map +1 -0
- package/dist/core/dataflowRiskAssembly.d.ts +11 -0
- package/dist/core/dataflowRiskAssembly.js +117 -0
- package/dist/core/dataflowRiskAssembly.js.map +1 -0
- package/dist/core/dataflowTraversal.d.ts +25 -0
- package/dist/core/dataflowTraversal.js +200 -0
- package/dist/core/dataflowTraversal.js.map +1 -0
- package/dist/core/fileInspectionReport.d.ts +13 -0
- package/dist/core/fileInspectionReport.js +49 -0
- package/dist/core/fileInspectionReport.js.map +1 -0
- package/dist/core/fileInspector.d.ts +3 -11
- package/dist/core/fileInspector.js +2 -46
- package/dist/core/fileInspector.js.map +1 -1
- package/dist/core/fixSuggest.d.ts +1 -9
- package/dist/core/fixSuggest.js +2 -58
- package/dist/core/fixSuggest.js.map +1 -1
- package/dist/core/fixSuggestDependencyNames.d.ts +1 -0
- package/dist/core/fixSuggestDependencyNames.js +9 -0
- package/dist/core/fixSuggestDependencyNames.js.map +1 -0
- package/dist/core/fixSuggestPreview.d.ts +10 -0
- package/dist/core/fixSuggestPreview.js +87 -0
- package/dist/core/fixSuggestPreview.js.map +1 -0
- package/dist/core/frameworkExpressSources.js +6 -31
- package/dist/core/frameworkExpressSources.js.map +1 -1
- package/dist/core/frameworkFastifySources.js +5 -22
- package/dist/core/frameworkFastifySources.js.map +1 -1
- package/dist/core/frameworkHonoSources.js +12 -24
- package/dist/core/frameworkHonoSources.js.map +1 -1
- package/dist/core/frameworkKoaSources.js +5 -24
- package/dist/core/frameworkKoaSources.js.map +1 -1
- package/dist/core/frameworkNextRouteSources.d.ts +6 -1
- package/dist/core/frameworkNextRouteSources.js +31 -1
- package/dist/core/frameworkNextRouteSources.js.map +1 -1
- package/dist/core/frameworkRemixSources.d.ts +2 -0
- package/dist/core/frameworkRemixSources.js +63 -0
- package/dist/core/frameworkRemixSources.js.map +1 -0
- package/dist/core/frameworkSourceContext.d.ts +15 -0
- package/dist/core/frameworkSourceContext.js +2 -0
- package/dist/core/frameworkSourceContext.js.map +1 -0
- package/dist/core/frameworkSourceMatching.d.ts +6 -0
- package/dist/core/frameworkSourceMatching.js +29 -0
- package/dist/core/frameworkSourceMatching.js.map +1 -0
- package/dist/core/frameworkSourceResolvers.d.ts +2 -0
- package/dist/core/frameworkSourceResolvers.js +45 -0
- package/dist/core/frameworkSourceResolvers.js.map +1 -0
- package/dist/core/frameworkSources.d.ts +3 -3
- package/dist/core/frameworkSources.js +17 -15
- package/dist/core/frameworkSources.js.map +1 -1
- package/dist/core/frameworkSvelteKitSources.d.ts +2 -0
- package/dist/core/frameworkSvelteKitSources.js +118 -0
- package/dist/core/frameworkSvelteKitSources.js.map +1 -0
- package/dist/core/intentRouter.d.ts +4 -14
- package/dist/core/intentRouter.js +2 -33
- package/dist/core/intentRouter.js.map +1 -1
- package/dist/core/intentRouterCatalog.js +49 -0
- package/dist/core/intentRouterCatalog.js.map +1 -1
- package/dist/core/intentRouterKeywordToolGuards.js +5 -0
- package/dist/core/intentRouterKeywordToolGuards.js.map +1 -1
- package/dist/core/intentRouterKeywordWeights.js +36 -0
- package/dist/core/intentRouterKeywordWeights.js.map +1 -1
- package/dist/core/intentRouterReleaseSignals.js +104 -39
- package/dist/core/intentRouterReleaseSignals.js.map +1 -1
- package/dist/core/intentRouterResolution.d.ts +3 -0
- package/dist/core/intentRouterResolution.js +11 -0
- package/dist/core/intentRouterResolution.js.map +1 -0
- package/dist/core/intentRouterResult.d.ts +16 -0
- package/dist/core/intentRouterResult.js +34 -0
- package/dist/core/intentRouterResult.js.map +1 -0
- package/dist/core/intentRouterWorkSignals.js +18 -0
- package/dist/core/intentRouterWorkSignals.js.map +1 -1
- package/dist/core/languages/pythonLockfiles.d.ts +4 -0
- package/dist/core/languages/pythonLockfiles.js +6 -2
- package/dist/core/languages/pythonLockfiles.js.map +1 -1
- package/dist/core/languages/pythonManifests.js +11 -24
- package/dist/core/languages/pythonManifests.js.map +1 -1
- package/dist/core/languages/pythonPep508.js +1 -1
- package/dist/core/languages/pythonPep508.js.map +1 -1
- package/dist/core/languages/pythonProjectEvidence.js +4 -4
- package/dist/core/languages/pythonProjectEvidence.js.map +1 -1
- package/dist/core/languages/pythonPyproject.js +1 -1
- package/dist/core/languages/pythonPyproject.js.map +1 -1
- package/dist/core/languages/pythonPyprojectEvidence.d.ts +7 -0
- package/dist/core/languages/pythonPyprojectEvidence.js +23 -0
- package/dist/core/languages/pythonPyprojectEvidence.js.map +1 -0
- package/dist/core/languages/pythonRequirements.d.ts +2 -0
- package/dist/core/languages/pythonRequirements.js +215 -24
- package/dist/core/languages/pythonRequirements.js.map +1 -1
- package/dist/core/pluginAnalyzerLoading.d.ts +3 -0
- package/dist/core/pluginAnalyzerLoading.js +55 -0
- package/dist/core/pluginAnalyzerLoading.js.map +1 -0
- package/dist/core/pluginAnalyzerRunning.d.ts +10 -0
- package/dist/core/pluginAnalyzerRunning.js +32 -0
- package/dist/core/pluginAnalyzerRunning.js.map +1 -0
- package/dist/core/pluginIssueValidation.d.ts +2 -0
- package/dist/core/pluginIssueValidation.js +22 -0
- package/dist/core/pluginIssueValidation.js.map +1 -0
- package/dist/core/pluginManifestDiscovery.d.ts +25 -0
- package/dist/core/pluginManifestDiscovery.js +80 -0
- package/dist/core/pluginManifestDiscovery.js.map +1 -0
- package/dist/core/pluginManifestValidation.d.ts +41 -0
- package/dist/core/pluginManifestValidation.js +179 -0
- package/dist/core/pluginManifestValidation.js.map +1 -0
- package/dist/core/pluginModuleLoading.d.ts +8 -0
- package/dist/core/pluginModuleLoading.js +91 -0
- package/dist/core/pluginModuleLoading.js.map +1 -0
- package/dist/core/pluginReporterLoading.d.ts +41 -0
- package/dist/core/pluginReporterLoading.js +105 -0
- package/dist/core/pluginReporterLoading.js.map +1 -0
- package/dist/core/pluginRuntimeTypes.d.ts +20 -0
- package/dist/core/pluginRuntimeTypes.js +2 -0
- package/dist/core/pluginRuntimeTypes.js.map +1 -0
- package/dist/core/plugins.d.ts +11 -126
- package/dist/core/plugins.js +13 -478
- package/dist/core/plugins.js.map +1 -1
- package/dist/core/preflight.d.ts +1 -2
- package/dist/core/preflight.js +4 -91
- package/dist/core/preflight.js.map +1 -1
- package/dist/core/preflightEvidence.js +11 -0
- package/dist/core/preflightEvidence.js.map +1 -1
- package/dist/core/preflightInputs.d.ts +1 -0
- package/dist/core/preflightInputs.js.map +1 -1
- package/dist/core/preflightReasons.d.ts +21 -0
- package/dist/core/preflightReasons.js +28 -0
- package/dist/core/preflightReasons.js.map +1 -0
- package/dist/core/preflightReport.d.ts +9 -0
- package/dist/core/preflightReport.js +67 -0
- package/dist/core/preflightReport.js.map +1 -0
- package/dist/core/regressionPlan.d.ts +2 -1
- package/dist/core/regressionPlan.js +7 -1
- package/dist/core/regressionPlan.js.map +1 -1
- package/dist/core/releaseEvidence.js +6 -120
- package/dist/core/releaseEvidence.js.map +1 -1
- package/dist/core/releaseEvidenceArtifacts.d.ts +3 -0
- package/dist/core/releaseEvidenceArtifacts.js +65 -0
- package/dist/core/releaseEvidenceArtifacts.js.map +1 -0
- package/dist/core/releaseEvidenceVerdict.d.ts +6 -0
- package/dist/core/releaseEvidenceVerdict.js +54 -0
- package/dist/core/releaseEvidenceVerdict.js.map +1 -0
- package/dist/core/reportPathRedaction.d.ts +4 -0
- package/dist/core/reportPathRedaction.js +64 -0
- package/dist/core/reportPathRedaction.js.map +1 -0
- package/dist/core/reportScope.js +2 -163
- package/dist/core/reportScope.js.map +1 -1
- package/dist/core/reportScopeFiltering.d.ts +9 -0
- package/dist/core/reportScopeFiltering.js +102 -0
- package/dist/core/reportScopeFiltering.js.map +1 -0
- package/dist/core/review.js +2 -47
- package/dist/core/review.js.map +1 -1
- package/dist/core/reviewChangedReport.d.ts +13 -0
- package/dist/core/reviewChangedReport.js +38 -0
- package/dist/core/reviewChangedReport.js.map +1 -0
- package/dist/core/reviewComputation.d.ts +9 -0
- package/dist/core/reviewComputation.js +14 -0
- package/dist/core/reviewComputation.js.map +1 -0
- package/dist/core/reviewContractChanges.js +22 -8
- package/dist/core/reviewContractChanges.js.map +1 -1
- package/dist/core/reviewDataflow.js +18 -0
- package/dist/core/reviewDataflow.js.map +1 -1
- package/dist/core/roadmapCatalog.js +7 -203
- package/dist/core/roadmapCatalog.js.map +1 -1
- package/dist/core/roadmapCatalogPost44.d.ts +2 -0
- package/dist/core/roadmapCatalogPost44.js +205 -0
- package/dist/core/roadmapCatalogPost44.js.map +1 -0
- package/dist/core/roadmapCatalogTypes.d.ts +6 -0
- package/dist/core/roadmapCatalogTypes.js +2 -0
- package/dist/core/roadmapCatalogTypes.js.map +1 -0
- package/dist/core/searchIndex.d.ts +2 -14
- package/dist/core/searchIndex.js +4 -227
- package/dist/core/searchIndex.js.map +1 -1
- package/dist/core/searchIndexFiles.d.ts +1 -0
- package/dist/core/searchIndexFiles.js +26 -0
- package/dist/core/searchIndexFiles.js.map +1 -0
- package/dist/core/searchIndexText.d.ts +15 -0
- package/dist/core/searchIndexText.js +204 -0
- package/dist/core/searchIndexText.js.map +1 -0
- package/dist/core/start.js +5 -46
- package/dist/core/start.js.map +1 -1
- package/dist/core/startClaimRouteCriteria.d.ts +7 -0
- package/dist/core/startClaimRouteCriteria.js +16 -0
- package/dist/core/startClaimRouteCriteria.js.map +1 -0
- package/dist/core/startCouplingRouteCriteria.d.ts +2 -0
- package/dist/core/startCouplingRouteCriteria.js +13 -0
- package/dist/core/startCouplingRouteCriteria.js.map +1 -0
- package/dist/core/startDependencyRouteCriteria.d.ts +2 -0
- package/dist/core/startDependencyRouteCriteria.js +43 -0
- package/dist/core/startDependencyRouteCriteria.js.map +1 -0
- package/dist/core/startEvidence.d.ts +1 -1
- package/dist/core/startEvidence.js +16 -1
- package/dist/core/startEvidence.js.map +1 -1
- package/dist/core/startFileRouteCriteria.d.ts +2 -0
- package/dist/core/startFileRouteCriteria.js +56 -0
- package/dist/core/startFileRouteCriteria.js.map +1 -0
- package/dist/core/startFixedRouteCriteria.d.ts +1 -0
- package/dist/core/startFixedRouteCriteria.js +90 -0
- package/dist/core/startFixedRouteCriteria.js.map +1 -0
- package/dist/core/startImpactRouteCriteria.d.ts +7 -0
- package/dist/core/startImpactRouteCriteria.js +14 -0
- package/dist/core/startImpactRouteCriteria.js.map +1 -0
- package/dist/core/startInputs.d.ts +1 -0
- package/dist/core/startInputs.js +4 -1
- package/dist/core/startInputs.js.map +1 -1
- package/dist/core/startIntentTargets.d.ts +1 -0
- package/dist/core/startIntentTargets.js +28 -0
- package/dist/core/startIntentTargets.js.map +1 -1
- package/dist/core/startMissionControl.js +8 -2
- package/dist/core/startMissionControl.js.map +1 -1
- package/dist/core/startMissionPolicy.js +12 -0
- package/dist/core/startMissionPolicy.js.map +1 -1
- package/dist/core/startMode.d.ts +1 -0
- package/dist/core/startMode.js +10 -2
- package/dist/core/startMode.js.map +1 -1
- package/dist/core/startPreflightRouteCriteria.d.ts +11 -0
- package/dist/core/startPreflightRouteCriteria.js +29 -0
- package/dist/core/startPreflightRouteCriteria.js.map +1 -0
- package/dist/core/startProductPlanningRouteCriteria.d.ts +8 -0
- package/dist/core/startProductPlanningRouteCriteria.js +29 -0
- package/dist/core/startProductPlanningRouteCriteria.js.map +1 -0
- package/dist/core/startRegressionRouteCriteria.d.ts +3 -0
- package/dist/core/startRegressionRouteCriteria.js +62 -0
- package/dist/core/startRegressionRouteCriteria.js.map +1 -0
- package/dist/core/startReportBuilder.d.ts +1 -0
- package/dist/core/startReportBuilder.js +1 -0
- package/dist/core/startReportBuilder.js.map +1 -1
- package/dist/core/startReportContext.d.ts +23 -0
- package/dist/core/startReportContext.js +51 -0
- package/dist/core/startReportContext.js.map +1 -0
- package/dist/core/startRoadmapPreview.d.ts +2 -0
- package/dist/core/startRoadmapPreview.js +31 -0
- package/dist/core/startRoadmapPreview.js.map +1 -0
- package/dist/core/startRouteActions.js +39 -1
- package/dist/core/startRouteActions.js.map +1 -1
- package/dist/core/startSuccessCriteria.d.ts +2 -3
- package/dist/core/startSuccessCriteria.js +15 -419
- package/dist/core/startSuccessCriteria.js.map +1 -1
- package/dist/core/startUnderstandRouteCriteria.d.ts +3 -0
- package/dist/core/startUnderstandRouteCriteria.js +97 -0
- package/dist/core/startUnderstandRouteCriteria.js.map +1 -0
- package/dist/core/taint.d.ts +2 -67
- package/dist/core/taint.js +41 -164
- package/dist/core/taint.js.map +1 -1
- package/dist/core/taintIndex.d.ts +20 -0
- package/dist/core/taintIndex.js +81 -0
- package/dist/core/taintIndex.js.map +1 -0
- package/dist/core/taintTraversal.d.ts +8 -0
- package/dist/core/taintTraversal.js +113 -0
- package/dist/core/taintTraversal.js.map +1 -0
- package/dist/core/taintTypes.d.ts +67 -0
- package/dist/core/taintTypes.js +2 -0
- package/dist/core/taintTypes.js.map +1 -0
- package/dist/core/telemetry.d.ts +9 -89
- package/dist/core/telemetry.js +35 -387
- package/dist/core/telemetry.js.map +1 -1
- package/dist/core/telemetryConfig.d.ts +58 -0
- package/dist/core/telemetryConfig.js +171 -0
- package/dist/core/telemetryConfig.js.map +1 -0
- package/dist/core/telemetryEvents.d.ts +57 -0
- package/dist/core/telemetryEvents.js +143 -0
- package/dist/core/telemetryEvents.js.map +1 -0
- package/dist/core/telemetryFlushing.d.ts +10 -0
- package/dist/core/telemetryFlushing.js +42 -0
- package/dist/core/telemetryFlushing.js.map +1 -0
- package/dist/core/telemetryRecording.d.ts +26 -0
- package/dist/core/telemetryRecording.js +38 -0
- package/dist/core/telemetryRecording.js.map +1 -0
- package/dist/core/telemetrySender.d.ts +9 -0
- package/dist/core/telemetrySender.js +22 -0
- package/dist/core/telemetrySender.js.map +1 -0
- package/dist/core/upgradePreviewPython.js +1 -1
- package/dist/core/upgradePreviewPython.js.map +1 -1
- package/dist/index.d.ts +4 -60
- package/dist/index.js +4 -60
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +2 -13
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/serverMessageHandling.d.ts +3 -0
- package/dist/mcp/serverMessageHandling.js +16 -0
- package/dist/mcp/serverMessageHandling.js.map +1 -0
- package/dist/mcp/toolDefinitions.d.ts +3 -0
- package/dist/mcp/toolDefinitions.js +15 -0
- package/dist/mcp/toolDefinitions.js.map +1 -0
- package/dist/mcp/tools.js +2 -13
- package/dist/mcp/tools.js.map +1 -1
- package/dist/projscan-sbom.cdx.json +6 -6
- package/dist/publicAgent.d.ts +22 -0
- package/dist/publicAgent.js +23 -0
- package/dist/publicAgent.js.map +1 -0
- package/dist/publicCore.d.ts +29 -0
- package/dist/publicCore.js +30 -0
- package/dist/publicCore.js.map +1 -0
- package/dist/publicLanguages.d.ts +1 -0
- package/dist/publicLanguages.js +2 -0
- package/dist/publicLanguages.js.map +1 -0
- package/dist/publicMcp.d.ts +8 -0
- package/dist/publicMcp.js +9 -0
- package/dist/publicMcp.js.map +1 -0
- package/dist/reporters/consoleFixReporter.d.ts +3 -0
- package/dist/reporters/consoleFixReporter.js +41 -0
- package/dist/reporters/consoleFixReporter.js.map +1 -0
- package/dist/reporters/consoleReporter.d.ts +1 -3
- package/dist/reporters/consoleReporter.js +1 -42
- package/dist/reporters/consoleReporter.js.map +1 -1
- package/dist/reporters/htmlAnalysisReporter.d.ts +3 -0
- package/dist/reporters/htmlAnalysisReporter.js +98 -0
- package/dist/reporters/htmlAnalysisReporter.js.map +1 -0
- package/dist/reporters/htmlCoverageReporter.d.ts +2 -0
- package/dist/reporters/htmlCoverageReporter.js +52 -0
- package/dist/reporters/htmlCoverageReporter.js.map +1 -0
- package/dist/reporters/htmlImpactReporter.d.ts +2 -0
- package/dist/reporters/htmlImpactReporter.js +41 -0
- package/dist/reporters/htmlImpactReporter.js.map +1 -0
- package/dist/reporters/htmlPrDiffReporter.d.ts +2 -0
- package/dist/reporters/htmlPrDiffReporter.js +84 -0
- package/dist/reporters/htmlPrDiffReporter.js.map +1 -0
- package/dist/reporters/htmlReporter.d.ts +20 -9
- package/dist/reporters/htmlReporter.js +7 -365
- package/dist/reporters/htmlReporter.js.map +1 -1
- package/dist/reporters/htmlReviewReporter.d.ts +2 -0
- package/dist/reporters/htmlReviewReporter.js +94 -0
- package/dist/reporters/htmlReviewReporter.js.map +1 -0
- package/dist/reporters/htmlShared.d.ts +7 -0
- package/dist/reporters/htmlShared.js +106 -0
- package/dist/reporters/htmlShared.js.map +1 -0
- package/dist/tool-manifest.json +2 -2
- package/dist/types/preflight.d.ts +19 -0
- package/dist/types/start.d.ts +7 -437
- package/dist/types/startCommon.d.ts +79 -0
- package/dist/types/startCommon.js +2 -0
- package/dist/types/startCommon.js.map +1 -0
- package/dist/types/startExecution.d.ts +44 -0
- package/dist/types/startExecution.js +2 -0
- package/dist/types/startExecution.js.map +1 -0
- package/dist/types/startMissionControl.d.ts +91 -0
- package/dist/types/startMissionControl.js +2 -0
- package/dist/types/startMissionControl.js.map +1 -0
- package/dist/types/startMissionProof.d.ts +91 -0
- package/dist/types/startMissionProof.js +2 -0
- package/dist/types/startMissionProof.js.map +1 -0
- package/dist/types/startMissionResume.d.ts +100 -0
- package/dist/types/startMissionResume.js +2 -0
- package/dist/types/startMissionResume.js.map +1 -0
- package/dist/types/startMissionReview.d.ts +45 -0
- package/dist/types/startMissionReview.js +2 -0
- package/dist/types/startMissionReview.js.map +1 -0
- package/dist/types/startMissionTooling.d.ts +16 -0
- package/dist/types/startMissionTooling.js +2 -0
- package/dist/types/startMissionTooling.js.map +1 -0
- package/dist/utils/changedFiles.d.ts +1 -0
- package/dist/utils/changedFiles.js +7 -4
- package/dist/utils/changedFiles.js.map +1 -1
- package/docs/GUIDE.md +9 -7
- package/docs/ROADMAP.md +18 -7
- package/docs/examples/adoption-workflows.md +12 -1
- package/docs/examples/swarm-coordination.md +11 -2
- package/package.json +1 -1
package/dist/core/taint.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { CodeGraph } from './codeGraph.js';
|
|
2
|
+
import type { TaintConfig, TaintReport } from './taintTypes.js';
|
|
3
|
+
export type { TaintConfig, TaintFlow, TaintReport } from './taintTypes.js';
|
|
2
4
|
/**
|
|
3
5
|
* Lightweight taint flow analysis (1.6+).
|
|
4
6
|
*
|
|
@@ -29,75 +31,8 @@ import type { CodeGraph } from './codeGraph.js';
|
|
|
29
31
|
* variable-level dataflow, no AST inspection beyond what callSites
|
|
30
32
|
* already gives us. If this drifts toward "general dataflow" cut it.
|
|
31
33
|
*/
|
|
32
|
-
export interface TaintConfig {
|
|
33
|
-
/**
|
|
34
|
-
* Bare callee names treated as taint sources. Examples:
|
|
35
|
-
* "process.env" — environment variables (read sensitive config)
|
|
36
|
-
* "req.body" — HTTP request body
|
|
37
|
-
* "readFileSync" — disk read (could be user-controlled paths)
|
|
38
|
-
*
|
|
39
|
-
* Match is by bare name (the rightmost identifier in a member-access
|
|
40
|
-
* chain). "process.env.SECRET" → "env"; "req.body.userId" → "body".
|
|
41
|
-
* The default list captures the most common JS / Python / Go sources;
|
|
42
|
-
* users override via .projscanrc taint.sources.
|
|
43
|
-
*/
|
|
44
|
-
sources: string[];
|
|
45
|
-
/**
|
|
46
|
-
* Bare callee names treated as taint sinks. Examples:
|
|
47
|
-
* "exec" — child_process.exec
|
|
48
|
-
* "spawn" — child_process.spawn
|
|
49
|
-
* "writeFile" — fs.writeFile
|
|
50
|
-
* "query" — raw SQL (db.query("SELECT...${user}"))
|
|
51
|
-
* "eval" — JS eval / Python eval / etc.
|
|
52
|
-
*/
|
|
53
|
-
sinks: string[];
|
|
54
|
-
}
|
|
55
34
|
export declare const DEFAULT_TAINT_SOURCES: ReadonlyArray<string>;
|
|
56
35
|
export declare const DEFAULT_TAINT_SINKS: ReadonlyArray<string>;
|
|
57
|
-
export interface TaintFlow {
|
|
58
|
-
/** Bare function name where the source was called. */
|
|
59
|
-
sourceFn: string;
|
|
60
|
-
/** Bare function name where the sink was called. */
|
|
61
|
-
sinkFn: string;
|
|
62
|
-
/** The source identifier (e.g. "env"). */
|
|
63
|
-
source: string;
|
|
64
|
-
/** The sink identifier (e.g. "exec"). */
|
|
65
|
-
sink: string;
|
|
66
|
-
/**
|
|
67
|
-
* Sequence of fully-qualified function names from sourceFn to sinkFn,
|
|
68
|
-
* inclusive at both ends. Length 1 means the same function reads the
|
|
69
|
-
* source and calls the sink (the most direct flow).
|
|
70
|
-
*/
|
|
71
|
-
path: string[];
|
|
72
|
-
/** Files touched by the path (in order, deduped). */
|
|
73
|
-
files: string[];
|
|
74
|
-
}
|
|
75
|
-
export interface TaintReport {
|
|
76
|
-
available: boolean;
|
|
77
|
-
reason?: string;
|
|
78
|
-
flowCount: number;
|
|
79
|
-
flows: TaintFlow[];
|
|
80
|
-
/** The effective sources/sinks list used for this run (after merging defaults + config). */
|
|
81
|
-
effectiveSources: string[];
|
|
82
|
-
effectiveSinks: string[];
|
|
83
|
-
/**
|
|
84
|
-
* 1.8+ — true when the BFS hit MAX_DEPTH for at least one source with
|
|
85
|
-
* a non-empty frontier still pending. When set, the agent should know
|
|
86
|
-
* that flows deeper than MAX_DEPTH may exist but weren't reported.
|
|
87
|
-
* Pairs with `truncatedSources` so a follow-up scan can re-target.
|
|
88
|
-
*/
|
|
89
|
-
truncated?: boolean;
|
|
90
|
-
/**
|
|
91
|
-
* 1.8+ — function names whose BFS exited at MAX_DEPTH with the
|
|
92
|
-
* frontier non-empty. Empty when no truncation occurred.
|
|
93
|
-
*/
|
|
94
|
-
truncatedSources?: string[];
|
|
95
|
-
/**
|
|
96
|
-
* 1.8+ — the depth cap actually used. Surfacing this lets agents
|
|
97
|
-
* notice when projscan's defaults shift between releases.
|
|
98
|
-
*/
|
|
99
|
-
maxDepth?: number;
|
|
100
|
-
}
|
|
101
36
|
/**
|
|
102
37
|
* Compute taint flows over the given code graph. Per-function callSites
|
|
103
38
|
* are required (1.5+ ships these for every adapter); functions without
|
package/dist/core/taint.js
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
|
-
import { FRAMEWORK_REQUEST_SOURCES
|
|
2
|
-
import {
|
|
1
|
+
import { FRAMEWORK_REQUEST_SOURCES } from './frameworkSources.js';
|
|
2
|
+
import { buildTaintFunctionIndex } from './taintIndex.js';
|
|
3
|
+
import { findTaintFlows } from './taintTraversal.js';
|
|
4
|
+
/**
|
|
5
|
+
* Lightweight taint flow analysis (1.6+).
|
|
6
|
+
*
|
|
7
|
+
* Source-to-sink reachability over the existing per-function call
|
|
8
|
+
* graph. Sources and sinks are *declared* by name (config-driven);
|
|
9
|
+
* anything in between is treated as a function that might propagate
|
|
10
|
+
* taint. We do NOT do general dataflow — we only ask "does some
|
|
11
|
+
* call chain reach from a function that calls a source to a function
|
|
12
|
+
* that calls a sink?"
|
|
13
|
+
*
|
|
14
|
+
* That heuristic catches the common case: a route handler reads
|
|
15
|
+
* `process.env.SECRET` (source) and somewhere downstream it ends up
|
|
16
|
+
* in `child_process.spawn` (sink). It misses any flow that goes
|
|
17
|
+
* through code we can't see (eval'd strings, plugin loaders), and it
|
|
18
|
+
* over-reports when functions read sources but launder them safely
|
|
19
|
+
* before reaching sinks. Both are documented limitations.
|
|
20
|
+
*
|
|
21
|
+
* Legacy taint algorithm gap (1.6+): the "bridge-helper" pattern is missed —
|
|
22
|
+
* `function bridge() { const v = getSecret(); runDangerous(v); }` where
|
|
23
|
+
* `getSecret` reads the source and `runDangerous` is the sink. The BFS
|
|
24
|
+
* walks DOWN from source-fns, but `bridge` has neither source nor sink
|
|
25
|
+
* directly; both are its callees. 3.0's `computeDataflow` /
|
|
26
|
+
* `projscan_dataflow` runs that second algorithm and review surfaces it
|
|
27
|
+
* as `newDataflowRisks`. Keep this legacy function as the compatibility
|
|
28
|
+
* source-to-sink reachability report.
|
|
29
|
+
*
|
|
30
|
+
* Strict scope discipline (per ROADMAP 1.6 guardrail): no CFG, no
|
|
31
|
+
* variable-level dataflow, no AST inspection beyond what callSites
|
|
32
|
+
* already gives us. If this drifts toward "general dataflow" cut it.
|
|
33
|
+
*/
|
|
3
34
|
export const DEFAULT_TAINT_SOURCES = [
|
|
4
35
|
'env', // process.env.X
|
|
5
36
|
'argv', // process.argv
|
|
@@ -55,50 +86,8 @@ export function computeTaint(graph, config) {
|
|
|
55
86
|
const sinks = new Set([...DEFAULT_TAINT_SINKS, ...config.sinks]);
|
|
56
87
|
const customSources = new Set(config.sources);
|
|
57
88
|
const customSinks = new Set(config.sinks);
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
let totalCallSites = 0;
|
|
61
|
-
for (const [file, gf] of graph.files) {
|
|
62
|
-
if (!gf.functions)
|
|
63
|
-
continue;
|
|
64
|
-
for (const fn of gf.functions) {
|
|
65
|
-
const callees = fn.callSites ?? [];
|
|
66
|
-
const directCallSites = fn.directCallSites ?? [];
|
|
67
|
-
const memberCallSites = fn.memberCallSites ?? [];
|
|
68
|
-
const memberReferences = fn.memberReferences ?? [];
|
|
69
|
-
const memberAliases = fn.memberAliases ?? [];
|
|
70
|
-
const references = fn.references ?? [];
|
|
71
|
-
totalCallSites += callees.length;
|
|
72
|
-
// Default sources mostly match property/reference reads; custom sources
|
|
73
|
-
// may still be call-shaped. Sinks are call-shaped, so callSites only.
|
|
74
|
-
const sourceHit = frameworkRequestSourceForFunction(file, fn.name, memberCallSites, memberReferences, fn.parameters ?? [], sources, references, fn.contextualCallSite, gf.imports) ?? pickSourceHit(callees, references, sources, customSources);
|
|
75
|
-
const sinkHit = pickSinkHit(callees, directCallSites, memberCallSites, memberAliases, sinks, customSinks, file, gf);
|
|
76
|
-
const hasSource = sourceHit !== null &&
|
|
77
|
-
!isDefaultChildProcessEnvPassthrough(sourceHit, sinkHit, memberReferences, customSources, customSinks);
|
|
78
|
-
const hasSink = sinkHit !== null;
|
|
79
|
-
const node = {
|
|
80
|
-
id: `${file}::${fn.name}@${fn.line}`,
|
|
81
|
-
qualName: fn.name,
|
|
82
|
-
bareName: bareName(fn.name),
|
|
83
|
-
file,
|
|
84
|
-
callees,
|
|
85
|
-
references,
|
|
86
|
-
memberReferences,
|
|
87
|
-
sourceHit,
|
|
88
|
-
sinkHit,
|
|
89
|
-
hasSource,
|
|
90
|
-
hasSink,
|
|
91
|
-
};
|
|
92
|
-
fnByQual.set(node.id, node);
|
|
93
|
-
let list = fnsByBareName.get(node.bareName);
|
|
94
|
-
if (!list) {
|
|
95
|
-
list = [];
|
|
96
|
-
fnsByBareName.set(node.bareName, list);
|
|
97
|
-
}
|
|
98
|
-
list.push(node);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
if (fnByQual.size === 0 || totalCallSites === 0) {
|
|
89
|
+
const index = buildTaintFunctionIndex(graph, sources, sinks, customSources, customSinks);
|
|
90
|
+
if (index.fnByQual.size === 0 || index.totalCallSites === 0) {
|
|
102
91
|
return {
|
|
103
92
|
available: false,
|
|
104
93
|
reason: 'No functions with callSites in the graph. Taint requires per-function callSites (1.5+).',
|
|
@@ -108,128 +97,16 @@ export function computeTaint(graph, config) {
|
|
|
108
97
|
effectiveSinks: [...sinks],
|
|
109
98
|
};
|
|
110
99
|
}
|
|
111
|
-
const
|
|
112
|
-
const seen = new Set(); // dedupe key: sourceFnId::sinkFnId
|
|
113
|
-
// 1.8+ — track which source functions hit MAX_DEPTH with frontier
|
|
114
|
-
// still non-empty. The agent gets these in `truncatedSources` so it
|
|
115
|
-
// knows where the analysis was clipped.
|
|
116
|
-
const truncatedSources = [];
|
|
117
|
-
// 1.8+ — raised from 8 → 12. The original 8 was a conservative pick
|
|
118
|
-
// when the algorithm was new; six months of dogfood data show real
|
|
119
|
-
// user repos averaging 10–11 hops between an HTTP handler and a
|
|
120
|
-
// shell-exec sink. 12 catches those without exploding fan-out
|
|
121
|
-
// memory in the BFS frontier.
|
|
122
|
-
const MAX_DEPTH = 12;
|
|
123
|
-
// 1.10+ — per-step frontier cap. MAX_DEPTH bounds path length, but
|
|
124
|
-
// wide-fan-out graphs (Java/TS with prevalent get/set/toString bare-name
|
|
125
|
-
// collisions) can balloon the frontier exponentially: each step
|
|
126
|
-
// resolves every bare-name callee to every same-named function in the
|
|
127
|
-
// graph. Once a single step would push past this cap, we abort the
|
|
128
|
-
// remaining BFS for this source and surface it in `truncatedSources`,
|
|
129
|
-
// matching how MAX_DEPTH truncation is reported.
|
|
130
|
-
const MAX_FRONTIER_PER_STEP = 5000;
|
|
131
|
-
for (const sourceFn of fnByQual.values()) {
|
|
132
|
-
if (!sourceFn.hasSource)
|
|
133
|
-
continue;
|
|
134
|
-
// Same-function shortcut.
|
|
135
|
-
if (sourceFn.hasSink) {
|
|
136
|
-
const key = `${sourceFn.id}::${sourceFn.id}`;
|
|
137
|
-
if (!seen.has(key)) {
|
|
138
|
-
seen.add(key);
|
|
139
|
-
flows.push({
|
|
140
|
-
sourceFn: sourceFn.qualName,
|
|
141
|
-
sinkFn: sourceFn.qualName,
|
|
142
|
-
source: sourceFn.sourceHit,
|
|
143
|
-
sink: sourceFn.sinkHit,
|
|
144
|
-
path: [sourceFn.qualName],
|
|
145
|
-
files: [sourceFn.file],
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
// BFS through callees.
|
|
150
|
-
const visited = new Set([sourceFn.id]);
|
|
151
|
-
let frontier = [{ node: sourceFn, path: [sourceFn] }];
|
|
152
|
-
let depth = 0;
|
|
153
|
-
let frontierCapped = false;
|
|
154
|
-
while (frontier.length > 0 && depth < MAX_DEPTH) {
|
|
155
|
-
depth += 1;
|
|
156
|
-
const next = [];
|
|
157
|
-
let aborted = false;
|
|
158
|
-
for (const entry of frontier) {
|
|
159
|
-
if (aborted)
|
|
160
|
-
break;
|
|
161
|
-
for (const calleeName of entry.node.callees) {
|
|
162
|
-
const candidates = fnsByBareName.get(calleeName) ?? [];
|
|
163
|
-
for (const candidate of candidates) {
|
|
164
|
-
if (visited.has(candidate.id))
|
|
165
|
-
continue;
|
|
166
|
-
visited.add(candidate.id);
|
|
167
|
-
const newPath = [...entry.path, candidate];
|
|
168
|
-
if (candidate.hasSink) {
|
|
169
|
-
const flowKey = `${sourceFn.id}::${candidate.id}`;
|
|
170
|
-
if (!seen.has(flowKey)) {
|
|
171
|
-
seen.add(flowKey);
|
|
172
|
-
const filesInPath = [];
|
|
173
|
-
for (const n of newPath) {
|
|
174
|
-
if (filesInPath[filesInPath.length - 1] !== n.file)
|
|
175
|
-
filesInPath.push(n.file);
|
|
176
|
-
}
|
|
177
|
-
flows.push({
|
|
178
|
-
sourceFn: sourceFn.qualName,
|
|
179
|
-
sinkFn: candidate.qualName,
|
|
180
|
-
source: sourceFn.sourceHit,
|
|
181
|
-
sink: candidate.sinkHit,
|
|
182
|
-
path: newPath.map((n) => n.qualName),
|
|
183
|
-
files: filesInPath,
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
// Don't continue past a sink — the flow is reported.
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
next.push({ node: candidate, path: newPath });
|
|
190
|
-
if (next.length >= MAX_FRONTIER_PER_STEP) {
|
|
191
|
-
// 1.10+ — per-step frontier cap reached. Abort this source's
|
|
192
|
-
// BFS and surface it as truncated. Continuing would just
|
|
193
|
-
// multiply: each entry in `next` will spawn its own bare-name
|
|
194
|
-
// resolutions on the following step.
|
|
195
|
-
frontierCapped = true;
|
|
196
|
-
aborted = true;
|
|
197
|
-
break;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
if (aborted)
|
|
201
|
-
break;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
frontier = next;
|
|
205
|
-
}
|
|
206
|
-
// If the BFS exited because of MAX_DEPTH or the per-step frontier cap
|
|
207
|
-
// (not because the frontier emptied), record the source so the caller
|
|
208
|
-
// knows flows beyond that point weren't explored.
|
|
209
|
-
if (frontier.length > 0 || frontierCapped) {
|
|
210
|
-
truncatedSources.push(sourceFn.qualName);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
flows.sort((a, b) => {
|
|
214
|
-
if (a.sourceFn !== b.sourceFn)
|
|
215
|
-
return a.sourceFn.localeCompare(b.sourceFn);
|
|
216
|
-
return a.sinkFn.localeCompare(b.sinkFn);
|
|
217
|
-
});
|
|
100
|
+
const traversal = findTaintFlows(index);
|
|
218
101
|
return {
|
|
219
102
|
available: true,
|
|
220
|
-
flowCount: flows.length,
|
|
221
|
-
flows,
|
|
103
|
+
flowCount: traversal.flows.length,
|
|
104
|
+
flows: traversal.flows,
|
|
222
105
|
effectiveSources: [...sources].sort(),
|
|
223
106
|
effectiveSinks: [...sinks].sort(),
|
|
224
|
-
truncated: truncatedSources.length > 0,
|
|
225
|
-
truncatedSources:
|
|
226
|
-
maxDepth:
|
|
107
|
+
truncated: traversal.truncatedSources.length > 0,
|
|
108
|
+
truncatedSources: traversal.truncatedSources,
|
|
109
|
+
maxDepth: traversal.maxDepth,
|
|
227
110
|
};
|
|
228
111
|
}
|
|
229
|
-
function bareName(qualified) {
|
|
230
|
-
const dot = qualified.lastIndexOf('.');
|
|
231
|
-
if (dot < 0)
|
|
232
|
-
return qualified;
|
|
233
|
-
return qualified.slice(dot + 1);
|
|
234
|
-
}
|
|
235
112
|
//# sourceMappingURL=taint.js.map
|
package/dist/core/taint.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"taint.js","sourceRoot":"","sources":["../../src/core/taint.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"taint.js","sourceRoot":"","sources":["../../src/core/taint.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAA0B;IAC1D,KAAK,EAAE,gBAAgB;IACvB,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,4EAA4E;IACrF,QAAQ,EAAE,aAAa;IACvB,SAAS,EAAE,cAAc;IACzB,SAAS,EAAE,cAAc;IACzB,UAAU,EAAE,wBAAwB;IACpC,cAAc;IACd,OAAO,EAAE,gBAAgB;IACzB,UAAU,EAAE,wBAAwB;IACpC,GAAG,yBAAyB;CAC7B,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAA0B;IACxD,MAAM,EAAE,qBAAqB;IAC7B,UAAU;IACV,OAAO,EAAE,sBAAsB;IAC/B,WAAW;IACX,MAAM,EAAE,cAAc;IACtB,UAAU,EAAE,yCAAyC;IACrD,WAAW,EAAE,6BAA6B;IAC1C,eAAe;IACf,QAAQ,EAAE,gCAAgC;IAC1C,QAAQ;IACR,IAAI;IACJ,OAAO,EAAE,uBAAuB;IAChC,SAAS,EAAE,yBAAyB;IACpC,QAAQ,EAAE,sBAAsB;IAChC,WAAW;IACX,YAAY,EAAE,2BAA2B;IACzC,WAAW,EAAE,wDAAwD;IACrE,kFAAkF;CACnF,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,YAAY,CAAC,KAAgB,EAAE,MAAmB;IAChE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,qBAAqB,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACvE,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,mBAAmB,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACjE,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC;IAEzF,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,cAAc,KAAK,CAAC,EAAE,CAAC;QAC5D,OAAO;YACL,SAAS,EAAE,KAAK;YAChB,MAAM,EACJ,yFAAyF;YAC3F,SAAS,EAAE,CAAC;YACZ,KAAK,EAAE,EAAE;YACT,gBAAgB,EAAE,CAAC,GAAG,OAAO,CAAC;YAC9B,cAAc,EAAE,CAAC,GAAG,KAAK,CAAC;SAC3B,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IAExC,OAAO;QACL,SAAS,EAAE,IAAI;QACf,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,MAAM;QACjC,KAAK,EAAE,SAAS,CAAC,KAAK;QACtB,gBAAgB,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE;QACrC,cAAc,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE;QACjC,SAAS,EAAE,SAAS,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC;QAChD,gBAAgB,EAAE,SAAS,CAAC,gBAAgB;QAC5C,QAAQ,EAAE,SAAS,CAAC,QAAQ;KAC7B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { CodeGraph } from './codeGraph.js';
|
|
2
|
+
export interface TaintFunctionNode {
|
|
3
|
+
id: string;
|
|
4
|
+
qualName: string;
|
|
5
|
+
bareName: string;
|
|
6
|
+
file: string;
|
|
7
|
+
callees: string[];
|
|
8
|
+
references: string[];
|
|
9
|
+
memberReferences: string[];
|
|
10
|
+
sourceHit: string | null;
|
|
11
|
+
sinkHit: string | null;
|
|
12
|
+
hasSource: boolean;
|
|
13
|
+
hasSink: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface TaintFunctionIndex {
|
|
16
|
+
fnByQual: Map<string, TaintFunctionNode>;
|
|
17
|
+
fnsByBareName: Map<string, TaintFunctionNode[]>;
|
|
18
|
+
totalCallSites: number;
|
|
19
|
+
}
|
|
20
|
+
export declare function buildTaintFunctionIndex(graph: CodeGraph, sources: Set<string>, sinks: Set<string>, customSources: Set<string>, customSinks: Set<string>): TaintFunctionIndex;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { frameworkRequestSourceForFunction } from './frameworkSources.js';
|
|
2
|
+
import { isDefaultChildProcessEnvPassthrough, pickSinkHit, pickSourceHit, } from './taintMatching.js';
|
|
3
|
+
const EMPTY_STRING_ARRAY = [];
|
|
4
|
+
export function buildTaintFunctionIndex(graph, sources, sinks, customSources, customSinks) {
|
|
5
|
+
const fnByQual = new Map();
|
|
6
|
+
const fnsByBareName = new Map();
|
|
7
|
+
let totalCallSites = 0;
|
|
8
|
+
for (const [file, graphFile] of graph.files) {
|
|
9
|
+
if (!graphFile.functions)
|
|
10
|
+
continue;
|
|
11
|
+
for (const fn of graphFile.functions) {
|
|
12
|
+
const node = buildTaintFunctionNode(file, graphFile, fn, sources, sinks, customSources, customSinks);
|
|
13
|
+
totalCallSites += node.callees.length;
|
|
14
|
+
fnByQual.set(node.id, node);
|
|
15
|
+
appendByBareName(fnsByBareName, node);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return { fnByQual, fnsByBareName, totalCallSites };
|
|
19
|
+
}
|
|
20
|
+
function buildTaintFunctionNode(file, graphFile, fn, sources, sinks, customSources, customSinks) {
|
|
21
|
+
const callees = optionalArray(fn.callSites);
|
|
22
|
+
const directCallSites = optionalArray(fn.directCallSites);
|
|
23
|
+
const memberCallSites = optionalArray(fn.memberCallSites);
|
|
24
|
+
const memberReferences = optionalArray(fn.memberReferences);
|
|
25
|
+
const memberAliases = optionalArray(fn.memberAliases);
|
|
26
|
+
const references = optionalArray(fn.references);
|
|
27
|
+
const sourceHit = resolveSourceHit(file, graphFile, fn, callees, directCallSites, memberCallSites, memberReferences, references, sources, customSources);
|
|
28
|
+
const sinkHit = resolveSinkHit(file, graphFile, callees, directCallSites, memberCallSites, memberAliases, sinks, customSinks);
|
|
29
|
+
return {
|
|
30
|
+
id: `${file}::${fn.name}@${fn.line}`,
|
|
31
|
+
qualName: fn.name,
|
|
32
|
+
bareName: bareName(fn.name),
|
|
33
|
+
file,
|
|
34
|
+
callees,
|
|
35
|
+
references,
|
|
36
|
+
memberReferences,
|
|
37
|
+
sourceHit,
|
|
38
|
+
sinkHit,
|
|
39
|
+
hasSource: isActiveSourceHit(sourceHit, sinkHit, memberReferences, customSources, customSinks),
|
|
40
|
+
hasSink: sinkHit !== null,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function resolveSourceHit(file, graphFile, fn, callees, directCallSites, memberCallSites, memberReferences, references, sources, customSources) {
|
|
44
|
+
return (frameworkRequestSourceForFunction({
|
|
45
|
+
file,
|
|
46
|
+
functionName: fn.name,
|
|
47
|
+
memberCallSites,
|
|
48
|
+
memberReferences,
|
|
49
|
+
parameters: fn.parameters ?? [],
|
|
50
|
+
enabledSources: sources,
|
|
51
|
+
references,
|
|
52
|
+
contextualCallSite: fn.contextualCallSite,
|
|
53
|
+
imports: graphFile.imports,
|
|
54
|
+
directCallSites,
|
|
55
|
+
}) ?? pickSourceHit(callees, references, sources, customSources));
|
|
56
|
+
}
|
|
57
|
+
function resolveSinkHit(file, graphFile, callees, directCallSites, memberCallSites, memberAliases, sinks, customSinks) {
|
|
58
|
+
return pickSinkHit(callees, directCallSites, memberCallSites, memberAliases, sinks, customSinks, file, graphFile);
|
|
59
|
+
}
|
|
60
|
+
function isActiveSourceHit(sourceHit, sinkHit, memberReferences, customSources, customSinks) {
|
|
61
|
+
return (sourceHit !== null &&
|
|
62
|
+
!isDefaultChildProcessEnvPassthrough(sourceHit, sinkHit, memberReferences, customSources, customSinks));
|
|
63
|
+
}
|
|
64
|
+
function appendByBareName(fnsByBareName, node) {
|
|
65
|
+
const existing = fnsByBareName.get(node.bareName);
|
|
66
|
+
if (existing) {
|
|
67
|
+
existing.push(node);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
fnsByBareName.set(node.bareName, [node]);
|
|
71
|
+
}
|
|
72
|
+
function optionalArray(values) {
|
|
73
|
+
return values ?? EMPTY_STRING_ARRAY;
|
|
74
|
+
}
|
|
75
|
+
function bareName(qualified) {
|
|
76
|
+
const dot = qualified.lastIndexOf('.');
|
|
77
|
+
if (dot < 0)
|
|
78
|
+
return qualified;
|
|
79
|
+
return qualified.slice(dot + 1);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=taintIndex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taintIndex.js","sourceRoot":"","sources":["../../src/core/taintIndex.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TaintFunctionIndex } from './taintIndex.js';
|
|
2
|
+
import type { TaintFlow } from './taintTypes.js';
|
|
3
|
+
export interface TaintTraversalResult {
|
|
4
|
+
flows: TaintFlow[];
|
|
5
|
+
truncatedSources: string[];
|
|
6
|
+
maxDepth: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function findTaintFlows(index: TaintFunctionIndex): TaintTraversalResult;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
const MAX_DEPTH = 12;
|
|
2
|
+
const MAX_FRONTIER_PER_STEP = 5000;
|
|
3
|
+
export function findTaintFlows(index) {
|
|
4
|
+
const flows = [];
|
|
5
|
+
const seen = new Set();
|
|
6
|
+
const truncatedSources = [];
|
|
7
|
+
for (const sourceFn of index.fnByQual.values()) {
|
|
8
|
+
if (!sourceFn.hasSource)
|
|
9
|
+
continue;
|
|
10
|
+
recordSameFunctionFlow(sourceFn, flows, seen);
|
|
11
|
+
if (findFlowsFromSource(sourceFn, index, flows, seen)) {
|
|
12
|
+
truncatedSources.push(sourceFn.qualName);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
sortTaintFlows(flows);
|
|
16
|
+
return {
|
|
17
|
+
flows,
|
|
18
|
+
truncatedSources: [...new Set(truncatedSources)].sort(),
|
|
19
|
+
maxDepth: MAX_DEPTH,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function recordSameFunctionFlow(sourceFn, flows, seen) {
|
|
23
|
+
if (!sourceFn.hasSink)
|
|
24
|
+
return;
|
|
25
|
+
const key = `${sourceFn.id}::${sourceFn.id}`;
|
|
26
|
+
if (seen.has(key))
|
|
27
|
+
return;
|
|
28
|
+
seen.add(key);
|
|
29
|
+
flows.push({
|
|
30
|
+
sourceFn: sourceFn.qualName,
|
|
31
|
+
sinkFn: sourceFn.qualName,
|
|
32
|
+
source: sourceFn.sourceHit,
|
|
33
|
+
sink: sourceFn.sinkHit,
|
|
34
|
+
path: [sourceFn.qualName],
|
|
35
|
+
files: [sourceFn.file],
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function findFlowsFromSource(sourceFn, index, flows, seen) {
|
|
39
|
+
const visited = new Set([sourceFn.id]);
|
|
40
|
+
let frontier = [{ node: sourceFn, path: [sourceFn] }];
|
|
41
|
+
let depth = 0;
|
|
42
|
+
let frontierCapped = false;
|
|
43
|
+
while (frontier.length > 0 && depth < MAX_DEPTH) {
|
|
44
|
+
depth += 1;
|
|
45
|
+
const result = expandFrontier(sourceFn, frontier, index, visited, flows, seen);
|
|
46
|
+
frontier = result.next;
|
|
47
|
+
frontierCapped ||= result.frontierCapped;
|
|
48
|
+
if (result.frontierCapped)
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
return frontier.length > 0 || frontierCapped;
|
|
52
|
+
}
|
|
53
|
+
function expandFrontier(sourceFn, frontier, index, visited, flows, seen) {
|
|
54
|
+
const next = [];
|
|
55
|
+
for (const entry of frontier) {
|
|
56
|
+
if (expandFrontierEntry(sourceFn, entry, index, visited, flows, seen, next)) {
|
|
57
|
+
return { next, frontierCapped: true };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return { next, frontierCapped: false };
|
|
61
|
+
}
|
|
62
|
+
function expandFrontierEntry(sourceFn, entry, index, visited, flows, seen, next) {
|
|
63
|
+
for (const calleeName of entry.node.callees) {
|
|
64
|
+
const candidates = index.fnsByBareName.get(calleeName) ?? [];
|
|
65
|
+
for (const candidate of candidates) {
|
|
66
|
+
if (addCandidate(sourceFn, entry, candidate, visited, flows, seen, next))
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
function addCandidate(sourceFn, entry, candidate, visited, flows, seen, next) {
|
|
73
|
+
if (visited.has(candidate.id))
|
|
74
|
+
return false;
|
|
75
|
+
visited.add(candidate.id);
|
|
76
|
+
const newPath = [...entry.path, candidate];
|
|
77
|
+
if (candidate.hasSink) {
|
|
78
|
+
recordPathFlow(sourceFn, candidate, newPath, flows, seen);
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
next.push({ node: candidate, path: newPath });
|
|
82
|
+
return next.length >= MAX_FRONTIER_PER_STEP;
|
|
83
|
+
}
|
|
84
|
+
function recordPathFlow(sourceFn, sinkFn, path, flows, seen) {
|
|
85
|
+
const flowKey = `${sourceFn.id}::${sinkFn.id}`;
|
|
86
|
+
if (seen.has(flowKey))
|
|
87
|
+
return;
|
|
88
|
+
seen.add(flowKey);
|
|
89
|
+
flows.push({
|
|
90
|
+
sourceFn: sourceFn.qualName,
|
|
91
|
+
sinkFn: sinkFn.qualName,
|
|
92
|
+
source: sourceFn.sourceHit,
|
|
93
|
+
sink: sinkFn.sinkHit,
|
|
94
|
+
path: path.map((node) => node.qualName),
|
|
95
|
+
files: filesInPath(path),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function filesInPath(path) {
|
|
99
|
+
const files = [];
|
|
100
|
+
for (const node of path) {
|
|
101
|
+
if (files[files.length - 1] !== node.file)
|
|
102
|
+
files.push(node.file);
|
|
103
|
+
}
|
|
104
|
+
return files;
|
|
105
|
+
}
|
|
106
|
+
function sortTaintFlows(flows) {
|
|
107
|
+
flows.sort((a, b) => {
|
|
108
|
+
if (a.sourceFn !== b.sourceFn)
|
|
109
|
+
return a.sourceFn.localeCompare(b.sourceFn);
|
|
110
|
+
return a.sinkFn.localeCompare(b.sinkFn);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=taintTraversal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taintTraversal.js","sourceRoot":"","sources":["../../src/core/taintTraversal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export interface TaintConfig {
|
|
2
|
+
/**
|
|
3
|
+
* Bare callee names treated as taint sources. Examples:
|
|
4
|
+
* "process.env" - environment variables (read sensitive config)
|
|
5
|
+
* "req.body" - HTTP request body
|
|
6
|
+
* "readFileSync" - disk read (could be user-controlled paths)
|
|
7
|
+
*
|
|
8
|
+
* Match is by bare name (the rightmost identifier in a member-access
|
|
9
|
+
* chain). "process.env.SECRET" -> "env"; "req.body.userId" -> "body".
|
|
10
|
+
* The default list captures the most common JS / Python / Go sources;
|
|
11
|
+
* users override via .projscanrc taint.sources.
|
|
12
|
+
*/
|
|
13
|
+
sources: string[];
|
|
14
|
+
/**
|
|
15
|
+
* Bare callee names treated as taint sinks. Examples:
|
|
16
|
+
* "exec" - child_process.exec
|
|
17
|
+
* "spawn" - child_process.spawn
|
|
18
|
+
* "writeFile" - fs.writeFile
|
|
19
|
+
* "query" - raw SQL (db.query("SELECT...${user}"))
|
|
20
|
+
* "eval" - JS eval / Python eval / etc.
|
|
21
|
+
*/
|
|
22
|
+
sinks: string[];
|
|
23
|
+
}
|
|
24
|
+
export interface TaintFlow {
|
|
25
|
+
/** Bare function name where the source was called. */
|
|
26
|
+
sourceFn: string;
|
|
27
|
+
/** Bare function name where the sink was called. */
|
|
28
|
+
sinkFn: string;
|
|
29
|
+
/** The source identifier (e.g. "env"). */
|
|
30
|
+
source: string;
|
|
31
|
+
/** The sink identifier (e.g. "exec"). */
|
|
32
|
+
sink: string;
|
|
33
|
+
/**
|
|
34
|
+
* Sequence of fully-qualified function names from sourceFn to sinkFn,
|
|
35
|
+
* inclusive at both ends. Length 1 means the same function reads the
|
|
36
|
+
* source and calls the sink (the most direct flow).
|
|
37
|
+
*/
|
|
38
|
+
path: string[];
|
|
39
|
+
/** Files touched by the path (in order, deduped). */
|
|
40
|
+
files: string[];
|
|
41
|
+
}
|
|
42
|
+
export interface TaintReport {
|
|
43
|
+
available: boolean;
|
|
44
|
+
reason?: string;
|
|
45
|
+
flowCount: number;
|
|
46
|
+
flows: TaintFlow[];
|
|
47
|
+
/** The effective sources/sinks list used for this run (after merging defaults + config). */
|
|
48
|
+
effectiveSources: string[];
|
|
49
|
+
effectiveSinks: string[];
|
|
50
|
+
/**
|
|
51
|
+
* 1.8+ - true when the BFS hit MAX_DEPTH for at least one source with
|
|
52
|
+
* a non-empty frontier still pending. When set, the agent should know
|
|
53
|
+
* that flows deeper than MAX_DEPTH may exist but weren't reported.
|
|
54
|
+
* Pairs with `truncatedSources` so a follow-up scan can re-target.
|
|
55
|
+
*/
|
|
56
|
+
truncated?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* 1.8+ - function names whose BFS exited at MAX_DEPTH with the
|
|
59
|
+
* frontier non-empty. Empty when no truncation occurred.
|
|
60
|
+
*/
|
|
61
|
+
truncatedSources?: string[];
|
|
62
|
+
/**
|
|
63
|
+
* 1.8+ - the depth cap actually used. Surfacing this lets agents
|
|
64
|
+
* notice when projscan's defaults shift between releases.
|
|
65
|
+
*/
|
|
66
|
+
maxDepth?: number;
|
|
67
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taintTypes.js","sourceRoot":"","sources":["../../src/core/taintTypes.ts"],"names":[],"mappings":""}
|