attocode-code-intel 0.1.0__py3-none-any.whl

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 (345) hide show
  1. attocode_code_intel-0.1.0.dist-info/METADATA +221 -0
  2. attocode_code_intel-0.1.0.dist-info/RECORD +345 -0
  3. attocode_code_intel-0.1.0.dist-info/WHEEL +4 -0
  4. attocode_code_intel-0.1.0.dist-info/entry_points.txt +2 -0
  5. attocode_code_intel-0.1.0.dist-info/licenses/LICENSE +21 -0
  6. attocode_intel/GUIDELINES.md +432 -0
  7. attocode_intel/__init__.py +52 -0
  8. attocode_intel/_internal/__init__.py +1 -0
  9. attocode_intel/_internal/errors/__init__.py +126 -0
  10. attocode_intel/_internal/integrations/__init__.py +1 -0
  11. attocode_intel/_internal/integrations/context/__init__.py +1 -0
  12. attocode_intel/_internal/integrations/context/architecture_drift.py +354 -0
  13. attocode_intel/_internal/integrations/context/ast_chunker.py +202 -0
  14. attocode_intel/_internal/integrations/context/ast_service.py +1483 -0
  15. attocode_intel/_internal/integrations/context/blob_oid.py +423 -0
  16. attocode_intel/_internal/integrations/context/cache_manifest.py +221 -0
  17. attocode_intel/_internal/integrations/context/cas.py +466 -0
  18. attocode_intel/_internal/integrations/context/code_analyzer.py +528 -0
  19. attocode_intel/_internal/integrations/context/codebase_ast.py +1461 -0
  20. attocode_intel/_internal/integrations/context/codebase_context.py +1736 -0
  21. attocode_intel/_internal/integrations/context/cross_mode.py +263 -0
  22. attocode_intel/_internal/integrations/context/cross_references.py +616 -0
  23. attocode_intel/_internal/integrations/context/embedding_rotation.py +597 -0
  24. attocode_intel/_internal/integrations/context/embeddings.py +282 -0
  25. attocode_intel/_internal/integrations/context/frecency.py +427 -0
  26. attocode_intel/_internal/integrations/context/fuzzy.py +320 -0
  27. attocode_intel/_internal/integrations/context/hierarchical_explorer.py +331 -0
  28. attocode_intel/_internal/integrations/context/hydration.py +90 -0
  29. attocode_intel/_internal/integrations/context/index_repair.py +87 -0
  30. attocode_intel/_internal/integrations/context/index_store.py +586 -0
  31. attocode_intel/_internal/integrations/context/memory_store.py +602 -0
  32. attocode_intel/_internal/integrations/context/module_resolution.py +52 -0
  33. attocode_intel/_internal/integrations/context/query_constraints.py +361 -0
  34. attocode_intel/_internal/integrations/context/query_history.py +417 -0
  35. attocode_intel/_internal/integrations/context/reranker.py +351 -0
  36. attocode_intel/_internal/integrations/context/semantic_search.py +2931 -0
  37. attocode_intel/_internal/integrations/context/syntax_evidence.py +94 -0
  38. attocode_intel/_internal/integrations/context/systemone_ranker.py +245 -0
  39. attocode_intel/_internal/integrations/context/temporal_coupling.py +411 -0
  40. attocode_intel/_internal/integrations/context/trigram_index.py +820 -0
  41. attocode_intel/_internal/integrations/context/trigram_regex.py +171 -0
  42. attocode_intel/_internal/integrations/context/ts_parser.py +2199 -0
  43. attocode_intel/_internal/integrations/context/vector_store.py +795 -0
  44. attocode_intel/_internal/integrations/feature_flags/__init__.py +357 -0
  45. attocode_intel/_internal/integrations/lsp/__init__.py +1 -0
  46. attocode_intel/_internal/integrations/lsp/client.py +1140 -0
  47. attocode_intel/_internal/integrations/mcp/__init__.py +1 -0
  48. attocode_intel/_internal/integrations/mcp/client.py +253 -0
  49. attocode_intel/_internal/integrations/security/__init__.py +1 -0
  50. attocode_intel/_internal/integrations/security/custom_rules.py +176 -0
  51. attocode_intel/_internal/integrations/security/dataflow.py +522 -0
  52. attocode_intel/_internal/integrations/security/dependency_audit.py +303 -0
  53. attocode_intel/_internal/integrations/security/matcher.py +44 -0
  54. attocode_intel/_internal/integrations/security/patterns.py +724 -0
  55. attocode_intel/_internal/integrations/security/scanner.py +351 -0
  56. attocode_intel/_internal/integrations/utilities/__init__.py +1 -0
  57. attocode_intel/_internal/integrations/utilities/ignore.py +64 -0
  58. attocode_intel/_internal/integrations/utilities/token_estimate.py +51 -0
  59. attocode_intel/_internal/tricks/__init__.py +1 -0
  60. attocode_intel/_internal/tricks/recursive_context.py +357 -0
  61. attocode_intel/_internal/types/__init__.py +1 -0
  62. attocode_intel/_internal/types/events.py +289 -0
  63. attocode_intel/_internal/types/severity.py +15 -0
  64. attocode_intel/_shared.py +341 -0
  65. attocode_intel/analysis_coverage.py +56 -0
  66. attocode_intel/api/__init__.py +1 -0
  67. attocode_intel/api/access.py +32 -0
  68. attocode_intel/api/app.py +247 -0
  69. attocode_intel/api/auth/__init__.py +128 -0
  70. attocode_intel/api/auth/api_keys.py +61 -0
  71. attocode_intel/api/auth/context.py +34 -0
  72. attocode_intel/api/auth/jwt.py +66 -0
  73. attocode_intel/api/auth/oauth.py +146 -0
  74. attocode_intel/api/auth/passwords.py +15 -0
  75. attocode_intel/api/deps.py +351 -0
  76. attocode_intel/api/knowledge_bridge.py +13 -0
  77. attocode_intel/api/mcp_transport.py +51 -0
  78. attocode_intel/api/middleware.py +411 -0
  79. attocode_intel/api/models.py +698 -0
  80. attocode_intel/api/providers/__init__.py +1 -0
  81. attocode_intel/api/providers/db_provider.py +1106 -0
  82. attocode_intel/api/providers/local_provider.py +476 -0
  83. attocode_intel/api/providers/remote_provider.py +740 -0
  84. attocode_intel/api/repository_source.py +21 -0
  85. attocode_intel/api/routes/__init__.py +1 -0
  86. attocode_intel/api/routes/_pin_helper.py +158 -0
  87. attocode_intel/api/routes/activity.py +148 -0
  88. attocode_intel/api/routes/adr.py +102 -0
  89. attocode_intel/api/routes/analysis.py +515 -0
  90. attocode_intel/api/routes/api_keys.py +170 -0
  91. attocode_intel/api/routes/auth.py +428 -0
  92. attocode_intel/api/routes/branches.py +262 -0
  93. attocode_intel/api/routes/cross_repo_search.py +198 -0
  94. attocode_intel/api/routes/embeddings.py +386 -0
  95. attocode_intel/api/routes/files.py +132 -0
  96. attocode_intel/api/routes/files_v2.py +388 -0
  97. attocode_intel/api/routes/gc.py +322 -0
  98. attocode_intel/api/routes/git_v2.py +433 -0
  99. attocode_intel/api/routes/graph.py +174 -0
  100. attocode_intel/api/routes/graph_viz.py +160 -0
  101. attocode_intel/api/routes/health.py +62 -0
  102. attocode_intel/api/routes/history.py +175 -0
  103. attocode_intel/api/routes/jobs.py +84 -0
  104. attocode_intel/api/routes/learning.py +205 -0
  105. attocode_intel/api/routes/lsp.py +272 -0
  106. attocode_intel/api/routes/notify.py +623 -0
  107. attocode_intel/api/routes/operations.py +27 -0
  108. attocode_intel/api/routes/orgs.py +924 -0
  109. attocode_intel/api/routes/preferences.py +100 -0
  110. attocode_intel/api/routes/presence.py +42 -0
  111. attocode_intel/api/routes/projects.py +116 -0
  112. attocode_intel/api/routes/repos.py +47 -0
  113. attocode_intel/api/routes/search.py +180 -0
  114. attocode_intel/api/routes/snapshots.py +614 -0
  115. attocode_intel/api/routes/webhooks.py +313 -0
  116. attocode_intel/api/routes/websocket.py +116 -0
  117. attocode_intel/api/static/graph.html +239 -0
  118. attocode_intel/api/utils.py +96 -0
  119. attocode_intel/artifacts/__init__.py +45 -0
  120. attocode_intel/artifacts/hashing.py +230 -0
  121. attocode_intel/artifacts/provenance.py +190 -0
  122. attocode_intel/artifacts/retrieval_pin.py +159 -0
  123. attocode_intel/audit.py +59 -0
  124. attocode_intel/bug_finder.py +206 -0
  125. attocode_intel/bundle.py +80 -0
  126. attocode_intel/catalog.py +242 -0
  127. attocode_intel/change_review.py +75 -0
  128. attocode_intel/cli.py +3062 -0
  129. attocode_intel/community.py +63 -0
  130. attocode_intel/confidence/__init__.py +144 -0
  131. attocode_intel/confidence/jev.py +234 -0
  132. attocode_intel/confidence/llm.py +330 -0
  133. attocode_intel/confidence/redact.py +44 -0
  134. attocode_intel/confidence/settings.py +74 -0
  135. attocode_intel/config.py +256 -0
  136. attocode_intel/crypto.py +31 -0
  137. attocode_intel/db/__init__.py +7 -0
  138. attocode_intel/db/base.py +33 -0
  139. attocode_intel/db/engine.py +61 -0
  140. attocode_intel/db/models.py +529 -0
  141. attocode_intel/entrypoint.py +185 -0
  142. attocode_intel/focused_evidence.py +130 -0
  143. attocode_intel/freshness.py +154 -0
  144. attocode_intel/gateway.py +734 -0
  145. attocode_intel/git/__init__.py +7 -0
  146. attocode_intel/git/credentials.py +75 -0
  147. attocode_intel/git/manager.py +493 -0
  148. attocode_intel/git/models.py +96 -0
  149. attocode_intel/git/storage.py +98 -0
  150. attocode_intel/graph_query_parser.py +761 -0
  151. attocode_intel/helpers.py +712 -0
  152. attocode_intel/indexing/__init__.py +29 -0
  153. attocode_intel/indexing/debouncer.py +136 -0
  154. attocode_intel/indexing/delta_indexer.py +151 -0
  155. attocode_intel/indexing/full_indexer.py +323 -0
  156. attocode_intel/indexing/incremental.py +240 -0
  157. attocode_intel/indexing/parser.py +403 -0
  158. attocode_intel/indexing/summarizer.py +264 -0
  159. attocode_intel/installer.py +1896 -0
  160. attocode_intel/knowledge.py +269 -0
  161. attocode_intel/local_knowledge.py +77 -0
  162. attocode_intel/migrations/alembic.ini +36 -0
  163. attocode_intel/migrations/env.py +71 -0
  164. attocode_intel/migrations/script.py.mako +27 -0
  165. attocode_intel/migrations/versions/001_initial_schema.py +219 -0
  166. attocode_intel/migrations/versions/002_branch_version_and_embeddings.py +61 -0
  167. attocode_intel/migrations/versions/003_embedding_uniqueness_and_cascade.py +51 -0
  168. attocode_intel/migrations/versions/004_audit_events.py +38 -0
  169. attocode_intel/migrations/versions/005_user_preferences.py +30 -0
  170. attocode_intel/migrations/versions/006_google_oauth.py +27 -0
  171. attocode_intel/migrations/versions/007_pgvector_embeddings.py +28 -0
  172. attocode_intel/migrations/versions/008_symbol_references.py +37 -0
  173. attocode_intel/migrations/versions/009_webhook_secret_encryption.py +25 -0
  174. attocode_intel/migrations/versions/010_add_commits_table.py +40 -0
  175. attocode_intel/migrations/versions/011_commit_changed_files.py +25 -0
  176. attocode_intel/migrations/versions/012_branch_merged_at.py +25 -0
  177. attocode_intel/migrations/versions/013_revoked_tokens.py +32 -0
  178. attocode_intel/migrations/versions/014_blame_hunks.py +40 -0
  179. attocode_intel/migrations/versions/015_commit_file_stats.py +40 -0
  180. attocode_intel/migrations/versions/016_embedding_provenance_columns.py +179 -0
  181. attocode_intel/migrations/versions/017_provenance_table.py +102 -0
  182. attocode_intel/migrations/versions/018_repo_snapshots.py +178 -0
  183. attocode_intel/migrations/versions/019_symref_caller.py +42 -0
  184. attocode_intel/migrations/versions/020_shared_knowledge.py +29 -0
  185. attocode_intel/onboarding.py +258 -0
  186. attocode_intel/output.py +178 -0
  187. attocode_intel/precision.py +133 -0
  188. attocode_intel/presence.py +160 -0
  189. attocode_intel/probe.py +110 -0
  190. attocode_intel/project_dir.py +97 -0
  191. attocode_intel/pubsub.py +113 -0
  192. attocode_intel/query_ranking.py +242 -0
  193. attocode_intel/readiness.py +972 -0
  194. attocode_intel/redis.py +51 -0
  195. attocode_intel/reference_pages.py +60 -0
  196. attocode_intel/remote.py +131 -0
  197. attocode_intel/repo_ranker.py +246 -0
  198. attocode_intel/request_context.py +82 -0
  199. attocode_intel/rules/__init__.py +28 -0
  200. attocode_intel/rules/ci.py +320 -0
  201. attocode_intel/rules/combinators.py +293 -0
  202. attocode_intel/rules/enricher.py +127 -0
  203. attocode_intel/rules/evolution.py +452 -0
  204. attocode_intel/rules/executor.py +531 -0
  205. attocode_intel/rules/filters/__init__.py +5 -0
  206. attocode_intel/rules/filters/pipeline.py +151 -0
  207. attocode_intel/rules/formatter.py +198 -0
  208. attocode_intel/rules/hygiene.py +242 -0
  209. attocode_intel/rules/importers/__init__.py +1 -0
  210. attocode_intel/rules/importers/semgrep.py +382 -0
  211. attocode_intel/rules/loader.py +292 -0
  212. attocode_intel/rules/marketplace.py +375 -0
  213. attocode_intel/rules/metavar.py +181 -0
  214. attocode_intel/rules/model.py +317 -0
  215. attocode_intel/rules/packs/__init__.py +1 -0
  216. attocode_intel/rules/packs/community/_license_templates/Apache-2.0.txt +176 -0
  217. attocode_intel/rules/packs/community/_license_templates/MIT.txt +21 -0
  218. attocode_intel/rules/packs/community/bandit-python/LICENSE +176 -0
  219. attocode_intel/rules/packs/community/bandit-python/NOTICE +13 -0
  220. attocode_intel/rules/packs/community/bandit-python/PORTING.md +23 -0
  221. attocode_intel/rules/packs/community/bandit-python/manifest.yaml +14 -0
  222. attocode_intel/rules/packs/community/bandit-python/rules/B105-hardcoded-password.yaml +23 -0
  223. attocode_intel/rules/packs/community/bandit-python/rules/B303-weak-md5.yaml +21 -0
  224. attocode_intel/rules/packs/community/bandit-python/rules/B304-weak-des.yaml +20 -0
  225. attocode_intel/rules/packs/community/bandit-python/rules/B307-use-of-eval.yaml +22 -0
  226. attocode_intel/rules/packs/community/bandit-python/rules/B324-weak-sha1.yaml +21 -0
  227. attocode_intel/rules/packs/community/bandit-python/rules/B501-no-cert-validation.yaml +23 -0
  228. attocode_intel/rules/packs/community/bandit-python/rules/B602-shell-true.yaml +22 -0
  229. attocode_intel/rules/packs/community/bandit-python/rules/B608-sqli.yaml +22 -0
  230. attocode_intel/rules/packs/community/eslint-typescript/LICENSE +21 -0
  231. attocode_intel/rules/packs/community/eslint-typescript/NOTICE +13 -0
  232. attocode_intel/rules/packs/community/eslint-typescript/PORTING.md +23 -0
  233. attocode_intel/rules/packs/community/eslint-typescript/manifest.yaml +14 -0
  234. attocode_intel/rules/packs/community/eslint-typescript/rules/eqeqeq.yaml +20 -0
  235. attocode_intel/rules/packs/community/eslint-typescript/rules/no-eval.yaml +22 -0
  236. attocode_intel/rules/packs/community/eslint-typescript/rules/no-implied-eval.yaml +20 -0
  237. attocode_intel/rules/packs/community/eslint-typescript/rules/no-new-func.yaml +21 -0
  238. attocode_intel/rules/packs/community/eslint-typescript/rules/no-throw-literal.yaml +19 -0
  239. attocode_intel/rules/packs/community/eslint-typescript/rules/no-var.yaml +20 -0
  240. attocode_intel/rules/packs/community/eslint-typescript/rules/no-with.yaml +18 -0
  241. attocode_intel/rules/packs/community/gosec-go/LICENSE +176 -0
  242. attocode_intel/rules/packs/community/gosec-go/NOTICE +13 -0
  243. attocode_intel/rules/packs/community/gosec-go/PORTING.md +23 -0
  244. attocode_intel/rules/packs/community/gosec-go/manifest.yaml +14 -0
  245. attocode_intel/rules/packs/community/gosec-go/rules/G101-hardcoded-credentials.yaml +22 -0
  246. attocode_intel/rules/packs/community/gosec-go/rules/G102-bind-all-interfaces.yaml +21 -0
  247. attocode_intel/rules/packs/community/gosec-go/rules/G103-unsafe-block.yaml +21 -0
  248. attocode_intel/rules/packs/community/gosec-go/rules/G201-sql-format.yaml +21 -0
  249. attocode_intel/rules/packs/community/gosec-go/rules/G304-file-inclusion.yaml +23 -0
  250. attocode_intel/rules/packs/community/gosec-go/rules/G401-weak-cipher.yaml +20 -0
  251. attocode_intel/rules/packs/community/gosec-go/rules/G402-tls-min-version.yaml +20 -0
  252. attocode_intel/rules/packs/community/gosec-go/rules/G501-md5-import.yaml +21 -0
  253. attocode_intel/rules/packs/examples/cpp/manifest.yaml +4 -0
  254. attocode_intel/rules/packs/examples/cpp/rules/security.yaml +90 -0
  255. attocode_intel/rules/packs/examples/cpp/rules/structural.yaml +42 -0
  256. attocode_intel/rules/packs/examples/csharp/manifest.yaml +4 -0
  257. attocode_intel/rules/packs/examples/csharp/rules/security.yaml +69 -0
  258. attocode_intel/rules/packs/examples/csharp/rules/structural.yaml +42 -0
  259. attocode_intel/rules/packs/examples/go/manifest.yaml +4 -0
  260. attocode_intel/rules/packs/examples/go/rules/performance.yaml +136 -0
  261. attocode_intel/rules/packs/examples/go/rules/security.yaml +48 -0
  262. attocode_intel/rules/packs/examples/go/rules/structural.yaml +58 -0
  263. attocode_intel/rules/packs/examples/go/taint/sanitizers.yaml +24 -0
  264. attocode_intel/rules/packs/examples/go/taint/sinks.yaml +51 -0
  265. attocode_intel/rules/packs/examples/go/taint/sources.yaml +26 -0
  266. attocode_intel/rules/packs/examples/java/manifest.yaml +4 -0
  267. attocode_intel/rules/packs/examples/java/rules/correctness.yaml +55 -0
  268. attocode_intel/rules/packs/examples/java/rules/structural.yaml +48 -0
  269. attocode_intel/rules/packs/examples/java/taint/sinks.yaml +37 -0
  270. attocode_intel/rules/packs/examples/java/taint/sources.yaml +21 -0
  271. attocode_intel/rules/packs/examples/kotlin/manifest.yaml +4 -0
  272. attocode_intel/rules/packs/examples/kotlin/rules/correctness.yaml +50 -0
  273. attocode_intel/rules/packs/examples/kotlin/rules/structural.yaml +38 -0
  274. attocode_intel/rules/packs/examples/php/manifest.yaml +4 -0
  275. attocode_intel/rules/packs/examples/php/rules/security.yaml +66 -0
  276. attocode_intel/rules/packs/examples/php/rules/structural.yaml +41 -0
  277. attocode_intel/rules/packs/examples/python/manifest.yaml +4 -0
  278. attocode_intel/rules/packs/examples/python/rules/performance.yaml +90 -0
  279. attocode_intel/rules/packs/examples/python/rules/structural.yaml +55 -0
  280. attocode_intel/rules/packs/examples/ruby/manifest.yaml +4 -0
  281. attocode_intel/rules/packs/examples/ruby/rules/security.yaml +73 -0
  282. attocode_intel/rules/packs/examples/ruby/rules/structural.yaml +41 -0
  283. attocode_intel/rules/packs/examples/rust/manifest.yaml +4 -0
  284. attocode_intel/rules/packs/examples/rust/rules/correctness.yaml +51 -0
  285. attocode_intel/rules/packs/examples/rust/rules/structural.yaml +49 -0
  286. attocode_intel/rules/packs/examples/typescript/manifest.yaml +4 -0
  287. attocode_intel/rules/packs/examples/typescript/rules/performance.yaml +70 -0
  288. attocode_intel/rules/packs/examples/typescript/rules/structural.yaml +48 -0
  289. attocode_intel/rules/packs/pack_loader.py +244 -0
  290. attocode_intel/rules/plugins/__init__.py +1 -0
  291. attocode_intel/rules/plugins/plugin_loader.py +132 -0
  292. attocode_intel/rules/profiling.py +332 -0
  293. attocode_intel/rules/registry.py +213 -0
  294. attocode_intel/rules/sarif.py +187 -0
  295. attocode_intel/rules/synthesis.py +420 -0
  296. attocode_intel/rules/testing.py +326 -0
  297. attocode_intel/server.py +734 -0
  298. attocode_intel/service.py +3416 -0
  299. attocode_intel/sharing.py +57 -0
  300. attocode_intel/storage/__init__.py +6 -0
  301. attocode_intel/storage/branch_overlay.py +352 -0
  302. attocode_intel/storage/content_store.py +220 -0
  303. attocode_intel/storage/dependency_store.py +143 -0
  304. attocode_intel/storage/diff_engine.py +187 -0
  305. attocode_intel/storage/embedding_store.py +594 -0
  306. attocode_intel/storage/provenance_store.py +137 -0
  307. attocode_intel/storage/security_scanner_db.py +164 -0
  308. attocode_intel/storage/symbol_store.py +160 -0
  309. attocode_intel/structural_evidence.py +144 -0
  310. attocode_intel/symbol_inspection.py +141 -0
  311. attocode_intel/symbol_links.py +167 -0
  312. attocode_intel/telemetry.py +42 -0
  313. attocode_intel/test_ranking.py +73 -0
  314. attocode_intel/testing/__init__.py +43 -0
  315. attocode_intel/testing/fixtures.py +122 -0
  316. attocode_intel/testing/helpers.py +75 -0
  317. attocode_intel/testing/mocks.py +99 -0
  318. attocode_intel/tools/__init__.py +2 -0
  319. attocode_intel/tools/adr_tools.py +628 -0
  320. attocode_intel/tools/analysis_tools.py +382 -0
  321. attocode_intel/tools/composite_tools.py +695 -0
  322. attocode_intel/tools/cross_mode_tools.py +173 -0
  323. attocode_intel/tools/dead_code_tools.py +582 -0
  324. attocode_intel/tools/distill_tools.py +353 -0
  325. attocode_intel/tools/frecency_tools.py +220 -0
  326. attocode_intel/tools/fuzzy_tools.py +255 -0
  327. attocode_intel/tools/history_tools.py +486 -0
  328. attocode_intel/tools/learning_tools.py +222 -0
  329. attocode_intel/tools/lsp_tools.py +218 -0
  330. attocode_intel/tools/maintenance_tools.py +1662 -0
  331. attocode_intel/tools/navigation_tools.py +220 -0
  332. attocode_intel/tools/overlay_tools.py +540 -0
  333. attocode_intel/tools/pin_store.py +432 -0
  334. attocode_intel/tools/pin_tools.py +266 -0
  335. attocode_intel/tools/query_constraints_tools.py +262 -0
  336. attocode_intel/tools/query_history_tools.py +158 -0
  337. attocode_intel/tools/readiness_tools.py +44 -0
  338. attocode_intel/tools/rule_tools.py +992 -0
  339. attocode_intel/tools/search_tools.py +770 -0
  340. attocode_intel/tools/snapshot_tools.py +624 -0
  341. attocode_intel/workers/__init__.py +1 -0
  342. attocode_intel/workers/job_utils.py +111 -0
  343. attocode_intel/workers/jobs.py +573 -0
  344. attocode_intel/workers/run.py +30 -0
  345. attocode_intel/workers/settings.py +61 -0
@@ -0,0 +1,303 @@
1
+ """Dependency auditing — check pinning and known vulnerabilities.
2
+
3
+ Parses common dependency files and flags:
4
+ - Unpinned/floating version specifiers (>= instead of ==)
5
+ - Known-vulnerable package ranges (via OSV.dev cache)
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import logging
12
+ import os
13
+ import re
14
+ from dataclasses import dataclass, field
15
+ from pathlib import Path
16
+ from typing import Any
17
+
18
+ from attocode_intel._internal.integrations.security.patterns import Category, Severity
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ # Cache directory for OSV vulnerability data
23
+ _DEFAULT_CACHE_DIR = os.path.expanduser("~/.attocode")
24
+ _OSV_CACHE_FILE = "osv-cache.json"
25
+ _OSV_CACHE_TTL = 86400 # 24 hours
26
+
27
+ # Suspicious tokens in package.json install hooks (GlassWorm-class supply-chain attacks)
28
+ _SUSPICIOUS_HOOK_TOKENS: list[tuple[str, "re.Pattern[str]", str]] = [
29
+ ("hook_eval", re.compile(r"\beval\b"), "dynamic evaluation in install hook"),
30
+ ("hook_atob", re.compile(r"\batob\s*\("), "atob decoder in install hook"),
31
+ ("hook_buffer_b64", re.compile(r"Buffer\.from\s*\([^)]*base64", re.IGNORECASE),
32
+ "Buffer.from base64 decode in install hook"),
33
+ ("hook_child_process", re.compile(r"require\s*\(\s*['\"]child_process['\"]\s*\)"),
34
+ "child_process require in install hook"),
35
+ ("hook_node_dash_e", re.compile(r"\bnode\s+-e\b"),
36
+ "node -e inline script in install hook"),
37
+ ("hook_curl_pipe_sh", re.compile(r"\b(?:curl|wget|fetch)\b[^|]*\|\s*(?:ba)?sh\b", re.IGNORECASE),
38
+ "curl/wget piped to shell in install hook"),
39
+ ("hook_remote_script", re.compile(r"https?://\S+\.(?:sh|py|exe|dll|so|dylib)\b", re.IGNORECASE),
40
+ "remote script fetch in install hook"),
41
+ ("hook_popen", re.compile(r"\bpopen\s*\("),
42
+ "popen call in install hook"),
43
+ ("hook_system_call", re.compile(r"\bsystem\s*\("),
44
+ "system call in install hook"),
45
+ ("hook_child_spawn", re.compile(r"\b(?:spawnSync|execSync|execFile|execFileSync)\s*\("),
46
+ "child_process spawn/exec variant in install hook"),
47
+ ]
48
+
49
+ # Suspicious patterns in setup.py (supply-chain attacks: ctx, W4SP, LiteLLM).
50
+ # setup.py should never make network calls; install-time fetches are a classic
51
+ # vector for staged-payload delivery.
52
+ _SUSPICIOUS_SETUP_PY_PATTERNS: list[tuple[str, "re.Pattern[str]", str]] = [
53
+ ("setup_urllib_fetch",
54
+ re.compile(r"\burllib(?:\.request)?\.urlopen\s*\("),
55
+ "urllib network fetch"),
56
+ ("setup_urlretrieve",
57
+ re.compile(r"\burlretrieve\s*\("),
58
+ "urlretrieve fetch"),
59
+ ("setup_http_client_call",
60
+ re.compile(r"\b(?:requests|httpx|aiohttp)\.(?:get|post|put|delete|head)\s*\("),
61
+ "HTTP client call"),
62
+ ("setup_socket_connect",
63
+ re.compile(r"\bsocket\.create_connection\s*\("),
64
+ "raw socket connection"),
65
+ ]
66
+
67
+
68
+ @dataclass(slots=True)
69
+ class DependencyFinding:
70
+ """A finding from dependency auditing."""
71
+
72
+ package: str
73
+ version_spec: str
74
+ severity: Severity
75
+ category: Category = Category.DEPENDENCY
76
+ cwe_id: str = ""
77
+ message: str = ""
78
+ recommendation: str = ""
79
+ source_file: str = ""
80
+
81
+
82
+ @dataclass(slots=True)
83
+ class DependencyAuditor:
84
+ """Audit project dependencies for security issues."""
85
+
86
+ root_dir: str
87
+ _osv_cache: dict[str, Any] = field(default_factory=dict, repr=False)
88
+ _cache_loaded: bool = field(default=False, repr=False)
89
+
90
+ def audit(self) -> list[DependencyFinding]:
91
+ """Run a full dependency audit.
92
+
93
+ Checks all supported dependency files for pinning issues.
94
+ """
95
+ findings: list[DependencyFinding] = []
96
+ root = Path(self.root_dir)
97
+
98
+ # Python: pyproject.toml
99
+ pyproject = root / "pyproject.toml"
100
+ if pyproject.exists():
101
+ findings.extend(self._audit_pyproject(pyproject))
102
+
103
+ # Python: requirements.txt
104
+ reqs = root / "requirements.txt"
105
+ if reqs.exists():
106
+ findings.extend(self._audit_requirements(reqs))
107
+
108
+ # Node: package.json
109
+ pkg_json = root / "package.json"
110
+ if pkg_json.exists():
111
+ findings.extend(self._audit_package_json(pkg_json))
112
+
113
+ # Python: setup.py (supply-chain network-at-install-time check)
114
+ setup_py = root / "setup.py"
115
+ if setup_py.exists():
116
+ findings.extend(self._audit_setup_py(setup_py))
117
+
118
+ return findings
119
+
120
+ def _audit_pyproject(self, path: Path) -> list[DependencyFinding]:
121
+ """Audit a pyproject.toml for dependency pinning."""
122
+ findings: list[DependencyFinding] = []
123
+ try:
124
+ import tomllib
125
+ with open(path, "rb") as f:
126
+ data = tomllib.load(f)
127
+ except (OSError, Exception):
128
+ return findings
129
+
130
+ # PEP 621 dependencies
131
+ deps = data.get("project", {}).get("dependencies", [])
132
+ # Also check optional-dependencies
133
+ opt_deps = data.get("project", {}).get("optional-dependencies", {})
134
+ for group_deps in opt_deps.values():
135
+ if isinstance(group_deps, list):
136
+ deps.extend(group_deps)
137
+
138
+ for dep_spec in deps:
139
+ if not isinstance(dep_spec, str):
140
+ continue
141
+ dep = dep_spec.strip()
142
+ if not dep or dep.startswith("#"):
143
+ continue
144
+ finding = self._check_pinning(dep, str(path))
145
+ if finding:
146
+ findings.append(finding)
147
+
148
+ return findings
149
+
150
+ def _audit_requirements(self, path: Path) -> list[DependencyFinding]:
151
+ """Audit a requirements.txt for dependency pinning."""
152
+ findings: list[DependencyFinding] = []
153
+ try:
154
+ content = path.read_text(encoding="utf-8")
155
+ except OSError:
156
+ return findings
157
+
158
+ for line in content.split("\n"):
159
+ line = line.strip()
160
+ if not line or line.startswith("#") or line.startswith("-"):
161
+ continue
162
+ finding = self._check_pinning(line, str(path))
163
+ if finding:
164
+ findings.append(finding)
165
+
166
+ return findings
167
+
168
+ def _audit_package_json(self, path: Path) -> list[DependencyFinding]:
169
+ """Audit a package.json for dependency pinning."""
170
+ findings: list[DependencyFinding] = []
171
+ try:
172
+ data = json.loads(path.read_text(encoding="utf-8"))
173
+ except (OSError, json.JSONDecodeError):
174
+ return findings
175
+
176
+ for section in ("dependencies", "devDependencies"):
177
+ deps = data.get(section, {})
178
+ if not isinstance(deps, dict):
179
+ continue
180
+ for pkg, version in deps.items():
181
+ if not isinstance(version, str):
182
+ continue
183
+ # Flag loose version ranges
184
+ if version.startswith("*") or version == "latest":
185
+ findings.append(DependencyFinding(
186
+ package=pkg,
187
+ version_spec=version,
188
+ severity=Severity.HIGH,
189
+ message=f"Unpinned dependency: {pkg}@{version}",
190
+ recommendation="Pin to a specific version range",
191
+ source_file=str(path),
192
+ ))
193
+ elif version.startswith(">=") and "<" not in version:
194
+ findings.append(DependencyFinding(
195
+ package=pkg,
196
+ version_spec=version,
197
+ severity=Severity.LOW,
198
+ message=f"Open-ended version range: {pkg}@{version}",
199
+ recommendation="Consider adding upper bound (e.g. >=1.0,<2.0)",
200
+ source_file=str(path),
201
+ ))
202
+
203
+ findings.extend(self._audit_install_hooks(data, path))
204
+ return findings
205
+
206
+ def _audit_install_hooks(self, data: dict, path: Path) -> list[DependencyFinding]:
207
+ """Flag package.json install hooks with obfuscation/remote-fetch patterns.
208
+
209
+ Supply-chain attackers (GlassWorm-class) place obfuscated one-liners in
210
+ preinstall/postinstall/install scripts that execute automatically on
211
+ ``npm install``. This detects the most common indicators.
212
+
213
+ Note: only the root-level package.json is audited (same as pinning check).
214
+ Monorepo workspace package.json files are not traversed.
215
+ """
216
+ findings: list[DependencyFinding] = []
217
+ scripts = data.get("scripts", {})
218
+ if not isinstance(scripts, dict):
219
+ return findings
220
+ for hook in ("preinstall", "install", "postinstall"):
221
+ script = scripts.get(hook)
222
+ if not isinstance(script, str) or not script.strip():
223
+ continue
224
+ for _name, regex, description in _SUSPICIOUS_HOOK_TOKENS:
225
+ if regex.search(script):
226
+ findings.append(DependencyFinding(
227
+ package=hook,
228
+ version_spec=script[:200],
229
+ severity=Severity.HIGH,
230
+ cwe_id="CWE-506",
231
+ message=f"Suspicious {hook} script: {description}",
232
+ recommendation=(
233
+ f"Review the '{hook}' script in package.json; "
234
+ "supply-chain attackers use install hooks to run "
235
+ "obfuscated one-liners on `npm install`"
236
+ ),
237
+ source_file=str(path),
238
+ ))
239
+ break # one finding per hook is enough
240
+ return findings
241
+
242
+ def _audit_setup_py(self, path: Path) -> list[DependencyFinding]:
243
+ """Flag network calls in setup.py (supply-chain attack vector).
244
+
245
+ setup.py executes arbitrary Python at install time. Legitimate setup
246
+ scripts only define metadata and dependencies; network fetches there
247
+ are almost always a staged-payload delivery mechanism (ctx/W4SP/
248
+ LiteLLM style attacks).
249
+ """
250
+ findings: list[DependencyFinding] = []
251
+ try:
252
+ content = path.read_text(encoding="utf-8")
253
+ except OSError:
254
+ return findings
255
+ for name, regex, description in _SUSPICIOUS_SETUP_PY_PATTERNS:
256
+ if regex.search(content):
257
+ findings.append(DependencyFinding(
258
+ package="setup.py",
259
+ version_spec=name,
260
+ severity=Severity.HIGH,
261
+ cwe_id="CWE-506",
262
+ message=f"setup.py contains {description} — supply-chain attack pattern",
263
+ recommendation=(
264
+ "Setup scripts should not make network calls; "
265
+ "install-time fetches are a classic supply-chain "
266
+ "vector (cf. PyPI ctx, W4SP stealer)"
267
+ ),
268
+ source_file=str(path),
269
+ ))
270
+ return findings
271
+
272
+ def _check_pinning(self, dep_spec: str, source_file: str) -> DependencyFinding | None:
273
+ """Check a single dependency specifier for pinning issues."""
274
+ # Parse package name and version spec
275
+ match = re.match(r"^([a-zA-Z0-9_.-]+)\s*(.*)$", dep_spec)
276
+ if not match:
277
+ return None
278
+
279
+ pkg = match.group(1)
280
+ version = match.group(2).strip()
281
+
282
+ if not version:
283
+ return DependencyFinding(
284
+ package=pkg,
285
+ version_spec="(none)",
286
+ severity=Severity.MEDIUM,
287
+ message=f"No version constraint for {pkg}",
288
+ recommendation=f"Add version constraint (e.g. {pkg}>=1.0)",
289
+ source_file=source_file,
290
+ )
291
+
292
+ # Floating >= without upper bound
293
+ if ">=" in version and "<" not in version and "==" not in version:
294
+ return DependencyFinding(
295
+ package=pkg,
296
+ version_spec=version,
297
+ severity=Severity.LOW,
298
+ message=f"Open-ended version: {pkg}{version}",
299
+ recommendation="Consider adding upper bound for reproducibility",
300
+ source_file=source_file,
301
+ )
302
+
303
+ return None
@@ -0,0 +1,44 @@
1
+ """Shared pattern-matching iteration for security scanners.
2
+
3
+ Both the filesystem-based scanner (`scanner.py`) and the DB-backed scanner
4
+ (`security_scanner_db.py`) need to walk lines of a file, apply per-pattern
5
+ language filtering, skip comment lines (unless a pattern opts in via
6
+ ``scan_comments``), and yield regex hits. This module centralises that logic.
7
+
8
+ Callers construct their own finding record types — this generator only
9
+ reports (line_number, line_text, matched_pattern).
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from collections.abc import Iterable, Iterator
15
+
16
+ from attocode_intel._internal.integrations.security.patterns import SecurityPattern
17
+
18
+
19
+ def iter_pattern_matches(
20
+ content: str,
21
+ patterns: Iterable[SecurityPattern],
22
+ language: str,
23
+ ) -> Iterator[tuple[int, str, SecurityPattern]]:
24
+ """Yield (line_number, line, pattern) for every pattern hit in ``content``.
25
+
26
+ Filters applied per line × pattern:
27
+ - Language filter: skip patterns scoped to other languages.
28
+ - Comment-line skip: lines starting with ``#`` or ``//`` are skipped
29
+ unless the pattern sets ``scan_comments=True`` (e.g. for stego payload
30
+ detectors that specifically want to scan comments).
31
+
32
+ A line may yield multiple matches if it hits multiple patterns; each
33
+ produces a separate tuple.
34
+ """
35
+ for line_no, line in enumerate(content.splitlines(), 1):
36
+ stripped = line.lstrip()
37
+ is_comment = stripped.startswith("#") or stripped.startswith("//")
38
+ for pat in patterns:
39
+ if pat.languages and language not in pat.languages:
40
+ continue
41
+ if is_comment and not pat.scan_comments:
42
+ continue
43
+ if pat.pattern.search(line):
44
+ yield line_no, line, pat