corgea-cli 1.9.3__tar.gz → 1.11.0__tar.gz

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 (187) hide show
  1. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/.github/workflows/test.yml +3 -1
  2. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/Cargo.lock +1 -1
  3. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/Cargo.toml +3 -3
  4. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/PKG-INFO +1 -1
  5. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/README.md +58 -0
  6. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/skills/corgea/SKILL.md +47 -3
  7. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/config.rs +8 -0
  8. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/ecosystems/maven.rs +180 -2
  9. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/ecosystems/mod.rs +10 -0
  10. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/mod.rs +7 -0
  11. corgea_cli-1.11.0/src/deps/report.rs +261 -0
  12. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/run.rs +3 -6
  13. corgea_cli-1.11.0/src/deps/tests/maven_tests.rs +338 -0
  14. corgea_cli-1.11.0/src/deps/tests/report_tests.rs +218 -0
  15. corgea_cli-1.11.0/src/images.rs +513 -0
  16. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/inspect.rs +1 -1
  17. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/list.rs +126 -48
  18. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/main.rs +261 -23
  19. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/mod.rs +34 -12
  20. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/test_support.rs +2 -2
  21. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/verdict.rs +1 -1
  22. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/scan.rs +63 -32
  23. corgea_cli-1.11.0/src/scanners/blast.rs +1962 -0
  24. corgea_cli-1.11.0/src/skip_scan.rs +690 -0
  25. corgea_cli-1.11.0/src/utils/api.rs +2370 -0
  26. corgea_cli-1.11.0/src/utils/generic.rs +1000 -0
  27. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/vuln_api_stub/mod.rs +135 -8
  28. corgea_cli-1.11.0/src/wait.rs +180 -0
  29. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_deps.rs +99 -0
  30. corgea_cli-1.11.0/tests/cli_scan_include_image.rs +310 -0
  31. corgea_cli-1.11.0/tests/cli_scan_sbom.rs +219 -0
  32. corgea_cli-1.11.0/tests/cli_scan_wait_terminal_state.rs +302 -0
  33. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_verdict.rs +51 -0
  34. corgea_cli-1.11.0/tests/cloud_commands_e2e/block_on_report.rs +204 -0
  35. corgea_cli-1.11.0/tests/cloud_commands_e2e/common/mod.rs +852 -0
  36. corgea_cli-1.11.0/tests/cloud_commands_e2e/inspect.rs +140 -0
  37. corgea_cli-1.11.0/tests/cloud_commands_e2e/main.rs +9 -0
  38. corgea_cli-1.11.0/tests/cloud_commands_e2e/scan_list.rs +243 -0
  39. corgea_cli-1.11.0/tests/cloud_commands_e2e/scan_skip.rs +565 -0
  40. corgea_cli-1.11.0/tests/cloud_commands_e2e/upload_wait.rs +152 -0
  41. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/common/mod.rs +198 -1
  42. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/README.md +1 -0
  43. corgea_cli-1.11.0/tests/fixtures/java-maven-alias/pom.xml +19 -0
  44. corgea_cli-1.11.0/tests/fixtures/java-maven-chained/pom.xml +20 -0
  45. corgea_cli-1.11.0/tests/fixtures/java-maven-deep-chain/pom.xml +25 -0
  46. corgea_cli-1.11.0/tests/fixtures/java-maven-managed/pom.xml +29 -0
  47. corgea_cli-1.11.0/tests/fixtures/java-maven-parent/pom.xml +29 -0
  48. corgea_cli-1.11.0/tests/fixtures/java-maven-plugin-deps/pom.xml +62 -0
  49. corgea_cli-1.11.0/tests/fixtures/java-maven-profile-mgmt/pom.xml +37 -0
  50. corgea_cli-1.11.0/tests/fixtures/java-maven-props/pom.xml +27 -0
  51. corgea_cli-1.11.0/tests/fixtures/java-maven-revision/pom.xml +19 -0
  52. corgea_cli-1.11.0/tests/fixtures/mixed-monorepo/services/api/requirements.txt +2 -0
  53. corgea_cli-1.11.0/tests/fixtures/mixed-monorepo/services/web/package-lock.json +29 -0
  54. corgea_cli-1.11.0/tests/fixtures/mixed-monorepo/services/web/package.json +10 -0
  55. corgea_cli-1.11.0/tests/list_code_quality.rs +209 -0
  56. corgea_cli-1.11.0/tests/list_resolution.rs +374 -0
  57. corgea_cli-1.11.0/tests/wait_resolution.rs +358 -0
  58. corgea_cli-1.9.3/.github/workflows/sync-skills.yml +0 -166
  59. corgea_cli-1.9.3/.github/workflows/update_docs..yml +0 -27
  60. corgea_cli-1.9.3/src/deps/report.rs +0 -172
  61. corgea_cli-1.9.3/src/deps/tests/maven_tests.rs +0 -129
  62. corgea_cli-1.9.3/src/deps/tests/report_tests.rs +0 -81
  63. corgea_cli-1.9.3/src/scanners/blast.rs +0 -850
  64. corgea_cli-1.9.3/src/utils/api.rs +0 -1342
  65. corgea_cli-1.9.3/src/utils/generic.rs +0 -453
  66. corgea_cli-1.9.3/src/wait.rs +0 -102
  67. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/.codex/hooks.json +0 -0
  68. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/.github/workflows/npm-publish.yml +0 -0
  69. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/.github/workflows/release-binaries.yml +0 -0
  70. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/.github/workflows/release.yml +0 -0
  71. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/.github/workflows/staging-contract.yml +0 -0
  72. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/.gitignore +0 -0
  73. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/AGENTS.md +0 -0
  74. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/LICENSE +0 -0
  75. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/RELEASING.md +0 -0
  76. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/bin/corgea.js +0 -0
  77. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/build_release.sh +0 -0
  78. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/examples/deps_skill.rs +0 -0
  79. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/harness +0 -0
  80. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/package.json +0 -0
  81. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/pyproject.toml +0 -0
  82. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/scripts/check-linux-binary.sh +0 -0
  83. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/scripts/npm/bundle-binaries.js +0 -0
  84. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/advisories.rs +0 -0
  85. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/authorize.rs +0 -0
  86. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/cicd.rs +0 -0
  87. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/catalog.rs +0 -0
  88. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/detect.rs +0 -0
  89. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/diff.rs +0 -0
  90. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/ecosystems/evaluate.rs +0 -0
  91. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/ecosystems/npm.rs +0 -0
  92. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/ecosystems/pypi.rs +0 -0
  93. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/explain.rs +0 -0
  94. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/findings.rs +0 -0
  95. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/model.rs +0 -0
  96. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/parse/mod.rs +0 -0
  97. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/parse/npm_lock.rs +0 -0
  98. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/parse/python_lock.rs +0 -0
  99. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/policy.rs +0 -0
  100. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/skill.rs +0 -0
  101. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/common.rs +0 -0
  102. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/correctness_tests.rs +0 -0
  103. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/detect_tests.rs +0 -0
  104. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/diff_tests.rs +0 -0
  105. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/explain_tests.rs +0 -0
  106. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/findings_tests.rs +0 -0
  107. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/mod.rs +0 -0
  108. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/npm_tests.rs +0 -0
  109. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/policy_tests.rs +0 -0
  110. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/pypi_tests.rs +0 -0
  111. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/robustness_tests.rs +0 -0
  112. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/slice0_tests.rs +0 -0
  113. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/lib.rs +0 -0
  114. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/log.rs +0 -0
  115. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/detect.rs +0 -0
  116. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/exec.rs +0 -0
  117. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/parse.rs +0 -0
  118. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/render.rs +0 -0
  119. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/tree.rs +0 -0
  120. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/uv.rs +0 -0
  121. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/scanners/fortify.rs +0 -0
  122. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/scanners/parsers/checkmarx.rs +0 -0
  123. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/scanners/parsers/coverity.rs +0 -0
  124. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/scanners/parsers/mod.rs +0 -0
  125. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/scanners/parsers/sarif.rs +0 -0
  126. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/scanners/parsers/semgrep.rs +0 -0
  127. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/setup_hooks.rs +0 -0
  128. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/skill.rs +0 -0
  129. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/targets.rs +0 -0
  130. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/utils/terminal.rs +0 -0
  131. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/verify_deps/mod.rs +0 -0
  132. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/verify_deps/registry.rs +0 -0
  133. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/vuln_api/mod.rs +0 -0
  134. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_advisories.rs +0 -0
  135. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_bare_install.rs +0 -0
  136. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_deps_skill.rs +0 -0
  137. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_exec_fallback.rs +0 -0
  138. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_install.rs +0 -0
  139. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_npm_ci.rs +0 -0
  140. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_provenance.rs +0 -0
  141. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_remediation.rs +0 -0
  142. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_tree.rs +0 -0
  143. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_uv_sync.rs +0 -0
  144. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/go-mod-smoke/go.mod +0 -0
  145. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/go-mod-smoke/go.sum +0 -0
  146. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/java-gradle/build.gradle +0 -0
  147. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/java-gradle/gradle.lockfile +0 -0
  148. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/java-maven/pom.xml +0 -0
  149. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/malformed/not-xml-pom.xml +0 -0
  150. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/malformed/package-lock.json +0 -0
  151. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/malformed/package.json +0 -0
  152. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/malformed/poetry.lock +0 -0
  153. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/malformed/pyproject.toml +0 -0
  154. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/malformed/truncated-poetry.lock +0 -0
  155. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-app/.corgea/deps.yml +0 -0
  156. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-app/package-lock.json +0 -0
  157. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-app/package.json +0 -0
  158. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-monorepo/package-lock.json +0 -0
  159. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-monorepo/package.json +0 -0
  160. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-monorepo/packages/a/package.json +0 -0
  161. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-monorepo/packages/b/package.json +0 -0
  162. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-pnpm/package.json +0 -0
  163. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-pnpm/pnpm-lock.yaml +0 -0
  164. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-stale/package-lock.json +0 -0
  165. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-stale/package.json +0 -0
  166. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-transitive/package-lock.json +0 -0
  167. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-transitive/package.json +0 -0
  168. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-yarn/package.json +0 -0
  169. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-yarn/yarn.lock +0 -0
  170. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-pip-nolock/requirements.txt +0 -0
  171. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-poetry/poetry.lock +0 -0
  172. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-poetry/pyproject.toml +0 -0
  173. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-poetry-multi/poetry.lock +0 -0
  174. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-poetry-multi/pyproject.toml +0 -0
  175. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-uv-requirements/pyproject.toml +0 -0
  176. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-uv-requirements/requirements.txt +0 -0
  177. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-uv-requirements/uv.lock +0 -0
  178. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/vuln_api/README.md +0 -0
  179. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/vuln_api/check_clean.json +0 -0
  180. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/vuln_api/check_malware.json +0 -0
  181. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/vuln_api/check_unknown.json +0 -0
  182. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/vuln_api/check_vulnerable.json +0 -0
  183. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/vuln_api/package_profile.json +0 -0
  184. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/vuln_api/package_profile_not_found.json +0 -0
  185. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/harness_smoke.rs +0 -0
  186. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/logging_e2e.rs +0 -0
  187. {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/vuln_api_contract.rs +0 -0
@@ -4,9 +4,11 @@ on:
4
4
  push:
5
5
  branches:
6
6
  - main
7
- - master
8
7
  pull_request:
9
8
 
9
+ permissions:
10
+ contents: read
11
+
10
12
  jobs:
11
13
  rust-tests:
12
14
  runs-on: ubuntu-latest
@@ -369,7 +369,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
369
369
 
370
370
  [[package]]
371
371
  name = "corgea"
372
- version = "1.9.3"
372
+ version = "1.11.0"
373
373
  dependencies = [
374
374
  "chrono",
375
375
  "clap",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "corgea"
3
- version = "1.9.3"
3
+ version = "1.11.0"
4
4
  edition = "2021"
5
5
  readme = "README.md"
6
6
 
@@ -17,7 +17,7 @@ test-stub = []
17
17
 
18
18
  [dev-dependencies]
19
19
  corgea = { path = ".", features = ["test-stub"] }
20
- tempfile = "3.12.0"
20
+ tempfile = "3.20.0"
21
21
 
22
22
  [dependencies]
23
23
  clap = { version = "4.4.13", features = ["derive"] }
@@ -41,7 +41,7 @@ serde_derive = "1.0.195"
41
41
  uuid = { version = "1.7.0", features = ["v4"] }
42
42
  which = "6.0.0"
43
43
  zip = "2.3.0"
44
- tempfile = "3.12.0"
44
+ tempfile = "3.20.0"
45
45
  quick-xml = "0.41"
46
46
  ignore = "0.4"
47
47
  globset = "0.4"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: corgea-cli
3
- Version: 1.9.3
3
+ Version: 1.11.0
4
4
  Classifier: Development Status :: 5 - Production/Stable
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -31,6 +31,64 @@ Once the binary is installed, login with your token from the Corgea app.
31
31
  corgea login <token>
32
32
  ```
33
33
 
34
+ ## Scanning
35
+
36
+ `corgea scan` uploads your project and waits for results. `corgea wait [scan_id]`
37
+ attaches to a running scan; `corgea upload <report> --wait` does the same for a
38
+ third-party report.
39
+
40
+ All three exit 1 if the scan fails, printing the reason and the scanners that hit
41
+ problems. A scan that completes with a scanner missing exits 0 with a warning.
42
+ Waiting gives up after 10 hours; override with `CORGEA_SCAN_TIMEOUT_SECONDS`.
43
+ `--fail`/`--block-on` then wait up to 15 minutes for blocking rules to be
44
+ evaluated; override with `CORGEA_BLOCKING_RULES_TIMEOUT_SECONDS`.
45
+
46
+ `--out-format`/`--out-file` and `--sbom` are honored whether or not a gate
47
+ trips: both are written before `--fail`/`--block-on` are evaluated, so a scan
48
+ that exits 1 on a blocking rule still leaves its report behind to ingest.
49
+
50
+ ### Skipping a re-scan of the same commit
51
+
52
+ A pipeline that re-runs on an unchanged commit can reuse the scan it already
53
+ has instead of paying for a duplicate:
54
+
55
+ ```bash
56
+ corgea scan --skip-if-commit-scanned-recently --block-on criticals
57
+ corgea scan --skip-if-commit-scanned-recently --scanned-within 4h # 90s, 30m, 4h, 7d
58
+ ```
59
+
60
+ When the project already has a completed scan of the current commit inside the
61
+ window (24h by default), that scan takes the new scan's place: the results
62
+ table, the `--block-on` gate and its exit code, and any `--out-file` report all
63
+ come from it, so the pipeline behaves the same whether or not a scan ran. The
64
+ window exists because unchanged code is still exposed to advisories published
65
+ since it was last scanned.
66
+
67
+ Two lines make the outcome scriptable — `CORGEA_SCAN_SKIPPED=true` plus
68
+ `CORGEA_SCAN_ID=<id>` when a scan was reused, `CORGEA_SCAN_SKIPPED=false` when
69
+ one ran — so a later step (an ingest, say) can branch on it.
70
+
71
+ Only a scan that answers the same question is reused, which is stricter than
72
+ "same commit". A candidate has to be a completed BLAST scan of that commit, on a
73
+ branch rather than a pull request, from an explicitly clean worktree, with no
74
+ scanner problems reported — and this run has to be a default whole-commit scan
75
+ itself. Anything else runs a real scan: nothing inside the window, only a failed
76
+ or still-running scan, a worktree that does not match the commit (including
77
+ files the index hides from `git status`), or a lookup the platform could not
78
+ answer.
79
+
80
+ Two things are hard errors instead. An unresolvable commit (not a git
81
+ repository, or no commits yet) exits 1 rather than silently scanning. And a run
82
+ that changes what gets scanned cannot be matched against a candidate — the API
83
+ exposes neither a scan's configured scan types and target policies nor whether
84
+ it bundled a container image — so the flag is rejected alongside `--scan-type`,
85
+ `--policy`, `--include-image`, `--only-uncommitted`, and `--target`.
86
+
87
+ `--exclude` is allowed, and warns on a skip. A reused scan is one of the whole
88
+ commit (an `--exclude` upload is recorded as not matching the commit exactly, so
89
+ it is never itself reusable), which means the results and the gate can cover
90
+ files this run would have skipped — over-reporting, never under-reporting.
91
+
34
92
  ## Dependency Inventory (offline)
35
93
 
36
94
  `corgea deps` builds a dependency inventory from npm, Python, and Java manifests
@@ -35,16 +35,38 @@ corgea scan --scan-type policy --policy 1 # Specific policy ID
35
35
  corgea scan --fail-on CR # Exit 1 on critical issues (CR, HI, ME, LO)
36
36
  corgea scan --fail-on malicious # Exit 1 if any dependency is classified malicious
37
37
  corgea scan --fail-on HI,malicious # Comma-separated conditions combine
38
- corgea scan --fail # Exit 1 based on project blocking rules
38
+ corgea scan --block-on criticals # Exit 1 if the scan violates the named CI blocking rules
39
+ corgea scan --block-on criticals,malicious-deps # Comma-separated rule slugs
40
+ corgea scan --fail # Deprecated: exit 1 based on every active blocking rule
39
41
  corgea scan --out-format json --out-file r.json # Export (json, html, sarif, markdown)
42
+ corgea scan --sbom # Also write a CycloneDX SBOM to bom.json
43
+ corgea scan --sbom sbom.cdx.json # SBOM to a custom file
44
+ corgea scan --include-image myapp:1.2.3 # Also scan a fully built container image
45
+ corgea scan --include-image myapp:1.2.3 --include-image ghcr.io/acme/api:latest # Repeatable
40
46
  corgea scan --project-name my-service # Override project name
47
+ corgea scan --skip-if-commit-scanned-recently # Reuse a recent scan of this commit instead of scanning again
48
+ corgea scan --skip-if-commit-scanned-recently --scanned-within 4h # Window for "recently" (default 24h)
41
49
  ```
42
50
 
43
51
  Scan types: `blast` (base AI), `policy` (PolicyIQ), `malicious`, `secrets`, `pii`.
44
52
 
45
53
  `--fail-on` takes comma-separated conditions: severity thresholds `CR`, `HI`, `ME`, `LO` (trip at or above the level) and/or `malicious` (trips when any dependency in the scan is classified malicious). Use `malicious` to block supply-chain findings in CI across every ecosystem the scan covers, including those the `corgea npm`/`corgea pip` install gate does not.
46
54
 
47
- `--only-uncommitted` and `--target` are mutually exclusive. `--fail-on` and `--fail` are mutually exclusive.
55
+ `--block-on` takes comma-separated blocking-rule slugs. Blocking rules are configured in the web app and each one applies either to pull requests or to CI. Only CI rules can be named by `--block-on`; a slug that is unknown, inactive, or scoped to pull requests is a hard error (exit 1) rather than a silently skipped gate. The slug is shown next to each rule in the web app and is derived from the rule name, so renaming a rule changes its slug. Name rules for the condition that trips them — `criticals`, not `no-criticals` — so that `--block-on` reads as a direct assertion rather than a double negative.
56
+
57
+ `--fail` is deprecated. It evaluates every active blocking rule regardless of what it applies to; use `--block-on` to name the CI rules a pipeline should enforce.
58
+
59
+ `--include-image` scans the image you actually ship. Without it, container scanning discovers the base images referenced by Dockerfiles and Compose files in the repo and scans those. With it, each image is exported to a tar archive with `docker save` (or `podman save`), bundled with the project, and scanned as a whole — base-image discovery is skipped for that scan. Images that aren't available locally are pulled first, so build (or pull) the image before the scan and stay logged in to its registry. Set `CORGEA_CONTAINER_ENGINE` to choose a specific container CLI. Container scanning must be enabled for your account.
60
+
61
+ An included image is enough on its own: when it is combined with `--only-uncommitted` or `--target` and no source files match (a clean working tree, for example), the scan warns and covers just the image rather than failing. An archive named `corgea-image-scanning-*.tar` that is committed to the repository is ignored — only images passed on the command line are scanned.
62
+
63
+ `--only-uncommitted` and `--target` are mutually exclusive. `--fail-on`, `--fail`, and `--block-on` are mutually exclusive.
64
+
65
+ `--out-format`/`--out-file` and `--sbom` are honored regardless of the gate: the report and the SBOM are written before `--fail`/`--block-on` are evaluated, so a scan that exits 1 on a blocking rule still leaves the report file behind for the pipeline to ingest.
66
+
67
+ `--skip-if-commit-scanned-recently` reuses the project's most recent reusable scan of the current commit instead of starting a duplicate, when one ran inside the `--scanned-within` window (default `24h`; accepts `90s`, `30m`, `4h`, `7d`, and a bare number as hours). The reused scan takes the new scan's place for the rest of the command — results table, `--block-on` gate and its exit code, `--out-file` report — so the pipeline behaves the same either way. It prints `CORGEA_SCAN_SKIPPED=true` plus `CORGEA_SCAN_ID=<id>` on a reuse and `CORGEA_SCAN_SKIPPED=false` when a scan runs, so a later step can branch on it.
68
+
69
+ Reuse requires a candidate that answers the same question: a completed `corgea-blast` scan of that commit, on a branch rather than a pull request, from an explicitly clean worktree, reporting no scanner problems. Anything else runs a real scan (nothing in the window, a failed or still-running scan, a worktree that does not match the commit including files hidden from `git status`, or a failed lookup). An unresolvable commit is a hard error (exit 1). Because the API exposes neither a scan's configured scan types and target policies nor whether it bundled a container image, a run that changes what gets scanned cannot be matched against a candidate, so the flag cannot be combined with `--scan-type`, `--policy`, `--include-image`, `--only-uncommitted`, or `--target`. `--exclude` is allowed but warns on a skip: what gets reused is a scan of the whole commit, so the results and the gate can cover files the run would have skipped (over-reporting, never under-reporting).
48
70
 
49
71
  ### Upload — `corgea upload [report]`
50
72
 
@@ -66,15 +88,23 @@ By default `upload` prints the scan page URL so you can track the results. Pass
66
88
 
67
89
  ```bash
68
90
  corgea wait # Wait for latest scan
69
- corgea wait --scan-id SCAN_ID # Wait for specific scan
91
+ corgea wait SCAN_ID # Wait for a specific scan
70
92
  ```
71
93
 
94
+ Waiting (`corgea scan`, `corgea wait`, `corgea upload --wait`) exits 1 if the
95
+ scan fails, printing why. A scan missing one scanner's results exits 0 with a
96
+ warning. Polling gives up after 10 hours; override with
97
+ `CORGEA_SCAN_TIMEOUT_SECONDS`. `--fail`/`--block-on` then wait up to 15 minutes
98
+ for blocking rules to be evaluated, and exit 1 if that runs out; override with
99
+ `CORGEA_BLOCKING_RULES_TIMEOUT_SECONDS`.
100
+
72
101
  ### List — `corgea list` (alias: `corgea ls`)
73
102
 
74
103
  ```bash
75
104
  corgea ls # List scans
76
105
  corgea ls --issues --scan-id SCAN_ID # Issues for a scan
77
106
  corgea ls --sca-issues # SCA (dependency) issues
107
+ corgea ls --code-quality # Code quality issues
78
108
  corgea ls --issues --page 2 --page-size 10 # Pagination
79
109
  corgea ls --issues --scan-id SCAN_ID --json # JSON output
80
110
  ```
@@ -83,6 +113,7 @@ corgea ls --issues --scan-id SCAN_ID --json # JSON output
83
113
  |------|-------|-------------|
84
114
  | `--issues` | `-i` | List code/SAST issues |
85
115
  | `--sca-issues` | `-c` | List SCA issues |
116
+ | `--code-quality` | `-q` | List code quality issues (alias `--quality`) |
86
117
  | `--scan-id` | `-s` | Filter to a scan |
87
118
  | `--page` | `-p` | Page number |
88
119
  | `--page-size` | | Items per page |
@@ -336,6 +367,13 @@ corgea scan
336
367
  corgea scan --only-uncommitted --fail-on HI
337
368
  ```
338
369
 
370
+ ### Scan the container image a build produced
371
+
372
+ ```bash
373
+ docker build -t myapp:1.2.3 .
374
+ corgea scan --include-image myapp:1.2.3
375
+ ```
376
+
339
377
  ### Scan a PR diff
340
378
 
341
379
  ```bash
@@ -354,8 +392,13 @@ corgea inspect --issue --diff ISSUE_ID
354
392
  ```bash
355
393
  corgea scan --fail-on CR --out-format sarif --out-file results.sarif
356
394
  corgea scan --fail-on CR,malicious --out-format sarif --out-file results.sarif # also block malicious dependencies
395
+ corgea scan --block-on criticals --out-format sarif --out-file results.sarif # gate on a CI blocking rule from the web app
396
+ corgea scan --block-on criticals --skip-if-commit-scanned-recently # re-runs of an already-scanned commit gate on that scan instead of rescanning
357
397
  ```
358
398
 
399
+ The report is written whether or not the gate trips, so a pipeline can both fail
400
+ on policy and ingest the results file.
401
+
359
402
  ### Upload third-party reports
360
403
 
361
404
  ```bash
@@ -367,6 +410,7 @@ corgea upload report.json --project-name my-app
367
410
  ```bash
368
411
  corgea scan --out-format html --out-file report.html
369
412
  corgea scan --out-format sarif --out-file report.sarif
413
+ corgea scan --out-format sarif --out-file report.sarif --sbom bom.json # SARIF + CycloneDX SBOM
370
414
  ```
371
415
 
372
416
  ## Severity Levels
@@ -4,6 +4,14 @@ use std::{env, fs, io};
4
4
 
5
5
  pub const DEFAULT_VULN_API_URL: &str = "https://cve-worker-staging.corgea.workers.dev";
6
6
 
7
+ /// Whether `DEFAULT_VULN_API_URL` is an endpoint Corgea tokens belong to.
8
+ /// The `-staging` hostname is historical: this worker serves as the production
9
+ /// vuln-api, so a token may be sent to it and authenticated (fail-closed)
10
+ /// verdicts apply by default. Set to `false` if the default is ever repointed
11
+ /// at an endpoint that customer tokens should not reach — token-send and
12
+ /// fail-closed then both require the explicit opt-in.
13
+ pub const DEFAULT_VULN_API_URL_IS_PRODUCTION: bool = true;
14
+
7
15
  #[derive(Serialize, Deserialize, Clone)]
8
16
  pub struct Config {
9
17
  pub(crate) url: String,
@@ -5,7 +5,7 @@ use crate::deps::ecosystems::classify_constraint;
5
5
  use crate::deps::ecosystems::evaluate::{
6
6
  constraint_to_findings, dep001, file_in_dir, parent_dir, ScanContext,
7
7
  };
8
- use crate::deps::model::{DependencyNode, Ecosystem, PackageId, Scope, SourceType};
8
+ use crate::deps::model::{DependencyEdge, DependencyNode, Ecosystem, PackageId, Scope, SourceType};
9
9
  use crate::deps::DepsError;
10
10
 
11
11
  pub fn scan_maven_projects(ctx: &mut ScanContext<'_>) -> Result<(), DepsError> {
@@ -68,6 +68,14 @@ fn scan_maven_pom(ctx: &mut ScanContext<'_>, dir: &Path, pom_path: &Path) -> Res
68
68
  Some(package_id.clone()),
69
69
  false,
70
70
  ));
71
+ ctx.graph.edges.push(DependencyEdge {
72
+ from: PackageId::root(),
73
+ to: package_id.clone(),
74
+ declared_constraint: declared.clone(),
75
+ resolved_version: Some(dep.version.clone()),
76
+ scope: dep.scope,
77
+ source_file: rel.clone(),
78
+ });
71
79
  ctx.graph.nodes.push(DependencyNode {
72
80
  id: package_id,
73
81
  name,
@@ -89,8 +97,178 @@ fn scan_maven_pom(ctx: &mut ScanContext<'_>, dir: &Path, pom_path: &Path) -> Res
89
97
  Ok(())
90
98
  }
91
99
 
100
+ /// Sections whose contents are not the project's own coordinates or
101
+ /// dependencies; stripped before any dependency or property extraction.
102
+ const NON_DEPENDENCY_SECTIONS: &[&str] = &["profiles", "build", "reporting"];
103
+
92
104
  fn parse_pom_dependencies(content: &str) -> Result<Vec<MavenDep>, DepsError> {
93
- Ok(parse_pom_regex(content))
105
+ let stripped = strip_sections(content, NON_DEPENDENCY_SECTIONS);
106
+ let props = parse_pom_properties(&stripped);
107
+ let (rest, management) = split_dependency_management(&stripped);
108
+ let managed: std::collections::HashMap<(String, String), String> = parse_pom_regex(management)
109
+ .into_iter()
110
+ .filter(|d| !d.version.is_empty())
111
+ .map(|d| ((d.group, d.artifact), d.version))
112
+ .collect();
113
+ let mut deps = parse_pom_regex(&rest);
114
+ for dep in &mut deps {
115
+ if dep.version.is_empty() {
116
+ if let Some(v) = managed.get(&(dep.group.clone(), dep.artifact.clone())) {
117
+ dep.version = v.clone();
118
+ }
119
+ }
120
+ dep.version = resolve_placeholders(&dep.version, &props);
121
+ }
122
+ Ok(deps)
123
+ }
124
+
125
+ /// Remove every `<tag>...</tag>` section. Their dependency blocks are not
126
+ /// application dependencies, and a profile's `<properties>` or
127
+ /// `<dependencyManagement>` must not affect the base dependency graph, so
128
+ /// stripping runs before property and management extraction.
129
+ fn strip_sections(content: &str, tags: &[&str]) -> String {
130
+ let mut content = content.to_string();
131
+ for tag in tags {
132
+ while let Some((rest, _)) = split_section(&content, tag) {
133
+ content = rest;
134
+ }
135
+ }
136
+ content
137
+ }
138
+
139
+ /// Split out the `<dependencyManagement>` section: its entries pin versions
140
+ /// for the project's dependencies but are not dependencies themselves.
141
+ /// Returns (pom without the section, the section's inner content).
142
+ fn split_dependency_management(content: &str) -> (String, &str) {
143
+ split_section(content, "dependencyManagement").unwrap_or_else(|| (content.to_string(), ""))
144
+ }
145
+
146
+ /// Locate a `<tag>...</tag>` section and split content into (content with
147
+ /// the section removed, the section's inner content). `None` if the tag
148
+ /// isn't present or is malformed (close before open).
149
+ fn split_section<'a>(content: &'a str, tag: &str) -> Option<(String, &'a str)> {
150
+ let open = format!("<{tag}>");
151
+ let close = format!("</{tag}>");
152
+ let s = content.find(&open)?;
153
+ let e = content.find(&close)?;
154
+ if s >= e {
155
+ return None;
156
+ }
157
+ let inner = &content[s + open.len()..e];
158
+ let rest = format!("{}{}", &content[..s], &content[e + close.len()..]);
159
+ Some((rest, inner))
160
+ }
161
+
162
+ /// Collect `<properties>` entries plus the built-in `project.version`.
163
+ fn parse_pom_properties(content: &str) -> std::collections::HashMap<String, String> {
164
+ let mut props = std::collections::HashMap::new();
165
+ if let Some(start) = content.find("<properties>") {
166
+ let rest = &content[start + "<properties>".len()..];
167
+ if let Some(end) = rest.find("</properties>") {
168
+ let mut block = &rest[..end];
169
+ while let Some(open_start) = block.find('<') {
170
+ let after = &block[open_start + 1..];
171
+ let Some(open_end) = after.find('>') else {
172
+ break;
173
+ };
174
+ let tag = after[..open_end].trim();
175
+ let body = &after[open_end + 1..];
176
+ if tag.starts_with('/') || tag.starts_with('!') || tag.ends_with('/') {
177
+ block = body;
178
+ continue;
179
+ }
180
+ let close = format!("</{tag}>");
181
+ match body.find(&close) {
182
+ Some(close_pos) => {
183
+ props.insert(tag.to_string(), body[..close_pos].trim().to_string());
184
+ block = &body[close_pos + close.len()..];
185
+ }
186
+ None => block = body,
187
+ }
188
+ }
189
+ }
190
+ }
191
+ // Property values may reference other properties; resolve the map to a
192
+ // fixed point, bounded to guard against definition cycles.
193
+ resolve_props_fixed_point(&mut props);
194
+ let project_version = resolve_placeholders(&pom_project_version(content), &props);
195
+ if !project_version.is_empty() && !project_version.contains("${") {
196
+ props.insert("project.version".to_string(), project_version);
197
+ }
198
+ // Properties aliasing ${project.version} (e.g. `<shared.version>`) only
199
+ // resolve now that project.version itself is in the map.
200
+ resolve_props_fixed_point(&mut props);
201
+ props
202
+ }
203
+
204
+ /// Resolve `${...}` references among property values to a fixed point. A
205
+ /// resolution chain can't be longer than the number of properties without
206
+ /// a cycle, so bound the iteration count by the map size.
207
+ fn resolve_props_fixed_point(props: &mut std::collections::HashMap<String, String>) {
208
+ for _ in 0..=props.len() {
209
+ let resolved: std::collections::HashMap<String, String> = props
210
+ .iter()
211
+ .map(|(k, v)| (k.clone(), resolve_placeholders(v, props)))
212
+ .collect();
213
+ if resolved == *props {
214
+ break;
215
+ }
216
+ *props = resolved;
217
+ }
218
+ }
219
+
220
+ /// The pom's own `<version>`: first `<version>` before `<dependencies>`,
221
+ /// excluding the `<parent>` block. A child that inherits its version has
222
+ /// none of its own, so fall back to the parent's (Maven's inheritance rule).
223
+ fn pom_project_version(content: &str) -> String {
224
+ let head = content.split("<dependencies>").next().unwrap_or(content);
225
+ // The project's own <version> lives among its coordinates, before any
226
+ // nested section that may carry unrelated <version> tags of its own
227
+ // (plugin versions in <build>, managed versions in
228
+ // <dependencyManagement>, etc).
229
+ let nested_start = NON_DEPENDENCY_SECTIONS
230
+ .iter()
231
+ .copied()
232
+ .chain(["dependencyManagement"])
233
+ .filter_map(|tag| head.find(&format!("<{tag}>")))
234
+ .min();
235
+ let head = match nested_start {
236
+ Some(pos) => &head[..pos],
237
+ None => head,
238
+ };
239
+ if let Some((cleaned, parent)) = split_section(head, "parent") {
240
+ let own = extract_xml_tag(&cleaned, "version");
241
+ if !own.is_empty() {
242
+ return own;
243
+ }
244
+ return extract_xml_tag(parent, "version");
245
+ }
246
+ extract_xml_tag(head, "version")
247
+ }
248
+
249
+ /// Substitute `${name}` placeholders; unresolved ones pass through unchanged.
250
+ fn resolve_placeholders(raw: &str, props: &std::collections::HashMap<String, String>) -> String {
251
+ if !raw.contains("${") {
252
+ return raw.to_string();
253
+ }
254
+ let mut out = String::new();
255
+ let mut rest = raw;
256
+ while let Some(start) = rest.find("${") {
257
+ out.push_str(&rest[..start]);
258
+ let after = &rest[start + 2..];
259
+ let Some(end) = after.find('}') else {
260
+ out.push_str(&rest[start..]);
261
+ return out;
262
+ };
263
+ let key = &after[..end];
264
+ match props.get(key) {
265
+ Some(v) => out.push_str(v),
266
+ None => out.push_str(&rest[start..start + 2 + end + 1]),
267
+ }
268
+ rest = &after[end + 1..];
269
+ }
270
+ out.push_str(rest);
271
+ out
94
272
  }
95
273
 
96
274
  fn parse_pom_regex(content: &str) -> Vec<MavenDep> {
@@ -10,6 +10,16 @@ pub fn scan_all(ctx: &mut ScanContext<'_>) -> Result<(), DepsError> {
10
10
  evaluate::scan_all(ctx)
11
11
  }
12
12
 
13
+ /// Whether `scan_all` builds graph nodes for this ecosystem. Keep in sync
14
+ /// with the scanners wired in `evaluate::scan_all` — detect-only ecosystems
15
+ /// (Go, Cargo) are found on disk but contribute nothing to the graph or SBOM.
16
+ pub fn is_graphed(ecosystem: Ecosystem) -> bool {
17
+ matches!(
18
+ ecosystem,
19
+ Ecosystem::Npm | Ecosystem::PyPI | Ecosystem::Maven
20
+ )
21
+ }
22
+
13
23
  use crate::deps::model::{ConstraintKind, Ecosystem};
14
24
 
15
25
  /// Classify a raw declared constraint string.
@@ -62,6 +62,13 @@ impl Inventory {
62
62
 
63
63
  /// Scan a directory tree: detect files, build the graph, evaluate policy.
64
64
  pub fn scan(root: &Path, policy: &Policy) -> Result<Inventory, DepsError> {
65
+ if !root.exists() {
66
+ return Err(DepsError(format!(
67
+ "path does not exist: {}",
68
+ root.display()
69
+ )));
70
+ }
71
+
65
72
  let detected = detect::detect_dependency_files(root);
66
73
  let mut graph = DependencyGraph::default();
67
74
  let mut findings = Vec::new();