@dailephd/my-dev-kit-lab 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +46 -269
  2. package/dist/scripts/security/validate.js +177 -70
  3. package/dist/src/audits/codeRot/detectors/architectureDriftDetector.js +5 -2
  4. package/dist/src/audits/codeRot/detectors/securityValidationAssumptionRotDetector.js +5 -2
  5. package/dist/src/audits/core/collectSourceFacts.js +21 -10
  6. package/dist/src/mobile/android/audit/androidFinding.js +68 -0
  7. package/dist/src/mobile/android/audit/checkResultBuilder.js +97 -0
  8. package/dist/src/mobile/android/audit/deepLinkAudit.js +183 -0
  9. package/dist/src/mobile/android/audit/exportedComponentAudit.js +183 -0
  10. package/dist/src/mobile/android/audit/intentFilterAudit.js +128 -0
  11. package/dist/src/mobile/android/audit/permissionAudit.js +142 -0
  12. package/dist/src/mobile/android/detect/androidTargetDetection.js +18 -0
  13. package/dist/src/mobile/android/detect/buildFileEvidence.js +36 -0
  14. package/dist/src/mobile/android/detect/classify.js +150 -0
  15. package/dist/src/mobile/android/detect/detectAndroidProject.js +252 -0
  16. package/dist/src/mobile/android/detect/settingsModules.js +60 -0
  17. package/dist/src/mobile/android/detect/sourceEvidence.js +92 -0
  18. package/dist/src/mobile/android/detect/traversal.js +79 -0
  19. package/dist/src/mobile/android/detect/versionCatalogEvidence.js +37 -0
  20. package/dist/src/mobile/android/detection.js +28 -0
  21. package/dist/src/mobile/android/gradle/gradleMetadataCheckResult.js +120 -0
  22. package/dist/src/mobile/android/gradle/moduleMetadataExtractor.js +137 -0
  23. package/dist/src/mobile/android/gradle/pluginVersionExtractor.js +40 -0
  24. package/dist/src/mobile/android/gradle/readAndroidGradleMetadata.js +210 -0
  25. package/dist/src/mobile/android/gradle/releaseMetadataSummary.js +64 -0
  26. package/dist/src/mobile/android/gradle/settingsMetadata.js +20 -0
  27. package/dist/src/mobile/android/gradle/types.js +1 -0
  28. package/dist/src/mobile/android/gradle/validate/executor.js +9 -0
  29. package/dist/src/mobile/android/gradle/validate/operationCheckResult.js +99 -0
  30. package/dist/src/mobile/android/gradle/validate/operations.js +68 -0
  31. package/dist/src/mobile/android/gradle/validate/planner.js +49 -0
  32. package/dist/src/mobile/android/gradle/validate/runOptionalGradleValidation.js +113 -0
  33. package/dist/src/mobile/android/gradle/validate/targetMutation.js +45 -0
  34. package/dist/src/mobile/android/gradle/validate/taskListParser.js +24 -0
  35. package/dist/src/mobile/android/gradle/versionCatalogMetadata.js +94 -0
  36. package/dist/src/mobile/android/gradle/wrapperMetadata.js +32 -0
  37. package/dist/src/mobile/android/manifest/parseAndroidManifest.js +341 -0
  38. package/dist/src/mobile/android/manifest/types.js +29 -0
  39. package/dist/src/mobile/android/manifest/xml/parseXml.js +313 -0
  40. package/dist/src/mobile/android/profile.js +29 -0
  41. package/dist/src/mobile/android/report/model.js +104 -0
  42. package/dist/src/mobile/android/report/renderAndroidReport.js +223 -0
  43. package/dist/src/mobile/android/report/writeAndroidReportFiles.js +23 -0
  44. package/dist/src/mobile/android/targetMetadata.js +27 -0
  45. package/dist/src/mobile/android/validate/androidVerdict.js +248 -0
  46. package/dist/src/mobile/android/validate/detectionAndImmutabilityCheckResults.js +177 -0
  47. package/dist/src/mobile/android/validate/playReadinessChecklist.js +145 -0
  48. package/dist/src/mobile/android/validate/validateAndroidTarget.js +172 -0
  49. package/dist/src/mobile/android/validation/checkResult.js +51 -0
  50. package/dist/src/mobile/android/validation/result.js +25 -0
  51. package/dist/src/mobile/index.js +42 -0
  52. package/dist/src/mobile/types.js +27 -0
  53. package/dist/src/securityValidation/attackScenarios/attackProfile.js +2 -0
  54. package/dist/src/securityValidation/attackScenarios/profiles/androidProfile.js +20 -0
  55. package/dist/src/securityValidation/validate/cliOptions.js +46 -2
  56. package/package.json +2 -1
  57. package/tests/fixtures/android/compose-app/app/build.gradle.kts +21 -0
  58. package/tests/fixtures/android/compose-app/app/src/main/AndroidManifest.xml +22 -0
  59. package/tests/fixtures/android/compose-app/app/src/main/java/com/example/composeapp/MainActivity.kt +11 -0
  60. package/tests/fixtures/android/compose-app/build.gradle.kts +4 -0
  61. package/tests/fixtures/android/compose-app/gradle/wrapper/gradle-wrapper.properties +4 -0
  62. package/tests/fixtures/android/compose-app/settings.gradle.kts +2 -0
  63. package/tests/fixtures/android/gradle-metadata-fixtures/catalog-only-plugin/build.gradle.kts +3 -0
  64. package/tests/fixtures/android/gradle-metadata-fixtures/catalog-only-plugin/gradle/libs.versions.toml +5 -0
  65. package/tests/fixtures/android/gradle-metadata-fixtures/comment-safety.gradle.kts +21 -0
  66. package/tests/fixtures/android/gradle-metadata-fixtures/dynamic-values.gradle.kts +17 -0
  67. package/tests/fixtures/android/gradle-metadata-fixtures/groovy-literal.gradle +23 -0
  68. package/tests/fixtures/android/gradle-metadata-fixtures/wrapper-malformed.properties +4 -0
  69. package/tests/fixtures/android/gradle-metadata-fixtures/wrapper-missing-url.properties +3 -0
  70. package/tests/fixtures/android/gradle-metadata-fixtures/wrapper-with-checksum.properties +5 -0
  71. package/tests/fixtures/android/java-app/app/build.gradle +16 -0
  72. package/tests/fixtures/android/java-app/app/src/main/AndroidManifest.xml +19 -0
  73. package/tests/fixtures/android/java-app/app/src/main/java/com/example/javaapp/MainActivity.java +4 -0
  74. package/tests/fixtures/android/java-app/build.gradle +3 -0
  75. package/tests/fixtures/android/java-app/gradle/wrapper/gradle-wrapper.properties +4 -0
  76. package/tests/fixtures/android/java-app/settings.gradle +2 -0
  77. package/tests/fixtures/android/library/build.gradle.kts +3 -0
  78. package/tests/fixtures/android/library/gradle/wrapper/gradle-wrapper.properties +4 -0
  79. package/tests/fixtures/android/library/mylibrary/build.gradle.kts +13 -0
  80. package/tests/fixtures/android/library/mylibrary/src/main/AndroidManifest.xml +2 -0
  81. package/tests/fixtures/android/library/settings.gradle.kts +2 -0
  82. package/tests/fixtures/android/manifest-audit-fixtures/incomplete-intent-filter.xml +14 -0
  83. package/tests/fixtures/android/manifest-audit-fixtures/malformed-exported.xml +10 -0
  84. package/tests/fixtures/android/manifest-audit-fixtures/malformed.xml +5 -0
  85. package/tests/fixtures/android/manifest-audit-fixtures/missing-application.xml +7 -0
  86. package/tests/fixtures/android/manifest-audit-fixtures/missing-component-name.xml +11 -0
  87. package/tests/fixtures/android/manifest-audit-fixtures/permission-coverage.xml +29 -0
  88. package/tests/fixtures/android/manifest-audit-fixtures/risky-components.xml +62 -0
  89. package/tests/fixtures/android/manifest-audit-fixtures/risky-deep-links.xml +45 -0
  90. package/tests/fixtures/android/manifest-audit-fixtures/unresolved-placeholder.xml +14 -0
  91. package/tests/fixtures/android/manifest-audit-fixtures/unusual-namespace-prefix.xml +11 -0
  92. package/tests/fixtures/android/multi-module/app/build.gradle.kts +22 -0
  93. package/tests/fixtures/android/multi-module/app/src/androidTest/java/com/example/multimodule/app/ExampleInstrumentedTest.kt +3 -0
  94. package/tests/fixtures/android/multi-module/app/src/main/AndroidManifest.xml +11 -0
  95. package/tests/fixtures/android/multi-module/app/src/test/java/com/example/multimodule/app/ExampleUnitTest.kt +3 -0
  96. package/tests/fixtures/android/multi-module/build.gradle.kts +5 -0
  97. package/tests/fixtures/android/multi-module/core/build.gradle.kts +14 -0
  98. package/tests/fixtures/android/multi-module/core/src/main/AndroidManifest.xml +2 -0
  99. package/tests/fixtures/android/multi-module/feature-login/build.gradle.kts +18 -0
  100. package/tests/fixtures/android/multi-module/feature-login/src/main/AndroidManifest.xml +2 -0
  101. package/tests/fixtures/android/multi-module/gradle/libs.versions.toml +8 -0
  102. package/tests/fixtures/android/multi-module/gradle/wrapper/gradle-wrapper.properties +4 -0
  103. package/tests/fixtures/android/multi-module/settings.gradle.kts +4 -0
  104. package/tests/fixtures/android/non-android-gradle/build.gradle.kts +3 -0
  105. package/tests/fixtures/android/non-android-gradle/core/build.gradle.kts +3 -0
  106. package/tests/fixtures/android/non-android-gradle/core/src/main/java/com/example/core/Core.java +4 -0
  107. package/tests/fixtures/android/non-android-gradle/gradle/wrapper/gradle-wrapper.properties +4 -0
  108. package/tests/fixtures/android/non-android-gradle/settings.gradle.kts +2 -0
  109. package/tests/fixtures/android/partial/app/build.gradle.kts +7 -0
  110. package/tests/fixtures/android/partial/settings.gradle.kts +2 -0
  111. package/tests/fixtures/android/xml-view-app/app/build.gradle.kts +17 -0
  112. package/tests/fixtures/android/xml-view-app/app/src/main/AndroidManifest.xml +31 -0
  113. package/tests/fixtures/android/xml-view-app/app/src/main/kotlin/com/example/xmlviewapp/MainActivity.kt +7 -0
  114. package/tests/fixtures/android/xml-view-app/app/src/main/res/layout/activity_main.xml +4 -0
  115. package/tests/fixtures/android/xml-view-app/build.gradle.kts +4 -0
  116. package/tests/fixtures/android/xml-view-app/gradle/wrapper/gradle-wrapper.properties +4 -0
  117. package/tests/fixtures/android/xml-view-app/settings.gradle.kts +2 -0
  118. package/tests/fixtures/audits/mixed-language/mixed-docs-claims/README.md +16 -0
  119. package/tests/fixtures/audits/mixed-language/mixed-docs-claims/build.gradle.kts +4 -0
  120. package/tests/fixtures/audits/mixed-language/mixed-docs-claims/src/main/java/com/example/Widget.java +7 -0
  121. package/tests/fixtures/audits/mixed-language/mixed-docs-claims/src/main/kotlin/com/example/Gadget.kt +7 -0
  122. package/tests/fixtures/audits/mixed-language/mixed-generated-vendor/README.md +10 -0
  123. package/tests/fixtures/audits/mixed-language/mixed-generated-vendor/build/Main.class +1 -0
  124. package/tests/fixtures/audits/mixed-language/mixed-generated-vendor/dist/index.js +1 -0
  125. package/tests/fixtures/audits/mixed-language/mixed-generated-vendor/generated/schema.ts +1 -0
  126. package/tests/fixtures/audits/mixed-language/mixed-generated-vendor/src/index.ts +3 -0
  127. package/tests/fixtures/audits/mixed-language/mixed-generated-vendor/vendor/lib.py +2 -0
  128. package/tests/fixtures/audits/mixed-language/mixed-java-kotlin/README.md +10 -0
  129. package/tests/fixtures/audits/mixed-language/mixed-java-kotlin/build.gradle.kts +8 -0
  130. package/tests/fixtures/audits/mixed-language/mixed-java-kotlin/settings.gradle.kts +1 -0
  131. package/tests/fixtures/audits/mixed-language/mixed-java-kotlin/src/main/java/com/example/FooService.java +7 -0
  132. package/tests/fixtures/audits/mixed-language/mixed-java-kotlin/src/main/kotlin/com/example/BarService.kt +7 -0
  133. package/tests/fixtures/audits/mixed-language/mixed-java-kotlin/src/test/java/com/example/FooServiceTest.java +8 -0
  134. package/tests/fixtures/audits/mixed-language/mixed-java-kotlin/src/test/kotlin/com/example/BarServiceTest.kt +8 -0
  135. package/tests/fixtures/audits/mixed-language/mixed-python-ts/README.md +8 -0
  136. package/tests/fixtures/audits/mixed-language/mixed-python-ts/src/app.py +7 -0
  137. package/tests/fixtures/audits/mixed-language/mixed-python-ts/src/index.ts +3 -0
  138. package/tests/fixtures/audits/mixed-language/mixed-python-ts/tests/test_app.py +5 -0
  139. package/tests/fixtures/audits/mixed-language/mixed-ts-js/README.md +7 -0
  140. package/tests/fixtures/audits/mixed-language/mixed-ts-js/src/helper.js +5 -0
  141. package/tests/fixtures/audits/mixed-language/mixed-ts-js/src/index.ts +3 -0
  142. package/tests/fixtures/audits/mixed-language/mixed-ts-js/tests/index.sample.ts +5 -0
  143. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/README.md +10 -0
  144. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/build.gradle.kts +4 -0
  145. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/pytests/test_app.py +5 -0
  146. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/src/app.py +2 -0
  147. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/src/helper.js +5 -0
  148. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/src/index.ts +3 -0
  149. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/src/main/java/com/example/Multiplier.java +7 -0
  150. package/tests/fixtures/audits/mixed-language/mixed-ts-python-jvm/src/main/kotlin/com/example/Divider.kt +7 -0
package/README.md CHANGED
@@ -1,301 +1,78 @@
1
1
  # my-dev-kit-lab
2
2
 
3
- my-dev-kit-lab is the experiment, evidence, reporting, security-validation, and audit companion for my-dev-kit. It runs reproducible experiments that test whether my-dev-kit's graph-guided retrieval helps coding-agent workflows, collects metrics, renders reports, generates plots, captures screenshots, builds gallery outputs, performs automated CLI/package security validation, and runs the generic audit framework.
3
+ my-dev-kit-lab is the experiment, evidence, reporting, visualization, and security-validation companion for my-dev-kit. It provides controlled raw-full-file versus graph-guided retrieval experiments, deterministic fake-agent demonstrations, reports, plots, gallery artifacts, generic audits, and local security-validation workflows.
4
4
 
5
- The current published baseline is `v0.3.2`. `v0.3.0` introduced the generic audit framework and the first implemented code-rot detector family; `v0.3.1` added the language-aware code-rot substrate plus TypeScript/JavaScript support; `v0.3.2` added Python-aware code-rot support and a first security-validation audit adapter. The generic experiment-plugin framework was introduced in `v0.2.0`. The first plugin is `context-strategy-comparison`, which preserves the existing raw-full-file vs my-dev-kit-guided workflow through the plugin runner.
6
-
7
- The checked-out implementation is ahead of the published baseline: release-prepared, not-yet-published `v0.3.3` work adds Java/Kotlin source-facts support and JVM-aware code-rot detector integration on top of the published `v0.3.2` baseline. Package metadata is now `0.3.3` as part of release preparation. Java/Kotlin support is conservative static analysis only: dependency-free scanners, static Gradle/Maven metadata detection, and no compiler, classpath, Gradle, Maven, Android, or target-test execution. Cross-language stability, Android validation, framework-aware profiles, and the `quality`/`project`/`all` audit types remain future roadmap work.
8
-
9
- my-dev-kit is most useful when the repository is larger than the task. It helps coding agents work with large codebases through reusable structural indexing, graph-guided retrieval, targeted source slices, and auditable context selection. Results are scoped evidence; the project does not claim that my-dev-kit always saves tokens.
10
-
11
- **my-dev-kit** is the repo indexing and graph-guided retrieval engine.
12
- **my-dev-kit-lab** is the separate lab layer that feeds it benchmark inputs and records evaluation outputs.
13
-
14
- ---
5
+ The current published baseline is `v0.3.4`. The v0.4.0 Android validation implementation is release-prepared on `release/v0.4.0`; publication is pending. It is not published, and the npm registry latest version remains `0.3.4`.
15
6
 
16
7
  ## Current capabilities
17
8
 
18
- - Benchmark projects at small, medium, and large complexity levels
19
- - Project complexity metrics and benchmark case metadata with answer keys
20
- - Prompt variant generation at `short`, `medium`, `long`, and `multi-step` complexity levels
21
- - Fake-agent adapter for deterministic smoke and demo validation
22
- - Codex and Claude adapters for real-agent campaigns
23
- - Controlled experiment runner comparing `raw-full-file` vs `my-dev-kit-guided` strategies
24
- - Deterministic correctness scoring from answer keys
25
- - Token usage, duration, and status comparisons between matched strategy pairs
26
- - HTML experiment report rendering
27
- - Static SVG plot generation
28
- - Optional PNG screenshot capture
29
- - Gallery manifest and static gallery index output
30
- - Visualization demos using my-dev-kit commands against benchmark projects
31
- - Final demo workflow combining all pipeline stages
32
- - Generic experiment-plugin command surface: `experiment:list`, `experiment:describe`, and `experiment:run`
33
- - First experiment plugin: `context-strategy-comparison`
34
- - Target-aware experiment execution for local projects via `experiment:run -- --target <path>`
35
- - Plugin-aware JSON and HTML reports with plugin, target, variant, metric, artifact, warning, skip, and failure metadata
36
- - Security validation framework: dependency audit, package tarball inspection, CLI adversarial tests, static scans (CodeQL/Semgrep), bounded fuzz smoke, attack-scenario checks, and structured verdict/report output — runnable against any local project via `security:validate --target <path>`. `security:validate` remains the standalone, focused security-validation command; it is not replaced by the audit adapter below.
37
- - Generic audit framework, current published baseline: `npm run audit` runs heuristic, conservative code-rot detectors and writes text/JSON reports under `reports/audits/code-rot/` by default. `code-rot` and `security` are the currently implemented audit types (`--types code-rot`, `--types security`, or combined `--types code-rot,security`); `quality`, `project`, and `all` audit types are planned and fail cleanly instead of running. `npm run audit` supports `--target`, `--types`, and other flags — see [docs/COMMANDS.md](docs/COMMANDS.md). Audit does not modify target files and does not auto-fix issues.
38
- - Language-aware code-rot support, current checked-out package state: normalized language/file-role inventory, a source-facts model and collector, TypeScript/JavaScript, Python, Java, and Kotlin analyzers, and conservative detector integrations for `dead-code-candidate`, `duplicate-implementation-candidate`, `test-rot`, and `docs-code-mismatch`. Python project metadata remains a top-level audit report field. Java/Kotlin support adds static JVM project metadata detection for Gradle/Maven/source-set shape and conservative source-facts evidence, but no compiler parsing, type resolution, classpath resolution, Gradle/Maven execution, Android validation, or target-project test execution. No `SourceFacts` schema change or new audit command was added for `v0.3.3`.
39
- - Security-validation audit adapter, current checked-out package state: `npm run audit -- --types security` runs security validation through the shared audit/report surface by calling the same `runSecurityValidation()` internals `security:validate` uses, maps security findings into audit-issue-shaped entries, and adds a `securitySummary` field (verdict, check counts, finding counts, and links to the original `reports/security/*.txt`/`*.json` report) to audit JSON/text reports. `npm run audit -- --types code-rot,security` runs both audit types together. The original `security:validate` command and its `reports/security/` output are unchanged.
40
-
41
- ---
42
-
43
- ## Architecture overview
44
-
45
- ```mermaid
46
- flowchart TD
47
- A[scripts/experiments] --> B[Experiment plugin registry + runner]
48
- B --> C[context-strategy-comparison]
49
- C --> D[Controlled experiment foundations]
50
- D --> E[Plugin + legacy artifacts]
51
- E --> F[Plugin-aware reports]
52
- E --> G[Plots / screenshots / gallery]
53
- H[scripts/security] --> I[Automated security validation]
54
- I --> J[Security reports + verdict]
55
- ```
56
-
57
- ---
9
+ - Controlled experiment plugins, reports, plots, screenshots, and gallery artifacts.
10
+ - Generic code-rot and general security audit types through `npm run audit`.
11
+ - Standalone CLI/package security validation through `npm run security:validate`.
12
+ - Android security validation through the canonical `android` profile on the v0.4.0 feature branch.
58
13
 
59
- ## Quickstart
14
+ ## Android validation
60
15
 
61
- ### Install
62
-
63
- ```bash
64
- npm install
65
- ```
16
+ Run static Android validation with:
66
17
 
67
18
  ```powershell
68
- npm install
19
+ npm run security:validate -- --target "<android-project-path>" --profile android
69
20
  ```
70
21
 
71
- `cmd.exe` users should run the same command on one line.
72
-
73
- ### Build
22
+ This default path executes **no Gradle commands**. It detects/classifies Android projects and UI evidence, parses discovered manifests independently, audits permissions/exported components/intent filters/deep links, extracts static Gradle metadata, assembles release metadata and Play-readiness placeholders, calculates an Android verdict, and writes bounded text and JSON reports.
74
23
 
75
- ```bash
76
- npm run build
77
- ```
78
-
79
- ### Verify the installation
80
-
81
- ```bash
82
- npm run verify
83
- ```
24
+ Reports use the existing `reports/security/` root unless `--out` is supplied. Android report files use the `<prefix>-android-security-validation.txt` and `.json` convention.
84
25
 
85
- ### Run the fake-agent final demo (deterministic, no external CLIs required)
86
-
87
- ```bash
88
- npm run run-final-demo -- \
89
- --cases examples/token-savings-cases.json \
90
- --out lab-output/final-demo \
91
- --kit-command "node tests/fixtures/fake-my-dev-kit-cli.js" \
92
- --agents fake-agent \
93
- --complexities short \
94
- --no-screenshot
95
- ```
26
+ Optional Gradle validation is explicit:
96
27
 
97
28
  ```powershell
98
- npm run run-final-demo -- `
99
- --cases examples/token-savings-cases.json `
100
- --out lab-output/final-demo `
101
- --kit-command "node tests/fixtures/fake-my-dev-kit-cli.js" `
102
- --agents fake-agent `
103
- --complexities short `
104
- --no-screenshot
29
+ npm run security:validate -- --target "<android-project-path>" --profile android --android-gradle-operations wrapper-version,tasks
105
30
  ```
106
31
 
107
- ```bat
108
- npm run run-final-demo -- --cases examples/token-savings-cases.json --out lab-output/final-demo --kit-command "node tests/fixtures/fake-my-dev-kit-cli.js" --agents fake-agent --complexities short --no-screenshot
109
- ```
32
+ The only allowed operation IDs are:
110
33
 
111
- The lab resolves Windows `.cmd` and `.ps1` CLI shims, supports command paths with spaces, and keeps generated artifacts inside the requested output directory.
34
+ - `wrapper-version`
35
+ - `tasks`
36
+ - `assemble-debug`
37
+ - `unit-test-debug`
38
+ - `lint-debug`
112
39
 
113
- This runs a full pipeline: controlled experiment → report → plots → visualization demos → gallery.
40
+ Unknown or empty lists, arbitrary tasks, and use with a non-Android profile are rejected. Optional operations can require Java, Android SDK components, wrapper distributions, and cached dependencies; environment gaps can produce skipped or inconclusive evidence.
114
41
 
115
- ### Run a real-agent campaign (requires Codex or Claude CLI)
42
+ ### Verdicts
116
43
 
117
- ```bash
118
- npm run run-controlled-experiment -- \
119
- --cases examples/real-agent-campaign-cases.json \
120
- --agents codex,claude \
121
- --strategies raw-full-file,my-dev-kit-guided \
122
- --complexities medium,multi-step \
123
- --out lab-output/real-agent-campaign \
124
- --include-real-agents \
125
- --continue-on-failure \
126
- --timeout-ms 240000
127
- ```
44
+ - `not-ready-security-blocker-remains`: a blocker remains.
45
+ - `inconclusive-audit-environment-incomplete`: required evidence/environment is incomplete.
46
+ - `ready-except-optional-manual-checks`: advisory or manual follow-up remains.
47
+ - `ready-for-release-preparation`: required static evidence passed.
128
48
 
129
- Real-agent runs require local Codex or Claude CLI setup and available usage capacity. Runs that time out, produce invalid output, or hit session limits are recorded as structured outcomes rather than failures.
49
+ These are validation-evidence states, not claims that an app is published, Play-ready, Play-compliant, runtime-secure, or signing-valid.
130
50
 
131
- ### List, describe, and run experiment plugins
51
+ ### Important Android limitations
132
52
 
133
- ```bash
134
- npm run experiment:list
135
- npm run experiment:describe -- --experiment context-strategy-comparison
136
- npm run experiment:run -- \
137
- --experiment context-strategy-comparison \
138
- --target /path/to/local/project \
139
- --agents fake-agent \
140
- --complexities short \
141
- --no-screenshot
142
- ```
53
+ - Static analysis does not prove runtime behavior.
54
+ - Manifests are not merged; placeholders and resource references are not resolved.
55
+ - Gradle scripts are not evaluated; dynamic metadata can stay unresolved; same-file duplicate assignment extraction uses the first match.
56
+ - Optional Gradle execution is disabled by default and environment-dependent.
57
+ - APK/AAB contents, signing, emulator/device behavior, Digital Asset Links, domain ownership, and live Google Play policy are not validated.
58
+ - Play Console items such as privacy policy, Data Safety, permissions declarations, store listing, release notes, content rating, and policy review remain manual placeholders.
59
+
60
+ ## Development
143
61
 
144
62
  ```powershell
145
- npm run experiment:list
146
- npm run experiment:describe -- --experiment context-strategy-comparison
147
- npm run experiment:run -- `
148
- --experiment context-strategy-comparison `
149
- --target "Z:\Users\newuser\Projects\my-dev-kit-v1" `
150
- --agents fake-agent `
151
- --complexities short `
152
- --no-screenshot
63
+ npm run typecheck
64
+ npm run build
65
+ npm run test
66
+ npm run verify
153
67
  ```
154
68
 
155
- When `--target` is omitted, the experiment runs in self mode against my-dev-kit-lab. When `--target <path>` is provided, the lab remains the tool root and the target project is inspected separately. Generated experiment outputs stay under lab-controlled output directories by default, not inside the target project.
156
-
157
- ---
158
-
159
- ## Where to find outputs
160
-
161
- | Artifact | Location |
162
- |---|---|
163
- | Experiment summary | `lab-output/<experiment>/experiment-summary.json` |
164
- | All runs | `lab-output/<experiment>/experiment-runs.json` |
165
- | Strategy comparisons | `lab-output/<experiment>/experiment-comparisons.json` |
166
- | HTML report | `lab-output/<report>/experiment-report.html` |
167
- | Report JSON | `lab-output/<report>/experiment-report.json` |
168
- | Report screenshot | `lab-output/<report>/experiment-report.png` |
169
- | Plugin experiment report JSON | `lab-output/experiments/<plugin>/<target>/<run>/report.json` |
170
- | Plugin experiment report HTML | `lab-output/experiments/<plugin>/<target>/<run>/report.html` |
171
- | Plot data | `lab-output/<plots>/plot-data.json` |
172
- | SVG charts | `lab-output/<plots>/charts/*.svg` |
173
- | Gallery manifest | `lab-output/<gallery>/gallery-manifest.json` |
174
- | Gallery index | `lab-output/<gallery>/gallery-index.html` |
175
-
176
- ---
177
-
178
- ## How to read the main report
179
-
180
- Open `experiment-report.html` in a browser. The report shows:
181
-
182
- - **Project profile** — benchmark project name, language mix, complexity score, and file tree
183
- - **Benchmark tasks** — task descriptions and answer keys
184
- - **Strategy comparisons** — paired `raw-full-file` vs `my-dev-kit-guided` runs per case
185
- - **Correctness scores** — deterministic answer-key scoring (not semantic LLM judging)
186
- - **Token usage** — estimated or reported token totals per run
187
- - **Token savings** — positive means my-dev-kit used fewer tokens; negative means it used more
188
- - **Duration** — wall-clock time per run
189
- - **Status** — completed, timeout, invalid-output, or limit-reached
190
- - **Warnings and limitations** — notes on missing token totals or partial results
191
-
192
- See [docs/METRICS.md](docs/METRICS.md) for full metric definitions.
193
-
194
- ---
195
-
196
- ## Current limitations
197
-
198
- - Token savings shown in fake-agent runs are based on estimated character counts, not provider billing telemetry
199
- - Claude does not expose token totals; token savings comparisons are unavailable for Claude runs
200
- - Codex may expose token totals but can produce timeouts or invalid-output runs
201
- - Small projects may make raw-full-file cheaper than my-dev-kit-guided; larger localized tasks are where my-dev-kit is expected to become more useful
202
- - The generic experiment-plugin framework currently ships one plugin, `context-strategy-comparison`; future plugins such as warm-index reuse, incremental-change, and context-window scaling are not implemented yet
203
- - The current baseline does not prove token savings are guaranteed; it produces auditable evidence for specific cases, targets, agents, and strategies
204
- - Provider telemetry dashboards, semantic LLM judging, and cloud API billing integration are not yet implemented
205
-
206
- ---
207
-
208
- ## Current baseline release positioning
209
-
210
- my-dev-kit-lab is at a working baseline. The raw-vs-indexed experiment pipeline is fully implemented and produces reproducible artifacts. Real-agent campaign support exists for Codex and Claude. The current published npm baseline is `v0.3.2`, which includes the generic audit framework, the code-rot detector family, the language-aware code-rot substrate with TypeScript/JavaScript and Python support, and a first security-validation audit adapter, on top of the earlier experiment and automated security-validation work.
211
-
212
- The release-prepared, not-yet-published `v0.3.3` implementation extends that baseline with Java/Kotlin analyzers, JVM metadata detection, Java/Kotlin detector support, and Java/Kotlin/Gradle/Maven docs-code-mismatch checks. This work is documented here as checked-out behavior, not as a published package state; package metadata is now `0.3.3`, while `v0.3.2` remains the previous published baseline until publication completes.
213
-
214
- Planned roadmap direction after the published baseline:
215
-
216
- - `v0.3.3`: Java/Kotlin code-rot support (release-prepared, not yet published)
217
- - `v0.3.4`: cross-language stability for the language-aware code-rot track
218
- - `v0.4.0` through `v0.4.2`: Android automated security validation, including an Android-specific extension of the security audit adapter
219
- - manual pentest: post-v1 / version TBD
220
-
221
- ---
222
-
223
- ## Security validation
224
-
225
- my-dev-kit-lab owns a release-security validation track for **my-dev-kit**. This work is separate from the experiment pipeline and does not replace the generic experiment-plugin roadmap. Its purpose is to generate release-validation evidence for the local CLI/package before release preparation.
226
-
227
- `security:validate` remains the standalone, focused command for this validation and is unaffected by the current checked-out state. `npm run audit -- --types security` additionally adapts the same `security:validate` internals into the shared audit/report surface (mapped issues, a `securitySummary` field, and links to the original `reports/security/` output) — it does not replace or duplicate `security:validate`'s own checks or reports.
228
-
229
- This is not a web application pentest framework. **my-dev-kit** is a local CLI/package, so the validation model is CLI/package adversarial testing focused on whether it remains:
230
-
231
- - local-first
232
- - deterministic
233
- - read-only with respect to user source files
234
- - network-free during normal CLI operation
235
- - LLM-free
236
- - database-free
237
- - safe to run on local repositories
238
-
239
- The automated validation gate is implemented. It combines static scans, dependency/package checks, adversarial CLI tests, bounded fuzz smoke tests, and attack-scenario checks with structured text/JSON reports and a four-category verdict.
240
-
241
- ### Security commands
242
-
243
- | Command | Description |
244
- |---|---|
245
- | `npm run security:deps` | npm audit, OSV-Scanner (if available), outdated packages |
246
- | `npm run security:package` | npm pack --dry-run, forbidden content detection |
247
- | `npm run security:codeql` | CodeQL CLI availability check; skipped gracefully when absent |
248
- | `npm run security:semgrep` | Semgrep scan via local binary or npx; skipped gracefully when both absent |
249
- | `npm run test:security` | Automated security and adversarial CLI tests (path traversal, read-only boundaries, malformed artifacts, JSON safety, and related checks) |
250
- | `npm run test:fuzz:smoke` | 9 bounded fuzz targets, seeded PRNG, completes in under 1 second |
251
- | `npm run security:validate` | Runs selected security checks, applies profile-aware defaults when requested, and writes text/JSON reports according to `--format` |
252
-
253
- CodeQL, Semgrep, and OSV-Scanner are optional. When unavailable locally, they are recorded as `skipped` in the report, not as passed. That can lead to `ready except optional manual checks`; it does not silently turn missing tooling into a clean pass.
254
-
255
- Each security command can validate my-dev-kit-lab itself or another local project via `--target <path>`. When `--target` is omitted, the framework performs self-validation. Target projects are inspected in place: their source files are not modified by default, generated artifacts stay under `reports/security/` unless `--out` is used, and external-target reports identify the tool root, target root, target package metadata, target git metadata, command cwd, exit code, and stdout/stderr summaries.
256
-
257
- `security:validate` supports `--checks`, `--profile`, `--format`, `--fail-on`, `--out`, and `--report-prefix`. The no-flag path remains backward compatible and still runs the classic implemented check groups: `deps`, `package`, `static`, `cli-adversarial`, and `fuzz`. Supplying `--profile` without `--checks` swaps in that profile's default checks; supplying explicit `--checks` always wins over profile defaults.
258
-
259
- The current attack-scenario checks cover boundary, subprocess, secrets, and network assumptions. They are automated adversarial checks, not a manual pentest. Manual pentest is deferred until after `v1.0.0`. `verdictImpact` metadata from each registered scenario drives blocker categorization in report reasoning, and narrowed `--checks` runs are labeled as scoped rather than described as a full release gate.
260
-
261
- JSON report poisoning/config-injection checks use a baseline-diff schema guard so legitimate additive JSON fields do not fail the guard while payload-created trusted top-level fields still do. Text reports are sanitized to strip ANSI/control-byte payloads before rendering.
262
-
263
- Known limits remain intentionally explicit: secret scanning is bounded rather than exhaustive, the network/local-first check is a bounded static assumption check rather than proof of runtime isolation, package-boundary severity is still result-level rather than per-evidence-item, and profile-specific scenario behavior is limited to profile-based scenario selection/default checks.
264
-
265
- For external-target validation, `security:validate` reads the target `package.json`, detects `scripts.test:security`, and runs `npm run test:security` in the target project root when that script exists. This behavior is validated both from the source checkout and from an installed packed tarball because published-package execution differs from local source execution.
266
-
267
- Generated security reports under `reports/security/` are excluded from git by default. They are produced locally or in CI as release-gate evidence and are not committed to the repository.
268
-
269
- See [docs/COMMANDS.md](docs/COMMANDS.md) for full command options and [docs/security-validation-framework.md](docs/security-validation-framework.md) for the security model, implemented modules, and release verdicts.
270
-
271
- ---
272
-
273
- ## License
274
-
275
- MIT License. See [LICENSE](LICENSE) for the full text.
276
-
277
- ---
278
-
279
- ## Support
280
-
281
- my-dev-kit-lab is an independent project by dailephd LLC, developed and maintained by Dai Le.
282
-
283
- If this project helps your workflow, you can support continued development through GitHub Sponsors or PayPal:
284
-
285
- - [Sponsor on GitHub](https://github.com/sponsors/dailephd)
286
- - [Support via PayPal](https://paypal.me/daile88)
287
-
288
- Support is optional and does not affect access to the project.
69
+ Use `npm run security:validate -- --help` for command usage. Help does not run validation or write reports.
289
70
 
290
- ---
71
+ ## Roadmap status
291
72
 
292
- ## Documentation
73
+ - `v0.4.0`: Android validation MVP — release-prepared; publication pending.
74
+ - `v0.4.1`: planned advanced Android security checks.
75
+ - `v0.4.2`: planned Android extension of the existing security audit adapter; it will not replace `security:validate`.
76
+ - Manual pentest: deferred post-v1 / version TBD; not part of v0.4.x.
293
77
 
294
- - [docs/PROJECT_OVERVIEW.md](docs/PROJECT_OVERVIEW.md) — product purpose and target users
295
- - [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) — current and future architecture
296
- - [docs/WORKFLOWS.md](docs/WORKFLOWS.md) — step-by-step workflows with diagrams
297
- - [docs/COMMANDS.md](docs/COMMANDS.md) — all commands with options and examples
298
- - [docs/TUTORIAL.md](docs/TUTORIAL.md) — first-run walkthrough
299
- - [docs/METRICS.md](docs/METRICS.md) — metric definitions and interpretation
300
- - [docs/ROADMAP.md](docs/ROADMAP.md) — current baseline and future phases
301
- - [docs/GALLERY.md](docs/GALLERY.md) — gallery output explained
78
+ See [docs/PROJECT_OVERVIEW.md](docs/PROJECT_OVERVIEW.md), [docs/COMMANDS.md](docs/COMMANDS.md), [docs/WORKFLOWS.md](docs/WORKFLOWS.md), [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md), and [docs/ROADMAP.md](docs/ROADMAP.md).
@@ -8,12 +8,36 @@ import { parseSecurityValidateArgs, normalizeSecurityValidateConfig, applyProfil
8
8
  import { resolveAttackProfile } from "../../src/securityValidation/attackScenarios/attackProfile.js";
9
9
  import { findingsBreachFailOnThreshold } from "../../src/securityValidation/validate/verdict.js";
10
10
  import { resolveToolRoot } from "./resolveToolRoot.js";
11
+ import { validateAndroidTarget } from "../../src/mobile/android/validate/validateAndroidTarget.js";
12
+ import { toAndroidReportModel } from "../../src/mobile/android/report/model.js";
13
+ import { renderAndroidTextReport } from "../../src/mobile/android/report/renderAndroidReport.js";
14
+ import { writeAndroidReportFiles } from "../../src/mobile/android/report/writeAndroidReportFiles.js";
11
15
  const USAGE = "Usage: npm run security:validate -- [--target <path>] [--out <dir>] [--report-prefix <name>] " +
12
16
  "[--checks deps,package,static,cli-adversarial,fuzz,boundary,subprocess,secrets,network] " +
13
- "[--profile node-cli-package|local-tool|npm-package] [--format text,json] [--fail-on blocker|high|medium|low]";
17
+ "[--profile node-cli-package|local-tool|npm-package|android] [--format text,json] [--fail-on blocker|high|medium|low] " +
18
+ "[--android-gradle-operations wrapper-version,tasks,assemble-debug,unit-test-debug,lint-debug]\n" +
19
+ "\n" +
20
+ "Android profile:\n" +
21
+ " --profile android performs static, read-only Android project detection, manifest parsing,\n" +
22
+ " permission/exported-component/intent-filter/deep-link audits, and static Gradle metadata\n" +
23
+ " extraction. Gradle is never executed by default.\n" +
24
+ " --android-gradle-operations explicitly opts into running ONLY the listed allowlisted Gradle\n" +
25
+ " operations (wrapper-version, tasks, assemble-debug, unit-test-debug, lint-debug) via the\n" +
26
+ " project's own Gradle wrapper. Arbitrary Gradle tasks cannot be passed. This option is only\n" +
27
+ " valid together with --profile android.\n" +
28
+ " Example: npm run security:validate -- --target \"<android-project-path>\" --profile android\n" +
29
+ " Example: npm run security:validate -- --target \"<android-project-path>\" --profile android --android-gradle-operations wrapper-version,tasks";
14
30
  // Parse CLI arguments from process.argv (after the node/tsx and script path).
15
31
  const rawArgs = process.argv.slice(2);
16
32
  const toolRoot = resolveToolRoot(import.meta.url);
33
+ // Help deliberately wins over every other argument. It must remain a
34
+ // no-work path: no target/default resolution, option normalization, report
35
+ // directory creation, validation orchestration, or subprocess execution.
36
+ if (rawArgs.includes("--help") || rawArgs.includes("-h")) {
37
+ console.log(USAGE);
38
+ process.exitCode = 0;
39
+ process.exit(0);
40
+ }
17
41
  let args;
18
42
  let config;
19
43
  try {
@@ -22,15 +46,18 @@ try {
22
46
  // v0.2.2 Batch 5: --profile with no --checks uses that profile's declared
23
47
  // default checks. No-op unless the user passed --profile without --checks
24
48
  // (see applyProfileDefaultChecksIfApplicable's guard) — the true no-flag
25
- // case and any explicit --checks case are always unaffected.
26
- config = applyProfileDefaultChecksIfApplicable(config, resolveAttackProfile(config.profile).defaultCheckIds);
49
+ // case and any explicit --checks case are always unaffected. Skipped for
50
+ // "android": that profile does not use the classic --checks pipeline.
51
+ if (config.profile !== "android") {
52
+ config = applyProfileDefaultChecksIfApplicable(config, resolveAttackProfile(config.profile).defaultCheckIds);
53
+ }
27
54
  }
28
55
  catch (err) {
29
56
  const msg = err instanceof Error ? err.message : String(err);
30
57
  console.error(`\nERROR: ${msg}`);
31
58
  console.error(USAGE);
32
- process.exitCode = 1;
33
- process.exit(1);
59
+ process.exitCode = 2;
60
+ process.exit(2);
34
61
  }
35
62
  // Resolve and validate target early so we can fail fast with a clean error.
36
63
  let target;
@@ -56,71 +83,151 @@ if (!target.isSelf) {
56
83
  else {
57
84
  console.log(`Mode : self-validation`);
58
85
  }
59
- if (!config.checksWereDefault) {
60
- console.log(`Checks : ${config.checks.join(", ")}`);
61
- }
62
- if (config.plannedChecksRequested.length > 0) {
63
- console.log(`Note : ${config.plannedChecksRequested.join(", ")} are routed through the attack-scenario framework rather than the classic check-group runners. Review the attack-scenario section in the report for their concrete results.`);
64
- }
65
- console.log("");
66
- const summary = await runSecurityValidation({
67
- cwd: toolRoot,
68
- targetPath: args.target,
69
- fuzzIterations: parseInt(process.env["FUZZ_ITERATIONS"] ?? "50", 10),
70
- fuzzSeed: parseInt(process.env["FUZZ_SEED"] ?? "0xDEADBEEF", 16),
71
- // Full selection (implemented + planned/attack-scenario ids) — the runner
72
- // gates both implemented check groups and attack-scenario checks off the
73
- // same selectedChecks set.
74
- selectedChecks: config.checks,
75
- profile: config.profile,
76
- });
77
- // v0.2.2 Batch 5: --fail-on breach is additive to (never a substitute for)
78
- // the existing verdict-based exit decision below — it can only escalate
79
- // exit 0 to exit 1 (e.g. --fail-on medium/low catching minor/informational
80
- // findings the verdict policy doesn't already treat as blocking), never
81
- // downgrade an existing blocker.
82
- const failOnBreached = findingsBreachFailOnThreshold(summary.findings, config.failOnThreshold);
83
- // Build report object
84
- const report = buildSecurityReportFromSummary(summary, {
85
- profile: config.profile,
86
- selectedChecks: config.checks,
87
- failOnThreshold: config.failOnThreshold,
88
- formats: config.formats,
89
- failOnBreached,
90
- });
91
- const textReport = renderTextReport(report);
92
- // Determine output directory
93
- const reportsDir = config.out;
94
- // Determine report filename prefix
95
- const prefix = args.reportPrefix ?? reportFilenamePrefix(target);
96
- const { textPath: txtPath, jsonPath, writtenPaths } = writeSecurityReportFiles({
97
- outDir: reportsDir,
98
- prefix,
99
- report,
100
- formats: config.formats,
101
- });
102
- // Print report to stdout
103
- console.log(textReport);
104
- console.log(`\nReports written:`);
105
- for (const p of writtenPaths) {
106
- console.log(` ${p}`);
107
- }
108
- // Exit code based on verdict, escalated (never downgraded) by --fail-on.
109
- const blockerExists = summary.verdict === "not-ready-security-blocker-remains";
110
- const inconclusive = summary.verdict === "inconclusive-audit-environment-incomplete";
111
- if (blockerExists) {
112
- console.error("\nExit 1 — security blocker remains.");
113
- process.exitCode = 1;
114
- }
115
- else if (inconclusive) {
116
- console.warn("\nExit 2 — audit environment incomplete.");
117
- process.exitCode = 2;
118
- }
119
- else if (failOnBreached) {
120
- console.error(`\nExit 1 — --fail-on ${config.failOnThreshold} threshold breached.`);
121
- process.exitCode = 1;
86
+ console.log(`Profile : ${config.profile}`);
87
+ // ---------------------------------------------------------------------------
88
+ // v0.4.0 Batch 5 — Android profile path.
89
+ //
90
+ // A separate orchestrator (not the classic check-group/attack-scenario
91
+ // pipeline below) because the Android check/finding/status vocabulary
92
+ // established in Batches 1-4 does not fit SecurityCheckId/SecurityCheckResult.
93
+ // Same command, same --profile flag, same reports/security/ output root.
94
+ // ---------------------------------------------------------------------------
95
+ if (config.profile === "android") {
96
+ if (config.androidGradleOperationIds.length > 0) {
97
+ console.log(`Gradle ops : ${config.androidGradleOperationIds.join(", ")} (explicitly requested — will execute via the target's Gradle wrapper)`);
98
+ }
99
+ else {
100
+ console.log(`Gradle ops : (none requested — static-only validation, zero Gradle process execution)`);
101
+ }
102
+ console.log("");
103
+ let result;
104
+ try {
105
+ result = await validateAndroidTarget({
106
+ toolRoot,
107
+ targetPath: args.target,
108
+ requestedGradleOperationIds: config.androidGradleOperationIds,
109
+ });
110
+ }
111
+ catch (err) {
112
+ const msg = err instanceof Error ? err.message : String(err);
113
+ console.error(`\nERROR: Android validation failed to run: ${msg}`);
114
+ process.exitCode = 3;
115
+ process.exit(3);
116
+ }
117
+ const reportModel = toAndroidReportModel(result, {
118
+ profile: config.profile,
119
+ requestedGradleOperations: config.androidGradleOperationIds,
120
+ });
121
+ const textReport = renderAndroidTextReport(reportModel);
122
+ const reportsDir = config.out;
123
+ const prefix = args.reportPrefix ??
124
+ reportFilenamePrefix({
125
+ isSelf: result.target.local.isSelf,
126
+ packageName: result.target.local.packageName,
127
+ packageVersion: result.target.local.packageVersion,
128
+ targetRoot: result.target.local.targetRoot,
129
+ });
130
+ let writtenPaths;
131
+ try {
132
+ ({ writtenPaths } = writeAndroidReportFiles({ outDir: reportsDir, prefix, report: reportModel, formats: config.formats }));
133
+ }
134
+ catch (err) {
135
+ const msg = err instanceof Error ? err.message : String(err);
136
+ console.error(`\nERROR: Failed to write Android report files: ${msg}`);
137
+ console.error("Validation completed but the report could not be written. The in-memory result was not persisted.");
138
+ process.exitCode = 4;
139
+ process.exit(4);
140
+ }
141
+ console.log(textReport);
142
+ console.log(`\nReports written:`);
143
+ for (const p of writtenPaths) {
144
+ console.log(` ${p}`);
145
+ }
146
+ const blockerExists = result.verdict === "not-ready-security-blocker-remains";
147
+ const inconclusive = result.verdict === "inconclusive-audit-environment-incomplete";
148
+ if (blockerExists) {
149
+ console.error("\nExit 1 — security blocker remains.");
150
+ process.exitCode = 1;
151
+ }
152
+ else if (inconclusive) {
153
+ console.warn("\nExit 2 — android environment incomplete.");
154
+ process.exitCode = 2;
155
+ }
156
+ else {
157
+ console.log("\nExit 0 — validation completed.");
158
+ process.exitCode = 0;
159
+ }
122
160
  }
123
161
  else {
124
- console.log("\nExit 0 — validation completed.");
125
- process.exitCode = 0;
162
+ // ---------------------------------------------------------------------------
163
+ // Classic check-group/attack-scenario pipeline (unchanged from prior versions).
164
+ // ---------------------------------------------------------------------------
165
+ if (!config.checksWereDefault) {
166
+ console.log(`Checks : ${config.checks.join(", ")}`);
167
+ }
168
+ if (config.plannedChecksRequested.length > 0) {
169
+ console.log(`Note : ${config.plannedChecksRequested.join(", ")} are routed through the attack-scenario framework rather than the classic check-group runners. Review the attack-scenario section in the report for their concrete results.`);
170
+ }
171
+ console.log("");
172
+ const summary = await runSecurityValidation({
173
+ cwd: toolRoot,
174
+ targetPath: args.target,
175
+ fuzzIterations: parseInt(process.env["FUZZ_ITERATIONS"] ?? "50", 10),
176
+ fuzzSeed: parseInt(process.env["FUZZ_SEED"] ?? "0xDEADBEEF", 16),
177
+ // Full selection (implemented + planned/attack-scenario ids) — the runner
178
+ // gates both implemented check groups and attack-scenario checks off the
179
+ // same selectedChecks set.
180
+ selectedChecks: config.checks,
181
+ profile: config.profile,
182
+ });
183
+ // v0.2.2 Batch 5: --fail-on breach is additive to (never a substitute for)
184
+ // the existing verdict-based exit decision below — it can only escalate
185
+ // exit 0 to exit 1 (e.g. --fail-on medium/low catching minor/informational
186
+ // findings the verdict policy doesn't already treat as blocking), never
187
+ // downgrade an existing blocker.
188
+ const failOnBreached = findingsBreachFailOnThreshold(summary.findings, config.failOnThreshold);
189
+ // Build report object
190
+ const report = buildSecurityReportFromSummary(summary, {
191
+ profile: config.profile,
192
+ selectedChecks: config.checks,
193
+ failOnThreshold: config.failOnThreshold,
194
+ formats: config.formats,
195
+ failOnBreached,
196
+ });
197
+ const textReport = renderTextReport(report);
198
+ // Determine output directory
199
+ const reportsDir = config.out;
200
+ // Determine report filename prefix
201
+ const prefix = args.reportPrefix ?? reportFilenamePrefix(target);
202
+ const { writtenPaths } = writeSecurityReportFiles({
203
+ outDir: reportsDir,
204
+ prefix,
205
+ report,
206
+ formats: config.formats,
207
+ });
208
+ // Print report to stdout
209
+ console.log(textReport);
210
+ console.log(`\nReports written:`);
211
+ for (const p of writtenPaths) {
212
+ console.log(` ${p}`);
213
+ }
214
+ // Exit code based on verdict, escalated (never downgraded) by --fail-on.
215
+ const blockerExists = summary.verdict === "not-ready-security-blocker-remains";
216
+ const inconclusive = summary.verdict === "inconclusive-audit-environment-incomplete";
217
+ if (blockerExists) {
218
+ console.error("\nExit 1 — security blocker remains.");
219
+ process.exitCode = 1;
220
+ }
221
+ else if (inconclusive) {
222
+ console.warn("\nExit 2 — audit environment incomplete.");
223
+ process.exitCode = 2;
224
+ }
225
+ else if (failOnBreached) {
226
+ console.error(`\nExit 1 — --fail-on ${config.failOnThreshold} threshold breached.`);
227
+ process.exitCode = 1;
228
+ }
229
+ else {
230
+ console.log("\nExit 0 — validation completed.");
231
+ process.exitCode = 0;
232
+ }
126
233
  }