Upload corgea.yaml with third-party scan reports - #167
Conversation
Report-only uploads never sent the policy file, so Fusion never created Repo policies from Checkmarx/Semgrep/SARIF/Coverity/Fortify ingest. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
No merge blockers on 0696a65 (0c6f63c plus an empty main merge).
upload_scan now appends cwd corgea.yaml / corgea.yml to the third-party file list, which is the actual ingest gap: report-only /code-upload never sent the policy file, so Fusion/doghouse never created Repo rows. Blast/full-zip is untouched and already ships the tree.
Checked against the call graph and the existing upload contract:
- Only
parse_scanand Fortify reachupload_scan. Extra paths go through the sameexists()→/code-upload→ retry loop as report files, with string-exact dedup before the existinguploaded_pathsset. - Discovery uses the same
ignore::WalkBuilder+standard_filters(true)as the zip walker, force-includes a gitignored root file, and skips gitignored nested copies. That matches the documented nested layout (frontend/corgea.yaml,backend/corgea.yaml) and does not pick up hidden paths such as.continue/mcpServers/corgea.yaml. - Tests pin basename match, empty tree, gitignored nested skip, gitignored root keep, and merge append/dedup. They do not HTTP-mock
upload_scan; the production change there is the two-line merge, which is enough.
parse_scan still exits on an empty path list before upload_scan runs. That is pre-existing (clean reports never created a scan) and is not a reason to hold this PR — changing it would start creating empty third-party scans.
Sent by Cursor Automation: pr-flow
| let mut found = Vec::new(); | ||
| for name in CORGEA_POLICY_FILENAMES { | ||
| if root.join(name).is_file() { | ||
| found.push((*name).to_string()); |
There was a problem hiding this comment.
high: Policy discovery can upload files outside the repository through symlinks
Path::is_file() follows symlinks. A repository can therefore contain corgea.yaml as a symlink to any readable local file. Discovery adds that path automatically, and the documented upload flow subsequently opens it for /code-upload, following the symlink and disclosing the target without explicit user selection. Reject symlinks or canonicalize each candidate and verify it remains beneath the canonical repository root before adding it.
Proof or reproduction:
#[cfg(unix)]
#[test]
fn does_not_discover_policy_symlink_outside_repo() {
use std::os::unix::fs::symlink;
let root = tempfile::tempdir().unwrap();
let secret = tempfile::NamedTempFile::new().unwrap();
std::fs::write(secret.path(), "secret").unwrap();
symlink(secret.path(), root.path().join("corgea.yaml")).unwrap();
assert!(find_corgea_policy_files(root.path()).is_empty());
// Currently fails: discovery returns ["corgea.yaml"].
}
There was a problem hiding this comment.
Automated review risk: 4/5.
Automatic policy discovery introduces a local file disclosure risk by following symlinks.
Critical or high-priority changes must be addressed.
Automatic approval was not submitted: automated review found critical or high-priority findings.


Summary
Third-party
corgea uploadonly sent files named in the scanner report, so Repo policies never ingested.upload_scannow also uploadscorgea.yaml/corgea.ymlfound under cwd (nested included). The walk uses the same ignore filters as the rest of the CLI, and still includes a policy file sitting on the project root even if gitignored.Blast / full-zip already ships the tree. No fusion or doghouse changes.
Related
Test plan
cargo test --bin corgea corgea_policy_files./harness checkcor-1172-manual-e2e, withcorgea.yamlpresent:../cli/target/release/corgea upload checkmarx-cli.json --project-name cor-1172-e2e-yaml-4 --waitcorgea.yamlpolicies_policyhas a Repo row (company_id=1, name ILIKE%yaml%,source_type=Repo)/opt/homebrew/bin/corgeawas not the binary used (still 1.10.0)Made with Cursor