@neurcode-ai/cli 0.9.64 → 0.9.65

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 (252) hide show
  1. package/LICENSE +201 -0
  2. package/dist/commands/brain.d.ts.map +1 -1
  3. package/dist/commands/brain.js +273 -0
  4. package/dist/commands/brain.js.map +1 -1
  5. package/dist/commands/pilot-report.d.ts +9 -0
  6. package/dist/commands/pilot-report.d.ts.map +1 -0
  7. package/dist/commands/pilot-report.js +176 -0
  8. package/dist/commands/pilot-report.js.map +1 -0
  9. package/dist/commands/remediate-governance.d.ts +54 -0
  10. package/dist/commands/remediate-governance.d.ts.map +1 -0
  11. package/dist/commands/remediate-governance.js +375 -0
  12. package/dist/commands/remediate-governance.js.map +1 -0
  13. package/dist/commands/remediate.d.ts.map +1 -1
  14. package/dist/commands/remediate.js.map +1 -1
  15. package/dist/commands/replay.d.ts.map +1 -1
  16. package/dist/commands/replay.js +30 -0
  17. package/dist/commands/replay.js.map +1 -1
  18. package/dist/commands/verify.d.ts.map +1 -1
  19. package/dist/commands/verify.js +307 -24
  20. package/dist/commands/verify.js.map +1 -1
  21. package/dist/daemon/server.d.ts.map +1 -1
  22. package/dist/daemon/server.js +1078 -0
  23. package/dist/daemon/server.js.map +1 -1
  24. package/dist/explainability/DeterminismClassifier.d.ts +34 -0
  25. package/dist/explainability/DeterminismClassifier.d.ts.map +1 -0
  26. package/dist/explainability/DeterminismClassifier.js +104 -0
  27. package/dist/explainability/DeterminismClassifier.js.map +1 -0
  28. package/dist/explainability/ViolationFormatter.d.ts +32 -0
  29. package/dist/explainability/ViolationFormatter.d.ts.map +1 -0
  30. package/dist/explainability/ViolationFormatter.js +252 -0
  31. package/dist/explainability/ViolationFormatter.js.map +1 -0
  32. package/dist/explainability/index.d.ts +15 -0
  33. package/dist/explainability/index.d.ts.map +1 -0
  34. package/dist/explainability/index.js +94 -0
  35. package/dist/explainability/index.js.map +1 -0
  36. package/dist/explainability/types.d.ts +37 -0
  37. package/dist/explainability/types.d.ts.map +1 -0
  38. package/dist/explainability/types.js +3 -0
  39. package/dist/explainability/types.js.map +1 -0
  40. package/dist/governance/canonical-pipeline.d.ts +38 -0
  41. package/dist/governance/canonical-pipeline.d.ts.map +1 -0
  42. package/dist/governance/canonical-pipeline.js +448 -0
  43. package/dist/governance/canonical-pipeline.js.map +1 -0
  44. package/dist/governance/structural-on-diff.d.ts +13 -0
  45. package/dist/governance/structural-on-diff.d.ts.map +1 -0
  46. package/dist/governance/structural-on-diff.js +35 -0
  47. package/dist/governance/structural-on-diff.js.map +1 -0
  48. package/dist/governance/structural-policy-merge.d.ts +14 -0
  49. package/dist/governance/structural-policy-merge.d.ts.map +1 -0
  50. package/dist/governance/structural-policy-merge.js +25 -0
  51. package/dist/governance/structural-policy-merge.js.map +1 -0
  52. package/dist/index.js +71 -0
  53. package/dist/index.js.map +1 -1
  54. package/dist/integrations/review-compression/index.d.ts +50 -0
  55. package/dist/integrations/review-compression/index.d.ts.map +1 -0
  56. package/dist/integrations/review-compression/index.js +158 -0
  57. package/dist/integrations/review-compression/index.js.map +1 -0
  58. package/dist/intent-engine/domain-taxonomy.d.ts +42 -0
  59. package/dist/intent-engine/domain-taxonomy.d.ts.map +1 -0
  60. package/dist/intent-engine/domain-taxonomy.js +534 -0
  61. package/dist/intent-engine/domain-taxonomy.js.map +1 -0
  62. package/dist/intent-engine/index.d.ts +1 -0
  63. package/dist/intent-engine/index.d.ts.map +1 -1
  64. package/dist/intent-engine/index.js +6 -1
  65. package/dist/intent-engine/index.js.map +1 -1
  66. package/dist/intent-engine/parser.d.ts.map +1 -1
  67. package/dist/intent-engine/parser.js +47 -0
  68. package/dist/intent-engine/parser.js.map +1 -1
  69. package/dist/intent-engine/semantic-expander.d.ts +104 -0
  70. package/dist/intent-engine/semantic-expander.d.ts.map +1 -0
  71. package/dist/intent-engine/semantic-expander.js +480 -0
  72. package/dist/intent-engine/semantic-expander.js.map +1 -0
  73. package/dist/patch-engine/patterns.d.ts.map +1 -1
  74. package/dist/patch-engine/patterns.js +8 -4
  75. package/dist/patch-engine/patterns.js.map +1 -1
  76. package/dist/semantic/index.d.ts +14 -0
  77. package/dist/semantic/index.d.ts.map +1 -0
  78. package/dist/semantic/index.js +30 -0
  79. package/dist/semantic/index.js.map +1 -0
  80. package/dist/semantic/tfidf-engine.d.ts +81 -0
  81. package/dist/semantic/tfidf-engine.d.ts.map +1 -0
  82. package/dist/semantic/tfidf-engine.js +278 -0
  83. package/dist/semantic/tfidf-engine.js.map +1 -0
  84. package/dist/semantic/vector-store.d.ts +108 -0
  85. package/dist/semantic/vector-store.d.ts.map +1 -0
  86. package/dist/semantic/vector-store.js +321 -0
  87. package/dist/semantic/vector-store.js.map +1 -0
  88. package/dist/structural-rules/context-severity.d.ts +46 -0
  89. package/dist/structural-rules/context-severity.d.ts.map +1 -0
  90. package/dist/structural-rules/context-severity.js +115 -0
  91. package/dist/structural-rules/context-severity.js.map +1 -0
  92. package/dist/structural-rules/distributed/DS001-saga-rollback-absence.d.ts +11 -0
  93. package/dist/structural-rules/distributed/DS001-saga-rollback-absence.d.ts.map +1 -0
  94. package/dist/structural-rules/distributed/DS001-saga-rollback-absence.js +212 -0
  95. package/dist/structural-rules/distributed/DS001-saga-rollback-absence.js.map +1 -0
  96. package/dist/structural-rules/distributed/DS002-missing-correlation-id.d.ts +11 -0
  97. package/dist/structural-rules/distributed/DS002-missing-correlation-id.d.ts.map +1 -0
  98. package/dist/structural-rules/distributed/DS002-missing-correlation-id.js +213 -0
  99. package/dist/structural-rules/distributed/DS002-missing-correlation-id.js.map +1 -0
  100. package/dist/structural-rules/distributed/index.d.ts +3 -0
  101. package/dist/structural-rules/distributed/index.d.ts.map +1 -0
  102. package/dist/structural-rules/distributed/index.js +8 -0
  103. package/dist/structural-rules/distributed/index.js.map +1 -0
  104. package/dist/structural-rules/engine.d.ts +25 -0
  105. package/dist/structural-rules/engine.d.ts.map +1 -0
  106. package/dist/structural-rules/engine.js +90 -0
  107. package/dist/structural-rules/engine.js.map +1 -0
  108. package/dist/structural-rules/index.d.ts +41 -0
  109. package/dist/structural-rules/index.d.ts.map +1 -0
  110. package/dist/structural-rules/index.js +141 -0
  111. package/dist/structural-rules/index.js.map +1 -0
  112. package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.d.ts +11 -0
  113. package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.d.ts.map +1 -0
  114. package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.js +66 -0
  115. package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.js.map +1 -0
  116. package/dist/structural-rules/python/PY002-unbounded-dict-singleton.d.ts +11 -0
  117. package/dist/structural-rules/python/PY002-unbounded-dict-singleton.d.ts.map +1 -0
  118. package/dist/structural-rules/python/PY002-unbounded-dict-singleton.js +135 -0
  119. package/dist/structural-rules/python/PY002-unbounded-dict-singleton.js.map +1 -0
  120. package/dist/structural-rules/python/PY003-broad-except-clause.d.ts +11 -0
  121. package/dist/structural-rules/python/PY003-broad-except-clause.d.ts.map +1 -0
  122. package/dist/structural-rules/python/PY003-broad-except-clause.js +86 -0
  123. package/dist/structural-rules/python/PY003-broad-except-clause.js.map +1 -0
  124. package/dist/structural-rules/python/PY004-swallowed-async-exception.d.ts +11 -0
  125. package/dist/structural-rules/python/PY004-swallowed-async-exception.d.ts.map +1 -0
  126. package/dist/structural-rules/python/PY004-swallowed-async-exception.js +167 -0
  127. package/dist/structural-rules/python/PY004-swallowed-async-exception.js.map +1 -0
  128. package/dist/structural-rules/python/PY005-fastapi-without-pydantic.d.ts +11 -0
  129. package/dist/structural-rules/python/PY005-fastapi-without-pydantic.d.ts.map +1 -0
  130. package/dist/structural-rules/python/PY005-fastapi-without-pydantic.js +154 -0
  131. package/dist/structural-rules/python/PY005-fastapi-without-pydantic.js.map +1 -0
  132. package/dist/structural-rules/python/PY006-blocking-io-in-async.d.ts +11 -0
  133. package/dist/structural-rules/python/PY006-blocking-io-in-async.d.ts.map +1 -0
  134. package/dist/structural-rules/python/PY006-blocking-io-in-async.js +130 -0
  135. package/dist/structural-rules/python/PY006-blocking-io-in-async.js.map +1 -0
  136. package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.d.ts +11 -0
  137. package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.d.ts.map +1 -0
  138. package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.js +93 -0
  139. package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.js.map +1 -0
  140. package/dist/structural-rules/python/PY008-celery-task-without-retry.d.ts +11 -0
  141. package/dist/structural-rules/python/PY008-celery-task-without-retry.d.ts.map +1 -0
  142. package/dist/structural-rules/python/PY008-celery-task-without-retry.js +154 -0
  143. package/dist/structural-rules/python/PY008-celery-task-without-retry.js.map +1 -0
  144. package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.d.ts +11 -0
  145. package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.d.ts.map +1 -0
  146. package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.js +133 -0
  147. package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.js.map +1 -0
  148. package/dist/structural-rules/python/PY010-leaked-aiohttp-session.d.ts +11 -0
  149. package/dist/structural-rules/python/PY010-leaked-aiohttp-session.d.ts.map +1 -0
  150. package/dist/structural-rules/python/PY010-leaked-aiohttp-session.js +80 -0
  151. package/dist/structural-rules/python/PY010-leaked-aiohttp-session.js.map +1 -0
  152. package/dist/structural-rules/rules/SR001-swallowed-async-rejection.d.ts +11 -0
  153. package/dist/structural-rules/rules/SR001-swallowed-async-rejection.d.ts.map +1 -0
  154. package/dist/structural-rules/rules/SR001-swallowed-async-rejection.js +145 -0
  155. package/dist/structural-rules/rules/SR001-swallowed-async-rejection.js.map +1 -0
  156. package/dist/structural-rules/rules/SR002-unbounded-collection.d.ts +11 -0
  157. package/dist/structural-rules/rules/SR002-unbounded-collection.d.ts.map +1 -0
  158. package/dist/structural-rules/rules/SR002-unbounded-collection.js +196 -0
  159. package/dist/structural-rules/rules/SR002-unbounded-collection.js.map +1 -0
  160. package/dist/structural-rules/rules/SR003-timer-without-cleanup.d.ts +11 -0
  161. package/dist/structural-rules/rules/SR003-timer-without-cleanup.d.ts.map +1 -0
  162. package/dist/structural-rules/rules/SR003-timer-without-cleanup.js +148 -0
  163. package/dist/structural-rules/rules/SR003-timer-without-cleanup.js.map +1 -0
  164. package/dist/structural-rules/rules/SR004-request-boundary-no-validation.d.ts +11 -0
  165. package/dist/structural-rules/rules/SR004-request-boundary-no-validation.d.ts.map +1 -0
  166. package/dist/structural-rules/rules/SR004-request-boundary-no-validation.js +162 -0
  167. package/dist/structural-rules/rules/SR004-request-boundary-no-validation.js.map +1 -0
  168. package/dist/structural-rules/rules/SR005-halfopen-probe-gate.d.ts +11 -0
  169. package/dist/structural-rules/rules/SR005-halfopen-probe-gate.d.ts.map +1 -0
  170. package/dist/structural-rules/rules/SR005-halfopen-probe-gate.js +150 -0
  171. package/dist/structural-rules/rules/SR005-halfopen-probe-gate.js.map +1 -0
  172. package/dist/structural-rules/rules/SR006-fanout-error-sanitization.d.ts +11 -0
  173. package/dist/structural-rules/rules/SR006-fanout-error-sanitization.d.ts.map +1 -0
  174. package/dist/structural-rules/rules/SR006-fanout-error-sanitization.js +161 -0
  175. package/dist/structural-rules/rules/SR006-fanout-error-sanitization.js.map +1 -0
  176. package/dist/structural-rules/rules/SR007-cross-request-error.d.ts +11 -0
  177. package/dist/structural-rules/rules/SR007-cross-request-error.d.ts.map +1 -0
  178. package/dist/structural-rules/rules/SR007-cross-request-error.js +175 -0
  179. package/dist/structural-rules/rules/SR007-cross-request-error.js.map +1 -0
  180. package/dist/structural-rules/rules/SR008-background-task-orphan.d.ts +11 -0
  181. package/dist/structural-rules/rules/SR008-background-task-orphan.d.ts.map +1 -0
  182. package/dist/structural-rules/rules/SR008-background-task-orphan.js +176 -0
  183. package/dist/structural-rules/rules/SR008-background-task-orphan.js.map +1 -0
  184. package/dist/structural-rules/rules/SR009-missing-retry-backoff.d.ts +11 -0
  185. package/dist/structural-rules/rules/SR009-missing-retry-backoff.d.ts.map +1 -0
  186. package/dist/structural-rules/rules/SR009-missing-retry-backoff.js +168 -0
  187. package/dist/structural-rules/rules/SR009-missing-retry-backoff.js.map +1 -0
  188. package/dist/structural-rules/rules/SR010-retry-storm.d.ts +11 -0
  189. package/dist/structural-rules/rules/SR010-retry-storm.d.ts.map +1 -0
  190. package/dist/structural-rules/rules/SR010-retry-storm.js +181 -0
  191. package/dist/structural-rules/rules/SR010-retry-storm.js.map +1 -0
  192. package/dist/structural-rules/rules/SR011-event-listener-leak.d.ts +11 -0
  193. package/dist/structural-rules/rules/SR011-event-listener-leak.d.ts.map +1 -0
  194. package/dist/structural-rules/rules/SR011-event-listener-leak.js +208 -0
  195. package/dist/structural-rules/rules/SR011-event-listener-leak.js.map +1 -0
  196. package/dist/structural-rules/rules/SR012-promise-race-leak.d.ts +11 -0
  197. package/dist/structural-rules/rules/SR012-promise-race-leak.d.ts.map +1 -0
  198. package/dist/structural-rules/rules/SR012-promise-race-leak.js +191 -0
  199. package/dist/structural-rules/rules/SR012-promise-race-leak.js.map +1 -0
  200. package/dist/structural-rules/rules/SR013-missing-idempotency-key.d.ts +11 -0
  201. package/dist/structural-rules/rules/SR013-missing-idempotency-key.d.ts.map +1 -0
  202. package/dist/structural-rules/rules/SR013-missing-idempotency-key.js +219 -0
  203. package/dist/structural-rules/rules/SR013-missing-idempotency-key.js.map +1 -0
  204. package/dist/structural-rules/rules/SR014-mutable-closure-async.d.ts +11 -0
  205. package/dist/structural-rules/rules/SR014-mutable-closure-async.d.ts.map +1 -0
  206. package/dist/structural-rules/rules/SR014-mutable-closure-async.js +208 -0
  207. package/dist/structural-rules/rules/SR014-mutable-closure-async.js.map +1 -0
  208. package/dist/structural-rules/rules/SR015-dangling-abort-controller.d.ts +11 -0
  209. package/dist/structural-rules/rules/SR015-dangling-abort-controller.d.ts.map +1 -0
  210. package/dist/structural-rules/rules/SR015-dangling-abort-controller.js +190 -0
  211. package/dist/structural-rules/rules/SR015-dangling-abort-controller.js.map +1 -0
  212. package/dist/structural-rules/rules/SR016-unsafe-json-parse.d.ts +11 -0
  213. package/dist/structural-rules/rules/SR016-unsafe-json-parse.d.ts.map +1 -0
  214. package/dist/structural-rules/rules/SR016-unsafe-json-parse.js +187 -0
  215. package/dist/structural-rules/rules/SR016-unsafe-json-parse.js.map +1 -0
  216. package/dist/structural-rules/suppressions.d.ts +43 -0
  217. package/dist/structural-rules/suppressions.d.ts.map +1 -0
  218. package/dist/structural-rules/suppressions.js +115 -0
  219. package/dist/structural-rules/suppressions.js.map +1 -0
  220. package/dist/structural-rules/types.d.ts +43 -0
  221. package/dist/structural-rules/types.d.ts.map +1 -0
  222. package/dist/structural-rules/types.js +3 -0
  223. package/dist/structural-rules/types.js.map +1 -0
  224. package/dist/utils/brain-cache.d.ts +100 -0
  225. package/dist/utils/brain-cache.d.ts.map +1 -0
  226. package/dist/utils/brain-cache.js +346 -0
  227. package/dist/utils/brain-cache.js.map +1 -0
  228. package/dist/utils/governance-provenance.d.ts +95 -0
  229. package/dist/utils/governance-provenance.d.ts.map +1 -0
  230. package/dist/utils/governance-provenance.js +187 -0
  231. package/dist/utils/governance-provenance.js.map +1 -0
  232. package/dist/utils/pilot-metrics.d.ts +46 -0
  233. package/dist/utils/pilot-metrics.d.ts.map +1 -0
  234. package/dist/utils/pilot-metrics.js +240 -0
  235. package/dist/utils/pilot-metrics.js.map +1 -0
  236. package/dist/utils/replay-runtime.d.ts +34 -0
  237. package/dist/utils/replay-runtime.d.ts.map +1 -1
  238. package/dist/utils/replay-runtime.js +207 -0
  239. package/dist/utils/replay-runtime.js.map +1 -1
  240. package/dist/workspace/cross-repo-graph.d.ts +111 -0
  241. package/dist/workspace/cross-repo-graph.d.ts.map +1 -0
  242. package/dist/workspace/cross-repo-graph.js +450 -0
  243. package/dist/workspace/cross-repo-graph.js.map +1 -0
  244. package/dist/workspace/federated-context.d.ts +144 -0
  245. package/dist/workspace/federated-context.d.ts.map +1 -0
  246. package/dist/workspace/federated-context.js +347 -0
  247. package/dist/workspace/federated-context.js.map +1 -0
  248. package/dist/workspace/index.d.ts +38 -0
  249. package/dist/workspace/index.d.ts.map +1 -0
  250. package/dist/workspace/index.js +48 -0
  251. package/dist/workspace/index.js.map +1 -0
  252. package/package.json +9 -9
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PY008CeleryTaskWithoutRetry = void 0;
4
+ // Matches Celery task decorators
5
+ const CELERY_DECORATOR_RE = /^\s*@(?:\w+\.)?(?:app\.task|celery\.task|shared_task)\s*[\(\n]/;
6
+ const CELERY_DECORATOR_INLINE_RE = /^\s*@(?:\w+\.)?(?:app\.task|celery\.task|shared_task)\s*\(/;
7
+ // Retry configuration keywords inside the decorator
8
+ const RETRY_CONFIG_RE = /(?:max_retries|retry_backoff|autoretry_for|bind\s*=\s*True)/;
9
+ // ignore_result=True — fire-and-forget, valid without retry
10
+ const IGNORE_RESULT_RE = /ignore_result\s*=\s*True/;
11
+ // A raise statement inside the function body
12
+ const RAISE_RE = /\braise\b/;
13
+ // self.retry( call — manual retry in bind=True task
14
+ const SELF_RETRY_RE = /\bself\.retry\s*\(/;
15
+ function getIndent(line) {
16
+ return line.length - line.trimStart().length;
17
+ }
18
+ /**
19
+ * Collect the decorator text (potentially multi-line) starting at decoratorLine.
20
+ * Returns the full decorator string and the line index where the decorator ends.
21
+ */
22
+ function collectDecorator(lines, decoratorLine) {
23
+ let text = lines[decoratorLine];
24
+ let depth = 0;
25
+ for (const ch of lines[decoratorLine]) {
26
+ if (ch === '(')
27
+ depth++;
28
+ else if (ch === ')')
29
+ depth--;
30
+ }
31
+ let j = decoratorLine + 1;
32
+ while (depth > 0 && j < lines.length) {
33
+ text += '\n' + lines[j];
34
+ for (const ch of lines[j]) {
35
+ if (ch === '(')
36
+ depth++;
37
+ else if (ch === ')')
38
+ depth--;
39
+ }
40
+ j++;
41
+ }
42
+ return { text, endLine: j - 1 };
43
+ }
44
+ class PY008CeleryTaskWithoutRetry {
45
+ id = 'PY008';
46
+ name = 'Celery task without retry configuration';
47
+ policyRef = 'PY008';
48
+ severity = 'ADVISORY';
49
+ languages = ['python'];
50
+ description = 'Celery task functions that can raise exceptions but have no retry configuration silently drop jobs on transient failures.';
51
+ check(filePath, sourceText) {
52
+ try {
53
+ const violations = [];
54
+ // Normalize line endings
55
+ const lines = sourceText.replace(/\r\n/g, '\n').replace(/\r/g, '\n').split('\n');
56
+ let i = 0;
57
+ while (i < lines.length) {
58
+ const line = lines[i];
59
+ // Detect Celery decorator
60
+ const isDecorator = CELERY_DECORATOR_RE.test(line) || CELERY_DECORATOR_INLINE_RE.test(line);
61
+ if (!isDecorator) {
62
+ i++;
63
+ continue;
64
+ }
65
+ const decoratorStartLine = i;
66
+ // Collect full decorator text (handles multi-line)
67
+ const { text: decoratorText, endLine: decoratorEnd } = collectDecorator(lines, i);
68
+ // Check for retry config
69
+ const hasRetryConfig = RETRY_CONFIG_RE.test(decoratorText);
70
+ const hasIgnoreResult = IGNORE_RESULT_RE.test(decoratorText);
71
+ // Find the function definition line after decorator
72
+ let funcDefLine = -1;
73
+ let j = decoratorEnd + 1;
74
+ while (j < Math.min(decoratorEnd + 6, lines.length)) {
75
+ const l = lines[j].trimStart();
76
+ if (/^(?:async\s+)?def\s+\w+\s*\(/.test(l)) {
77
+ funcDefLine = j;
78
+ break;
79
+ }
80
+ if (l.length > 0 && !l.startsWith('@') && !l.startsWith('#'))
81
+ break;
82
+ j++;
83
+ }
84
+ if (funcDefLine === -1) {
85
+ i = j;
86
+ continue;
87
+ }
88
+ if (hasRetryConfig) {
89
+ // Already has retry config — no violation
90
+ i = funcDefLine + 1;
91
+ continue;
92
+ }
93
+ // Collect function body
94
+ const funcIndent = getIndent(lines[funcDefLine]);
95
+ let bodyHasRaise = false;
96
+ let bodyHasSelfRetry = false;
97
+ let k = funcDefLine + 1;
98
+ while (k < lines.length) {
99
+ const bl = lines[k];
100
+ const bt = bl.trimStart();
101
+ if (bt.length === 0) {
102
+ k++;
103
+ continue;
104
+ }
105
+ const bi = getIndent(bl);
106
+ if (bi <= funcIndent)
107
+ break;
108
+ if (RAISE_RE.test(bl))
109
+ bodyHasRaise = true;
110
+ if (SELF_RETRY_RE.test(bl))
111
+ bodyHasSelfRetry = true;
112
+ k++;
113
+ }
114
+ // If fire-and-forget (ignore_result=True) and no raise → no violation
115
+ if (hasIgnoreResult && !bodyHasRaise) {
116
+ i = k;
117
+ continue;
118
+ }
119
+ // If uses self.retry() manually → no violation
120
+ if (bodyHasSelfRetry) {
121
+ i = k;
122
+ continue;
123
+ }
124
+ // If function has potential raises and no retry config → flag it
125
+ if (bodyHasRaise) {
126
+ violations.push({
127
+ ruleId: this.id,
128
+ ruleName: this.name,
129
+ policyRef: this.policyRef,
130
+ severity: this.severity,
131
+ filePath,
132
+ line: decoratorStartLine + 1,
133
+ column: 1,
134
+ evidence: lines[decoratorStartLine].slice(0, 120),
135
+ operationalRisk: 'A transient failure (network timeout, DB connection error) in a Celery task without retry configuration ' +
136
+ 'permanently drops the job. The message is lost without processing, causing data loss or inconsistent state.',
137
+ remediation: 'Add `autoretry_for=(Exception,), max_retries=3, retry_backoff=True` to the decorator, ' +
138
+ 'or use `self.retry(exc=exc, countdown=2**self.request.retries)` in the exception handler.',
139
+ determinism: 'heuristic-advisory',
140
+ confidence: 0.75,
141
+ language: 'python',
142
+ });
143
+ }
144
+ i = k;
145
+ }
146
+ return violations;
147
+ }
148
+ catch {
149
+ return [];
150
+ }
151
+ }
152
+ }
153
+ exports.PY008CeleryTaskWithoutRetry = PY008CeleryTaskWithoutRetry;
154
+ //# sourceMappingURL=PY008-celery-task-without-retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PY008-celery-task-without-retry.js","sourceRoot":"","sources":["../../../src/structural-rules/python/PY008-celery-task-without-retry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { StructuralRule, StructuralViolation, RuleLanguage } from '../types';
2
+ export declare class PY009UnsafePickleDeserialization implements StructuralRule {
3
+ id: string;
4
+ name: string;
5
+ policyRef: string;
6
+ severity: "BLOCKING";
7
+ languages: RuleLanguage[];
8
+ description: string;
9
+ check(filePath: string, sourceText: string): StructuralViolation[];
10
+ }
11
+ //# sourceMappingURL=PY009-unsafe-pickle-deserialization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PY009-unsafe-pickle-deserialization.d.ts","sourceRoot":"","sources":["../../../src/structural-rules/python/PY009-unsafe-pickle-deserialization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAmB7E,qBAAa,gCAAiC,YAAW,cAAc;IACrE,EAAE,SAAW;IACb,IAAI,SAAmC;IACvC,SAAS,SAAW;IACpB,QAAQ,EAAG,UAAU,CAAU;IAC/B,SAAS,EAAE,YAAY,EAAE,CAAc;IACvC,WAAW,SAEsD;IAEjE,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,mBAAmB,EAAE;CAoHnE"}
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PY009UnsafePickleDeserialization = void 0;
4
+ // Matches pickle.loads( or pickle.load(
5
+ const PICKLE_LOAD_RE = /\bpickle\.loads?\s*\(/;
6
+ // Matches joblib.load(
7
+ const JOBLIB_LOAD_RE = /\bjoblib\.load\s*\(/;
8
+ // Matches torch.load( without weights_only=True
9
+ const TORCH_LOAD_RE = /\btorch\.load\s*\(/;
10
+ const TORCH_WEIGHTS_ONLY_RE = /weights_only\s*=\s*True/;
11
+ // Detects if this appears to be a test file
12
+ const TEST_FILE_RE = /(?:^|[\\/])(?:test_|_test|tests[\\/])/;
13
+ // Detects if the pickle input looks like a literal bytes value in a test
14
+ // e.g. pickle.loads(b'\x80\x04...') or pickle.loads(b"...")
15
+ const LITERAL_BYTES_ARG_RE = /\bpickle\.loads?\s*\(\s*b['"]|pickle\.loads?\s*\(\s*b"""|\bpickle\.loads?\s*\(\s*b'''/;
16
+ class PY009UnsafePickleDeserialization {
17
+ id = 'PY009';
18
+ name = 'Unsafe pickle deserialization';
19
+ policyRef = 'PY009';
20
+ severity = 'BLOCKING';
21
+ languages = ['python'];
22
+ description = 'pickle.loads() / pickle.load() executes arbitrary Python code during deserialization. ' +
23
+ 'torch.load() without weights_only=True is equally dangerous.';
24
+ check(filePath, sourceText) {
25
+ try {
26
+ const violations = [];
27
+ // Normalize line endings
28
+ const lines = sourceText.replace(/\r\n/g, '\n').replace(/\r/g, '\n').split('\n');
29
+ const isTestFile = TEST_FILE_RE.test(filePath);
30
+ for (let i = 0; i < lines.length; i++) {
31
+ const line = lines[i];
32
+ const trimmed = line.trimStart();
33
+ // Skip comment lines
34
+ if (trimmed.startsWith('#'))
35
+ continue;
36
+ // Skip noqa lines
37
+ if (/\bnoqa\b/.test(line))
38
+ continue;
39
+ // Check pickle.loads / pickle.load
40
+ if (PICKLE_LOAD_RE.test(line)) {
41
+ // Exclude: test file with literal bytes argument
42
+ if (isTestFile && LITERAL_BYTES_ARG_RE.test(line)) {
43
+ continue;
44
+ }
45
+ violations.push({
46
+ ruleId: this.id,
47
+ ruleName: this.name,
48
+ policyRef: this.policyRef,
49
+ severity: this.severity,
50
+ filePath,
51
+ line: i + 1,
52
+ column: 1,
53
+ evidence: line.slice(0, 120),
54
+ operationalRisk: '`pickle.loads()` executes arbitrary Python code during deserialization. ' +
55
+ 'A single compromised or malformed pickle payload from any source achieves remote code execution ' +
56
+ 'on the deserializing machine. This is a critical supply-chain attack vector in ML systems that share model artifacts.',
57
+ remediation: 'Replace `pickle` with `json`, `msgpack`, or `protobuf` for data serialization. ' +
58
+ 'For ML models, use `safetensors` format. If pickle is truly required, validate the HMAC signature ' +
59
+ 'before deserializing and only accept pickles from trusted, authenticated internal sources.',
60
+ determinism: 'heuristic-advisory',
61
+ confidence: 0.95,
62
+ language: 'python',
63
+ });
64
+ continue;
65
+ }
66
+ // Check joblib.load(
67
+ if (JOBLIB_LOAD_RE.test(line)) {
68
+ violations.push({
69
+ ruleId: this.id,
70
+ ruleName: this.name,
71
+ policyRef: this.policyRef,
72
+ severity: this.severity,
73
+ filePath,
74
+ line: i + 1,
75
+ column: 1,
76
+ evidence: line.slice(0, 120),
77
+ operationalRisk: '`joblib.load()` uses pickle internally and executes arbitrary Python code during deserialization. ' +
78
+ 'Malicious or tampered model artifacts can achieve remote code execution.',
79
+ remediation: 'Use `safetensors` format for model artifacts, or validate the HMAC signature of the joblib file before loading.',
80
+ determinism: 'heuristic-advisory',
81
+ confidence: 0.95,
82
+ language: 'python',
83
+ });
84
+ continue;
85
+ }
86
+ // Check torch.load( — flag if weights_only=True is NOT on the same line
87
+ // Also check the next 2 lines for multi-line calls
88
+ if (TORCH_LOAD_RE.test(line)) {
89
+ // Collect the call: check current line + next 2 for weights_only=True
90
+ let callText = line;
91
+ for (let k = 1; k <= 2 && i + k < lines.length; k++) {
92
+ callText += '\n' + lines[i + k];
93
+ // Stop if we've closed the parens
94
+ let depth = 0;
95
+ for (const ch of callText) {
96
+ if (ch === '(')
97
+ depth++;
98
+ else if (ch === ')')
99
+ depth--;
100
+ }
101
+ if (depth <= 0)
102
+ break;
103
+ }
104
+ if (!TORCH_WEIGHTS_ONLY_RE.test(callText)) {
105
+ violations.push({
106
+ ruleId: this.id,
107
+ ruleName: this.name,
108
+ policyRef: this.policyRef,
109
+ severity: this.severity,
110
+ filePath,
111
+ line: i + 1,
112
+ column: 1,
113
+ evidence: line.slice(0, 120),
114
+ operationalRisk: '`torch.load()` without `weights_only=True` uses pickle and executes arbitrary Python code. ' +
115
+ 'PyTorch 2.0+ requires `weights_only=True` for safe model loading from untrusted sources.',
116
+ remediation: 'Add `weights_only=True`: `torch.load(path, weights_only=True)`. ' +
117
+ 'For full model loading you trust internally, at minimum validate the source integrity before loading.',
118
+ determinism: 'heuristic-advisory',
119
+ confidence: 0.95,
120
+ language: 'python',
121
+ });
122
+ }
123
+ }
124
+ }
125
+ return violations;
126
+ }
127
+ catch {
128
+ return [];
129
+ }
130
+ }
131
+ }
132
+ exports.PY009UnsafePickleDeserialization = PY009UnsafePickleDeserialization;
133
+ //# sourceMappingURL=PY009-unsafe-pickle-deserialization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PY009-unsafe-pickle-deserialization.js","sourceRoot":"","sources":["../../../src/structural-rules/python/PY009-unsafe-pickle-deserialization.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { StructuralRule, StructuralViolation, RuleLanguage } from '../types';
2
+ export declare class PY010LeakedAiohttpSession implements StructuralRule {
3
+ id: string;
4
+ name: string;
5
+ policyRef: string;
6
+ severity: "BLOCKING";
7
+ languages: RuleLanguage[];
8
+ description: string;
9
+ check(filePath: string, sourceText: string): StructuralViolation[];
10
+ }
11
+ //# sourceMappingURL=PY010-leaked-aiohttp-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PY010-leaked-aiohttp-session.d.ts","sourceRoot":"","sources":["../../../src/structural-rules/python/PY010-leaked-aiohttp-session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAY7E,qBAAa,yBAA0B,YAAW,cAAc;IAC9D,EAAE,SAAW;IACb,IAAI,SAA2D;IAC/D,SAAS,SAAW;IACpB,QAAQ,EAAG,UAAU,CAAU;IAC/B,SAAS,EAAE,YAAY,EAAE,CAAc;IACvC,WAAW,SAC8G;IAEzH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,mBAAmB,EAAE;CAiEnE"}
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PY010LeakedAiohttpSession = void 0;
4
+ // Matches bare assignment: session = aiohttp.ClientSession() or session = ClientSession()
5
+ // Captures variable name and whether it's aiohttp-qualified
6
+ const SESSION_ASSIGN_RE = /^(\s*)(\w+)\s*=\s*(?:aiohttp\.)?ClientSession\s*\(/;
7
+ // Matches correct async with usage
8
+ const ASYNC_WITH_SESSION_RE = /^\s*async\s+with\s+(?:aiohttp\.)?ClientSession\s*\(/;
9
+ // Matches await <varname>.close() — shutdown hook pattern
10
+ const AWAIT_CLOSE_RE = /\bawait\s+\w+\s*\.\s*close\s*\(\)/;
11
+ class PY010LeakedAiohttpSession {
12
+ id = 'PY010';
13
+ name = 'aiohttp.ClientSession created without context manager';
14
+ policyRef = 'PY010';
15
+ severity = 'BLOCKING';
16
+ languages = ['python'];
17
+ description = 'aiohttp.ClientSession() assigned to a variable without `async with` leaks TCP connection pools and file descriptors.';
18
+ check(filePath, sourceText) {
19
+ try {
20
+ const violations = [];
21
+ // Normalize line endings
22
+ const normalizedText = sourceText.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
23
+ const lines = normalizedText.split('\n');
24
+ // Pre-scan: does the file contain await <something>.close() anywhere?
25
+ // This handles the module-level singleton pattern with a shutdown hook.
26
+ const fileHasAwaitClose = AWAIT_CLOSE_RE.test(normalizedText);
27
+ for (let i = 0; i < lines.length; i++) {
28
+ const line = lines[i];
29
+ const trimmed = line.trimStart();
30
+ // Skip comment lines
31
+ if (trimmed.startsWith('#'))
32
+ continue;
33
+ // Skip noqa
34
+ if (/\bnoqa\b/.test(line))
35
+ continue;
36
+ // Skip correct async with usage
37
+ if (ASYNC_WITH_SESSION_RE.test(line))
38
+ continue;
39
+ const match = SESSION_ASSIGN_RE.exec(line);
40
+ if (!match)
41
+ continue;
42
+ const varName = match[2];
43
+ // Check if the specific variable has a close() call anywhere in the file
44
+ const varCloseRe = new RegExp(`\\bawait\\s+${varName}\\s*\\.\\s*close\\s*\\(\\)`);
45
+ const varHasClose = varCloseRe.test(normalizedText);
46
+ // If this variable is closed somewhere (shutdown hook) — it's a managed singleton, skip
47
+ if (varHasClose)
48
+ continue;
49
+ // If the file has generic await <x>.close() and this is likely a module-level singleton
50
+ // Heuristic: if the assignment is at module level (indent == 0) and file has await close → skip
51
+ const assignIndent = match[1].length;
52
+ if (assignIndent === 0 && fileHasAwaitClose)
53
+ continue;
54
+ violations.push({
55
+ ruleId: this.id,
56
+ ruleName: this.name,
57
+ policyRef: this.policyRef,
58
+ severity: this.severity,
59
+ filePath,
60
+ line: i + 1,
61
+ column: 1,
62
+ evidence: line.slice(0, 120),
63
+ operationalRisk: 'Each unclosed aiohttp session leaks a TCP connection pool and an underlying connector. ' +
64
+ 'In services that create sessions per-request, this exhausts file descriptors within minutes under load.',
65
+ remediation: 'Use `async with aiohttp.ClientSession() as session:` for request-scoped sessions. ' +
66
+ 'For long-lived sessions, create once at startup and call `await session.close()` in the app shutdown handler.',
67
+ determinism: 'heuristic-advisory',
68
+ confidence: 0.85,
69
+ language: 'python',
70
+ });
71
+ }
72
+ return violations;
73
+ }
74
+ catch {
75
+ return [];
76
+ }
77
+ }
78
+ }
79
+ exports.PY010LeakedAiohttpSession = PY010LeakedAiohttpSession;
80
+ //# sourceMappingURL=PY010-leaked-aiohttp-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PY010-leaked-aiohttp-session.js","sourceRoot":"","sources":["../../../src/structural-rules/python/PY010-leaked-aiohttp-session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { StructuralRule, StructuralViolation, RuleLanguage } from '../types';
2
+ export declare class SR001SwallowedAsyncRejection implements StructuralRule {
3
+ id: string;
4
+ name: string;
5
+ policyRef: string;
6
+ severity: "BLOCKING";
7
+ languages: RuleLanguage[];
8
+ description: string;
9
+ check(filePath: string, sourceText: string): StructuralViolation[];
10
+ }
11
+ //# sourceMappingURL=SR001-swallowed-async-rejection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SR001-swallowed-async-rejection.d.ts","sourceRoot":"","sources":["../../../src/structural-rules/rules/SR001-swallowed-async-rejection.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAiC7E,qBAAa,4BAA6B,YAAW,cAAc;IACjE,EAAE,SAAW;IACb,IAAI,SAA+B;IACnC,SAAS,SAAU;IACnB,QAAQ,EAAG,UAAU,CAAU;IAC/B,SAAS,EAAE,YAAY,EAAE,CAAgC;IACzD,WAAW,SACgG;IAE3G,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,mBAAmB,EAAE;CAmFnE"}
@@ -0,0 +1,145 @@
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.SR001SwallowedAsyncRejection = void 0;
37
+ const ts = __importStar(require("typescript"));
38
+ function containsThrowOrReject(node) {
39
+ if (ts.isThrowStatement(node))
40
+ return true;
41
+ if (ts.isCallExpression(node) &&
42
+ ts.isIdentifier(node.expression) &&
43
+ node.expression.text === 'reject') {
44
+ return true;
45
+ }
46
+ let found = false;
47
+ ts.forEachChild(node, child => {
48
+ if (!found)
49
+ found = containsThrowOrReject(child);
50
+ });
51
+ return found;
52
+ }
53
+ function getLineAndCol(sf, pos) {
54
+ const lc = sf.getLineAndCharacterOfPosition(pos);
55
+ return { line: lc.line + 1, column: lc.character + 1 };
56
+ }
57
+ function getEvidenceLines(sourceText, line, extra = 1) {
58
+ const lines = sourceText.split('\n');
59
+ const start = line - 1;
60
+ const end = Math.min(start + extra, lines.length);
61
+ return lines
62
+ .slice(start, end)
63
+ .map(l => l.slice(0, 120))
64
+ .join('\n');
65
+ }
66
+ class SR001SwallowedAsyncRejection {
67
+ id = 'SR001';
68
+ name = 'Swallowed async rejection';
69
+ policyRef = 'P005';
70
+ severity = 'BLOCKING';
71
+ languages = ['typescript', 'javascript'];
72
+ description = '.catch() callbacks that do not contain a throw statement or a call to reject() silently absorb errors.';
73
+ check(filePath, sourceText) {
74
+ try {
75
+ const violations = [];
76
+ const ext = filePath.endsWith('.tsx')
77
+ ? ts.ScriptKind.TSX
78
+ : filePath.endsWith('.jsx')
79
+ ? ts.ScriptKind.JSX
80
+ : filePath.endsWith('.js')
81
+ ? ts.ScriptKind.JS
82
+ : ts.ScriptKind.TS;
83
+ const sf = ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true, ext);
84
+ const visit = (node) => {
85
+ // Looking for: expr.catch(callback)
86
+ if (ts.isCallExpression(node) &&
87
+ ts.isPropertyAccessExpression(node.expression) &&
88
+ node.expression.name.text === 'catch') {
89
+ const args = node.arguments;
90
+ if (args.length !== 1) {
91
+ ts.forEachChild(node, visit);
92
+ return;
93
+ }
94
+ const callback = args[0];
95
+ // Exclude shorthand: .catch(console.error) or .catch(logger.error)
96
+ if (ts.isPropertyAccessExpression(callback) || ts.isIdentifier(callback)) {
97
+ ts.forEachChild(node, visit);
98
+ return;
99
+ }
100
+ // Must be arrow function or function expression
101
+ if (!ts.isArrowFunction(callback) && !ts.isFunctionExpression(callback)) {
102
+ ts.forEachChild(node, visit);
103
+ return;
104
+ }
105
+ const body = callback.body;
106
+ // Exclude empty body: .catch(() => {})
107
+ if (ts.isBlock(body) && body.statements.length === 0) {
108
+ ts.forEachChild(node, visit);
109
+ return;
110
+ }
111
+ // Check if body contains throw or reject
112
+ if (!containsThrowOrReject(body)) {
113
+ const { line, column } = getLineAndCol(sf, node.expression.name.getStart(sf));
114
+ const evidence = getEvidenceLines(sourceText, line, 2);
115
+ violations.push({
116
+ ruleId: this.id,
117
+ ruleName: this.name,
118
+ policyRef: this.policyRef,
119
+ severity: this.severity,
120
+ filePath,
121
+ line,
122
+ column,
123
+ evidence,
124
+ operationalRisk: 'Rejected promises are silently absorbed; errors never surface to callers or monitoring, ' +
125
+ 'leading to invisible failures and stale state in production.',
126
+ remediation: 'Add `throw err` (or re-wrap: `throw new Error(err.message)`) inside the .catch() body, ' +
127
+ 'or replace with `.catch(err => { logger.error(err); throw err; })`.',
128
+ determinism: 'deterministic-structural',
129
+ confidence: 0.92,
130
+ language: filePath.endsWith('.py') ? 'python' : filePath.match(/\.(js|jsx)$/) ? 'javascript' : 'typescript',
131
+ });
132
+ }
133
+ }
134
+ ts.forEachChild(node, visit);
135
+ };
136
+ ts.forEachChild(sf, visit);
137
+ return violations;
138
+ }
139
+ catch {
140
+ return [];
141
+ }
142
+ }
143
+ }
144
+ exports.SR001SwallowedAsyncRejection = SR001SwallowedAsyncRejection;
145
+ //# sourceMappingURL=SR001-swallowed-async-rejection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SR001-swallowed-async-rejection.js","sourceRoot":"","sources":["../../../src/structural-rules/rules/SR001-swallowed-async-rejection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { StructuralRule, StructuralViolation, RuleLanguage } from '../types';
2
+ export declare class SR002UnboundedCollection implements StructuralRule {
3
+ id: string;
4
+ name: string;
5
+ policyRef: string;
6
+ severity: "BLOCKING";
7
+ languages: RuleLanguage[];
8
+ description: string;
9
+ check(filePath: string, sourceText: string): StructuralViolation[];
10
+ }
11
+ //# sourceMappingURL=SR002-unbounded-collection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SR002-unbounded-collection.d.ts","sourceRoot":"","sources":["../../../src/structural-rules/rules/SR002-unbounded-collection.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AA2E7E,qBAAa,wBAAyB,YAAW,cAAc;IAC7D,EAAE,SAAW;IACb,IAAI,SAA0B;IAC9B,SAAS,SAAU;IACnB,QAAQ,EAAG,UAAU,CAAU;IAC/B,SAAS,EAAE,YAAY,EAAE,CAAgC;IACzD,WAAW,SAC+F;IAE1G,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,mBAAmB,EAAE;CAoGnE"}