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.
- package/.torusguard/.manifest.json +113 -9
- package/.torusguard/rules/README.md +93 -62
- package/.torusguard/rules/TG-AUTH-001-weak-password-storage.md +103 -0
- package/.torusguard/rules/TG-AUTH-002-client-only-authorization.md +85 -0
- package/.torusguard/rules/TG-AUTH-003-missing-object-authorization.md +85 -0
- package/.torusguard/rules/TG-AUTH-004-insecure-session-cookie.md +96 -0
- package/.torusguard/rules/TG-AUTH-005-unsafe-password-reset.md +104 -0
- package/.torusguard/rules/TG-CLIENT-001-public-production-source-maps.md +102 -0
- package/.torusguard/rules/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
- package/.torusguard/rules/TG-DB-001-frontend-database-query.md +83 -0
- package/.torusguard/rules/TG-DB-002-privileged-database-credential.md +86 -0
- package/.torusguard/rules/TG-DB-003-frontend-admin-sdk.md +91 -0
- package/.torusguard/rules/TG-DB-004-missing-tenant-query-isolation.md +103 -0
- package/.torusguard/rules/TG-INPUT-001-missing-server-validation.md +98 -0
- package/.torusguard/rules/TG-INPUT-002-raw-sql-concatenation.md +94 -0
- package/.torusguard/rules/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
- package/.torusguard/rules/TG-INPUT-004-unrestricted-file-upload.md +92 -0
- package/.torusguard/rules/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
- package/.torusguard/rules/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
- package/.torusguard/rules/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
- package/.torusguard/rules/TG-PLATFORM-002-missing-security-headers.md +95 -0
- package/.torusguard/rules/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
- package/.torusguard/rules/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
- package/.torusguard/rules/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
- package/.torusguard/rules/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
- package/.torusguard/rules/TG-RATE-003-unbounded-resource-consumption.md +105 -0
- package/.torusguard/rules/TG-SEC-001-hardcoded-secrets.md +83 -0
- package/.torusguard/rules/TG-SEC-002-public-environment-secrets.md +83 -0
- package/.torusguard/rules/TG-SEC-003-tracked-env-file.md +79 -0
- package/.torusguard/rules/TG-SEC-004-sensitive-logging.md +83 -0
- package/.torusguard/rules/active/TG-AUTH-001-weak-password-storage.md +103 -0
- package/.torusguard/rules/active/TG-AUTH-002-client-only-authorization.md +85 -0
- package/.torusguard/rules/active/TG-AUTH-003-missing-object-authorization.md +85 -0
- package/.torusguard/rules/active/TG-AUTH-004-insecure-session-cookie.md +96 -0
- package/.torusguard/rules/active/TG-AUTH-005-unsafe-password-reset.md +104 -0
- package/.torusguard/rules/active/TG-CLIENT-001-public-production-source-maps.md +102 -0
- package/.torusguard/rules/active/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
- package/.torusguard/rules/active/TG-DB-001-frontend-database-query.md +83 -0
- package/.torusguard/rules/active/TG-DB-002-privileged-database-credential.md +86 -0
- package/.torusguard/rules/active/TG-DB-003-frontend-admin-sdk.md +91 -0
- package/.torusguard/rules/active/TG-DB-004-missing-tenant-query-isolation.md +103 -0
- package/.torusguard/rules/active/TG-INPUT-001-missing-server-validation.md +98 -0
- package/.torusguard/rules/active/TG-INPUT-002-raw-sql-concatenation.md +94 -0
- package/.torusguard/rules/active/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
- package/.torusguard/rules/active/TG-INPUT-004-unrestricted-file-upload.md +92 -0
- package/.torusguard/rules/active/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
- package/.torusguard/rules/active/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
- package/.torusguard/rules/active/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
- package/.torusguard/rules/active/TG-PLATFORM-002-missing-security-headers.md +95 -0
- package/.torusguard/rules/active/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
- package/.torusguard/rules/active/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
- package/.torusguard/rules/active/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
- package/.torusguard/rules/active/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
- package/.torusguard/rules/active/TG-RATE-003-unbounded-resource-consumption.md +105 -0
- package/.torusguard/rules/active/TG-SEC-001-hardcoded-secrets.md +83 -0
- package/.torusguard/rules/active/TG-SEC-002-public-environment-secrets.md +83 -0
- package/.torusguard/rules/active/TG-SEC-003-tracked-env-file.md +79 -0
- package/.torusguard/rules/active/TG-SEC-004-sensitive-logging.md +83 -0
- package/.torusguard/rules/agent/TG-AGENT-001-prompt-injection-system-context.md +56 -0
- package/.torusguard/rules/agent/TG-AGENT-002-unsafe-tool-dispatch-unsandboxed-execution.md +68 -0
- package/.torusguard/rules/agent/TG-AGENT-003-broad-mcp-tool-scoping.md +53 -0
- package/.torusguard/rules/agent/TG-AGENT-004-persistent-memory-cross-session-leakage.md +67 -0
- package/.torusguard/rules/authorization/TG-AUTH-006-mass-assignment.md +70 -0
- package/.torusguard/rules/authorization/TG-AUTH-007-missing-property-level-authorization.md +71 -0
- package/.torusguard/rules/authorization/TG-AUTH-008-untrusted-role-header-injection.md +112 -0
- package/.torusguard/rules/business-logic/TG-BIZ-001-client-controlled-sensitive-business-value.md +37 -0
- package/.torusguard/rules/business-logic/TG-BIZ-002-replayable-one-time-operation.md +37 -0
- package/.torusguard/rules/business-logic/TG-BIZ-003-missing-workflow-state-validation.md +37 -0
- package/.torusguard/rules/business-logic/TG-BIZ-004-unrestricted-sensitive-business-flow.md +37 -0
- package/.torusguard/rules/cache/TG-CACHE-001-sensitive-response-publicly-cacheable.md +37 -0
- package/.torusguard/rules/cache/TG-CACHE-002-missing-user-cache-isolation.md +37 -0
- package/.torusguard/rules/cache/TG-CACHE-003-sensitive-data-in-url.md +37 -0
- package/.torusguard/rules/csrf/TG-CSRF-001-missing-csrf-protection.md +37 -0
- package/.torusguard/rules/csrf/TG-CSRF-002-unsafe-credentialed-cross-origin-request.md +37 -0
- package/.torusguard/rules/edge/TG-EDGE-001-serverless-global-state-leak.md +83 -0
- package/.torusguard/rules/edge/TG-EDGE-003-aws-lambda-ephemeral-cold-start.md +76 -0
- package/.torusguard/rules/graphql/TG-GQL-001-missing-query-depth-or-complexity-limits.md +64 -0
- package/.torusguard/rules/graphql/TG-GQL-002-resolver-missing-authorization.md +37 -0
- package/.torusguard/rules/graphql/TG-GQL-003-unbounded-graphql-pagination-or-batching.md +37 -0
- package/.torusguard/rules/graphql/TG-GQL-004-unnecessary-production-introspection.md +37 -0
- package/.torusguard/rules/secrets/TG-SEC-005-secret-in-git-history.md +37 -0
- package/.torusguard/rules/secrets/TG-SEC-006-secret-in-build-artifact.md +37 -0
- package/.torusguard/rules/secrets/TG-SEC-007-secret-in-test-or-example-fixture.md +37 -0
- package/.torusguard/rules/ssrf/TG-SSRF-001-user-controlled-server-side-url-fetch.md +68 -0
- package/.torusguard/rules/ssrf/TG-SSRF-002-missing-internal-network-protection.md +37 -0
- package/.torusguard/rules/ssrf/TG-SSRF-003-unsafe-redirect-following.md +37 -0
- package/.torusguard/rules/ssrf/TG-SSRF-004-unbounded-outbound-request.md +37 -0
- package/.torusguard/rules/supply-chain/TG-SUPPLY-001-missing-or-ignored-dependency-lockfile.md +37 -0
- package/.torusguard/rules/supply-chain/TG-SUPPLY-002-vulnerable-dependency-review-missing.md +94 -0
- package/.torusguard/rules/supply-chain/TG-SUPPLY-003-unsafe-ci-cd-secret-exposure.md +37 -0
- package/.torusguard/rules/supply-chain/TG-SUPPLY-004-unpinned-ci-action.md +37 -0
- package/.torusguard/rules/supply-chain/TG-SUPPLY-005-unsafe-dependency-install-script.md +37 -0
- package/.torusguard/rules/supply-chain/TG-SUPPLY-006-container-build-secret-persistence.md +61 -0
- package/.torusguard/rules/webhook/TG-WEBHOOK-001-missing-webhook-signature-verification.md +37 -0
- package/.torusguard/rules/webhook/TG-WEBHOOK-002-replayable-webhook.md +37 -0
- package/.torusguard/rules/webhook/TG-WEBHOOK-003-missing-webhook-idempotency.md +37 -0
- package/.torusguard/rules/webhook/TG-WEBHOOK-004-unvalidated-webhook-event-type.md +37 -0
- package/.torusguard/rules/websocket/TG-WS-001-unauthenticated-websocket-handshake.md +82 -0
- package/.torusguard/rules/websocket/TG-WS-002-missing-channel-level-authorization.md +37 -0
- package/.torusguard/rules/websocket/TG-WS-003-unvalidated-websocket-message.md +37 -0
- package/.torusguard/rules/websocket/TG-WS-004-unbounded-websocket-connections.md +37 -0
- package/.torusguard/runs/report-latest.html +62 -20
- package/.torusguard/runs/run-20260908-112648-audit/findings.json +1520 -0
- package/.torusguard/runs/run-20260908-112648-audit/findings.md +560 -0
- package/.torusguard/runs/run-20260908-112648-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260908-112648-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260908-112722-audit/findings.json +1520 -0
- package/.torusguard/runs/run-20260908-112722-audit/findings.md +560 -0
- package/.torusguard/runs/run-20260908-112722-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260908-112722-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260908-113004-audit/findings.json +1520 -0
- package/.torusguard/runs/run-20260908-113004-audit/findings.md +560 -0
- package/.torusguard/runs/run-20260908-113004-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260908-113004-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-115-9a059e/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-115-9a059e/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-115-9a059e/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-119-61557c/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-119-61557c/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-119-61557c/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-265-996ca3/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-265-996ca3/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-265-996ca3/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-334-cb819d/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-334-cb819d/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-334-cb819d/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-503-d11cf8/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-503-d11cf8/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-503-d11cf8/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-79-91f41f/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-79-91f41f/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-79-91f41f/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-107-516a40/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-107-516a40/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-107-516a40/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-128-7809a1/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-128-7809a1/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-128-7809a1/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-232-1b45d1/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-232-1b45d1/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-232-1b45d1/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-003-53-d167b4/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-003-53-d167b4/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-003-53-d167b4/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-209-4f6424/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-209-4f6424/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-209-4f6424/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-257-89bf34/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-257-89bf34/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-257-89bf34/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-341-ce228c/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-341-ce228c/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-341-ce228c/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-355-7b190b/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-355-7b190b/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-355-7b190b/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-64-5af31a/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-64-5af31a/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-64-5af31a/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-9-f51467/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-9-f51467/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-9-f51467/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/findings.json +1520 -0
- package/.torusguard/runs/run-20260908-113127-audit/findings.md +560 -0
- package/.torusguard/runs/run-20260908-113127-audit/manifest.json +13 -0
- package/.torusguard/runs/run-20260908-113127-audit/remediation.md +262 -0
- package/.torusguard/runs/run-20260908-113127-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260908-115240-audit/apply_plan.md +6 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-115-9a059e/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-115-9a059e/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-115-9a059e/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-119-61557c/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-119-61557c/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-119-61557c/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-265-996ca3/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-265-996ca3/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-265-996ca3/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-334-cb819d/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-334-cb819d/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-334-cb819d/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-503-d11cf8/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-503-d11cf8/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-503-d11cf8/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-79-91f41f/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-79-91f41f/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-79-91f41f/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-107-516a40/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-107-516a40/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-107-516a40/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-128-7809a1/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-128-7809a1/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-128-7809a1/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-232-1b45d1/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-232-1b45d1/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-232-1b45d1/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-003-53-d167b4/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-003-53-d167b4/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-003-53-d167b4/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-platform-001-168-5027cb/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-platform-001-168-5027cb/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-platform-001-168-5027cb/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-209-4f6424/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-209-4f6424/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-209-4f6424/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-257-89bf34/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-257-89bf34/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-257-89bf34/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-341-ce228c/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-341-ce228c/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-341-ce228c/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-355-7b190b/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-355-7b190b/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-355-7b190b/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-64-5af31a/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-64-5af31a/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-64-5af31a/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-9-f51467/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-9-f51467/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-9-f51467/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/diff_summary.md +221 -0
- package/.torusguard/runs/run-20260908-115240-audit/findings.json +1553 -0
- package/.torusguard/runs/run-20260908-115240-audit/findings.md +572 -0
- package/.torusguard/runs/run-20260908-115240-audit/manifest.json +14 -0
- package/.torusguard/runs/run-20260908-115240-audit/recheck.md +91 -0
- package/.torusguard/runs/run-20260908-115240-audit/remediation.md +278 -0
- package/.torusguard/runs/run-20260908-115240-audit/summary.md +5 -0
- package/.torusguard/scripts/__pycache__/audit_runner.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/finding_scorer.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/memory_engine.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/monorepo_detector.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/run_manager.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/stack_detect.cpython-311.pyc +0 -0
- package/.torusguard/scripts/apply_runner.py +339 -0
- package/.torusguard/scripts/audit_runner.py +550 -0
- package/.torusguard/scripts/diff_guard.py +52 -4
- package/.torusguard/scripts/finding_scorer.py +58 -0
- package/.torusguard/scripts/harden_runner.py +375 -0
- package/.torusguard/scripts/html_reporter.py +25 -10
- package/.torusguard/scripts/manifest_builder.py +2 -0
- package/.torusguard/scripts/memory_engine.py +4 -0
- package/.torusguard/scripts/recheck_runner.py +221 -0
- package/.torusguard/scripts/recipes_runner.py +130 -0
- package/.torusguard/scripts/run_manager.py +17 -5
- package/.torusguard/skills/torusguard/SKILL.md +42 -42
- package/.torusguard/skills/torusguard/bootstrap.py +149 -70
- package/.torusguard/snapshots/run-20260908-115240-audit/examples/vulnerable-react-express/client/src/App.jsx.bak +63 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/examples/vulnerable-react-express/server/index.js.bak +82 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/engine/fixture_manager.py.bak +245 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/master_validation.py.bak +698 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/runner.py.bak +551 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_e2e.py.bak +498 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_qa_v0_6_0.py.bak +572 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v0_6_1_scale.py.bak +371 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v0_6_2_modern_stacks.py.bak +462 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v0_6_3_hardening.py.bak +444 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v1_0_0_memory.py.bak +302 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v1_1_0_advanced_memory.py.bak +342 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/skills/torusguard/payload/scripts/harden_runner.py.bak +353 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/tests/test_v0_6_0_governed_remediation.py.bak +353 -0
- package/README.md +70 -33
- package/bin/torusguard.js +92 -22
- package/package.json +1 -1
- package/skills/torusguard/SKILL.md +42 -42
- package/skills/torusguard/bootstrap.py +147 -68
- package/skills/torusguard/payload/.manifest.json +113 -9
- package/skills/torusguard/payload/rules/README.md +93 -62
- package/skills/torusguard/payload/rules/TG-AUTH-001-weak-password-storage.md +103 -0
- package/skills/torusguard/payload/rules/TG-AUTH-002-client-only-authorization.md +85 -0
- package/skills/torusguard/payload/rules/TG-AUTH-003-missing-object-authorization.md +85 -0
- package/skills/torusguard/payload/rules/TG-AUTH-004-insecure-session-cookie.md +96 -0
- package/skills/torusguard/payload/rules/TG-AUTH-005-unsafe-password-reset.md +104 -0
- package/skills/torusguard/payload/rules/TG-CLIENT-001-public-production-source-maps.md +102 -0
- package/skills/torusguard/payload/rules/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
- package/skills/torusguard/payload/rules/TG-DB-001-frontend-database-query.md +83 -0
- package/skills/torusguard/payload/rules/TG-DB-002-privileged-database-credential.md +86 -0
- package/skills/torusguard/payload/rules/TG-DB-003-frontend-admin-sdk.md +91 -0
- package/skills/torusguard/payload/rules/TG-DB-004-missing-tenant-query-isolation.md +103 -0
- package/skills/torusguard/payload/rules/TG-INPUT-001-missing-server-validation.md +98 -0
- package/skills/torusguard/payload/rules/TG-INPUT-002-raw-sql-concatenation.md +94 -0
- package/skills/torusguard/payload/rules/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
- package/skills/torusguard/payload/rules/TG-INPUT-004-unrestricted-file-upload.md +92 -0
- package/skills/torusguard/payload/rules/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
- package/skills/torusguard/payload/rules/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
- package/skills/torusguard/payload/rules/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
- package/skills/torusguard/payload/rules/TG-PLATFORM-002-missing-security-headers.md +95 -0
- package/skills/torusguard/payload/rules/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
- package/skills/torusguard/payload/rules/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
- package/skills/torusguard/payload/rules/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
- package/skills/torusguard/payload/rules/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
- package/skills/torusguard/payload/rules/TG-RATE-003-unbounded-resource-consumption.md +105 -0
- package/skills/torusguard/payload/rules/TG-SEC-001-hardcoded-secrets.md +83 -0
- package/skills/torusguard/payload/rules/TG-SEC-002-public-environment-secrets.md +83 -0
- package/skills/torusguard/payload/rules/TG-SEC-003-tracked-env-file.md +79 -0
- package/skills/torusguard/payload/rules/TG-SEC-004-sensitive-logging.md +83 -0
- package/skills/torusguard/payload/rules/active/TG-AUTH-001-weak-password-storage.md +103 -0
- package/skills/torusguard/payload/rules/active/TG-AUTH-002-client-only-authorization.md +85 -0
- package/skills/torusguard/payload/rules/active/TG-AUTH-003-missing-object-authorization.md +85 -0
- package/skills/torusguard/payload/rules/active/TG-AUTH-004-insecure-session-cookie.md +96 -0
- package/skills/torusguard/payload/rules/active/TG-AUTH-005-unsafe-password-reset.md +104 -0
- package/skills/torusguard/payload/rules/active/TG-CLIENT-001-public-production-source-maps.md +102 -0
- package/skills/torusguard/payload/rules/active/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
- package/skills/torusguard/payload/rules/active/TG-DB-001-frontend-database-query.md +83 -0
- package/skills/torusguard/payload/rules/active/TG-DB-002-privileged-database-credential.md +86 -0
- package/skills/torusguard/payload/rules/active/TG-DB-003-frontend-admin-sdk.md +91 -0
- package/skills/torusguard/payload/rules/active/TG-DB-004-missing-tenant-query-isolation.md +103 -0
- package/skills/torusguard/payload/rules/active/TG-INPUT-001-missing-server-validation.md +98 -0
- package/skills/torusguard/payload/rules/active/TG-INPUT-002-raw-sql-concatenation.md +94 -0
- package/skills/torusguard/payload/rules/active/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
- package/skills/torusguard/payload/rules/active/TG-INPUT-004-unrestricted-file-upload.md +92 -0
- package/skills/torusguard/payload/rules/active/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
- package/skills/torusguard/payload/rules/active/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
- package/skills/torusguard/payload/rules/active/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
- package/skills/torusguard/payload/rules/active/TG-PLATFORM-002-missing-security-headers.md +95 -0
- package/skills/torusguard/payload/rules/active/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
- package/skills/torusguard/payload/rules/active/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
- package/skills/torusguard/payload/rules/active/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
- package/skills/torusguard/payload/rules/active/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
- package/skills/torusguard/payload/rules/active/TG-RATE-003-unbounded-resource-consumption.md +105 -0
- package/skills/torusguard/payload/rules/active/TG-SEC-001-hardcoded-secrets.md +83 -0
- package/skills/torusguard/payload/rules/active/TG-SEC-002-public-environment-secrets.md +83 -0
- package/skills/torusguard/payload/rules/active/TG-SEC-003-tracked-env-file.md +79 -0
- package/skills/torusguard/payload/rules/active/TG-SEC-004-sensitive-logging.md +83 -0
- package/skills/torusguard/payload/rules/agent/TG-AGENT-001-prompt-injection-system-context.md +56 -0
- package/skills/torusguard/payload/rules/agent/TG-AGENT-002-unsafe-tool-dispatch-unsandboxed-execution.md +68 -0
- package/skills/torusguard/payload/rules/agent/TG-AGENT-003-broad-mcp-tool-scoping.md +53 -0
- package/skills/torusguard/payload/rules/agent/TG-AGENT-004-persistent-memory-cross-session-leakage.md +67 -0
- package/skills/torusguard/payload/rules/authorization/TG-AUTH-006-mass-assignment.md +70 -0
- package/skills/torusguard/payload/rules/authorization/TG-AUTH-007-missing-property-level-authorization.md +71 -0
- package/skills/torusguard/payload/rules/authorization/TG-AUTH-008-untrusted-role-header-injection.md +112 -0
- package/skills/torusguard/payload/rules/business-logic/TG-BIZ-001-client-controlled-sensitive-business-value.md +37 -0
- package/skills/torusguard/payload/rules/business-logic/TG-BIZ-002-replayable-one-time-operation.md +37 -0
- package/skills/torusguard/payload/rules/business-logic/TG-BIZ-003-missing-workflow-state-validation.md +37 -0
- package/skills/torusguard/payload/rules/business-logic/TG-BIZ-004-unrestricted-sensitive-business-flow.md +37 -0
- package/skills/torusguard/payload/rules/cache/TG-CACHE-001-sensitive-response-publicly-cacheable.md +37 -0
- package/skills/torusguard/payload/rules/cache/TG-CACHE-002-missing-user-cache-isolation.md +37 -0
- package/skills/torusguard/payload/rules/cache/TG-CACHE-003-sensitive-data-in-url.md +37 -0
- package/skills/torusguard/payload/rules/csrf/TG-CSRF-001-missing-csrf-protection.md +37 -0
- package/skills/torusguard/payload/rules/csrf/TG-CSRF-002-unsafe-credentialed-cross-origin-request.md +37 -0
- package/skills/torusguard/payload/rules/edge/TG-EDGE-001-serverless-global-state-leak.md +83 -0
- package/skills/torusguard/payload/rules/edge/TG-EDGE-003-aws-lambda-ephemeral-cold-start.md +76 -0
- package/skills/torusguard/payload/rules/graphql/TG-GQL-001-missing-query-depth-or-complexity-limits.md +64 -0
- package/skills/torusguard/payload/rules/graphql/TG-GQL-002-resolver-missing-authorization.md +37 -0
- package/skills/torusguard/payload/rules/graphql/TG-GQL-003-unbounded-graphql-pagination-or-batching.md +37 -0
- package/skills/torusguard/payload/rules/graphql/TG-GQL-004-unnecessary-production-introspection.md +37 -0
- package/skills/torusguard/payload/rules/secrets/TG-SEC-005-secret-in-git-history.md +37 -0
- package/skills/torusguard/payload/rules/secrets/TG-SEC-006-secret-in-build-artifact.md +37 -0
- package/skills/torusguard/payload/rules/secrets/TG-SEC-007-secret-in-test-or-example-fixture.md +37 -0
- package/skills/torusguard/payload/rules/ssrf/TG-SSRF-001-user-controlled-server-side-url-fetch.md +68 -0
- package/skills/torusguard/payload/rules/ssrf/TG-SSRF-002-missing-internal-network-protection.md +37 -0
- package/skills/torusguard/payload/rules/ssrf/TG-SSRF-003-unsafe-redirect-following.md +37 -0
- package/skills/torusguard/payload/rules/ssrf/TG-SSRF-004-unbounded-outbound-request.md +37 -0
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-001-missing-or-ignored-dependency-lockfile.md +37 -0
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-002-vulnerable-dependency-review-missing.md +94 -0
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-003-unsafe-ci-cd-secret-exposure.md +37 -0
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-004-unpinned-ci-action.md +37 -0
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-005-unsafe-dependency-install-script.md +37 -0
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-006-container-build-secret-persistence.md +61 -0
- package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-001-missing-webhook-signature-verification.md +37 -0
- package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-002-replayable-webhook.md +37 -0
- package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-003-missing-webhook-idempotency.md +37 -0
- package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-004-unvalidated-webhook-event-type.md +37 -0
- package/skills/torusguard/payload/rules/websocket/TG-WS-001-unauthenticated-websocket-handshake.md +82 -0
- package/skills/torusguard/payload/rules/websocket/TG-WS-002-missing-channel-level-authorization.md +37 -0
- package/skills/torusguard/payload/rules/websocket/TG-WS-003-unvalidated-websocket-message.md +37 -0
- package/skills/torusguard/payload/rules/websocket/TG-WS-004-unbounded-websocket-connections.md +37 -0
- package/skills/torusguard/payload/scripts/apply_runner.py +339 -0
- package/skills/torusguard/payload/scripts/audit_runner.py +550 -0
- package/skills/torusguard/payload/scripts/diff_guard.py +52 -4
- package/skills/torusguard/payload/scripts/finding_scorer.py +58 -0
- package/skills/torusguard/payload/scripts/harden_runner.py +375 -0
- package/skills/torusguard/payload/scripts/html_reporter.py +25 -10
- package/skills/torusguard/payload/scripts/manifest_builder.py +2 -0
- package/skills/torusguard/payload/scripts/memory_engine.py +4 -0
- package/skills/torusguard/payload/scripts/recheck_runner.py +221 -0
- package/skills/torusguard/payload/scripts/recipes_runner.py +130 -0
- package/skills/torusguard/payload/scripts/run_manager.py +17 -5
- package/skills/torusguard/payload/skills/torusguard/SKILL.md +42 -42
- package/skills/torusguard/payload/skills/torusguard/bootstrap.py +147 -68
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TorusGuard Validation Harness & Engine Runner (v0.5.4)
|
|
3
|
+
Executes comprehensive validation engine cycles: deterministic replay, differential comparison, regression tracking, and schema validation.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
import json
|
|
9
|
+
import re
|
|
10
|
+
import glob
|
|
11
|
+
import shutil
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Dict, List, Tuple, Any
|
|
14
|
+
|
|
15
|
+
# Add project root to sys.path
|
|
16
|
+
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
|
17
|
+
sys.path.insert(0, str(PROJECT_ROOT))
|
|
18
|
+
|
|
19
|
+
from core.models import (
|
|
20
|
+
Finding,
|
|
21
|
+
Evidence,
|
|
22
|
+
Remediation,
|
|
23
|
+
FrameworkPattern,
|
|
24
|
+
AffectedComponent,
|
|
25
|
+
ReproductionMethod,
|
|
26
|
+
RetestRecord,
|
|
27
|
+
NotesRecord,
|
|
28
|
+
FindingTimestamps,
|
|
29
|
+
ProvenanceChain,
|
|
30
|
+
ConfidenceScore,
|
|
31
|
+
ConfidenceFactors,
|
|
32
|
+
ConfidenceBand,
|
|
33
|
+
SeverityLevel,
|
|
34
|
+
SeverityInfo,
|
|
35
|
+
RemediationPriority,
|
|
36
|
+
FindingStatus,
|
|
37
|
+
LifecycleStage,
|
|
38
|
+
TaxonomyCategory,
|
|
39
|
+
EvidenceType,
|
|
40
|
+
AuditReport,
|
|
41
|
+
mask_sensitive_data,
|
|
42
|
+
)
|
|
43
|
+
from core.lifecycle import FindingLifecycleManager, LifecycleTransitionError
|
|
44
|
+
from core.formatter import ReportFormatter
|
|
45
|
+
|
|
46
|
+
from harness.engine.models import (
|
|
47
|
+
ValidationOutcome,
|
|
48
|
+
FixtureDefinition,
|
|
49
|
+
FixtureVariant,
|
|
50
|
+
ReplayResult,
|
|
51
|
+
ComparisonResult,
|
|
52
|
+
RegressionRecord,
|
|
53
|
+
ValidationRunReport,
|
|
54
|
+
)
|
|
55
|
+
from harness.engine.fixture_manager import FixtureManager
|
|
56
|
+
from harness.engine.replay_runner import ReplayRunner
|
|
57
|
+
from harness.engine.comparator import ResultComparator
|
|
58
|
+
from harness.engine.regression_tracker import RegressionTracker
|
|
59
|
+
from harness.engine.fp_analyzer import FalsePositiveAnalyzer
|
|
60
|
+
from harness.engine.evidence_collector import ValidationEvidenceCollector
|
|
61
|
+
from harness.engine.report_emitter import ValidationReportEmitter
|
|
62
|
+
|
|
63
|
+
from core.run_folder import RunFolder
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class ValidationHarnessRunner:
|
|
67
|
+
def __init__(self, root_dir: str = "."):
|
|
68
|
+
self.root_dir = Path(root_dir).resolve()
|
|
69
|
+
self.passed_tests = 0
|
|
70
|
+
self.failed_tests = 0
|
|
71
|
+
self.results: List[Dict[str, Any]] = []
|
|
72
|
+
|
|
73
|
+
def log_test(self, test_name: str, passed: bool, message: str = ""):
|
|
74
|
+
if passed:
|
|
75
|
+
self.passed_tests += 1
|
|
76
|
+
print(f" [PASS] {test_name}")
|
|
77
|
+
else:
|
|
78
|
+
self.failed_tests += 1
|
|
79
|
+
print(f" [FAIL] {test_name}: {message}")
|
|
80
|
+
self.results.append({"name": test_name, "passed": passed, "message": message})
|
|
81
|
+
|
|
82
|
+
def run_all(self) -> bool:
|
|
83
|
+
print("=" * 80)
|
|
84
|
+
print("TORUSGUARD v0.5.4 REPORTING USABILITY & VALIDATION HARNESS")
|
|
85
|
+
print("=" * 80)
|
|
86
|
+
|
|
87
|
+
self.test_schema_integrity()
|
|
88
|
+
self.test_rule_catalog()
|
|
89
|
+
self.test_skill_definition()
|
|
90
|
+
self.test_confidence_scoring_model()
|
|
91
|
+
self.test_provenance_and_evidence_hashing()
|
|
92
|
+
self.test_sensitive_data_masking()
|
|
93
|
+
self.test_retest_lifecycle_closure()
|
|
94
|
+
self.test_validation_engine_subsystem()
|
|
95
|
+
self.test_stack_detection_fixtures()
|
|
96
|
+
self.test_educational_differential_fixtures()
|
|
97
|
+
self.test_regression_fixtures()
|
|
98
|
+
self.test_report_formatting()
|
|
99
|
+
self.test_run_context_and_ponytail()
|
|
100
|
+
self.test_v6_governed_remediation_suite()
|
|
101
|
+
|
|
102
|
+
print("-" * 80)
|
|
103
|
+
print(f"SUMMARY: {self.passed_tests} Passed | {self.failed_tests} Failed")
|
|
104
|
+
print("=" * 80)
|
|
105
|
+
return self.failed_tests == 0
|
|
106
|
+
|
|
107
|
+
def test_schema_integrity(self):
|
|
108
|
+
print("\n1. Testing Formal Schema Integrity (v0.5.4)...")
|
|
109
|
+
schemas_dir = self.root_dir / "schemas"
|
|
110
|
+
required_schemas = [
|
|
111
|
+
"finding.schema.json",
|
|
112
|
+
"evidence.schema.json",
|
|
113
|
+
"remediation.schema.json",
|
|
114
|
+
"rule.schema.json",
|
|
115
|
+
"lifecycle.schema.json",
|
|
116
|
+
"provenance.schema.json",
|
|
117
|
+
"confidence.schema.json",
|
|
118
|
+
"retest.schema.json",
|
|
119
|
+
"fixture.schema.json",
|
|
120
|
+
"validation-run.schema.json",
|
|
121
|
+
]
|
|
122
|
+
for s in required_schemas:
|
|
123
|
+
schema_path = schemas_dir / s
|
|
124
|
+
if not schema_path.exists():
|
|
125
|
+
self.log_test(f"Schema file exists: {s}", False, "File missing")
|
|
126
|
+
continue
|
|
127
|
+
try:
|
|
128
|
+
with open(schema_path, "r", encoding="utf-8") as f:
|
|
129
|
+
data = json.load(f)
|
|
130
|
+
valid = "$schema" in data and "title" in data
|
|
131
|
+
self.log_test(f"Schema valid JSON: {s}", valid, "Missing $schema or title")
|
|
132
|
+
except Exception as e:
|
|
133
|
+
self.log_test(f"Schema valid JSON: {s}", False, str(e))
|
|
134
|
+
|
|
135
|
+
def test_rule_catalog(self):
|
|
136
|
+
print("\n2. Testing Rule Catalog & ID Uniqueness...")
|
|
137
|
+
rules_dir = self.root_dir / "rules"
|
|
138
|
+
rule_files = list(rules_dir.glob("**/*.md"))
|
|
139
|
+
rule_ids = {}
|
|
140
|
+
|
|
141
|
+
for rf in rule_files:
|
|
142
|
+
if rf.name == "README.md":
|
|
143
|
+
continue
|
|
144
|
+
with open(rf, "r", encoding="utf-8") as f:
|
|
145
|
+
content = f.read()
|
|
146
|
+
|
|
147
|
+
match = re.search(r"^(TG-[A-Z0-9]+-[0-9]{3})", rf.name)
|
|
148
|
+
if not match:
|
|
149
|
+
match = re.search(r"#\s+(TG-[A-Z0-9]+-[0-9]{3})", content)
|
|
150
|
+
|
|
151
|
+
if match:
|
|
152
|
+
rid = match.group(1)
|
|
153
|
+
if rid in rule_ids:
|
|
154
|
+
self.log_test(f"Rule ID unique: {rid}", False, f"Duplicate found in {rf.name} and {rule_ids[rid]}")
|
|
155
|
+
else:
|
|
156
|
+
rule_ids[rid] = rf.name
|
|
157
|
+
else:
|
|
158
|
+
self.log_test(f"Rule ID parseable in {rf.name}", False, "No valid TG-* rule ID found in header")
|
|
159
|
+
|
|
160
|
+
self.log_test(f"Total Rules Cataloged ({len(rule_ids)})", len(rule_ids) >= 64, f"Found {len(rule_ids)} rules")
|
|
161
|
+
|
|
162
|
+
def test_skill_definition(self):
|
|
163
|
+
print("\n3. Testing Skill Definition & References...")
|
|
164
|
+
skill_file = self.root_dir / "skills" / "TorusGuard" / "SKILL.md"
|
|
165
|
+
if not skill_file.exists():
|
|
166
|
+
self.log_test("SKILL.md exists", False, "Missing skills/TorusGuard/SKILL.md")
|
|
167
|
+
return
|
|
168
|
+
|
|
169
|
+
with open(skill_file, "r", encoding="utf-8") as f:
|
|
170
|
+
content = f.read()
|
|
171
|
+
|
|
172
|
+
has_frontmatter = content.startswith("---") and "name: torusguard" in content
|
|
173
|
+
self.log_test("SKILL.md YAML Frontmatter", has_frontmatter)
|
|
174
|
+
|
|
175
|
+
has_commands = all(cmd in content for cmd in ["/torusguard init", "/torusguard audit", "/torusguard harden", "/torusguard apply", "/torusguard verify", "/torusguard recheck"])
|
|
176
|
+
self.log_test("SKILL.md Core Commands Documented (including apply & recheck)", has_commands)
|
|
177
|
+
|
|
178
|
+
refs_dir = self.root_dir / "skills" / "TorusGuard" / "references"
|
|
179
|
+
ref_files = list(refs_dir.glob("*.md"))
|
|
180
|
+
self.log_test(f"Skill Reference Modules ({len(ref_files)})", len(ref_files) >= 7)
|
|
181
|
+
|
|
182
|
+
def test_confidence_scoring_model(self):
|
|
183
|
+
print("\n4. Testing Auditable Confidence Scoring Model...")
|
|
184
|
+
c_confirmed = ConfidenceScore.calculate(
|
|
185
|
+
evidence_quality=35,
|
|
186
|
+
reproduction_success=25,
|
|
187
|
+
independent_confirmations=15,
|
|
188
|
+
environmental_clarity=15,
|
|
189
|
+
manual_review_status=5,
|
|
190
|
+
rationale="Direct AST match with deterministic reproduction.",
|
|
191
|
+
)
|
|
192
|
+
self.log_test("Confidence calculation: Confirmed band (>= 90)", c_confirmed.score == 95 and c_confirmed.band == ConfidenceBand.CONFIRMED)
|
|
193
|
+
|
|
194
|
+
c_high = ConfidenceScore.calculate(
|
|
195
|
+
evidence_quality=30,
|
|
196
|
+
reproduction_success=20,
|
|
197
|
+
independent_confirmations=10,
|
|
198
|
+
environmental_clarity=15,
|
|
199
|
+
manual_review_status=0,
|
|
200
|
+
rationale="Strong static indicator without manual validation.",
|
|
201
|
+
)
|
|
202
|
+
self.log_test("Confidence calculation: High Confidence band (70-89)", c_high.score == 75 and c_high.band == ConfidenceBand.HIGH_CONFIDENCE)
|
|
203
|
+
|
|
204
|
+
def test_provenance_and_evidence_hashing(self):
|
|
205
|
+
print("\n5. Testing Provenance Chain & SHA-256 Evidence Integrity...")
|
|
206
|
+
ev = Evidence(
|
|
207
|
+
type=EvidenceType.SOURCE,
|
|
208
|
+
location="server/auth.py:42",
|
|
209
|
+
raw_snippet="SECRET_KEY = 'super_secret_jwt_key'",
|
|
210
|
+
rationale="Hardcoded secret credential.",
|
|
211
|
+
confidence_level=ConfidenceBand.CONFIRMED,
|
|
212
|
+
is_sufficient_for_confirmed=True,
|
|
213
|
+
)
|
|
214
|
+
has_hash = bool(ev.sha256_checksum) and len(ev.sha256_checksum) == 64
|
|
215
|
+
self.log_test("Evidence SHA-256 Checksum Computed", has_hash)
|
|
216
|
+
|
|
217
|
+
def test_sensitive_data_masking(self):
|
|
218
|
+
print("\n6. Testing Sensitive Secret & Token Masking...")
|
|
219
|
+
sample_secret = "API_KEY = 'sk_live_998877665544332211'"
|
|
220
|
+
masked = mask_sensitive_data(sample_secret)
|
|
221
|
+
self.log_test("Stripe Secret Key Redaction", "sk_live_***REDACTED***" in masked and "998877665544332211" not in masked)
|
|
222
|
+
|
|
223
|
+
sample_jwt = "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.doNotLeakSignature"
|
|
224
|
+
masked_jwt = mask_sensitive_data(sample_jwt)
|
|
225
|
+
self.log_test("JWT Token Redaction", "***REDACTED_JWT***" in masked_jwt and "doNotLeakSignature" not in masked_jwt)
|
|
226
|
+
|
|
227
|
+
def test_retest_lifecycle_closure(self):
|
|
228
|
+
print("\n7. Testing Retest Execution & Closure State Machine...")
|
|
229
|
+
ev = Evidence(
|
|
230
|
+
type=EvidenceType.SOURCE,
|
|
231
|
+
location="views.py:15",
|
|
232
|
+
raw_snippet="User.objects.raw('SELECT * FROM users WHERE name = %s')",
|
|
233
|
+
rationale="Direct string concatenation into SQL query.",
|
|
234
|
+
confidence_level=ConfidenceBand.CONFIRMED,
|
|
235
|
+
is_sufficient_for_confirmed=True,
|
|
236
|
+
)
|
|
237
|
+
sev = SeverityInfo(
|
|
238
|
+
level=SeverityLevel.CRITICAL,
|
|
239
|
+
rationale="Allows arbitrary SQL execution and data exfiltration.",
|
|
240
|
+
rubric_justification="Critical because unauthenticated user input reaches raw SQL interpreter.",
|
|
241
|
+
)
|
|
242
|
+
conf = ConfidenceScore.calculate(35, 25, 15, 15, 5, "Direct AST concatenation match.")
|
|
243
|
+
prov = ProvenanceChain(
|
|
244
|
+
discovery_module="rules/input/TG-INPUT-002-raw-sql-concatenation.md",
|
|
245
|
+
triggering_input="Raw SQL execution with f-string formatting",
|
|
246
|
+
evidence_collected=["views.py:15"],
|
|
247
|
+
decision_path=["Detected raw SQL method", "Verified unparameterized input"],
|
|
248
|
+
verification_step="Inspect query parameterization.",
|
|
249
|
+
)
|
|
250
|
+
rem = Remediation(
|
|
251
|
+
problem_statement="Raw SQL string concatenation vulnerable to SQL injection.",
|
|
252
|
+
risk_explanation="Attackers can inject malicious SQL payloads.",
|
|
253
|
+
recommended_fix="Use parameterized queries.",
|
|
254
|
+
framework_pattern=FrameworkPattern(
|
|
255
|
+
framework="Django",
|
|
256
|
+
unsafe_snippet="User.objects.raw(f'SELECT * FROM users WHERE name = {name}')",
|
|
257
|
+
safe_snippet="User.objects.raw('SELECT * FROM users WHERE name = %s', [name])",
|
|
258
|
+
),
|
|
259
|
+
verification_method="Test with quote payload and verify parameterized execution.",
|
|
260
|
+
residual_risk_notes="Ensure database permissions are restricted.",
|
|
261
|
+
)
|
|
262
|
+
finding = Finding(
|
|
263
|
+
rule_id="TG-INPUT-002",
|
|
264
|
+
title="Raw SQL Concatenation",
|
|
265
|
+
category=TaxonomyCategory.INPUT,
|
|
266
|
+
severity=sev,
|
|
267
|
+
confidence=conf,
|
|
268
|
+
status=FindingStatus.CONFIRMED,
|
|
269
|
+
affected_component=AffectedComponent(component_name="UserSearch", target_path="views.py", start_line=15),
|
|
270
|
+
evidence=[ev],
|
|
271
|
+
provenance=prov,
|
|
272
|
+
reproduction_method=ReproductionMethod(step_by_step=["Pass ' OR '1'='1 into search endpoint"], test_command="pytest tests/test_search.py"),
|
|
273
|
+
remediation=rem,
|
|
274
|
+
asvs_control="V5.3.4",
|
|
275
|
+
cwe="CWE-89",
|
|
276
|
+
nist_ssdf="PW.5.1",
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
FindingLifecycleManager.transition(finding, LifecycleStage.CLASSIFY)
|
|
280
|
+
FindingLifecycleManager.transition(finding, LifecycleStage.VERIFY)
|
|
281
|
+
FindingLifecycleManager.transition(finding, LifecycleStage.REMEDIATE)
|
|
282
|
+
|
|
283
|
+
ok, msg = FindingLifecycleManager.execute_retest(
|
|
284
|
+
finding,
|
|
285
|
+
post_fix_code="User.objects.raw('SELECT * FROM users WHERE name = %s', [name])",
|
|
286
|
+
safe_pattern_verified=True,
|
|
287
|
+
verifier_notes="Verified parameterized binding query.",
|
|
288
|
+
)
|
|
289
|
+
self.log_test("Retest execution -> Verified Fixed", ok and finding.status == FindingStatus.VERIFIED_FIXED)
|
|
290
|
+
|
|
291
|
+
def test_validation_engine_subsystem(self):
|
|
292
|
+
print("\n8. Testing Validation Engine Subsystem (v0.5.4)...")
|
|
293
|
+
fm = FixtureManager(str(self.root_dir))
|
|
294
|
+
fixtures = fm.list_fixtures()
|
|
295
|
+
self.log_test(f"Fixture Manager Catalog Loaded ({len(fixtures)} fixtures)", len(fixtures) >= 8)
|
|
296
|
+
|
|
297
|
+
rr = ReplayRunner(str(self.root_dir))
|
|
298
|
+
comparator = ResultComparator(str(self.root_dir))
|
|
299
|
+
comparison_results = []
|
|
300
|
+
|
|
301
|
+
for f in fixtures:
|
|
302
|
+
replay_res = rr.replay_fixture(f, passes=3)
|
|
303
|
+
self.log_test(f"Deterministic Replay (3 passes): {f.fixture_id}", replay_res.deterministic)
|
|
304
|
+
|
|
305
|
+
comp_res = comparator.compare_fixture(f, replay_deterministic=replay_res.deterministic)
|
|
306
|
+
comparison_results.append(comp_res)
|
|
307
|
+
self.log_test(f"Differential Comparison ({comp_res.outcome.value}): {f.fixture_id}", comp_res.diff_verified)
|
|
308
|
+
|
|
309
|
+
# Regression tracker
|
|
310
|
+
rt = RegressionTracker(str(self.root_dir))
|
|
311
|
+
reg_records = rt.evaluate_all_regressions()
|
|
312
|
+
all_clean = all(r.regression_status == "Clean" for r in reg_records)
|
|
313
|
+
self.log_test(f"Regression Tracker Verification ({len(reg_records)} baseline cases clean)", all_clean)
|
|
314
|
+
|
|
315
|
+
# FP Analyzer
|
|
316
|
+
diagnostics = FalsePositiveAnalyzer.analyze_results(comparison_results)
|
|
317
|
+
self.log_test("False Positive Analyzer Diagnostic Check (0 false alarms)", len(diagnostics) == 0)
|
|
318
|
+
|
|
319
|
+
# Evidence Collector & Report Emitter
|
|
320
|
+
collector = ValidationEvidenceCollector(str(self.root_dir))
|
|
321
|
+
env_snap = collector.capture_environment_snapshot()
|
|
322
|
+
self.log_test("Validation Evidence Collector Environment Snapshot", "os" in env_snap and "python_version" in env_snap)
|
|
323
|
+
|
|
324
|
+
val_report = ValidationRunReport(
|
|
325
|
+
environment=env_snap,
|
|
326
|
+
fixture_results=comparison_results,
|
|
327
|
+
regression_records=reg_records,
|
|
328
|
+
)
|
|
329
|
+
report_md = ValidationReportEmitter.render_markdown(val_report)
|
|
330
|
+
self.log_test("Validation Report Emitter Markdown Rendering", "# TorusGuard Validation Engine" in report_md and "Execution Summary" in report_md)
|
|
331
|
+
|
|
332
|
+
def test_stack_detection_fixtures(self):
|
|
333
|
+
print("\n9. Testing Stack Detection Layouts...")
|
|
334
|
+
stack_dir = self.root_dir / "tests" / "fixtures" / "python" / "stack-detection"
|
|
335
|
+
expected_stacks = [
|
|
336
|
+
"django",
|
|
337
|
+
"django-drf",
|
|
338
|
+
"fastapi",
|
|
339
|
+
"flask",
|
|
340
|
+
"flask-sqlalchemy",
|
|
341
|
+
"python-library",
|
|
342
|
+
"mixed-monorepo",
|
|
343
|
+
]
|
|
344
|
+
for s in expected_stacks:
|
|
345
|
+
target = stack_dir / s
|
|
346
|
+
exists = target.exists() and any(target.iterdir())
|
|
347
|
+
self.log_test(f"Stack layout fixture: {s}", exists)
|
|
348
|
+
|
|
349
|
+
def test_educational_differential_fixtures(self):
|
|
350
|
+
print("\n10. Testing Educational Differential Fixtures...")
|
|
351
|
+
pairs = [
|
|
352
|
+
("examples/python/django-vuln", "examples/python/django-hardened"),
|
|
353
|
+
("examples/python/drf-vuln", "examples/python/drf-hardened"),
|
|
354
|
+
("examples/python/fastapi-vuln", "examples/python/fastapi-hardened"),
|
|
355
|
+
("examples/python/flask-vuln", "examples/python/flask-hardened"),
|
|
356
|
+
("examples/python/sqlalchemy-vuln", "examples/python/sqlalchemy-hardened"),
|
|
357
|
+
]
|
|
358
|
+
for vuln_rel, hard_rel in pairs:
|
|
359
|
+
vuln_path = self.root_dir / vuln_rel
|
|
360
|
+
hard_path = self.root_dir / hard_rel
|
|
361
|
+
exists = vuln_path.exists() and hard_path.exists()
|
|
362
|
+
has_fixes = (hard_path / "fixes.md").exists() or (vuln_path / "README.md").exists()
|
|
363
|
+
self.log_test(f"Paired differential fixture: {Path(vuln_rel).name}", exists and has_fixes)
|
|
364
|
+
|
|
365
|
+
def test_regression_fixtures(self):
|
|
366
|
+
print("\n11. Testing Python Regression Fixtures Suite...")
|
|
367
|
+
regression_dir = self.root_dir / "tests" / "fixtures" / "python"
|
|
368
|
+
cases = [
|
|
369
|
+
"django/safe-service-layer-auth",
|
|
370
|
+
"django/missing-owner-scope",
|
|
371
|
+
"drf/safe-read-only-fields",
|
|
372
|
+
"drf/unbounded-pagination",
|
|
373
|
+
"fastapi/safe-pydantic-boundary",
|
|
374
|
+
"fastapi/unsafe-outbound-url",
|
|
375
|
+
"flask/csrf-enabled",
|
|
376
|
+
"flask/unsafe-upload",
|
|
377
|
+
"sqlalchemy/safe-bound-query",
|
|
378
|
+
"sqlalchemy/missing-tenant-scope",
|
|
379
|
+
]
|
|
380
|
+
for c in cases:
|
|
381
|
+
c_path = regression_dir / c
|
|
382
|
+
exists = c_path.exists() and (c_path / "README.md").exists()
|
|
383
|
+
self.log_test(f"Regression fixture: {c}", exists)
|
|
384
|
+
|
|
385
|
+
def test_report_formatting(self):
|
|
386
|
+
print("\n12. Testing Canonical v0.5.4 9-Section Actionable Markdown Report...")
|
|
387
|
+
ev = Evidence(
|
|
388
|
+
type=EvidenceType.SOURCE,
|
|
389
|
+
location="settings.py:10",
|
|
390
|
+
raw_snippet="DEBUG = True\nSECRET_KEY = 'sk_live_secret_key_12345'",
|
|
391
|
+
rationale="Production debug mode exposure and hardcoded secret.",
|
|
392
|
+
confidence_level=ConfidenceBand.CONFIRMED,
|
|
393
|
+
is_sufficient_for_confirmed=True,
|
|
394
|
+
)
|
|
395
|
+
sev = SeverityInfo(
|
|
396
|
+
level=SeverityLevel.CRITICAL,
|
|
397
|
+
rationale="Exposes internal stack traces and hardcoded production secret.",
|
|
398
|
+
rubric_justification="Critical because secret key enables session forgery and debug leaks internals.",
|
|
399
|
+
)
|
|
400
|
+
conf = ConfidenceScore.calculate(35, 25, 15, 15, 5, "Direct settings file check.")
|
|
401
|
+
prov = ProvenanceChain(
|
|
402
|
+
discovery_module="rules/TG-PLATFORM-003-production-stack-trace-exposure.md",
|
|
403
|
+
triggering_input="DEBUG = True assignment in settings.py",
|
|
404
|
+
evidence_collected=["settings.py:10"],
|
|
405
|
+
decision_path=["Loaded Django settings", "Found DEBUG enabled"],
|
|
406
|
+
verification_step="Assert DEBUG is False.",
|
|
407
|
+
)
|
|
408
|
+
rem = Remediation(
|
|
409
|
+
problem_statement="Debug mode is enabled and hardcoded secret present.",
|
|
410
|
+
risk_explanation="Stack traces leak environment variables and secret allows token forgery.",
|
|
411
|
+
recommended_fix="Set DEBUG = False and load secret from environment.",
|
|
412
|
+
framework_pattern=FrameworkPattern(
|
|
413
|
+
framework="Django",
|
|
414
|
+
unsafe_snippet="DEBUG = True",
|
|
415
|
+
safe_snippet="DEBUG = False",
|
|
416
|
+
),
|
|
417
|
+
verification_method="Assert DEBUG is False in production.",
|
|
418
|
+
residual_risk_notes="Ensure 500.html template exists.",
|
|
419
|
+
)
|
|
420
|
+
f = Finding(
|
|
421
|
+
rule_id="TG-PLATFORM-003",
|
|
422
|
+
title="Production Stack Trace Exposure",
|
|
423
|
+
category=TaxonomyCategory.CLIENT_PLATFORM,
|
|
424
|
+
severity=sev,
|
|
425
|
+
confidence=conf,
|
|
426
|
+
status=FindingStatus.CONFIRMED,
|
|
427
|
+
remediation_priority=RemediationPriority.IMMEDIATE,
|
|
428
|
+
affected_component=AffectedComponent(component_name="Config", target_path="settings.py", start_line=10),
|
|
429
|
+
evidence=[ev],
|
|
430
|
+
provenance=prov,
|
|
431
|
+
reproduction_method=ReproductionMethod(step_by_step=["Trigger 500 error and inspect response body"]),
|
|
432
|
+
remediation=rem,
|
|
433
|
+
asvs_control="V14.4.1",
|
|
434
|
+
cwe="CWE-209",
|
|
435
|
+
nist_ssdf="PW.5.1",
|
|
436
|
+
)
|
|
437
|
+
report = AuditReport(
|
|
438
|
+
project_name="DemoApp",
|
|
439
|
+
detected_stack={"language": "Python", "framework": "Django", "confidence": "Confirmed"},
|
|
440
|
+
findings=[f],
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
md_output = ReportFormatter.render_markdown(report)
|
|
444
|
+
has_header = "# TorusGuard Security Audit & Remediation Report" in md_output
|
|
445
|
+
has_exec_summary = "## 1. 📋 Executive Summary" in md_output
|
|
446
|
+
has_scope = "## 2. 🔍 Scope and Methodology" in md_output
|
|
447
|
+
has_summary_table = "## 3. 📑 Key Findings Summary Table" in md_output
|
|
448
|
+
has_detailed = "## 4. 🛡️ Detailed Findings" in md_output
|
|
449
|
+
has_business_context = "🏢 Business Impact & Executive Context" in md_output
|
|
450
|
+
has_remediation_roadmap = "## 5. 🎯 Remediation Priorities & Triage Roadmap" in md_output
|
|
451
|
+
has_ticket_payload = "🎫 Copy-Paste Issue Tracker Payload" in md_output
|
|
452
|
+
has_redaction = "sk_live_***REDACTED***" in md_output
|
|
453
|
+
|
|
454
|
+
self.log_test(
|
|
455
|
+
"Render v0.5.4 9-Section Actionable Report",
|
|
456
|
+
has_header and has_exec_summary and has_scope and has_summary_table and has_detailed and has_business_context and has_remediation_roadmap and has_ticket_payload and has_redaction
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
def test_run_context_and_ponytail(self):
|
|
460
|
+
print("\n13. Testing v0.5.5 RunFolder Structure...")
|
|
461
|
+
import shutil
|
|
462
|
+
test_root = self.root_dir / ".torusguard" / "runs_test"
|
|
463
|
+
if test_root.exists():
|
|
464
|
+
shutil.rmtree(test_root)
|
|
465
|
+
|
|
466
|
+
rf = RunFolder(output_root=str(test_root), run_name="test-run-001")
|
|
467
|
+
|
|
468
|
+
# Test directory initialization
|
|
469
|
+
has_dirs = rf.run_path.exists() and rf.patches_dir.exists() and rf.logs_dir.exists()
|
|
470
|
+
|
|
471
|
+
# Test metadata file initialization
|
|
472
|
+
has_metadata = rf.metadata_file.exists()
|
|
473
|
+
if has_metadata:
|
|
474
|
+
with open(rf.metadata_file, "r", encoding="utf-8") as f:
|
|
475
|
+
metadata = json.load(f)
|
|
476
|
+
has_metadata = metadata.get("run_id") == "test-run-001"
|
|
477
|
+
|
|
478
|
+
self.log_test("RunFolder Initialization", has_dirs and has_metadata)
|
|
479
|
+
|
|
480
|
+
# Cleanup
|
|
481
|
+
shutil.rmtree(test_root)
|
|
482
|
+
|
|
483
|
+
def test_v6_governed_remediation_suite(self):
|
|
484
|
+
print("\n14. Testing TorusGuard v0.6.0 Governed Remediation & Targeted Recheck Engine...")
|
|
485
|
+
import tempfile
|
|
486
|
+
from core.identity import IdentityEngine
|
|
487
|
+
from core.clustering import ClusteringEngine
|
|
488
|
+
from core.bundle import BundleManager
|
|
489
|
+
from core.governance import PatchGovernor
|
|
490
|
+
from core.rechecker import TargetedRechecker, RecheckOutcome
|
|
491
|
+
from core.run_manager import RunManager
|
|
492
|
+
from core.sarif import SarifExporter
|
|
493
|
+
from core.v6_workflow import V6Workflow
|
|
494
|
+
|
|
495
|
+
temp_dir = Path(tempfile.mkdtemp(prefix="tg-v0-6-harness-"))
|
|
496
|
+
try:
|
|
497
|
+
# 1. Run Folder
|
|
498
|
+
rm = RunManager(base_dir=temp_dir, target_name="test-target", command="audit", run_id="run-harness-01")
|
|
499
|
+
rm.write_manifest(status_counts={"total_findings": 1, "confirmed": 1, "high_confidence": 0, "needs_review": 0, "remediated": 0, "verified_fixed": 0, "regressed": 0})
|
|
500
|
+
self.log_test("v0.6.0 RunFolder & Manifest.json Generation", rm.manifest_file.exists() and rm.patches_dir.exists())
|
|
501
|
+
|
|
502
|
+
# 2. Stable Finding Identity
|
|
503
|
+
code_a = "def view():\n return Item.objects.get(id=id)"
|
|
504
|
+
code_b = "# Shifted comment\ndef view():\n return Item.objects.get(id=id)"
|
|
505
|
+
fp1 = IdentityEngine.generate_identity("TG-DB-004", "views.py", code_a, sink_signature="Item.objects.get")
|
|
506
|
+
fp2 = IdentityEngine.generate_identity("TG-DB-004", "views.py", code_b, sink_signature="Item.objects.get")
|
|
507
|
+
self.log_test("v0.6.0 Stable Finding Identity (Line Shift Invariance)", fp1.fingerprint_id == fp2.fingerprint_id and fp1.fingerprint_id.startswith("TG-DB-"))
|
|
508
|
+
|
|
509
|
+
# 3. Root-Cause Clustering
|
|
510
|
+
raw_f = [
|
|
511
|
+
{"finding_id": "f1", "rule_id": "TG-DB-004", "title": "Missing Tenant Isolation", "severity": "High", "target": {"file_path": "a.py"}},
|
|
512
|
+
{"finding_id": "f2", "rule_id": "TG-DB-004", "title": "Missing Tenant Isolation", "severity": "High", "target": {"file_path": "b.py"}},
|
|
513
|
+
]
|
|
514
|
+
clusters = ClusteringEngine.cluster_findings(raw_f)
|
|
515
|
+
self.log_test("v0.6.0 Root-Cause Clustering (Multi-Tenant Pattern)", len(clusters) == 1 and clusters[0].cluster_id == "cluster-tenant-isolation")
|
|
516
|
+
|
|
517
|
+
# 4. Remediation Bundle
|
|
518
|
+
bundle = BundleManager.create_bundle(raw_f[0], cluster_id="cluster-tenant-isolation")
|
|
519
|
+
b_dir = bundle.write_to_directory(temp_dir)
|
|
520
|
+
self.log_test("v0.6.0 Remediation Bundle Packaging (5 Artifacts)", (b_dir / "finding.md").exists() and (b_dir / "minimal_patch_plan.md").exists())
|
|
521
|
+
|
|
522
|
+
# 5. Patch Governance
|
|
523
|
+
gov = PatchGovernor(max_additions_per_file=10)
|
|
524
|
+
clean_diff = "--- a/x.py\n+++ b/x.py\n@@ -1 +1 @@\n-old()\n+new()\n"
|
|
525
|
+
oversized_diff = "--- a/x.py\n+++ b/x.py\n" + "\n".join(f"+line_{i}()" for i in range(20))
|
|
526
|
+
d_clean = gov.evaluate_diff(clean_diff, "x.py")
|
|
527
|
+
d_over = gov.evaluate_diff(oversized_diff, "x.py")
|
|
528
|
+
self.log_test("v0.6.0 Minimal Patch Governance (Line Churn Policy)", d_clean.allowed_auto_apply and not d_over.allowed_auto_apply)
|
|
529
|
+
|
|
530
|
+
# 6. Targeted Recheck
|
|
531
|
+
r_fix = TargetedRechecker.verify_finding("f1", "TG-DB-004", "a.py", "old", "new", is_safe_pattern_present=True, is_unsafe_pattern_present=False)
|
|
532
|
+
r_reg = TargetedRechecker.verify_finding("f2", "TG-DB-004", "b.py", "old", "bad", is_safe_pattern_present=False, is_unsafe_pattern_present=True, introduced_new_flaws=["TG-SEC-001"])
|
|
533
|
+
self.log_test("v0.6.0 Targeted Recheck Transitions (Confirmed Fixed & Regressed)", r_fix.outcome == RecheckOutcome.CONFIRMED_FIXED and r_reg.outcome == RecheckOutcome.REGRESSED)
|
|
534
|
+
|
|
535
|
+
# 7. SARIF Export
|
|
536
|
+
sarif = SarifExporter.generate_sarif([{"finding_id": "f1", "rule_id": "TG-DB-004", "title": "Missing Tenant Isolation", "target": {"file_path": "a.py"}}])
|
|
537
|
+
self.log_test("v0.6.0 SARIF v2.1.0 Structured Export", sarif["version"] == "2.1.0" and len(sarif["runs"]) == 1)
|
|
538
|
+
|
|
539
|
+
# 8. End-to-End Workflow
|
|
540
|
+
wf = V6Workflow(target_root=temp_dir, output_base=temp_dir / "runs")
|
|
541
|
+
run_wf = wf.execute_audit(raw_f, target_name="e2e-demo", export_sarif=True)
|
|
542
|
+
self.log_test("v0.6.0 End-to-End Workflow Execution", run_wf.manifest_file.exists() and run_wf.sarif_file.exists())
|
|
543
|
+
|
|
544
|
+
finally:
|
|
545
|
+
shutil.rmtree(temp_dir, ignore_errors=True)
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
if __name__ == "__main__":
|
|
549
|
+
runner = ValidationHarnessRunner()
|
|
550
|
+
success = runner.run_all()
|
|
551
|
+
sys.exit(0 if success else 1)
|