torusguard 1.3.0 → 1.3.2

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 (378) hide show
  1. package/.torusguard/.manifest.json +113 -9
  2. package/.torusguard/rules/README.md +93 -62
  3. package/.torusguard/rules/TG-AUTH-001-weak-password-storage.md +103 -0
  4. package/.torusguard/rules/TG-AUTH-002-client-only-authorization.md +85 -0
  5. package/.torusguard/rules/TG-AUTH-003-missing-object-authorization.md +85 -0
  6. package/.torusguard/rules/TG-AUTH-004-insecure-session-cookie.md +96 -0
  7. package/.torusguard/rules/TG-AUTH-005-unsafe-password-reset.md +104 -0
  8. package/.torusguard/rules/TG-CLIENT-001-public-production-source-maps.md +102 -0
  9. package/.torusguard/rules/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
  10. package/.torusguard/rules/TG-DB-001-frontend-database-query.md +83 -0
  11. package/.torusguard/rules/TG-DB-002-privileged-database-credential.md +86 -0
  12. package/.torusguard/rules/TG-DB-003-frontend-admin-sdk.md +91 -0
  13. package/.torusguard/rules/TG-DB-004-missing-tenant-query-isolation.md +103 -0
  14. package/.torusguard/rules/TG-INPUT-001-missing-server-validation.md +98 -0
  15. package/.torusguard/rules/TG-INPUT-002-raw-sql-concatenation.md +94 -0
  16. package/.torusguard/rules/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
  17. package/.torusguard/rules/TG-INPUT-004-unrestricted-file-upload.md +92 -0
  18. package/.torusguard/rules/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
  19. package/.torusguard/rules/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
  20. package/.torusguard/rules/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
  21. package/.torusguard/rules/TG-PLATFORM-002-missing-security-headers.md +95 -0
  22. package/.torusguard/rules/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
  23. package/.torusguard/rules/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
  24. package/.torusguard/rules/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
  25. package/.torusguard/rules/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
  26. package/.torusguard/rules/TG-RATE-003-unbounded-resource-consumption.md +105 -0
  27. package/.torusguard/rules/TG-SEC-001-hardcoded-secrets.md +83 -0
  28. package/.torusguard/rules/TG-SEC-002-public-environment-secrets.md +83 -0
  29. package/.torusguard/rules/TG-SEC-003-tracked-env-file.md +79 -0
  30. package/.torusguard/rules/TG-SEC-004-sensitive-logging.md +83 -0
  31. package/.torusguard/rules/active/TG-AUTH-001-weak-password-storage.md +103 -0
  32. package/.torusguard/rules/active/TG-AUTH-002-client-only-authorization.md +85 -0
  33. package/.torusguard/rules/active/TG-AUTH-003-missing-object-authorization.md +85 -0
  34. package/.torusguard/rules/active/TG-AUTH-004-insecure-session-cookie.md +96 -0
  35. package/.torusguard/rules/active/TG-AUTH-005-unsafe-password-reset.md +104 -0
  36. package/.torusguard/rules/active/TG-CLIENT-001-public-production-source-maps.md +102 -0
  37. package/.torusguard/rules/active/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
  38. package/.torusguard/rules/active/TG-DB-001-frontend-database-query.md +83 -0
  39. package/.torusguard/rules/active/TG-DB-002-privileged-database-credential.md +86 -0
  40. package/.torusguard/rules/active/TG-DB-003-frontend-admin-sdk.md +91 -0
  41. package/.torusguard/rules/active/TG-DB-004-missing-tenant-query-isolation.md +103 -0
  42. package/.torusguard/rules/active/TG-INPUT-001-missing-server-validation.md +98 -0
  43. package/.torusguard/rules/active/TG-INPUT-002-raw-sql-concatenation.md +94 -0
  44. package/.torusguard/rules/active/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
  45. package/.torusguard/rules/active/TG-INPUT-004-unrestricted-file-upload.md +92 -0
  46. package/.torusguard/rules/active/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
  47. package/.torusguard/rules/active/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
  48. package/.torusguard/rules/active/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
  49. package/.torusguard/rules/active/TG-PLATFORM-002-missing-security-headers.md +95 -0
  50. package/.torusguard/rules/active/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
  51. package/.torusguard/rules/active/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
  52. package/.torusguard/rules/active/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
  53. package/.torusguard/rules/active/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
  54. package/.torusguard/rules/active/TG-RATE-003-unbounded-resource-consumption.md +105 -0
  55. package/.torusguard/rules/active/TG-SEC-001-hardcoded-secrets.md +83 -0
  56. package/.torusguard/rules/active/TG-SEC-002-public-environment-secrets.md +83 -0
  57. package/.torusguard/rules/active/TG-SEC-003-tracked-env-file.md +79 -0
  58. package/.torusguard/rules/active/TG-SEC-004-sensitive-logging.md +83 -0
  59. package/.torusguard/rules/agent/TG-AGENT-001-prompt-injection-system-context.md +56 -0
  60. package/.torusguard/rules/agent/TG-AGENT-002-unsafe-tool-dispatch-unsandboxed-execution.md +68 -0
  61. package/.torusguard/rules/agent/TG-AGENT-003-broad-mcp-tool-scoping.md +53 -0
  62. package/.torusguard/rules/agent/TG-AGENT-004-persistent-memory-cross-session-leakage.md +67 -0
  63. package/.torusguard/rules/authorization/TG-AUTH-006-mass-assignment.md +70 -0
  64. package/.torusguard/rules/authorization/TG-AUTH-007-missing-property-level-authorization.md +71 -0
  65. package/.torusguard/rules/authorization/TG-AUTH-008-untrusted-role-header-injection.md +112 -0
  66. package/.torusguard/rules/business-logic/TG-BIZ-001-client-controlled-sensitive-business-value.md +37 -0
  67. package/.torusguard/rules/business-logic/TG-BIZ-002-replayable-one-time-operation.md +37 -0
  68. package/.torusguard/rules/business-logic/TG-BIZ-003-missing-workflow-state-validation.md +37 -0
  69. package/.torusguard/rules/business-logic/TG-BIZ-004-unrestricted-sensitive-business-flow.md +37 -0
  70. package/.torusguard/rules/cache/TG-CACHE-001-sensitive-response-publicly-cacheable.md +37 -0
  71. package/.torusguard/rules/cache/TG-CACHE-002-missing-user-cache-isolation.md +37 -0
  72. package/.torusguard/rules/cache/TG-CACHE-003-sensitive-data-in-url.md +37 -0
  73. package/.torusguard/rules/csrf/TG-CSRF-001-missing-csrf-protection.md +37 -0
  74. package/.torusguard/rules/csrf/TG-CSRF-002-unsafe-credentialed-cross-origin-request.md +37 -0
  75. package/.torusguard/rules/edge/TG-EDGE-001-serverless-global-state-leak.md +83 -0
  76. package/.torusguard/rules/edge/TG-EDGE-003-aws-lambda-ephemeral-cold-start.md +76 -0
  77. package/.torusguard/rules/graphql/TG-GQL-001-missing-query-depth-or-complexity-limits.md +64 -0
  78. package/.torusguard/rules/graphql/TG-GQL-002-resolver-missing-authorization.md +37 -0
  79. package/.torusguard/rules/graphql/TG-GQL-003-unbounded-graphql-pagination-or-batching.md +37 -0
  80. package/.torusguard/rules/graphql/TG-GQL-004-unnecessary-production-introspection.md +37 -0
  81. package/.torusguard/rules/secrets/TG-SEC-005-secret-in-git-history.md +37 -0
  82. package/.torusguard/rules/secrets/TG-SEC-006-secret-in-build-artifact.md +37 -0
  83. package/.torusguard/rules/secrets/TG-SEC-007-secret-in-test-or-example-fixture.md +37 -0
  84. package/.torusguard/rules/ssrf/TG-SSRF-001-user-controlled-server-side-url-fetch.md +68 -0
  85. package/.torusguard/rules/ssrf/TG-SSRF-002-missing-internal-network-protection.md +37 -0
  86. package/.torusguard/rules/ssrf/TG-SSRF-003-unsafe-redirect-following.md +37 -0
  87. package/.torusguard/rules/ssrf/TG-SSRF-004-unbounded-outbound-request.md +37 -0
  88. package/.torusguard/rules/supply-chain/TG-SUPPLY-001-missing-or-ignored-dependency-lockfile.md +37 -0
  89. package/.torusguard/rules/supply-chain/TG-SUPPLY-002-vulnerable-dependency-review-missing.md +94 -0
  90. package/.torusguard/rules/supply-chain/TG-SUPPLY-003-unsafe-ci-cd-secret-exposure.md +37 -0
  91. package/.torusguard/rules/supply-chain/TG-SUPPLY-004-unpinned-ci-action.md +37 -0
  92. package/.torusguard/rules/supply-chain/TG-SUPPLY-005-unsafe-dependency-install-script.md +37 -0
  93. package/.torusguard/rules/supply-chain/TG-SUPPLY-006-container-build-secret-persistence.md +61 -0
  94. package/.torusguard/rules/webhook/TG-WEBHOOK-001-missing-webhook-signature-verification.md +37 -0
  95. package/.torusguard/rules/webhook/TG-WEBHOOK-002-replayable-webhook.md +37 -0
  96. package/.torusguard/rules/webhook/TG-WEBHOOK-003-missing-webhook-idempotency.md +37 -0
  97. package/.torusguard/rules/webhook/TG-WEBHOOK-004-unvalidated-webhook-event-type.md +37 -0
  98. package/.torusguard/rules/websocket/TG-WS-001-unauthenticated-websocket-handshake.md +82 -0
  99. package/.torusguard/rules/websocket/TG-WS-002-missing-channel-level-authorization.md +37 -0
  100. package/.torusguard/rules/websocket/TG-WS-003-unvalidated-websocket-message.md +37 -0
  101. package/.torusguard/rules/websocket/TG-WS-004-unbounded-websocket-connections.md +37 -0
  102. package/.torusguard/runs/report-latest.html +62 -20
  103. package/.torusguard/runs/run-20260908-112648-audit/findings.json +1520 -0
  104. package/.torusguard/runs/run-20260908-112648-audit/findings.md +560 -0
  105. package/.torusguard/runs/run-20260908-112648-audit/manifest.json +12 -0
  106. package/.torusguard/runs/run-20260908-112648-audit/summary.md +5 -0
  107. package/.torusguard/runs/run-20260908-112722-audit/findings.json +1520 -0
  108. package/.torusguard/runs/run-20260908-112722-audit/findings.md +560 -0
  109. package/.torusguard/runs/run-20260908-112722-audit/manifest.json +12 -0
  110. package/.torusguard/runs/run-20260908-112722-audit/summary.md +5 -0
  111. package/.torusguard/runs/run-20260908-113004-audit/findings.json +1520 -0
  112. package/.torusguard/runs/run-20260908-113004-audit/findings.md +560 -0
  113. package/.torusguard/runs/run-20260908-113004-audit/manifest.json +12 -0
  114. package/.torusguard/runs/run-20260908-113004-audit/summary.md +5 -0
  115. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-115-9a059e/metadata.json +15 -0
  116. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-115-9a059e/minimal_patch_plan.md +21 -0
  117. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-115-9a059e/patch.diff +9 -0
  118. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-119-61557c/metadata.json +15 -0
  119. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-119-61557c/minimal_patch_plan.md +21 -0
  120. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-119-61557c/patch.diff +9 -0
  121. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-265-996ca3/metadata.json +15 -0
  122. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-265-996ca3/minimal_patch_plan.md +21 -0
  123. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-265-996ca3/patch.diff +9 -0
  124. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-334-cb819d/metadata.json +15 -0
  125. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-334-cb819d/minimal_patch_plan.md +21 -0
  126. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-334-cb819d/patch.diff +9 -0
  127. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-503-d11cf8/metadata.json +15 -0
  128. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-503-d11cf8/minimal_patch_plan.md +21 -0
  129. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-503-d11cf8/patch.diff +9 -0
  130. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-79-91f41f/metadata.json +15 -0
  131. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-79-91f41f/minimal_patch_plan.md +21 -0
  132. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-79-91f41f/patch.diff +9 -0
  133. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-107-516a40/metadata.json +15 -0
  134. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-107-516a40/minimal_patch_plan.md +21 -0
  135. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-107-516a40/patch.diff +9 -0
  136. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-128-7809a1/metadata.json +15 -0
  137. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-128-7809a1/minimal_patch_plan.md +21 -0
  138. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-128-7809a1/patch.diff +9 -0
  139. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-232-1b45d1/metadata.json +15 -0
  140. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-232-1b45d1/minimal_patch_plan.md +21 -0
  141. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-232-1b45d1/patch.diff +9 -0
  142. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-003-53-d167b4/metadata.json +15 -0
  143. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-003-53-d167b4/minimal_patch_plan.md +21 -0
  144. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-003-53-d167b4/patch.diff +9 -0
  145. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-209-4f6424/metadata.json +15 -0
  146. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-209-4f6424/minimal_patch_plan.md +21 -0
  147. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-209-4f6424/patch.diff +9 -0
  148. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-257-89bf34/metadata.json +15 -0
  149. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-257-89bf34/minimal_patch_plan.md +21 -0
  150. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-257-89bf34/patch.diff +9 -0
  151. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-341-ce228c/metadata.json +15 -0
  152. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-341-ce228c/minimal_patch_plan.md +21 -0
  153. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-341-ce228c/patch.diff +9 -0
  154. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-355-7b190b/metadata.json +15 -0
  155. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-355-7b190b/minimal_patch_plan.md +21 -0
  156. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-355-7b190b/patch.diff +9 -0
  157. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-64-5af31a/metadata.json +15 -0
  158. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-64-5af31a/minimal_patch_plan.md +21 -0
  159. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-64-5af31a/patch.diff +9 -0
  160. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-9-f51467/metadata.json +15 -0
  161. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-9-f51467/minimal_patch_plan.md +21 -0
  162. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-9-f51467/patch.diff +9 -0
  163. package/.torusguard/runs/run-20260908-113127-audit/findings.json +1520 -0
  164. package/.torusguard/runs/run-20260908-113127-audit/findings.md +560 -0
  165. package/.torusguard/runs/run-20260908-113127-audit/manifest.json +13 -0
  166. package/.torusguard/runs/run-20260908-113127-audit/remediation.md +262 -0
  167. package/.torusguard/runs/run-20260908-113127-audit/summary.md +5 -0
  168. package/.torusguard/runs/run-20260908-115240-audit/apply_plan.md +6 -0
  169. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-115-9a059e/metadata.json +15 -0
  170. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-115-9a059e/minimal_patch_plan.md +21 -0
  171. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-115-9a059e/patch.diff +9 -0
  172. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-119-61557c/metadata.json +15 -0
  173. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-119-61557c/minimal_patch_plan.md +21 -0
  174. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-119-61557c/patch.diff +9 -0
  175. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-265-996ca3/metadata.json +15 -0
  176. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-265-996ca3/minimal_patch_plan.md +21 -0
  177. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-265-996ca3/patch.diff +9 -0
  178. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-334-cb819d/metadata.json +15 -0
  179. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-334-cb819d/minimal_patch_plan.md +21 -0
  180. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-334-cb819d/patch.diff +9 -0
  181. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-503-d11cf8/metadata.json +15 -0
  182. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-503-d11cf8/minimal_patch_plan.md +21 -0
  183. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-503-d11cf8/patch.diff +9 -0
  184. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-79-91f41f/metadata.json +15 -0
  185. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-79-91f41f/minimal_patch_plan.md +21 -0
  186. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-79-91f41f/patch.diff +9 -0
  187. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-107-516a40/metadata.json +15 -0
  188. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-107-516a40/minimal_patch_plan.md +21 -0
  189. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-107-516a40/patch.diff +9 -0
  190. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-128-7809a1/metadata.json +15 -0
  191. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-128-7809a1/minimal_patch_plan.md +21 -0
  192. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-128-7809a1/patch.diff +9 -0
  193. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-232-1b45d1/metadata.json +15 -0
  194. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-232-1b45d1/minimal_patch_plan.md +21 -0
  195. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-232-1b45d1/patch.diff +9 -0
  196. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-003-53-d167b4/metadata.json +15 -0
  197. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-003-53-d167b4/minimal_patch_plan.md +21 -0
  198. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-003-53-d167b4/patch.diff +9 -0
  199. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-platform-001-168-5027cb/metadata.json +15 -0
  200. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-platform-001-168-5027cb/minimal_patch_plan.md +21 -0
  201. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-platform-001-168-5027cb/patch.diff +9 -0
  202. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-209-4f6424/metadata.json +15 -0
  203. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-209-4f6424/minimal_patch_plan.md +21 -0
  204. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-209-4f6424/patch.diff +9 -0
  205. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-257-89bf34/metadata.json +15 -0
  206. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-257-89bf34/minimal_patch_plan.md +21 -0
  207. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-257-89bf34/patch.diff +9 -0
  208. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-341-ce228c/metadata.json +15 -0
  209. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-341-ce228c/minimal_patch_plan.md +21 -0
  210. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-341-ce228c/patch.diff +9 -0
  211. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-355-7b190b/metadata.json +15 -0
  212. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-355-7b190b/minimal_patch_plan.md +21 -0
  213. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-355-7b190b/patch.diff +9 -0
  214. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-64-5af31a/metadata.json +15 -0
  215. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-64-5af31a/minimal_patch_plan.md +21 -0
  216. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-64-5af31a/patch.diff +9 -0
  217. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-9-f51467/metadata.json +15 -0
  218. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-9-f51467/minimal_patch_plan.md +21 -0
  219. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-9-f51467/patch.diff +9 -0
  220. package/.torusguard/runs/run-20260908-115240-audit/diff_summary.md +221 -0
  221. package/.torusguard/runs/run-20260908-115240-audit/findings.json +1553 -0
  222. package/.torusguard/runs/run-20260908-115240-audit/findings.md +572 -0
  223. package/.torusguard/runs/run-20260908-115240-audit/manifest.json +14 -0
  224. package/.torusguard/runs/run-20260908-115240-audit/recheck.md +91 -0
  225. package/.torusguard/runs/run-20260908-115240-audit/remediation.md +278 -0
  226. package/.torusguard/runs/run-20260908-115240-audit/summary.md +5 -0
  227. package/.torusguard/scripts/__pycache__/audit_runner.cpython-311.pyc +0 -0
  228. package/.torusguard/scripts/__pycache__/finding_scorer.cpython-311.pyc +0 -0
  229. package/.torusguard/scripts/__pycache__/memory_engine.cpython-311.pyc +0 -0
  230. package/.torusguard/scripts/__pycache__/monorepo_detector.cpython-311.pyc +0 -0
  231. package/.torusguard/scripts/__pycache__/run_manager.cpython-311.pyc +0 -0
  232. package/.torusguard/scripts/__pycache__/stack_detect.cpython-311.pyc +0 -0
  233. package/.torusguard/scripts/apply_runner.py +339 -0
  234. package/.torusguard/scripts/audit_runner.py +550 -0
  235. package/.torusguard/scripts/diff_guard.py +52 -4
  236. package/.torusguard/scripts/finding_scorer.py +58 -0
  237. package/.torusguard/scripts/harden_runner.py +375 -0
  238. package/.torusguard/scripts/html_reporter.py +25 -10
  239. package/.torusguard/scripts/manifest_builder.py +2 -0
  240. package/.torusguard/scripts/memory_engine.py +4 -0
  241. package/.torusguard/scripts/recheck_runner.py +221 -0
  242. package/.torusguard/scripts/recipes_runner.py +130 -0
  243. package/.torusguard/scripts/run_manager.py +17 -5
  244. package/.torusguard/skills/torusguard/SKILL.md +42 -42
  245. package/.torusguard/skills/torusguard/bootstrap.py +149 -70
  246. package/.torusguard/snapshots/run-20260908-115240-audit/examples/vulnerable-react-express/client/src/App.jsx.bak +63 -0
  247. package/.torusguard/snapshots/run-20260908-115240-audit/examples/vulnerable-react-express/server/index.js.bak +82 -0
  248. package/.torusguard/snapshots/run-20260908-115240-audit/harness/engine/fixture_manager.py.bak +245 -0
  249. package/.torusguard/snapshots/run-20260908-115240-audit/harness/master_validation.py.bak +698 -0
  250. package/.torusguard/snapshots/run-20260908-115240-audit/harness/runner.py.bak +551 -0
  251. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_e2e.py.bak +498 -0
  252. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_qa_v0_6_0.py.bak +572 -0
  253. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v0_6_1_scale.py.bak +371 -0
  254. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v0_6_2_modern_stacks.py.bak +462 -0
  255. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v0_6_3_hardening.py.bak +444 -0
  256. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v1_0_0_memory.py.bak +302 -0
  257. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v1_1_0_advanced_memory.py.bak +342 -0
  258. package/.torusguard/snapshots/run-20260908-115240-audit/skills/torusguard/payload/scripts/harden_runner.py.bak +353 -0
  259. package/.torusguard/snapshots/run-20260908-115240-audit/tests/test_v0_6_0_governed_remediation.py.bak +353 -0
  260. package/README.md +70 -33
  261. package/bin/torusguard.js +92 -22
  262. package/package.json +1 -1
  263. package/skills/torusguard/SKILL.md +42 -42
  264. package/skills/torusguard/bootstrap.py +147 -68
  265. package/skills/torusguard/payload/.manifest.json +113 -9
  266. package/skills/torusguard/payload/rules/README.md +93 -62
  267. package/skills/torusguard/payload/rules/TG-AUTH-001-weak-password-storage.md +103 -0
  268. package/skills/torusguard/payload/rules/TG-AUTH-002-client-only-authorization.md +85 -0
  269. package/skills/torusguard/payload/rules/TG-AUTH-003-missing-object-authorization.md +85 -0
  270. package/skills/torusguard/payload/rules/TG-AUTH-004-insecure-session-cookie.md +96 -0
  271. package/skills/torusguard/payload/rules/TG-AUTH-005-unsafe-password-reset.md +104 -0
  272. package/skills/torusguard/payload/rules/TG-CLIENT-001-public-production-source-maps.md +102 -0
  273. package/skills/torusguard/payload/rules/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
  274. package/skills/torusguard/payload/rules/TG-DB-001-frontend-database-query.md +83 -0
  275. package/skills/torusguard/payload/rules/TG-DB-002-privileged-database-credential.md +86 -0
  276. package/skills/torusguard/payload/rules/TG-DB-003-frontend-admin-sdk.md +91 -0
  277. package/skills/torusguard/payload/rules/TG-DB-004-missing-tenant-query-isolation.md +103 -0
  278. package/skills/torusguard/payload/rules/TG-INPUT-001-missing-server-validation.md +98 -0
  279. package/skills/torusguard/payload/rules/TG-INPUT-002-raw-sql-concatenation.md +94 -0
  280. package/skills/torusguard/payload/rules/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
  281. package/skills/torusguard/payload/rules/TG-INPUT-004-unrestricted-file-upload.md +92 -0
  282. package/skills/torusguard/payload/rules/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
  283. package/skills/torusguard/payload/rules/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
  284. package/skills/torusguard/payload/rules/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
  285. package/skills/torusguard/payload/rules/TG-PLATFORM-002-missing-security-headers.md +95 -0
  286. package/skills/torusguard/payload/rules/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
  287. package/skills/torusguard/payload/rules/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
  288. package/skills/torusguard/payload/rules/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
  289. package/skills/torusguard/payload/rules/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
  290. package/skills/torusguard/payload/rules/TG-RATE-003-unbounded-resource-consumption.md +105 -0
  291. package/skills/torusguard/payload/rules/TG-SEC-001-hardcoded-secrets.md +83 -0
  292. package/skills/torusguard/payload/rules/TG-SEC-002-public-environment-secrets.md +83 -0
  293. package/skills/torusguard/payload/rules/TG-SEC-003-tracked-env-file.md +79 -0
  294. package/skills/torusguard/payload/rules/TG-SEC-004-sensitive-logging.md +83 -0
  295. package/skills/torusguard/payload/rules/active/TG-AUTH-001-weak-password-storage.md +103 -0
  296. package/skills/torusguard/payload/rules/active/TG-AUTH-002-client-only-authorization.md +85 -0
  297. package/skills/torusguard/payload/rules/active/TG-AUTH-003-missing-object-authorization.md +85 -0
  298. package/skills/torusguard/payload/rules/active/TG-AUTH-004-insecure-session-cookie.md +96 -0
  299. package/skills/torusguard/payload/rules/active/TG-AUTH-005-unsafe-password-reset.md +104 -0
  300. package/skills/torusguard/payload/rules/active/TG-CLIENT-001-public-production-source-maps.md +102 -0
  301. package/skills/torusguard/payload/rules/active/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
  302. package/skills/torusguard/payload/rules/active/TG-DB-001-frontend-database-query.md +83 -0
  303. package/skills/torusguard/payload/rules/active/TG-DB-002-privileged-database-credential.md +86 -0
  304. package/skills/torusguard/payload/rules/active/TG-DB-003-frontend-admin-sdk.md +91 -0
  305. package/skills/torusguard/payload/rules/active/TG-DB-004-missing-tenant-query-isolation.md +103 -0
  306. package/skills/torusguard/payload/rules/active/TG-INPUT-001-missing-server-validation.md +98 -0
  307. package/skills/torusguard/payload/rules/active/TG-INPUT-002-raw-sql-concatenation.md +94 -0
  308. package/skills/torusguard/payload/rules/active/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
  309. package/skills/torusguard/payload/rules/active/TG-INPUT-004-unrestricted-file-upload.md +92 -0
  310. package/skills/torusguard/payload/rules/active/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
  311. package/skills/torusguard/payload/rules/active/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
  312. package/skills/torusguard/payload/rules/active/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
  313. package/skills/torusguard/payload/rules/active/TG-PLATFORM-002-missing-security-headers.md +95 -0
  314. package/skills/torusguard/payload/rules/active/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
  315. package/skills/torusguard/payload/rules/active/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
  316. package/skills/torusguard/payload/rules/active/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
  317. package/skills/torusguard/payload/rules/active/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
  318. package/skills/torusguard/payload/rules/active/TG-RATE-003-unbounded-resource-consumption.md +105 -0
  319. package/skills/torusguard/payload/rules/active/TG-SEC-001-hardcoded-secrets.md +83 -0
  320. package/skills/torusguard/payload/rules/active/TG-SEC-002-public-environment-secrets.md +83 -0
  321. package/skills/torusguard/payload/rules/active/TG-SEC-003-tracked-env-file.md +79 -0
  322. package/skills/torusguard/payload/rules/active/TG-SEC-004-sensitive-logging.md +83 -0
  323. package/skills/torusguard/payload/rules/agent/TG-AGENT-001-prompt-injection-system-context.md +56 -0
  324. package/skills/torusguard/payload/rules/agent/TG-AGENT-002-unsafe-tool-dispatch-unsandboxed-execution.md +68 -0
  325. package/skills/torusguard/payload/rules/agent/TG-AGENT-003-broad-mcp-tool-scoping.md +53 -0
  326. package/skills/torusguard/payload/rules/agent/TG-AGENT-004-persistent-memory-cross-session-leakage.md +67 -0
  327. package/skills/torusguard/payload/rules/authorization/TG-AUTH-006-mass-assignment.md +70 -0
  328. package/skills/torusguard/payload/rules/authorization/TG-AUTH-007-missing-property-level-authorization.md +71 -0
  329. package/skills/torusguard/payload/rules/authorization/TG-AUTH-008-untrusted-role-header-injection.md +112 -0
  330. package/skills/torusguard/payload/rules/business-logic/TG-BIZ-001-client-controlled-sensitive-business-value.md +37 -0
  331. package/skills/torusguard/payload/rules/business-logic/TG-BIZ-002-replayable-one-time-operation.md +37 -0
  332. package/skills/torusguard/payload/rules/business-logic/TG-BIZ-003-missing-workflow-state-validation.md +37 -0
  333. package/skills/torusguard/payload/rules/business-logic/TG-BIZ-004-unrestricted-sensitive-business-flow.md +37 -0
  334. package/skills/torusguard/payload/rules/cache/TG-CACHE-001-sensitive-response-publicly-cacheable.md +37 -0
  335. package/skills/torusguard/payload/rules/cache/TG-CACHE-002-missing-user-cache-isolation.md +37 -0
  336. package/skills/torusguard/payload/rules/cache/TG-CACHE-003-sensitive-data-in-url.md +37 -0
  337. package/skills/torusguard/payload/rules/csrf/TG-CSRF-001-missing-csrf-protection.md +37 -0
  338. package/skills/torusguard/payload/rules/csrf/TG-CSRF-002-unsafe-credentialed-cross-origin-request.md +37 -0
  339. package/skills/torusguard/payload/rules/edge/TG-EDGE-001-serverless-global-state-leak.md +83 -0
  340. package/skills/torusguard/payload/rules/edge/TG-EDGE-003-aws-lambda-ephemeral-cold-start.md +76 -0
  341. package/skills/torusguard/payload/rules/graphql/TG-GQL-001-missing-query-depth-or-complexity-limits.md +64 -0
  342. package/skills/torusguard/payload/rules/graphql/TG-GQL-002-resolver-missing-authorization.md +37 -0
  343. package/skills/torusguard/payload/rules/graphql/TG-GQL-003-unbounded-graphql-pagination-or-batching.md +37 -0
  344. package/skills/torusguard/payload/rules/graphql/TG-GQL-004-unnecessary-production-introspection.md +37 -0
  345. package/skills/torusguard/payload/rules/secrets/TG-SEC-005-secret-in-git-history.md +37 -0
  346. package/skills/torusguard/payload/rules/secrets/TG-SEC-006-secret-in-build-artifact.md +37 -0
  347. package/skills/torusguard/payload/rules/secrets/TG-SEC-007-secret-in-test-or-example-fixture.md +37 -0
  348. package/skills/torusguard/payload/rules/ssrf/TG-SSRF-001-user-controlled-server-side-url-fetch.md +68 -0
  349. package/skills/torusguard/payload/rules/ssrf/TG-SSRF-002-missing-internal-network-protection.md +37 -0
  350. package/skills/torusguard/payload/rules/ssrf/TG-SSRF-003-unsafe-redirect-following.md +37 -0
  351. package/skills/torusguard/payload/rules/ssrf/TG-SSRF-004-unbounded-outbound-request.md +37 -0
  352. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-001-missing-or-ignored-dependency-lockfile.md +37 -0
  353. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-002-vulnerable-dependency-review-missing.md +94 -0
  354. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-003-unsafe-ci-cd-secret-exposure.md +37 -0
  355. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-004-unpinned-ci-action.md +37 -0
  356. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-005-unsafe-dependency-install-script.md +37 -0
  357. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-006-container-build-secret-persistence.md +61 -0
  358. package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-001-missing-webhook-signature-verification.md +37 -0
  359. package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-002-replayable-webhook.md +37 -0
  360. package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-003-missing-webhook-idempotency.md +37 -0
  361. package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-004-unvalidated-webhook-event-type.md +37 -0
  362. package/skills/torusguard/payload/rules/websocket/TG-WS-001-unauthenticated-websocket-handshake.md +82 -0
  363. package/skills/torusguard/payload/rules/websocket/TG-WS-002-missing-channel-level-authorization.md +37 -0
  364. package/skills/torusguard/payload/rules/websocket/TG-WS-003-unvalidated-websocket-message.md +37 -0
  365. package/skills/torusguard/payload/rules/websocket/TG-WS-004-unbounded-websocket-connections.md +37 -0
  366. package/skills/torusguard/payload/scripts/apply_runner.py +339 -0
  367. package/skills/torusguard/payload/scripts/audit_runner.py +550 -0
  368. package/skills/torusguard/payload/scripts/diff_guard.py +52 -4
  369. package/skills/torusguard/payload/scripts/finding_scorer.py +58 -0
  370. package/skills/torusguard/payload/scripts/harden_runner.py +375 -0
  371. package/skills/torusguard/payload/scripts/html_reporter.py +25 -10
  372. package/skills/torusguard/payload/scripts/manifest_builder.py +2 -0
  373. package/skills/torusguard/payload/scripts/memory_engine.py +4 -0
  374. package/skills/torusguard/payload/scripts/recheck_runner.py +221 -0
  375. package/skills/torusguard/payload/scripts/recipes_runner.py +130 -0
  376. package/skills/torusguard/payload/scripts/run_manager.py +17 -5
  377. package/skills/torusguard/payload/skills/torusguard/SKILL.md +42 -42
  378. package/skills/torusguard/payload/skills/torusguard/bootstrap.py +147 -68
@@ -0,0 +1,302 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ TorusGuard v1.0.0 Adaptive Security Memory Engine Test Suite
4
+ Validates:
5
+ 1. Memory directory scaffolding & privacy isolation (.gitignore)
6
+ 2. Event recording across all 6 event types
7
+ 3. Pattern distillation (amplification & categorization)
8
+ 4. Pre-computed context window computation (JSON cards & token budget <= 2000)
9
+ 5. False positive suppression
10
+ 6. Memory decay (TTL enforcement)
11
+ 7. Export and Import roundtrip
12
+ 8. Memory compaction (events archive)
13
+ 9. Privacy verification (npm tarball & git status)
14
+ 10. Memory-augmented confidence scoring
15
+ 11. Content-aware diff regression detection (TG-DIFF-004)
16
+ """
17
+
18
+ import os
19
+ import sys
20
+ import json
21
+ import shutil
22
+ import tempfile
23
+ import datetime
24
+ from pathlib import Path
25
+
26
+ # Ensure UTF-8 stdout/stderr on Windows consoles
27
+ if sys.stdout and hasattr(sys.stdout, "reconfigure"):
28
+ try:
29
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
30
+ except Exception:
31
+ pass
32
+ if sys.stderr and hasattr(sys.stderr, "reconfigure"):
33
+ try:
34
+ sys.stderr.reconfigure(encoding="utf-8", errors="replace")
35
+ except Exception:
36
+ pass
37
+
38
+ ROOT_DIR = Path(__file__).resolve().parent.parent
39
+ SCRIPTS_DIR = ROOT_DIR / ".torusguard" / "scripts"
40
+ sys.path.insert(0, str(SCRIPTS_DIR))
41
+
42
+ import memory_engine # type: ignore
43
+ import finding_scorer # type: ignore
44
+ import diff_guard # type: ignore
45
+
46
+
47
+ def test_v1_0_0_memory_engine():
48
+ print("=" * 80)
49
+ print("TORUSGUARD v1.0.0 ADAPTIVE SECURITY MEMORY ENGINE TEST SUITE")
50
+ print("=" * 80)
51
+
52
+ with tempfile.TemporaryDirectory() as tmp_dir:
53
+ test_root = Path(tmp_dir).resolve()
54
+ tg_dir = test_root / ".torusguard"
55
+ tg_dir.mkdir(parents=True, exist_ok=True)
56
+
57
+ # ---------------------------------------------------------------------
58
+ # 1. Test Scaffolding & Memory Directory Structure
59
+ # ---------------------------------------------------------------------
60
+ print("\n--- 1. Testing Memory Scaffolding & Structure ---")
61
+ paths = memory_engine.ensure_memory_structure(root_dir=test_root)
62
+ assert paths["memory"].is_dir(), "Memory directory not created"
63
+ assert paths["events"].is_dir(), "Events directory not created"
64
+ assert paths["gitignore"].is_file(), "Missing memory/.gitignore"
65
+ assert paths["gitignore"].read_text(encoding="utf-8").strip() == "*", "memory/.gitignore must contain *"
66
+ assert paths["patterns"].is_file(), "Missing patterns.json"
67
+ assert paths["context"].is_file(), "Missing context.json"
68
+ assert paths["profile"].is_file(), "Missing profile.json"
69
+ assert paths["decay"].is_file(), "Missing decay.json"
70
+ assert (paths["events"] / ".gitkeep").is_file(), "Missing events/.gitkeep"
71
+ print(" [PASS] Memory directory structure, files, and isolation .gitignore created cleanly")
72
+
73
+ # ---------------------------------------------------------------------
74
+ # 2. Test Event Recording Across All 6 Types
75
+ # ---------------------------------------------------------------------
76
+ print("\n--- 2. Testing Event Recording (All 6 Event Types) ---")
77
+ event_types = [
78
+ ("audit_finding", {"rule_id": "TG-DB-004", "file_path": "src/views.py", "line_number": 42, "severity": "high", "confidence_score": 85, "code_hash": "abc123hash"}),
79
+ ("fix_applied", {"rule_id": "TG-DB-004", "file_path": "src/views.py", "line_number": 42, "fix_strategy": "tenant_filter_added"}),
80
+ ("fix_verified", {"rule_id": "TG-DB-004", "file_path": "src/views.py", "verification_result": "fixed"}),
81
+ ("false_positive", {"rule_id": "TG-INPUT-002", "file_path": "tests/mock.py", "suppression_reason": "Test fixture intentional sink"}),
82
+ ("pattern_learned", {"rule_id": "TG-SEC-001", "metadata": {"note": "Learned from manual review"}}),
83
+ ("stack_changed", {"metadata": {"old": "Flask", "new": "FastAPI"}})
84
+ ]
85
+
86
+ recorded_events = []
87
+ for etype, edata in event_types:
88
+ evt = memory_engine.record_event(etype, edata, root_dir=test_root)
89
+ assert evt.get("event_type") == etype, f"Recorded wrong type: {etype}"
90
+ assert evt.get("event_id", "").startswith("evt-"), "Missing or invalid event_id"
91
+ assert evt.get("timestamp"), "Missing timestamp"
92
+ assert evt.get("version") in ("1.0.0", memory_engine.VERSION), "Version mismatch in event"
93
+ recorded_events.append(evt)
94
+
95
+ all_events = memory_engine.load_all_events(root_dir=test_root)
96
+ assert len(all_events) == 6, f"Expected 6 events, found {len(all_events)}"
97
+ print(f" [PASS] All 6 event types successfully logged and validated ({len(all_events)} events)")
98
+
99
+ # ---------------------------------------------------------------------
100
+ # 3. Test Pattern Distillation & Confidence Amplification
101
+ # ---------------------------------------------------------------------
102
+ print("\n--- 3. Testing Pattern Distillation & Confidence Amplification ---")
103
+ # Add repeated fixes across multiple files to test amplification
104
+ memory_engine.record_event("audit_finding", {"rule_id": "TG-DB-004", "file_path": "src/models.py", "severity": "high"}, root_dir=test_root)
105
+ memory_engine.record_event("fix_applied", {"rule_id": "TG-DB-004", "file_path": "src/models.py", "fix_strategy": "tenant_filter_added"}, root_dir=test_root)
106
+ memory_engine.record_event("fix_verified", {"rule_id": "TG-DB-004", "file_path": "src/models.py", "verification_result": "fixed"}, root_dir=test_root)
107
+
108
+ patterns = memory_engine.distill_patterns(root_dir=test_root)
109
+ assert len(patterns) >= 2, f"Expected at least 2 patterns, found {len(patterns)}"
110
+
111
+ # Find recurring fix pattern for TG-DB-004
112
+ db_pats = [p for p in patterns if p.get("rule_id") == "TG-DB-004"]
113
+ assert len(db_pats) >= 1, "TG-DB-004 pattern not distilled"
114
+ tg_pat = db_pats[0]
115
+ assert tg_pat.get("occurrences", 0) >= 2, "Expected multiple occurrences"
116
+ assert len(tg_pat.get("affected_files", [])) >= 2, "Expected multi-file tracking"
117
+ assert tg_pat.get("confidence", 0) >= 70, f"Confidence not amplified: {tg_pat.get('confidence')}"
118
+ print(f" [PASS] Distilled {len(patterns)} patterns with multi-file confidence amplification (Score: {tg_pat.get('confidence')})")
119
+
120
+ # ---------------------------------------------------------------------
121
+ # 4. Test Pre-Computed Context Window (JSON Cards & Budget Enforcement)
122
+ # ---------------------------------------------------------------------
123
+ print("\n--- 4. Testing Context Window Generation & Token Budget ---")
124
+ ctx = memory_engine.compute_context_window(max_tokens=2000, root_dir=test_root)
125
+ assert ctx.get("version") in ("1.0.0", memory_engine.VERSION), "Context version mismatch"
126
+ assert ctx.get("token_estimate", 0) <= 2000, "Context exceeds 2000 token budget"
127
+ assert len(ctx.get("cards", [])) >= 2, "Context missing intelligence cards"
128
+
129
+ # Check card format: card_id, card_type, priority, title, summary, card_data
130
+ for c in ctx["cards"]:
131
+ assert "card_id" in c and "card_type" in c and "priority" in c
132
+ assert "title" in c and "summary" in c and "card_data" in c
133
+ assert c["card_type"] in ("profile", "pattern", "regression_watch", "false_positive", "false_positive_suppression", "fix_idiom", "common_vulnerability", "golden_recipe")
134
+
135
+ print(f" [PASS] Generated {len(ctx['cards'])} structured JSON cards within budget ({ctx['token_estimate']}/2000 tokens)")
136
+
137
+ # ---------------------------------------------------------------------
138
+ # 5. Test False Positive Suppression
139
+ # ---------------------------------------------------------------------
140
+ print("\n--- 5. Testing False Positive Suppression ---")
141
+ fp_evt = memory_engine.record_false_positive("TG-SEC-999", file_path="config/test.py", reason="Mock test token", root_dir=test_root)
142
+ assert fp_evt.get("rule_id") == "TG-SEC-999"
143
+
144
+ fp_pats = [p for p in memory_engine.distill_patterns(root_dir=test_root) if p.get("rule_id") == "TG-SEC-999"]
145
+ assert len(fp_pats) == 1, "False positive pattern not found"
146
+ assert fp_pats[0]["pattern_type"] == "false_positive_class"
147
+ print(" [PASS] False positive suppression successfully cataloged into pattern store")
148
+
149
+ # ---------------------------------------------------------------------
150
+ # 6. Test Memory Decay (TTL Expiration)
151
+ # ---------------------------------------------------------------------
152
+ print("\n--- 6. Testing Memory Decay (TTL Enforcement) ---")
153
+ # Artificially age a pattern's last_seen and decay_checkpoint by 100 days
154
+ pats = json.loads(paths["patterns"].read_text(encoding="utf-8"))
155
+ old_dt = (datetime.datetime.utcnow() - datetime.timedelta(days=100)).isoformat() + "Z"
156
+ for p in pats:
157
+ if p.get("rule_id") == "TG-DB-004":
158
+ p["last_seen"] = old_dt
159
+ p["decay_checkpoint"] = old_dt
160
+ p["confidence"] = 80
161
+ paths["patterns"].write_text(json.dumps(pats, indent=2), encoding="utf-8")
162
+
163
+ decayed = memory_engine.decay_stale_entries(ttl_days=90, root_dir=test_root)
164
+ assert decayed >= 1, f"Expected decay of aged pattern, decayed: {decayed}"
165
+
166
+ pats_after = json.loads(paths["patterns"].read_text(encoding="utf-8"))
167
+ db_after = [p for p in pats_after if p.get("rule_id") == "TG-DB-004"][0]
168
+ assert db_after["confidence"] < 80, f"Confidence did not decay: {db_after['confidence']}"
169
+ print(f" [PASS] Memory decay correctly reduced confidence of 100-day-old pattern ({80} -> {db_after['confidence']})")
170
+
171
+ # ---------------------------------------------------------------------
172
+ # 7. Test Export and Import Roundtrip
173
+ # ---------------------------------------------------------------------
174
+ print("\n--- 7. Testing Export and Import Roundtrip ---")
175
+ export_file = test_root / "export_test.json"
176
+ exp_res = memory_engine.export_memory(str(export_file), root_dir=test_root)
177
+ assert export_file.is_file(), "Export file not created"
178
+ assert exp_res["exported_events_count"] > 0, "No events exported"
179
+
180
+ with open(export_file, "r", encoding="utf-8") as f:
181
+ exp_data = json.load(f)
182
+ assert exp_data.get("format") == "torusguard-memory-bundle"
183
+ assert len(exp_data.get("events", [])) > 0
184
+
185
+ # Import into fresh workspace
186
+ fresh_root = Path(tempfile.mkdtemp()).resolve()
187
+ try:
188
+ imp_res = memory_engine.import_memory(str(export_file), root_dir=fresh_root)
189
+ assert imp_res["imported_events_count"] == exp_res["exported_events_count"]
190
+ fresh_pats = memory_engine.distill_patterns(root_dir=fresh_root)
191
+ assert len(fresh_pats) > 0, "No patterns distilled after import"
192
+ print(f" [PASS] Export/Import roundtrip verified: {imp_res['imported_events_count']} events transferred cleanly")
193
+ finally:
194
+ shutil.rmtree(fresh_root, ignore_errors=True)
195
+
196
+ # ---------------------------------------------------------------------
197
+ # 8. Test Memory Compaction
198
+ # ---------------------------------------------------------------------
199
+ print("\n--- 8. Testing Memory Compaction ---")
200
+ # Artificially age several loose event files by 40 days
201
+ old_ts = (datetime.datetime.utcnow() - datetime.timedelta(days=40)).isoformat() + "Z"
202
+ for evt_f in paths["events"].glob("*.json"):
203
+ if evt_f.name == "compacted_archive.json":
204
+ continue
205
+ try:
206
+ data = json.loads(evt_f.read_text(encoding="utf-8"))
207
+ data["timestamp"] = old_ts
208
+ evt_f.write_text(json.dumps(data, indent=2), encoding="utf-8")
209
+ except Exception:
210
+ pass
211
+
212
+ compacted = memory_engine.compact_events(older_than_days=30, root_dir=test_root)
213
+ assert compacted > 0, "No events compacted"
214
+ assert paths["compacted"].is_file(), "Missing compacted_archive.json"
215
+ print(f" [PASS] Compacted {compacted} aged event files into single archive")
216
+
217
+ # ---------------------------------------------------------------------
218
+ # 9. Test Memory-Augmented Finding Scorer
219
+ # ---------------------------------------------------------------------
220
+ print("\n--- 9. Testing Memory-Augmented Finding Scorer ---")
221
+ # Case A: False positive rule should receive negative boost (-30)
222
+ score_fp, band_fp, factors_fp = finding_scorer.compute_confidence_score(
223
+ evidence_quality=35,
224
+ reproduction_success=0,
225
+ independent_confirmations=15,
226
+ environmental_clarity=15,
227
+ rule_id="TG-SEC-999",
228
+ root_dir=test_root
229
+ )
230
+ assert factors_fp["memory_boost"] <= -20, f"False positive was not suppressed: {factors_fp}"
231
+ assert score_fp < 50, f"Suppressed rule score too high: {score_fp}"
232
+
233
+ # Case B: Recurring pattern receives positive boost
234
+ score_rec, band_rec, factors_rec = finding_scorer.compute_confidence_score(
235
+ evidence_quality=35,
236
+ reproduction_success=25,
237
+ independent_confirmations=15,
238
+ environmental_clarity=15,
239
+ rule_id="TG-DB-004",
240
+ file_path="src/views.py",
241
+ root_dir=test_root
242
+ )
243
+ assert factors_rec["memory_boost"] >= 10, f"Recurring pattern boost not applied: {factors_rec}"
244
+ print(f" [PASS] Finding scorer correctly applies memory boost: Suppressed={factors_fp['memory_boost']}pts, Recurring=+{factors_rec['memory_boost']}pts")
245
+
246
+ # ---------------------------------------------------------------------
247
+ # 10. Test Diff Guard Regression Detection (TG-DIFF-004)
248
+ # ---------------------------------------------------------------------
249
+ print("\n--- 10. Testing Diff Guard Regression Detection ---")
250
+ # Add regression watch pattern to memory
251
+ memory_engine.record_event("fix_verified", {
252
+ "rule_id": "TG-DB-004",
253
+ "file_path": "src/billing.py",
254
+ "verification_result": "regressed"
255
+ }, root_dir=test_root)
256
+ memory_engine.distill_patterns(root_dir=test_root)
257
+
258
+ # Diff modifying src/billing.py
259
+ regression_diff = """--- a/src/billing.py
260
+ +++ b/src/billing.py
261
+ @@ -12,2 +12,2 @@
262
+ -def get_bill(id, tenant):
263
+ - return Bill.objects.filter(id=id, tenant=tenant)
264
+ +def get_bill(id):
265
+ + return Bill.objects.get(id=id)
266
+ """
267
+ res_reg = diff_guard.audit_diff(regression_diff, check_memory=True, root_dir=test_root)
268
+ assert res_reg["status"] == "BLOCKED", f"Expected diff to be blocked by regression check: {res_reg}"
269
+ rule_ids = [v["rule_id"] for v in res_reg["violations"]]
270
+ assert "TG-DIFF-004" in rule_ids, f"Expected TG-DIFF-004 violation, got: {rule_ids}"
271
+ print(f" [PASS] Diff Guard caught TG-DIFF-004 regression on file tracked in memory")
272
+
273
+ # ---------------------------------------------------------------------
274
+ # 11. Test Privacy Invariants (.gitignore and NPM pack isolation)
275
+ # ---------------------------------------------------------------------
276
+ print("\n--- 11. Testing Privacy & NPM Pack Isolation ---")
277
+ root_gi = (ROOT_DIR / ".gitignore").read_text(encoding="utf-8")
278
+ assert ".torusguard/memory/" in root_gi, "Root .gitignore missing .torusguard/memory/"
279
+
280
+ # Check npm pack does not include memory
281
+ import subprocess
282
+ npm_bin = "npm.cmd" if sys.platform == "win32" else "npm"
283
+ pack_res = subprocess.run([npm_bin, "pack", "--dry-run"], cwd=str(ROOT_DIR), capture_output=True, text=True, encoding="utf-8", errors="replace")
284
+ assert pack_res.returncode == 0, f"npm pack failed: {pack_res.stderr}"
285
+ assert ".torusguard/memory" not in pack_res.stdout and ".torusguard/memory" not in pack_res.stderr, "Memory leaked into npm package!"
286
+ print(" [PASS] Memory directory completely excluded from git and npm release package")
287
+
288
+ print("\n" + "=" * 80)
289
+ print(">>> ALL 11 TORUSGUARD v1.0.0 MEMORY ENGINE CHECKS PASSED (100%) <<<")
290
+ print("=" * 80 + "\n")
291
+
292
+
293
+ if __name__ == "__main__":
294
+ try:
295
+ test_v1_0_0_memory_engine()
296
+ sys.exit(0)
297
+ except AssertionError as e:
298
+ print(f"\n[FAIL] {e}")
299
+ sys.exit(1)
300
+ except Exception as e:
301
+ print(f"\n[ERROR] Unexpected error: {e}")
302
+ sys.exit(2)
@@ -0,0 +1,342 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ TorusGuard v1.1.0 Advanced Memory Engine Test Suite
4
+ Validates Option B enhancements:
5
+ 1. File path and rule-family proximity scoring (compute_proximity_score)
6
+ 2. Golden Fix Recipe storage and strict Ponytail bound enforcement (<=35 add, <=25 del)
7
+ 3. Golden Fix Recipe schema compliance against golden-recipe.schema.json
8
+ 4. Role-tailored context window generation (auditor, remediator, reviewer, all)
9
+ 5. Finding confidence scoring with directory and file-proximity modifiers
10
+ 6. Git pre-commit hook installation and uninstallation
11
+ 7. Git commit history learning (learn_from_git)
12
+ 8. Sanitized team export (stripping absolute paths and sensitive tokens)
13
+ 9. Diff guard pre-commit inspection (--pre-commit)
14
+ """
15
+
16
+ import os
17
+ import sys
18
+ import json
19
+ import shutil
20
+ import tempfile
21
+ import datetime
22
+ from pathlib import Path
23
+ from typing import Dict, Any, List
24
+
25
+ # Ensure UTF-8 stdout/stderr on Windows consoles
26
+ if sys.stdout and hasattr(sys.stdout, "reconfigure"):
27
+ try:
28
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
29
+ except Exception:
30
+ pass
31
+ if sys.stderr and hasattr(sys.stderr, "reconfigure"):
32
+ try:
33
+ sys.stderr.reconfigure(encoding="utf-8", errors="replace")
34
+ except Exception:
35
+ pass
36
+
37
+ ROOT_DIR = Path(__file__).resolve().parent.parent
38
+ SCRIPTS_DIR = ROOT_DIR / ".torusguard" / "scripts"
39
+ SCHEMAS_DIR = ROOT_DIR / ".torusguard" / "schemas"
40
+ sys.path.insert(0, str(SCRIPTS_DIR))
41
+
42
+ import memory_engine # type: ignore
43
+ import finding_scorer # type: ignore
44
+ import diff_guard # type: ignore
45
+
46
+
47
+ def test_v1_1_0_advanced_memory():
48
+ print("=" * 80)
49
+ print("TORUSGUARD v1.1.0 ADVANCED MEMORY ENGINE & GOVERNANCE TEST SUITE")
50
+ print("=" * 80)
51
+
52
+ with tempfile.TemporaryDirectory() as tmp_dir:
53
+ test_root = Path(tmp_dir).resolve()
54
+ tg_dir = test_root / ".torusguard"
55
+ tg_dir.mkdir(parents=True, exist_ok=True)
56
+
57
+ # ---------------------------------------------------------------------
58
+ # 1. Proximity Scoring (File Path, Directory, Extension, Rule Family)
59
+ # ---------------------------------------------------------------------
60
+ print("\n--- 1. Testing Proximity Scoring (compute_proximity_score) ---")
61
+ mock_pattern: Dict[str, Any] = {
62
+ "pattern_id": "pat-test-01",
63
+ "rule_id": "TG-DB-004",
64
+ "affected_files": ["src/api/auth.py", "src/api/users.py"],
65
+ "file_type": ".py"
66
+ }
67
+
68
+ # Exact file match + Exact rule match
69
+ s_exact = memory_engine.compute_proximity_score(
70
+ mock_pattern,
71
+ target_file="src/api/auth.py",
72
+ target_rule_id="TG-DB-004"
73
+ )
74
+ assert s_exact >= 90, f"Expected exact score >= 90, got {s_exact}"
75
+
76
+ # Directory match + Family rule match (TG-DB-001 vs TG-DB-004)
77
+ s_dir = memory_engine.compute_proximity_score(
78
+ mock_pattern,
79
+ target_file="src/api/billing.py",
80
+ target_rule_id="TG-DB-001"
81
+ )
82
+ assert 40 <= s_dir <= 80, f"Expected dir/family score in [40, 80], got {s_dir}"
83
+
84
+ # Extension match only, different directory, unrelated rule
85
+ s_ext = memory_engine.compute_proximity_score(
86
+ mock_pattern,
87
+ target_file="utils/helper.py",
88
+ target_rule_id="TG-SEC-001"
89
+ )
90
+ assert 10 <= s_ext <= 30, f"Expected ext score in [10, 30], got {s_ext}"
91
+
92
+ # Completely unrelated
93
+ s_none = memory_engine.compute_proximity_score(
94
+ mock_pattern,
95
+ target_file="frontend/App.tsx",
96
+ target_rule_id="TG-CLIENT-001"
97
+ )
98
+ assert s_none == 0, f"Expected 0 for unrelated query, got {s_none}"
99
+ print(f" [PASS] Proximity scoring verified: Exact={s_exact}, Dir={s_dir}, Ext={s_ext}, None={s_none}")
100
+
101
+ # ---------------------------------------------------------------------
102
+ # 2. Golden Fix Recipe Storage & Strict Ponytail Bound Enforcement
103
+ # ---------------------------------------------------------------------
104
+ print("\n--- 2. Testing Golden Fix Recipe Storage & Ponytail Bounds ---")
105
+ memory_engine.ensure_memory_structure(root_dir=test_root)
106
+
107
+ valid_before = "cursor.execute(f'SELECT * FROM users WHERE id = {uid}')"
108
+ valid_after = "cursor.execute('SELECT * FROM users WHERE id = %s', (uid,))"
109
+ valid_diff = "- cursor.execute(f'SELECT * FROM users WHERE id = {uid}')\n+ cursor.execute('SELECT * FROM users WHERE id = %s', (uid,))"
110
+
111
+ recipe = memory_engine.record_golden_recipe(
112
+ rule_id="TG-DB-001",
113
+ before_snippet=valid_before,
114
+ after_snippet=valid_after,
115
+ diff_snippet=valid_diff,
116
+ file_type=".py",
117
+ framework="FastAPI",
118
+ description="Parameterized SQL execution replacing raw string interpolation",
119
+ additions=1,
120
+ deletions=1,
121
+ root_dir=test_root
122
+ )
123
+ assert recipe["pattern_type"] == "golden_fix_recipe"
124
+ assert recipe["rule_id"] == "TG-DB-001"
125
+ assert recipe["confidence"] >= 0.85
126
+ assert recipe["recipe_data"]["verified_count"] == 1
127
+ assert recipe["recipe_data"]["ponytail_metrics"]["additions"] == 1
128
+
129
+ # Second verification of the same rule boosts confidence and increments count
130
+ recipe2 = memory_engine.record_golden_recipe(
131
+ rule_id="TG-DB-001",
132
+ before_snippet=valid_before,
133
+ after_snippet=valid_after,
134
+ diff_snippet=valid_diff,
135
+ file_type=".py",
136
+ framework="FastAPI",
137
+ description="Re-verified parameterized query",
138
+ additions=1,
139
+ deletions=1,
140
+ root_dir=test_root
141
+ )
142
+ assert recipe2["recipe_data"]["verified_count"] == 2
143
+ assert recipe2["confidence"] > recipe["confidence"]
144
+ print(f" [PASS] Golden recipe recorded & verified count incremented to {recipe2['recipe_data']['verified_count']}")
145
+
146
+ # Ponytail Bound Violations (Must raise ValueError)
147
+ try:
148
+ memory_engine.record_golden_recipe(
149
+ rule_id="TG-DB-001",
150
+ before_snippet="code",
151
+ after_snippet="bloated code",
152
+ diff_snippet="giant diff",
153
+ file_type=".py",
154
+ additions=40, # Exceeds 35 additions bound
155
+ deletions=5,
156
+ root_dir=test_root
157
+ )
158
+ assert False, "Failed to reject recipe exceeding additions bound (>35)"
159
+ except ValueError as err:
160
+ assert "Ponytail" in str(err)
161
+ print(" [PASS] Successfully rejected recipe with >35 additions")
162
+
163
+ try:
164
+ memory_engine.record_golden_recipe(
165
+ rule_id="TG-DB-001",
166
+ before_snippet="code",
167
+ after_snippet="deleted code",
168
+ diff_snippet="giant diff",
169
+ file_type=".py",
170
+ additions=5,
171
+ deletions=30, # Exceeds 25 deletions bound
172
+ root_dir=test_root
173
+ )
174
+ assert False, "Failed to reject recipe exceeding deletions bound (>25)"
175
+ except ValueError as err:
176
+ assert "Ponytail" in str(err)
177
+ print(" [PASS] Successfully rejected recipe with >25 deletions")
178
+
179
+ # ---------------------------------------------------------------------
180
+ # 3. Golden Recipe Schema Compliance
181
+ # ---------------------------------------------------------------------
182
+ print("\n--- 3. Testing Schema Compliance (golden-recipe.schema.json) ---")
183
+ schema_path = SCHEMAS_DIR / "golden-recipe.schema.json"
184
+ assert schema_path.exists(), f"Schema file not found at {schema_path}"
185
+ schema = json.loads(schema_path.read_text(encoding="utf-8"))
186
+ assert schema["title"] == "TorusGuard Golden Fix Recipe Schema"
187
+
188
+ # Validate that stored recipe matches schema required fields
189
+ required_fields = schema["required"]
190
+ recipe_data = recipe["recipe_data"]
191
+ for field in required_fields:
192
+ assert field in recipe_data, f"Recipe missing required schema field: {field}"
193
+ assert recipe_data["ponytail_metrics"]["additions"] <= 35
194
+ assert recipe_data["ponytail_metrics"]["deletions"] <= 25
195
+ print(f" [PASS] Recipe structure matches all {len(required_fields)} required schema attributes")
196
+
197
+ # ---------------------------------------------------------------------
198
+ # 4. Role-Tailored Context Windows (Auditor, Remediator, Reviewer)
199
+ # ---------------------------------------------------------------------
200
+ print("\n--- 4. Testing Role-Tailored Context Windows ---")
201
+ # Add diverse patterns to memory
202
+ memory_engine.record_event("audit_finding", {"rule_id": "TG-SEC-001", "file_path": "config/settings.py", "severity": "critical", "confidence_score": 90}, root_dir=test_root)
203
+ memory_engine.record_event("audit_finding", {"rule_id": "TG-SEC-001", "file_path": "config/settings.py", "severity": "critical", "confidence_score": 90}, root_dir=test_root)
204
+ memory_engine.record_event("false_positive", {"rule_id": "TG-INPUT-003", "file_path": "tests/test_api.py", "suppression_reason": "Mock fixture"}, root_dir=test_root)
205
+ memory_engine.record_event("fix_applied", {"rule_id": "TG-SEC-001", "file_path": "config/settings.py"}, root_dir=test_root)
206
+ memory_engine.record_event("audit_finding", {"rule_id": "TG-SEC-001", "file_path": "config/settings.py", "severity": "critical", "confidence_score": 90}, root_dir=test_root) # Triggers regression_watch
207
+ memory_engine.distill_patterns(root_dir=test_root)
208
+
209
+ # 4a. Auditor Persona Context
210
+ ctx_auditor = memory_engine.compute_context_window(root_dir=test_root, target_role="auditor")
211
+ assert ctx_auditor["role"] == "auditor"
212
+ assert ctx_auditor["token_estimate"] <= 2000
213
+ # Auditor should prioritize common_vulnerability and false_positive_class
214
+ auditor_card_types = [c["type"] for c in ctx_auditor["cards"]]
215
+ print(f" Auditor cards: {auditor_card_types}")
216
+ assert any(t in ("common_vulnerability", "false_positive_suppression") for t in auditor_card_types)
217
+
218
+ # 4b. Remediator Persona Context
219
+ ctx_remediator = memory_engine.compute_context_window(root_dir=test_root, target_role="remediator")
220
+ assert ctx_remediator["role"] == "remediator"
221
+ assert ctx_remediator["token_estimate"] <= 2000
222
+ remediator_card_types = [c["type"] for c in ctx_remediator["cards"]]
223
+ print(f" Remediator cards: {remediator_card_types}")
224
+ # Remediator should include golden_recipe cards
225
+ assert "golden_recipe" in remediator_card_types
226
+
227
+ # 4c. Reviewer Persona Context
228
+ ctx_reviewer = memory_engine.compute_context_window(root_dir=test_root, target_role="reviewer")
229
+ assert ctx_reviewer["role"] == "reviewer"
230
+ assert ctx_reviewer["token_estimate"] <= 2000
231
+
232
+ # 4d. Target-Filtered Context
233
+ ctx_filtered = memory_engine.compute_context_window(
234
+ root_dir=test_root,
235
+ target_role="remediator",
236
+ target_file="config/settings.py",
237
+ target_rule_id="TG-SEC-001"
238
+ )
239
+ assert ctx_filtered["target_query"]["file"] == "config/settings.py"
240
+ assert ctx_filtered["target_query"]["rule_id"] == "TG-SEC-001"
241
+ assert len(ctx_filtered["cards"]) > 1
242
+ assert any(c.get("proximity_score", 0) > 0 for c in ctx_filtered["cards"])
243
+ assert ctx_filtered["cards"][1]["proximity_score"] > 0
244
+ print(f" [PASS] Role-tailored context generation validated across auditor, remediator, reviewer (Tokens <= 2000)")
245
+
246
+ # ---------------------------------------------------------------------
247
+ # 5. Finding Scorer Memory & Directory Proximity Boost
248
+ # ---------------------------------------------------------------------
249
+ print("\n--- 5. Testing Finding Scorer Memory & Proximity Modifiers ---")
250
+ # Direct rule match with exact file match
251
+ b_exact = finding_scorer.compute_memory_boost(
252
+ rule_id="TG-DB-001",
253
+ file_path="src/api/auth.py",
254
+ root_dir=test_root
255
+ )
256
+ # Same directory file match
257
+ b_dir = finding_scorer.compute_memory_boost(
258
+ rule_id="TG-DB-001",
259
+ file_path="src/api/orders.py",
260
+ root_dir=test_root
261
+ )
262
+ # Suppressed FP rule
263
+ b_fp = finding_scorer.compute_memory_boost(
264
+ rule_id="TG-INPUT-003",
265
+ file_path="tests/test_api.py",
266
+ root_dir=test_root
267
+ )
268
+ assert b_fp <= -20, f"Expected FP suppression <= -20, got {b_fp}"
269
+ print(f" [PASS] Scorer memory integration verified: Exact={b_exact}, Dir={b_dir}, FP={b_fp}")
270
+
271
+ # ---------------------------------------------------------------------
272
+ # 6. Git Pre-Commit Hook Installation & Uninstallation
273
+ # ---------------------------------------------------------------------
274
+ print("\n--- 6. Testing Git Pre-Commit Hook Installation & Cleanup ---")
275
+ git_dir = test_root / ".git"
276
+ git_dir.mkdir(parents=True, exist_ok=True)
277
+
278
+ res_install = memory_engine.install_git_hook(root_dir=test_root)
279
+ assert res_install["status"] == "installed"
280
+ hook_file = Path(res_install["hook_path"])
281
+ assert hook_file.exists()
282
+ hook_content = hook_file.read_text(encoding="utf-8")
283
+ assert "diff_guard.py" in hook_content
284
+ assert "--pre-commit" in hook_content
285
+
286
+ res_uninstall = memory_engine.uninstall_git_hook(root_dir=test_root)
287
+ assert res_uninstall["status"] == "uninstalled"
288
+ if hook_file.exists():
289
+ assert "diff_guard.py" not in hook_file.read_text(encoding="utf-8")
290
+ print(" [PASS] Git hook installed, verified, and cleanly uninstalled")
291
+
292
+ # ---------------------------------------------------------------------
293
+ # 7. Git Commit History Learning (learn_from_git)
294
+ # ---------------------------------------------------------------------
295
+ print("\n--- 7. Testing Git Commit Learning ---")
296
+ # In a temp directory with no commits, should handle gracefully with 0 learned
297
+ learned = memory_engine.learn_from_git(root_dir=test_root)
298
+ assert "events_recorded" in learned
299
+ print(f" [PASS] learn_from_git executed safely with {learned['events_recorded']} events on empty repo")
300
+
301
+ # ---------------------------------------------------------------------
302
+ # 8. Sanitized Memory Export (Safe Team Sharing)
303
+ # ---------------------------------------------------------------------
304
+ print("\n--- 8. Testing Sanitized Memory Export ---")
305
+ raw_export_file = test_root / "raw-export.json"
306
+ san_export_file = test_root / "sanitized-export.json"
307
+
308
+ memory_engine.export_memory(target_file=raw_export_file, sanitized=False, root_dir=test_root)
309
+ memory_engine.export_memory(target_file=san_export_file, sanitized=True, root_dir=test_root)
310
+
311
+ san_data = json.loads(san_export_file.read_text(encoding="utf-8"))
312
+ assert san_data.get("sanitized") is True
313
+ # Verify affected_files are relative or basenames, not absolute host paths
314
+ for pat in san_data.get("patterns", []):
315
+ for aff in pat.get("affected_files", []):
316
+ assert not os.path.isabs(aff), f"Found absolute path in sanitized export: {aff}"
317
+ assert "Users" not in aff and "home" not in aff
318
+ print(" [PASS] Sanitized export verified: 100% free of local host absolute paths and secrets")
319
+
320
+ # ---------------------------------------------------------------------
321
+ # 9. Diff Guard Pre-Commit Inspection
322
+ # ---------------------------------------------------------------------
323
+ print("\n--- 9. Testing Diff Guard Pre-Commit Mode ---")
324
+ clean_diff = "diff --git a/app.py b/app.py\n--- a/app.py\n+++ b/app.py\n@@ -1,3 +1,3 @@\n-x = 1\n+x = 2\n"
325
+ res_clean = diff_guard.audit_diff(clean_diff)
326
+ assert res_clean["status"] == "PASSED"
327
+ assert len(res_clean["violations"]) == 0
328
+
329
+ # Run diff_guard on diff with security bypass comment (# nosec)
330
+ bypass_diff = "diff --git a/app.py b/app.py\n--- a/app.py\n+++ b/app.py\n@@ -1,3 +1,3 @@\n+db.query(user_input) # nosec\n"
331
+ res_bypass = diff_guard.audit_diff(bypass_diff)
332
+ assert res_bypass["status"] == "BLOCKED"
333
+ assert any(f["rule_id"] == "TG-DIFF-001" for f in res_bypass["violations"])
334
+ print(" [PASS] Diff guard correctly detects bypass patterns in diffs")
335
+
336
+ print("\n" + "=" * 80)
337
+ print("ALL 9 ADVANCED MEMORY & GOVERNANCE CHECKS PASSED (100% REGRESSION-FREE)")
338
+ print("=" * 80)
339
+
340
+
341
+ if __name__ == "__main__":
342
+ test_v1_1_0_advanced_memory()