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.
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/.github/workflows/test.yml +3 -1
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/Cargo.lock +1 -1
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/Cargo.toml +3 -3
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/PKG-INFO +1 -1
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/README.md +58 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/skills/corgea/SKILL.md +47 -3
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/config.rs +8 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/ecosystems/maven.rs +180 -2
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/ecosystems/mod.rs +10 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/mod.rs +7 -0
- corgea_cli-1.11.0/src/deps/report.rs +261 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/run.rs +3 -6
- corgea_cli-1.11.0/src/deps/tests/maven_tests.rs +338 -0
- corgea_cli-1.11.0/src/deps/tests/report_tests.rs +218 -0
- corgea_cli-1.11.0/src/images.rs +513 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/inspect.rs +1 -1
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/list.rs +126 -48
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/main.rs +261 -23
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/mod.rs +34 -12
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/test_support.rs +2 -2
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/verdict.rs +1 -1
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/scan.rs +63 -32
- corgea_cli-1.11.0/src/scanners/blast.rs +1962 -0
- corgea_cli-1.11.0/src/skip_scan.rs +690 -0
- corgea_cli-1.11.0/src/utils/api.rs +2370 -0
- corgea_cli-1.11.0/src/utils/generic.rs +1000 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/vuln_api_stub/mod.rs +135 -8
- corgea_cli-1.11.0/src/wait.rs +180 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_deps.rs +99 -0
- corgea_cli-1.11.0/tests/cli_scan_include_image.rs +310 -0
- corgea_cli-1.11.0/tests/cli_scan_sbom.rs +219 -0
- corgea_cli-1.11.0/tests/cli_scan_wait_terminal_state.rs +302 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_verdict.rs +51 -0
- corgea_cli-1.11.0/tests/cloud_commands_e2e/block_on_report.rs +204 -0
- corgea_cli-1.11.0/tests/cloud_commands_e2e/common/mod.rs +852 -0
- corgea_cli-1.11.0/tests/cloud_commands_e2e/inspect.rs +140 -0
- corgea_cli-1.11.0/tests/cloud_commands_e2e/main.rs +9 -0
- corgea_cli-1.11.0/tests/cloud_commands_e2e/scan_list.rs +243 -0
- corgea_cli-1.11.0/tests/cloud_commands_e2e/scan_skip.rs +565 -0
- corgea_cli-1.11.0/tests/cloud_commands_e2e/upload_wait.rs +152 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/common/mod.rs +198 -1
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/README.md +1 -0
- corgea_cli-1.11.0/tests/fixtures/java-maven-alias/pom.xml +19 -0
- corgea_cli-1.11.0/tests/fixtures/java-maven-chained/pom.xml +20 -0
- corgea_cli-1.11.0/tests/fixtures/java-maven-deep-chain/pom.xml +25 -0
- corgea_cli-1.11.0/tests/fixtures/java-maven-managed/pom.xml +29 -0
- corgea_cli-1.11.0/tests/fixtures/java-maven-parent/pom.xml +29 -0
- corgea_cli-1.11.0/tests/fixtures/java-maven-plugin-deps/pom.xml +62 -0
- corgea_cli-1.11.0/tests/fixtures/java-maven-profile-mgmt/pom.xml +37 -0
- corgea_cli-1.11.0/tests/fixtures/java-maven-props/pom.xml +27 -0
- corgea_cli-1.11.0/tests/fixtures/java-maven-revision/pom.xml +19 -0
- corgea_cli-1.11.0/tests/fixtures/mixed-monorepo/services/api/requirements.txt +2 -0
- corgea_cli-1.11.0/tests/fixtures/mixed-monorepo/services/web/package-lock.json +29 -0
- corgea_cli-1.11.0/tests/fixtures/mixed-monorepo/services/web/package.json +10 -0
- corgea_cli-1.11.0/tests/list_code_quality.rs +209 -0
- corgea_cli-1.11.0/tests/list_resolution.rs +374 -0
- corgea_cli-1.11.0/tests/wait_resolution.rs +358 -0
- corgea_cli-1.9.3/.github/workflows/sync-skills.yml +0 -166
- corgea_cli-1.9.3/.github/workflows/update_docs..yml +0 -27
- corgea_cli-1.9.3/src/deps/report.rs +0 -172
- corgea_cli-1.9.3/src/deps/tests/maven_tests.rs +0 -129
- corgea_cli-1.9.3/src/deps/tests/report_tests.rs +0 -81
- corgea_cli-1.9.3/src/scanners/blast.rs +0 -850
- corgea_cli-1.9.3/src/utils/api.rs +0 -1342
- corgea_cli-1.9.3/src/utils/generic.rs +0 -453
- corgea_cli-1.9.3/src/wait.rs +0 -102
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/.codex/hooks.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/.github/workflows/npm-publish.yml +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/.github/workflows/release-binaries.yml +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/.github/workflows/release.yml +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/.github/workflows/staging-contract.yml +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/.gitignore +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/AGENTS.md +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/LICENSE +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/RELEASING.md +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/bin/corgea.js +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/build_release.sh +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/examples/deps_skill.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/harness +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/package.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/pyproject.toml +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/scripts/check-linux-binary.sh +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/scripts/npm/bundle-binaries.js +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/advisories.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/authorize.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/cicd.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/catalog.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/detect.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/diff.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/ecosystems/evaluate.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/ecosystems/npm.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/ecosystems/pypi.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/explain.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/findings.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/model.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/parse/mod.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/parse/npm_lock.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/parse/python_lock.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/policy.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/skill.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/common.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/correctness_tests.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/detect_tests.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/diff_tests.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/explain_tests.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/findings_tests.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/mod.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/npm_tests.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/policy_tests.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/pypi_tests.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/robustness_tests.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/deps/tests/slice0_tests.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/lib.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/log.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/detect.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/exec.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/parse.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/render.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/tree.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/precheck/uv.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/scanners/fortify.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/scanners/parsers/checkmarx.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/scanners/parsers/coverity.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/scanners/parsers/mod.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/scanners/parsers/sarif.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/scanners/parsers/semgrep.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/setup_hooks.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/skill.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/targets.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/utils/terminal.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/verify_deps/mod.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/verify_deps/registry.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/src/vuln_api/mod.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_advisories.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_bare_install.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_deps_skill.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_exec_fallback.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_install.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_npm_ci.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_provenance.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_remediation.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_tree.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/cli_uv_sync.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/go-mod-smoke/go.mod +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/go-mod-smoke/go.sum +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/java-gradle/build.gradle +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/java-gradle/gradle.lockfile +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/java-maven/pom.xml +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/malformed/not-xml-pom.xml +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/malformed/package-lock.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/malformed/package.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/malformed/poetry.lock +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/malformed/pyproject.toml +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/malformed/truncated-poetry.lock +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-app/.corgea/deps.yml +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-app/package-lock.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-app/package.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-monorepo/package-lock.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-monorepo/package.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-monorepo/packages/a/package.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-monorepo/packages/b/package.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-pnpm/package.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-pnpm/pnpm-lock.yaml +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-stale/package-lock.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-stale/package.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-transitive/package-lock.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-transitive/package.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-yarn/package.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/node-yarn/yarn.lock +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-pip-nolock/requirements.txt +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-poetry/poetry.lock +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-poetry/pyproject.toml +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-poetry-multi/poetry.lock +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-poetry-multi/pyproject.toml +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-uv-requirements/pyproject.toml +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-uv-requirements/requirements.txt +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/python-uv-requirements/uv.lock +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/vuln_api/README.md +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/vuln_api/check_clean.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/vuln_api/check_malware.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/vuln_api/check_unknown.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/vuln_api/check_vulnerable.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/vuln_api/package_profile.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/fixtures/vuln_api/package_profile_not_found.json +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/harness_smoke.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/logging_e2e.rs +0 -0
- {corgea_cli-1.9.3 → corgea_cli-1.11.0}/tests/vuln_api_contract.rs +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "corgea"
|
|
3
|
-
version = "1.
|
|
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.
|
|
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.
|
|
44
|
+
tempfile = "3.20.0"
|
|
45
45
|
quick-xml = "0.41"
|
|
46
46
|
ignore = "0.4"
|
|
47
47
|
globset = "0.4"
|
|
@@ -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 --
|
|
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
|
-
`--
|
|
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
|
|
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
|
-
|
|
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();
|