# GitHub Code Scanning Integration via SARIF
> **Status:** Revised
> **Original:** 09-Jan-2026 (Lighting Up GitHub with SARIF)
> **Revision:** 09-Jan-2026
> **Author:** Product/Engineering
> **Epic:** Platform Integrations
---
## Executive Summary
This advisory defines the complete integration between StellaOps Scanner and **GitHub Code Scanning** via SARIF 2.1.0. The integration enables StellaOps findings to appear natively in GitHub's Security tab with zero custom UI, leveraging GitHub's existing annotation, filtering, and alerting infrastructure.
### Current State
| Component | Status | Notes |
|-----------|--------|-------|
| SARIF 2.1.0 Models | **Implemented** | Full schema in `Scanner.SmartDiff` |
| SmartDiff SARIF Export | **Implemented** | Binary diff findings, production-ready |
| Findings SARIF Export | **Not Implemented** | Main vulnerability findings |
| GitHub App Connector | **Implemented** | Auth + health checks working |
| GitHub Code Scanning Upload | **Not Implemented** | REST API client needed |
| GitHub Actions Workflow | **Not Implemented** | Template generation needed |
### Business Value
- **Zero Custom UI:** GitHub renders findings, annotations, and PR decorations
- **Native Integration:** Findings appear in Security tab alongside Dependabot/CodeQL
- **Alert Management:** GitHub's existing dismiss/reopen/severity workflow
- **PR Blocking:** Branch protection rules can require scan results
- **Enterprise Ready:** Supports GitHub.com and GitHub Enterprise Server
---
## What SARIF Is
**SARIF** (Static Analysis Results Interchange Format) is an OASIS standard (version 2.1.0) for representing static analysis results. GitHub Code Scanning accepts a **subset** of SARIF 2.1.0 and renders it as security alerts.
### SARIF Structure
```
SarifLog
├── $schema: "https://json.schemastore.org/sarif-2.1.0.json"
├── version: "2.1.0"
└── runs[]
├── tool
│ └── driver
│ ├── name: "StellaOps Scanner"
│ ├── version: "1.0.0"
│ └── rules[]
│ ├── id: "STELLA-VULN-001"
│ ├── name: "Critical Vulnerability"
│ └── properties (CWE, CVSS, etc.)
├── results[]
│ ├── ruleId: "STELLA-VULN-001"
│ ├── level: "error" | "warning" | "note"
│ ├── message.text
│ ├── locations[]
│ │ └── physicalLocation
│ │ ├── artifactLocation.uri
│ │ └── region.startLine
│ └── fingerprints (deduplication)
└── versionControlProvenance (git metadata)
```
---
## Three Upload Options
### Option 1: GitHub Actions (Recommended)
```yaml
# .github/workflows/stellaops-scan.yml
name: StellaOps Scan
on:
push:
branches: [main, release/*]
pull_request:
branches: [main]
schedule:
- cron: "0 3 * * 1" # Weekly Monday 3 AM
jobs:
scan:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write # Required for Code Scanning
steps:
- uses: actions/checkout@v4
- name: Run StellaOps Scanner
uses: stellaops/scanner-action@v1
with:
image: ${{ github.repository }}:${{ github.sha }}
output-format: sarif
output-file: results.sarif
# Optional: filter by severity
min-severity: medium
- name: Upload SARIF to Code Scanning
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
category: stellaops-scanner
# Optional: wait for processing
wait-for-processing: true
```
### Option 2: REST API
For scans running outside GitHub Actions:
```bash
# Gzip + base64 encode the SARIF file
gzip -c results.sarif | base64 -w0 > sarif.b64
# Upload to GitHub Code Scanning API
curl -X POST \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/OWNER/REPO/code-scanning/sarifs" \
-d "{
\"commit_sha\": \"$(git rev-parse HEAD)\",
\"ref\": \"refs/heads/main\",
\"sarif\": \"$(cat sarif.b64)\",
\"tool_name\": \"StellaOps Scanner\"
}"
```
**Required Scopes:**
- Public repos: `public_repo`
- Private repos: `security_events`
### Option 3: StellaOps CLI
```bash
# Scan and upload in one command
stella scan \
--image myregistry/myapp:latest \
--sarif results.sarif \
--github-upload \
--github-token $GITHUB_TOKEN \
--github-repo owner/repo \
--github-ref refs/heads/main \
--github-sha $(git rev-parse HEAD)
# Or: scan first, upload separately
stella scan --image myregistry/myapp:latest --sarif results.sarif
stella github upload \
--sarif results.sarif \
--repo owner/repo \
--ref refs/heads/main
```
---
## StellaOps SARIF Rule Taxonomy
### Vulnerability Rules (STELLA-VULN-*)
| Rule ID | Name | Level | Description |
|---------|------|-------|-------------|
| STELLA-VULN-001 | Critical Vulnerability | error | CVSS >= 9.0 or KEV-listed |
| STELLA-VULN-002 | High Vulnerability | error | CVSS 7.0-8.9 |
| STELLA-VULN-003 | Medium Vulnerability | warning | CVSS 4.0-6.9 |
| STELLA-VULN-004 | Low Vulnerability | note | CVSS < 4.0 |
| STELLA-VULN-005 | Reachable Vulnerability | error | Runtime-confirmed reachable |
| STELLA-VULN-006 | Static Reachable Vulnerability | warning | Static-only reachable |
### Secret Detection Rules (STELLA-SEC-*)
| Rule ID | Name | Level | Description |
|---------|------|-------|-------------|
| STELLA-SEC-001 | Hardcoded Secret | error | API key, password, token in code |
| STELLA-SEC-002 | Private Key Exposure | error | PEM, PKCS#8 private key |
| STELLA-SEC-003 | Credential Pattern | warning | Potential credential pattern |
### Supply Chain Rules (STELLA-SC-*)
| Rule ID | Name | Level | Description |
|---------|------|-------|-------------|
| STELLA-SC-001 | Unsigned Package | warning | Package lacks signature |
| STELLA-SC-002 | Unknown Provenance | warning | No SLSA provenance |
| STELLA-SC-003 | Typosquat Candidate | error | Potential typosquatting |
| STELLA-SC-004 | Deprecated Package | note | Package marked deprecated |
### Binary Hardening Rules (STELLA-BIN-*)
| Rule ID | Name | Level | Description |
|---------|------|-------|-------------|
| STELLA-BIN-001 | Missing RELRO | warning | No full RELRO |
| STELLA-BIN-002 | No Stack Canary | warning | Stack protection disabled |
| STELLA-BIN-003 | No PIE | warning | Position-independent disabled |
| STELLA-BIN-004 | No Fortify | note | FORTIFY_SOURCE not used |
### SmartDiff Rules (SDIFF-*) - Already Implemented
| Rule ID | Name | Level | Description |
|---------|------|-------|-------------|
| SDIFF001 | Material Risk Change | warning | Risk profile changed |
| SDIFF002 | Binary Hardening Regression | error | Security control removed |
| SDIFF003 | VEX Candidate | note | VEX status changed |
| SDIFF004 | Reachability Change | warning | Reachability status changed |
---
## SARIF Schema for Findings
### Complete Finding Example
```json
{
"version": "2.1.0",
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"runs": [{
"tool": {
"driver": {
"name": "StellaOps Scanner",
"version": "3.2.1",
"informationUri": "https://stellaops.io/scanner",
"rules": [{
"id": "STELLA-VULN-001",
"name": "CriticalVulnerability",
"shortDescription": {
"text": "Critical vulnerability detected"
},
"fullDescription": {
"text": "A critical severity vulnerability (CVSS >= 9.0) was detected in a dependency."
},
"helpUri": "https://stellaops.io/rules/STELLA-VULN-001",
"properties": {
"precision": "high",
"problem.severity": "error",
"security-severity": "9.8",
"tags": ["security", "vulnerability", "critical"]
}
}],
"supportedTaxonomies": [{
"name": "CWE",
"guid": "d4c8a3c4-8f5e-4f3a-9a6b-2c7d8e9f0a1b"
}]
}
},
"taxonomies": [{
"name": "CWE",
"guid": "d4c8a3c4-8f5e-4f3a-9a6b-2c7d8e9f0a1b",
"taxa": [{
"id": "502",
"name": "Deserialization of Untrusted Data"
}]
}],
"results": [{
"ruleId": "STELLA-VULN-001",
"ruleIndex": 0,
"level": "error",
"message": {
"text": "Critical vulnerability CVE-2021-44228 (Log4Shell) in org.apache.logging.log4j:log4j-core@2.14.1. CVSS: 10.0. This vulnerability allows remote code execution via JNDI injection.",
"markdown": "**Critical vulnerability** [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) (Log4Shell) in `org.apache.logging.log4j:log4j-core@2.14.1`.\n\n**CVSS:** 10.0 (Critical)\n\n**Description:** Remote code execution via JNDI injection.\n\n**Remediation:** Upgrade to log4j-core >= 2.17.0"
},
"locations": [{
"physicalLocation": {
"artifactLocation": {
"uri": "pom.xml",
"uriBaseId": "%SRCROOT%"
},
"region": {
"startLine": 45,
"startColumn": 1,
"endLine": 49,
"endColumn": 1,
"snippet": {
"text": "\n org.apache.logging.log4j\n log4j-core\n 2.14.1\n"
}
}
},
"logicalLocations": [{
"name": "org.apache.logging.log4j:log4j-core",
"kind": "package",
"fullyQualifiedName": "pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1"
}]
}],
"fingerprints": {
"stellaops/v1": "sha256:a1b2c3d4e5f6...",
"primaryLocationLineHash": "abc123..."
},
"partialFingerprints": {
"primaryLocationLineHash": "abc123..."
},
"taxa": [{
"id": "502",
"toolComponent": {
"name": "CWE"
}
}],
"properties": {
"stellaops.finding.id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"stellaops.component.purl": "pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1",
"stellaops.vulnerability.cve": "CVE-2021-44228",
"stellaops.vulnerability.cvss": 10.0,
"stellaops.vulnerability.severity": "critical",
"stellaops.vulnerability.epss": 0.975,
"stellaops.vulnerability.kev": true,
"stellaops.reachability.state": "RuntimeObserved",
"stellaops.reachability.confidence": 0.92,
"stellaops.vex.status": "affected",
"stellaops.evidence.uris": [
"stella://reachgraph/blake3:abc123",
"stella://signals/runtime/tenant/sha256:def456"
]
}
}],
"artifacts": [{
"location": {
"uri": "pom.xml",
"uriBaseId": "%SRCROOT%"
},
"mimeType": "application/xml",
"hashes": {
"sha-256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
}
}],
"versionControlProvenance": [{
"repositoryUri": "https://github.com/example/myapp",
"revisionId": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"branch": "main",
"mappedTo": {
"uriBaseId": "%SRCROOT%"
}
}],
"properties": {
"stellaops.scan.id": "scan-12345",
"stellaops.scan.artifact": "sha256:abc123...",
"stellaops.scan.timestamp": "2026-01-09T10:30:00Z",
"stellaops.scan.version": "3.2.1",
"stellaops.attestation": {
"digest": "sha256:sig789...",
"predicateType": "https://stellaops.io/attestation/scan/v1",
"rekorLogId": 12345678
}
}
}]
}
```
---
## Fingerprinting Strategy
Fingerprints enable GitHub to deduplicate alerts across scans:
### Primary Fingerprint (stellaops/v1)
```
SHA-256(
ruleId + "|" +
component_purl + "|" +
vulnerability_id + "|" +
artifact_digest
)
```
### Partial Fingerprints (GitHub-computed fallback)
When source code is available, provide:
- `primaryLocationLineHash`: Hash of code at finding location
- `primaryLocationContextHash`: Hash of surrounding context
### Deduplication Behavior
| Scenario | GitHub Behavior |
|----------|----------------|
| Same fingerprint, new scan | Updates existing alert |
| New fingerprint | Creates new alert |
| Missing fingerprint in new scan | Closes alert as fixed |
| Fingerprint reappears | Reopens alert |
---
## GitHub Code Scanning API Integration
### Upload Endpoint
```
POST /repos/{owner}/{repo}/code-scanning/sarifs
```
### Request Format
```json
{
"commit_sha": "a1b2c3d4e5f6...",
"ref": "refs/heads/main",
"sarif": "",
"checkout_uri": "file:///home/runner/work/repo/repo",
"started_at": "2026-01-09T10:00:00Z",
"tool_name": "StellaOps Scanner"
}
```
### Response
```json
{
"id": "47177e22-5596-11eb-80a1-c1e54ef945c6",
"url": "https://api.github.com/repos/owner/repo/code-scanning/sarifs/47177e22-5596-11eb-80a1-c1e54ef945c6"
}
```
### Status Polling
```
GET /repos/{owner}/{repo}/code-scanning/sarifs/{sarif_id}
```
Response includes `processing_status`: `pending` | `complete` | `failed`
---
## GitHub Enterprise Server Support
The existing `GitHubAppConnectorPlugin` supports GHES:
```csharp
// Endpoint resolution
var apiBase = isEnterprise
? $"https://{hostname}/api/v3"
: "https://api.github.com";
```
### GHES Configuration
```yaml
# etc/integrations.yaml
github:
type: github_enterprise
hostname: github.mycompany.com
api_version: "2022-11-28"
app_id: 12345
private_key_path: /secrets/github-app.pem
```
---
## Important Gotchas
### 1. One Tool Per Run (June 2025 Deadline)
GitHub is deprecating combined runs. Each tool must have its own run:
```json
{
"runs": [
{ "tool": { "driver": { "name": "StellaOps Scanner" } }, "results": [...] },
{ "tool": { "driver": { "name": "StellaOps SmartDiff" } }, "results": [...] }
]
}
```
**Not:**
```json
{
"runs": [
{
"tool": { "driver": { "name": "StellaOps" } },
"results": [/* mixed scanner + smartdiff */]
}
]
}
```
### 2. Permissions
| Context | Required Permission |
|---------|---------------------|
| GitHub Actions | `security-events: write` |
| REST API (public) | `public_repo` scope |
| REST API (private) | `security_events` scope |
| GitHub App | `security_events: write` |
### 3. PR Uploads from Forks
- Direct API uploads from forks have restrictions
- Use `github/codeql-action/upload-sarif` action instead
- The action handles fork context correctly
### 4. SARIF Size Limits
| Limit | Value |
|-------|-------|
| Uncompressed | 10 MB |
| Compressed (gzip) | Recommended for API |
| Results per run | 10,000 (soft limit) |
### 5. Rate Limits
- 1000 requests/hour for Code Scanning API
- Use conditional requests (`If-None-Match`) where possible
---
## Integration Architecture
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ StellaOps Scanner │
│ ┌─────────────┐ ┌─────────────────┐ ┌─────────────────────────────┐ │
│ │ Scan Engine │──>│ Findings Ledger │──>│ SARIF Export Service │ │
│ └─────────────┘ └─────────────────┘ │ - FindingsSarifMapper │ │
│ │ - SarifRuleRegistry │ │
│ │ - FingerprintGenerator │ │
│ └─────────────┬───────────────┘ │
└─────────────────────────────────────────────────────────┼───────────────────┘
│
│ SARIF 2.1.0
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ GitHub Integration Service │
│ ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────┐ │
│ │ GitHubAppConnector │ │ CodeScanningClient │ │ SarifUploader │ │
│ │ (existing) │ │ (new) │ │ (new) │ │
│ └─────────────────────┘ └─────────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────┬───────────────────┘
│
│ REST API / Actions
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ GitHub Code Scanning │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────────┐ │
│ │ Security Tab │ │ PR Annotations │ │ Branch Protection │ │
│ │ Alerts │ │ Check Runs │ │ Rules │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## CLI Commands
### Scan with SARIF Output
```bash
# Basic scan with SARIF output
stella scan --image myapp:latest --format sarif --output results.sarif
# With severity filter
stella scan --image myapp:latest --format sarif --output results.sarif \
--min-severity high
# With reachability evidence
stella scan --image myapp:latest --format sarif --output results.sarif \
--include-reachability
# Pretty-printed for debugging
stella scan --image myapp:latest --format sarif --output results.sarif \
--pretty
```
### GitHub Upload
```bash
# Upload SARIF to GitHub Code Scanning
stella github upload-sarif \
--sarif results.sarif \
--repo owner/repo \
--ref refs/heads/main \
--sha $(git rev-parse HEAD)
# With GitHub Enterprise
stella github upload-sarif \
--sarif results.sarif \
--repo owner/repo \
--ref refs/heads/main \
--sha $(git rev-parse HEAD) \
--github-url https://github.mycompany.com
# Wait for processing
stella github upload-sarif \
--sarif results.sarif \
--repo owner/repo \
--wait --timeout 5m
```
### Generate Workflow
```bash
# Generate GitHub Actions workflow
stella github generate-workflow \
--repo owner/repo \
--output .github/workflows/stellaops-scan.yml \
--triggers push,pull_request,schedule \
--schedule "0 3 * * 1"
```
---
## Success Criteria
### Quantitative
| Metric | Target |
|--------|--------|
| SARIF schema validation | 100% pass rate |
| Upload success rate | > 99% |
| Processing time (1000 findings) | < 30 seconds |
| Fingerprint stability | 100% (same input = same fingerprint) |
### Qualitative
- Findings appear correctly in GitHub Security tab
- PR annotations show at correct line numbers
- Alert deduplication works across scans
- Branch protection rules can gate on scan results
---
## Related Documentation
- [SARIF 2.1.0 Specification (OASIS)](https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html)
- [GitHub SARIF Support](https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning)
- [GitHub Code Scanning REST API](https://docs.github.com/en/rest/code-scanning)
- [upload-sarif Action](https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github)
---
## Sprint Index
| Sprint ID | Title | Status |
|-----------|-------|--------|
| SPRINT_20260109_010_000 | INDEX: GitHub Code Scanning | Planning |
| SPRINT_20260109_010_001 | Findings SARIF Exporter | Planning |
| SPRINT_20260109_010_002 | GitHub Code Scanning Client | Planning |
| SPRINT_20260109_010_003 | CI/CD Workflow Templates | Planning |
---
_Last updated: 09-Jan-2026_