# 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_