@archpilotlabs/archpilot 0.2.2 → 0.2.3

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.
Files changed (296) hide show
  1. package/dist/archpilot-cli.js +516 -105
  2. package/dist/cli/src/archpilot-cli.js +5523 -0
  3. package/dist/cli/src/archpilot-cli.js.map +1 -0
  4. package/dist/core/src/adr/adrLoader.js +97 -0
  5. package/dist/core/src/adr/adrLoader.js.map +1 -0
  6. package/dist/core/src/adr/adrParser.js +77 -0
  7. package/dist/core/src/adr/adrParser.js.map +1 -0
  8. package/dist/core/src/adr/adrTemplate.js +45 -0
  9. package/dist/core/src/adr/adrTemplate.js.map +1 -0
  10. package/dist/core/src/adr/adrTypes.js +3 -0
  11. package/dist/core/src/adr/adrTypes.js.map +1 -0
  12. package/dist/core/src/adr/adrValidation.js +160 -0
  13. package/dist/core/src/adr/adrValidation.js.map +1 -0
  14. package/dist/core/src/adr/index.js +9 -0
  15. package/dist/core/src/adr/index.js.map +1 -0
  16. package/dist/core/src/adrManagement.js +174 -0
  17. package/dist/core/src/adrManagement.js.map +1 -0
  18. package/dist/core/src/adrRequirementStatus.js +62 -0
  19. package/dist/core/src/adrRequirementStatus.js.map +1 -0
  20. package/dist/core/src/adrScaffoldGeneration.js +325 -0
  21. package/dist/core/src/adrScaffoldGeneration.js.map +1 -0
  22. package/dist/core/src/apiDesignAnalysis.js +869 -0
  23. package/dist/core/src/apiDesignAnalysis.js.map +1 -0
  24. package/dist/core/src/applicationLayeringAnalysis.js +920 -0
  25. package/dist/core/src/applicationLayeringAnalysis.js.map +1 -0
  26. package/dist/core/src/applyRulePack.js +117 -0
  27. package/dist/core/src/applyRulePack.js.map +1 -0
  28. package/dist/core/src/architectureBaseline.js +271 -0
  29. package/dist/core/src/architectureBaseline.js.map +1 -0
  30. package/dist/core/src/architectureComponentDiscoveryDefaults.js +139 -0
  31. package/dist/core/src/architectureComponentDiscoveryDefaults.js.map +1 -0
  32. package/dist/core/src/architectureDependencyContext.js +316 -0
  33. package/dist/core/src/architectureDependencyContext.js.map +1 -0
  34. package/dist/core/src/architectureDriftDetection.js +96 -0
  35. package/dist/core/src/architectureDriftDetection.js.map +1 -0
  36. package/dist/core/src/architectureDriftTimeline.js +221 -0
  37. package/dist/core/src/architectureDriftTimeline.js.map +1 -0
  38. package/dist/core/src/architectureGovernanceBaseline.js +469 -0
  39. package/dist/core/src/architectureGovernanceBaseline.js.map +1 -0
  40. package/dist/core/src/architectureHealthHistory.js +208 -0
  41. package/dist/core/src/architectureHealthHistory.js.map +1 -0
  42. package/dist/core/src/architectureHealthScore.js +657 -0
  43. package/dist/core/src/architectureHealthScore.js.map +1 -0
  44. package/dist/core/src/architectureInit.js +826 -0
  45. package/dist/core/src/architectureInit.js.map +1 -0
  46. package/dist/core/src/architectureMap.js +727 -0
  47. package/dist/core/src/architectureMap.js.map +1 -0
  48. package/dist/core/src/architectureMigrationPreview.js +467 -0
  49. package/dist/core/src/architectureMigrationPreview.js.map +1 -0
  50. package/dist/core/src/architectureModelRefresh.js +209 -0
  51. package/dist/core/src/architectureModelRefresh.js.map +1 -0
  52. package/dist/core/src/architectureReportWorkflow.js +139 -0
  53. package/dist/core/src/architectureReportWorkflow.js.map +1 -0
  54. package/dist/core/src/architectureValidation.js +3879 -0
  55. package/dist/core/src/architectureValidation.js.map +1 -0
  56. package/dist/core/src/architectureWorkspaceModel.js +166 -0
  57. package/dist/core/src/architectureWorkspaceModel.js.map +1 -0
  58. package/dist/core/src/authorizationTenantAnalysis.js +652 -0
  59. package/dist/core/src/authorizationTenantAnalysis.js.map +1 -0
  60. package/dist/core/src/bootstrapArchitectureConfig.js +150 -0
  61. package/dist/core/src/bootstrapArchitectureConfig.js.map +1 -0
  62. package/dist/core/src/changeRisk/changeRiskAssessment.js +251 -0
  63. package/dist/core/src/changeRisk/changeRiskAssessment.js.map +1 -0
  64. package/dist/core/src/changeRisk/changeRiskTypes.js +3 -0
  65. package/dist/core/src/changeRisk/changeRiskTypes.js.map +1 -0
  66. package/dist/core/src/changeRisk/index.js +6 -0
  67. package/dist/core/src/changeRisk/index.js.map +1 -0
  68. package/dist/core/src/ci/githubInlineAnnotations.js +245 -0
  69. package/dist/core/src/ci/githubInlineAnnotations.js.map +1 -0
  70. package/dist/core/src/ci/githubPrCommentAdapter.js +232 -0
  71. package/dist/core/src/ci/githubPrCommentAdapter.js.map +1 -0
  72. package/dist/core/src/ciWorkflowTemplates.js +1042 -0
  73. package/dist/core/src/ciWorkflowTemplates.js.map +1 -0
  74. package/dist/core/src/compliance/complianceExportBuilder.js +122 -0
  75. package/dist/core/src/compliance/complianceExportBuilder.js.map +1 -0
  76. package/dist/core/src/compliance/complianceExportTypes.js +3 -0
  77. package/dist/core/src/compliance/complianceExportTypes.js.map +1 -0
  78. package/dist/core/src/compliance/complianceExportWriter.js +48 -0
  79. package/dist/core/src/compliance/complianceExportWriter.js.map +1 -0
  80. package/dist/core/src/compliance/complianceRulePackResolver.js +62 -0
  81. package/dist/core/src/compliance/complianceRulePackResolver.js.map +1 -0
  82. package/dist/core/src/config/index.js +17 -0
  83. package/dist/core/src/config/index.js.map +1 -0
  84. package/dist/core/src/config/projectConfig.js +224 -0
  85. package/dist/core/src/config/projectConfig.js.map +1 -0
  86. package/dist/core/src/config/projectIdentity.js +160 -0
  87. package/dist/core/src/config/projectIdentity.js.map +1 -0
  88. package/dist/core/src/dataQueryRiskDetection.js +1203 -0
  89. package/dist/core/src/dataQueryRiskDetection.js.map +1 -0
  90. package/dist/core/src/dependencyValidation.js +2557 -0
  91. package/dist/core/src/dependencyValidation.js.map +1 -0
  92. package/dist/core/src/discoverAdrs.js +15 -0
  93. package/dist/core/src/discoverAdrs.js.map +1 -0
  94. package/dist/core/src/drift/driftComparator.js +49 -0
  95. package/dist/core/src/drift/driftComparator.js.map +1 -0
  96. package/dist/core/src/drift/driftSnapshotLoader.js +136 -0
  97. package/dist/core/src/drift/driftSnapshotLoader.js.map +1 -0
  98. package/dist/core/src/drift/driftSnapshotTypes.js +3 -0
  99. package/dist/core/src/drift/driftSnapshotTypes.js.map +1 -0
  100. package/dist/core/src/drift/driftSnapshotWriter.js +48 -0
  101. package/dist/core/src/drift/driftSnapshotWriter.js.map +1 -0
  102. package/dist/core/src/drift/index.js +6 -0
  103. package/dist/core/src/drift/index.js.map +1 -0
  104. package/dist/core/src/eventArchitectureAnalysis.js +925 -0
  105. package/dist/core/src/eventArchitectureAnalysis.js.map +1 -0
  106. package/dist/core/src/findingTargetResolution.js +117 -0
  107. package/dist/core/src/findingTargetResolution.js.map +1 -0
  108. package/dist/core/src/generateArchitectureDiagrams.js +57 -0
  109. package/dist/core/src/generateArchitectureDiagrams.js.map +1 -0
  110. package/dist/core/src/generateImpactAnalysis.js +366 -0
  111. package/dist/core/src/generateImpactAnalysis.js.map +1 -0
  112. package/dist/core/src/generateOnboardingDocs.js +262 -0
  113. package/dist/core/src/generateOnboardingDocs.js.map +1 -0
  114. package/dist/core/src/governance/cloudConnection.js +203 -0
  115. package/dist/core/src/governance/cloudConnection.js.map +1 -0
  116. package/dist/core/src/governance/governanceContracts.js +129 -0
  117. package/dist/core/src/governance/governanceContracts.js.map +1 -0
  118. package/dist/core/src/governance/governanceGitMetadata.js +78 -0
  119. package/dist/core/src/governance/governanceGitMetadata.js.map +1 -0
  120. package/dist/core/src/governance/governanceUploadClient.js +119 -0
  121. package/dist/core/src/governance/governanceUploadClient.js.map +1 -0
  122. package/dist/core/src/governance/governanceUploadLimitErrorFormatting.js +155 -0
  123. package/dist/core/src/governance/governanceUploadLimitErrorFormatting.js.map +1 -0
  124. package/dist/core/src/governance/governanceUploadPayload.js +439 -0
  125. package/dist/core/src/governance/governanceUploadPayload.js.map +1 -0
  126. package/dist/core/src/governance/runGovernanceUpload.js +103 -0
  127. package/dist/core/src/governance/runGovernanceUpload.js.map +1 -0
  128. package/dist/core/src/impactAnalysisEngine.js +376 -0
  129. package/dist/core/src/impactAnalysisEngine.js.map +1 -0
  130. package/dist/core/src/initializationState.js +99 -0
  131. package/dist/core/src/initializationState.js.map +1 -0
  132. package/dist/core/src/managedArtifacts.js +151 -0
  133. package/dist/core/src/managedArtifacts.js.map +1 -0
  134. package/dist/core/src/moduleContractValidation.js +266 -0
  135. package/dist/core/src/moduleContractValidation.js.map +1 -0
  136. package/dist/core/src/moduleContractsGenerator.js +337 -0
  137. package/dist/core/src/moduleContractsGenerator.js.map +1 -0
  138. package/dist/core/src/moduleDiscovery.js +416 -0
  139. package/dist/core/src/moduleDiscovery.js.map +1 -0
  140. package/dist/core/src/moduleScope.js +426 -0
  141. package/dist/core/src/moduleScope.js.map +1 -0
  142. package/dist/core/src/onboardingGuidance.js +74 -0
  143. package/dist/core/src/onboardingGuidance.js.map +1 -0
  144. package/dist/core/src/operationalLogging.js +7 -0
  145. package/dist/core/src/operationalLogging.js.map +1 -0
  146. package/dist/core/src/packageVersion.js +52 -0
  147. package/dist/core/src/packageVersion.js.map +1 -0
  148. package/dist/core/src/policy/effectivePolicyResolver.js +91 -0
  149. package/dist/core/src/policy/effectivePolicyResolver.js.map +1 -0
  150. package/dist/core/src/policy/exceptionLoader.js +285 -0
  151. package/dist/core/src/policy/exceptionLoader.js.map +1 -0
  152. package/dist/core/src/policy/remotePolicyLoader.js +227 -0
  153. package/dist/core/src/policy/remotePolicyLoader.js.map +1 -0
  154. package/dist/core/src/policy/remotePolicyTypes.js +3 -0
  155. package/dist/core/src/policy/remotePolicyTypes.js.map +1 -0
  156. package/dist/core/src/policy/riskPolicyConfig.js +206 -0
  157. package/dist/core/src/policy/riskPolicyConfig.js.map +1 -0
  158. package/dist/core/src/policy/riskPolicyEnforcement.js +203 -0
  159. package/dist/core/src/policy/riskPolicyEnforcement.js.map +1 -0
  160. package/dist/core/src/policy/riskPolicyExitCode.js +16 -0
  161. package/dist/core/src/policy/riskPolicyExitCode.js.map +1 -0
  162. package/dist/core/src/policy/riskPolicyInitializer.js +90 -0
  163. package/dist/core/src/policy/riskPolicyInitializer.js.map +1 -0
  164. package/dist/core/src/quickFix/quickFixEngine.js +132 -0
  165. package/dist/core/src/quickFix/quickFixEngine.js.map +1 -0
  166. package/dist/core/src/quickFix/quickFixMessaging.js +15 -0
  167. package/dist/core/src/quickFix/quickFixMessaging.js.map +1 -0
  168. package/dist/core/src/quickFix/quickFixProviders.js +87 -0
  169. package/dist/core/src/quickFix/quickFixProviders.js.map +1 -0
  170. package/dist/core/src/quickFix/quickFixTypes.js +3 -0
  171. package/dist/core/src/quickFix/quickFixTypes.js.map +1 -0
  172. package/dist/core/src/remediation/fileHelpers.js +86 -0
  173. package/dist/core/src/remediation/fileHelpers.js.map +1 -0
  174. package/dist/core/src/remediation/fixRegistry.js +645 -0
  175. package/dist/core/src/remediation/fixRegistry.js.map +1 -0
  176. package/dist/core/src/remediation/index.js +8 -0
  177. package/dist/core/src/remediation/index.js.map +1 -0
  178. package/dist/core/src/remediation/remediationEngine.js +207 -0
  179. package/dist/core/src/remediation/remediationEngine.js.map +1 -0
  180. package/dist/core/src/reporting/adrReporter.js +59 -0
  181. package/dist/core/src/reporting/adrReporter.js.map +1 -0
  182. package/dist/core/src/reporting/architectureBaselineReporter.js +64 -0
  183. package/dist/core/src/reporting/architectureBaselineReporter.js.map +1 -0
  184. package/dist/core/src/reporting/architectureDiagramReporter.js +148 -0
  185. package/dist/core/src/reporting/architectureDiagramReporter.js.map +1 -0
  186. package/dist/core/src/reporting/architectureDriftTimelineReporter.js +44 -0
  187. package/dist/core/src/reporting/architectureDriftTimelineReporter.js.map +1 -0
  188. package/dist/core/src/reporting/architectureHealthHistoryReporter.js +51 -0
  189. package/dist/core/src/reporting/architectureHealthHistoryReporter.js.map +1 -0
  190. package/dist/core/src/reporting/architectureMapReporter.js +228 -0
  191. package/dist/core/src/reporting/architectureMapReporter.js.map +1 -0
  192. package/dist/core/src/reporting/architecturePrCommentReporter.js +324 -0
  193. package/dist/core/src/reporting/architecturePrCommentReporter.js.map +1 -0
  194. package/dist/core/src/reporting/architecturePrReviewReporter.js +389 -0
  195. package/dist/core/src/reporting/architecturePrReviewReporter.js.map +1 -0
  196. package/dist/core/src/reporting/architectureReportArtifacts.js +166 -0
  197. package/dist/core/src/reporting/architectureReportArtifacts.js.map +1 -0
  198. package/dist/core/src/reporting/architectureReviewReportGenerator.js +382 -0
  199. package/dist/core/src/reporting/architectureReviewReportGenerator.js.map +1 -0
  200. package/dist/core/src/reporting/architectureReviewReporter.js +1633 -0
  201. package/dist/core/src/reporting/architectureReviewReporter.js.map +1 -0
  202. package/dist/core/src/reporting/architectureRiskAssessment.js +101 -0
  203. package/dist/core/src/reporting/architectureRiskAssessment.js.map +1 -0
  204. package/dist/core/src/reporting/architectureScoreBadge.js +177 -0
  205. package/dist/core/src/reporting/architectureScoreBadge.js.map +1 -0
  206. package/dist/core/src/reporting/architectureSupplementalReporters.js +124 -0
  207. package/dist/core/src/reporting/architectureSupplementalReporters.js.map +1 -0
  208. package/dist/core/src/reporting/changeRiskAssessment.js +6 -0
  209. package/dist/core/src/reporting/changeRiskAssessment.js.map +1 -0
  210. package/dist/core/src/reporting/changeRiskTypes.js +3 -0
  211. package/dist/core/src/reporting/changeRiskTypes.js.map +1 -0
  212. package/dist/core/src/reporting/impactAnalysisReporter.js +111 -0
  213. package/dist/core/src/reporting/impactAnalysisReporter.js.map +1 -0
  214. package/dist/core/src/reporting/onboardingDocsReporter.js +113 -0
  215. package/dist/core/src/reporting/onboardingDocsReporter.js.map +1 -0
  216. package/dist/core/src/reporting/rulePackReporter.js +61 -0
  217. package/dist/core/src/reporting/rulePackReporter.js.map +1 -0
  218. package/dist/core/src/reporting/safetyControlsDetection.js +343 -0
  219. package/dist/core/src/reporting/safetyControlsDetection.js.map +1 -0
  220. package/dist/core/src/resolveRuleAdrs.js +31 -0
  221. package/dist/core/src/resolveRuleAdrs.js.map +1 -0
  222. package/dist/core/src/reviewGenerationWorkflow.js +220 -0
  223. package/dist/core/src/reviewGenerationWorkflow.js.map +1 -0
  224. package/dist/core/src/rulePacks/index.js +17 -0
  225. package/dist/core/src/rulePacks/index.js.map +1 -0
  226. package/dist/core/src/rulePacks/layeredMonolithRulePack.js +45 -0
  227. package/dist/core/src/rulePacks/layeredMonolithRulePack.js.map +1 -0
  228. package/dist/core/src/rulePacks/modularMonolithRulePack.js +41 -0
  229. package/dist/core/src/rulePacks/modularMonolithRulePack.js.map +1 -0
  230. package/dist/core/src/rulePacks/types.js +3 -0
  231. package/dist/core/src/rulePacks/types.js.map +1 -0
  232. package/dist/core/src/setupNextSteps.js +939 -0
  233. package/dist/core/src/setupNextSteps.js.map +1 -0
  234. package/dist/core/src/setupRefresh.js +152 -0
  235. package/dist/core/src/setupRefresh.js.map +1 -0
  236. package/dist/core/src/smartInit/apiDbHintDetection.js +836 -0
  237. package/dist/core/src/smartInit/apiDbHintDetection.js.map +1 -0
  238. package/dist/core/src/smartInit/architectureProposalBuilder.js +1215 -0
  239. package/dist/core/src/smartInit/architectureProposalBuilder.js.map +1 -0
  240. package/dist/core/src/smartInit/architectureStyleDetection.js +472 -0
  241. package/dist/core/src/smartInit/architectureStyleDetection.js.map +1 -0
  242. package/dist/core/src/smartInit/archpilotIgnore.js +139 -0
  243. package/dist/core/src/smartInit/archpilotIgnore.js.map +1 -0
  244. package/dist/core/src/smartInit/componentDetection.js +1084 -0
  245. package/dist/core/src/smartInit/componentDetection.js.map +1 -0
  246. package/dist/core/src/smartInit/implementationProfileResolution.js +53 -0
  247. package/dist/core/src/smartInit/implementationProfileResolution.js.map +1 -0
  248. package/dist/core/src/smartInit/index.js +31 -0
  249. package/dist/core/src/smartInit/index.js.map +1 -0
  250. package/dist/core/src/smartInit/moduleDetection.js +982 -0
  251. package/dist/core/src/smartInit/moduleDetection.js.map +1 -0
  252. package/dist/core/src/smartInit/projectKindDetection.js +437 -0
  253. package/dist/core/src/smartInit/projectKindDetection.js.map +1 -0
  254. package/dist/core/src/smartInit/repoTopologyDetection.js +470 -0
  255. package/dist/core/src/smartInit/repoTopologyDetection.js.map +1 -0
  256. package/dist/core/src/smartInit/runContext.js +112 -0
  257. package/dist/core/src/smartInit/runContext.js.map +1 -0
  258. package/dist/core/src/smartInit/smartInitEngine.js +94 -0
  259. package/dist/core/src/smartInit/smartInitEngine.js.map +1 -0
  260. package/dist/core/src/smartInit/stackDetection.js +503 -0
  261. package/dist/core/src/smartInit/stackDetection.js.map +1 -0
  262. package/dist/core/src/smartInit/toolingHintDetection.js +345 -0
  263. package/dist/core/src/smartInit/toolingHintDetection.js.map +1 -0
  264. package/dist/core/src/sourceScopeClassification.js +83 -0
  265. package/dist/core/src/sourceScopeClassification.js.map +1 -0
  266. package/dist/core/src/stackAdapters.js +2475 -0
  267. package/dist/core/src/stackAdapters.js.map +1 -0
  268. package/dist/core/src/stackMetadata.js +157 -0
  269. package/dist/core/src/stackMetadata.js.map +1 -0
  270. package/dist/core/src/suppressions/index.js +3 -0
  271. package/dist/core/src/suppressions/index.js.map +1 -0
  272. package/dist/core/src/suppressions/suppressionReporter.js +38 -0
  273. package/dist/core/src/suppressions/suppressionReporter.js.map +1 -0
  274. package/dist/core/src/suppressions/suppressionTypes.js +3 -0
  275. package/dist/core/src/suppressions/suppressionTypes.js.map +1 -0
  276. package/dist/core/src/suppressions/suppressionValidator.js +119 -0
  277. package/dist/core/src/suppressions/suppressionValidator.js.map +1 -0
  278. package/dist/core/src/transactionDomainAnalysis.js +1416 -0
  279. package/dist/core/src/transactionDomainAnalysis.js.map +1 -0
  280. package/dist/core/src/validation/changedFilesResolver.js +165 -0
  281. package/dist/core/src/validation/changedFilesResolver.js.map +1 -0
  282. package/dist/core/src/validationProfiling.js +33 -0
  283. package/dist/core/src/validationProfiling.js.map +1 -0
  284. package/dist/core/src/validationRuleExplanations.js +69 -0
  285. package/dist/core/src/validationRuleExplanations.js.map +1 -0
  286. package/dist/core/src/validationSourceInventory.js +200 -0
  287. package/dist/core/src/validationSourceInventory.js.map +1 -0
  288. package/dist/core/src/validationSuppressions.js +231 -0
  289. package/dist/core/src/validationSuppressions.js.map +1 -0
  290. package/dist/core/src/validationTypeScriptAstCache.js +82 -0
  291. package/dist/core/src/validationTypeScriptAstCache.js.map +1 -0
  292. package/dist/core/src/validationWorkflow.js +222 -0
  293. package/dist/core/src/validationWorkflow.js.map +1 -0
  294. package/dist/core/src/workspaceRoot.js +68 -0
  295. package/dist/core/src/workspaceRoot.js.map +1 -0
  296. package/package.json +1 -1
@@ -0,0 +1,652 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.detectAuthorizationTenantFindings = detectAuthorizationTenantFindings;
37
+ const path = __importStar(require("node:path"));
38
+ const node_fs_1 = require("node:fs");
39
+ const ts = __importStar(require("typescript"));
40
+ const moduleDiscovery_1 = require("./moduleDiscovery");
41
+ const archpilotIgnore_1 = require("./smartInit/archpilotIgnore");
42
+ const validationProfiling_1 = require("./validationProfiling");
43
+ const RuleIds = {
44
+ AUTH_MISSING_ENFORCEMENT: 'AP-AUTH-001',
45
+ AUTH_INCONSISTENT_ENFORCEMENT: 'AP-AUTH-002',
46
+ AUTH_WRONG_LAYER: 'AP-AUTH-003',
47
+ TEN_MISSING_CONTEXT_PROPAGATION: 'AP-TEN-001',
48
+ TEN_MISSING_ENFORCEMENT: 'AP-TEN-002',
49
+ TEN_CROSS_TENANT_RISK: 'AP-TEN-003',
50
+ TEN_MODEL_UNDOCUMENTED: 'AP-TEN-004',
51
+ };
52
+ const maxFileSizeBytes = 384 * 1024;
53
+ const supportedExtensions = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.java', '.py', '.php', '.cs', '.go']);
54
+ const ignoredDirectoryNames = new Set([
55
+ '.git',
56
+ '.archpilot',
57
+ '.next',
58
+ '.vscode-test',
59
+ 'node_modules',
60
+ 'dist',
61
+ 'build',
62
+ 'out',
63
+ 'coverage',
64
+ 'test',
65
+ 'tests',
66
+ '__tests__',
67
+ 'fixtures',
68
+ 'smoke',
69
+ 'examples',
70
+ 'docs',
71
+ 'reports',
72
+ 'generated',
73
+ ]);
74
+ const protectedOperationPattern = /\b(create|update|delete|remove|revoke|approve|assign|invite|export|payment|billing|member|team|org|repository|token|policy|exception|admin)\b/iu;
75
+ const publicEndpointPattern = /\b(health|ready|live|login|logout|callback|oauth|public|static|status)\b/iu;
76
+ const authEvidencePattern = /@(?:UseGuards|Roles|Permissions|RequirePermission|PreAuthorize|PostAuthorize|Secured|RolesAllowed)\b|\[(?:Authorize)\b[^\]]*\]|\b(?:Depends|Security)\s*\([^)]*(?:auth|oauth|current_user|currentUser|permission|role|scope)|\b(?:auth|authn|authz|authorize|authorized|authorization|permission|permissions|role|roles|policy|can|jwt|bearer|oauth|current_user|currentUser|requireRole\w*|RequireRole\w*|require_role|AuthGuard|JwtAuthGuard|RolesGuard|PermissionGuard|SecurityContextHolder|Authentication|Principal)(?:Middleware|Guard|Policy|Checker|Dependency)?\b/iu;
77
+ const publicEvidencePattern = /@Public\b|@PermitAll\b|\[AllowAnonymous\b[^\]]*\]|permitAll\s*\(|anonymous\(\)|permitAll\b|AllowAnonymous\b/u;
78
+ const roleEvidencePattern = /@(?:Roles|Permissions|RequirePermission|PreAuthorize|Secured|RolesAllowed)\s*(?:\(|\b)([^)\n]*)|\[Authorize\s*\([^)\]]*(?:Roles|Policy)\s*=|(?:requireRole\w*|RequireRole\w*|require_role|RoleChecker|adminMiddleware|can:|permission:|scopes?\s*=|Security\s*\([^)]*scopes)\b/u;
79
+ const tenantSignalPattern = /\b(?:tenantId|tenant_id|organizationId|organization_id|orgId|org_id|workspaceId|workspace_id|accountId|account_id|companyId|company_id|customerId|customer_id|TenantContext|CurrentTenant|TenantResolver|TenantProvider|request\.tenant|req\.tenant|user\.tenantId|user\.tenant_id|user\.organizationId|user\.organization_id|user\.orgId|user\.accountId|user\.workspaceId|user\.companyId|user\.customerId|HibernateFilter|CurrentTenant)\b/u;
80
+ const tenantPredicateEvidencePattern = /\b(?:tenantId|tenant_id|organizationId|organization_id|orgId|org_id|workspaceId|workspace_id|accountId|account_id|companyId|company_id|customerId|customer_id|TenantContext|CurrentTenant|TenantResolver|TenantProvider|request\.tenant|req\.tenant|user\.tenantId|user\.tenant_id|user\.organizationId|user\.organization_id|user\.orgId|user\.accountId|user\.workspaceId|user\.companyId|user\.customerId|HibernateFilter|CurrentTenant)\b/u;
81
+ const repositoryRolePattern = /\b(?:role|roles|permission|permissions|isAdmin|hasRole|hasPermission|SecurityContextHolder|Authentication|Principal)\b/u;
82
+ function normalizePath(value) {
83
+ return value.replace(/\\/g, '/');
84
+ }
85
+ function toPosixRelative(workspaceRoot, absolutePath) {
86
+ return normalizePath(path.relative(workspaceRoot, absolutePath));
87
+ }
88
+ async function readTextFileIfReasonable(filePath, sourceInventory) {
89
+ if (sourceInventory) {
90
+ return sourceInventory.readText(filePath, { maxFileSizeBytes });
91
+ }
92
+ try {
93
+ const stats = await node_fs_1.promises.stat(filePath);
94
+ if (stats.size > maxFileSizeBytes) {
95
+ return undefined;
96
+ }
97
+ return await node_fs_1.promises.readFile(filePath, { encoding: 'utf8' });
98
+ }
99
+ catch {
100
+ return undefined;
101
+ }
102
+ }
103
+ async function collectSourceFiles(workspaceRoot, sourceInventory) {
104
+ if (sourceInventory) {
105
+ const files = await sourceInventory.getTextFiles({
106
+ extensions: [...supportedExtensions],
107
+ ignoredDirectoryNames: [...ignoredDirectoryNames],
108
+ maxFileSizeBytes,
109
+ });
110
+ return files.map((file) => ({
111
+ relativePath: file.relativePath,
112
+ content: file.content,
113
+ extension: file.extension,
114
+ }));
115
+ }
116
+ const ignoreMatcher = (0, archpilotIgnore_1.loadArchpilotIgnoreMatcher)(workspaceRoot);
117
+ const collected = [];
118
+ const stack = [workspaceRoot];
119
+ while (stack.length > 0) {
120
+ const current = stack.pop();
121
+ if (!current) {
122
+ continue;
123
+ }
124
+ let entries;
125
+ try {
126
+ entries = await node_fs_1.promises.readdir(current, { withFileTypes: true });
127
+ }
128
+ catch {
129
+ continue;
130
+ }
131
+ for (const entry of entries) {
132
+ const absoluteEntryPath = path.join(current, entry.name);
133
+ const relativeEntryPath = toPosixRelative(workspaceRoot, absoluteEntryPath);
134
+ if (ignoreMatcher.isIgnored(relativeEntryPath)) {
135
+ continue;
136
+ }
137
+ if (entry.isDirectory()) {
138
+ if (entry.name.startsWith('.') || ignoredDirectoryNames.has(entry.name)) {
139
+ continue;
140
+ }
141
+ stack.push(absoluteEntryPath);
142
+ continue;
143
+ }
144
+ const extension = path.extname(entry.name).toLowerCase();
145
+ if (!supportedExtensions.has(extension)) {
146
+ continue;
147
+ }
148
+ const content = await readTextFileIfReasonable(absoluteEntryPath, sourceInventory);
149
+ if (content === undefined) {
150
+ continue;
151
+ }
152
+ collected.push({ relativePath: relativeEntryPath, content, extension });
153
+ }
154
+ }
155
+ return collected.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
156
+ }
157
+ function lineNumberForOffset(content, offset) {
158
+ let line = 1;
159
+ for (let index = 0; index < offset && index < content.length; index += 1) {
160
+ if (content[index] === '\n') {
161
+ line += 1;
162
+ }
163
+ }
164
+ return line;
165
+ }
166
+ function inferModuleForPath(contract, relativePath) {
167
+ const normalized = normalizePath(relativePath);
168
+ const modulesRoot = (0, moduleDiscovery_1.resolveModulesRootFromContract)(contract);
169
+ for (const [moduleName, reference] of Object.entries(contract.modules ?? {})) {
170
+ const modulePath = normalizePath(reference.path ?? `${modulesRoot}/${moduleName}`);
171
+ if (normalized === modulePath || normalized.startsWith(`${modulePath}/`)) {
172
+ return moduleName;
173
+ }
174
+ }
175
+ return undefined;
176
+ }
177
+ function createFinding(input) {
178
+ return {
179
+ id: input.id,
180
+ severity: input.severity ?? 'warning',
181
+ passed: false,
182
+ message: input.message,
183
+ findingType: 'file-scope',
184
+ filePath: input.file.relativePath,
185
+ sourceFile: input.file.relativePath,
186
+ ...(input.line ? { sourceLine: input.line } : {}),
187
+ ...(input.module ? { module: input.module } : {}),
188
+ ...(input.target ? { target: input.target } : {}),
189
+ };
190
+ }
191
+ function getTypeScriptDeclaredRoles(file, astCache) {
192
+ const sourceFile = astCache
193
+ ? astCache.parseSourceFile({
194
+ filePath: file.relativePath,
195
+ sourceText: file.content,
196
+ scriptTarget: ts.ScriptTarget.Latest,
197
+ setParentNodes: true,
198
+ })
199
+ : ts.createSourceFile(file.relativePath, file.content, ts.ScriptTarget.Latest, true);
200
+ const roles = new Set();
201
+ const visit = (node) => {
202
+ if ((ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node)) && node.name) {
203
+ const name = node.name.text;
204
+ if (/Controller$/u.test(name)) {
205
+ roles.add('controller');
206
+ }
207
+ if (/Service$/u.test(name)) {
208
+ roles.add('service');
209
+ }
210
+ if (/(Repository|Dao)$/u.test(name)) {
211
+ roles.add('repository');
212
+ }
213
+ }
214
+ ts.forEachChild(node, visit);
215
+ };
216
+ visit(sourceFile);
217
+ return [...roles];
218
+ }
219
+ function getDeclaredRoles(file, astCache) {
220
+ if (file.extension === '.ts' || file.extension === '.tsx' || file.extension === '.js' || file.extension === '.jsx' || file.extension === '.mjs' || file.extension === '.cjs') {
221
+ return getTypeScriptDeclaredRoles(file, astCache);
222
+ }
223
+ if (file.extension === '.java' || file.extension === '.cs') {
224
+ const roles = new Set();
225
+ if (/\bclass\s+\w*Controller\b/u.test(file.content) || /@(?:Controller|RestController)\b|\[ApiController\]/u.test(file.content)) {
226
+ roles.add('controller');
227
+ }
228
+ if (/\bclass\s+\w*Service\b/u.test(file.content) || /@Service\b/u.test(file.content)) {
229
+ roles.add('service');
230
+ }
231
+ if (/\bclass\s+\w*(?:Repository|Dao)\b/u.test(file.content) || /@Repository\b/u.test(file.content)) {
232
+ roles.add('repository');
233
+ }
234
+ return [...roles];
235
+ }
236
+ const lowerPath = file.relativePath.toLowerCase();
237
+ const roles = new Set();
238
+ if (/(^|\/)(controllers?|routers?|routes?|handlers?)\//u.test(lowerPath) || /controller\.(php|py|go)$/u.test(lowerPath)) {
239
+ roles.add('controller');
240
+ }
241
+ if (/(^|\/)(services?)\//u.test(lowerPath) || /service\.(php|py|go)$/u.test(lowerPath)) {
242
+ roles.add('service');
243
+ }
244
+ if (/(^|\/)(repositories?|repository|dao|data)\//u.test(lowerPath) || /(repository|repo|dao)\.(php|py|go)$/u.test(lowerPath)) {
245
+ roles.add('repository');
246
+ }
247
+ return [...roles];
248
+ }
249
+ function isControllerFile(file, astCache) {
250
+ const roles = getDeclaredRoles(file, astCache);
251
+ return (/(^|[./_-])controller\.(ts|tsx|java)$/iu.test(file.relativePath) ||
252
+ roles.includes('controller'));
253
+ }
254
+ function isRepositoryFile(file, astCache) {
255
+ const roles = getDeclaredRoles(file, astCache);
256
+ return (/(^|[./_-])(?:repository|repo|dao)\.(ts|tsx|js|jsx|mjs|cjs|java|cs|py|php|go)$/iu.test(file.relativePath) ||
257
+ roles.includes('repository'));
258
+ }
259
+ function isServiceFile(file, astCache) {
260
+ const roles = getDeclaredRoles(file, astCache);
261
+ return (/(^|[./_-])service\.(ts|tsx|js|jsx|mjs|cjs|java|cs|py|php|go)$/iu.test(file.relativePath) ||
262
+ roles.includes('service'));
263
+ }
264
+ function stringLiteralFromCall(value) {
265
+ const match = /['"`]([^'"`]*)['"`]/u.exec(value);
266
+ return match?.[1] ?? '';
267
+ }
268
+ function routeVerbFromName(value) {
269
+ const lower = value.toLowerCase();
270
+ if (lower.includes('delete') || lower.includes('destroy') || lower.includes('remove')) {
271
+ return 'delete';
272
+ }
273
+ if (lower.includes('post') || lower.includes('store') || lower.includes('create')) {
274
+ return 'post';
275
+ }
276
+ if (lower.includes('put') || lower.includes('patch') || lower.includes('update')) {
277
+ return 'write';
278
+ }
279
+ return 'get';
280
+ }
281
+ function createEndpoint(input) {
282
+ return {
283
+ name: input.name,
284
+ verb: input.verb,
285
+ pathText: input.pathText,
286
+ line: input.line,
287
+ decorators: input.decorators ?? '',
288
+ body: input.body ?? '',
289
+ file: input.file,
290
+ ...(input.moduleName ? { moduleName: input.moduleName } : {}),
291
+ };
292
+ }
293
+ function findPythonFunctionBody(content, startIndex, searchFromIndex) {
294
+ const nextDefinition = content.slice(searchFromIndex).search(/\n(?:async\s+def|def|class)\s+/u);
295
+ if (nextDefinition < 0) {
296
+ return content.slice(startIndex);
297
+ }
298
+ return content.slice(startIndex, searchFromIndex + nextDefinition);
299
+ }
300
+ function extractPythonEndpoints(file, moduleName) {
301
+ const endpoints = [];
302
+ const pattern = /((?:\s*@\w+\.(?:get|post|put|patch|delete)\s*\([^)]*\)\s*\n)+)\s*(?:async\s+)?def\s+(\w+)\s*\(([^)]*)\)\s*:/gu;
303
+ for (const match of file.content.matchAll(pattern)) {
304
+ const decorators = match[1] ?? '';
305
+ const routeMatch = /@(\w+)\.(get|post|put|patch|delete)\s*\(([^)]*)\)/u.exec(decorators);
306
+ if (!routeMatch?.[2]) {
307
+ continue;
308
+ }
309
+ const body = findPythonFunctionBody(file.content, match.index ?? 0, (match.index ?? 0) + match[0].length);
310
+ endpoints.push(createEndpoint({
311
+ file,
312
+ moduleName,
313
+ name: match[2] ?? 'handler',
314
+ verb: routeVerbFromName(routeMatch[2]),
315
+ pathText: `${stringLiteralFromCall(routeMatch[3] ?? '')} ${match[3] ?? ''}`,
316
+ line: lineNumberForOffset(file.content, match.index ?? 0),
317
+ decorators,
318
+ body,
319
+ }));
320
+ }
321
+ return endpoints;
322
+ }
323
+ function extractPhpEndpoints(file, moduleName) {
324
+ const endpoints = [];
325
+ const routePattern = /\bRoute::(get|post|put|patch|delete)\s*\(\s*(['"])([^'"]+)\2\s*,\s*([^)]+)\)(?:->middleware\s*\(([^;]+)\))?/giu;
326
+ for (const match of file.content.matchAll(routePattern)) {
327
+ const handler = match[4] ?? '';
328
+ const handlerName = /['"](\w+)['"]/.exec(handler)?.[1] ?? `${match[1] ?? 'route'}Route`;
329
+ endpoints.push(createEndpoint({
330
+ file,
331
+ moduleName,
332
+ name: handlerName,
333
+ verb: routeVerbFromName(match[1] ?? 'get'),
334
+ pathText: match[3] ?? '/',
335
+ line: lineNumberForOffset(file.content, match.index ?? 0),
336
+ decorators: match[5] ?? '',
337
+ body: match[0],
338
+ }));
339
+ }
340
+ return endpoints;
341
+ }
342
+ function extractCSharpEndpoints(file, moduleName) {
343
+ const endpoints = [];
344
+ const classPattern = /((?:\s*\[[^\]]+\]\s*)*)\s*public\s+class\s+(\w+Controller)\b[\s\S]*?\{/gu;
345
+ for (const classMatch of file.content.matchAll(classPattern)) {
346
+ const classAttributes = classMatch[1] ?? '';
347
+ const classStart = classMatch.index ?? 0;
348
+ const classBody = file.content.slice(classStart);
349
+ const methodPattern = /((?:\s*\[(?:HttpGet|HttpPost|HttpPut|HttpPatch|HttpDelete|Authorize|AllowAnonymous)[^\]]*\]\s*)+)\s*public\s+(?:async\s+)?[\w<>., ?\[\]]+\s+(\w+)\s*\([^)]*\)\s*\{/gu;
350
+ for (const match of classBody.matchAll(methodPattern)) {
351
+ const attributes = `${classAttributes}\n${match[1] ?? ''}`;
352
+ const methodMatch = /\[(HttpGet|HttpPost|HttpPut|HttpPatch|HttpDelete)\b/u.exec(attributes);
353
+ if (!methodMatch?.[1]) {
354
+ continue;
355
+ }
356
+ const absoluteIndex = classStart + (match.index ?? 0);
357
+ endpoints.push(createEndpoint({
358
+ file,
359
+ moduleName,
360
+ name: match[2] ?? 'handler',
361
+ verb: routeVerbFromName(methodMatch[1]),
362
+ pathText: attributes,
363
+ line: lineNumberForOffset(file.content, absoluteIndex),
364
+ decorators: attributes,
365
+ body: file.content.slice(absoluteIndex, Math.min(file.content.length, absoluteIndex + 1200)),
366
+ }));
367
+ }
368
+ }
369
+ return endpoints;
370
+ }
371
+ function extractGoEndpoints(file, moduleName) {
372
+ const endpoints = [];
373
+ const routePattern = /\b\w+\.(GET|POST|PUT|PATCH|DELETE|Get|Post|Put|Patch|Delete|HandleFunc)\s*\(\s*["`]([^"`]+)["`]\s*,\s*([^)]+)\)/gu;
374
+ for (const match of file.content.matchAll(routePattern)) {
375
+ const handlerExpression = match[3] ?? '';
376
+ endpoints.push(createEndpoint({
377
+ file,
378
+ moduleName,
379
+ name: /(\w+)\s*(?:\)|$)/u.exec(handlerExpression)?.[1] ?? 'handler',
380
+ verb: match[1] === 'HandleFunc' ? 'get' : routeVerbFromName(match[1] ?? 'get'),
381
+ pathText: match[2] ?? '/',
382
+ line: lineNumberForOffset(file.content, match.index ?? 0),
383
+ decorators: handlerExpression,
384
+ body: match[0],
385
+ }));
386
+ }
387
+ return endpoints;
388
+ }
389
+ function extractExpressEndpoints(file, moduleName) {
390
+ const endpoints = [];
391
+ const routePattern = /\b(?:router|app|[A-Za-z_]\w*Router)\.(get|post|put|patch|delete)\s*\(\s*['"`]([^'"`]+)['"`]\s*,\s*([^)]+)\)/giu;
392
+ for (const match of file.content.matchAll(routePattern)) {
393
+ const chain = match[3] ?? '';
394
+ endpoints.push(createEndpoint({
395
+ file,
396
+ moduleName,
397
+ name: /(\w+)\s*(?:\)|$)/u.exec(chain)?.[1] ?? `${match[1] ?? 'route'}Route`,
398
+ verb: routeVerbFromName(match[1] ?? 'get'),
399
+ pathText: match[2] ?? '/',
400
+ line: lineNumberForOffset(file.content, match.index ?? 0),
401
+ decorators: chain,
402
+ body: match[0],
403
+ }));
404
+ }
405
+ return endpoints;
406
+ }
407
+ function extractEndpoints(file, moduleName) {
408
+ if (file.extension === '.py') {
409
+ return extractPythonEndpoints(file, moduleName);
410
+ }
411
+ if (file.extension === '.php') {
412
+ return extractPhpEndpoints(file, moduleName);
413
+ }
414
+ if (file.extension === '.cs') {
415
+ return extractCSharpEndpoints(file, moduleName);
416
+ }
417
+ if (file.extension === '.go') {
418
+ return extractGoEndpoints(file, moduleName);
419
+ }
420
+ if (file.extension === '.js' || file.extension === '.jsx' || file.extension === '.mjs' || file.extension === '.cjs') {
421
+ return extractExpressEndpoints(file, moduleName);
422
+ }
423
+ const endpoints = [];
424
+ const content = file.content;
425
+ const tsEndpoint = /((?:\s*@(?:Get|Post|Put|Patch|Delete|Controller|UseGuards|Roles|Permissions|RequirePermission|Public)\b[^\n]*\n)+)\s*(?:public\s+|private\s+|protected\s+)?(?:async\s+)?(\w+)\s*\([^)]*\)\s*\{/gu;
426
+ const javaEndpoint = /((?:\s*@(?:GetMapping|PostMapping|PutMapping|PatchMapping|DeleteMapping|RequestMapping|PreAuthorize|PostAuthorize|Secured|RolesAllowed|PermitAll)\b[^\n]*\n)+)\s*(?:public|private|protected)\s+[\w<>, ?\[\]]+\s+(\w+)\s*\([^)]*\)\s*\{/gu;
427
+ const pattern = file.extension === '.java' ? javaEndpoint : tsEndpoint;
428
+ for (const match of content.matchAll(pattern)) {
429
+ const decorators = match[1] ?? '';
430
+ if (!/@(?:Get|Post|Put|Patch|Delete|GetMapping|PostMapping|PutMapping|PatchMapping|DeleteMapping|RequestMapping)\b/u.test(decorators)) {
431
+ continue;
432
+ }
433
+ const start = match.index ?? 0;
434
+ const bodyEnd = content.indexOf('\n}', start + match[0].length);
435
+ endpoints.push({
436
+ name: match[2] ?? 'handler',
437
+ verb: /@(Delete|DeleteMapping)\b/u.test(decorators)
438
+ ? 'delete'
439
+ : /@(Post|PostMapping)\b/u.test(decorators)
440
+ ? 'post'
441
+ : /@(Put|Patch|PutMapping|PatchMapping)\b/u.test(decorators)
442
+ ? 'write'
443
+ : 'get',
444
+ pathText: decorators,
445
+ line: lineNumberForOffset(content, start),
446
+ decorators,
447
+ body: content.slice(start, bodyEnd > start ? bodyEnd : Math.min(content.length, start + 1200)),
448
+ file,
449
+ moduleName,
450
+ });
451
+ }
452
+ if (file.extension === '.ts' || file.extension === '.tsx') {
453
+ endpoints.push(...extractExpressEndpoints(file, moduleName));
454
+ }
455
+ return endpoints;
456
+ }
457
+ function isPublicEndpoint(endpoint) {
458
+ return (publicEvidencePattern.test(endpoint.decorators) ||
459
+ publicEndpointPattern.test(endpoint.name) ||
460
+ publicEndpointPattern.test(endpoint.pathText));
461
+ }
462
+ function hasAuthEvidence(endpoint) {
463
+ return authEvidencePattern.test(`${endpoint.decorators}\n${endpoint.body}\n${endpoint.pathText}`) || /\b(?:request|req)\.user\b|\buser\./u.test(endpoint.body);
464
+ }
465
+ function getRoleEvidence(endpoint) {
466
+ const match = roleEvidencePattern.exec(`${endpoint.decorators}\n${endpoint.body}\n${endpoint.pathText}`);
467
+ return match?.[0]?.trim();
468
+ }
469
+ function isProtectedLooking(endpoint) {
470
+ return endpoint.verb !== 'get' || protectedOperationPattern.test(endpoint.name) || protectedOperationPattern.test(endpoint.pathText);
471
+ }
472
+ function detectAuthorizationFindings(files, contract, astCache) {
473
+ const findings = [];
474
+ for (const file of files) {
475
+ const moduleName = inferModuleForPath(contract, file.relativePath);
476
+ const endpoints = extractEndpoints(file, moduleName);
477
+ if (endpoints.length === 0 && !isControllerFile(file, astCache)) {
478
+ continue;
479
+ }
480
+ const protectedPeers = endpoints.filter((endpoint) => hasAuthEvidence(endpoint) && !isPublicEndpoint(endpoint));
481
+ if (protectedPeers.length < 2) {
482
+ continue;
483
+ }
484
+ for (const endpoint of endpoints) {
485
+ if (isPublicEndpoint(endpoint) || hasAuthEvidence(endpoint) || !isProtectedLooking(endpoint)) {
486
+ continue;
487
+ }
488
+ findings.push(createFinding({
489
+ id: RuleIds.AUTH_MISSING_ENFORCEMENT,
490
+ message: `Endpoint '${endpoint.name}' lacks authorization evidence while peer endpoint '${protectedPeers[0]?.name ?? 'unknown'}' is protected.`,
491
+ file,
492
+ line: endpoint.line,
493
+ module: moduleName,
494
+ target: endpoint.name,
495
+ }));
496
+ const hasRolePeer = protectedPeers.some((peer) => getRoleEvidence(peer));
497
+ if (hasRolePeer) {
498
+ findings.push(createFinding({
499
+ id: RuleIds.AUTH_INCONSISTENT_ENFORCEMENT,
500
+ message: `Endpoint '${endpoint.name}' has weaker authorization evidence than protected peer '${protectedPeers.find((peer) => getRoleEvidence(peer))?.name ?? 'unknown'}'.`,
501
+ file,
502
+ line: endpoint.line,
503
+ module: moduleName,
504
+ target: endpoint.name,
505
+ }));
506
+ }
507
+ }
508
+ }
509
+ for (const file of files.filter((candidate) => isRepositoryFile(candidate, astCache))) {
510
+ const roleMatch = repositoryRolePattern.exec(file.content);
511
+ if (!roleMatch) {
512
+ continue;
513
+ }
514
+ if (/\b(?:tenantId|tenant_id|organizationId|orgId|workspaceId)\b/u.test(file.content) && !/\b(?:role|permission|isAdmin|hasRole|hasPermission)\b/u.test(file.content)) {
515
+ continue;
516
+ }
517
+ findings.push(createFinding({
518
+ id: RuleIds.AUTH_WRONG_LAYER,
519
+ message: 'Repository/data layer appears to contain role or permission authorization decisions.',
520
+ file,
521
+ line: lineNumberForOffset(file.content, roleMatch.index),
522
+ module: inferModuleForPath(contract, file.relativePath),
523
+ target: 'repository',
524
+ }));
525
+ }
526
+ return findings;
527
+ }
528
+ function hasTenantEvidence(value) {
529
+ return tenantSignalPattern.test(value);
530
+ }
531
+ function firstPatternWithoutTenant(value, patterns, windowSize = 360) {
532
+ for (const pattern of patterns) {
533
+ pattern.lastIndex = 0;
534
+ for (const match of value.matchAll(pattern)) {
535
+ const index = match.index ?? 0;
536
+ const snippet = value.slice(index, index + windowSize);
537
+ if (!tenantPredicateEvidencePattern.test(snippet)) {
538
+ return match;
539
+ }
540
+ }
541
+ }
542
+ return undefined;
543
+ }
544
+ function containsRepositoryCallWithoutTenant(value) {
545
+ return firstPatternWithoutTenant(value, [
546
+ /\b(?:this\.)?\w*(?:Repository|Repo)\.\w+\s*\(/gu,
547
+ /\b(?:this->)?\w*(?:Repository|Repo)->\w+\s*\(/gu,
548
+ ]) !== undefined;
549
+ }
550
+ function containsOrmOperationWithoutTenant(value) {
551
+ return firstPatternWithoutTenant(value, [
552
+ /\b(?:findMany|findUnique|findFirst|update|delete|deleteMany|updateMany|createQueryBuilder|createQuery|query)\s*\(/giu,
553
+ /\b(?:createNativeQuery|executeUpdate)\s*\(/giu,
554
+ /\b(?:FirstOrDefault|SingleOrDefault|Find|FindAsync|Where|ExecuteDelete|ExecuteUpdate|Remove|Update)\s*\(/gu,
555
+ /\b(?:session|db)\.(?:query|execute|get|delete)\s*\(/giu,
556
+ /\bselect\s*\(\s*\w+/giu,
557
+ /\b(?:DB::table|[A-Z]\w*::(?:query|where|find|findOrFail|update|delete))\s*\(/g,
558
+ /->(?:where|first|find|delete|update|get)\s*\(/g,
559
+ /\b(?:QueryContext|QueryRowContext|ExecContext|Query|Exec|Raw|Where|First|Find|Delete|Updates?)\s*\(/g,
560
+ ]) !== undefined;
561
+ }
562
+ function isDestructiveTenantRisk(value) {
563
+ const destructiveMatch = firstPatternWithoutTenant(value, [
564
+ /\b(?:update|delete|deleteMany|updateMany|createQuery|createNativeQuery|executeUpdate|ExecuteDelete|ExecuteUpdate|Remove|Delete|ExecContext|Exec|query)\s*\(/giu,
565
+ /\b(?:session|db)\.(?:execute|delete)\s*\(/giu,
566
+ /->(?:delete|update)\s*\(/g,
567
+ /\b[A-Z]\w*::(?:delete|update)\s*\(/g,
568
+ ], 420);
569
+ if (!destructiveMatch) {
570
+ return false;
571
+ }
572
+ const snippet = value.slice(destructiveMatch.index ?? 0, (destructiveMatch.index ?? 0) + 420);
573
+ return /\b(?:delete|update|remove|ExecuteDelete|ExecuteUpdate)\b/iu.test(snippet);
574
+ }
575
+ function detectTenantFindings(input) {
576
+ if (input.config.tenantModel === 'single_tenant') {
577
+ return [];
578
+ }
579
+ const findings = [];
580
+ const hasAnyTenantEvidence = input.files.some((file) => hasTenantEvidence(file.content));
581
+ if (!hasAnyTenantEvidence && input.config.tenantModel === 'same_db_same_schema') {
582
+ const firstSource = input.files.find((file) => isRepositoryFile(file, input.astCache) || isServiceFile(file, input.astCache));
583
+ if (firstSource) {
584
+ findings.push(createFinding({
585
+ id: RuleIds.TEN_MODEL_UNDOCUMENTED,
586
+ severity: 'info',
587
+ message: 'Architecture config uses same-schema tenancy, but scanned source has little tenant context evidence.',
588
+ file: firstSource,
589
+ line: 1,
590
+ module: inferModuleForPath(input.contract, firstSource.relativePath),
591
+ }));
592
+ }
593
+ return findings;
594
+ }
595
+ for (const file of input.files) {
596
+ const moduleName = inferModuleForPath(input.contract, file.relativePath);
597
+ if (isServiceFile(file, input.astCache) && hasTenantEvidence(file.content) && containsRepositoryCallWithoutTenant(file.content)) {
598
+ findings.push(createFinding({
599
+ id: RuleIds.TEN_MISSING_CONTEXT_PROPAGATION,
600
+ message: 'Service appears to use tenant context but calls a repository without passing tenant/org scope.',
601
+ file,
602
+ line: lineNumberForOffset(file.content, file.content.search(/\b\w*(?:Repository|Repo)\.\w+\s*\(/u)),
603
+ module: moduleName,
604
+ target: 'service',
605
+ }));
606
+ }
607
+ if (input.config.tenantModel === 'same_db_same_schema' && isRepositoryFile(file, input.astCache)) {
608
+ if (containsOrmOperationWithoutTenant(file.content)) {
609
+ findings.push(createFinding({
610
+ id: RuleIds.TEN_MISSING_ENFORCEMENT,
611
+ message: 'Tenant-scoped repository/query operation lacks tenant/org predicate evidence.',
612
+ file,
613
+ line: lineNumberForOffset(file.content, file.content.search(/\b(?:findMany|findUnique|findFirst|update|delete|deleteMany|updateMany|createQueryBuilder|createQuery|query)\s*\(/u)),
614
+ module: moduleName,
615
+ target: 'repository',
616
+ }));
617
+ }
618
+ if (isDestructiveTenantRisk(file.content)) {
619
+ findings.push(createFinding({
620
+ id: RuleIds.TEN_CROSS_TENANT_RISK,
621
+ message: 'Destructive tenant-scoped data operation appears to be scoped only by entity id.',
622
+ file,
623
+ line: lineNumberForOffset(file.content, file.content.search(/\b(?:update|delete|deleteMany|updateMany)\s*\(/u)),
624
+ module: moduleName,
625
+ target: 'repository',
626
+ }));
627
+ }
628
+ }
629
+ }
630
+ return findings;
631
+ }
632
+ async function detectAuthorizationTenantFindings(input) {
633
+ const disabled = input.disabledRuleIds ?? new Set();
634
+ const started = Date.now();
635
+ const files = await collectSourceFiles(input.workspaceRoot, input.sourceInventory);
636
+ (0, validationProfiling_1.emitValidationProfile)('AP-AUTH/AP-TEN analyzer file scan', Date.now() - started, [
637
+ { name: 'files', value: files.length },
638
+ ]);
639
+ return [
640
+ ...detectAuthorizationFindings(files, input.contract, input.astCache),
641
+ ...detectTenantFindings({ files, config: input.config, contract: input.contract, astCache: input.astCache }),
642
+ ]
643
+ .filter((finding) => !disabled.has(finding.id))
644
+ .sort((left, right) => {
645
+ const fileCompare = (left.sourceFile ?? '').localeCompare(right.sourceFile ?? '');
646
+ if (fileCompare !== 0) {
647
+ return fileCompare;
648
+ }
649
+ return left.id.localeCompare(right.id);
650
+ });
651
+ }
652
+ //# sourceMappingURL=authorizationTenantAnalysis.js.map