A Ninety-Minute CI SARIF and Static Analysis Triage Pass for Unity and Godot Merge Queues (2026)
Your CI already prints logs tall enough to hide a medium-sized narrative game. SARIF (Static Analysis Results Interchange Format) is the compact, structured alternative that security scanners, compilers, and linters increasingly emit so machines—not humans squinting at stderr—can compare runs, deduplicate findings, and attach results to pull requests. If your Unity or Godot repository recently turned on “upload SARIF” in GitHub Actions, GitLab, or a hosted scanner, you may have discovered a fresh problem: ten thousand warnings feel just as blocking as ten errors when nobody owns severity rules.
This article is a ninety-minute working session for small teams who need merge-queue discipline without hiring a dedicated AppSec program. It sits beside inventory and provenance evidence—use A Ninety-Minute SBOM and Dependency Evidence Pass for Unity and Godot Teams Before Partner Audits (2026) for dependency rows and A Ninety-Minute Build Provenance and SLSA-Style Attestation Pass for Unity and Godot Teams Before Partner Audits (2026) for artifact integrity—while this pass answers which defects you treat as release gates versus technical debt tickets. When partners ask how you prevent repeat crash signatures, cross-link to your internal habits around build failure signature registries so static findings and runtime fingerprints do not live in separate brains.
Maintenance note (May 2026): this refresh tightens release-lane framing for teams running same-week patch and compliance windows, where stale SARIF baselines frequently reopen “already accepted” findings and block merge queues during certification crunch.

Why this matters now
Three ecosystem shifts make SARIF a front-line topic for 2026 indie pipelines, not a Fortune 500 appendix.
First, Git hosting platforms normalized SARIF ingestion for code scanning views. That means your analyzer output is no longer a disposable artifact—it becomes a durable record attached to commits and branches. If you never configure severity thresholds, your default experience is a guilt dashboard that trains engineers to ignore the product.
Second, merge queues and required checks reward structured outputs. Plain logs fail diff-friendly comparisons; SARIF carries rule ids, locations, and fingerprints so CI can say “this finding existed last week” instead of “something yelled about nullable reference types again.”
Third, publisher security questionnaires increasingly mention SAST (static application security testing) adjacent to SBOM and provenance asks. You may not run enterprise CodeQL coverage, but you can still show governance: what runs, what gates promotion, how exceptions expire. A ninety-minute triage pass produces that narrative without buying another dashboard license.
If you already track semantic versioning and changelog discipline for releases, extend the same seriousness to static findings ownership—your build metadata and release notes resources habit is the cultural sibling of this workflow.
Current trend trigger: if your queue now mixes security scans from more than one runner image or toolchain minor in a single sprint, treat baseline drift as a first-class incident and rerun this pass before cut-off approvals.
Who this helps
- Teams that enabled GitHub code scanning, GitLab SAST, Azure DevOps security scans, or IDE-exported SARIF and now stare at multi-thousand finding counts
- Unity engineers juggling Roslyn analyzers, Burst constraints, and package upgrades that reshuffle warning surfaces overnight
- Godot 4.x teams mixing GDScript lint culture with C# or GDExtension native modules that compile under different toolchains
- Producers who need a single paragraph explaining static analysis posture for partner reviews without promising CVE-free perfection
Beginner quick start
If you only finish five outcomes in this pass, make them these:
- Name the canonical SARIF files your CI produces per platform track (Windows editor build, Linux headless export, Android Gradle slice—pick realism over completeness).
- Pick one severity mapping from vendor rule ids to merge-blocking versus issue-tracker buckets.
- Record retention: where SARIF JSON lives, how long you keep it, and which commit SHA it references.
- Write one exception policy—how long a suppressed warning may live before re-review.
- Link static findings to runtime signals when applicable—if a rule flags unsafe deserialization, tie it to crash buckets you already track.
Success check: another engineer can open yesterday’s SARIF, filter error-level items, and answer whether trunk was eligible for a release branch without calling you on vacation.
SARIF in plain English
You do not need to memorize the OASIS SARIF 2.1 specification to ship games. You need a working mental model:
Runs describe which tool executed, with what configuration, on which command-line invocation snapshot.
Results are individual findings with rule ids, message strings, locations (file path, region line/column), and optional fingerprints so two uploads can recognize duplicates.
Rules metadata explains severity defaults and help URLs—when absent, your triage defaults become everything.
Baselines (conceptually) compare current results against an accepted snapshot so only new defects block merges—many teams simulate baselines with scripts or platform features.
Think of SARIF as structured linter JSON that crossed into security tooling. Your job in triage is not to eliminate noise—that is a multi-quarter hygiene campaign—but to stop noise from masquerading as policy.
Unity merge-queue realities
Roslyn analyzers and IDE parity
Unity 6 projects often enable analyzers at the .csproj level through packages and custom Directory.Build.props. CI must use the same package lock as developers or SARIF deltas become meaningless fights. Record manifest.json and lockfiles alongside SARIF uploads.
Burst, IL2CPP, and platform slices
Not every warning triggers on every target. If CI builds Windows first because it is faster, do not assume Android IL2CPP warnings appear in that slice. Your severity policy should either label platform gaps honestly or add a second compile job—even weekly—to catch platform-specific static failures before submission crunch.
Packages you do not control
Third-party assets sometimes ship deprecated APIs. Your SARIF triage should distinguish your gameplay scripts from imported plugin code using path prefixes (Assets/ThirdParty/...). Partner reviewers usually accept governed suppressions with expiry dates for vendor folders—silence without governance does not age well.
Godot merge-queue realities
GDScript versus C# tracks
Godot’s GDScript analyzers differ from .NET Roslyn rules for C# projects. If your repo mixes both, produce separate SARIF uploads or clearly tagged runs so you do not compare incompatible schemas in one dashboard view.
Headless export builds
CI exports should mirror release flags as closely as budget allows. A debug-only code path might never execute in CI, hiding warnings that appear only when DEBUG macros expand differently.
GDExtension and native code
Native modules compiled with Clang or MSVC may emit SARIF or diagnostics through LLVM tooling. Treat those runs as first-class if crashes in native glue dominate your live metrics—static findings there are cheap compared to post-launch native patches.
Tooling landscape (honest framing)
GitHub documents SARIF upload endpoints for code scanning; GitLab documents SAST report artifacts; GitHub also publishes CodeQL starter workflows widely forked by game repos. You may use commercial scanners that export SARIF, clang-tidy adapters, or eslint-style JSON converted to SARIF. This article stays vendor-agnostic: the governance pattern matters more than whether your badge says CodeQL or a niche Unity-focused analyzer.
Outbound references worth bookmarking for platform truth:
- OASIS SARIF resources for specification grounding when partners ask for standards literacy.
- GitHub documentation on SARIF support for code scanning when your remote is GitHub—substitute your forge’s equivalent if self-hosted.
The ninety-minute agenda
Use a visible timer. The failure mode is forty minutes of arguing whether “warning” is an emotion.
Minutes 0 to 10 — Freeze scope
- Pick one integration branch (example:
mainorrelease/2.x). - Decide whether today’s goal is merge blocking policy or audit narrative—you can touch both, but rank them.
- Assign one owner who signs the triage notes footer.
Minutes 10 to 25 — Inventory SARIF producers
- List every job emitting SARIF or convertible diagnostics: Unity compile, Gradle, .NET tests, Godot export, optional native clang pass.
- Record filenames and artifact retention paths (
artifacts/sarif/*.sarifpatterns). - Note which jobs are PR-blocking today versus informational.
Minutes 25 to 45 — Severity mapping workshop
- Export a sample SARIF from the latest green build.
- Sort by level (error, warning, note) and by rule id.
- Decide two thresholds: what blocks merge, what becomes a ticket template with SLA.
- Write a suppression policy: who approves, maximum duration, required Git blame link.
Minutes 45 to 65 — Baseline or delta strategy
- If your platform supports baselines, configure them for legacy folders.
- If not, choose a pragmatic stand-in—example: only error-level fails CI until warning backlog burn-down completes.
- Capture new finding detection criteria so noisy rules do not re-open every Monday.
Minutes 65 to 80 — Link static analysis to runtime evidence
- For top five rules firing today, ask whether crash telemetry or customer reports correlate.
- If yes, promote severity; if no, demote to debt with measurable reduction targets.
Minutes 80 to 90 — Publish the governance note
- One page: owners, thresholds, retention, exception policy, links to SBOM and provenance rituals.
- Store beside your build metadata checklist—static analysis is another release artifact, not a side quest.
Spreadsheet rows your producer can defend
Use a single tab engineers cannot dodge:
rule_idvendor_or_tooldefault_severitypolicy_severitymerge_blocking_yes_noexample_messagefirst_seen_commitowner_teamexception_expiry_date_if_anylinked_issue_url
Add a Noise budget row quarterly—some warning classes remain acceptable if totals shrink month over month.
Comparison table — SARIF versus logs versus tests
| Signal type | Strength | Weakness | Best use |
|---|---|---|---|
| SARIF bundles | Structured dedupe, rule metadata | Requires disciplined uploads | Merge gates and partner narratives |
| Plain CI logs | Easy to capture | Hard to compare across runs | Spot debugging, short retention |
| Automated tests | Validates behavior | Misses latent classes until triggered | Release confidence complements static |
Teams over-index on tests alone—static analysis catches categories tests may never exercise until production load shapes emerge.
Failure modes that embarrass audits
- Suppress-all culture —
#pragma warning disablegrows faster than gameplay features. - Platform-skewed CI — Android-only defects discovered by Google Play pre-launch reports instead of SARIF slices.
- Toolchain drift — Unity package bumps reorder warnings; policy tables rot because nobody owns updates.
- Unbounded SARIF retention — artifact storage fills; you cannot reconstruct past gates when regulators ask.
- Disconnected narratives — SBOM lists packages while SARIF ignores known vulnerable call sites—cross-reference both.
Unity-specific ninety-minute drill hints
Gradle and Android merges
If Gradle emits SARIF or convertible diagnostics, align Java/Kotlin rule sets with Unity’s embedded Gradle templates. Capture JDK and Gradle versions in the SARIF run metadata notes—even if your upload format hides them—so Play submission weeks reproduce cleanly.
Burst safety
Burst compilation warnings often deserve merge-blocking treatment when they imply undefined behavior on worker threads. Treat those separately from stylistic Roslyn nits.
Godot-specific ninety-minute drill hints
Export templates
Pin export template versions in CI variables and echo them into SARIF upload annotations so diffs across weeks remain explainable.
GDScript typing drift
Gradual typing produces churn. Decide whether typing warnings block merges or feed a typed-module roadmap—either is valid; ambiguity is not.
Partner questionnaire language you can reuse
When asked “describe static analysis controls,” avoid aspirational maturity levels. Use concrete statements:
- Scope — which repositories and binary targets run analyzers pre-merge.
- Gating — which severity levels block promotion to release branches.
- Evidence — SARIF artifact locations tied to commit SHAs, retention windows aligned with your build metadata policy.
- Exceptions — documented suppressions with owners and expiry.
Pair that paragraph with your SBOM and provenance packets so reviewers see ingredients, origin, and defect governance as one story.
Worked example — turning a rule flood into a decision
Imagine rule CS8602 (dereference of a possibly null reference) fires two hundred times after a Unity package update. A fifteen-minute panic might mass-suppress the rule. A governed response instead:
- Filter to your
Assets/Scriptstree only—drop generated and third-party paths for the first pass. - Cluster by subsystem (combat, UI, save-load). If one cluster jumped from five to ninety findings, you likely have a shared nullability contract change, not random noise.
- Pick a one-line interface fix (example: centralize a factory that never returns null for hot paths) before touching two hundred call sites.
- Timebox remaining single-file fixes to the current sprint; ticket the stragglers with owner and count so the dashboard trends down instead of flatlines at “we will clean later.”
- Re-upload SARIF after the interface fix to prove the delta—auditors and producers both understand graphs better than static totals.
This pattern works for Godot C# projects and for native modules where clang-tidy rule families spike after LLVM upgrades. The point is not achieving zero warnings in one night; the point is showing downward velocity with an owner and a commit-level story.
How this connects to shipping rituals you already run
If you maintain Unity Addressables lockfile discipline, treat SARIF baselines similarly—both fight silent drift. If you run Steam depot identity checks, remember depot correctness prevents wrong binaries from reaching players; SARIF correctness prevents known-bad code paths from riding those binaries to certification.
Conclusion
SARIF will not replace judgment—it replaces unstructured panic. A disciplined ninety-minute triage turns scanner floods into policy, owners, and comparable histories that survive personnel changes and engine upgrades. Ship merges knowing which warnings are debt, which are gates, and which deserve tickets with titles humans actually want to close.
Key takeaways
- SARIF gives structured static findings so CI can dedupe, baseline, and attach results to commits instead of drowning in logs.
- Define merge-blocking severity separately from informational noise—ambiguity trains teams to ignore dashboards.
- Unity teams must align Roslyn, Burst, and Gradle slices so warnings reflect real shipping surfaces.
- Godot teams should separate GDScript and C#/native analyzer tracks to avoid comparing incompatible runs.
- Pair static governance with runtime signature discipline via your build failure registry habits so audits see prevention plus detection.
- Publish a one-page policy listing owners, retention, suppression expiry, and links to SBOM/provenance rituals for 2026 partner asks.
- Revisit severity tables when engine versions or packages shift—stale policies are worse than no policies because they lie calmly.
FAQ
Do we need CodeQL specifically?
No. Many studios adopt whatever their Git host integrates fastest. The governance pattern—structured uploads, severity ownership, retention—applies across vendors.
Can we block merges on warnings?
You can, but expect rebellion unless warnings are low volume or baselined. Most teams block on error-level and trend warnings down quarterly.
SARIF files are huge—do we store them all?
Store release-branch SARIF for months; rotate feature-branch uploads faster. Align retention with your artifact storage budget and compliance asks.
What if two tools disagree on severity?
Pick a policy owner—usually engineering lead—and document precedence. Mixed signals are normal; hiding the conflict is not.
How does this relate to SBOM vulnerability rows?
SBOM names vulnerable packages; SARIF may flag dangerous call sites. Together they answer what and where—keep cross-links in tickets when both fire on the same feature area.
Our Unity project uses Asset Store plugins we cannot fix—now what?
Path-based suppressions with vendor labels and expiry dates satisfy many reviewers better than pretend cleanliness.
Does Godot 4.x need different handling than 3.x?
Tooling and export defaults shifted—revalidate SARIF producers after major upgrades instead of inheriting old thresholds blindly.
Written by GamineAI Team. For dependency inventories and signing conversations that partner worksheets bundle alongside static analysis asks, pair this pass with the SBOM and provenance ninety-minute articles linked near the top.