Skip to content

feat: Add SARIF output format for GitHub Code Scanning#33

Merged
fummicc1 merged 3 commits into
mainfrom
feature/sarif-output-format
Jul 5, 2026
Merged

feat: Add SARIF output format for GitHub Code Scanning#33
fummicc1 merged 3 commits into
mainfrom
feature/sarif-output-format

Conversation

@fummicc1

@fummicc1 fummicc1 commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a new -f sarif output format producing a SARIF 2.1.0 report, so CI pipelines can surface complexity violations as inline PR annotations and Security-tab alerts via GitHub Code Scanning — without swift-complexity implementing its own PR integration.

This is the first step of the "Now" roadmap (CI adoption in 5 minutes); an official GitHub Action building on this format will follow in a separate PR.

Changes

  • New sarif case in OutputFormat + SARIFReport.swift with a minimal internal Codable model of SARIF 2.1.0
  • One result per violated metric (cyclomatic_complexity, cognitive_complexity, lcom4_cohesion) so each annotation is actionable on its own
  • Exit-code consistency: violation detection reuses ThresholdConfiguration.isExceeded (>= semantics), so a non-empty results array always coincides with exit code 1
  • Severity: warning when a metric reaches the threshold, error at twice the threshold (mirrors the Xcode diagnostics convention); LCOM4 mirrors the existing cohesion diagnostic rule (low cohesion → warning, LCOM4 >= 5 → error)
  • Repository-relative URIs: absolute paths under the working directory are relativized, as required by Code Scanning
  • SwiftComplexityVersion: new single source of truth for the version string; the CLI and MCP server previously hardcoded "1.0.0" in two places, and SARIF needs the same value for tool.driver.version
  • stderr warning when -f sarif is used without --threshold/config, since the report would otherwise be silently empty
  • Docs: SARIF (and previously undocumented Xcode) sections in output-formats.md, README examples with an upload-sarif workflow snippet

Verification

  • swift test: 86 tests pass, including 3 new SARIF tests (per-metric results & severity, empty-without-threshold, LCOM4 cohesion)
  • E2E: swift-complexity Sources -f sarif -t 8 -r produced 12 results with correct rule ids, levels, relative URIs, and line numbers, and exited with code 1; violation-free input produced an empty results array and exit 0
  • swift-format clean via lefthook pre-commit

https://claude.ai/code/session_01GaTHVDhSAx76RbLmVziLQu

Add `-f sarif` producing a SARIF 2.1.0 report so CI pipelines can surface
complexity violations as inline PR annotations via GitHub Code Scanning,
without swift-complexity having to implement its own PR integration.

- One SARIF result per violated metric (cyclomatic_complexity,
  cognitive_complexity, lcom4_cohesion) so annotations stay actionable
- Violation detection reuses ThresholdConfiguration.isExceeded (>=
  semantics), guaranteeing the results array and exit code 1 always agree
- warning level escalates to error at twice the threshold, mirroring the
  Xcode diagnostics convention
- File URIs are relativized to the working directory because Code
  Scanning requires repository-relative paths
- Introduce SwiftComplexityVersion as the single version constant; the
  CLI and MCP server previously hardcoded "1.0.0" separately and SARIF
  needs the same value for tool.driver.version
- Warn on stderr when sarif is selected without any threshold, since the
  report would otherwise be silently empty

Claude-Session: https://claude.ai/code/session_01GaTHVDhSAx76RbLmVziLQu
@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown

📊 PR Analysis

Type Count
Swift files 8
Test files 2
Documentation 2
Configuration 0

📝 Large PR: Consider breaking this into smaller, focused PRs.


Automated analysis by swift-complexity CI

@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown

🔍 Complexity Analysis Results

✅ All functions are below the complexity threshold of 15.

This analysis was performed by swift-complexity itself.

Scoped to this branch only (push trigger on
feature/sarif-output-format) so it does not touch the main CI path.
Builds the release binary, generates a SARIF report with a low
threshold to guarantee visible violations, and uploads it via
github/codeql-action/upload-sarif to confirm GitHub Code Scanning
renders inline PR annotations for the new -f sarif output.

This workflow will be removed once annotations are confirmed.

Claude-Session: https://claude.ai/code/session_01GaTHVDhSAx76RbLmVziLQu
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown

📊 PR Analysis

Type Count
Swift files 8
Test files 2
Documentation 2
Configuration 1

📝 Large PR: Consider breaking this into smaller, focused PRs.


Automated analysis by swift-complexity CI

@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

/// Builds one SARIF result per metric that reaches its effective threshold,
/// using the same `>=` semantics as the CLI exit-code check so annotations
/// and CI failures always agree.
private func complexityResults(
}

/// Mirrors the Xcode diagnostics severity convention for LCOM4.
private func cohesionResults(for result: ComplexityResult) -> [SARIFResult] {

/// GitHub Code Scanning expects URIs relative to the repository root, so
/// absolute paths under the current working directory are relativized.
private func relativizedURI(for filePath: String) -> String {
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown

🔍 Complexity Analysis Results

✅ All functions are below the complexity threshold of 15.

This analysis was performed by swift-complexity itself.

The workflow confirmed that GitHub Code Scanning correctly renders
inline PR annotations for swift-complexity's SARIF output: with a low
threshold, the check run's annotations were correctly scoped to the
3 violations inside SARIFReport.swift (the file this PR actually
changes), out of 102 total alerts detected across the wider tree.
No longer needed now that annotation rendering is verified.

Claude-Session: https://claude.ai/code/session_01GaTHVDhSAx76RbLmVziLQu
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown

📊 PR Analysis

Type Count
Swift files 8
Test files 2
Documentation 2
Configuration 0

📝 Large PR: Consider breaking this into smaller, focused PRs.


Automated analysis by swift-complexity CI

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown

🔍 Complexity Analysis Results

✅ All functions are below the complexity threshold of 15.

This analysis was performed by swift-complexity itself.

@fummicc1
fummicc1 merged commit 39bee78 into main Jul 5, 2026
7 checks passed
@fummicc1
fummicc1 deleted the feature/sarif-output-format branch July 5, 2026 17:05
@fummicc1 fummicc1 added the enhancement New feature or improvement label Jul 18, 2026
fummicc1 added a commit that referenced this pull request Jul 18, 2026
Release includes SARIF output format (#33) and inline suppression
comments (#35).

Claude-Session: https://claude.ai/code/session_01GaTHVDhSAx76RbLmVziLQu
fummicc1 added a commit that referenced this pull request Jul 23, 2026
* feat: Add official GitHub Action and CI integration guide

Add a composite action at the repository root so CI adoption becomes a
single `uses:` step instead of hand-rolling binary download, checksum
verification, and SARIF wiring in every project. Completes the CI
adoption path started with SARIF output (#33): action -> SARIF ->
upload-sarif -> inline PR annotations.

Action design:
- Downloads the release binary for the runner platform (macOS
  arm64/x86_64, Linux x86_64), verifies its published sha256, and runs
  the analysis; "latest" resolves through the GitHub API using the
  workflow token to avoid rate limits.
- SARIF by default with threshold 10, because without any threshold the
  report is silently empty; an empty threshold input supports
  config-file-driven setups.
- fail-on-threshold=false ignores exit code 1 for report-only setups,
  while other non-zero exits always fail. The SARIF upload itself is
  deliberately left to github/codeql-action/upload-sarif in the caller's
  workflow, keeping security-events write permission out of this action.
- Docs pin to an exact release tag rather than a moving major tag (v1):
  release.yml triggers on any v* tag and derives the version from the
  tag name without validation, so pushing a bare v1 tag would start a
  bogus release. Major-tag automation needs a trigger guard first and is
  left as a follow-up.

The new action-test CI job runs the action from the local checkout
(uses: ./) on both macOS and Ubuntu against a pinned released version,
then validates the generated SARIF structure with jq - this is the E2E
test for the download/verify/run path on both platforms.

Claude-Session: https://claude.ai/code/session_01GaTHVDhSAx76RbLmVziLQu

* fix: Statically link Swift stdlib on Linux and fix action-test

The action-test job exposed that Linux release binaries are dynamically
linked against the Swift runtime: they fail with a libswiftCore.so
loading error on any machine without a Swift toolchain, which defeats
the action's promise of toolchain-free CI (and equally affects direct
binary downloads and nest installs on Linux).

- release.yml: build Linux binaries with --static-swift-stdlib so
  future releases are self-contained.
- ci.yml (test job): use the same flag for the Linux build so static
  linking breakage is caught on every PR instead of at release time.
- ci.yml (action-test): run the Linux leg in a swift:6.2-jammy
  container as a temporary measure, because the pinned v1.1.0 binaries
  are still dynamic; a comment marks it for removal once a static
  release ships. Also set fail-fast: false - the macOS leg had actually
  passed end-to-end but was cancelled when the Linux leg failed.

Claude-Session: https://claude.ai/code/session_01GaTHVDhSAx76RbLmVziLQu

* fix: Point the loader at the container's Swift runtime in action-test

The swift:6.2-jammy container does ship the runtime at
/usr/lib/swift/linux, but the v1.1.0 binary embeds a runpath from its
build machine (a swiftly toolchain path), so the loader never looks
there. Set LD_LIBRARY_PATH on the action step; this lives inside the
same temporary block that goes away once a --static-swift-stdlib
release ships.

Claude-Session: https://claude.ai/code/session_01GaTHVDhSAx76RbLmVziLQu
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants