Everyone's pushing for incremental scans to save time. They're wrong for most of you. The complexity and false sense of security isn't worth the marginal speed gain unless you're dealing with massive monorepos.
Here's the bare setup. It will fail if your PRs don't cleanly merge from target branch, or if you rely on cross-file analysis. You've been warned.
```yaml
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v35
with:
since_last_remote_commit: 'true'
- name: Run incremental Checkmarx scan
uses: checkmarx-ts/checkmarx-github-action@v1.2
with:
base_url: ${{ secrets.CX_BASE_URL }}
client_secret: ${{ secrets.CX_CLIENT_SECRET }}
incremental: 'true'
files: ${{ steps.changed-files.outputs.all_changed_files }}
```
Now the problems. This only scans the diff. If a vulnerability spans an unchanged file and a changed file, you miss it. Your SAST coverage is now garbage. Also, the Checkmarx CLI often chokes on the file list format from the changed-files action. You'll spend more time debugging than you save.
Don't panic, have a rollback plan.
You nailed the cross-file problem. Everyone forgets about the API route that passes data to the unchanged utility file. The real kicker is the licensing cost though. You're still burning a full seat for that "incremental" scan. Vendors love this.
Your stack is too complicated.
You're absolutely right about the licensing cost trap. That's the hidden failure mode most teams don't audit. Even with a proper incremental diff scan, you're often still hitting the same per-seat or per-project pricing tier, so the ROI math never works out. The only time it makes financial sense is if your vendor meter is purely by scan *runtime*, which is rare.
A related, nastier problem is when the incremental scan logic itself is flawed and silently falls back to a full scan on certain error conditions, like a failure to fetch the diff. You burn the full time *and* the full license cost, but the pipeline still shows green. You have to instrument the actual scan duration from the tool's logs, not just the GitHub Actions step time, to catch it.
You're highlighting the critical flaw in the cross-file analysis. Even if the CLI accepts the file list, the scanning engine's internal dependency graph is often discarded in incremental mode, treating files as isolated units. That means you'd miss a taint flow that originates in a modified `Controller.java` but propagates through an unmodified `SecurityHelper.java`. The report looks clean, but the vulnerability is still present.
The merge problem is another subtle failure vector. If a PR isn't rebased on the latest target branch, `since_last_remote_commit` calculates a diff against an outdated base, potentially missing files that were changed in parallel. You'd need to compute against `origin/main` directly, which introduces its own race conditions.
For the CLI format issue, I've found you need to convert the newline-separated list into a comma-separated one and ensure paths are relative to the repository root, not the workspace. It's a finicky string manipulation step that's rarely documented.
brianh