torusguard 1.0.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (411) hide show
  1. package/.torusguard/.manifest.json +196 -78
  2. package/.torusguard/references/csharp-security.md +41 -0
  3. package/.torusguard/references/go-security.md +41 -0
  4. package/.torusguard/references/java-security.md +40 -0
  5. package/.torusguard/references/polyglot-security-matrix.md +25 -0
  6. package/.torusguard/references/rust-security.md +40 -0
  7. package/.torusguard/rules/README.md +93 -62
  8. package/.torusguard/rules/TG-AUTH-001-weak-password-storage.md +103 -0
  9. package/.torusguard/rules/TG-AUTH-002-client-only-authorization.md +85 -0
  10. package/.torusguard/rules/TG-AUTH-003-missing-object-authorization.md +85 -0
  11. package/.torusguard/rules/TG-AUTH-004-insecure-session-cookie.md +96 -0
  12. package/.torusguard/rules/TG-AUTH-005-unsafe-password-reset.md +104 -0
  13. package/.torusguard/rules/TG-CLIENT-001-public-production-source-maps.md +102 -0
  14. package/.torusguard/rules/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
  15. package/.torusguard/rules/TG-DB-001-frontend-database-query.md +83 -0
  16. package/.torusguard/rules/TG-DB-002-privileged-database-credential.md +86 -0
  17. package/.torusguard/rules/TG-DB-003-frontend-admin-sdk.md +91 -0
  18. package/.torusguard/rules/TG-DB-004-missing-tenant-query-isolation.md +103 -0
  19. package/.torusguard/rules/TG-INPUT-001-missing-server-validation.md +98 -0
  20. package/.torusguard/rules/TG-INPUT-002-raw-sql-concatenation.md +94 -0
  21. package/.torusguard/rules/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
  22. package/.torusguard/rules/TG-INPUT-004-unrestricted-file-upload.md +92 -0
  23. package/.torusguard/rules/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
  24. package/.torusguard/rules/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
  25. package/.torusguard/rules/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
  26. package/.torusguard/rules/TG-PLATFORM-002-missing-security-headers.md +95 -0
  27. package/.torusguard/rules/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
  28. package/.torusguard/rules/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
  29. package/.torusguard/rules/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
  30. package/.torusguard/rules/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
  31. package/.torusguard/rules/TG-RATE-003-unbounded-resource-consumption.md +105 -0
  32. package/.torusguard/rules/TG-SEC-001-hardcoded-secrets.md +83 -0
  33. package/.torusguard/rules/TG-SEC-002-public-environment-secrets.md +83 -0
  34. package/.torusguard/rules/TG-SEC-003-tracked-env-file.md +79 -0
  35. package/.torusguard/rules/TG-SEC-004-sensitive-logging.md +83 -0
  36. package/.torusguard/rules/active/TG-AUTH-001-weak-password-storage.md +103 -0
  37. package/.torusguard/rules/active/TG-AUTH-002-client-only-authorization.md +85 -0
  38. package/.torusguard/rules/active/TG-AUTH-003-missing-object-authorization.md +85 -0
  39. package/.torusguard/rules/active/TG-AUTH-004-insecure-session-cookie.md +96 -0
  40. package/.torusguard/rules/active/TG-AUTH-005-unsafe-password-reset.md +104 -0
  41. package/.torusguard/rules/active/TG-CLIENT-001-public-production-source-maps.md +102 -0
  42. package/.torusguard/rules/active/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
  43. package/.torusguard/rules/active/TG-DB-001-frontend-database-query.md +83 -0
  44. package/.torusguard/rules/active/TG-DB-002-privileged-database-credential.md +86 -0
  45. package/.torusguard/rules/active/TG-DB-003-frontend-admin-sdk.md +91 -0
  46. package/.torusguard/rules/active/TG-DB-004-missing-tenant-query-isolation.md +103 -0
  47. package/.torusguard/rules/active/TG-INPUT-001-missing-server-validation.md +98 -0
  48. package/.torusguard/rules/active/TG-INPUT-002-raw-sql-concatenation.md +94 -0
  49. package/.torusguard/rules/active/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
  50. package/.torusguard/rules/active/TG-INPUT-004-unrestricted-file-upload.md +92 -0
  51. package/.torusguard/rules/active/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
  52. package/.torusguard/rules/active/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
  53. package/.torusguard/rules/active/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
  54. package/.torusguard/rules/active/TG-PLATFORM-002-missing-security-headers.md +95 -0
  55. package/.torusguard/rules/active/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
  56. package/.torusguard/rules/active/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
  57. package/.torusguard/rules/active/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
  58. package/.torusguard/rules/active/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
  59. package/.torusguard/rules/active/TG-RATE-003-unbounded-resource-consumption.md +105 -0
  60. package/.torusguard/rules/active/TG-SEC-001-hardcoded-secrets.md +83 -0
  61. package/.torusguard/rules/active/TG-SEC-002-public-environment-secrets.md +83 -0
  62. package/.torusguard/rules/active/TG-SEC-003-tracked-env-file.md +79 -0
  63. package/.torusguard/rules/active/TG-SEC-004-sensitive-logging.md +83 -0
  64. package/.torusguard/rules/agent/TG-AGENT-001-prompt-injection-system-context.md +56 -0
  65. package/.torusguard/rules/agent/TG-AGENT-002-unsafe-tool-dispatch-unsandboxed-execution.md +68 -0
  66. package/.torusguard/rules/agent/TG-AGENT-003-broad-mcp-tool-scoping.md +53 -0
  67. package/.torusguard/rules/agent/TG-AGENT-004-persistent-memory-cross-session-leakage.md +67 -0
  68. package/.torusguard/rules/authorization/TG-AUTH-006-mass-assignment.md +70 -0
  69. package/.torusguard/rules/authorization/TG-AUTH-007-missing-property-level-authorization.md +71 -0
  70. package/.torusguard/rules/authorization/TG-AUTH-008-untrusted-role-header-injection.md +112 -0
  71. package/.torusguard/rules/business-logic/TG-BIZ-001-client-controlled-sensitive-business-value.md +37 -0
  72. package/.torusguard/rules/business-logic/TG-BIZ-002-replayable-one-time-operation.md +37 -0
  73. package/.torusguard/rules/business-logic/TG-BIZ-003-missing-workflow-state-validation.md +37 -0
  74. package/.torusguard/rules/business-logic/TG-BIZ-004-unrestricted-sensitive-business-flow.md +37 -0
  75. package/.torusguard/rules/cache/TG-CACHE-001-sensitive-response-publicly-cacheable.md +37 -0
  76. package/.torusguard/rules/cache/TG-CACHE-002-missing-user-cache-isolation.md +37 -0
  77. package/.torusguard/rules/cache/TG-CACHE-003-sensitive-data-in-url.md +37 -0
  78. package/.torusguard/rules/csrf/TG-CSRF-001-missing-csrf-protection.md +37 -0
  79. package/.torusguard/rules/csrf/TG-CSRF-002-unsafe-credentialed-cross-origin-request.md +37 -0
  80. package/.torusguard/rules/custom/.gitkeep +1 -0
  81. package/.torusguard/rules/custom/README.md +30 -0
  82. package/.torusguard/rules/edge/TG-EDGE-001-serverless-global-state-leak.md +83 -0
  83. package/.torusguard/rules/edge/TG-EDGE-003-aws-lambda-ephemeral-cold-start.md +76 -0
  84. package/.torusguard/rules/graphql/TG-GQL-001-missing-query-depth-or-complexity-limits.md +64 -0
  85. package/.torusguard/rules/graphql/TG-GQL-002-resolver-missing-authorization.md +37 -0
  86. package/.torusguard/rules/graphql/TG-GQL-003-unbounded-graphql-pagination-or-batching.md +37 -0
  87. package/.torusguard/rules/graphql/TG-GQL-004-unnecessary-production-introspection.md +37 -0
  88. package/.torusguard/rules/secrets/TG-SEC-005-secret-in-git-history.md +37 -0
  89. package/.torusguard/rules/secrets/TG-SEC-006-secret-in-build-artifact.md +37 -0
  90. package/.torusguard/rules/secrets/TG-SEC-007-secret-in-test-or-example-fixture.md +37 -0
  91. package/.torusguard/rules/ssrf/TG-SSRF-001-user-controlled-server-side-url-fetch.md +68 -0
  92. package/.torusguard/rules/ssrf/TG-SSRF-002-missing-internal-network-protection.md +37 -0
  93. package/.torusguard/rules/ssrf/TG-SSRF-003-unsafe-redirect-following.md +37 -0
  94. package/.torusguard/rules/ssrf/TG-SSRF-004-unbounded-outbound-request.md +37 -0
  95. package/.torusguard/rules/supply-chain/TG-SUPPLY-001-missing-or-ignored-dependency-lockfile.md +37 -0
  96. package/.torusguard/rules/supply-chain/TG-SUPPLY-002-vulnerable-dependency-review-missing.md +94 -0
  97. package/.torusguard/rules/supply-chain/TG-SUPPLY-003-unsafe-ci-cd-secret-exposure.md +37 -0
  98. package/.torusguard/rules/supply-chain/TG-SUPPLY-004-unpinned-ci-action.md +37 -0
  99. package/.torusguard/rules/supply-chain/TG-SUPPLY-005-unsafe-dependency-install-script.md +37 -0
  100. package/.torusguard/rules/supply-chain/TG-SUPPLY-006-container-build-secret-persistence.md +61 -0
  101. package/.torusguard/rules/webhook/TG-WEBHOOK-001-missing-webhook-signature-verification.md +37 -0
  102. package/.torusguard/rules/webhook/TG-WEBHOOK-002-replayable-webhook.md +37 -0
  103. package/.torusguard/rules/webhook/TG-WEBHOOK-003-missing-webhook-idempotency.md +37 -0
  104. package/.torusguard/rules/webhook/TG-WEBHOOK-004-unvalidated-webhook-event-type.md +37 -0
  105. package/.torusguard/rules/websocket/TG-WS-001-unauthenticated-websocket-handshake.md +82 -0
  106. package/.torusguard/rules/websocket/TG-WS-002-missing-channel-level-authorization.md +37 -0
  107. package/.torusguard/rules/websocket/TG-WS-003-unvalidated-websocket-message.md +37 -0
  108. package/.torusguard/rules/websocket/TG-WS-004-unbounded-websocket-connections.md +37 -0
  109. package/.torusguard/runs/report-latest.html +370 -0
  110. package/.torusguard/runs/run-20260908-112648-audit/findings.json +1520 -0
  111. package/.torusguard/runs/run-20260908-112648-audit/findings.md +560 -0
  112. package/.torusguard/runs/run-20260908-112648-audit/manifest.json +12 -0
  113. package/.torusguard/runs/run-20260908-112648-audit/summary.md +5 -0
  114. package/.torusguard/runs/run-20260908-112722-audit/findings.json +1520 -0
  115. package/.torusguard/runs/run-20260908-112722-audit/findings.md +560 -0
  116. package/.torusguard/runs/run-20260908-112722-audit/manifest.json +12 -0
  117. package/.torusguard/runs/run-20260908-112722-audit/summary.md +5 -0
  118. package/.torusguard/runs/run-20260908-113004-audit/findings.json +1520 -0
  119. package/.torusguard/runs/run-20260908-113004-audit/findings.md +560 -0
  120. package/.torusguard/runs/run-20260908-113004-audit/manifest.json +12 -0
  121. package/.torusguard/runs/run-20260908-113004-audit/summary.md +5 -0
  122. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-115-9a059e/metadata.json +15 -0
  123. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-115-9a059e/minimal_patch_plan.md +21 -0
  124. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-115-9a059e/patch.diff +9 -0
  125. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-119-61557c/metadata.json +15 -0
  126. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-119-61557c/minimal_patch_plan.md +21 -0
  127. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-119-61557c/patch.diff +9 -0
  128. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-265-996ca3/metadata.json +15 -0
  129. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-265-996ca3/minimal_patch_plan.md +21 -0
  130. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-265-996ca3/patch.diff +9 -0
  131. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-334-cb819d/metadata.json +15 -0
  132. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-334-cb819d/minimal_patch_plan.md +21 -0
  133. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-334-cb819d/patch.diff +9 -0
  134. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-503-d11cf8/metadata.json +15 -0
  135. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-503-d11cf8/minimal_patch_plan.md +21 -0
  136. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-503-d11cf8/patch.diff +9 -0
  137. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-79-91f41f/metadata.json +15 -0
  138. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-79-91f41f/minimal_patch_plan.md +21 -0
  139. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-79-91f41f/patch.diff +9 -0
  140. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-107-516a40/metadata.json +15 -0
  141. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-107-516a40/minimal_patch_plan.md +21 -0
  142. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-107-516a40/patch.diff +9 -0
  143. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-128-7809a1/metadata.json +15 -0
  144. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-128-7809a1/minimal_patch_plan.md +21 -0
  145. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-128-7809a1/patch.diff +9 -0
  146. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-232-1b45d1/metadata.json +15 -0
  147. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-232-1b45d1/minimal_patch_plan.md +21 -0
  148. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-232-1b45d1/patch.diff +9 -0
  149. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-003-53-d167b4/metadata.json +15 -0
  150. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-003-53-d167b4/minimal_patch_plan.md +21 -0
  151. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-003-53-d167b4/patch.diff +9 -0
  152. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-209-4f6424/metadata.json +15 -0
  153. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-209-4f6424/minimal_patch_plan.md +21 -0
  154. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-209-4f6424/patch.diff +9 -0
  155. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-257-89bf34/metadata.json +15 -0
  156. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-257-89bf34/minimal_patch_plan.md +21 -0
  157. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-257-89bf34/patch.diff +9 -0
  158. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-341-ce228c/metadata.json +15 -0
  159. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-341-ce228c/minimal_patch_plan.md +21 -0
  160. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-341-ce228c/patch.diff +9 -0
  161. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-355-7b190b/metadata.json +15 -0
  162. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-355-7b190b/minimal_patch_plan.md +21 -0
  163. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-355-7b190b/patch.diff +9 -0
  164. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-64-5af31a/metadata.json +15 -0
  165. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-64-5af31a/minimal_patch_plan.md +21 -0
  166. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-64-5af31a/patch.diff +9 -0
  167. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-9-f51467/metadata.json +15 -0
  168. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-9-f51467/minimal_patch_plan.md +21 -0
  169. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-9-f51467/patch.diff +9 -0
  170. package/.torusguard/runs/run-20260908-113127-audit/findings.json +1520 -0
  171. package/.torusguard/runs/run-20260908-113127-audit/findings.md +560 -0
  172. package/.torusguard/runs/run-20260908-113127-audit/manifest.json +13 -0
  173. package/.torusguard/runs/run-20260908-113127-audit/remediation.md +262 -0
  174. package/.torusguard/runs/run-20260908-113127-audit/summary.md +5 -0
  175. package/.torusguard/runs/run-20260908-115240-audit/apply_plan.md +6 -0
  176. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-115-9a059e/metadata.json +15 -0
  177. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-115-9a059e/minimal_patch_plan.md +21 -0
  178. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-115-9a059e/patch.diff +9 -0
  179. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-119-61557c/metadata.json +15 -0
  180. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-119-61557c/minimal_patch_plan.md +21 -0
  181. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-119-61557c/patch.diff +9 -0
  182. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-265-996ca3/metadata.json +15 -0
  183. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-265-996ca3/minimal_patch_plan.md +21 -0
  184. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-265-996ca3/patch.diff +9 -0
  185. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-334-cb819d/metadata.json +15 -0
  186. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-334-cb819d/minimal_patch_plan.md +21 -0
  187. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-334-cb819d/patch.diff +9 -0
  188. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-503-d11cf8/metadata.json +15 -0
  189. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-503-d11cf8/minimal_patch_plan.md +21 -0
  190. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-503-d11cf8/patch.diff +9 -0
  191. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-79-91f41f/metadata.json +15 -0
  192. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-79-91f41f/minimal_patch_plan.md +21 -0
  193. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-79-91f41f/patch.diff +9 -0
  194. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-107-516a40/metadata.json +15 -0
  195. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-107-516a40/minimal_patch_plan.md +21 -0
  196. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-107-516a40/patch.diff +9 -0
  197. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-128-7809a1/metadata.json +15 -0
  198. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-128-7809a1/minimal_patch_plan.md +21 -0
  199. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-128-7809a1/patch.diff +9 -0
  200. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-232-1b45d1/metadata.json +15 -0
  201. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-232-1b45d1/minimal_patch_plan.md +21 -0
  202. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-232-1b45d1/patch.diff +9 -0
  203. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-003-53-d167b4/metadata.json +15 -0
  204. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-003-53-d167b4/minimal_patch_plan.md +21 -0
  205. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-003-53-d167b4/patch.diff +9 -0
  206. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-platform-001-168-5027cb/metadata.json +15 -0
  207. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-platform-001-168-5027cb/minimal_patch_plan.md +21 -0
  208. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-platform-001-168-5027cb/patch.diff +9 -0
  209. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-209-4f6424/metadata.json +15 -0
  210. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-209-4f6424/minimal_patch_plan.md +21 -0
  211. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-209-4f6424/patch.diff +9 -0
  212. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-257-89bf34/metadata.json +15 -0
  213. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-257-89bf34/minimal_patch_plan.md +21 -0
  214. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-257-89bf34/patch.diff +9 -0
  215. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-341-ce228c/metadata.json +15 -0
  216. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-341-ce228c/minimal_patch_plan.md +21 -0
  217. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-341-ce228c/patch.diff +9 -0
  218. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-355-7b190b/metadata.json +15 -0
  219. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-355-7b190b/minimal_patch_plan.md +21 -0
  220. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-355-7b190b/patch.diff +9 -0
  221. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-64-5af31a/metadata.json +15 -0
  222. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-64-5af31a/minimal_patch_plan.md +21 -0
  223. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-64-5af31a/patch.diff +9 -0
  224. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-9-f51467/metadata.json +15 -0
  225. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-9-f51467/minimal_patch_plan.md +21 -0
  226. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-9-f51467/patch.diff +9 -0
  227. package/.torusguard/runs/run-20260908-115240-audit/diff_summary.md +221 -0
  228. package/.torusguard/runs/run-20260908-115240-audit/findings.json +1553 -0
  229. package/.torusguard/runs/run-20260908-115240-audit/findings.md +572 -0
  230. package/.torusguard/runs/run-20260908-115240-audit/manifest.json +14 -0
  231. package/.torusguard/runs/run-20260908-115240-audit/recheck.md +91 -0
  232. package/.torusguard/runs/run-20260908-115240-audit/remediation.md +278 -0
  233. package/.torusguard/runs/run-20260908-115240-audit/summary.md +5 -0
  234. package/.torusguard/schemas/golden-recipe.schema.json +75 -0
  235. package/.torusguard/scripts/__pycache__/audit_runner.cpython-311.pyc +0 -0
  236. package/.torusguard/scripts/__pycache__/finding_scorer.cpython-311.pyc +0 -0
  237. package/.torusguard/scripts/__pycache__/memory_engine.cpython-311.pyc +0 -0
  238. package/.torusguard/scripts/__pycache__/monorepo_detector.cpython-311.pyc +0 -0
  239. package/.torusguard/scripts/__pycache__/run_manager.cpython-311.pyc +0 -0
  240. package/.torusguard/scripts/__pycache__/stack_detect.cpython-311.pyc +0 -0
  241. package/.torusguard/scripts/apply_runner.py +332 -0
  242. package/.torusguard/scripts/audit_runner.py +550 -0
  243. package/.torusguard/scripts/diff_guard.py +183 -8
  244. package/.torusguard/scripts/finding_scorer.py +91 -5
  245. package/.torusguard/scripts/harden_runner.py +353 -0
  246. package/.torusguard/scripts/html_reporter.py +643 -0
  247. package/.torusguard/scripts/manifest_builder.py +7 -5
  248. package/.torusguard/scripts/memory_engine.py +525 -99
  249. package/.torusguard/scripts/monorepo_detector.py +123 -10
  250. package/.torusguard/scripts/recheck_runner.py +221 -0
  251. package/.torusguard/scripts/recipes_runner.py +130 -0
  252. package/.torusguard/scripts/rules_sync.py +321 -0
  253. package/.torusguard/scripts/run_manager.py +17 -5
  254. package/.torusguard/scripts/stack_detect.py +458 -26
  255. package/.torusguard/skills/torusguard/SKILL.md +42 -42
  256. package/.torusguard/skills/torusguard/references/csharp-security.md +41 -0
  257. package/.torusguard/skills/torusguard/references/go-security.md +41 -0
  258. package/.torusguard/skills/torusguard/references/java-security.md +40 -0
  259. package/.torusguard/skills/torusguard/references/polyglot-security-matrix.md +25 -0
  260. package/.torusguard/skills/torusguard/references/rust-security.md +40 -0
  261. package/.torusguard/snapshots/run-20260908-115240-audit/examples/vulnerable-react-express/client/src/App.jsx.bak +63 -0
  262. package/.torusguard/snapshots/run-20260908-115240-audit/examples/vulnerable-react-express/server/index.js.bak +82 -0
  263. package/.torusguard/snapshots/run-20260908-115240-audit/harness/engine/fixture_manager.py.bak +245 -0
  264. package/.torusguard/snapshots/run-20260908-115240-audit/harness/master_validation.py.bak +698 -0
  265. package/.torusguard/snapshots/run-20260908-115240-audit/harness/runner.py.bak +551 -0
  266. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_e2e.py.bak +498 -0
  267. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_qa_v0_6_0.py.bak +572 -0
  268. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v0_6_1_scale.py.bak +371 -0
  269. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v0_6_2_modern_stacks.py.bak +462 -0
  270. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v0_6_3_hardening.py.bak +444 -0
  271. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v1_0_0_memory.py.bak +302 -0
  272. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v1_1_0_advanced_memory.py.bak +342 -0
  273. package/.torusguard/snapshots/run-20260908-115240-audit/skills/torusguard/payload/scripts/harden_runner.py.bak +353 -0
  274. package/.torusguard/snapshots/run-20260908-115240-audit/tests/test_v0_6_0_governed_remediation.py.bak +353 -0
  275. package/README.md +344 -410
  276. package/bin/torusguard.js +195 -21
  277. package/package.json +1 -1
  278. package/skills/torusguard/SKILL.md +42 -42
  279. package/skills/torusguard/bootstrap.py +149 -70
  280. package/skills/torusguard/payload/.manifest.json +196 -78
  281. package/skills/torusguard/payload/references/csharp-security.md +41 -0
  282. package/skills/torusguard/payload/references/go-security.md +41 -0
  283. package/skills/torusguard/payload/references/java-security.md +40 -0
  284. package/skills/torusguard/payload/references/polyglot-security-matrix.md +25 -0
  285. package/skills/torusguard/payload/references/rust-security.md +40 -0
  286. package/skills/torusguard/payload/rules/README.md +93 -62
  287. package/skills/torusguard/payload/rules/TG-AUTH-001-weak-password-storage.md +103 -0
  288. package/skills/torusguard/payload/rules/TG-AUTH-002-client-only-authorization.md +85 -0
  289. package/skills/torusguard/payload/rules/TG-AUTH-003-missing-object-authorization.md +85 -0
  290. package/skills/torusguard/payload/rules/TG-AUTH-004-insecure-session-cookie.md +96 -0
  291. package/skills/torusguard/payload/rules/TG-AUTH-005-unsafe-password-reset.md +104 -0
  292. package/skills/torusguard/payload/rules/TG-CLIENT-001-public-production-source-maps.md +102 -0
  293. package/skills/torusguard/payload/rules/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
  294. package/skills/torusguard/payload/rules/TG-DB-001-frontend-database-query.md +83 -0
  295. package/skills/torusguard/payload/rules/TG-DB-002-privileged-database-credential.md +86 -0
  296. package/skills/torusguard/payload/rules/TG-DB-003-frontend-admin-sdk.md +91 -0
  297. package/skills/torusguard/payload/rules/TG-DB-004-missing-tenant-query-isolation.md +103 -0
  298. package/skills/torusguard/payload/rules/TG-INPUT-001-missing-server-validation.md +98 -0
  299. package/skills/torusguard/payload/rules/TG-INPUT-002-raw-sql-concatenation.md +94 -0
  300. package/skills/torusguard/payload/rules/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
  301. package/skills/torusguard/payload/rules/TG-INPUT-004-unrestricted-file-upload.md +92 -0
  302. package/skills/torusguard/payload/rules/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
  303. package/skills/torusguard/payload/rules/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
  304. package/skills/torusguard/payload/rules/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
  305. package/skills/torusguard/payload/rules/TG-PLATFORM-002-missing-security-headers.md +95 -0
  306. package/skills/torusguard/payload/rules/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
  307. package/skills/torusguard/payload/rules/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
  308. package/skills/torusguard/payload/rules/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
  309. package/skills/torusguard/payload/rules/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
  310. package/skills/torusguard/payload/rules/TG-RATE-003-unbounded-resource-consumption.md +105 -0
  311. package/skills/torusguard/payload/rules/TG-SEC-001-hardcoded-secrets.md +83 -0
  312. package/skills/torusguard/payload/rules/TG-SEC-002-public-environment-secrets.md +83 -0
  313. package/skills/torusguard/payload/rules/TG-SEC-003-tracked-env-file.md +79 -0
  314. package/skills/torusguard/payload/rules/TG-SEC-004-sensitive-logging.md +83 -0
  315. package/skills/torusguard/payload/rules/active/TG-AUTH-001-weak-password-storage.md +103 -0
  316. package/skills/torusguard/payload/rules/active/TG-AUTH-002-client-only-authorization.md +85 -0
  317. package/skills/torusguard/payload/rules/active/TG-AUTH-003-missing-object-authorization.md +85 -0
  318. package/skills/torusguard/payload/rules/active/TG-AUTH-004-insecure-session-cookie.md +96 -0
  319. package/skills/torusguard/payload/rules/active/TG-AUTH-005-unsafe-password-reset.md +104 -0
  320. package/skills/torusguard/payload/rules/active/TG-CLIENT-001-public-production-source-maps.md +102 -0
  321. package/skills/torusguard/payload/rules/active/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
  322. package/skills/torusguard/payload/rules/active/TG-DB-001-frontend-database-query.md +83 -0
  323. package/skills/torusguard/payload/rules/active/TG-DB-002-privileged-database-credential.md +86 -0
  324. package/skills/torusguard/payload/rules/active/TG-DB-003-frontend-admin-sdk.md +91 -0
  325. package/skills/torusguard/payload/rules/active/TG-DB-004-missing-tenant-query-isolation.md +103 -0
  326. package/skills/torusguard/payload/rules/active/TG-INPUT-001-missing-server-validation.md +98 -0
  327. package/skills/torusguard/payload/rules/active/TG-INPUT-002-raw-sql-concatenation.md +94 -0
  328. package/skills/torusguard/payload/rules/active/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
  329. package/skills/torusguard/payload/rules/active/TG-INPUT-004-unrestricted-file-upload.md +92 -0
  330. package/skills/torusguard/payload/rules/active/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
  331. package/skills/torusguard/payload/rules/active/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
  332. package/skills/torusguard/payload/rules/active/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
  333. package/skills/torusguard/payload/rules/active/TG-PLATFORM-002-missing-security-headers.md +95 -0
  334. package/skills/torusguard/payload/rules/active/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
  335. package/skills/torusguard/payload/rules/active/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
  336. package/skills/torusguard/payload/rules/active/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
  337. package/skills/torusguard/payload/rules/active/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
  338. package/skills/torusguard/payload/rules/active/TG-RATE-003-unbounded-resource-consumption.md +105 -0
  339. package/skills/torusguard/payload/rules/active/TG-SEC-001-hardcoded-secrets.md +83 -0
  340. package/skills/torusguard/payload/rules/active/TG-SEC-002-public-environment-secrets.md +83 -0
  341. package/skills/torusguard/payload/rules/active/TG-SEC-003-tracked-env-file.md +79 -0
  342. package/skills/torusguard/payload/rules/active/TG-SEC-004-sensitive-logging.md +83 -0
  343. package/skills/torusguard/payload/rules/agent/TG-AGENT-001-prompt-injection-system-context.md +56 -0
  344. package/skills/torusguard/payload/rules/agent/TG-AGENT-002-unsafe-tool-dispatch-unsandboxed-execution.md +68 -0
  345. package/skills/torusguard/payload/rules/agent/TG-AGENT-003-broad-mcp-tool-scoping.md +53 -0
  346. package/skills/torusguard/payload/rules/agent/TG-AGENT-004-persistent-memory-cross-session-leakage.md +67 -0
  347. package/skills/torusguard/payload/rules/authorization/TG-AUTH-006-mass-assignment.md +70 -0
  348. package/skills/torusguard/payload/rules/authorization/TG-AUTH-007-missing-property-level-authorization.md +71 -0
  349. package/skills/torusguard/payload/rules/authorization/TG-AUTH-008-untrusted-role-header-injection.md +112 -0
  350. package/skills/torusguard/payload/rules/business-logic/TG-BIZ-001-client-controlled-sensitive-business-value.md +37 -0
  351. package/skills/torusguard/payload/rules/business-logic/TG-BIZ-002-replayable-one-time-operation.md +37 -0
  352. package/skills/torusguard/payload/rules/business-logic/TG-BIZ-003-missing-workflow-state-validation.md +37 -0
  353. package/skills/torusguard/payload/rules/business-logic/TG-BIZ-004-unrestricted-sensitive-business-flow.md +37 -0
  354. package/skills/torusguard/payload/rules/cache/TG-CACHE-001-sensitive-response-publicly-cacheable.md +37 -0
  355. package/skills/torusguard/payload/rules/cache/TG-CACHE-002-missing-user-cache-isolation.md +37 -0
  356. package/skills/torusguard/payload/rules/cache/TG-CACHE-003-sensitive-data-in-url.md +37 -0
  357. package/skills/torusguard/payload/rules/csrf/TG-CSRF-001-missing-csrf-protection.md +37 -0
  358. package/skills/torusguard/payload/rules/csrf/TG-CSRF-002-unsafe-credentialed-cross-origin-request.md +37 -0
  359. package/skills/torusguard/payload/rules/custom/.gitkeep +1 -0
  360. package/skills/torusguard/payload/rules/custom/README.md +30 -0
  361. package/skills/torusguard/payload/rules/edge/TG-EDGE-001-serverless-global-state-leak.md +83 -0
  362. package/skills/torusguard/payload/rules/edge/TG-EDGE-003-aws-lambda-ephemeral-cold-start.md +76 -0
  363. package/skills/torusguard/payload/rules/graphql/TG-GQL-001-missing-query-depth-or-complexity-limits.md +64 -0
  364. package/skills/torusguard/payload/rules/graphql/TG-GQL-002-resolver-missing-authorization.md +37 -0
  365. package/skills/torusguard/payload/rules/graphql/TG-GQL-003-unbounded-graphql-pagination-or-batching.md +37 -0
  366. package/skills/torusguard/payload/rules/graphql/TG-GQL-004-unnecessary-production-introspection.md +37 -0
  367. package/skills/torusguard/payload/rules/secrets/TG-SEC-005-secret-in-git-history.md +37 -0
  368. package/skills/torusguard/payload/rules/secrets/TG-SEC-006-secret-in-build-artifact.md +37 -0
  369. package/skills/torusguard/payload/rules/secrets/TG-SEC-007-secret-in-test-or-example-fixture.md +37 -0
  370. package/skills/torusguard/payload/rules/ssrf/TG-SSRF-001-user-controlled-server-side-url-fetch.md +68 -0
  371. package/skills/torusguard/payload/rules/ssrf/TG-SSRF-002-missing-internal-network-protection.md +37 -0
  372. package/skills/torusguard/payload/rules/ssrf/TG-SSRF-003-unsafe-redirect-following.md +37 -0
  373. package/skills/torusguard/payload/rules/ssrf/TG-SSRF-004-unbounded-outbound-request.md +37 -0
  374. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-001-missing-or-ignored-dependency-lockfile.md +37 -0
  375. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-002-vulnerable-dependency-review-missing.md +94 -0
  376. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-003-unsafe-ci-cd-secret-exposure.md +37 -0
  377. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-004-unpinned-ci-action.md +37 -0
  378. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-005-unsafe-dependency-install-script.md +37 -0
  379. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-006-container-build-secret-persistence.md +61 -0
  380. package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-001-missing-webhook-signature-verification.md +37 -0
  381. package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-002-replayable-webhook.md +37 -0
  382. package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-003-missing-webhook-idempotency.md +37 -0
  383. package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-004-unvalidated-webhook-event-type.md +37 -0
  384. package/skills/torusguard/payload/rules/websocket/TG-WS-001-unauthenticated-websocket-handshake.md +82 -0
  385. package/skills/torusguard/payload/rules/websocket/TG-WS-002-missing-channel-level-authorization.md +37 -0
  386. package/skills/torusguard/payload/rules/websocket/TG-WS-003-unvalidated-websocket-message.md +37 -0
  387. package/skills/torusguard/payload/rules/websocket/TG-WS-004-unbounded-websocket-connections.md +37 -0
  388. package/skills/torusguard/payload/schemas/golden-recipe.schema.json +75 -0
  389. package/skills/torusguard/payload/scripts/apply_runner.py +332 -0
  390. package/skills/torusguard/payload/scripts/audit_runner.py +550 -0
  391. package/skills/torusguard/payload/scripts/diff_guard.py +183 -8
  392. package/skills/torusguard/payload/scripts/finding_scorer.py +91 -5
  393. package/skills/torusguard/payload/scripts/harden_runner.py +353 -0
  394. package/skills/torusguard/payload/scripts/html_reporter.py +643 -0
  395. package/skills/torusguard/payload/scripts/manifest_builder.py +7 -5
  396. package/skills/torusguard/payload/scripts/memory_engine.py +525 -99
  397. package/skills/torusguard/payload/scripts/monorepo_detector.py +123 -10
  398. package/skills/torusguard/payload/scripts/recheck_runner.py +221 -0
  399. package/skills/torusguard/payload/scripts/recipes_runner.py +130 -0
  400. package/skills/torusguard/payload/scripts/rules_sync.py +321 -0
  401. package/skills/torusguard/payload/scripts/run_manager.py +17 -5
  402. package/skills/torusguard/payload/scripts/stack_detect.py +458 -26
  403. package/skills/torusguard/payload/skills/torusguard/SKILL.md +42 -42
  404. package/skills/torusguard/payload/skills/torusguard/bootstrap.py +149 -70
  405. package/skills/torusguard/payload/skills/torusguard/references/csharp-security.md +41 -0
  406. package/skills/torusguard/payload/skills/torusguard/references/go-security.md +41 -0
  407. package/skills/torusguard/payload/skills/torusguard/references/java-security.md +40 -0
  408. package/skills/torusguard/payload/skills/torusguard/references/polyglot-security-matrix.md +25 -0
  409. package/skills/torusguard/payload/skills/torusguard/references/rust-security.md +40 -0
  410. package/.torusguard/scripts/__pycache__/diff_guard.cpython-311.pyc +0 -0
  411. package/skills/torusguard/__pycache__/bootstrap.cpython-311.pyc +0 -0
@@ -1,21 +1,132 @@
1
1
  #!/usr/bin/env python3
2
2
  """
3
- TorusGuard Stack Detector Utility
4
- Inspects project directory to detect programming language, frameworks, ORM/data layer,
5
- and dependency manifests. Outputs canonical stack block and structured JSON.
3
+ TorusGuard Universal Polyglot Stack Detector (v1.3.0)
4
+ Inspects project directory to detect programming language, framework, ORM/data layer,
5
+ and dependency manifests across 16+ languages, 30+ frameworks, and 20+ data layers.
6
+ Zero external dependencies (100% Python 3.10+ standard library).
6
7
  """
7
8
 
8
9
  import sys
9
10
  import json
10
11
  import argparse
11
12
  from pathlib import Path
12
- from typing import Dict, Any, List
13
+ from typing import Any
13
14
 
14
- def detect_stack(project_root: Path) -> Dict[str, Any]:
15
- profile = {
15
+ # Windows console UTF-8 support
16
+ if sys.stdout and hasattr(sys.stdout, "reconfigure"):
17
+ try:
18
+ getattr(sys.stdout, "reconfigure")(encoding="utf-8", errors="replace")
19
+ except (AttributeError, OSError):
20
+ pass
21
+ if sys.stderr and hasattr(sys.stderr, "reconfigure"):
22
+ try:
23
+ getattr(sys.stderr, "reconfigure")(encoding="utf-8", errors="replace")
24
+ except (AttributeError, OSError):
25
+ pass
26
+
27
+ # Comprehensive Manifest Catalog across 16+ Language Ecosystems
28
+ MANIFEST_CATALOG: dict[str, str] = {
29
+ # Python
30
+ "pyproject.toml": "Python",
31
+ "requirements.txt": "Python",
32
+ "Pipfile": "Python",
33
+ "poetry.lock": "Python",
34
+ "manage.py": "Python",
35
+ "setup.py": "Python",
36
+ # JavaScript / TypeScript
37
+ "package.json": "JavaScript / TypeScript",
38
+ "pnpm-lock.yaml": "JavaScript / TypeScript",
39
+ "yarn.lock": "JavaScript / TypeScript",
40
+ "bun.lockb": "JavaScript / TypeScript",
41
+ "deno.json": "JavaScript / TypeScript",
42
+ # Go
43
+ "go.mod": "Go",
44
+ "go.sum": "Go",
45
+ # Rust
46
+ "Cargo.toml": "Rust",
47
+ "Cargo.lock": "Rust",
48
+ # Java / Kotlin
49
+ "pom.xml": "Java",
50
+ "build.gradle": "Java / Kotlin",
51
+ "build.gradle.kts": "Kotlin",
52
+ "gradlew": "Java / Kotlin",
53
+ # C# / .NET
54
+ "global.json": "C# / .NET",
55
+ # PHP
56
+ "composer.json": "PHP",
57
+ "composer.lock": "PHP",
58
+ # Ruby
59
+ "Gemfile": "Ruby",
60
+ "Gemfile.lock": "Ruby",
61
+ # Elixir
62
+ "mix.exs": "Elixir",
63
+ "mix.lock": "Elixir",
64
+ # Dart / Flutter
65
+ "pubspec.yaml": "Dart / Flutter",
66
+ "pubspec.lock": "Dart / Flutter",
67
+ # C / C++
68
+ "CMakeLists.txt": "C / C++",
69
+ "Makefile": "C / C++",
70
+ "meson.build": "C / C++",
71
+ # Scala
72
+ "build.sbt": "Scala",
73
+ # Swift
74
+ "Package.swift": "Swift"
75
+ }
76
+
77
+ # Extension mappings for fallback file census
78
+ EXTENSION_MAP: dict[str, str] = {
79
+ ".py": "Python",
80
+ ".ts": "TypeScript",
81
+ ".tsx": "TypeScript",
82
+ ".js": "JavaScript",
83
+ ".jsx": "JavaScript",
84
+ ".go": "Go",
85
+ ".rs": "Rust",
86
+ ".java": "Java",
87
+ ".cs": "C#",
88
+ ".php": "PHP",
89
+ ".rb": "Ruby",
90
+ ".kt": "Kotlin",
91
+ ".kts": "Kotlin",
92
+ ".swift": "Swift",
93
+ ".dart": "Dart",
94
+ ".ex": "Elixir",
95
+ ".exs": "Elixir",
96
+ ".scala": "Scala",
97
+ ".c": "C",
98
+ ".cpp": "C++",
99
+ ".cc": "C++",
100
+ ".h": "C / C++",
101
+ ".hpp": "C++",
102
+ ".sh": "Shell / Bash",
103
+ ".sql": "SQL"
104
+ }
105
+
106
+
107
+ def census_file_extensions(project_root: Path) -> dict[str, int]:
108
+ """Tally source file extensions to infer primary languages when no manifest is present."""
109
+ census: dict[str, int] = {}
110
+ ignored_dirs = {".git", "node_modules", "vendor", ".venv", "venv", "dist", "build", ".torusguard", "target"}
111
+
112
+ for p in project_root.rglob("*"):
113
+ if p.is_file() and not any(part in ignored_dirs for part in p.parts):
114
+ ext = p.suffix.lower()
115
+ if ext in EXTENSION_MAP:
116
+ lang = EXTENSION_MAP[ext]
117
+ census[lang] = census.get(lang, 0) + 1
118
+ return census
119
+
120
+
121
+ def detect_stack(project_root: Path) -> dict[str, Any]:
122
+ """
123
+ Universally detect programming language, framework, ORM, and dependency manifests.
124
+ """
125
+ profile: dict[str, Any] = {
16
126
  "language": "Unknown",
17
127
  "framework": "None",
18
128
  "data_layer": "None",
129
+ "ecosystem_family": "universal",
19
130
  "dependency_files": [],
20
131
  "detection_evidence": [],
21
132
  "confidence": "Needs Review",
@@ -24,31 +135,47 @@ def detect_stack(project_root: Path) -> Dict[str, Any]:
24
135
  "TG-INPUT-*",
25
136
  "TG-AUTH-*"
26
137
  ],
27
- "recommended_references": []
138
+ "recommended_references": [
139
+ "polyglot-security-matrix.md"
140
+ ]
28
141
  }
29
142
 
30
- # 1. Inspect dependency manifests
31
- dep_candidates = ["pyproject.toml", "requirements.txt", "Pipfile", "package.json", "package-lock.json", "pnpm-lock.yaml"]
32
- for dc in dep_candidates:
33
- if (project_root / dc).is_file():
34
- profile["dependency_files"].append(dc)
143
+ # 1. Discover all dependency manifest files present
144
+ for manifest_name, lang in MANIFEST_CATALOG.items():
145
+ if (project_root / manifest_name).is_file():
146
+ profile["dependency_files"].append(manifest_name)
147
+
148
+ # Check for C# csproj/sln files (recursive)
149
+ csproj_files = list(project_root.glob("**/*.csproj"))
150
+ sln_files = list(project_root.glob("**/*.sln"))
151
+ for f in (csproj_files + sln_files)[:10]:
152
+ rel = str(f.relative_to(project_root))
153
+ if rel not in profile["dependency_files"]:
154
+ profile["dependency_files"].append(rel)
155
+
156
+ # 2. Inspect Ecosystems in order of specificity
35
157
 
36
- # 2. Check Python ecosystem
158
+ # -------------------------------------------------------------------------
159
+ # A. Python Ecosystem
160
+ # -------------------------------------------------------------------------
37
161
  manage_py = project_root / "manage.py"
38
162
  settings_py = list(project_root.glob("**/settings.py"))
39
-
163
+ has_py_manifest = any(f in profile["dependency_files"] for f in ["pyproject.toml", "requirements.txt", "Pipfile", "poetry.lock"])
164
+
40
165
  if manage_py.is_file() or settings_py:
41
166
  profile["language"] = "Python"
167
+ profile["ecosystem_family"] = "python"
42
168
  profile["framework"] = "Django"
43
169
  profile["data_layer"] = "Django ORM"
44
170
  profile["confidence"] = "Confirmed"
171
+ evidence_file = "manage.py" if manage_py.is_file() else str(settings_py[0].relative_to(project_root))
45
172
  profile["detection_evidence"].append({
46
- "file": "manage.py" if manage_py.is_file() else str(settings_py[0].relative_to(project_root)),
173
+ "file": evidence_file,
47
174
  "indicator": "Django management or settings configuration"
48
175
  })
49
176
  profile["recommended_rules"].extend(["TG-DB-004", "TG-RATE-001", "TG-PLATFORM-*"])
50
177
  profile["recommended_references"].extend(["django-security.md", "python-security-overview.md"])
51
-
178
+
52
179
  # Check for DRF
53
180
  for py_file in project_root.glob("**/*.py"):
54
181
  try:
@@ -60,13 +187,15 @@ def detect_stack(project_root: Path) -> Dict[str, Any]:
60
187
  except Exception:
61
188
  continue
62
189
 
63
- # Check for FastAPI / Flask if not Django
64
- if profile["framework"] == "None":
65
- for py_file in list(project_root.glob("*.py")) + list(project_root.glob("app/**/*.py")) + list(project_root.glob("src/**/*.py")):
190
+ elif has_py_manifest or list(project_root.glob("*.py")):
191
+ # Check FastAPI / Flask / SQLAlchemy
192
+ py_search_files = list(project_root.glob("*.py")) + list(project_root.glob("app/**/*.py")) + list(project_root.glob("src/**/*.py"))
193
+ for py_file in py_search_files[:25]:
66
194
  try:
67
195
  content = py_file.read_text(encoding="utf-8", errors="ignore")
68
196
  if "FastAPI(" in content or "from fastapi" in content:
69
197
  profile["language"] = "Python"
198
+ profile["ecosystem_family"] = "python"
70
199
  profile["framework"] = "FastAPI"
71
200
  profile["confidence"] = "Confirmed"
72
201
  profile["detection_evidence"].append({
@@ -76,6 +205,7 @@ def detect_stack(project_root: Path) -> Dict[str, Any]:
76
205
  profile["recommended_references"].append("fastapi-security.md")
77
206
  elif "Flask(__name__)" in content or "from flask" in content:
78
207
  profile["language"] = "Python"
208
+ profile["ecosystem_family"] = "python"
79
209
  profile["framework"] = "Flask"
80
210
  profile["confidence"] = "Confirmed"
81
211
  profile["detection_evidence"].append({
@@ -87,24 +217,62 @@ def detect_stack(project_root: Path) -> Dict[str, Any]:
87
217
  if "sqlalchemy" in content:
88
218
  profile["data_layer"] = "SQLAlchemy"
89
219
  profile["recommended_references"].append("sqlalchemy-security.md")
220
+ elif "tortoise" in content:
221
+ profile["data_layer"] = "Tortoise ORM"
90
222
  except Exception:
91
223
  continue
92
224
 
93
- # 3. Check JavaScript / TypeScript ecosystem
225
+ if profile["language"] == "Unknown" and has_py_manifest:
226
+ profile["language"] = "Python"
227
+ profile["ecosystem_family"] = "python"
228
+ profile["confidence"] = "High Confidence"
229
+ profile["detection_evidence"].append({
230
+ "file": profile["dependency_files"][0],
231
+ "indicator": "Python dependency manifest"
232
+ })
233
+ profile["recommended_references"].append("python-security-overview.md")
234
+
235
+ # -------------------------------------------------------------------------
236
+ # B. JavaScript / TypeScript Ecosystem
237
+ # -------------------------------------------------------------------------
94
238
  pkg_json_path = project_root / "package.json"
95
- if pkg_json_path.is_file():
96
- profile["language"] = "TypeScript" if list(project_root.glob("**/*.ts*")) else "JavaScript"
239
+ has_backend_manifest = any((project_root / m).is_file() for m in [
240
+ "composer.json", "mix.exs", "Gemfile", "Cargo.toml", "go.mod", "pom.xml", "build.gradle", "build.gradle.kts"
241
+ ]) or bool(csproj_files) or bool(sln_files)
242
+
243
+ if pkg_json_path.is_file() and profile["language"] == "Unknown" and not has_backend_manifest:
244
+ is_ts = bool(list(project_root.glob("**/*.ts*")))
245
+ profile["language"] = "TypeScript" if is_ts else "JavaScript"
246
+ profile["ecosystem_family"] = "javascript"
97
247
  try:
98
248
  with open(pkg_json_path, "r", encoding="utf-8") as f:
99
249
  pkg = json.load(f)
100
250
  deps = {**pkg.get("dependencies", {}), **pkg.get("devDependencies", {})}
101
-
251
+
252
+ # Framework detection
102
253
  if "next" in deps:
103
254
  profile["framework"] = "Next.js"
104
255
  profile["confidence"] = "Confirmed"
105
256
  profile["detection_evidence"].append({"file": "package.json", "indicator": "next dependency"})
106
257
  profile["recommended_references"].append("nextjs-security.md")
107
258
  profile["recommended_rules"].extend(["TG-CLIENT-*", "TG-PLATFORM-001"])
259
+ elif "@nestjs/core" in deps:
260
+ profile["framework"] = "NestJS"
261
+ profile["confidence"] = "Confirmed"
262
+ profile["detection_evidence"].append({"file": "package.json", "indicator": "NestJS dependency"})
263
+ profile["recommended_references"].append("nestjs-security.md")
264
+ elif "@sveltejs/kit" in deps:
265
+ profile["framework"] = "SvelteKit"
266
+ profile["confidence"] = "Confirmed"
267
+ profile["detection_evidence"].append({"file": "package.json", "indicator": "SvelteKit dependency"})
268
+ elif "nuxt" in deps:
269
+ profile["framework"] = "Nuxt"
270
+ profile["confidence"] = "Confirmed"
271
+ profile["detection_evidence"].append({"file": "package.json", "indicator": "Nuxt dependency"})
272
+ elif "astro" in deps:
273
+ profile["framework"] = "Astro"
274
+ profile["confidence"] = "Confirmed"
275
+ profile["detection_evidence"].append({"file": "package.json", "indicator": "Astro dependency"})
108
276
  elif "express" in deps:
109
277
  profile["framework"] = "Express"
110
278
  profile["confidence"] = "Confirmed"
@@ -116,7 +284,16 @@ def detect_stack(project_root: Path) -> Dict[str, Any]:
116
284
  profile["detection_evidence"].append({"file": "package.json", "indicator": "react dependency"})
117
285
  profile["recommended_references"].append("react-vite-security.md")
118
286
 
119
- if "@supabase/supabase-js" in deps:
287
+ # ORM / Data layer detection
288
+ if "@prisma/client" in deps or "prisma" in deps:
289
+ profile["data_layer"] = "Prisma ORM"
290
+ elif "drizzle-orm" in deps:
291
+ profile["data_layer"] = "Drizzle ORM"
292
+ elif "typeorm" in deps:
293
+ profile["data_layer"] = "TypeORM"
294
+ elif "mongoose" in deps:
295
+ profile["data_layer"] = "Mongoose"
296
+ elif "@supabase/supabase-js" in deps:
120
297
  profile["data_layer"] = "Supabase"
121
298
  profile["recommended_references"].append("supabase-security.md")
122
299
  elif "firebase" in deps or "firebase-admin" in deps:
@@ -125,11 +302,264 @@ def detect_stack(project_root: Path) -> Dict[str, Any]:
125
302
  except Exception:
126
303
  pass
127
304
 
305
+ # -------------------------------------------------------------------------
306
+ # C. Go Ecosystem
307
+ # -------------------------------------------------------------------------
308
+ go_mod = project_root / "go.mod"
309
+ if go_mod.is_file():
310
+ profile["language"] = "Go"
311
+ profile["ecosystem_family"] = "go"
312
+ profile["confidence"] = "Confirmed"
313
+ profile["detection_evidence"].append({"file": "go.mod", "indicator": "Go module manifest"})
314
+ profile["recommended_rules"].extend(["TG-SEC-*", "TG-INPUT-001", "TG-INPUT-002", "TG-DB-004", "TG-SSRF-*"])
315
+ profile["recommended_references"].append("go-security.md")
316
+
317
+ try:
318
+ go_content = go_mod.read_text(encoding="utf-8", errors="ignore")
319
+ if "github.com/gin-gonic/gin" in go_content:
320
+ profile["framework"] = "Gin"
321
+ elif "github.com/gofiber/fiber" in go_content:
322
+ profile["framework"] = "Fiber"
323
+ elif "github.com/labstack/echo" in go_content:
324
+ profile["framework"] = "Echo"
325
+ elif "github.com/go-chi/chi" in go_content:
326
+ profile["framework"] = "Chi"
327
+
328
+ if "gorm.io/gorm" in go_content:
329
+ profile["data_layer"] = "GORM"
330
+ elif "github.com/jmoiron/sqlx" in go_content:
331
+ profile["data_layer"] = "SQLx"
332
+ elif "database/sql" in go_content or "github.com/lib/pq" in go_content or "github.com/go-sql-driver/mysql" in go_content:
333
+ profile["data_layer"] = "database/sql"
334
+ except Exception:
335
+ pass
336
+
337
+ # -------------------------------------------------------------------------
338
+ # D. Rust Ecosystem
339
+ # -------------------------------------------------------------------------
340
+ cargo_toml = project_root / "Cargo.toml"
341
+ if cargo_toml.is_file() and profile["language"] == "Unknown":
342
+ profile["language"] = "Rust"
343
+ profile["ecosystem_family"] = "rust"
344
+ profile["confidence"] = "Confirmed"
345
+ profile["detection_evidence"].append({"file": "Cargo.toml", "indicator": "Cargo package manifest"})
346
+ profile["recommended_rules"].extend(["TG-SEC-*", "TG-INPUT-001", "TG-DB-004", "TG-BIZ-001"])
347
+ profile["recommended_references"].append("rust-security.md")
348
+
349
+ try:
350
+ cargo_content = cargo_toml.read_text(encoding="utf-8", errors="ignore")
351
+ if "actix-web" in cargo_content:
352
+ profile["framework"] = "Actix-web"
353
+ elif "axum" in cargo_content:
354
+ profile["framework"] = "Axum"
355
+ elif "rocket" in cargo_content:
356
+ profile["framework"] = "Rocket"
357
+
358
+ if "diesel" in cargo_content:
359
+ profile["data_layer"] = "Diesel ORM"
360
+ elif "sqlx" in cargo_content:
361
+ profile["data_layer"] = "SQLx"
362
+ elif "sea-orm" in cargo_content:
363
+ profile["data_layer"] = "SeaORM"
364
+ except Exception:
365
+ pass
366
+
367
+ # -------------------------------------------------------------------------
368
+ # E. Java / Kotlin Ecosystem
369
+ # -------------------------------------------------------------------------
370
+ pom_files = [project_root / "pom.xml"] + list(project_root.glob("*/pom.xml"))[:10]
371
+ gradle_files = [project_root / "build.gradle", project_root / "build.gradle.kts"] + list(project_root.glob("*/build.gradle*"))[:10]
372
+ has_jvm_manifest = any(f.is_file() for f in pom_files + gradle_files)
373
+ if has_jvm_manifest and profile["language"] == "Unknown":
374
+ java_files = list(project_root.glob("**/*.java"))
375
+ kt_files = list(project_root.glob("**/*.kt"))
376
+ is_kotlin = (project_root / "build.gradle.kts").is_file() or (len(kt_files) > len(java_files) and len(kt_files) > 0)
377
+ profile["language"] = "Kotlin" if is_kotlin else "Java"
378
+ profile["ecosystem_family"] = "jvm"
379
+ profile["confidence"] = "Confirmed"
380
+ ev_file = "build.gradle.kts" if (project_root / "build.gradle.kts").is_file() else ("build.gradle" if (project_root / "build.gradle").is_file() else "pom.xml")
381
+ profile["detection_evidence"].append({"file": ev_file, "indicator": f"{profile['language']} build configuration"})
382
+ profile["recommended_rules"].extend(["TG-SEC-*", "TG-AUTH-*", "TG-INPUT-001", "TG-INPUT-002", "TG-DB-004"])
383
+ profile["recommended_references"].append("java-security.md")
384
+
385
+ check_content = ""
386
+ for jf in (pom_files + gradle_files)[:15]:
387
+ if jf.is_file():
388
+ try:
389
+ check_content += jf.read_text(encoding="utf-8", errors="ignore") + "\n"
390
+ except Exception:
391
+ pass
392
+
393
+ if "quarkus" in check_content:
394
+ profile["framework"] = "Quarkus"
395
+ elif "spring-boot" in check_content or "springframework" in check_content:
396
+ profile["framework"] = "Spring Boot"
397
+ elif "ktor" in check_content:
398
+ profile["framework"] = "Ktor"
399
+ elif "micronaut" in check_content:
400
+ profile["framework"] = "Micronaut"
401
+
402
+ if "hibernate" in check_content or "spring-boot-starter-data-jpa" in check_content or "quarkus-hibernate" in check_content:
403
+ profile["data_layer"] = "Hibernate / JPA"
404
+ elif "jooq" in check_content:
405
+ profile["data_layer"] = "jOOQ"
406
+
407
+ # -------------------------------------------------------------------------
408
+ # F. C# / .NET Ecosystem
409
+ # -------------------------------------------------------------------------
410
+ if (csproj_files or sln_files) and profile["language"] == "Unknown":
411
+ profile["language"] = "C#"
412
+ profile["ecosystem_family"] = "dotnet"
413
+ profile["confidence"] = "Confirmed"
414
+ ev_file = str(csproj_files[0].relative_to(project_root)) if csproj_files else str(sln_files[0].relative_to(project_root))
415
+ profile["detection_evidence"].append({"file": ev_file, "indicator": ".NET project or solution manifest"})
416
+ profile["recommended_rules"].extend(["TG-SEC-*", "TG-AUTH-*", "TG-INPUT-001", "TG-DB-004"])
417
+ profile["recommended_references"].append("csharp-security.md")
418
+
419
+ csproj_content = ""
420
+ for cf in csproj_files[:10]:
421
+ try:
422
+ csproj_content += cf.read_text(encoding="utf-8", errors="ignore") + "\n"
423
+ except Exception:
424
+ pass
425
+
426
+ if "Microsoft.NET.Sdk.Web" in csproj_content or "Microsoft.AspNetCore" in csproj_content or "Swashbuckle" in csproj_content:
427
+ profile["framework"] = "ASP.NET Core"
428
+ if "Microsoft.EntityFrameworkCore" in csproj_content:
429
+ profile["data_layer"] = "Entity Framework Core"
430
+ elif "Dapper" in csproj_content:
431
+ profile["data_layer"] = "Dapper"
432
+
433
+ # -------------------------------------------------------------------------
434
+ # G. PHP Ecosystem
435
+ # -------------------------------------------------------------------------
436
+ composer_json = project_root / "composer.json"
437
+ if composer_json.is_file() and profile["language"] == "Unknown":
438
+ profile["language"] = "PHP"
439
+ profile["ecosystem_family"] = "php"
440
+ profile["confidence"] = "Confirmed"
441
+ profile["detection_evidence"].append({"file": "composer.json", "indicator": "PHP Composer manifest"})
442
+ profile["recommended_rules"].extend(["TG-SEC-*", "TG-INPUT-001", "TG-INPUT-002", "TG-PLATFORM-*"])
443
+ profile["recommended_references"].append("polyglot-security-matrix.md")
444
+
445
+ try:
446
+ with open(composer_json, "r", encoding="utf-8") as f:
447
+ c_data = json.load(f)
448
+ reqs = {**c_data.get("require", {}), **c_data.get("require-dev", {})}
449
+ if "laravel/framework" in reqs:
450
+ profile["framework"] = "Laravel"
451
+ profile["data_layer"] = "Eloquent ORM"
452
+ elif "symfony/framework-bundle" in reqs or any("symfony/" in k for k in reqs):
453
+ profile["framework"] = "Symfony"
454
+ profile["data_layer"] = "Doctrine ORM"
455
+ except Exception:
456
+ pass
457
+
458
+ # -------------------------------------------------------------------------
459
+ # H. Ruby Ecosystem
460
+ # -------------------------------------------------------------------------
461
+ gemfile = project_root / "Gemfile"
462
+ if gemfile.is_file() and profile["language"] == "Unknown":
463
+ profile["language"] = "Ruby"
464
+ profile["ecosystem_family"] = "ruby"
465
+ profile["confidence"] = "Confirmed"
466
+ profile["detection_evidence"].append({"file": "Gemfile", "indicator": "Ruby Bundler manifest"})
467
+ profile["recommended_rules"].extend(["TG-SEC-*", "TG-AUTH-*", "TG-INPUT-001", "TG-DB-004"])
468
+ profile["recommended_references"].append("polyglot-security-matrix.md")
469
+
470
+ try:
471
+ g_content = gemfile.read_text(encoding="utf-8", errors="ignore")
472
+ if "rails" in g_content:
473
+ profile["framework"] = "Ruby on Rails"
474
+ profile["data_layer"] = "ActiveRecord"
475
+ elif "sinatra" in g_content:
476
+ profile["framework"] = "Sinatra"
477
+ except Exception:
478
+ pass
479
+
480
+ # -------------------------------------------------------------------------
481
+ # I. Elixir Ecosystem
482
+ # -------------------------------------------------------------------------
483
+ mix_exs = project_root / "mix.exs"
484
+ if mix_exs.is_file() and profile["language"] == "Unknown":
485
+ profile["language"] = "Elixir"
486
+ profile["ecosystem_family"] = "elixir"
487
+ profile["confidence"] = "Confirmed"
488
+ profile["detection_evidence"].append({"file": "mix.exs", "indicator": "Elixir Mix manifest"})
489
+ profile["recommended_references"].append("polyglot-security-matrix.md")
490
+ try:
491
+ m_content = mix_exs.read_text(encoding="utf-8", errors="ignore")
492
+ if "phoenix" in m_content:
493
+ profile["framework"] = "Phoenix"
494
+ profile["data_layer"] = "Ecto"
495
+ except Exception:
496
+ pass
497
+
498
+ # -------------------------------------------------------------------------
499
+ # J. Dart / Flutter Ecosystem
500
+ # -------------------------------------------------------------------------
501
+ pubspec = project_root / "pubspec.yaml"
502
+ if pubspec.is_file() and profile["language"] == "Unknown":
503
+ profile["language"] = "Dart"
504
+ profile["ecosystem_family"] = "dart"
505
+ profile["confidence"] = "Confirmed"
506
+ profile["detection_evidence"].append({"file": "pubspec.yaml", "indicator": "Dart pubspec manifest"})
507
+ try:
508
+ p_content = pubspec.read_text(encoding="utf-8", errors="ignore")
509
+ if "flutter:" in p_content:
510
+ profile["framework"] = "Flutter"
511
+ except Exception:
512
+ pass
513
+
514
+ # -------------------------------------------------------------------------
515
+ # K. Fallback: Extension Census (When No Manifest or Custom Structure)
516
+ # -------------------------------------------------------------------------
517
+ census = census_file_extensions(project_root)
518
+ profile["extension_census"] = census
519
+
520
+ if profile["language"] == "Unknown" and census:
521
+ top_lang = max(census.items(), key=lambda x: x[1])[0]
522
+ profile["language"] = top_lang
523
+ profile["confidence"] = "Inferred from file census"
524
+ profile["detection_evidence"].append({
525
+ "file": "source files",
526
+ "indicator": f"{census[top_lang]} {top_lang} source file(s) found"
527
+ })
528
+ family_map = {
529
+ "Go": "go", "Rust": "rust", "Java": "jvm", "Kotlin": "jvm",
530
+ "C#": "dotnet", "PHP": "php", "Ruby": "ruby", "Python": "python",
531
+ "TypeScript": "javascript", "JavaScript": "javascript",
532
+ "C": "native", "C++": "native", "Swift": "apple", "Dart": "dart"
533
+ }
534
+ profile["ecosystem_family"] = family_map.get(top_lang, "universal")
535
+
536
+ # -------------------------------------------------------------------------
537
+ # L. Monorepo & Multi-Package Workspace Integration
538
+ # -------------------------------------------------------------------------
539
+ try:
540
+ from monorepo_detector import scan_workspace
541
+ ws_res = scan_workspace(str(project_root))
542
+ if ws_res.get("is_monorepo"):
543
+ profile["is_monorepo"] = True
544
+ profile["monorepo_type"] = ws_res.get("monorepo_type", "monorepo")
545
+ profile["sub_stacks"] = ws_res.get("packages", [])
546
+ languages_found = list(set(
547
+ p["language"] for p in ws_res.get("packages", [])
548
+ if p.get("language") and p["language"] != "unknown"
549
+ ))
550
+ profile["sub_languages"] = languages_found
551
+ if len(languages_found) > 1:
552
+ profile["ecosystem_family"] = "polyglot_monorepo"
553
+ profile["recommended_rules"].extend(["TG-SEC-*", "TG-AUTH-*", "TG-PLATFORM-*"])
554
+ except Exception:
555
+ profile["is_monorepo"] = False
556
+ profile["sub_stacks"] = []
557
+
128
558
  return profile
129
559
 
130
560
 
131
561
  def main():
132
- parser = argparse.ArgumentParser(description="TorusGuard Stack Detector")
562
+ parser = argparse.ArgumentParser(description="TorusGuard Universal Polyglot Stack Detector")
133
563
  parser.add_argument("path", nargs="?", default=".", help="Target project root directory")
134
564
  parser.add_argument("--json", action="store_true", help="Output raw JSON")
135
565
  args = parser.parse_args()
@@ -141,12 +571,14 @@ def main():
141
571
  print(json.dumps(profile, indent=2))
142
572
  else:
143
573
  evidence = profile["detection_evidence"][0]["file"] if profile["detection_evidence"] else "heuristic"
144
- print(f"## Detected Stack")
574
+ print("## Detected Stack (Universal Polyglot)")
145
575
  print(f"- Language: {profile['language']}")
576
+ print(f"- Ecosystem Family: {profile.get('ecosystem_family', 'universal')}")
146
577
  print(f"- Framework: {profile['framework']}")
147
578
  print(f"- Data layer: {profile['data_layer']}")
148
579
  print(f"- Dependency files: {', '.join(profile['dependency_files']) if profile['dependency_files'] else 'None'}")
149
580
  print(f"- Detection confidence: {profile['confidence']} ({evidence})")
150
581
 
582
+
151
583
  if __name__ == "__main__":
152
584
  main()