Setting up your checks: what each one should do
Three of the version control tests ask for three separate pieces of proof: your test suite ran, the third-party code you depend on was scanned, and the code you wrote was scanned. Run all three in one pipeline, and give each its own job.
Can I do all three in one job?
You can run them in one pipeline. Don't run them in one job.
Your CI reports one result per job, under one name. Three checks in one job produce one name and one pass or fail — so when the dependency scan fails and the tests pass, you get a single red result and nothing saying which claim broke. Three jobs give you three names, three results, three pieces of evidence that stand on their own.
It's also what makes them nameable: each test looks for its own check by name. Telling UprootSecurity which CI checks to look for covers where to read that name on your provider.
The compliance reason is the same as the engineering reason. Three claims need three pieces of evidence. A combined result asserting "everything passed" can't be handed to an auditor as proof that dependency scanning specifically happened. Splitting costs nothing: same pipeline, same trigger, same runtime, three jobs instead of one.
What each check should do
Check | What it proves | What belongs in it | A weak version |
|---|---|---|---|
Integration testing | The change still works with the rest of the system | Your test suite, run against a realistically wired-up application | Unit tests only — every part works alone, which isn't the claim |
Dependency testing | The third-party code you pull in isn't known-vulnerable | A scan of your lockfile or manifest against a vulnerability database | Direct dependencies only, or a nightly scan rather than a per-change one |
Static application security testing (SAST) | The code you wrote has no known-dangerous patterns | An analyser that reads your source without running it | An untuned scan nobody reads, or rules for a different language |
Integration testing
Run the suite against an application that's actually wired together — a real database, real service boundaries, not everything stubbed. Unit tests are worth having and they aren't this: they prove each part works alone, where the claim here is that the parts still work together after your change.
What good looks like: it runs on the merge result rather than your branch alone, exercises the paths that touch data and other services, and fails the job when a test fails.
Dependency testing
This reads your lockfile or manifest and checks every package version in it against a public vulnerability database. You'll also see it called software composition analysis.
What good looks like: it runs on every pull request rather than once a night, it covers transitive dependencies and not just the ones you named yourself, and it fails on the severity you've decided matters rather than on everything it finds.
That last point deserves a decision, not a default. Pick your severity threshold deliberately and write down why. A scanner that fails the build on every low-severity advisory gets switched off within a month, and a switched-off scanner is worse than a strict one — no signal, no record. A threshold you chose and can defend beats one you inherited.
Static application security testing
SAST reads your source code without running it, looking for patterns already known to be dangerous: injection, unsafe deserialization, hardcoded secrets, weak or misused cryptography.
What good looks like: it scans the code the pull request changed, its rules match the language and framework you actually use, and it's tuned enough that people read the output. An untuned first run on a mature codebase produces hundreds of findings, and the lasting damage isn't the noise — it's teaching the team that the check is safe to ignore. Baseline what's already there, fail on what's new, work the backlog down separately.
Why three, and not one
These three don't overlap, which is the point. A test suite says nothing about a vulnerable version of a package you didn't write. A dependency scanner says nothing about the injection flaw you wrote yourself. SAST says nothing about whether your services still talk to each other. Each covers a gap the other two structurally cannot see.
Setting up the pipeline
Your provider's documentation does the syntax better than we can. What matters is the shape.
The pipeline is a file in your repository. That's a useful property most people never notice: the definition of your gate is versioned and reviewed exactly like the code it guards, so changing what gets checked is itself a change someone approved.
Trigger it on pull requests, not only on pushes to your main branch. This is the most common setup mistake by a distance, and usually a one-line change — if your suite already runs on pushes to main, add the pull request trigger and keep the push one. Why we grade pull requests, not your main branch has the reasoning.
One job per claim — as above.
Each job has to end in a clear pass or fail. A job that always exits successfully and prints its findings as warnings is a report, not a check.
Two things then finish it, and both live elsewhere: make the checks required to merge — building a release process when you don't have one — and give UprootSecurity each check's exact name — telling UprootSecurity which CI checks to look for.
If you have no CI at all
All three providers ship CI of their own, and turning it on is a file in your repository, not a procurement decision. The smallest useful first version is one job running your existing test command on every pull request — an afternoon, not a quarter.
Ship that, watch it run on a few real pull requests, then add the dependency scan and the security scan as jobs beside it. Trying to build all three at once is how this ends up on a roadmap instead of in your repository.
How to tell it worked
Open a pull request and confirm four things on it:
- All three checks appear. If one is missing, its trigger or its job didn't run.
- Each shows its own result, separately from the other two.
- The names match what you typed into UprootSecurity, character for character.
- A failing check blocks the merge — the merge is held, not just marked red.
From there every pull request carries its own evidence, and how UprootSecurity grades your version control covers what happens to it over time.
