thuban 0.4.9 → 0.4.11
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/LICENSE +21 -21
- package/README.md +437 -437
- package/dist/LICENSE +21 -0
- package/dist/README.md +437 -0
- package/dist/cli.js +2 -0
- package/dist/package.json +63 -0
- package/dist/packages/crucible/.golden/golden-master.json +414 -0
- package/dist/packages/crucible/report-generator.js +1 -0
- package/dist/packages/crucible/rules/code-scanner-core.json +303 -0
- package/dist/packages/crucible/rules/command-injection.json +411 -0
- package/dist/packages/crucible/rules/crypto-misuse.json +35 -0
- package/dist/packages/crucible/rules/deserialization.json +152 -0
- package/dist/packages/crucible/rules/env-injection.json +46 -0
- package/dist/packages/crucible/rules/eval-abuse.json +104 -0
- package/dist/packages/crucible/rules/file-upload.json +46 -0
- package/dist/packages/crucible/rules/hallucination.json +22 -0
- package/dist/packages/crucible/rules/hardcoded-secret.json +397 -0
- package/dist/packages/crucible/rules/hardcoded-url.json +13 -0
- package/dist/packages/crucible/rules/insecure-crypto.json +302 -0
- package/dist/packages/crucible/rules/integer-overflow.json +35 -0
- package/dist/packages/crucible/rules/log-injection.json +33 -0
- package/dist/packages/crucible/rules/mass-assignment.json +112 -0
- package/dist/packages/crucible/rules/open-redirect.json +196 -0
- package/dist/packages/crucible/rules/path-traversal.json +422 -0
- package/dist/packages/crucible/rules/prototype-pollution.json +22 -0
- package/dist/packages/crucible/rules/sql-injection.json +619 -0
- package/dist/packages/crucible/rules/ssrf.json +557 -0
- package/dist/packages/crucible/rules/timing-attack.json +55 -0
- package/dist/packages/crucible/rules/unsafe-block.json +24 -0
- package/dist/packages/crucible/rules/xss.json +663 -0
- package/dist/packages/crucible/rules/xxe.json +66 -0
- package/dist/packages/crucible/rules/yaml-deserialization.json +22 -0
- package/dist/packages/crucible/rules/yaml-injection.json +22 -0
- package/dist/packages/crucible/seeds/csharp/seed-001.cs +28 -0
- package/dist/packages/crucible/seeds/csharp/seed-002.cs +24 -0
- package/dist/packages/crucible/seeds/csharp/seed-003.cs +30 -0
- package/dist/packages/crucible/seeds/csharp/seed-004.cs +31 -0
- package/dist/packages/crucible/seeds/csharp/seed-005.cs +28 -0
- package/dist/packages/crucible/seeds/csharp/seed-006.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-007.cs +34 -0
- package/dist/packages/crucible/seeds/csharp/seed-008.cs +23 -0
- package/dist/packages/crucible/seeds/csharp/seed-009.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-010.cs +29 -0
- package/dist/packages/crucible/seeds/csharp/seed-011.cs +32 -0
- package/dist/packages/crucible/seeds/csharp/seed-012.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-013.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-014.cs +26 -0
- package/dist/packages/crucible/seeds/csharp/seed-015.cs +33 -0
- package/dist/packages/crucible/seeds/csharp/seed-016.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-017.cs +22 -0
- package/dist/packages/crucible/seeds/csharp/seed-018.cs +26 -0
- package/dist/packages/crucible/seeds/csharp/seed-019.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-020.cs +22 -0
- package/dist/packages/crucible/seeds/csharp/seed-021.cs +28 -0
- package/dist/packages/crucible/seeds/csharp/seed-022.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-023.cs +33 -0
- package/dist/packages/crucible/seeds/csharp/seed-024.cs +31 -0
- package/dist/packages/crucible/seeds/csharp/seed-025.cs +31 -0
- package/dist/packages/crucible/seeds/csharp/seed-026.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-027.cs +29 -0
- package/dist/packages/crucible/seeds/csharp/seed-028.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-029.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-030.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-031.cs +28 -0
- package/dist/packages/crucible/seeds/csharp/seed-032.cs +30 -0
- package/dist/packages/crucible/seeds/csharp/seed-033.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-034.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-035.cs +32 -0
- package/dist/packages/crucible/seeds/csharp/seed-036.cs +28 -0
- package/dist/packages/crucible/seeds/csharp/seed-037.cs +29 -0
- package/dist/packages/crucible/seeds/csharp/seed-038.cs +28 -0
- package/dist/packages/crucible/seeds/csharp/seed-039.cs +29 -0
- package/dist/packages/crucible/seeds/csharp/seed-040.cs +28 -0
- package/dist/packages/crucible/seeds/csharp/seed-041.cs +33 -0
- package/dist/packages/crucible/seeds/csharp/seed-042.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-043.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-044.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-045.cs +30 -0
- package/dist/packages/crucible/seeds/csharp/seed-046.cs +29 -0
- package/dist/packages/crucible/seeds/csharp/seed-047.cs +26 -0
- package/dist/packages/crucible/seeds/csharp/seed-048.cs +31 -0
- package/dist/packages/crucible/seeds/csharp/seed-049.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-050.cs +30 -0
- package/dist/packages/crucible/seeds/csharp/seed-051.cs +34 -0
- package/dist/packages/crucible/seeds/csharp/seed-052.cs +36 -0
- package/dist/packages/crucible/seeds/go/seed-001.go +29 -0
- package/dist/packages/crucible/seeds/go/seed-002.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-003.go +31 -0
- package/dist/packages/crucible/seeds/go/seed-004.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-005.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-006.go +29 -0
- package/dist/packages/crucible/seeds/go/seed-007.go +24 -0
- package/dist/packages/crucible/seeds/go/seed-008.go +25 -0
- package/dist/packages/crucible/seeds/go/seed-009.go +30 -0
- package/dist/packages/crucible/seeds/go/seed-010.go +35 -0
- package/dist/packages/crucible/seeds/go/seed-011.go +24 -0
- package/dist/packages/crucible/seeds/go/seed-012.go +24 -0
- package/dist/packages/crucible/seeds/go/seed-013.go +31 -0
- package/dist/packages/crucible/seeds/go/seed-014.go +35 -0
- package/dist/packages/crucible/seeds/go/seed-015.go +25 -0
- package/dist/packages/crucible/seeds/go/seed-016.go +19 -0
- package/dist/packages/crucible/seeds/go/seed-017.go +23 -0
- package/dist/packages/crucible/seeds/go/seed-018.go +23 -0
- package/dist/packages/crucible/seeds/go/seed-019.go +22 -0
- package/dist/packages/crucible/seeds/go/seed-020.go +31 -0
- package/dist/packages/crucible/seeds/go/seed-021.go +22 -0
- package/dist/packages/crucible/seeds/go/seed-022.go +29 -0
- package/dist/packages/crucible/seeds/go/seed-023.go +26 -0
- package/dist/packages/crucible/seeds/go/seed-024.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-025.go +23 -0
- package/dist/packages/crucible/seeds/go/seed-026.go +29 -0
- package/dist/packages/crucible/seeds/go/seed-027.go +26 -0
- package/dist/packages/crucible/seeds/go/seed-028.go +23 -0
- package/dist/packages/crucible/seeds/go/seed-029.go +28 -0
- package/dist/packages/crucible/seeds/go/seed-030.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-031.go +28 -0
- package/dist/packages/crucible/seeds/go/seed-032.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-033.go +29 -0
- package/dist/packages/crucible/seeds/go/seed-034.go +22 -0
- package/dist/packages/crucible/seeds/go/seed-035.go +32 -0
- package/dist/packages/crucible/seeds/go/seed-036.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-037.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-038.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-039.go +26 -0
- package/dist/packages/crucible/seeds/go/seed-040.go +37 -0
- package/dist/packages/crucible/seeds/go/seed-041.go +23 -0
- package/dist/packages/crucible/seeds/go/seed-042.go +32 -0
- package/dist/packages/crucible/seeds/go/seed-043.go +35 -0
- package/dist/packages/crucible/seeds/go/seed-044.go +25 -0
- package/dist/packages/crucible/seeds/go/seed-045.go +26 -0
- package/dist/packages/crucible/seeds/go/seed-046.go +34 -0
- package/dist/packages/crucible/seeds/go/seed-047.go +26 -0
- package/dist/packages/crucible/seeds/go/seed-048.go +29 -0
- package/dist/packages/crucible/seeds/go/seed-049.go +24 -0
- package/dist/packages/crucible/seeds/go/seed-050.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-051.go +38 -0
- package/dist/packages/crucible/seeds/go/seed-052.go +27 -0
- package/dist/packages/crucible/seeds/java/seed-001.java +23 -0
- package/dist/packages/crucible/seeds/java/seed-002.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-003.java +28 -0
- package/dist/packages/crucible/seeds/java/seed-004.java +26 -0
- package/dist/packages/crucible/seeds/java/seed-005.java +33 -0
- package/dist/packages/crucible/seeds/java/seed-006.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-007.java +21 -0
- package/dist/packages/crucible/seeds/java/seed-008.java +29 -0
- package/dist/packages/crucible/seeds/java/seed-009.java +24 -0
- package/dist/packages/crucible/seeds/java/seed-010.java +30 -0
- package/dist/packages/crucible/seeds/java/seed-011.java +25 -0
- package/dist/packages/crucible/seeds/java/seed-012.java +20 -0
- package/dist/packages/crucible/seeds/java/seed-013.java +26 -0
- package/dist/packages/crucible/seeds/java/seed-014.java +23 -0
- package/dist/packages/crucible/seeds/java/seed-015.java +25 -0
- package/dist/packages/crucible/seeds/java/seed-016.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-017.java +24 -0
- package/dist/packages/crucible/seeds/java/seed-018.java +24 -0
- package/dist/packages/crucible/seeds/java/seed-019.java +38 -0
- package/dist/packages/crucible/seeds/java/seed-020.java +24 -0
- package/dist/packages/crucible/seeds/java/seed-021.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-022.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-023.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-024.java +25 -0
- package/dist/packages/crucible/seeds/java/seed-025.java +27 -0
- package/dist/packages/crucible/seeds/java/seed-026.java +25 -0
- package/dist/packages/crucible/seeds/java/seed-027.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-028.java +21 -0
- package/dist/packages/crucible/seeds/java/seed-029.java +28 -0
- package/dist/packages/crucible/seeds/java/seed-030.java +27 -0
- package/dist/packages/crucible/seeds/java/seed-031.java +23 -0
- package/dist/packages/crucible/seeds/java/seed-032.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-033.java +24 -0
- package/dist/packages/crucible/seeds/java/seed-034.java +24 -0
- package/dist/packages/crucible/seeds/java/seed-035.java +29 -0
- package/dist/packages/crucible/seeds/java/seed-036.java +25 -0
- package/dist/packages/crucible/seeds/java/seed-037.java +30 -0
- package/dist/packages/crucible/seeds/java/seed-038.java +29 -0
- package/dist/packages/crucible/seeds/java/seed-039.java +26 -0
- package/dist/packages/crucible/seeds/java/seed-040.java +31 -0
- package/dist/packages/crucible/seeds/java/seed-041.java +20 -0
- package/dist/packages/crucible/seeds/java/seed-042.java +26 -0
- package/dist/packages/crucible/seeds/java/seed-043.java +31 -0
- package/dist/packages/crucible/seeds/java/seed-044.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-045.java +25 -0
- package/dist/packages/crucible/seeds/java/seed-046.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-047.java +26 -0
- package/dist/packages/crucible/seeds/java/seed-048.java +24 -0
- package/dist/packages/crucible/seeds/java/seed-049.java +28 -0
- package/dist/packages/crucible/seeds/java/seed-050.java +29 -0
- package/dist/packages/crucible/seeds/java/seed-051.java +25 -0
- package/dist/packages/crucible/seeds/java/seed-052.java +32 -0
- package/dist/packages/crucible/seeds/js/seed-001.js +27 -0
- package/dist/packages/crucible/seeds/js/seed-002.js +28 -0
- package/dist/packages/crucible/seeds/js/seed-003.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-004.js +28 -0
- package/dist/packages/crucible/seeds/js/seed-005.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-006.js +28 -0
- package/dist/packages/crucible/seeds/js/seed-007.js +26 -0
- package/dist/packages/crucible/seeds/js/seed-008.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-009.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-010.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-011.js +34 -0
- package/dist/packages/crucible/seeds/js/seed-012.js +32 -0
- package/dist/packages/crucible/seeds/js/seed-013.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-014.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-015.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-016.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-017.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-018.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-019.js +32 -0
- package/dist/packages/crucible/seeds/js/seed-020.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-021.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-022.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-023.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-024.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-025.js +34 -0
- package/dist/packages/crucible/seeds/js/seed-026.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-027.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-028.js +33 -0
- package/dist/packages/crucible/seeds/js/seed-029.js +33 -0
- package/dist/packages/crucible/seeds/js/seed-030.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-031.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-032.js +34 -0
- package/dist/packages/crucible/seeds/js/seed-033.js +33 -0
- package/dist/packages/crucible/seeds/js/seed-034.js +33 -0
- package/dist/packages/crucible/seeds/js/seed-035.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-036.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-037.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-038.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-039.js +34 -0
- package/dist/packages/crucible/seeds/js/seed-040.js +35 -0
- package/dist/packages/crucible/seeds/js/seed-041.js +32 -0
- package/dist/packages/crucible/seeds/js/seed-042.js +32 -0
- package/dist/packages/crucible/seeds/js/seed-043.js +27 -0
- package/dist/packages/crucible/seeds/js/seed-044.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-045.js +33 -0
- package/dist/packages/crucible/seeds/js/seed-046.js +33 -0
- package/dist/packages/crucible/seeds/js/seed-047.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-048.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-049.js +34 -0
- package/dist/packages/crucible/seeds/js/seed-050.js +34 -0
- package/dist/packages/crucible/seeds/js/seed-051.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-052.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-053.js +26 -0
- package/dist/packages/crucible/seeds/js/seed-054.js +35 -0
- package/dist/packages/crucible/seeds/js/seed-055.js +33 -0
- package/dist/packages/crucible/seeds/kotlin/seed-001.kt +24 -0
- package/dist/packages/crucible/seeds/kotlin/seed-002.kt +27 -0
- package/dist/packages/crucible/seeds/kotlin/seed-003.kt +29 -0
- package/dist/packages/crucible/seeds/kotlin/seed-004.kt +24 -0
- package/dist/packages/crucible/seeds/kotlin/seed-005.kt +29 -0
- package/dist/packages/crucible/seeds/kotlin/seed-006.kt +21 -0
- package/dist/packages/crucible/seeds/kotlin/seed-007.kt +23 -0
- package/dist/packages/crucible/seeds/kotlin/seed-008.kt +25 -0
- package/dist/packages/crucible/seeds/kotlin/seed-009.kt +21 -0
- package/dist/packages/crucible/seeds/kotlin/seed-010.kt +28 -0
- package/dist/packages/crucible/seeds/kotlin/seed-011.kt +22 -0
- package/dist/packages/crucible/seeds/kotlin/seed-012.kt +25 -0
- package/dist/packages/crucible/seeds/kotlin/seed-013.kt +30 -0
- package/dist/packages/crucible/seeds/kotlin/seed-014.kt +27 -0
- package/dist/packages/crucible/seeds/kotlin/seed-015.kt +24 -0
- package/dist/packages/crucible/seeds/kotlin/seed-016.kt +28 -0
- package/dist/packages/crucible/seeds/kotlin/seed-017.kt +33 -0
- package/dist/packages/crucible/seeds/kotlin/seed-018.kt +31 -0
- package/dist/packages/crucible/seeds/kotlin/seed-019.kt +28 -0
- package/dist/packages/crucible/seeds/kotlin/seed-020.kt +31 -0
- package/dist/packages/crucible/seeds/kotlin/seed-021.kt +34 -0
- package/dist/packages/crucible/seeds/kotlin/seed-022.kt +29 -0
- package/dist/packages/crucible/seeds/kotlin/seed-023.kt +20 -0
- package/dist/packages/crucible/seeds/kotlin/seed-024.kt +23 -0
- package/dist/packages/crucible/seeds/kotlin/seed-025.kt +23 -0
- package/dist/packages/crucible/seeds/kotlin/seed-026.kt +26 -0
- package/dist/packages/crucible/seeds/kotlin/seed-027.kt +29 -0
- package/dist/packages/crucible/seeds/kotlin/seed-028.kt +24 -0
- package/dist/packages/crucible/seeds/kotlin/seed-029.kt +27 -0
- package/dist/packages/crucible/seeds/kotlin/seed-030.kt +26 -0
- package/dist/packages/crucible/seeds/kotlin/seed-031.kt +28 -0
- package/dist/packages/crucible/seeds/kotlin/seed-032.kt +29 -0
- package/dist/packages/crucible/seeds/kotlin/seed-033.kt +30 -0
- package/dist/packages/crucible/seeds/kotlin/seed-034.kt +26 -0
- package/dist/packages/crucible/seeds/kotlin/seed-035.kt +33 -0
- package/dist/packages/crucible/seeds/kotlin/seed-036.kt +25 -0
- package/dist/packages/crucible/seeds/kotlin/seed-037.kt +26 -0
- package/dist/packages/crucible/seeds/kotlin/seed-038.kt +25 -0
- package/dist/packages/crucible/seeds/kotlin/seed-039.kt +29 -0
- package/dist/packages/crucible/seeds/kotlin/seed-040.kt +28 -0
- package/dist/packages/crucible/seeds/kotlin/seed-041.kt +31 -0
- package/dist/packages/crucible/seeds/kotlin/seed-042.kt +27 -0
- package/dist/packages/crucible/seeds/kotlin/seed-043.kt +26 -0
- package/dist/packages/crucible/seeds/kotlin/seed-044.kt +27 -0
- package/dist/packages/crucible/seeds/kotlin/seed-045.kt +27 -0
- package/dist/packages/crucible/seeds/kotlin/seed-046.kt +33 -0
- package/dist/packages/crucible/seeds/kotlin/seed-047.kt +32 -0
- package/dist/packages/crucible/seeds/kotlin/seed-048.kt +20 -0
- package/dist/packages/crucible/seeds/kotlin/seed-049.kt +23 -0
- package/dist/packages/crucible/seeds/kotlin/seed-050.kt +19 -0
- package/dist/packages/crucible/seeds/php/seed-001.php +23 -0
- package/dist/packages/crucible/seeds/php/seed-002.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-003.php +25 -0
- package/dist/packages/crucible/seeds/php/seed-004.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-005.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-006.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-007.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-008.php +19 -0
- package/dist/packages/crucible/seeds/php/seed-009.php +24 -0
- package/dist/packages/crucible/seeds/php/seed-010.php +24 -0
- package/dist/packages/crucible/seeds/php/seed-011.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-012.php +24 -0
- package/dist/packages/crucible/seeds/php/seed-013.php +23 -0
- package/dist/packages/crucible/seeds/php/seed-014.php +20 -0
- package/dist/packages/crucible/seeds/php/seed-015.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-016.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-017.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-018.php +17 -0
- package/dist/packages/crucible/seeds/php/seed-019.php +24 -0
- package/dist/packages/crucible/seeds/php/seed-020.php +19 -0
- package/dist/packages/crucible/seeds/php/seed-021.php +22 -0
- package/dist/packages/crucible/seeds/php/seed-022.php +15 -0
- package/dist/packages/crucible/seeds/php/seed-023.php +24 -0
- package/dist/packages/crucible/seeds/php/seed-024.php +22 -0
- package/dist/packages/crucible/seeds/php/seed-025.php +20 -0
- package/dist/packages/crucible/seeds/php/seed-026.php +22 -0
- package/dist/packages/crucible/seeds/php/seed-027.php +15 -0
- package/dist/packages/crucible/seeds/php/seed-028.php +15 -0
- package/dist/packages/crucible/seeds/php/seed-029.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-030.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-031.php +23 -0
- package/dist/packages/crucible/seeds/php/seed-032.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-033.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-034.php +24 -0
- package/dist/packages/crucible/seeds/php/seed-035.php +22 -0
- package/dist/packages/crucible/seeds/php/seed-036.php +17 -0
- package/dist/packages/crucible/seeds/php/seed-037.php +19 -0
- package/dist/packages/crucible/seeds/php/seed-038.php +20 -0
- package/dist/packages/crucible/seeds/php/seed-039.php +15 -0
- package/dist/packages/crucible/seeds/php/seed-040.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-041.php +20 -0
- package/dist/packages/crucible/seeds/php/seed-042.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-043.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-044.php +25 -0
- package/dist/packages/crucible/seeds/php/seed-045.php +25 -0
- package/dist/packages/crucible/seeds/php/seed-046.php +20 -0
- package/dist/packages/crucible/seeds/php/seed-047.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-048.php +19 -0
- package/dist/packages/crucible/seeds/php/seed-049.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-050.php +20 -0
- package/dist/packages/crucible/seeds/python/seed-001.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-002.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-003.py +31 -0
- package/dist/packages/crucible/seeds/python/seed-004.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-005.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-006.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-007.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-008.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-009.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-010.py +42 -0
- package/dist/packages/crucible/seeds/python/seed-011.py +30 -0
- package/dist/packages/crucible/seeds/python/seed-012.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-013.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-014.py +40 -0
- package/dist/packages/crucible/seeds/python/seed-015.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-016.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-017.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-018.py +30 -0
- package/dist/packages/crucible/seeds/python/seed-019.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-020.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-021 2.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-021.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-022 2.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-022.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-023 2.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-023.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-024 2.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-024.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-025 2.py +40 -0
- package/dist/packages/crucible/seeds/python/seed-025.py +40 -0
- package/dist/packages/crucible/seeds/python/seed-026 2.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-026.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-027 2.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-027.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-028 2.py +42 -0
- package/dist/packages/crucible/seeds/python/seed-028.py +42 -0
- package/dist/packages/crucible/seeds/python/seed-029.py +42 -0
- package/dist/packages/crucible/seeds/python/seed-030 2.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-030.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-031 2.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-031.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-032.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-033.py +32 -0
- package/dist/packages/crucible/seeds/python/seed-034.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-035.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-036 2.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-036.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-037 2.py +41 -0
- package/dist/packages/crucible/seeds/python/seed-037.py +41 -0
- package/dist/packages/crucible/seeds/python/seed-038 2.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-038.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-039 2.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-039.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-040 2.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-040.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-041 2.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-041.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-042 2.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-042.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-043 2.py +32 -0
- package/dist/packages/crucible/seeds/python/seed-043.py +32 -0
- package/dist/packages/crucible/seeds/python/seed-044 2.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-044.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-045 2.py +36 -0
- package/dist/packages/crucible/seeds/python/seed-045.py +36 -0
- package/dist/packages/crucible/seeds/python/seed-046 2.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-046.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-047 2.py +44 -0
- package/dist/packages/crucible/seeds/python/seed-047.py +44 -0
- package/dist/packages/crucible/seeds/python/seed-048 2.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-048.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-049 2.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-049.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-050 2.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-050.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-051 2.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-051.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-052 2.py +41 -0
- package/dist/packages/crucible/seeds/python/seed-052.py +41 -0
- package/dist/packages/crucible/seeds/ruby/seed-001 2.rb +15 -0
- package/dist/packages/crucible/seeds/ruby/seed-001.rb +15 -0
- package/dist/packages/crucible/seeds/ruby/seed-002 2.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-002.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-003 2.rb +25 -0
- package/dist/packages/crucible/seeds/ruby/seed-003.rb +25 -0
- package/dist/packages/crucible/seeds/ruby/seed-004 2.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-004.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-005 2.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-005.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-006 2.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-006.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-007 2.rb +16 -0
- package/dist/packages/crucible/seeds/ruby/seed-007.rb +16 -0
- package/dist/packages/crucible/seeds/ruby/seed-008 2.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-008.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-009 2.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-009.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-010 2.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-010.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-011 2.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-011.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-012 2.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-012.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-013 2.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-013.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-014 2.rb +16 -0
- package/dist/packages/crucible/seeds/ruby/seed-014.rb +16 -0
- package/dist/packages/crucible/seeds/ruby/seed-015 2.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-015.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-016 2.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-016.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-017 2.rb +25 -0
- package/dist/packages/crucible/seeds/ruby/seed-017.rb +25 -0
- package/dist/packages/crucible/seeds/ruby/seed-018 2.rb +23 -0
- package/dist/packages/crucible/seeds/ruby/seed-018.rb +23 -0
- package/dist/packages/crucible/seeds/ruby/seed-019 2.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-019.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-020 2.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-020.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-021 2.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-021.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-022 2.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-022.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-023 2.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-023.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-024 2.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-024.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-025 2.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-025.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-026 2.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-026.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-027 2.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-027.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-028 2.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-028.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-029 2.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-029.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-030 2.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-030.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-031 2.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-031.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-032 2.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-032.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-033 2.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-033.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-034 2.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-034.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-035 2.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-035.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-036 2.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-036.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-037 2.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-037.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-038 2.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-038.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-039 2.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-039.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-040 2.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-040.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-041 2.rb +23 -0
- package/dist/packages/crucible/seeds/ruby/seed-041.rb +23 -0
- package/dist/packages/crucible/seeds/ruby/seed-042 2.rb +25 -0
- package/dist/packages/crucible/seeds/ruby/seed-042.rb +25 -0
- package/dist/packages/crucible/seeds/ruby/seed-043 2.rb +23 -0
- package/dist/packages/crucible/seeds/ruby/seed-043.rb +23 -0
- package/dist/packages/crucible/seeds/ruby/seed-044 2.rb +16 -0
- package/dist/packages/crucible/seeds/ruby/seed-044.rb +16 -0
- package/dist/packages/crucible/seeds/ruby/seed-045 2.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-045.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-046 2.rb +27 -0
- package/dist/packages/crucible/seeds/ruby/seed-046.rb +27 -0
- package/dist/packages/crucible/seeds/ruby/seed-047 2.rb +26 -0
- package/dist/packages/crucible/seeds/ruby/seed-047.rb +26 -0
- package/dist/packages/crucible/seeds/ruby/seed-048 2.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-048.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-049 2.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-049.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-050 2.rb +27 -0
- package/dist/packages/crucible/seeds/ruby/seed-050.rb +27 -0
- package/dist/packages/crucible/seeds/rust/seed-001 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-001.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-002 2.rs +20 -0
- package/dist/packages/crucible/seeds/rust/seed-002.rs +20 -0
- package/dist/packages/crucible/seeds/rust/seed-003 2.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-003.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-004 2.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-004.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-005 2.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-005.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-006 2.rs +24 -0
- package/dist/packages/crucible/seeds/rust/seed-006.rs +24 -0
- package/dist/packages/crucible/seeds/rust/seed-007 2.rs +20 -0
- package/dist/packages/crucible/seeds/rust/seed-007.rs +20 -0
- package/dist/packages/crucible/seeds/rust/seed-008 2.rs +19 -0
- package/dist/packages/crucible/seeds/rust/seed-008.rs +19 -0
- package/dist/packages/crucible/seeds/rust/seed-009 2.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-009.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-010 2.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-010.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-011 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-011.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-012 2.rs +31 -0
- package/dist/packages/crucible/seeds/rust/seed-012.rs +31 -0
- package/dist/packages/crucible/seeds/rust/seed-013 2.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-013.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-014 2.rs +30 -0
- package/dist/packages/crucible/seeds/rust/seed-014.rs +30 -0
- package/dist/packages/crucible/seeds/rust/seed-015 2.rs +33 -0
- package/dist/packages/crucible/seeds/rust/seed-015.rs +33 -0
- package/dist/packages/crucible/seeds/rust/seed-016 2.rs +22 -0
- package/dist/packages/crucible/seeds/rust/seed-016.rs +22 -0
- package/dist/packages/crucible/seeds/rust/seed-017 2.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-017.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-018 2.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-018.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-019 2.rs +36 -0
- package/dist/packages/crucible/seeds/rust/seed-019.rs +36 -0
- package/dist/packages/crucible/seeds/rust/seed-020 2.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-020.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-021 2.rs +26 -0
- package/dist/packages/crucible/seeds/rust/seed-021.rs +26 -0
- package/dist/packages/crucible/seeds/rust/seed-022 2.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-022.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-023 2.rs +22 -0
- package/dist/packages/crucible/seeds/rust/seed-023.rs +22 -0
- package/dist/packages/crucible/seeds/rust/seed-024 2.rs +24 -0
- package/dist/packages/crucible/seeds/rust/seed-024.rs +24 -0
- package/dist/packages/crucible/seeds/rust/seed-025 2.rs +29 -0
- package/dist/packages/crucible/seeds/rust/seed-025.rs +29 -0
- package/dist/packages/crucible/seeds/rust/seed-026 2.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-026.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-027 2.rs +24 -0
- package/dist/packages/crucible/seeds/rust/seed-027.rs +24 -0
- package/dist/packages/crucible/seeds/rust/seed-028 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-028.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-029 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-029.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-030 2.rs +30 -0
- package/dist/packages/crucible/seeds/rust/seed-030.rs +30 -0
- package/dist/packages/crucible/seeds/rust/seed-031 2.rs +22 -0
- package/dist/packages/crucible/seeds/rust/seed-031.rs +22 -0
- package/dist/packages/crucible/seeds/rust/seed-032 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-032.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-033 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-033.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-034 2.rs +20 -0
- package/dist/packages/crucible/seeds/rust/seed-034.rs +20 -0
- package/dist/packages/crucible/seeds/rust/seed-035 2.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-035.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-036 2.rs +26 -0
- package/dist/packages/crucible/seeds/rust/seed-036.rs +26 -0
- package/dist/packages/crucible/seeds/rust/seed-037 2.rs +31 -0
- package/dist/packages/crucible/seeds/rust/seed-037.rs +31 -0
- package/dist/packages/crucible/seeds/rust/seed-038 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-038.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-039 2.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-039.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-040 2.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-040.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-041 2.rs +32 -0
- package/dist/packages/crucible/seeds/rust/seed-041.rs +32 -0
- package/dist/packages/crucible/seeds/rust/seed-042 2.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-042.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-043 2.rs +29 -0
- package/dist/packages/crucible/seeds/rust/seed-043.rs +29 -0
- package/dist/packages/crucible/seeds/rust/seed-044 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-044.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-045 2.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-045.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-046 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-046.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-047 2.rs +34 -0
- package/dist/packages/crucible/seeds/rust/seed-047.rs +34 -0
- package/dist/packages/crucible/seeds/rust/seed-048 2.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-048.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-049 2.rs +26 -0
- package/dist/packages/crucible/seeds/rust/seed-049.rs +26 -0
- package/dist/packages/crucible/seeds/rust/seed-050 2.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-050.rs +23 -0
- package/dist/packages/crucible/seeds/ts/seed-001 2.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-001.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-002 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-002.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-003 2.ts +28 -0
- package/dist/packages/crucible/seeds/ts/seed-003.ts +28 -0
- package/dist/packages/crucible/seeds/ts/seed-004 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-004.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-005 2.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-005.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-006 2.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-006.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-007 2.ts +28 -0
- package/dist/packages/crucible/seeds/ts/seed-007.ts +28 -0
- package/dist/packages/crucible/seeds/ts/seed-008 2.ts +40 -0
- package/dist/packages/crucible/seeds/ts/seed-008.ts +40 -0
- package/dist/packages/crucible/seeds/ts/seed-009 2.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-009.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-010 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-010.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-011 2.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-011.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-012 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-012.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-013 2.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-013.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-014 2.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-014.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-015 2.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-015.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-016 2.ts +37 -0
- package/dist/packages/crucible/seeds/ts/seed-016.ts +37 -0
- package/dist/packages/crucible/seeds/ts/seed-017 2.ts +44 -0
- package/dist/packages/crucible/seeds/ts/seed-017.ts +44 -0
- package/dist/packages/crucible/seeds/ts/seed-018 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-018.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-019 2.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-019.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-020 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-020.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-021 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-021.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-022 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-022.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-023 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-023.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-024 2.ts +35 -0
- package/dist/packages/crucible/seeds/ts/seed-024.ts +35 -0
- package/dist/packages/crucible/seeds/ts/seed-025 2.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-025.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-026 2.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-026.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-027 2.ts +30 -0
- package/dist/packages/crucible/seeds/ts/seed-027.ts +30 -0
- package/dist/packages/crucible/seeds/ts/seed-028 2.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-028.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-029 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-029.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-030 2.ts +37 -0
- package/dist/packages/crucible/seeds/ts/seed-030.ts +37 -0
- package/dist/packages/crucible/seeds/ts/seed-031 2.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-031.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-032 2.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-032.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-033 2.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-033.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-034 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-034.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-035 2.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-035.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-036 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-036.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-037 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-037.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-038 2.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-038.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-039 2.ts +35 -0
- package/dist/packages/crucible/seeds/ts/seed-039.ts +35 -0
- package/dist/packages/crucible/seeds/ts/seed-040 2.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-040.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-041 2.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-041.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-042 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-042.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-043 2.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-043.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-044 2.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-044.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-045 2.ts +39 -0
- package/dist/packages/crucible/seeds/ts/seed-045.ts +39 -0
- package/dist/packages/crucible/seeds/ts/seed-046 2.ts +41 -0
- package/dist/packages/crucible/seeds/ts/seed-046.ts +41 -0
- package/dist/packages/crucible/seeds/ts/seed-047 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-047.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-048 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-048.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-049 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-049.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-050 2.ts +41 -0
- package/dist/packages/crucible/seeds/ts/seed-050.ts +41 -0
- package/dist/packages/crucible/seeds/ts/seed-051 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-051.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-052 2.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-052.ts +36 -0
- package/dist/packages/scanner/alert-manager.js +1 -0
- package/dist/packages/scanner/architecture-map.js +1 -0
- package/dist/packages/scanner/ast-analyzer.js +1 -0
- package/dist/packages/scanner/benchmarks.js +1 -0
- package/dist/packages/scanner/cfg-analyzer.js +1 -0
- package/dist/packages/scanner/code-scanner.js +1 -0
- package/dist/packages/scanner/compliance-mapper.js +1 -0
- package/dist/packages/scanner/file-collector.js +1 -0
- package/dist/packages/scanner/file-watcher.js +1 -0
- package/dist/packages/scanner/ghost-code-detector.js +1 -0
- package/dist/packages/scanner/git-velocity.js +1 -0
- package/dist/packages/scanner/hallucination-detector.js +1 -0
- package/dist/packages/scanner/health-checker.js +1 -0
- package/dist/packages/scanner/investor-report.js +1 -0
- package/dist/packages/scanner/json-file-util.js +1 -0
- package/dist/packages/scanner/monitor-store.js +1 -0
- package/dist/packages/scanner/python_ast_helper.py +426 -0
- package/dist/packages/scanner/risk-valuation.js +1 -0
- package/dist/packages/scanner/scan-history.js +1 -0
- package/dist/packages/scanner/secret-scanner.js +1 -0
- package/dist/packages/scanner/sentinel-core.js +1 -0
- package/dist/packages/scanner/supply-chain.js +1 -0
- package/dist/packages/scanner/support-bot.js +1 -0
- package/dist/packages/scanner/support-knowledge.js +1 -0
- package/dist/packages/scanner/taint-tracker.js +1 -0
- package/package.json +65 -65
- package/cli.js +0 -2
- package/packages/crucible/.golden/golden-master.json +0 -414
- package/packages/crucible/README.md +0 -93
- package/packages/crucible/report-generator.js +0 -1
- package/packages/crucible/rules/code-scanner-core.json +0 -281
- package/packages/crucible/rules/command-injection.json +0 -411
- package/packages/crucible/rules/crypto-misuse.json +0 -35
- package/packages/crucible/rules/deserialization.json +0 -152
- package/packages/crucible/rules/env-injection.json +0 -46
- package/packages/crucible/rules/eval-abuse.json +0 -104
- package/packages/crucible/rules/file-upload.json +0 -46
- package/packages/crucible/rules/hallucination.json +0 -22
- package/packages/crucible/rules/hardcoded-secret.json +0 -397
- package/packages/crucible/rules/hardcoded-url.json +0 -13
- package/packages/crucible/rules/insecure-crypto.json +0 -302
- package/packages/crucible/rules/integer-overflow.json +0 -35
- package/packages/crucible/rules/log-injection.json +0 -33
- package/packages/crucible/rules/mass-assignment.json +0 -112
- package/packages/crucible/rules/open-redirect.json +0 -196
- package/packages/crucible/rules/path-traversal.json +0 -422
- package/packages/crucible/rules/prototype-pollution.json +0 -22
- package/packages/crucible/rules/sql-injection.json +0 -619
- package/packages/crucible/rules/ssrf.json +0 -557
- package/packages/crucible/rules/timing-attack.json +0 -55
- package/packages/crucible/rules/unsafe-block.json +0 -24
- package/packages/crucible/rules/xss.json +0 -663
- package/packages/crucible/rules/xxe.json +0 -66
- package/packages/crucible/rules/yaml-deserialization.json +0 -22
- package/packages/crucible/rules/yaml-injection.json +0 -22
- package/packages/crucible/seeds/csharp/seed-001.cs +0 -28
- package/packages/crucible/seeds/csharp/seed-002.cs +0 -24
- package/packages/crucible/seeds/csharp/seed-003.cs +0 -30
- package/packages/crucible/seeds/csharp/seed-004.cs +0 -31
- package/packages/crucible/seeds/csharp/seed-005.cs +0 -28
- package/packages/crucible/seeds/csharp/seed-006.cs +0 -25
- package/packages/crucible/seeds/csharp/seed-007.cs +0 -34
- package/packages/crucible/seeds/csharp/seed-008.cs +0 -23
- package/packages/crucible/seeds/csharp/seed-009.cs +0 -27
- package/packages/crucible/seeds/csharp/seed-010.cs +0 -29
- package/packages/crucible/seeds/csharp/seed-011.cs +0 -32
- package/packages/crucible/seeds/csharp/seed-012.cs +0 -27
- package/packages/crucible/seeds/csharp/seed-013.cs +0 -27
- package/packages/crucible/seeds/csharp/seed-014.cs +0 -26
- package/packages/crucible/seeds/csharp/seed-015.cs +0 -33
- package/packages/crucible/seeds/csharp/seed-016.cs +0 -25
- package/packages/crucible/seeds/csharp/seed-017.cs +0 -22
- package/packages/crucible/seeds/csharp/seed-018.cs +0 -26
- package/packages/crucible/seeds/csharp/seed-019.cs +0 -25
- package/packages/crucible/seeds/csharp/seed-020.cs +0 -22
- package/packages/crucible/seeds/csharp/seed-021.cs +0 -28
- package/packages/crucible/seeds/csharp/seed-022.cs +0 -25
- package/packages/crucible/seeds/csharp/seed-023.cs +0 -33
- package/packages/crucible/seeds/csharp/seed-024.cs +0 -31
- package/packages/crucible/seeds/csharp/seed-025.cs +0 -31
- package/packages/crucible/seeds/csharp/seed-026.cs +0 -25
- package/packages/crucible/seeds/csharp/seed-027.cs +0 -29
- package/packages/crucible/seeds/csharp/seed-028.cs +0 -25
- package/packages/crucible/seeds/csharp/seed-029.cs +0 -27
- package/packages/crucible/seeds/csharp/seed-030.cs +0 -27
- package/packages/crucible/seeds/csharp/seed-031.cs +0 -28
- package/packages/crucible/seeds/csharp/seed-032.cs +0 -30
- package/packages/crucible/seeds/csharp/seed-033.cs +0 -27
- package/packages/crucible/seeds/csharp/seed-034.cs +0 -25
- package/packages/crucible/seeds/csharp/seed-035.cs +0 -32
- package/packages/crucible/seeds/csharp/seed-036.cs +0 -28
- package/packages/crucible/seeds/csharp/seed-037.cs +0 -29
- package/packages/crucible/seeds/csharp/seed-038.cs +0 -28
- package/packages/crucible/seeds/csharp/seed-039.cs +0 -29
- package/packages/crucible/seeds/csharp/seed-040.cs +0 -28
- package/packages/crucible/seeds/csharp/seed-041.cs +0 -33
- package/packages/crucible/seeds/csharp/seed-042.cs +0 -27
- package/packages/crucible/seeds/csharp/seed-043.cs +0 -27
- package/packages/crucible/seeds/csharp/seed-044.cs +0 -25
- package/packages/crucible/seeds/csharp/seed-045.cs +0 -30
- package/packages/crucible/seeds/csharp/seed-046.cs +0 -29
- package/packages/crucible/seeds/csharp/seed-047.cs +0 -26
- package/packages/crucible/seeds/csharp/seed-048.cs +0 -31
- package/packages/crucible/seeds/csharp/seed-049.cs +0 -27
- package/packages/crucible/seeds/csharp/seed-050.cs +0 -30
- package/packages/crucible/seeds/csharp/seed-051.cs +0 -34
- package/packages/crucible/seeds/csharp/seed-052.cs +0 -36
- package/packages/crucible/seeds/go/seed-001.go +0 -29
- package/packages/crucible/seeds/go/seed-002.go +0 -27
- package/packages/crucible/seeds/go/seed-003.go +0 -31
- package/packages/crucible/seeds/go/seed-004.go +0 -27
- package/packages/crucible/seeds/go/seed-005.go +0 -27
- package/packages/crucible/seeds/go/seed-006.go +0 -29
- package/packages/crucible/seeds/go/seed-007.go +0 -24
- package/packages/crucible/seeds/go/seed-008.go +0 -25
- package/packages/crucible/seeds/go/seed-009.go +0 -30
- package/packages/crucible/seeds/go/seed-010.go +0 -35
- package/packages/crucible/seeds/go/seed-011.go +0 -24
- package/packages/crucible/seeds/go/seed-012.go +0 -24
- package/packages/crucible/seeds/go/seed-013.go +0 -31
- package/packages/crucible/seeds/go/seed-014.go +0 -35
- package/packages/crucible/seeds/go/seed-015.go +0 -25
- package/packages/crucible/seeds/go/seed-016.go +0 -19
- package/packages/crucible/seeds/go/seed-017.go +0 -23
- package/packages/crucible/seeds/go/seed-018.go +0 -23
- package/packages/crucible/seeds/go/seed-019.go +0 -22
- package/packages/crucible/seeds/go/seed-020.go +0 -31
- package/packages/crucible/seeds/go/seed-021.go +0 -22
- package/packages/crucible/seeds/go/seed-022.go +0 -29
- package/packages/crucible/seeds/go/seed-023.go +0 -26
- package/packages/crucible/seeds/go/seed-024.go +0 -27
- package/packages/crucible/seeds/go/seed-025.go +0 -23
- package/packages/crucible/seeds/go/seed-026.go +0 -29
- package/packages/crucible/seeds/go/seed-027.go +0 -26
- package/packages/crucible/seeds/go/seed-028.go +0 -23
- package/packages/crucible/seeds/go/seed-029.go +0 -28
- package/packages/crucible/seeds/go/seed-030.go +0 -27
- package/packages/crucible/seeds/go/seed-031.go +0 -28
- package/packages/crucible/seeds/go/seed-032.go +0 -27
- package/packages/crucible/seeds/go/seed-033.go +0 -29
- package/packages/crucible/seeds/go/seed-034.go +0 -22
- package/packages/crucible/seeds/go/seed-035.go +0 -32
- package/packages/crucible/seeds/go/seed-036.go +0 -27
- package/packages/crucible/seeds/go/seed-037.go +0 -27
- package/packages/crucible/seeds/go/seed-038.go +0 -27
- package/packages/crucible/seeds/go/seed-039.go +0 -26
- package/packages/crucible/seeds/go/seed-040.go +0 -37
- package/packages/crucible/seeds/go/seed-041.go +0 -23
- package/packages/crucible/seeds/go/seed-042.go +0 -32
- package/packages/crucible/seeds/go/seed-043.go +0 -35
- package/packages/crucible/seeds/go/seed-044.go +0 -25
- package/packages/crucible/seeds/go/seed-045.go +0 -26
- package/packages/crucible/seeds/go/seed-046.go +0 -34
- package/packages/crucible/seeds/go/seed-047.go +0 -26
- package/packages/crucible/seeds/go/seed-048.go +0 -29
- package/packages/crucible/seeds/go/seed-049.go +0 -24
- package/packages/crucible/seeds/go/seed-050.go +0 -27
- package/packages/crucible/seeds/go/seed-051.go +0 -38
- package/packages/crucible/seeds/go/seed-052.go +0 -27
- package/packages/crucible/seeds/java/seed-001.java +0 -23
- package/packages/crucible/seeds/java/seed-002.java +0 -22
- package/packages/crucible/seeds/java/seed-003.java +0 -28
- package/packages/crucible/seeds/java/seed-004.java +0 -26
- package/packages/crucible/seeds/java/seed-005.java +0 -33
- package/packages/crucible/seeds/java/seed-006.java +0 -22
- package/packages/crucible/seeds/java/seed-007.java +0 -21
- package/packages/crucible/seeds/java/seed-008.java +0 -29
- package/packages/crucible/seeds/java/seed-009.java +0 -24
- package/packages/crucible/seeds/java/seed-010.java +0 -30
- package/packages/crucible/seeds/java/seed-011.java +0 -25
- package/packages/crucible/seeds/java/seed-012.java +0 -20
- package/packages/crucible/seeds/java/seed-013.java +0 -26
- package/packages/crucible/seeds/java/seed-014.java +0 -23
- package/packages/crucible/seeds/java/seed-015.java +0 -25
- package/packages/crucible/seeds/java/seed-016.java +0 -22
- package/packages/crucible/seeds/java/seed-017.java +0 -24
- package/packages/crucible/seeds/java/seed-018.java +0 -24
- package/packages/crucible/seeds/java/seed-019.java +0 -38
- package/packages/crucible/seeds/java/seed-020.java +0 -24
- package/packages/crucible/seeds/java/seed-021.java +0 -22
- package/packages/crucible/seeds/java/seed-022.java +0 -22
- package/packages/crucible/seeds/java/seed-023.java +0 -22
- package/packages/crucible/seeds/java/seed-024.java +0 -25
- package/packages/crucible/seeds/java/seed-025.java +0 -27
- package/packages/crucible/seeds/java/seed-026.java +0 -25
- package/packages/crucible/seeds/java/seed-027.java +0 -22
- package/packages/crucible/seeds/java/seed-028.java +0 -21
- package/packages/crucible/seeds/java/seed-029.java +0 -28
- package/packages/crucible/seeds/java/seed-030.java +0 -27
- package/packages/crucible/seeds/java/seed-031.java +0 -23
- package/packages/crucible/seeds/java/seed-032.java +0 -22
- package/packages/crucible/seeds/java/seed-033.java +0 -24
- package/packages/crucible/seeds/java/seed-034.java +0 -24
- package/packages/crucible/seeds/java/seed-035.java +0 -29
- package/packages/crucible/seeds/java/seed-036.java +0 -25
- package/packages/crucible/seeds/java/seed-037.java +0 -30
- package/packages/crucible/seeds/java/seed-038.java +0 -29
- package/packages/crucible/seeds/java/seed-039.java +0 -26
- package/packages/crucible/seeds/java/seed-040.java +0 -31
- package/packages/crucible/seeds/java/seed-041.java +0 -20
- package/packages/crucible/seeds/java/seed-042.java +0 -26
- package/packages/crucible/seeds/java/seed-043.java +0 -31
- package/packages/crucible/seeds/java/seed-044.java +0 -22
- package/packages/crucible/seeds/java/seed-045.java +0 -25
- package/packages/crucible/seeds/java/seed-046.java +0 -22
- package/packages/crucible/seeds/java/seed-047.java +0 -26
- package/packages/crucible/seeds/java/seed-048.java +0 -24
- package/packages/crucible/seeds/java/seed-049.java +0 -28
- package/packages/crucible/seeds/java/seed-050.java +0 -29
- package/packages/crucible/seeds/java/seed-051.java +0 -25
- package/packages/crucible/seeds/java/seed-052.java +0 -32
- package/packages/crucible/seeds/js/seed-001.js +0 -27
- package/packages/crucible/seeds/js/seed-002.js +0 -28
- package/packages/crucible/seeds/js/seed-003.js +0 -30
- package/packages/crucible/seeds/js/seed-004.js +0 -28
- package/packages/crucible/seeds/js/seed-005.js +0 -31
- package/packages/crucible/seeds/js/seed-006.js +0 -28
- package/packages/crucible/seeds/js/seed-007.js +0 -26
- package/packages/crucible/seeds/js/seed-008.js +0 -30
- package/packages/crucible/seeds/js/seed-009.js +0 -30
- package/packages/crucible/seeds/js/seed-010.js +0 -29
- package/packages/crucible/seeds/js/seed-011.js +0 -34
- package/packages/crucible/seeds/js/seed-012.js +0 -32
- package/packages/crucible/seeds/js/seed-013.js +0 -29
- package/packages/crucible/seeds/js/seed-014.js +0 -29
- package/packages/crucible/seeds/js/seed-015.js +0 -31
- package/packages/crucible/seeds/js/seed-016.js +0 -31
- package/packages/crucible/seeds/js/seed-017.js +0 -30
- package/packages/crucible/seeds/js/seed-018.js +0 -29
- package/packages/crucible/seeds/js/seed-019.js +0 -32
- package/packages/crucible/seeds/js/seed-020.js +0 -29
- package/packages/crucible/seeds/js/seed-021.js +0 -31
- package/packages/crucible/seeds/js/seed-022.js +0 -31
- package/packages/crucible/seeds/js/seed-023.js +0 -29
- package/packages/crucible/seeds/js/seed-024.js +0 -29
- package/packages/crucible/seeds/js/seed-025.js +0 -34
- package/packages/crucible/seeds/js/seed-026.js +0 -31
- package/packages/crucible/seeds/js/seed-027.js +0 -31
- package/packages/crucible/seeds/js/seed-028.js +0 -33
- package/packages/crucible/seeds/js/seed-029.js +0 -33
- package/packages/crucible/seeds/js/seed-030.js +0 -30
- package/packages/crucible/seeds/js/seed-031.js +0 -31
- package/packages/crucible/seeds/js/seed-032.js +0 -34
- package/packages/crucible/seeds/js/seed-033.js +0 -33
- package/packages/crucible/seeds/js/seed-034.js +0 -33
- package/packages/crucible/seeds/js/seed-035.js +0 -30
- package/packages/crucible/seeds/js/seed-036.js +0 -30
- package/packages/crucible/seeds/js/seed-037.js +0 -29
- package/packages/crucible/seeds/js/seed-038.js +0 -31
- package/packages/crucible/seeds/js/seed-039.js +0 -34
- package/packages/crucible/seeds/js/seed-040.js +0 -35
- package/packages/crucible/seeds/js/seed-041.js +0 -32
- package/packages/crucible/seeds/js/seed-042.js +0 -32
- package/packages/crucible/seeds/js/seed-043.js +0 -27
- package/packages/crucible/seeds/js/seed-044.js +0 -29
- package/packages/crucible/seeds/js/seed-045.js +0 -33
- package/packages/crucible/seeds/js/seed-046.js +0 -33
- package/packages/crucible/seeds/js/seed-047.js +0 -29
- package/packages/crucible/seeds/js/seed-048.js +0 -29
- package/packages/crucible/seeds/js/seed-049.js +0 -34
- package/packages/crucible/seeds/js/seed-050.js +0 -34
- package/packages/crucible/seeds/js/seed-051.js +0 -30
- package/packages/crucible/seeds/js/seed-052.js +0 -30
- package/packages/crucible/seeds/js/seed-053.js +0 -26
- package/packages/crucible/seeds/js/seed-054.js +0 -35
- package/packages/crucible/seeds/js/seed-055.js +0 -33
- package/packages/crucible/seeds/kotlin/seed-001.kt +0 -24
- package/packages/crucible/seeds/kotlin/seed-002.kt +0 -27
- package/packages/crucible/seeds/kotlin/seed-003.kt +0 -29
- package/packages/crucible/seeds/kotlin/seed-004.kt +0 -24
- package/packages/crucible/seeds/kotlin/seed-005.kt +0 -29
- package/packages/crucible/seeds/kotlin/seed-006.kt +0 -21
- package/packages/crucible/seeds/kotlin/seed-007.kt +0 -23
- package/packages/crucible/seeds/kotlin/seed-008.kt +0 -25
- package/packages/crucible/seeds/kotlin/seed-009.kt +0 -21
- package/packages/crucible/seeds/kotlin/seed-010.kt +0 -28
- package/packages/crucible/seeds/kotlin/seed-011.kt +0 -22
- package/packages/crucible/seeds/kotlin/seed-012.kt +0 -25
- package/packages/crucible/seeds/kotlin/seed-013.kt +0 -30
- package/packages/crucible/seeds/kotlin/seed-014.kt +0 -27
- package/packages/crucible/seeds/kotlin/seed-015.kt +0 -24
- package/packages/crucible/seeds/kotlin/seed-016.kt +0 -28
- package/packages/crucible/seeds/kotlin/seed-017.kt +0 -33
- package/packages/crucible/seeds/kotlin/seed-018.kt +0 -31
- package/packages/crucible/seeds/kotlin/seed-019.kt +0 -28
- package/packages/crucible/seeds/kotlin/seed-020.kt +0 -31
- package/packages/crucible/seeds/kotlin/seed-021.kt +0 -34
- package/packages/crucible/seeds/kotlin/seed-022.kt +0 -29
- package/packages/crucible/seeds/kotlin/seed-023.kt +0 -20
- package/packages/crucible/seeds/kotlin/seed-024.kt +0 -23
- package/packages/crucible/seeds/kotlin/seed-025.kt +0 -23
- package/packages/crucible/seeds/kotlin/seed-026.kt +0 -26
- package/packages/crucible/seeds/kotlin/seed-027.kt +0 -29
- package/packages/crucible/seeds/kotlin/seed-028.kt +0 -24
- package/packages/crucible/seeds/kotlin/seed-029.kt +0 -27
- package/packages/crucible/seeds/kotlin/seed-030.kt +0 -26
- package/packages/crucible/seeds/kotlin/seed-031.kt +0 -28
- package/packages/crucible/seeds/kotlin/seed-032.kt +0 -29
- package/packages/crucible/seeds/kotlin/seed-033.kt +0 -30
- package/packages/crucible/seeds/kotlin/seed-034.kt +0 -26
- package/packages/crucible/seeds/kotlin/seed-035.kt +0 -33
- package/packages/crucible/seeds/kotlin/seed-036.kt +0 -25
- package/packages/crucible/seeds/kotlin/seed-037.kt +0 -26
- package/packages/crucible/seeds/kotlin/seed-038.kt +0 -25
- package/packages/crucible/seeds/kotlin/seed-039.kt +0 -29
- package/packages/crucible/seeds/kotlin/seed-040.kt +0 -28
- package/packages/crucible/seeds/kotlin/seed-041.kt +0 -31
- package/packages/crucible/seeds/kotlin/seed-042.kt +0 -27
- package/packages/crucible/seeds/kotlin/seed-043.kt +0 -26
- package/packages/crucible/seeds/kotlin/seed-044.kt +0 -27
- package/packages/crucible/seeds/kotlin/seed-045.kt +0 -27
- package/packages/crucible/seeds/kotlin/seed-046.kt +0 -33
- package/packages/crucible/seeds/kotlin/seed-047.kt +0 -32
- package/packages/crucible/seeds/kotlin/seed-048.kt +0 -20
- package/packages/crucible/seeds/kotlin/seed-049.kt +0 -23
- package/packages/crucible/seeds/kotlin/seed-050.kt +0 -19
- package/packages/crucible/seeds/php/seed-001.php +0 -23
- package/packages/crucible/seeds/php/seed-002.php +0 -18
- package/packages/crucible/seeds/php/seed-003.php +0 -25
- package/packages/crucible/seeds/php/seed-004.php +0 -21
- package/packages/crucible/seeds/php/seed-005.php +0 -21
- package/packages/crucible/seeds/php/seed-006.php +0 -21
- package/packages/crucible/seeds/php/seed-007.php +0 -18
- package/packages/crucible/seeds/php/seed-008.php +0 -19
- package/packages/crucible/seeds/php/seed-009.php +0 -24
- package/packages/crucible/seeds/php/seed-010.php +0 -24
- package/packages/crucible/seeds/php/seed-011.php +0 -18
- package/packages/crucible/seeds/php/seed-012.php +0 -24
- package/packages/crucible/seeds/php/seed-013.php +0 -23
- package/packages/crucible/seeds/php/seed-014.php +0 -20
- package/packages/crucible/seeds/php/seed-015.php +0 -18
- package/packages/crucible/seeds/php/seed-016.php +0 -18
- package/packages/crucible/seeds/php/seed-017.php +0 -18
- package/packages/crucible/seeds/php/seed-018.php +0 -17
- package/packages/crucible/seeds/php/seed-019.php +0 -24
- package/packages/crucible/seeds/php/seed-020.php +0 -19
- package/packages/crucible/seeds/php/seed-021.php +0 -22
- package/packages/crucible/seeds/php/seed-022.php +0 -15
- package/packages/crucible/seeds/php/seed-023.php +0 -24
- package/packages/crucible/seeds/php/seed-024.php +0 -22
- package/packages/crucible/seeds/php/seed-025.php +0 -20
- package/packages/crucible/seeds/php/seed-026.php +0 -22
- package/packages/crucible/seeds/php/seed-027.php +0 -15
- package/packages/crucible/seeds/php/seed-028.php +0 -15
- package/packages/crucible/seeds/php/seed-029.php +0 -21
- package/packages/crucible/seeds/php/seed-030.php +0 -21
- package/packages/crucible/seeds/php/seed-031.php +0 -23
- package/packages/crucible/seeds/php/seed-032.php +0 -18
- package/packages/crucible/seeds/php/seed-033.php +0 -18
- package/packages/crucible/seeds/php/seed-034.php +0 -24
- package/packages/crucible/seeds/php/seed-035.php +0 -22
- package/packages/crucible/seeds/php/seed-036.php +0 -17
- package/packages/crucible/seeds/php/seed-037.php +0 -19
- package/packages/crucible/seeds/php/seed-038.php +0 -20
- package/packages/crucible/seeds/php/seed-039.php +0 -15
- package/packages/crucible/seeds/php/seed-040.php +0 -21
- package/packages/crucible/seeds/php/seed-041.php +0 -20
- package/packages/crucible/seeds/php/seed-042.php +0 -21
- package/packages/crucible/seeds/php/seed-043.php +0 -21
- package/packages/crucible/seeds/php/seed-044.php +0 -25
- package/packages/crucible/seeds/php/seed-045.php +0 -25
- package/packages/crucible/seeds/php/seed-046.php +0 -20
- package/packages/crucible/seeds/php/seed-047.php +0 -21
- package/packages/crucible/seeds/php/seed-048.php +0 -19
- package/packages/crucible/seeds/php/seed-049.php +0 -18
- package/packages/crucible/seeds/php/seed-050.php +0 -20
- package/packages/crucible/seeds/python/seed-001.py +0 -33
- package/packages/crucible/seeds/python/seed-002.py +0 -39
- package/packages/crucible/seeds/python/seed-003.py +0 -31
- package/packages/crucible/seeds/python/seed-004.py +0 -33
- package/packages/crucible/seeds/python/seed-005.py +0 -33
- package/packages/crucible/seeds/python/seed-006.py +0 -34
- package/packages/crucible/seeds/python/seed-007.py +0 -33
- package/packages/crucible/seeds/python/seed-008.py +0 -38
- package/packages/crucible/seeds/python/seed-009.py +0 -38
- package/packages/crucible/seeds/python/seed-010.py +0 -42
- package/packages/crucible/seeds/python/seed-011.py +0 -30
- package/packages/crucible/seeds/python/seed-012.py +0 -35
- package/packages/crucible/seeds/python/seed-013.py +0 -33
- package/packages/crucible/seeds/python/seed-014.py +0 -40
- package/packages/crucible/seeds/python/seed-015.py +0 -33
- package/packages/crucible/seeds/python/seed-016.py +0 -34
- package/packages/crucible/seeds/python/seed-017.py +0 -34
- package/packages/crucible/seeds/python/seed-018.py +0 -30
- package/packages/crucible/seeds/python/seed-019.py +0 -33
- package/packages/crucible/seeds/python/seed-020.py +0 -37
- package/packages/crucible/seeds/python/seed-021 2.py +0 -37
- package/packages/crucible/seeds/python/seed-021.py +0 -37
- package/packages/crucible/seeds/python/seed-022 2.py +0 -34
- package/packages/crucible/seeds/python/seed-022.py +0 -34
- package/packages/crucible/seeds/python/seed-023 2.py +0 -37
- package/packages/crucible/seeds/python/seed-023.py +0 -37
- package/packages/crucible/seeds/python/seed-024 2.py +0 -38
- package/packages/crucible/seeds/python/seed-024.py +0 -38
- package/packages/crucible/seeds/python/seed-025 2.py +0 -40
- package/packages/crucible/seeds/python/seed-025.py +0 -40
- package/packages/crucible/seeds/python/seed-026 2.py +0 -35
- package/packages/crucible/seeds/python/seed-026.py +0 -35
- package/packages/crucible/seeds/python/seed-027 2.py +0 -35
- package/packages/crucible/seeds/python/seed-027.py +0 -35
- package/packages/crucible/seeds/python/seed-028 2.py +0 -42
- package/packages/crucible/seeds/python/seed-028.py +0 -42
- package/packages/crucible/seeds/python/seed-029.py +0 -42
- package/packages/crucible/seeds/python/seed-030 2.py +0 -37
- package/packages/crucible/seeds/python/seed-030.py +0 -37
- package/packages/crucible/seeds/python/seed-031 2.py +0 -34
- package/packages/crucible/seeds/python/seed-031.py +0 -34
- package/packages/crucible/seeds/python/seed-032.py +0 -33
- package/packages/crucible/seeds/python/seed-033.py +0 -32
- package/packages/crucible/seeds/python/seed-034.py +0 -38
- package/packages/crucible/seeds/python/seed-035.py +0 -35
- package/packages/crucible/seeds/python/seed-036 2.py +0 -33
- package/packages/crucible/seeds/python/seed-036.py +0 -33
- package/packages/crucible/seeds/python/seed-037 2.py +0 -41
- package/packages/crucible/seeds/python/seed-037.py +0 -41
- package/packages/crucible/seeds/python/seed-038 2.py +0 -33
- package/packages/crucible/seeds/python/seed-038.py +0 -33
- package/packages/crucible/seeds/python/seed-039 2.py +0 -39
- package/packages/crucible/seeds/python/seed-039.py +0 -39
- package/packages/crucible/seeds/python/seed-040 2.py +0 -39
- package/packages/crucible/seeds/python/seed-040.py +0 -39
- package/packages/crucible/seeds/python/seed-041 2.py +0 -37
- package/packages/crucible/seeds/python/seed-041.py +0 -37
- package/packages/crucible/seeds/python/seed-042 2.py +0 -38
- package/packages/crucible/seeds/python/seed-042.py +0 -38
- package/packages/crucible/seeds/python/seed-043 2.py +0 -32
- package/packages/crucible/seeds/python/seed-043.py +0 -32
- package/packages/crucible/seeds/python/seed-044 2.py +0 -38
- package/packages/crucible/seeds/python/seed-044.py +0 -38
- package/packages/crucible/seeds/python/seed-045 2.py +0 -36
- package/packages/crucible/seeds/python/seed-045.py +0 -36
- package/packages/crucible/seeds/python/seed-046 2.py +0 -33
- package/packages/crucible/seeds/python/seed-046.py +0 -33
- package/packages/crucible/seeds/python/seed-047 2.py +0 -44
- package/packages/crucible/seeds/python/seed-047.py +0 -44
- package/packages/crucible/seeds/python/seed-048 2.py +0 -35
- package/packages/crucible/seeds/python/seed-048.py +0 -35
- package/packages/crucible/seeds/python/seed-049 2.py +0 -39
- package/packages/crucible/seeds/python/seed-049.py +0 -39
- package/packages/crucible/seeds/python/seed-050 2.py +0 -39
- package/packages/crucible/seeds/python/seed-050.py +0 -39
- package/packages/crucible/seeds/python/seed-051 2.py +0 -38
- package/packages/crucible/seeds/python/seed-051.py +0 -38
- package/packages/crucible/seeds/python/seed-052 2.py +0 -41
- package/packages/crucible/seeds/python/seed-052.py +0 -41
- package/packages/crucible/seeds/ruby/seed-001 2.rb +0 -15
- package/packages/crucible/seeds/ruby/seed-001.rb +0 -15
- package/packages/crucible/seeds/ruby/seed-002 2.rb +0 -22
- package/packages/crucible/seeds/ruby/seed-002.rb +0 -22
- package/packages/crucible/seeds/ruby/seed-003 2.rb +0 -25
- package/packages/crucible/seeds/ruby/seed-003.rb +0 -25
- package/packages/crucible/seeds/ruby/seed-004 2.rb +0 -17
- package/packages/crucible/seeds/ruby/seed-004.rb +0 -17
- package/packages/crucible/seeds/ruby/seed-005 2.rb +0 -21
- package/packages/crucible/seeds/ruby/seed-005.rb +0 -21
- package/packages/crucible/seeds/ruby/seed-006 2.rb +0 -17
- package/packages/crucible/seeds/ruby/seed-006.rb +0 -17
- package/packages/crucible/seeds/ruby/seed-007 2.rb +0 -16
- package/packages/crucible/seeds/ruby/seed-007.rb +0 -16
- package/packages/crucible/seeds/ruby/seed-008 2.rb +0 -18
- package/packages/crucible/seeds/ruby/seed-008.rb +0 -18
- package/packages/crucible/seeds/ruby/seed-009 2.rb +0 -20
- package/packages/crucible/seeds/ruby/seed-009.rb +0 -20
- package/packages/crucible/seeds/ruby/seed-010 2.rb +0 -24
- package/packages/crucible/seeds/ruby/seed-010.rb +0 -24
- package/packages/crucible/seeds/ruby/seed-011 2.rb +0 -21
- package/packages/crucible/seeds/ruby/seed-011.rb +0 -21
- package/packages/crucible/seeds/ruby/seed-012 2.rb +0 -22
- package/packages/crucible/seeds/ruby/seed-012.rb +0 -22
- package/packages/crucible/seeds/ruby/seed-013 2.rb +0 -21
- package/packages/crucible/seeds/ruby/seed-013.rb +0 -21
- package/packages/crucible/seeds/ruby/seed-014 2.rb +0 -16
- package/packages/crucible/seeds/ruby/seed-014.rb +0 -16
- package/packages/crucible/seeds/ruby/seed-015 2.rb +0 -18
- package/packages/crucible/seeds/ruby/seed-015.rb +0 -18
- package/packages/crucible/seeds/ruby/seed-016 2.rb +0 -17
- package/packages/crucible/seeds/ruby/seed-016.rb +0 -17
- package/packages/crucible/seeds/ruby/seed-017 2.rb +0 -25
- package/packages/crucible/seeds/ruby/seed-017.rb +0 -25
- package/packages/crucible/seeds/ruby/seed-018 2.rb +0 -23
- package/packages/crucible/seeds/ruby/seed-018.rb +0 -23
- package/packages/crucible/seeds/ruby/seed-019 2.rb +0 -20
- package/packages/crucible/seeds/ruby/seed-019.rb +0 -20
- package/packages/crucible/seeds/ruby/seed-020 2.rb +0 -17
- package/packages/crucible/seeds/ruby/seed-020.rb +0 -17
- package/packages/crucible/seeds/ruby/seed-021 2.rb +0 -20
- package/packages/crucible/seeds/ruby/seed-021.rb +0 -20
- package/packages/crucible/seeds/ruby/seed-022 2.rb +0 -21
- package/packages/crucible/seeds/ruby/seed-022.rb +0 -21
- package/packages/crucible/seeds/ruby/seed-023 2.rb +0 -19
- package/packages/crucible/seeds/ruby/seed-023.rb +0 -19
- package/packages/crucible/seeds/ruby/seed-024 2.rb +0 -17
- package/packages/crucible/seeds/ruby/seed-024.rb +0 -17
- package/packages/crucible/seeds/ruby/seed-025 2.rb +0 -17
- package/packages/crucible/seeds/ruby/seed-025.rb +0 -17
- package/packages/crucible/seeds/ruby/seed-026 2.rb +0 -18
- package/packages/crucible/seeds/ruby/seed-026.rb +0 -18
- package/packages/crucible/seeds/ruby/seed-027 2.rb +0 -21
- package/packages/crucible/seeds/ruby/seed-027.rb +0 -21
- package/packages/crucible/seeds/ruby/seed-028 2.rb +0 -22
- package/packages/crucible/seeds/ruby/seed-028.rb +0 -22
- package/packages/crucible/seeds/ruby/seed-029 2.rb +0 -19
- package/packages/crucible/seeds/ruby/seed-029.rb +0 -19
- package/packages/crucible/seeds/ruby/seed-030 2.rb +0 -20
- package/packages/crucible/seeds/ruby/seed-030.rb +0 -20
- package/packages/crucible/seeds/ruby/seed-031 2.rb +0 -17
- package/packages/crucible/seeds/ruby/seed-031.rb +0 -17
- package/packages/crucible/seeds/ruby/seed-032 2.rb +0 -22
- package/packages/crucible/seeds/ruby/seed-032.rb +0 -22
- package/packages/crucible/seeds/ruby/seed-033 2.rb +0 -18
- package/packages/crucible/seeds/ruby/seed-033.rb +0 -18
- package/packages/crucible/seeds/ruby/seed-034 2.rb +0 -19
- package/packages/crucible/seeds/ruby/seed-034.rb +0 -19
- package/packages/crucible/seeds/ruby/seed-035 2.rb +0 -19
- package/packages/crucible/seeds/ruby/seed-035.rb +0 -19
- package/packages/crucible/seeds/ruby/seed-036 2.rb +0 -18
- package/packages/crucible/seeds/ruby/seed-036.rb +0 -18
- package/packages/crucible/seeds/ruby/seed-037 2.rb +0 -21
- package/packages/crucible/seeds/ruby/seed-037.rb +0 -21
- package/packages/crucible/seeds/ruby/seed-038 2.rb +0 -24
- package/packages/crucible/seeds/ruby/seed-038.rb +0 -24
- package/packages/crucible/seeds/ruby/seed-039 2.rb +0 -24
- package/packages/crucible/seeds/ruby/seed-039.rb +0 -24
- package/packages/crucible/seeds/ruby/seed-040 2.rb +0 -22
- package/packages/crucible/seeds/ruby/seed-040.rb +0 -22
- package/packages/crucible/seeds/ruby/seed-041 2.rb +0 -23
- package/packages/crucible/seeds/ruby/seed-041.rb +0 -23
- package/packages/crucible/seeds/ruby/seed-042 2.rb +0 -25
- package/packages/crucible/seeds/ruby/seed-042.rb +0 -25
- package/packages/crucible/seeds/ruby/seed-043 2.rb +0 -23
- package/packages/crucible/seeds/ruby/seed-043.rb +0 -23
- package/packages/crucible/seeds/ruby/seed-044 2.rb +0 -16
- package/packages/crucible/seeds/ruby/seed-044.rb +0 -16
- package/packages/crucible/seeds/ruby/seed-045 2.rb +0 -22
- package/packages/crucible/seeds/ruby/seed-045.rb +0 -22
- package/packages/crucible/seeds/ruby/seed-046 2.rb +0 -27
- package/packages/crucible/seeds/ruby/seed-046.rb +0 -27
- package/packages/crucible/seeds/ruby/seed-047 2.rb +0 -26
- package/packages/crucible/seeds/ruby/seed-047.rb +0 -26
- package/packages/crucible/seeds/ruby/seed-048 2.rb +0 -24
- package/packages/crucible/seeds/ruby/seed-048.rb +0 -24
- package/packages/crucible/seeds/ruby/seed-049 2.rb +0 -20
- package/packages/crucible/seeds/ruby/seed-049.rb +0 -20
- package/packages/crucible/seeds/ruby/seed-050 2.rb +0 -27
- package/packages/crucible/seeds/ruby/seed-050.rb +0 -27
- package/packages/crucible/seeds/rust/seed-001 2.rs +0 -25
- package/packages/crucible/seeds/rust/seed-001.rs +0 -25
- package/packages/crucible/seeds/rust/seed-002 2.rs +0 -20
- package/packages/crucible/seeds/rust/seed-002.rs +0 -20
- package/packages/crucible/seeds/rust/seed-003 2.rs +0 -23
- package/packages/crucible/seeds/rust/seed-003.rs +0 -23
- package/packages/crucible/seeds/rust/seed-004 2.rs +0 -21
- package/packages/crucible/seeds/rust/seed-004.rs +0 -21
- package/packages/crucible/seeds/rust/seed-005 2.rs +0 -21
- package/packages/crucible/seeds/rust/seed-005.rs +0 -21
- package/packages/crucible/seeds/rust/seed-006 2.rs +0 -24
- package/packages/crucible/seeds/rust/seed-006.rs +0 -24
- package/packages/crucible/seeds/rust/seed-007 2.rs +0 -20
- package/packages/crucible/seeds/rust/seed-007.rs +0 -20
- package/packages/crucible/seeds/rust/seed-008 2.rs +0 -19
- package/packages/crucible/seeds/rust/seed-008.rs +0 -19
- package/packages/crucible/seeds/rust/seed-009 2.rs +0 -28
- package/packages/crucible/seeds/rust/seed-009.rs +0 -28
- package/packages/crucible/seeds/rust/seed-010 2.rs +0 -28
- package/packages/crucible/seeds/rust/seed-010.rs +0 -28
- package/packages/crucible/seeds/rust/seed-011 2.rs +0 -25
- package/packages/crucible/seeds/rust/seed-011.rs +0 -25
- package/packages/crucible/seeds/rust/seed-012 2.rs +0 -31
- package/packages/crucible/seeds/rust/seed-012.rs +0 -31
- package/packages/crucible/seeds/rust/seed-013 2.rs +0 -27
- package/packages/crucible/seeds/rust/seed-013.rs +0 -27
- package/packages/crucible/seeds/rust/seed-014 2.rs +0 -30
- package/packages/crucible/seeds/rust/seed-014.rs +0 -30
- package/packages/crucible/seeds/rust/seed-015 2.rs +0 -33
- package/packages/crucible/seeds/rust/seed-015.rs +0 -33
- package/packages/crucible/seeds/rust/seed-016 2.rs +0 -22
- package/packages/crucible/seeds/rust/seed-016.rs +0 -22
- package/packages/crucible/seeds/rust/seed-017 2.rs +0 -28
- package/packages/crucible/seeds/rust/seed-017.rs +0 -28
- package/packages/crucible/seeds/rust/seed-018 2.rs +0 -21
- package/packages/crucible/seeds/rust/seed-018.rs +0 -21
- package/packages/crucible/seeds/rust/seed-019 2.rs +0 -36
- package/packages/crucible/seeds/rust/seed-019.rs +0 -36
- package/packages/crucible/seeds/rust/seed-020 2.rs +0 -27
- package/packages/crucible/seeds/rust/seed-020.rs +0 -27
- package/packages/crucible/seeds/rust/seed-021 2.rs +0 -26
- package/packages/crucible/seeds/rust/seed-021.rs +0 -26
- package/packages/crucible/seeds/rust/seed-022 2.rs +0 -23
- package/packages/crucible/seeds/rust/seed-022.rs +0 -23
- package/packages/crucible/seeds/rust/seed-023 2.rs +0 -22
- package/packages/crucible/seeds/rust/seed-023.rs +0 -22
- package/packages/crucible/seeds/rust/seed-024 2.rs +0 -24
- package/packages/crucible/seeds/rust/seed-024.rs +0 -24
- package/packages/crucible/seeds/rust/seed-025 2.rs +0 -29
- package/packages/crucible/seeds/rust/seed-025.rs +0 -29
- package/packages/crucible/seeds/rust/seed-026 2.rs +0 -23
- package/packages/crucible/seeds/rust/seed-026.rs +0 -23
- package/packages/crucible/seeds/rust/seed-027 2.rs +0 -24
- package/packages/crucible/seeds/rust/seed-027.rs +0 -24
- package/packages/crucible/seeds/rust/seed-028 2.rs +0 -25
- package/packages/crucible/seeds/rust/seed-028.rs +0 -25
- package/packages/crucible/seeds/rust/seed-029 2.rs +0 -25
- package/packages/crucible/seeds/rust/seed-029.rs +0 -25
- package/packages/crucible/seeds/rust/seed-030 2.rs +0 -30
- package/packages/crucible/seeds/rust/seed-030.rs +0 -30
- package/packages/crucible/seeds/rust/seed-031 2.rs +0 -22
- package/packages/crucible/seeds/rust/seed-031.rs +0 -22
- package/packages/crucible/seeds/rust/seed-032 2.rs +0 -25
- package/packages/crucible/seeds/rust/seed-032.rs +0 -25
- package/packages/crucible/seeds/rust/seed-033 2.rs +0 -25
- package/packages/crucible/seeds/rust/seed-033.rs +0 -25
- package/packages/crucible/seeds/rust/seed-034 2.rs +0 -20
- package/packages/crucible/seeds/rust/seed-034.rs +0 -20
- package/packages/crucible/seeds/rust/seed-035 2.rs +0 -28
- package/packages/crucible/seeds/rust/seed-035.rs +0 -28
- package/packages/crucible/seeds/rust/seed-036 2.rs +0 -26
- package/packages/crucible/seeds/rust/seed-036.rs +0 -26
- package/packages/crucible/seeds/rust/seed-037 2.rs +0 -31
- package/packages/crucible/seeds/rust/seed-037.rs +0 -31
- package/packages/crucible/seeds/rust/seed-038 2.rs +0 -25
- package/packages/crucible/seeds/rust/seed-038.rs +0 -25
- package/packages/crucible/seeds/rust/seed-039 2.rs +0 -28
- package/packages/crucible/seeds/rust/seed-039.rs +0 -28
- package/packages/crucible/seeds/rust/seed-040 2.rs +0 -27
- package/packages/crucible/seeds/rust/seed-040.rs +0 -27
- package/packages/crucible/seeds/rust/seed-041 2.rs +0 -32
- package/packages/crucible/seeds/rust/seed-041.rs +0 -32
- package/packages/crucible/seeds/rust/seed-042 2.rs +0 -27
- package/packages/crucible/seeds/rust/seed-042.rs +0 -27
- package/packages/crucible/seeds/rust/seed-043 2.rs +0 -29
- package/packages/crucible/seeds/rust/seed-043.rs +0 -29
- package/packages/crucible/seeds/rust/seed-044 2.rs +0 -25
- package/packages/crucible/seeds/rust/seed-044.rs +0 -25
- package/packages/crucible/seeds/rust/seed-045 2.rs +0 -28
- package/packages/crucible/seeds/rust/seed-045.rs +0 -28
- package/packages/crucible/seeds/rust/seed-046 2.rs +0 -25
- package/packages/crucible/seeds/rust/seed-046.rs +0 -25
- package/packages/crucible/seeds/rust/seed-047 2.rs +0 -34
- package/packages/crucible/seeds/rust/seed-047.rs +0 -34
- package/packages/crucible/seeds/rust/seed-048 2.rs +0 -21
- package/packages/crucible/seeds/rust/seed-048.rs +0 -21
- package/packages/crucible/seeds/rust/seed-049 2.rs +0 -26
- package/packages/crucible/seeds/rust/seed-049.rs +0 -26
- package/packages/crucible/seeds/rust/seed-050 2.rs +0 -23
- package/packages/crucible/seeds/rust/seed-050.rs +0 -23
- package/packages/crucible/seeds/ts/seed-001 2.ts +0 -32
- package/packages/crucible/seeds/ts/seed-001.ts +0 -32
- package/packages/crucible/seeds/ts/seed-002 2.ts +0 -34
- package/packages/crucible/seeds/ts/seed-002.ts +0 -34
- package/packages/crucible/seeds/ts/seed-003 2.ts +0 -28
- package/packages/crucible/seeds/ts/seed-003.ts +0 -28
- package/packages/crucible/seeds/ts/seed-004 2.ts +0 -34
- package/packages/crucible/seeds/ts/seed-004.ts +0 -34
- package/packages/crucible/seeds/ts/seed-005 2.ts +0 -32
- package/packages/crucible/seeds/ts/seed-005.ts +0 -32
- package/packages/crucible/seeds/ts/seed-006 2.ts +0 -31
- package/packages/crucible/seeds/ts/seed-006.ts +0 -31
- package/packages/crucible/seeds/ts/seed-007 2.ts +0 -28
- package/packages/crucible/seeds/ts/seed-007.ts +0 -28
- package/packages/crucible/seeds/ts/seed-008 2.ts +0 -40
- package/packages/crucible/seeds/ts/seed-008.ts +0 -40
- package/packages/crucible/seeds/ts/seed-009 2.ts +0 -31
- package/packages/crucible/seeds/ts/seed-009.ts +0 -31
- package/packages/crucible/seeds/ts/seed-010 2.ts +0 -33
- package/packages/crucible/seeds/ts/seed-010.ts +0 -33
- package/packages/crucible/seeds/ts/seed-011 2.ts +0 -29
- package/packages/crucible/seeds/ts/seed-011.ts +0 -29
- package/packages/crucible/seeds/ts/seed-012 2.ts +0 -34
- package/packages/crucible/seeds/ts/seed-012.ts +0 -34
- package/packages/crucible/seeds/ts/seed-013 2.ts +0 -31
- package/packages/crucible/seeds/ts/seed-013.ts +0 -31
- package/packages/crucible/seeds/ts/seed-014 2.ts +0 -36
- package/packages/crucible/seeds/ts/seed-014.ts +0 -36
- package/packages/crucible/seeds/ts/seed-015 2.ts +0 -31
- package/packages/crucible/seeds/ts/seed-015.ts +0 -31
- package/packages/crucible/seeds/ts/seed-016 2.ts +0 -37
- package/packages/crucible/seeds/ts/seed-016.ts +0 -37
- package/packages/crucible/seeds/ts/seed-017 2.ts +0 -44
- package/packages/crucible/seeds/ts/seed-017.ts +0 -44
- package/packages/crucible/seeds/ts/seed-018 2.ts +0 -33
- package/packages/crucible/seeds/ts/seed-018.ts +0 -33
- package/packages/crucible/seeds/ts/seed-019 2.ts +0 -32
- package/packages/crucible/seeds/ts/seed-019.ts +0 -32
- package/packages/crucible/seeds/ts/seed-020 2.ts +0 -33
- package/packages/crucible/seeds/ts/seed-020.ts +0 -33
- package/packages/crucible/seeds/ts/seed-021 2.ts +0 -33
- package/packages/crucible/seeds/ts/seed-021.ts +0 -33
- package/packages/crucible/seeds/ts/seed-022 2.ts +0 -34
- package/packages/crucible/seeds/ts/seed-022.ts +0 -34
- package/packages/crucible/seeds/ts/seed-023 2.ts +0 -33
- package/packages/crucible/seeds/ts/seed-023.ts +0 -33
- package/packages/crucible/seeds/ts/seed-024 2.ts +0 -35
- package/packages/crucible/seeds/ts/seed-024.ts +0 -35
- package/packages/crucible/seeds/ts/seed-025 2.ts +0 -29
- package/packages/crucible/seeds/ts/seed-025.ts +0 -29
- package/packages/crucible/seeds/ts/seed-026 2.ts +0 -36
- package/packages/crucible/seeds/ts/seed-026.ts +0 -36
- package/packages/crucible/seeds/ts/seed-027 2.ts +0 -30
- package/packages/crucible/seeds/ts/seed-027.ts +0 -30
- package/packages/crucible/seeds/ts/seed-028 2.ts +0 -32
- package/packages/crucible/seeds/ts/seed-028.ts +0 -32
- package/packages/crucible/seeds/ts/seed-029 2.ts +0 -34
- package/packages/crucible/seeds/ts/seed-029.ts +0 -34
- package/packages/crucible/seeds/ts/seed-030 2.ts +0 -37
- package/packages/crucible/seeds/ts/seed-030.ts +0 -37
- package/packages/crucible/seeds/ts/seed-031 2.ts +0 -31
- package/packages/crucible/seeds/ts/seed-031.ts +0 -31
- package/packages/crucible/seeds/ts/seed-032 2.ts +0 -32
- package/packages/crucible/seeds/ts/seed-032.ts +0 -32
- package/packages/crucible/seeds/ts/seed-033 2.ts +0 -32
- package/packages/crucible/seeds/ts/seed-033.ts +0 -32
- package/packages/crucible/seeds/ts/seed-034 2.ts +0 -34
- package/packages/crucible/seeds/ts/seed-034.ts +0 -34
- package/packages/crucible/seeds/ts/seed-035 2.ts +0 -29
- package/packages/crucible/seeds/ts/seed-035.ts +0 -29
- package/packages/crucible/seeds/ts/seed-036 2.ts +0 -34
- package/packages/crucible/seeds/ts/seed-036.ts +0 -34
- package/packages/crucible/seeds/ts/seed-037 2.ts +0 -33
- package/packages/crucible/seeds/ts/seed-037.ts +0 -33
- package/packages/crucible/seeds/ts/seed-038 2.ts +0 -29
- package/packages/crucible/seeds/ts/seed-038.ts +0 -29
- package/packages/crucible/seeds/ts/seed-039 2.ts +0 -35
- package/packages/crucible/seeds/ts/seed-039.ts +0 -35
- package/packages/crucible/seeds/ts/seed-040 2.ts +0 -31
- package/packages/crucible/seeds/ts/seed-040.ts +0 -31
- package/packages/crucible/seeds/ts/seed-041 2.ts +0 -29
- package/packages/crucible/seeds/ts/seed-041.ts +0 -29
- package/packages/crucible/seeds/ts/seed-042 2.ts +0 -33
- package/packages/crucible/seeds/ts/seed-042.ts +0 -33
- package/packages/crucible/seeds/ts/seed-043 2.ts +0 -32
- package/packages/crucible/seeds/ts/seed-043.ts +0 -32
- package/packages/crucible/seeds/ts/seed-044 2.ts +0 -36
- package/packages/crucible/seeds/ts/seed-044.ts +0 -36
- package/packages/crucible/seeds/ts/seed-045 2.ts +0 -39
- package/packages/crucible/seeds/ts/seed-045.ts +0 -39
- package/packages/crucible/seeds/ts/seed-046 2.ts +0 -41
- package/packages/crucible/seeds/ts/seed-046.ts +0 -41
- package/packages/crucible/seeds/ts/seed-047 2.ts +0 -33
- package/packages/crucible/seeds/ts/seed-047.ts +0 -33
- package/packages/crucible/seeds/ts/seed-048 2.ts +0 -33
- package/packages/crucible/seeds/ts/seed-048.ts +0 -33
- package/packages/crucible/seeds/ts/seed-049 2.ts +0 -34
- package/packages/crucible/seeds/ts/seed-049.ts +0 -34
- package/packages/crucible/seeds/ts/seed-050 2.ts +0 -41
- package/packages/crucible/seeds/ts/seed-050.ts +0 -41
- package/packages/crucible/seeds/ts/seed-051 2.ts +0 -34
- package/packages/crucible/seeds/ts/seed-051.ts +0 -34
- package/packages/crucible/seeds/ts/seed-052 2.ts +0 -36
- package/packages/crucible/seeds/ts/seed-052.ts +0 -36
- package/packages/scanner/alert-manager.js +0 -1
- package/packages/scanner/ast-analyzer.js +0 -1
- package/packages/scanner/cfg-analyzer.js +0 -1
- package/packages/scanner/code-scanner.js +0 -1
- package/packages/scanner/file-collector.js +0 -1
- package/packages/scanner/file-watcher.js +0 -1
- package/packages/scanner/ghost-code-detector.js +0 -1
- package/packages/scanner/hallucination-detector.js +0 -1
- package/packages/scanner/health-checker.js +0 -1
- package/packages/scanner/investor-report.js +0 -1
- package/packages/scanner/master-health-checker.js +0 -1
- package/packages/scanner/monitor-store.js +0 -1
- package/packages/scanner/python_ast_helper.py +0 -426
- package/packages/scanner/secret-scanner.js +0 -1
- package/packages/scanner/sentinel-core.js +0 -1
- package/packages/scanner/support-bot.js +0 -1
- package/packages/scanner/support-knowledge.js +0 -1
- package/packages/scanner/taint-tracker.js +0 -1
- /package/{packages → dist/packages}/crucible/badge-generator.js +0 -0
- /package/{packages → dist/packages}/crucible/banner.js +0 -0
- /package/{packages → dist/packages}/crucible/ci-integration.js +0 -0
- /package/{packages → dist/packages}/crucible/golden-master.js +0 -0
- /package/{packages → dist/packages}/crucible/index.js +0 -0
- /package/{packages → dist/packages}/crucible/kenny-mode.js +0 -0
- /package/{packages → dist/packages}/crucible/leaderboard.js +0 -0
- /package/{packages → dist/packages}/crucible/mutation-engine.js +0 -0
- /package/{packages → dist/packages}/crucible/pattern-learner.js +0 -0
- /package/{packages → dist/packages}/crucible/rule-loader.js +0 -0
- /package/{packages → dist/packages}/crucible/seeding-engine.js +0 -0
- /package/{packages → dist/packages}/crucible/self-attack.js +0 -0
- /package/{packages → dist/packages}/scanner/ai-confidence-scorer.js +0 -0
- /package/{packages → dist/packages}/scanner/baseline-manager.js +0 -0
- /package/{packages → dist/packages}/scanner/codebase-passport.js +0 -0
- /package/{packages → dist/packages}/scanner/copy-paste-detector.js +0 -0
- /package/{packages → dist/packages}/scanner/dependency-graph.js +0 -0
- /package/{packages → dist/packages}/scanner/drift-detector.js +0 -0
- /package/{packages → dist/packages}/scanner/executive-report.js +0 -0
- /package/{packages → dist/packages}/scanner/export-verifier.js +0 -0
- /package/{packages → dist/packages}/scanner/feedback-client.js +0 -0
- /package/{packages → dist/packages}/scanner/go-ast-analyzer.js +0 -0
- /package/{packages → dist/packages}/scanner/html-report.js +0 -0
- /package/{packages → dist/packages}/scanner/index.js +0 -0
- /package/{packages → dist/packages}/scanner/license-manager.js +0 -0
- /package/{packages → dist/packages}/scanner/monitor-notifier.js +0 -0
- /package/{packages → dist/packages}/scanner/monitor-service.js +0 -0
- /package/{packages → dist/packages}/scanner/pre-commit-gate.js +0 -0
- /package/{packages → dist/packages}/scanner/python-ast-analyzer.js +0 -0
- /package/{packages → dist/packages}/scanner/read-file.js +0 -0
- /package/{packages → dist/packages}/scanner/scan-diff.js +0 -0
- /package/{packages → dist/packages}/scanner/scan-runner.js +0 -0
- /package/{packages → dist/packages}/scanner/sentinel-knowledge.js +0 -0
- /package/{packages → dist/packages}/scanner/slack-notifier.js +0 -0
- /package/{packages → dist/packages}/scanner/tech-debt-analyzer.js +0 -0
- /package/{packages → dist/packages}/scanner/tech-debt-cost.js +0 -0
- /package/{packages → dist/packages}/scanner/widget-generator.js +0 -0
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Thuban Python AST Helper
|
|
4
|
+
|
|
5
|
+
Reads Python source from stdin, parses it with the built-in `ast` module,
|
|
6
|
+
and prints a single-line JSON report to stdout describing:
|
|
7
|
+
|
|
8
|
+
- unused_import Imported names never referenced anywhere in the file
|
|
9
|
+
- unused_variable Local variables assigned in a function but never read
|
|
10
|
+
- high_complexity Functions whose McCabe cyclomatic complexity exceeds
|
|
11
|
+
COMPLEXITY_THRESHOLD
|
|
12
|
+
- dead_code Statements that are unreachable because they follow
|
|
13
|
+
an unconditional return/raise/break/continue in the
|
|
14
|
+
same block
|
|
15
|
+
- bare_except `except:` clauses with no exception type
|
|
16
|
+
- mutable_default_arg Function parameters defaulting to a mutable literal
|
|
17
|
+
(list/dict/set) or list()/dict()/set() call
|
|
18
|
+
|
|
19
|
+
This script is invoked by packages/scanner/python-ast-analyzer.js as a
|
|
20
|
+
subprocess (one call per Python file). It must never raise past main() -
|
|
21
|
+
on any parse failure it prints {"ok": false, "error": "..."} and exits 0,
|
|
22
|
+
so the caller can treat AST analysis as a best-effort supplement.
|
|
23
|
+
|
|
24
|
+
Output contract (stdout, single JSON object):
|
|
25
|
+
{"ok": true, "issues": [{"type": str, "line": int, "name": str|null, "message": str}, ...]}
|
|
26
|
+
{"ok": false, "error": str}
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
import ast
|
|
30
|
+
import json
|
|
31
|
+
import sys
|
|
32
|
+
|
|
33
|
+
COMPLEXITY_THRESHOLD = 10
|
|
34
|
+
|
|
35
|
+
TERMINATOR_TYPES = (ast.Return, ast.Raise, ast.Continue, ast.Break)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
39
|
+
# Unused imports
|
|
40
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
class _UnusedImportChecker:
|
|
43
|
+
def __init__(self, tree):
|
|
44
|
+
self.tree = tree
|
|
45
|
+
self.imports = [] # [{'name', 'line', 'source'}]
|
|
46
|
+
self.used_names = set()
|
|
47
|
+
self.dunder_all_names = set()
|
|
48
|
+
|
|
49
|
+
def collect(self):
|
|
50
|
+
for node in ast.walk(self.tree):
|
|
51
|
+
if isinstance(node, ast.Import):
|
|
52
|
+
for alias in node.names:
|
|
53
|
+
if alias.name == '*':
|
|
54
|
+
continue
|
|
55
|
+
bound = alias.asname or alias.name.split('.')[0]
|
|
56
|
+
self.imports.append({'name': bound, 'line': node.lineno, 'source': ''})
|
|
57
|
+
elif isinstance(node, ast.ImportFrom):
|
|
58
|
+
if node.module == '__future__':
|
|
59
|
+
continue
|
|
60
|
+
for alias in node.names:
|
|
61
|
+
if alias.name == '*':
|
|
62
|
+
continue
|
|
63
|
+
bound = alias.asname or alias.name
|
|
64
|
+
self.imports.append({'name': bound, 'line': node.lineno, 'source': node.module or ''})
|
|
65
|
+
elif isinstance(node, ast.Name) and isinstance(node.ctx, ast.Load):
|
|
66
|
+
self.used_names.add(node.id)
|
|
67
|
+
elif isinstance(node, ast.Assign):
|
|
68
|
+
for target in node.targets:
|
|
69
|
+
if isinstance(target, ast.Name) and target.id == '__all__' and \
|
|
70
|
+
isinstance(node.value, (ast.List, ast.Tuple, ast.Set)):
|
|
71
|
+
for elt in node.value.elts:
|
|
72
|
+
if isinstance(elt, ast.Constant) and isinstance(elt.value, str):
|
|
73
|
+
self.dunder_all_names.add(elt.value)
|
|
74
|
+
|
|
75
|
+
def unused(self):
|
|
76
|
+
issues = []
|
|
77
|
+
seen = set()
|
|
78
|
+
for imp in self.imports:
|
|
79
|
+
name = imp['name']
|
|
80
|
+
if name.startswith('_'):
|
|
81
|
+
continue
|
|
82
|
+
if name in self.used_names or name in self.dunder_all_names:
|
|
83
|
+
continue
|
|
84
|
+
key = (name, imp['line'])
|
|
85
|
+
if key in seen:
|
|
86
|
+
continue
|
|
87
|
+
seen.add(key)
|
|
88
|
+
source_suffix = " from '%s'" % imp['source'] if imp['source'] else ''
|
|
89
|
+
issues.append({
|
|
90
|
+
'type': 'unused_import',
|
|
91
|
+
'line': imp['line'],
|
|
92
|
+
'name': name,
|
|
93
|
+
'message': "Unused import: '%s'%s" % (name, source_suffix),
|
|
94
|
+
})
|
|
95
|
+
return issues
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
99
|
+
# Per-function analysis: complexity, unused locals, mutable defaults
|
|
100
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
101
|
+
|
|
102
|
+
class _ComplexityVisitor(ast.NodeVisitor):
|
|
103
|
+
"""Counts McCabe decision points within a single function's own body,
|
|
104
|
+
stopping at nested function/lambda boundaries (those are analyzed
|
|
105
|
+
independently when ast.walk() reaches them on its own)."""
|
|
106
|
+
|
|
107
|
+
def __init__(self):
|
|
108
|
+
self.complexity = 1
|
|
109
|
+
|
|
110
|
+
def visit_If(self, node):
|
|
111
|
+
self.complexity += 1
|
|
112
|
+
self.generic_visit(node)
|
|
113
|
+
|
|
114
|
+
def visit_For(self, node):
|
|
115
|
+
self.complexity += 1
|
|
116
|
+
self.generic_visit(node)
|
|
117
|
+
|
|
118
|
+
def visit_AsyncFor(self, node):
|
|
119
|
+
self.complexity += 1
|
|
120
|
+
self.generic_visit(node)
|
|
121
|
+
|
|
122
|
+
def visit_While(self, node):
|
|
123
|
+
self.complexity += 1
|
|
124
|
+
self.generic_visit(node)
|
|
125
|
+
|
|
126
|
+
def visit_IfExp(self, node):
|
|
127
|
+
self.complexity += 1
|
|
128
|
+
self.generic_visit(node)
|
|
129
|
+
|
|
130
|
+
def visit_ExceptHandler(self, node):
|
|
131
|
+
self.complexity += 1
|
|
132
|
+
self.generic_visit(node)
|
|
133
|
+
|
|
134
|
+
def visit_BoolOp(self, node):
|
|
135
|
+
self.complexity += max(len(node.values) - 1, 0)
|
|
136
|
+
self.generic_visit(node)
|
|
137
|
+
|
|
138
|
+
def visit_comprehension(self, node):
|
|
139
|
+
self.complexity += len(node.ifs)
|
|
140
|
+
self.generic_visit(node)
|
|
141
|
+
|
|
142
|
+
# Nested scopes get their own complexity computation - don't descend.
|
|
143
|
+
def visit_FunctionDef(self, node):
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
def visit_AsyncFunctionDef(self, node):
|
|
147
|
+
pass
|
|
148
|
+
|
|
149
|
+
def visit_Lambda(self, node):
|
|
150
|
+
pass
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _compute_complexity(fn):
|
|
154
|
+
visitor = _ComplexityVisitor()
|
|
155
|
+
for stmt in fn.body:
|
|
156
|
+
visitor.visit(stmt)
|
|
157
|
+
return visitor.complexity
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _is_mutable_default(default):
|
|
161
|
+
if isinstance(default, (ast.List, ast.Dict, ast.Set)):
|
|
162
|
+
return True
|
|
163
|
+
if isinstance(default, ast.Call) and isinstance(default.func, ast.Name):
|
|
164
|
+
return default.func.id in ('list', 'dict', 'set')
|
|
165
|
+
return False
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _mutable_defaults(fn):
|
|
169
|
+
issues = []
|
|
170
|
+
args = fn.args
|
|
171
|
+
positional = list(getattr(args, 'posonlyargs', [])) + list(args.args)
|
|
172
|
+
if args.defaults:
|
|
173
|
+
for arg, default in zip(reversed(positional), reversed(args.defaults)):
|
|
174
|
+
if _is_mutable_default(default):
|
|
175
|
+
issues.append({
|
|
176
|
+
'type': 'mutable_default_arg',
|
|
177
|
+
'line': default.lineno,
|
|
178
|
+
'name': arg.arg,
|
|
179
|
+
'message': "Mutable default argument '%s' in function '%s' - shared across all calls" % (arg.arg, fn.name),
|
|
180
|
+
})
|
|
181
|
+
for arg, default in zip(args.kwonlyargs, args.kw_defaults or []):
|
|
182
|
+
if default is not None and _is_mutable_default(default):
|
|
183
|
+
issues.append({
|
|
184
|
+
'type': 'mutable_default_arg',
|
|
185
|
+
'line': default.lineno,
|
|
186
|
+
'name': arg.arg,
|
|
187
|
+
'message': "Mutable default argument '%s' in function '%s' - shared across all calls" % (arg.arg, fn.name),
|
|
188
|
+
})
|
|
189
|
+
return issues
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class _LocalAssignCollector(ast.NodeVisitor):
|
|
193
|
+
"""Collects simple (single-Name-target) local assignments made directly
|
|
194
|
+
within a function's own body - not inside nested function/lambda
|
|
195
|
+
scopes, which own their own locals."""
|
|
196
|
+
|
|
197
|
+
def __init__(self):
|
|
198
|
+
self.assigned = {} # name -> first assignment line
|
|
199
|
+
self.declared_global_nonlocal = set()
|
|
200
|
+
|
|
201
|
+
def visit_Assign(self, node):
|
|
202
|
+
if len(node.targets) == 1 and isinstance(node.targets[0], ast.Name):
|
|
203
|
+
name = node.targets[0].id
|
|
204
|
+
self.assigned.setdefault(name, node.lineno)
|
|
205
|
+
self.generic_visit(node)
|
|
206
|
+
|
|
207
|
+
def visit_AnnAssign(self, node):
|
|
208
|
+
if isinstance(node.target, ast.Name) and node.value is not None:
|
|
209
|
+
self.assigned.setdefault(node.target.id, node.lineno)
|
|
210
|
+
self.generic_visit(node)
|
|
211
|
+
|
|
212
|
+
def visit_For(self, node):
|
|
213
|
+
if isinstance(node.target, ast.Name):
|
|
214
|
+
self.assigned.setdefault(node.target.id, node.lineno)
|
|
215
|
+
self.generic_visit(node)
|
|
216
|
+
|
|
217
|
+
def visit_With(self, node):
|
|
218
|
+
for item in node.items:
|
|
219
|
+
if item.optional_vars is not None and isinstance(item.optional_vars, ast.Name):
|
|
220
|
+
self.assigned.setdefault(item.optional_vars.id, node.lineno)
|
|
221
|
+
self.generic_visit(node)
|
|
222
|
+
|
|
223
|
+
def visit_Global(self, node):
|
|
224
|
+
self.declared_global_nonlocal.update(node.names)
|
|
225
|
+
|
|
226
|
+
def visit_Nonlocal(self, node):
|
|
227
|
+
self.declared_global_nonlocal.update(node.names)
|
|
228
|
+
|
|
229
|
+
def visit_FunctionDef(self, node):
|
|
230
|
+
pass
|
|
231
|
+
|
|
232
|
+
def visit_AsyncFunctionDef(self, node):
|
|
233
|
+
pass
|
|
234
|
+
|
|
235
|
+
def visit_Lambda(self, node):
|
|
236
|
+
pass
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class _LoadNameCollector(ast.NodeVisitor):
|
|
240
|
+
"""Collects every Name read (Load context) anywhere within a subtree,
|
|
241
|
+
INCLUDING nested functions/lambdas - a variable captured by a closure
|
|
242
|
+
still counts as used."""
|
|
243
|
+
|
|
244
|
+
def __init__(self):
|
|
245
|
+
self.loaded = set()
|
|
246
|
+
|
|
247
|
+
def visit_Name(self, node):
|
|
248
|
+
if isinstance(node.ctx, ast.Load):
|
|
249
|
+
self.loaded.add(node.id)
|
|
250
|
+
self.generic_visit(node)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _unused_locals(fn):
|
|
254
|
+
assign_collector = _LocalAssignCollector()
|
|
255
|
+
for stmt in fn.body:
|
|
256
|
+
assign_collector.visit(stmt)
|
|
257
|
+
|
|
258
|
+
load_collector = _LoadNameCollector()
|
|
259
|
+
load_collector.visit(fn)
|
|
260
|
+
|
|
261
|
+
issues = []
|
|
262
|
+
for name, line in assign_collector.assigned.items():
|
|
263
|
+
if name.startswith('_'):
|
|
264
|
+
continue
|
|
265
|
+
if name in assign_collector.declared_global_nonlocal:
|
|
266
|
+
continue
|
|
267
|
+
if name in load_collector.loaded:
|
|
268
|
+
continue
|
|
269
|
+
issues.append({
|
|
270
|
+
'type': 'unused_variable',
|
|
271
|
+
'line': line,
|
|
272
|
+
'name': name,
|
|
273
|
+
'message': "Variable '%s' is assigned but never used" % name,
|
|
274
|
+
})
|
|
275
|
+
return issues
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
279
|
+
# Dead code (unreachable statements)
|
|
280
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
281
|
+
|
|
282
|
+
def _check_block(stmts, issues):
|
|
283
|
+
for i, stmt in enumerate(stmts):
|
|
284
|
+
if isinstance(stmt, TERMINATOR_TYPES):
|
|
285
|
+
if i + 1 < len(stmts):
|
|
286
|
+
nxt = stmts[i + 1]
|
|
287
|
+
kind = type(stmt).__name__.lower()
|
|
288
|
+
issues.append({
|
|
289
|
+
'type': 'dead_code',
|
|
290
|
+
'line': nxt.lineno,
|
|
291
|
+
'name': None,
|
|
292
|
+
'message': "Unreachable code after '%s' statement" % kind,
|
|
293
|
+
})
|
|
294
|
+
break # only report the first unreachable run per block
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
class _DeadCodeVisitor(ast.NodeVisitor):
|
|
298
|
+
def __init__(self):
|
|
299
|
+
self.issues = []
|
|
300
|
+
|
|
301
|
+
def visit_Module(self, node):
|
|
302
|
+
_check_block(node.body, self.issues)
|
|
303
|
+
self.generic_visit(node)
|
|
304
|
+
|
|
305
|
+
def visit_FunctionDef(self, node):
|
|
306
|
+
_check_block(node.body, self.issues)
|
|
307
|
+
self.generic_visit(node)
|
|
308
|
+
|
|
309
|
+
def visit_AsyncFunctionDef(self, node):
|
|
310
|
+
_check_block(node.body, self.issues)
|
|
311
|
+
self.generic_visit(node)
|
|
312
|
+
|
|
313
|
+
def visit_If(self, node):
|
|
314
|
+
_check_block(node.body, self.issues)
|
|
315
|
+
_check_block(node.orelse, self.issues)
|
|
316
|
+
self.generic_visit(node)
|
|
317
|
+
|
|
318
|
+
def visit_For(self, node):
|
|
319
|
+
_check_block(node.body, self.issues)
|
|
320
|
+
_check_block(node.orelse, self.issues)
|
|
321
|
+
self.generic_visit(node)
|
|
322
|
+
|
|
323
|
+
def visit_AsyncFor(self, node):
|
|
324
|
+
_check_block(node.body, self.issues)
|
|
325
|
+
_check_block(node.orelse, self.issues)
|
|
326
|
+
self.generic_visit(node)
|
|
327
|
+
|
|
328
|
+
def visit_While(self, node):
|
|
329
|
+
_check_block(node.body, self.issues)
|
|
330
|
+
_check_block(node.orelse, self.issues)
|
|
331
|
+
self.generic_visit(node)
|
|
332
|
+
|
|
333
|
+
def visit_Try(self, node):
|
|
334
|
+
_check_block(node.body, self.issues)
|
|
335
|
+
for handler in node.handlers:
|
|
336
|
+
_check_block(handler.body, self.issues)
|
|
337
|
+
_check_block(node.orelse, self.issues)
|
|
338
|
+
_check_block(node.finalbody, self.issues)
|
|
339
|
+
self.generic_visit(node)
|
|
340
|
+
|
|
341
|
+
def visit_With(self, node):
|
|
342
|
+
_check_block(node.body, self.issues)
|
|
343
|
+
self.generic_visit(node)
|
|
344
|
+
|
|
345
|
+
def visit_AsyncWith(self, node):
|
|
346
|
+
_check_block(node.body, self.issues)
|
|
347
|
+
self.generic_visit(node)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
351
|
+
# Suspicious patterns: bare except
|
|
352
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
353
|
+
|
|
354
|
+
def _find_bare_except(tree):
|
|
355
|
+
issues = []
|
|
356
|
+
for node in ast.walk(tree):
|
|
357
|
+
if isinstance(node, ast.ExceptHandler) and node.type is None:
|
|
358
|
+
issues.append({
|
|
359
|
+
'type': 'bare_except',
|
|
360
|
+
'line': node.lineno,
|
|
361
|
+
'name': None,
|
|
362
|
+
'message': "Bare 'except:' catches all exceptions including SystemExit/KeyboardInterrupt - catch specific exception types instead",
|
|
363
|
+
})
|
|
364
|
+
return issues
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
368
|
+
# Entry point
|
|
369
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
370
|
+
|
|
371
|
+
def main():
|
|
372
|
+
source = sys.stdin.read()
|
|
373
|
+
|
|
374
|
+
try:
|
|
375
|
+
tree = ast.parse(source)
|
|
376
|
+
except SyntaxError as e:
|
|
377
|
+
print(json.dumps({'ok': False, 'error': 'SyntaxError: %s' % e}))
|
|
378
|
+
return
|
|
379
|
+
except Exception as e: # pragma: no cover - defensive
|
|
380
|
+
print(json.dumps({'ok': False, 'error': str(e)}))
|
|
381
|
+
return
|
|
382
|
+
|
|
383
|
+
issues = []
|
|
384
|
+
|
|
385
|
+
try:
|
|
386
|
+
importer = _UnusedImportChecker(tree)
|
|
387
|
+
importer.collect()
|
|
388
|
+
issues.extend(importer.unused())
|
|
389
|
+
except Exception:
|
|
390
|
+
pass
|
|
391
|
+
|
|
392
|
+
try:
|
|
393
|
+
for node in ast.walk(tree):
|
|
394
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
395
|
+
issues.extend(_mutable_defaults(node))
|
|
396
|
+
complexity = _compute_complexity(node)
|
|
397
|
+
if complexity > COMPLEXITY_THRESHOLD:
|
|
398
|
+
issues.append({
|
|
399
|
+
'type': 'high_complexity',
|
|
400
|
+
'line': node.lineno,
|
|
401
|
+
'name': node.name,
|
|
402
|
+
'message': "Function '%s' has cyclomatic complexity %d (threshold %d)" % (
|
|
403
|
+
node.name, complexity, COMPLEXITY_THRESHOLD),
|
|
404
|
+
})
|
|
405
|
+
issues.extend(_unused_locals(node))
|
|
406
|
+
except Exception:
|
|
407
|
+
pass
|
|
408
|
+
|
|
409
|
+
try:
|
|
410
|
+
dead_code_visitor = _DeadCodeVisitor()
|
|
411
|
+
dead_code_visitor.visit(tree)
|
|
412
|
+
issues.extend(dead_code_visitor.issues)
|
|
413
|
+
except Exception:
|
|
414
|
+
pass
|
|
415
|
+
|
|
416
|
+
try:
|
|
417
|
+
issues.extend(_find_bare_except(tree))
|
|
418
|
+
except Exception:
|
|
419
|
+
pass
|
|
420
|
+
|
|
421
|
+
issues.sort(key=lambda i: i.get('line') or 0)
|
|
422
|
+
print(json.dumps({'ok': True, 'issues': issues}))
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
if __name__ == '__main__':
|
|
426
|
+
main()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const RISK_PROFILES={sqlInjection:{label:"SQL Injection",probability:.35,probabilityLabel:"High",impactMin:12e5,impactMax:32e5,source:"IBM Cost of a Data Breach — breach involving injection/database compromise"},xss:{label:"Cross-Site Scripting (XSS)",probability:.25,probabilityLabel:"Medium",impactMin:3e5,impactMax:9e5,source:"Industry incident-response data — client-side compromise / session hijack"},authBypass:{label:"Authentication Bypass",probability:.3,probabilityLabel:"High",impactMin:5e5,impactMax:15e5,source:"Account takeover remediation + notification cost benchmarks"},hardcodedSecret:{label:"Hardcoded Secret / Credential",probability:.2,probabilityLabel:"Medium",impactMin:2e5,impactMax:8e5,source:"Credential leak incident response + key rotation cost"},hallucinatedApi:{label:"Hallucinated / Phantom API Call",probability:.55,probabilityLabel:"High",impactMin:1e4,impactMax:5e4,source:"Production incident / outage cost for runtime crash"},deprecatedApi:{label:"Deprecated API Usage",probability:.15,probabilityLabel:"Low",impactMin:5e3,impactMax:25e3,source:"Future breakage remediation cost"},injectionGeneric:{label:"Injection / Taint Risk (Generic)",probability:.25,probabilityLabel:"Medium",impactMin:4e5,impactMax:12e5,source:"IBM Cost of a Data Breach — generic injection-class vulnerability"},ghostCode:{label:"Ghost / Dead Code",probability:.05,probabilityLabel:"Low",impactMin:1e3,impactMax:8e3,source:"Maintenance overhead / accidental re-activation risk"},codeClone:{label:"Code Clone / Duplication",probability:.08,probabilityLabel:"Low",impactMin:2e3,impactMax:15e3,source:"Divergent-fix maintenance risk (bug fixed in one clone, not others)"},qualityGeneric:{label:"Code Quality Issue (Generic)",probability:.05,probabilityLabel:"Low",impactMin:500,impactMax:5e3,source:"General defect / maintenance cost"}},DEV_HOURLY_RATE=150;function classifyIssue(e){const i=`${e.message||""} ${e.name||""} ${e.id||""}`.toLowerCase(),t=(e.category||"").toLowerCase();return"info"===e.severity?null:i.includes("sql")&&i.includes("inject")?"sqlInjection":i.includes("xss")||i.includes("cross-site")?"xss":i.includes("auth")&&(i.includes("bypass")||i.includes("missing")||i.includes("weak"))?"authBypass":i.includes("secret")||i.includes("hardcoded")||i.includes("credential")||i.includes("api key")||i.includes("apikey")||"secret"===t||"secret-history"===t?"hardcodedSecret":i.includes("inject")||i.includes("taint")||"security"===t?"injectionGeneric":"quality"===t||"style"===t?"qualityGeneric":null}const FIX_HOURS_BY_TYPE={sqlInjection:3,xss:2,authBypass:4,hardcodedSecret:1,hallucinatedApi:2,deprecatedApi:1.5,injectionGeneric:2.5,ghostCode:.5,codeClone:3,qualityGeneric:.3};function calculateRiskValuation(e={}){const i=e.scanResults||{},t=e.hallResults||{},a=e.ghostResults||{},o=e.cloneResults||{},c={},n=(e,i=1)=>{c[e]||(c[e]=0),c[e]+=i};for(const e of i.issues||[]){const i=classifyIssue(e);i&&n(i)}const s=(t.phantomAPIs||[]).length,l=(t.deprecatedAPIs||[]).length;s>0&&n("hallucinatedApi",s),l>0&&n("deprecatedApi",l);const r=a.totalGhosts||0;r>0&&n("ghostCode",r);const u=o.totalClusters||0;u>0&&n("codeClone",u);const d=[];let p=0,b=0,y=0;for(const[e,i]of Object.entries(c)){if(i<=0)continue;const t=RISK_PROFILES[e];if(!t)continue;const a=i*t.impactMax,o=i*t.impactMin,c=(t.impactMin+t.impactMax)/2,n=i*t.probability*c,s=i*(FIX_HOURS_BY_TYPE[e]||1),l=150*s;p+=a,b+=n,y+=s,d.push({typeKey:e,label:t.label,count:i,probability:t.probability,probabilityLabel:t.probabilityLabel,impactMin:o,impactMax:a,expectedLoss:Math.round(n),fixHours:Math.round(10*s)/10,fixCost:Math.round(l),source:t.source})}d.sort((e,i)=>i.expectedLoss-e.expectedLoss);const h=Math.round(150*y);p=Math.round(p),b=Math.round(b);let m=null,M=null;return h>0&&(m=Math.round((b-h)/h*100),M=Math.round(b/h*10)/10),{byType:d,totalMaxExposure:p,totalExpectedLoss:b,costToFix:h,fixHours:Math.round(10*y)/10,hourlyRate:150,roi:m,roiMultiple:M,hasFindings:d.length>0}}module.exports={calculateRiskValuation:calculateRiskValuation,RISK_PROFILES:RISK_PROFILES,DEV_HOURLY_RATE:150};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const fs=require("fs"),path=require("path"),HISTORY_FILENAME=".thuban-history.json",MAX_ENTRIES=500;function historyPath(e){return path.join(path.resolve(e),HISTORY_FILENAME)}function loadHistory(e){const t=historyPath(e);if(!fs.existsSync(t))return{entries:[]};try{const e=JSON.parse(fs.readFileSync(t,"utf-8"));return Array.isArray(e)?{entries:e}:{entries:Array.isArray(e.entries)?e.entries:[]}}catch{return{entries:[]}}}function recordScan(e,t){const r=historyPath(e),n=loadHistory(e),s={date:(new Date).toISOString(),trustScore:"number"==typeof t.trustScore?t.trustScore:null,crucibleScore:"number"==typeof t.crucibleScore?t.crucibleScore:null,findingsByType:t.findingsByType||{}};n.entries.push(s),n.entries.length>500&&(n.entries=n.entries.slice(n.entries.length-500));try{fs.writeFileSync(r,JSON.stringify({_version:"1.0.0",entries:n.entries},null,2),"utf-8")}catch{}return n.entries}function analyzeTrend(e){const t=(e||[]).filter(e=>"number"==typeof e.trustScore);if(0===t.length)return{hasHistory:!1,isFirstScan:!0,scanCount:0,direction:null,avgMonthlyChange:null,firstScore:null,latestScore:null,totalChange:null,series:[]};if(1===t.length)return{hasHistory:!0,isFirstScan:!0,scanCount:1,direction:null,avgMonthlyChange:null,firstScore:t[0].trustScore,latestScore:t[0].trustScore,totalChange:0,series:t};const r=t[0],n=t[t.length-1],s=n.trustScore-r.trustScore,i=new Date(r.date).getTime(),o=new Date(n.date).getTime(),a=Math.max((o-i)/2592e6,1/30),c=Math.round(s/a*10)/10;let l;return l=Math.abs(s)<2?"flat":s>0?"improving":"declining",{hasHistory:!0,isFirstScan:!1,scanCount:t.length,direction:l,avgMonthlyChange:c,firstScore:r.trustScore,latestScore:n.trustScore,totalChange:Math.round(10*s)/10,series:t}}function recordAndAnalyze(e,t){const r=loadHistory(e).entries,n=analyzeTrend(r),s=analyzeTrend(recordScan(e,t));return s.wasFirstScanBeforeThis=0===r.filter(e=>"number"==typeof e.trustScore).length,s.priorLatestScore=n.latestScore,s}module.exports={recordScan:recordScan,loadHistory:loadHistory,analyzeTrend:analyzeTrend,recordAndAnalyze:recordAndAnalyze,HISTORY_FILENAME:HISTORY_FILENAME};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const fs=require("fs"),path=require("path"),crypto=require("crypto"),EventEmitter=require("events"),{execFileSync:execFileSync}=require("child_process"),GENERATED_OUTPUT_PATTERN=/^thuban-(sbom-(cyclonedx|spdx)|investor-report|scan-results|passport)-.*\.(json|html)$/i,LOCKFILE_NAMES=new Set(["package-lock.json","npm-shrinkwrap.json","yarn.lock","pnpm-lock.yaml","composer.lock","Cargo.lock","Gemfile.lock","poetry.lock","Pipfile.lock","go.sum"]);class SecretScanner extends EventEmitter{constructor(e={}){super();const t=new Set(["rootPath","ignorePatterns","maxFileSize","entropyThreshold","minEntropyLength","includeGitHistory"]),i={};for(const s of Object.keys(e))t.has(s)&&(i[s]=e[s]);this.config={rootPath:i.rootPath||process.cwd(),ignorePatterns:i.ignorePatterns||["node_modules/**",".git/**","dist/**",".next/**","coverage/**"],maxFileSize:i.maxFileSize||1048576,entropyThreshold:i.entropyThreshold||4.2,minEntropyLength:i.minEntropyLength||20,includeGitHistory:void 0===i.includeGitHistory||i.includeGitHistory},this.scanExtensions=new Set([".env",".js",".jsx",".ts",".tsx",".py",".json",".yaml",".yml",".toml",".ini",".conf",".config",".properties",".sh",".bash",".zsh"]),this.ignoredDirectories=["node_modules",".git","dist",".next","coverage",".venv","venv","__pycache__"],this.safeLinePatterns=[/process\.env\./i,/process\.env\[/i,/os\.environ/i,/sample/i,/placeholder/i,/dummy/i,/mock/i,/example/i,/replace[_-\s]?me/i,/replace[_-\s]?with/i,/local-dev-token/i,/changeme/i,/your[_-\s]?key/i,/your[_-\s]?(secret|token|password)/i,/<secret>/i,/<token>/i,/x{8,}/i],this.secretPatterns=[{id:"SECRET001",type:"Stripe Secret Key",severity:"critical",recommendation:"Move this key to a cloud secret manager and load it via environment variables.",pattern:/\bsk_(live|test)_[0-9a-zA-Z]{16,}\b/gi},{id:"SECRET002",type:"Stripe Publishable Key",severity:"high",recommendation:"Verify this publishable key is intended to be public; if not, move it to managed secrets.",pattern:/\bpk_(live|test)_[0-9a-zA-Z]{16,}\b/gi},{id:"SECRET003",type:"AWS Access Key",severity:"critical",recommendation:"Rotate the AWS credential immediately and store replacements in a cloud secret manager.",pattern:/\b(AKIA|ASIA|AGPA|AIDA|AROA|AIPA)[A-Z0-9]{16}\b/g},{id:"SECRET004",type:"GitHub Token",severity:"critical",recommendation:"Revoke the GitHub token and replace it with a managed secret or GitHub App credential.",pattern:/\b(ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{20,}\b/g},{id:"SECRET005",type:"Slack Token",severity:"critical",recommendation:"Rotate the Slack token and move it into a cloud secret manager.",pattern:/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g},{id:"SECRET006",type:"Twilio Credential",severity:"critical",recommendation:"Rotate the Twilio credential and store it in managed secrets.",pattern:/\b(SK|AC)[0-9a-fA-F]{32}\b/g},{id:"SECRET007",type:"Google API Key",severity:"critical",recommendation:"Restrict and rotate the Google API key, then move it to a cloud secret manager.",pattern:/\bAIza[0-9A-Za-z\-_]{35}\b/g},{id:"SECRET007B",type:"OpenAI Project Key",severity:"critical",recommendation:"Rotate the OpenAI project key and move it to a cloud secret manager.",pattern:/\bsk-proj-[A-Za-z0-9\-_]{20,}\b/g},{id:"SECRET007C",type:"Cartesia API Key",severity:"critical",recommendation:"Rotate the Cartesia API key and move it to a cloud secret manager.",pattern:/\bsk_car_[A-Za-z0-9]{16,}\b/g},{id:"SECRET008",type:"JWT Token",severity:"high",recommendation:"Do not hardcode JWTs; issue them dynamically and store signing secrets in managed secrets.",pattern:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9._-]{8,}\.[A-Za-z0-9._-]{8,}\b/g},{id:"SECRET009",type:"Bearer Token",severity:"high",recommendation:"Move bearer tokens to a cloud secret manager and inject them at runtime.",pattern:/\bBearer\s+[A-Za-z0-9\-._~+/]+=*\b/g},{id:"SECRET010",type:"Private Key",severity:"critical",recommendation:"Remove the private key from source control, rotate it, and store it in a secret manager.",pattern:/-----BEGIN (RSA |DSA |EC |OPENSSH |PGP )?PRIVATE KEY-----/g},{id:"SECRET011",type:"Database Connection String with Password",severity:"critical",recommendation:"Move the connection string to managed secrets and avoid embedding passwords in code or config.",pattern:/\b(?:postgres(?:ql)?|mysql|mssql|mongodb(?:\+srv)?|redis):\/\/[^:\s]+:[^@\s]+@[^'"`\s]+\b/gi},{id:"SECRET012",type:"Webhook Secret",severity:"high",recommendation:"Store webhook secrets in a cloud secret manager and inject them via environment variables.",pattern:/\b(?:whsec_[A-Za-z0-9]+|webhook[_-]?secret[_:=\s'"]+[A-Za-z0-9_\-]{12,})\b/gi},{id:"SECRET013",type:"Hardcoded Password or Secret Assignment",severity:"high",recommendation:"Replace hardcoded credentials with environment variables backed by a cloud secret manager.",pattern:/\b(?:password|passwd|pwd|secret|client_secret|api[_-]?secret|signing[_-]?secret)\b\s*[:=]\s*['"`][^'"`\s][^'"`]{5,}['"`]/gi},{id:"SECRET014",type:"Hardcoded API Key Assignment",severity:"high",recommendation:"Move API keys to a cloud secret manager and reference them through environment variables.",pattern:/\b(?:api[_-]?key|access[_-]?token|auth[_-]?token|token)\b\s*[:=]\s*['"`][A-Za-z0-9_\-./+=]{12,}['"`]/gi},{id:"SECRET015",type:".env File Present",severity:"medium",recommendation:"Ensure .env files are excluded from git and move production secrets to a cloud secret manager.",filePattern:/(^|[\\/])\.env(\.[^\\/]+)?$/i},{id:"SECRET016",type:"LiveKit API Secret",severity:"critical",recommendation:"Rotate the LiveKit API secret and store it in managed secrets.",pattern:/\b(?:LIVEKIT_API_SECRET|livekit[_-]?api[_-]?secret)\b\s*[:=]\s*['"`]?([A-Za-z0-9]{24,})['"`]?/gi}]}async scanAll(){const e=Date.now(),t=await this._discoverFiles(this.config.rootPath),i=[];for(const e of t)i.push(...await this.scanFile(e));return this.config.includeGitHistory&&i.push(...this.scanGitHistory()),{filesScanned:t.length,issues:i,summary:this._summarizeIssues(i),duration:Date.now()-e}}async scanFiles(e){const t=[];for(const i of e)t.push(...await this.scanFile(i));return this.config.includeGitHistory&&t.push(...this.scanGitHistory()),{filesScanned:e.length,issues:t,summary:this._summarizeIssues(t)}}async scanFile(e){const t=[],i=path.relative(this.config.rootPath,e).replace(/\\/g,"/");try{if(fs.statSync(e).size>this.config.maxFileSize)return t;const s=path.basename(e),n=fs.readFileSync(e,"utf8").split(/\r?\n/);for(const r of this.secretPatterns)if(r.filePattern&&r.filePattern.test(e)){if(this._shouldSkipLine(s,i,r))continue;this._isGitIgnored(i)||t.push(this._createIssue({file:e,line:1,type:r.type,severity:r.severity,recommendation:"Add this file to .gitignore and move any production secrets to a cloud secret manager.",id:r.id,match:s,category:"secret"}))}else if(r.pattern)for(let s=0;s<n.length;s++){const o=n[s];if(this._shouldSkipLine(o,i,r))continue;let a;for(r.pattern.lastIndex=0;null!==(a=r.pattern.exec(o));){const i=a[1]||a[0];this._isLikelyPlaceholder(i)||t.push(this._createIssue({file:e,line:s+1,column:a.index,type:r.type,severity:r.severity,recommendation:r.recommendation,id:r.id,match:a[0],category:"secret"}))}}return t.push(...this._scanEntropy(e,n,i)),this._dedupeIssues(t)}catch(t){return[{file:e,line:1,category:"secret",severity:"medium",id:"SECRET_SCAN_ERROR",type:"Secret Scan Error",recommendation:"Verify file permissions and encoding, then rerun the scan.",message:"Failed to scan file for secrets: "+("ENOENT"===t.code?"File not found":"EACCES"===t.code?"Permission denied":"Scan error")}]}}scanGitHistory(){try{const e=execFileSync("git",["log","-p","--all","--full-history","--","."],{cwd:this.config.rootPath,encoding:"utf8",maxBuffer:20971520}),t=[],i=e.split(/\r?\n/);let s=null,n=null;for(const e of i){if(e.startsWith("commit ")){s=e.replace("commit ","").trim();continue}if(e.startsWith("+++ b/")){n=e.replace("+++ b/","").trim();continue}if(!e.startsWith("+")||e.startsWith("+++"))continue;const i=e.slice(1);if(!this._shouldSkipLine(i,n||""))for(const e of this.secretPatterns){if(!e.pattern)continue;let r;for(e.pattern.lastIndex=0;null!==(r=e.pattern.exec(i));){const o=r[1]||r[0];this._isLikelyPlaceholder(o)||t.push({file:n||"unknown",line:null,category:"secret-history",severity:"medium"===e.severity?"high":e.severity,id:`${e.id}_HISTORY`,type:`${e.type} in Git History`,recommendation:"Purge the secret from git history, rotate it, and move it to a cloud secret manager.",message:`Potential secret remains in git history (${s||"unknown commit"})`,commit:s,code:i.trim().slice(0,140)})}}}return this._dedupeIssues(t)}catch(e){return[]}}_scanEntropy(e,t,i){const s=[],n=/['"`]([A-Za-z0-9+/=_\-]{20,})['"`]/g;for(let r=0;r<t.length;r++){const o=t[r];if(this._shouldSkipLine(o,i))continue;let a;for(n.lastIndex=0;null!==(a=n.exec(o));){const t=a[1];if(t.length<this.config.minEntropyLength)continue;if(!/[A-Z]/.test(t)||!/[a-z]/.test(t)||!/[0-9]/.test(t))continue;const i=this._calculateEntropy(t);i>=this.config.entropyThreshold&&s.push(this._createIssue({file:e,line:r+1,column:a.index,type:"High Entropy Secret Candidate",severity:"medium",recommendation:"Review this value, move it to a cloud secret manager if it is a credential, and reference it via environment variables.",id:"SECRET_ENTROPY",match:t,category:"secret",extraMessage:`High-entropy string detected (entropy ${i.toFixed(2)})`}))}}return s}_createIssue({file:e,line:t,column:i,type:s,severity:n,recommendation:r,id:o,match:a,category:c,extraMessage:l}){return{file:e,line:t,column:i,category:c,severity:n,id:o,type:s,recommendation:r,message:l||`${s} detected`,code:"string"==typeof a?a.slice(0,140):""}}async _discoverFiles(e,t=[]){let i=[];try{i=fs.readdirSync(e,{withFileTypes:!0})}catch{return t}for(const s of i){const i=path.join(e,s.name),n=path.relative(this.config.rootPath,i).replace(/\\/g,"/");if(this._shouldIgnore(n))continue;if(s.isDirectory()){await this._discoverFiles(i,t);continue}if(!s.isFile())continue;if(GENERATED_OUTPUT_PATTERN.test(s.name))continue;if(LOCKFILE_NAMES.has(s.name))continue;const r=path.extname(s.name).toLowerCase();(this.scanExtensions.has(r)||s.name.startsWith(".env"))&&t.push(i)}return t}_shouldIgnore(e){const t=e.replace(/\\/g,"/"),i=this.ignoredDirectories;for(const e of i)if(t===e||t.startsWith(`${e}/`)||t.includes(`/${e}/`))return!0;return this.config.ignorePatterns.some(e=>{const i=e.replace(/\\/g,"/"),s=i.replace(/\./g,"\\.").replace(/\*\*/g,".*").replace(/\*/g,"[^/]*");return new RegExp(`^${s}$`).test(t)||t.startsWith(i.replace("/**",""))})}_shouldSkipLine(e,t,i=null){if(!e||!e.trim())return!0;const s=(t||"").replace(/\\/g,"/").toLowerCase();return!!(s.includes("__tests__")||s.includes("/test/")||s.includes("/tests/")||s.endsWith(".spec.js")||s.endsWith(".test.js")||s.endsWith(".spec.ts")||s.endsWith(".test.ts")||s.endsWith(".example")||s.endsWith(".env.example"))||(!i||"SECRET015"!==i.id)&&this.safeLinePatterns.some(t=>t.test(e))}_calculateEntropy(e){const t=new Map;for(const i of e)t.set(i,(t.get(i)||0)+1);let i=0;for(const s of t.values()){const t=s/e.length;i-=t*Math.log2(t)}return i}_isLikelyPlaceholder(e){return!!e&&[/replace[_-\s]?me/i,/replace[_-\s]?with/i,/example/i,/dummy/i,/placeholder/i,/changeme/i,/your[_-\s]?(key|secret|token|password)/i,/local-dev-token/i,/x{8,}/i].some(t=>t.test(e))}_isGitIgnored(e){try{return execFileSync("git",["check-ignore",e],{cwd:this.config.rootPath,stdio:"ignore"}),!0}catch{return!1}}_dedupeIssues(e){const t=new Set;return e.filter(e=>{const i=crypto.createHash("sha1").update(JSON.stringify([e.file,e.line,e.id,e.code,e.commit||""])).digest("hex");return!t.has(i)&&(t.add(i),!0)})}_summarizeIssues(e){return{total:e.length,bySeverity:{critical:e.filter(e=>"critical"===e.severity).length,high:e.filter(e=>"high"===e.severity).length,medium:e.filter(e=>"medium"===e.severity).length},byType:e.reduce((e,t)=>(e[t.type]=(e[t.type]||0)+1,e),{})}}}module.exports=SecretScanner;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const fs=require("fs"),path=require("path"),EventEmitter=require("events");let FileWatcher,CodeScanner,DriftDetector,HealthChecker,AlertManager,SecretScanner;class SentinelCore extends EventEmitter{constructor(e={}){super();const t={...e};delete t.__proto__,delete t.constructor,delete t.prototype,this.config={rootPath:t.rootPath||process.cwd(),watchPatterns:t.watchPatterns||["**/*.js","**/*.ts","**/*.json"],ignorePatterns:t.ignorePatterns||["node_modules/**",".git/**","dist/**",".orion/snapshots/**"],scanIntervalHours:t.scanIntervalHours||6,dailyReportHour:t.dailyReportHour||8,weeklyReportDay:t.weeklyReportDay||1,enableRealtime:!1!==t.enableRealtime,enableScheduled:!1!==t.enableScheduled,alertThreshold:t.alertThreshold||"warning"},this.state={isRunning:!1,lastFullScan:null,lastHealthCheck:null,lastDriftCheck:null,filesWatched:0,issuesFound:[],metrics:{totalScans:0,issuesDetected:0,issuesResolved:0,averageScanTime:0}},this.components={fileWatcher:null,codeScanner:null,driftDetector:null,healthChecker:null,alertManager:null},this.scheduledJobs=[]}async initialize(){console.log("[SENTINEL] Initializing Sentinel Core...");try{return FileWatcher=require("./file-watcher.js"),CodeScanner=require("./code-scanner.js"),DriftDetector=require("./drift-detector.js"),HealthChecker=require("./health-checker.js"),AlertManager=require("./alert-manager.js"),SecretScanner=require("./secret-scanner.js"),this.components.fileWatcher=new FileWatcher(this.config),this.components.codeScanner=new CodeScanner(this.config),this.components.driftDetector=new DriftDetector(this.config),this.components.healthChecker=new HealthChecker(this.config),this.components.alertManager=new AlertManager(this.config),this.components.secretScanner=new SecretScanner(this.config),this._setupEventHandlers(),console.log("[SENTINEL] All components initialized"),{success:!0}}catch(e){return console.error("[SENTINEL] Initialization failed"),{success:!1,error:"Initialization failed"}}}async start(){if(this.state.isRunning)return console.log("[SENTINEL] Already running"),{success:!0,message:"Already running"};console.log("[SENTINEL] Starting Sentinel monitoring...");try{this.config.enableRealtime&&this.components.fileWatcher&&(await this.components.fileWatcher.start(),this.state.filesWatched=this.components.fileWatcher.getWatchedCount()),this.config.enableScheduled&&this._setupScheduledJobs(),await this.runHealthCheck();const e=await this.runFullScan();return this.state.isRunning=!0,this.emit("started",{timestamp:(new Date).toISOString()}),console.log("[SENTINEL] Monitoring active"),console.log(`[SENTINEL] Watching ${this.state.filesWatched} files`),console.log(`[SENTINEL] Initial scan found ${e.issues?.length||0} issues`),{success:!0,filesWatched:this.state.filesWatched,initialIssues:e.issues?.length||0}}catch(e){return console.error("[SENTINEL] Start failed"),{success:!1,error:"Start failed"}}}async stop(){return this.state.isRunning?(console.log("[SENTINEL] Stopping Sentinel monitoring..."),this.components.fileWatcher&&await this.components.fileWatcher.stop(),this.scheduledJobs.forEach(e=>clearInterval(e)),this.scheduledJobs=[],this.state.isRunning=!1,this.emit("stopped",{timestamp:(new Date).toISOString()}),console.log("[SENTINEL] Monitoring stopped"),{success:!0}):{success:!0,message:"Not running"}}async runFullScan(e={}){const t=Date.now();console.log("[SENTINEL] Starting full codebase scan...");const s={timestamp:(new Date).toISOString(),duration:0,filesScanned:0,issues:[],summary:{}};try{if(!this.components.codeScanner)throw new Error("Code scanner not initialized");const e=await this.components.codeScanner.scanAll();if(s.filesScanned=e.filesScanned||0,s.issues.push(...e.issues||[]),this.components.secretScanner){const e=await this.components.secretScanner.scanAll();s.filesScanned+=e.filesScanned||0,s.issues.push(...e.issues||[])}if(this.components.driftDetector){const e=await this.components.driftDetector.detectAll();s.issues.push(...e.issues||[]),this.state.lastDriftCheck=(new Date).toISOString()}return s.duration=Date.now()-t,this.state.lastFullScan=s.timestamp,this.state.metrics.totalScans++,this.state.metrics.issuesDetected+=s.issues.length,this.state.metrics.averageScanTime=(this.state.metrics.averageScanTime*(this.state.metrics.totalScans-1)+s.duration)/this.state.metrics.totalScans,s.summary=this._generateScanSummary(s.issues),this.state.issuesFound=s.issues,await this._processIssues(s.issues),console.log(`[SENTINEL] Scan complete: ${s.filesScanned} files, ${s.issues.length} issues, ${s.duration}ms`),this.emit("scanComplete",s),s}catch(e){return console.error("[SENTINEL] Full scan failed"),s.error="Scan failed",s}}async runQuickScan(e){if(!this.components.codeScanner)return{success:!1,error:"Code scanner not initialized"};console.log(`[SENTINEL] Quick scan on ${e.length} files...`);const t=await this.components.codeScanner.scanFiles(e);return t.issues&&t.issues.length>0&&await this._processIssues(t.issues),t}async runHealthCheck(){if(console.log("[SENTINEL] Running health check..."),!this.components.healthChecker)return{success:!1,error:"Health checker not initialized"};const e=await this.components.healthChecker.checkAll();return this.state.lastHealthCheck=(new Date).toISOString(),e.unhealthySystems&&e.unhealthySystems.length>0&&await(this.components.alertManager?.sendAlert({level:"warning",title:"System Health Issues Detected",message:`${e.unhealthySystems.length} systems are unhealthy`,details:e.unhealthySystems})),this.emit("healthCheck",e),e}async generateDailyDigest(){console.log("[SENTINEL] Generating daily digest...");const e={date:(new Date).toISOString().split("T")[0],timestamp:(new Date).toISOString(),summary:{issuesFound:this.state.issuesFound.length,criticalIssues:this.state.issuesFound.filter(e=>"critical"===e.severity).length,warningIssues:this.state.issuesFound.filter(e=>"warning"===e.severity).length,filesWatched:this.state.filesWatched,lastScan:this.state.lastFullScan,lastHealthCheck:this.state.lastHealthCheck},topIssues:this.state.issuesFound.sort((e,t)=>this._severityScore(t.severity)-this._severityScore(e.severity)).slice(0,10),metrics:this.state.metrics,recommendations:this._generateRecommendations()};return this.components.alertManager&&await this.components.alertManager.sendDigest(e),this.emit("dailyDigest",e),e}async generateWeeklyReport(){console.log("[SENTINEL] Generating weekly report...");const e={weekOf:(new Date).toISOString().split("T")[0],timestamp:(new Date).toISOString(),summary:this.state.metrics,issuesTrend:this._calculateTrend(),codeQuality:await this._assessCodeQuality(),technicalDebt:await this._assessTechnicalDebt(),recommendations:this._generateRecommendations(),fullIssueList:this.state.issuesFound};return this.components.alertManager&&await this.components.alertManager.sendWeeklyReport(e),this.emit("weeklyReport",e),e}getStatus(){return{isRunning:this.state.isRunning,config:this.config,state:{...this.state,componentsLoaded:{fileWatcher:!!this.components.fileWatcher,codeScanner:!!this.components.codeScanner,driftDetector:!!this.components.driftDetector,healthChecker:!!this.components.healthChecker,alertManager:!!this.components.alertManager}},uptime:this.state.isRunning?Date.now()-new Date(this.state.lastFullScan).getTime():0}}_setupEventHandlers(){this.components.fileWatcher&&(this.components.fileWatcher.on("change",async e=>{console.log(`[SENTINEL] File changed: ${e.filePath}`),await this.runQuickScan([e.filePath])}),this.components.fileWatcher.on("error",e=>{console.error("[SENTINEL] File watcher error:",e)})),this.components.codeScanner&&this.components.codeScanner.on("issueFound",async e=>{await this._processIssues([e])})}_setupScheduledJobs(){const e=60*this.config.scanIntervalHours*60*1e3;this.scheduledJobs.push(setInterval(()=>this.runFullScan(),e)),this.scheduledJobs.push(setInterval(()=>this.runHealthCheck(),36e5)),this.scheduledJobs.push(setInterval(()=>{const e=new Date;e.getHours()===this.config.dailyReportHour&&e.getMinutes()<5&&this.generateDailyDigest()},36e5)),this.scheduledJobs.push(setInterval(()=>{const e=new Date;e.getDay()===this.config.weeklyReportDay&&e.getHours()===this.config.dailyReportHour&&e.getMinutes()<5&&this.generateWeeklyReport()},36e5)),console.log(`[SENTINEL] Scheduled jobs: scan every ${this.config.scanIntervalHours}h, daily digest at ${this.config.dailyReportHour}:00`)}async _processIssues(e){for(const t of e)this._meetsThreshold(t.severity)&&this.components.alertManager&&await this.components.alertManager.sendAlert({level:t.severity,title:`[${t.category}] ${t.title||t.message}`,message:t.message,file:t.file,line:t.line,details:t})}_meetsThreshold(e){const t=["info","warning","error","critical"];return t.indexOf(e)>=t.indexOf(this.config.alertThreshold)}_severityScore(e){return{info:1,warning:2,error:3,critical:4}[e]||0}_generateScanSummary(e){return{total:e.length,bySeverity:{critical:e.filter(e=>"critical"===e.severity).length,error:e.filter(e=>"error"===e.severity).length,warning:e.filter(e=>"warning"===e.severity).length,info:e.filter(e=>"info"===e.severity).length},byCategory:e.reduce((e,t)=>(e[t.category]=(e[t.category]||0)+1,e),{})}}_generateRecommendations(){const e=[],t=this.state.issuesFound,s=t.filter(e=>"security"===e.category);s.length>0&&e.push({priority:"high",category:"security",message:`Address ${s.length} security issues before deploying`,issues:s.slice(0,5)});const n=t.filter(e=>"quality"===e.category);n.length>10&&e.push({priority:"medium",category:"quality",message:`Consider refactoring - ${n.length} quality issues detected`,issues:n.slice(0,5)});const i=t.filter(e=>"drift"===e.category);return i.length>0&&e.push({priority:"medium",category:"drift",message:`${i.length} files have drifted from their declared contracts`,issues:i.slice(0,5)}),e}_calculateTrend(){return{direction:"stable",change:0,note:"Trend analysis requires historical data"}}async _assessCodeQuality(){return{score:75,grade:"B",factors:{complexity:70,maintainability:80,documentation:65,testCoverage:40}}}async _assessTechnicalDebt(){return{estimatedHours:40,categories:{refactoring:20,documentation:10,testing:10},priorityItems:[]}}}function createSentinel(e={}){return new SentinelCore(e)}async function main(){const e=createSentinel({rootPath:path.resolve(__dirname,".."),enableRealtime:!0,enableScheduled:!1}),t=await e.initialize();t.success||(console.error("Failed to initialize Sentinel:",t.error),process.exit(1)),await e.start(),console.log("Sentinel status:",e.getStatus()),process.on("SIGINT",async()=>{console.log("\nShutting down Sentinel..."),await e.stop(),process.exit(0)})}require.main===module&&main().catch(console.error),module.exports={SentinelCore:SentinelCore,createSentinel:createSentinel};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const fs=require("fs"),path=require("path"),https=require("https"),crypto=require("crypto"),{readJsonSafe:readJsonSafe}=require("./json-file-util.js"),PERMISSIVE_LICENSES=new Set(["MIT","ISC","BSD-2-Clause","BSD-3-Clause","BSD-3-Clause-Clear","BSD-4-Clause","0BSD","Apache-2.0","Unlicense","CC0-1.0","Python-2.0","Zlib","WTFPL","Artistic-2.0","PostgreSQL","blessing","CC-BY-4.0","CC-BY-3.0","OFL-1.1"]),WEAK_COPYLEFT_LICENSES=new Set(["LGPL-2.0","LGPL-2.0-only","LGPL-2.0-or-later","LGPL-2.1","LGPL-2.1-only","LGPL-2.1-or-later","LGPL-3.0","LGPL-3.0-only","LGPL-3.0-or-later","MPL-1.1","MPL-2.0","EPL-1.0","EPL-2.0","CDDL-1.0","CDDL-1.1"]),STRONG_COPYLEFT_LICENSES=new Set(["GPL-1.0","GPL-1.0-only","GPL-1.0-or-later","GPL-2.0","GPL-2.0-only","GPL-2.0-or-later","GPL-3.0","GPL-3.0-only","GPL-3.0-or-later","AGPL-1.0","AGPL-1.0-only","AGPL-1.0-or-later","AGPL-3.0","AGPL-3.0-only","AGPL-3.0-or-later","SSPL-1.0","OSL-3.0"]),UNLICENSED_MARKERS=new Set(["UNLICENSED","UNLICENCED","NONE","NOASSERTION","PROPRIETARY"]);function classifyLicense(e){if(!e||"string"!=typeof e||!e.trim())return"unknown";const t=e.trim();if(UNLICENSED_MARKERS.has(t.toUpperCase()))return"unlicensed";if(/see license in/i.test(t))return"unlicensed";const n=t.replace(/[()]/g," ").split(/\s+(?:OR|AND|WITH)\s+/i).map(e=>e.trim()).filter(Boolean);let s="unknown";const o={unknown:0,permissive:1,"weak-copyleft":2,copyleft:3,unlicensed:3};for(const e of n){let t;t=STRONG_COPYLEFT_LICENSES.has(e)?"copyleft":WEAK_COPYLEFT_LICENSES.has(e)?"weak-copyleft":PERMISSIVE_LICENSES.has(e)?"permissive":UNLICENSED_MARKERS.has(e.toUpperCase())?"unlicensed":"unknown",o[t]>o[s]&&(s=t)}return s}function httpsRequestJSON(e,{method:t="GET",body:n=null,headers:s={},timeout:o=1e4}={}){return new Promise(r=>{let i;try{i=new URL(e)}catch{return r({ok:!1,status:0,error:"invalid URL",data:null})}const a=n?JSON.stringify(n):null,c={hostname:i.hostname,port:443,path:i.pathname+i.search,method:t,headers:Object.assign(a?{"Content-Type":"application/json","Content-Length":Buffer.byteLength(a)}:{},{"User-Agent":"thuban-supply-chain-scanner"},s),timeout:o},l=https.request(c,e=>{let t="";e.on("data",e=>{t+=e}),e.on("end",()=>{if(e.statusCode<200||e.statusCode>=300)return r({ok:!1,status:e.statusCode,error:`HTTP ${e.statusCode}`,data:null});try{r({ok:!0,status:e.statusCode,data:JSON.parse(t)})}catch(t){r({ok:!1,status:e.statusCode,error:`JSON parse error: ${t.message}`,data:null})}})});l.on("timeout",()=>{l.destroy(),r({ok:!1,status:0,error:"timeout",data:null})}),l.on("error",e=>r({ok:!1,status:0,error:e.message,data:null})),a&&l.write(a),l.end()})}async function withConcurrency(e,t,n){const s=new Array(e.length);let o=0;async function r(){for(;o<e.length;){const t=o++;s[t]=await n(e[t],t)}}const i=[];for(let n=0;n<Math.min(t,Math.max(e.length,1));n++)i.push(r());return await Promise.all(i),s}function chunk(e,t){const n=[];for(let s=0;s<e.length;s+=t)n.push(e.slice(s,s+t));return n}function parseSemver(e){if(!e||"string"!=typeof e)return null;const t=e.trim().replace(/^[\^~=vV]+/,""),n=/^(\d+)\.(\d+)\.(\d+)/.exec(t);return n?{major:parseInt(n[1],10),minor:parseInt(n[2],10),patch:parseInt(n[3],10)}:null}function compareSemver(e,t){const n=parseSemver(e),s=parseSemver(t);return n&&s?n.major!==s.major?n.major-s.major:n.minor!==s.minor?n.minor-s.minor:n.patch-s.patch:0}const KNOWN_MALICIOUS_NPM=new Map([["event-stream",{versions:["3.3.6"],reason:"Injected flatmap-stream dependency harvesting Copay wallet credentials (2018)"}],["flatmap-stream",{versions:["0.1.1"],reason:"Malicious payload injected into event-stream dependency chain (2018)"}],["eslint-scope",{versions:["3.7.2"],reason:"Compromised npm account published version stealing npm tokens (2018)"}],["rc",{versions:["1.3.9"],reason:"Supply-chain compromise injecting crypto-clipper malware (Sept 2025 npm incident)"}],["coa",{versions:["2.0.3","2.0.4","2.1.1","2.1.3","3.0.1","3.1.3"],reason:"Compromised maintainer account published credential-stealing payload"}],["ua-parser-js",{versions:["0.7.29","0.8.0","1.0.0"],reason:"Compromised maintainer account published cryptominer/password-stealer (Oct 2021)"}],["node-ipc",{versions:["10.1.1","10.1.2","9.2.2"],reason:'"Protestware" — destructive file-wiping payload targeting Russian/Belarusian IPs (2022)'}],["colors",{versions:["1.4.1"],reason:"Maintainer sabotage — infinite loop / non-ASCII spam payload (Jan 2022)"}],["faker",{versions:["6.6.6"],reason:"Maintainer sabotage — corrupted package output (Jan 2022)"}]]),KNOWN_MALICIOUS_PYPI=new Map([["requests-darwin-lite",{versions:null,reason:"Typosquat of requests exfiltrating credentials"}],["python3-dateutil",{versions:null,reason:"Typosquat of python-dateutil dropping malicious payload (2019)"}],["jeIlyfish",{versions:null,reason:"Typosquat of jellyfish (2019 PyPI typosquat campaign)"}]]),POPULAR_NPM_PACKAGES=["react","react-dom","lodash","express","axios","chalk","commander","debug","request","moment","webpack","babel","eslint","jest","typescript","next","vue","angular","jquery","underscore","async","colors","yargs","inquirer","mongoose","redis","mysql","pg","socket.io","bcrypt","jsonwebtoken","dotenv","cors","body-parser","nodemon","prettier","rimraf","glob","semver","uuid","node-fetch","form-data","qs","minimist","tar","ini","ansi-styles","strip-ansi"];function levenshtein(e,t){if(e===t)return 0;const n=e.length,s=t.length;if(0===n)return s;if(0===s)return n;const o=new Array(s+1);for(let e=0;e<=s;e++)o[e]=e;for(let r=1;r<=n;r++){let n=o[0];o[0]=r;for(let i=1;i<=s;i++){const s=o[i];o[i]=e[r-1]===t[i-1]?n:1+Math.min(n,o[i],o[i-1]),n=s}}return o[s]}const KNOWN_LEGITIMATE_PACKAGES=new Set(["esquery","acorn","espree","estree","eslint-visitor-keys"]);function suspectedTyposquat(e,t){if("npm"!==t)return null;if(e.startsWith("@"))return null;const n=e;if(POPULAR_NPM_PACKAGES.includes(n))return null;if(KNOWN_LEGITIMATE_PACKAGES.has(n))return null;for(const e of POPULAR_NPM_PACKAGES){const t=levenshtein(n,e);if(0!==t&&(t<=(Math.min(n.length,e.length)>=8?2:1)&&Math.abs(n.length-e.length)<=2))return`Name closely resembles popular package "${e}" (edit distance ${t}) — verify this is the intended dependency`}return null}const OSV_ECOSYSTEM_MAP={npm:"npm",pypi:"PyPI",go:"Go",cargo:"crates.io"};async function osvBatchQuery(e,{timeout:t=15e3}={}){const n=new Map;if(0===e.length)return n;const s=chunk(e,500);for(const e of s){const s=e.map(e=>({package:{name:e.name,ecosystem:OSV_ECOSYSTEM_MAP[e.ecosystem]||e.ecosystem},version:e.version})),o=await httpsRequestJSON("https://api.osv.dev/v1/querybatch",{method:"POST",body:{queries:s},timeout:t});o.ok&&o.data&&Array.isArray(o.data.results)&&o.data.results.forEach((t,s)=>{const o=e[s],r=`${o.ecosystem}:${o.name}@${o.version}`;n.set(r,(t.vulns||[]).map(e=>e.id))})}return n}async function osvResolveIds(e,{concurrency:t=10,timeout:n=1e4}={}){const s=[...new Set(e)],o=new Map;return await withConcurrency(s,t,async e=>{const t=await httpsRequestJSON(`https://api.osv.dev/v1/vulns/${encodeURIComponent(e)}`,{timeout:n});t.ok&&t.data&&o.set(e,t.data)}),o}function osvSeverityLabel(e){const t=e?.database_specific?.severity;if(t){const e=String(t).toUpperCase();if("MODERATE"===e)return"MEDIUM";if(["CRITICAL","HIGH","MEDIUM","LOW"].includes(e))return e}const n=(e?.severity||[]).find(e=>/CVSS/i.test(e.type));if(n&&"string"==typeof n.score){const e=/\/A:(N|L|H)/.exec(n.score)||/\/C:(N|L|H)/.exec(n.score);if(e){if("H"===e[1])return"HIGH";if("L"===e[1])return"MEDIUM"}}return"UNKNOWN"}function osvFixedVersion(e,t,n){const s=OSV_ECOSYSTEM_MAP[t]||t;for(const t of e.affected||[])if(t.package&&t.package.ecosystem===s&&t.package.name===n)for(const e of t.ranges||[]){if("SEMVER"!==e.type&&"ECOSYSTEM"!==e.type)continue;const t=(e.events||[]).filter(e=>e.fixed);if(t.length)return t[t.length-1].fixed}return null}const registryCache=new Map;function npmRegistryLookup(e){const t=`npm:${e}`;if(registryCache.has(t))return registryCache.get(t);const n=(async()=>{const t=await httpsRequestJSON(`https://registry.npmjs.org/${encodeURIComponent(e).replace("%40","@")}`,{timeout:1e4});if(!t.ok||!t.data)return null;const n=t.data,s=n["dist-tags"]?.latest||null,o=s?n.versions?.[s]:null;return{latest:s,license:o?.license?.type||o?.license||n.license?.type||n.license||null,deprecated:!!o?.deprecated}})();return registryCache.set(t,n),n}function pypiRegistryLookup(e){const t=`pypi:${e}`;if(registryCache.has(t))return registryCache.get(t);const n=(async()=>{const t=await httpsRequestJSON(`https://pypi.org/pypi/${encodeURIComponent(e)}/json`,{timeout:1e4});if(!t.ok||!t.data)return null;const n=t.data.info||{};let s=n.license&&n.license.trim()?n.license.trim():null;if(!s||s.length>100){const e=(n.classifiers||[]).find(e=>e.startsWith("License :: OSI Approved ::"));e?s=e.split("::").pop().trim():s&&s.length>100&&(s=null)}return{latest:n.version||null,license:s,deprecated:!1}})();return registryCache.set(t,n),n}function cratesRegistryLookup(e){const t=`cargo:${e}`;if(registryCache.has(t))return registryCache.get(t);const n=(async()=>{const t=await httpsRequestJSON(`https://crates.io/api/v1/crates/${encodeURIComponent(e)}`,{timeout:1e4,headers:{"User-Agent":"thuban-supply-chain-scanner (https://thuban.dev)"}});if(!t.ok||!t.data||!t.data.crate)return null;const n=t.data.versions||[],s=n.find(e=>e.num===t.data.crate.max_stable_version)||n[0];return{latest:t.data.crate.max_stable_version||null,license:s?.license||null,deprecated:!!s?.yanked}})();return registryCache.set(t,n),n}function goProxyLookup(e){const t=`go:${e}`;if(registryCache.has(t))return registryCache.get(t);const n=(async()=>{const t=e.split("/").map(e=>e.replace(/[A-Z]/g,e=>"!"+e.toLowerCase())).join("/"),n=await httpsRequestJSON(`https://proxy.golang.org/${t}/@latest`,{timeout:1e4});return n.ok&&n.data?{latest:n.data.Version||null,license:null,deprecated:!1}:null})();return registryCache.set(t,n),n}function registryLookup(e,t){return"npm"===e?npmRegistryLookup(t):"pypi"===e?pypiRegistryLookup(t):"cargo"===e?cratesRegistryLookup(t):"go"===e?goProxyLookup(t):Promise.resolve(null)}function readJSONSafe(e){return readJsonSafe(e,null)}function readTextSafe(e){try{return fs.readFileSync(e,"utf-8")}catch{return null}}function integrityToHex(e){if(!e||"string"!=typeof e)return null;const t=/^sha(?:256|384|512)-([A-Za-z0-9+/=]+)$/.exec(e.split(" ")[0]);if(!t)return null;try{return Buffer.from(t[1],"base64").toString("hex")}catch{return null}}function integrityAlgo(e){return e?e.startsWith("sha512-")?"SHA-512":e.startsWith("sha384-")?"SHA-384":e.startsWith("sha256-")?"SHA-256":null:null}function parseNpmProject(e,t){const n=readJSONSafe(path.join(e,"package.json"));if(!n)return[];const s=new Set([...Object.keys(n.dependencies||{}),...Object.keys(n.devDependencies||{}),...Object.keys(n.optionalDependencies||{}),...Object.keys(n.peerDependencies||{})]),o=new Set(Object.keys(n.devDependencies||{})),r=readJSONSafe(path.join(e,"package-lock.json")),i=[];if(r&&r.lockfileVersion>=2&&r.packages)for(const[e,t]of Object.entries(r.packages)){if(""===e||!e.includes("node_modules/"))continue;if(!t||!t.version)continue;const n=e.lastIndexOf("node_modules/"),r=e.slice(n+13),a=1===(e.match(/node_modules\//g)||[]).length&&s.has(r);i.push({name:r,version:t.version,ecosystem:"npm",direct:a,dev:!!t.dev||a&&o.has(r),license:t.license||null,resolved:t.resolved||null,integrity:t.integrity||null})}else if(r&&r.dependencies){const e=(t,n)=>{for(const[o,r]of Object.entries(t||{}))i.push({name:o,version:r.version,ecosystem:"npm",direct:0===n&&s.has(o),dev:!!r.dev,license:null,resolved:r.resolved||null,integrity:r.integrity||null}),r.dependencies&&e(r.dependencies,n+1)};e(r.dependencies,0)}else if(!t){for(const[e,t]of Object.entries(n.dependencies||{}))i.push({name:e,version:t.replace(/^[\^~]/,""),versionRange:t,ecosystem:"npm",direct:!0,dev:!1,license:null,unresolved:!0});for(const[e,t]of Object.entries(n.devDependencies||{}))i.push({name:e,version:t.replace(/^[\^~]/,""),versionRange:t,ecosystem:"npm",direct:!0,dev:!0,license:null,unresolved:!0})}const a=new Map;for(const e of i){const t=`${e.name}@${e.version}`,n=a.get(t);(!n||e.direct&&!n.direct)&&a.set(t,e)}return[...a.values()]}function parseYarnLock(e,t,n){const s=readTextSafe(path.join(e,"yarn.lock"));if(!s)return[];const o=[],r=s.split(/\n\n+/);for(const e of r){const s=e.split("\n"),r=s[0];if(!r||r.startsWith("#")||!r.includes(":"))continue;const i=s.find(e=>/^\s+version\s+"?/.test(e));if(!i)continue;const a=/"([^"]+)"/.exec(i)||/version\s+(\S+)/.exec(i);if(!a)continue;const c=a[1],l=s.find(e=>/^\s+resolved\s+/.test(e)),u=l?(/"([^"]+)"/.exec(l)||[])[1]:null,p=s.find(e=>/^\s+integrity\s+/.test(e)),d=p?p.replace(/^\s*integrity\s+/,"").trim():null,m=r.replace(/:$/,"").split(",").map(e=>e.trim().replace(/^"|"$/g,"")),h=new Set;for(const e of m){const t=e.lastIndexOf("@"),n=t>0?e.slice(0,t):e;h.add(n)}for(const e of h)o.push({name:e,version:c,ecosystem:"npm",direct:t.has(e),dev:n.has(e),license:null,resolved:u,integrity:d})}return o}function parsePnpmLock(e,t,n){const s=readTextSafe(path.join(e,"pnpm-lock.yaml"));if(!s)return[];const o=[],r=s.split("\n");let i=!1;for(const e of r){if(/^packages:\s*$/.test(e)){i=!0;continue}if(i&&/^\S/.test(e)&&(i=!1),!i)continue;const s=/^\s{2}'?\/?((?:@[^/]+\/)?[^@'\s]+)@([^'\s:]+)'?:/.exec(e);if(!s)continue;const[,r,a]=s;o.push({name:r,version:a.split("(")[0],ecosystem:"npm",direct:t.has(r),dev:n.has(r),license:null,resolved:null,integrity:null})}const a=new Map;for(const e of o)a.set(`${e.name}@${e.version}`,e);return[...a.values()]}function parseRequirementsTxt(e){const t=readTextSafe(path.join(e,"requirements.txt"));if(!t)return[];const n=[];for(const e of t.split("\n")){const t=e.split("#")[0].trim();if(!t||t.startsWith("-"))continue;const s=/^([A-Za-z0-9._-]+)\s*(==|>=|<=|~=|!=)?\s*([A-Za-z0-9.*+!-]*)/.exec(t);if(!s)continue;const[,o,r,i]=s;n.push({name:o,version:"=="===r&&i?i:i||null,ecosystem:"pypi",direct:!0,dev:!1,license:null,unresolved:"=="!==r})}return n}function parsePipfileLock(e){const t=readJSONSafe(path.join(e,"Pipfile.lock"));if(!t)return[];const n=[],s=[["default",!1],["develop",!0]];for(const[e,o]of s)for(const[s,r]of Object.entries(t[e]||{})){const e=(r.version||"").replace(/^==/,"");e&&n.push({name:s,version:e,ecosystem:"pypi",direct:!0,dev:o,license:null,integrity:(r.hashes||[])[0]||null})}return n}function parseGoModDirects(e){const t=readTextSafe(path.join(e,"go.mod")),n=new Set;if(!t)return n;const s=/require\s*\(([\s\S]*?)\)/.exec(t),o=s?s[1].split("\n"):[],r=t.split("\n").filter(e=>/^require\s+\S/.test(e.trim()));for(const e of[...o,...r]){const t=e.replace(/^require\s+/,"").trim();if(!t||t.includes("// indirect"))continue;const s=/^(\S+)\s+(\S+)/.exec(t);s&&n.add(s[1])}return n}function parseGoSum(e){const t=readTextSafe(path.join(e,"go.sum"));if(!t)return[];const n=parseGoModDirects(e),s=new Map;for(const e of t.split("\n")){const t=e.trim().split(/\s+/);if(t.length<2)continue;const[o,r]=t;if(r.endsWith("/go.mod"))continue;const i=r.replace(/^v/,"");s.set(`${o}@${i}`,{name:o,version:i,ecosystem:"go",direct:n.has(o),dev:!1,license:null})}return[...s.values()]}function parseCargoTomlDirects(e){const t=readTextSafe(path.join(e,"Cargo.toml")),n=new Set;if(!t)return n;let s=!1;for(const e of t.split("\n")){const t=e.trim();if(/^\[(dependencies|dev-dependencies|build-dependencies)\]/.test(t)){s=!0;continue}if(/^\[/.test(t)){s=!1;continue}if(!s||!t||t.startsWith("#"))continue;const o=/^([A-Za-z0-9_-]+)\s*=/.exec(t);o&&n.add(o[1])}return n}function parseCargoLock(e){const t=readTextSafe(path.join(e,"Cargo.lock"));if(!t)return[];const n=parseCargoTomlDirects(e),s=[],o=t.split("[[package]]").slice(1);for(const e of o){const t=/name\s*=\s*"([^"]+)"/.exec(e),o=/version\s*=\s*"([^"]+)"/.exec(e),r=/checksum\s*=\s*"([^"]+)"/.exec(e);t&&o&&s.push({name:t[1],version:o[1],ecosystem:"cargo",direct:n.has(t[1]),dev:!1,license:null,integrity:r?r[1]:null})}return s}function toPurl(e,t,n){return`pkg:${{npm:"npm",pypi:"pypi",go:"golang",cargo:"cargo"}[e]||e}/${t.startsWith("@")?t.replace("@","%40"):t}@${n}`}class SupplyChainAnalyzer{constructor(e={}){this.rootPath=e.rootPath||process.cwd(),this.offline=!!e.offline,this.concurrency=e.concurrency||20,this.timeoutMs=e.timeoutMs||15e3}detectEcosystems(){const e=e=>fs.existsSync(path.join(this.rootPath,e));return{npm:e("package.json"),pypi:e("requirements.txt")||e("Pipfile.lock"),go:e("go.sum"),cargo:e("Cargo.lock")}}collectPackages(){const e=[],t=readJSONSafe(path.join(this.rootPath,"package.json"));if(fs.existsSync(path.join(this.rootPath,"package.json"))){const n=fs.existsSync(path.join(this.rootPath,"package-lock.json")),s=fs.existsSync(path.join(this.rootPath,"yarn.lock")),o=fs.existsSync(path.join(this.rootPath,"pnpm-lock.yaml")),r=parseNpmProject(this.rootPath,!n&&(s||o));if(e.push(...r),!n&&t){const n=new Set([...Object.keys(t.dependencies||{}),...Object.keys(t.devDependencies||{})]),r=new Set(Object.keys(t.devDependencies||{}));s?e.push(...parseYarnLock(this.rootPath,n,r)):o&&e.push(...parsePnpmLock(this.rootPath,n,r))}}return fs.existsSync(path.join(this.rootPath,"Pipfile.lock"))?e.push(...parsePipfileLock(this.rootPath)):fs.existsSync(path.join(this.rootPath,"requirements.txt"))&&e.push(...parseRequirementsTxt(this.rootPath)),fs.existsSync(path.join(this.rootPath,"go.sum"))&&e.push(...parseGoSum(this.rootPath)),fs.existsSync(path.join(this.rootPath,"Cargo.lock"))&&e.push(...parseCargoLock(this.rootPath)),e}async analyze(){const e=this.collectPackages(),t=e.filter(e=>e.version&&!e.unresolved);let n=new Map,s=new Map,o=!0;if(!this.offline&&t.length>0)try{n=await osvBatchQuery(t.map(e=>({name:e.name,version:e.version,ecosystem:e.ecosystem})),{timeout:this.timeoutMs});const e=[...n.values()].flat();s=await osvResolveIds(e,{concurrency:this.concurrency,timeout:this.timeoutMs})}catch{o=!1}else t.length>0&&(o=!1);const r=new Map;for(const t of e)r.set(`${t.ecosystem}:${t.name}`,{ecosystem:t.ecosystem,name:t.name});const i=new Map;this.offline||await withConcurrency([...r.values()],this.concurrency,async({ecosystem:e,name:t})=>{try{const n=await registryLookup(e,t);n&&i.set(`${e}:${t}`,n)}catch{}});const a=[];for(const t of e){const e=`${t.ecosystem}:${t.name}`,o=i.get(e),r=t.license||o?.license||null,c=classifyLicense(r),l=`${t.ecosystem}:${t.name}@${t.version}`,u=n.get(l)||[],p=[],d=[];for(const e of u){const n=s.get(e);/^MAL-/.test(e)?d.push(n?.summary||`Flagged malicious by OSV (${e})`):n?p.push({id:e,severity:osvSeverityLabel(n),summary:n.summary||null,fixedVersion:osvFixedVersion(n,t.ecosystem,t.name),aliases:n.aliases||[]}):p.push({id:e,severity:"UNKNOWN",summary:null,fixedVersion:null,aliases:[]})}const m="npm"===t.ecosystem?KNOWN_MALICIOUS_NPM.get(t.name):"pypi"===t.ecosystem?KNOWN_MALICIOUS_PYPI.get(t.name):null;!m||m.versions&&!m.versions.includes(t.version)||d.push(m.reason);const h=0===d.length?suspectedTyposquat(t.name,t.ecosystem):null,f=o?.latest||null,y=!!(f&&t.version&&compareSemver(t.version,f)<0),g=parseSemver(t.version)?.major,v=parseSemver(f)?.major,S=y&&"number"==typeof g&&"number"==typeof v?Math.max(0,v-g):0,C=p.reduce((e,t)=>{const n={CRITICAL:4,HIGH:3,MEDIUM:2,LOW:1,UNKNOWN:0};return(n[t.severity]||0)>(n[e]||0)?t.severity:e},"UNKNOWN");let P="none";d.length>0||"CRITICAL"===C?P="critical":"HIGH"===C?P="high":"MEDIUM"===C?P="medium":"LOW"===C||p.length>0?P="low":"copyleft"===c?P="medium":("unlicensed"===c||h)&&(P="low"),a.push({name:t.name,version:t.version,ecosystem:t.ecosystem,direct:!!t.direct,dev:!!t.dev,license:r,licenseCategory:c,latestVersion:f,outdated:y,majorVersionsBehind:S,deprecated:!!o?.deprecated,cves:p,malicious:d.length>0,maliciousReasons:d,suspectedTyposquat:h,riskLevel:P,resolved:t.resolved||null,integrity:t.integrity||null,purl:toPurl(t.ecosystem,t.name,t.version)})}a.sort((e,t)=>{const n={critical:4,high:3,medium:2,low:1,none:0};return n[t.riskLevel]-n[e.riskLevel]||e.name.localeCompare(t.name)});const c=this._buildSummary(a,o);return{generatedAt:(new Date).toISOString(),rootPath:this.rootPath,ecosystemsDetected:Object.entries(this.detectEcosystems()).filter(([,e])=>e).map(([e])=>e),networkAvailable:o,packages:a,summary:c}}_buildSummary(e,t){const n=e.filter(e=>e.direct),s=e.filter(e=>!e.direct),o=e.flatMap(e=>e.cves.map(t=>({...t,package:e.name,version:e.version}))),r={CRITICAL:0,HIGH:0,MEDIUM:0,LOW:0,UNKNOWN:0};for(const e of o)r[e.severity]=(r[e.severity]||0)+1;const i={permissive:0,"weak-copyleft":0,copyleft:0,unlicensed:0,unknown:0};for(const t of e)i[t.licenseCategory]=(i[t.licenseCategory]||0)+1;const a=e.filter(e=>e.malicious),c=e.filter(e=>!e.malicious&&e.suspectedTyposquat),l=e.filter(e=>e.outdated),u=e.filter(e=>e.deprecated),p=e.filter(e=>"copyleft"===e.licenseCategory||"weak-copyleft"===e.licenseCategory),d=e.filter(e=>"unlicensed"===e.licenseCategory||"unknown"===e.licenseCategory);return{totalDirect:n.length,totalTransitive:s.length,totalPackages:e.length,totalCVEs:o.length,criticalCVEs:r.CRITICAL,highCVEs:r.HIGH,mediumCVEs:r.MEDIUM,lowCVEs:r.LOW,unknownSeverityCVEs:r.UNKNOWN,maliciousCount:a.length,suspectedTyposquatCount:c.length,outdatedCount:l.length,majorVersionsBehindCount:l.filter(e=>e.majorVersionsBehind>0).length,deprecatedCount:u.length,licenseBreakdown:i,copyleftCount:p.length,unlicensedCount:d.length,networkAvailable:t}}generateCycloneDX(e,t={}){const n=t.componentName||path.basename(this.rootPath),s=t.componentVersion||"0.0.0",o=`urn:uuid:${crypto.randomUUID()}`,r=e.packages.map(e=>{const t=integrityAlgo(e.integrity),n=integrityToHex(e.integrity),s={type:"library","bom-ref":e.purl,name:e.name,version:e.version,purl:e.purl,scope:e.dev?"excluded":"required"};return e.license&&"unknown"!==e.licenseCategory?s.licenses=[{license:{id:e.license}}]:e.license&&(s.licenses=[{license:{name:e.license}}]),t&&n&&(s.hashes=[{alg:t,content:n}]),(e.cves.length>0||e.malicious)&&(s.properties=[{name:"thuban:riskLevel",value:e.riskLevel},{name:"thuban:cveCount",value:String(e.cves.length)},{name:"thuban:malicious",value:String(e.malicious)}]),s}),i=[];for(const t of e.packages)for(const e of t.cves)i.push({id:e.id,source:{name:"OSV"},ratings:[{source:{name:"OSV"},severity:e.severity.toLowerCase()}],description:e.summary||void 0,affects:[{ref:t.purl}],...e.fixedVersion?{recommendation:`Upgrade to ${e.fixedVersion} or later`}:{}});return{bomFormat:"CycloneDX",specVersion:"1.5",serialNumber:o,version:1,metadata:{timestamp:e.generatedAt,tools:[{vendor:"Thuban",name:"Thuban Supply Chain Scanner",version:"1.0.0"}],component:{type:"application",name:n,version:s}},components:r,...i.length>0?{vulnerabilities:i}:{}}}generateSPDX(e,t={}){const n=t.componentName||path.basename(this.rootPath),s=`https://thuban.dev/spdx/${crypto.randomUUID()}`,o=e=>e.license&&/^[A-Za-z0-9.+-]+$/.test(e.license)?e.license:"NOASSERTION",r=e.packages.map((e,t)=>({SPDXID:`SPDXRef-Package-${t}-${e.name.replace(/[^A-Za-z0-9.-]/g,"-")}`,name:e.name,versionInfo:e.version,downloadLocation:e.resolved||"NOASSERTION",licenseConcluded:o(e),licenseDeclared:o(e),copyrightText:"NOASSERTION",externalRefs:[{referenceCategory:"PACKAGE-MANAGER",referenceType:"purl",referenceLocator:e.purl}]})),i=r.map(e=>({spdxElementId:"SPDXRef-DOCUMENT",relationshipType:"DESCRIBES",relatedSpdxElement:e.SPDXID}));return{spdxVersion:"SPDX-2.3",dataLicense:"CC0-1.0",SPDXID:"SPDXRef-DOCUMENT",name:`${n}-sbom`,documentNamespace:s,creationInfo:{created:e.generatedAt,creators:["Tool: Thuban-Supply-Chain-Scanner-1.0.0"]},packages:r,relationships:i}}}module.exports={SupplyChainAnalyzer:SupplyChainAnalyzer,classifyLicense:classifyLicense,toPurl:toPurl,suspectedTyposquat:suspectedTyposquat};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const fs=require("fs"),path=require("path"),os=require("os"),https=require("https"),{execSync:execSync}=require("child_process"),readline=require("readline"),KB=require("./support-knowledge.js"),C={reset:"[0m",bold:"[1m",red:"[31m",green:"[32m",yellow:"[33m",blue:"[34m",cyan:"[36m",gray:"[90m"};function ok(e){return` ${C.green}✓${C.reset} ${e}`}function warn(e){return` ${C.yellow}⚠${C.reset} ${e}`}function fail(e){return` ${C.red}✗${C.reset} ${e}`}function safeExec(e){try{return execSync(e,{encoding:"utf8",timeout:1e4,stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}function parseSemver(e){const o=(e||"").match(/(\d+)\.(\d+)\.(\d+)/);return o?{major:Number(o[1]),minor:Number(o[2]),patch:Number(o[3])}:null}function countFiles(e){try{return fs.readdirSync(e).filter(o=>{try{return fs.statSync(path.join(e,o)).isFile()}catch{return!1}}).length}catch{return-1}}function wordOverlap(e,o){const s=new Set(e.toLowerCase().split(/\s+/).filter(Boolean)),t=new Set(o.toLowerCase().split(/\s+/).filter(Boolean));if(0===s.size||0===t.size)return 0;let n=0;for(const e of s)t.has(e)&&n++;return n/Math.max(s.size,t.size)}class SupportBot{constructor(e={}){this.rootPath=e.rootPath||process.cwd(),this.verbose=e.verbose||!1,this.smart=e.smart||!1,this._thubanVersion=null}async semanticQuery(e){const o=process.env.OPENAI_API_KEY,s=process.env.PINECONE_API_KEY;if(!o||!s){try{const o=await this._httpPost("europe-west2-orion-os-479912.cloudfunctions.net","/thuban-api/support/query",{},{query:e,topK:3});if(o.data&&o.data.results)return o.data.results}catch{}return null}try{const t=await this._httpPost("api.openai.com","/v1/embeddings",{Authorization:`Bearer ${o}`},{model:"text-embedding-3-small",input:e});if(!t.data||!t.data.data)return null;const n=t.data.data[0].embedding,r=await this._httpPost("thuban-kb-es8yjbx.svc.aped-4627-b74a.pinecone.io","/query",{"Api-Key":s},{vector:n,topK:3,includeMetadata:!0});return r.data&&r.data.matches?r.data.matches.map(e=>({score:e.score,type:e.metadata.type,...e.metadata})):null}catch(e){return this.verbose&&console.error(`${C.gray} Semantic search error: ${e.message}${C.reset}`),null}}_httpPost(e,o,s,t){return new Promise((n,r)=>{const a=JSON.stringify(t),i=https.request({hostname:e,path:o,method:"POST",timeout:1e4,headers:{...s,"Content-Type":"application/json","Content-Length":Buffer.byteLength(a)}},e=>{let o="";e.on("data",e=>o+=e),e.on("end",()=>{try{n({status:e.statusCode,data:JSON.parse(o)})}catch{n({status:e.statusCode,data:o})}})});i.on("error",r),i.on("timeout",()=>{i.destroy(),r(new Error("timeout"))}),i.write(a),i.end()})}async diagnose(){const e=[],o=[],s=[],t={},n=safeExec("node --version"),r=parseSemver(n);t.nodeVersion=n||"unknown",r&&r.major>=16?e.push(ok(`Node.js ${n} (requires >= 16)`)):r?s.push(fail(`Node.js ${n} — version 16+ required`)):s.push(fail("Node.js not found"));const a=safeExec("npm --version");t.npmVersion=a||"unknown",a?e.push(ok(`npm v${a}`)):o.push(warn("npm not found — install via Node.js installer"));const i=safeExec("git --version"),c=i?i.replace(/^git version\s*/,""):null;t.gitVersion=c||"unknown",c?e.push(ok(`Git v${c}`)):o.push(warn("Git not found — some features require Git"));const l=this._readThubanVersion();t.thubanVersion=l||"unknown",l?e.push(ok(`Thuban v${l}`)):o.push(warn("Could not determine Thuban version")),this._thubanVersion=l;const u=os.platform(),d=os.arch(),p=os.release();t.os=u,t.arch=d,t.release=p;const g=this._formatOS(u,p,d);e.push(ok(`OS: ${g}`));try{fs.accessSync(this.rootPath,fs.constants.R_OK),e.push(ok("Target path exists and is readable"))}catch{s.push(fail(`Target path not readable: ${this.rootPath}`))}const h=countFiles(this.rootPath);h>=0&&(0===h?o.push(warn("Target directory is empty")):this.verbose&&e.push(ok(`${h} file(s) in target directory`))),fs.existsSync(path.join(this.rootPath,"package.json"))?e.push(ok("package.json found")):s.push(fail("No package.json found in target directory")),this._hasCodeFiles(this.rootPath)||o.push(warn("No .js or .ts files found in target directory"));const f=this._checkDiskSpace();!1===f.ok?o.push(warn(`Low disk space: ${f.free} available`)):f.free&&this.verbose&&e.push(ok(`Disk space: ${f.free} available`)),/\s/.test(this.rootPath)&&o.push(warn("Path contains spaces — may cause issues with some commands"));try{fs.accessSync(this.rootPath,fs.constants.W_OK),this.verbose&&e.push(ok("Write permissions on target directory"))}catch{o.push(warn("No write permissions on target directory"))}const $={passed:e,warnings:o,failed:s,systemInfo:t};return this._printDiagnosticReport($),$}_printDiagnosticReport(e){console.log(""),console.log(` ${C.bold}THUBAN SYSTEM DIAGNOSTIC${C.reset}`),console.log(` ${C.gray}────────────────────────${C.reset}`),console.log("");for(const o of e.passed)console.log(o);for(const o of e.warnings)console.log(o);for(const o of e.failed)console.log(o);console.log("");const o=[];e.passed.length&&o.push(`${C.green}${e.passed.length} passed${C.reset}`),e.warnings.length&&o.push(`${C.yellow}${e.warnings.length} warning${1!==e.warnings.length?"s":""}${C.reset}`),e.failed.length&&o.push(`${C.red}${e.failed.length} failed${C.reset}`),console.log(` ${o.join(", ")}`),console.log("")}query(e){return this._queryLocal(e)}async queryAsync(e){const o=this._queryLocal(e);if(o.confidence>=.7)return o;if(this.smart){const o=await this.semanticQuery(e);if(o&&o.length>0&&o[0].score>.35){const e=o[0];return{type:e.type||"faq",data:{question:e.question||e.title||e.name||"",answer:e.answer||e.fix||e.description||"",category:e.category||"general",source:"pinecone",score:e.score,alternatives:o.slice(1).map(e=>({type:e.type,title:e.question||e.title||e.name||"",score:e.score}))},confidence:Math.min(e.score+.3,1)}}}return o}_queryLocal(e){if(!e||"string"!=typeof e)return{type:"none",data:null,confidence:0};const o=e.trim().toLowerCase();if(!o)return{type:"none",data:null,confidence:0};if(KB.patterns&&Array.isArray(KB.patterns))for(const e of KB.patterns)if(e.regex&&new RegExp(e.regex,"i").test(o))return{type:e.type||"troubleshooting",data:e,confidence:1};let s=null,t=0;if(KB.faq&&Array.isArray(KB.faq))for(const e of KB.faq){const n=e.keywords||[];let r=0;for(const e of n)if(o===e.toLowerCase()){r=1;break}if(r<1)for(const e of n)(o.includes(e.toLowerCase())||e.toLowerCase().includes(o))&&(r=Math.max(r,.7));r<.7&&e.question&&wordOverlap(o,e.question)>.5&&(r=Math.max(r,.5)),r>t&&(t=r,s=e)}let n=null,r=0;if(KB.errors&&Array.isArray(KB.errors))for(const e of KB.errors){const s=(e.code||"").toLowerCase(),t=(e.message||"").toLowerCase();if(s&&o.includes(s)){n=e,r=1;break}if(t&&o.includes(t)&&(n=e,r=Math.max(r,.7)),e.keywords)for(const s of e.keywords)o.includes(s.toLowerCase())&&(r=Math.max(r,.5),n=e)}let a=null,i=0;if(KB.commands&&Array.isArray(KB.commands))for(const e of KB.commands){const s=(e.name||"").toLowerCase();if(s&&o.includes(s)){a=e,i=o===s?1:.7;break}if(e.aliases)for(const s of e.aliases)o.includes(s.toLowerCase())&&(a=e,i=.7)}const c=[{type:"faq",data:s,confidence:t},{type:"error",data:n,confidence:r},{type:"command",data:a,confidence:i}].filter(e=>null!==e.data);return c.sort((e,o)=>o.confidence-e.confidence),c.length>0&&c[0].confidence>0?c[0]:{type:"none",data:{suggestions:(KB.faq||[]).slice(0,3).map(e=>({question:e.question,keywords:e.keywords}))},confidence:0}}async startInteractive(){const e=this._readThubanVersion()||"0.0.0",o=readline.createInterface({input:process.stdin,output:process.stdout});console.log(""),console.log(` ${C.cyan}╔══════════════════════════════════════╗${C.reset}`),console.log(` ${C.cyan}║${C.reset} ${C.bold}THUBAN Support Assistant${C.reset} ${C.cyan}║${C.reset}`),console.log(` ${C.cyan}║${C.reset} v${e} · Type 'help' or 'exit' ${C.cyan}║${C.reset}`),console.log(` ${C.cyan}╚══════════════════════════════════════╝${C.reset}`),console.log(""),console.log(` ${C.bold}Quick actions:${C.reset}`),console.log(` ${C.cyan}[1]${C.reset} Run system diagnostic`),console.log(` ${C.cyan}[2]${C.reset} Installation help`),console.log(` ${C.cyan}[3]${C.reset} Scan not working`),console.log(` ${C.cyan}[4]${C.reset} Understanding results`),console.log(` ${C.cyan}[5]${C.reset} Monitor/watch mode guide`),console.log(` ${C.cyan}[6]${C.reset} Commands reference`),console.log(` ${C.cyan}[7]${C.reset} Report a bug (thuban feedback)`),console.log("");const s={1:"diagnose",2:"installation",3:"scan-not-working",4:"understanding-results",5:"monitor-mode",6:"commands",7:"report-bug"},t=()=>new Promise(e=>{o.question(` ${C.bold}You:${C.reset} `,o=>{e(o?o.trim():"")})}),n=()=>new Promise(e=>{o.question(`\n ${C.gray}Did this help? (y/n/more):${C.reset} `,o=>{e(o?o.trim().toLowerCase():"")})});let r=!0;for(;r;){const e=await t();if(!e)continue;const o=e.toLowerCase();if("exit"===o||"quit"===o){console.log(`\n ${C.cyan}Goodbye! Run 'thuban support' anytime.${C.reset}\n`),r=!1;break}if("help"===o){this._printHelp();continue}if("diagnose"===o||"1"===o){await this.diagnose();continue}if(s[o]&&"1"!==o){const e=s[o];if("report-bug"===e){console.log(`\n ${C.cyan}To report a bug, run:${C.reset}`),console.log(" thuban feedback 'describe your issue'\n");continue}this._handleSlugQuery(e);const t=await n();this._handleFollowUp(t,e);continue}const a=this.query(e);if(this._printQueryResult(a),a.confidence<.5)console.log(`\n ${C.yellow}I couldn't find an exact match. Try:${C.reset}`),console.log(` • ${C.cyan}thuban support --diagnose${C.reset} (run diagnostics)`),console.log(` • ${C.cyan}thuban feedback 'describe your issue'${C.reset} (report to the team)`);else{const e=await n();this._handleFollowUp(e,null)}}o.close()}_readThubanVersion(){const e=[path.join(__dirname,"package.json"),path.join(__dirname,"..","package.json"),path.join(__dirname,"..","..","package.json")];for(const o of e)try{const e=fs.readFileSync(o,"utf8"),s=JSON.parse(e);if(s.version)return s.version}catch{}return null}_formatOS(e,o,s){return`${{win32:"Windows",darwin:"macOS",linux:"Linux",freebsd:"FreeBSD"}[e]||e} ${o} (${s})`}_hasCodeFiles(e){try{return fs.readdirSync(e).some(e=>/\.(js|ts|jsx|tsx|mjs|cjs)$/.test(e))}catch{return!1}}_checkDiskSpace(){const e="win32"===os.platform();try{if(e){const e=safeExec(`wmic logicaldisk where "DeviceID='${(path.parse(this.rootPath).root||"C:\\").charAt(0)}:'" get FreeSpace /format:value`);if(e){const o=e.match(/FreeSpace=(\d+)/);if(o){const e=parseInt(o[1],10);return{ok:e>536870912,free:`${(e/1073741824).toFixed(1)} GB`}}}}else{const e=safeExec(`df -h "${this.rootPath}" 2>/dev/null`);if(e){const o=e.split("\n");if(o.length>=2){return{ok:!0,free:o[1].split(/\s+/)[3]||"unknown"}}}}}catch{}return{ok:null,free:null}}_printHelp(){console.log(""),console.log(` ${C.bold}Available commands:${C.reset}`),console.log(` ${C.cyan}help${C.reset} — Show this help message`),console.log(` ${C.cyan}diagnose${C.reset} — Run full system diagnostic`),console.log(` ${C.cyan}1-7${C.reset} — Quick action shortcuts`),console.log(` ${C.cyan}exit${C.reset} — Exit the support assistant`),console.log(""),console.log(` ${C.bold}Or type any question:${C.reset}`),console.log(' "How do I scan a project?"'),console.log(' "What does error E001 mean?"'),console.log(' "scan command options"'),console.log("")}_handleSlugQuery(e){if(KB.troubleshooting&&Array.isArray(KB.troubleshooting)){const o=KB.troubleshooting.find(o=>o.slug===e);if(o){if(console.log(""),console.log(` ${C.bold}${o.title||o.slug}${C.reset}`),console.log(` ${C.gray}${"─".repeat(40)}${C.reset}`),o.summary&&console.log(`\n ${o.summary}`),o.steps&&o.steps.length>0){console.log("");for(let e=0;e<o.steps.length;e++){const s=o.steps[e];console.log(` ${C.cyan}${e+1}.${C.reset} ${s.description||s.text||""}`),s.fix&&console.log(` ${C.gray}→ ${s.fix}${C.reset}`)}}return void console.log("")}}const o=this.query(e);this._printQueryResult(o)}_printQueryResult(e){if(console.log(""),"none"===e.type){if(e.data&&e.data.suggestions&&e.data.suggestions.length>0){console.log(` ${C.yellow}No exact match found. Did you mean:${C.reset}`);for(const o of e.data.suggestions)console.log(` • ${o.question||o.keywords?.join(", ")||"(untitled)"}`)}else console.log(` ${C.yellow}No results found.${C.reset}`);return void console.log("")}const o=e.data;switch(e.type){case"faq":console.log(` ${C.bold}${o.question||"FAQ"}${C.reset}`),o.answer&&console.log(` ${o.answer}`),o.example&&console.log(`\n ${C.gray}Example:${C.reset} ${o.example}`);break;case"error":console.log(` ${C.bold}${C.red}Error: ${o.code||"Unknown"}${C.reset}`),o.message&&console.log(` ${o.message}`),o.cause&&console.log(`\n ${C.yellow}Cause:${C.reset} ${o.cause}`),o.fix&&console.log(` ${C.green}Fix:${C.reset} ${o.fix}`);break;case"command":if(console.log(` ${C.bold}${C.cyan}${o.name||"Command"}${C.reset}`),o.description&&console.log(` ${o.description}`),o.usage&&console.log(`\n ${C.gray}Usage:${C.reset} ${o.usage}`),o.options&&Array.isArray(o.options)){console.log(`\n ${C.bold}Options:${C.reset}`);for(const e of o.options)console.log(` ${C.cyan}${e.flag||e.name}${C.reset} ${e.description||""}`)}break;case"troubleshooting":if(console.log(` ${C.bold}${o.title||o.slug||"Troubleshooting"}${C.reset}`),o.response&&console.log(` ${o.response}`),o.steps&&Array.isArray(o.steps))for(const e of o.steps)console.log(` • ${e}`);break;default:console.log(` ${C.gray}(${e.type})${C.reset} ${JSON.stringify(o)}`)}e.confidence<1&&e.confidence>=.5&&console.log(`\n ${C.gray}(confidence: ${Math.round(100*e.confidence)}% — results may be approximate)${C.reset}`),console.log("")}_handleFollowUp(e,o){if(e)switch(e){case"y":case"yes":console.log(`\n ${C.green}Great! Anything else?${C.reset}\n`);break;case"n":case"no":console.log(`\n ${C.yellow}Sorry about that. Try describing your issue differently,`),console.log(` or run '${C.cyan}thuban feedback${C.reset}' to report it.${C.reset}\n`);break;case"more":this._showRelatedEntries(o)}}_showRelatedEntries(e){if(!KB.faq||!Array.isArray(KB.faq))return void console.log(`\n ${C.gray}No additional entries available.${C.reset}\n`);const o=KB.faq.filter(o=>o.slug!==e).slice(0,5);if(0!==o.length){console.log(`\n ${C.bold}Related topics:${C.reset}`);for(const e of o)console.log(` • ${e.question||e.keywords?.join(", ")||e.slug||"(untitled)"}`);console.log("")}else console.log(`\n ${C.gray}No additional entries available.${C.reset}\n`)}}module.exports=SupportBot;
|