Skip to content

ci: add CodeQL + SonarQube Cloud security scanning - #268

Open
jl-0 wants to merge 1 commit into
masterfrom
feature/sonarcloud-security-scan
Open

ci: add CodeQL + SonarQube Cloud security scanning#268
jl-0 wants to merge 1 commit into
masterfrom
feature/sonarcloud-security-scan

Conversation

@jl-0

@jl-0 jl-0 commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Adds workflow-based CodeQL + SonarQube Cloud scanning, following the AMMOS scanning guide and matching the setup on MMGIS and astria_ui. CI configuration only — no application code is touched.

Pipeline

CodeQL → nasa-scrub translate_results → fix_sarif_paths.py → sonarqube-scan-action

nasa-scrub is the step the AMMOS guide prescribes, but it is lossy in two ways that break the SonarQube import:

  1. It rewrites CodeQL's workspace-relative URIs to absolute paths and writes the absolute source root into uriBaseId, so SonarQube cannot map findings to files — everything collapses to project-level "unable to resolve issue location".
  2. It deletes tool.extensions, where CodeQL keeps its real query metadata, and rebuilds tool.driver.rules as id-only stubs — so every finding imports as MEDIUM regardless of true severity, under a rule key named after the input file rather than CodeQL.

.github/scripts/fix_sarif_paths.py repairs both from the pre-scrub report. It keeps the guide's pipeline intact while making the import correct, and ships with a 24-case unit suite (python3 .github/scripts/test_fix_sarif_paths.py).

Verified end to end

Run 34523549184 is green and its results are on master in SonarQube Cloud. The seven imported findings confirm all three repairs:

evidence
paths findings map to real files and line numbers
rule keys external_CodeQL:*, not external_python:* / external_javascript:*
severities CRITICAL / MAJOR, not a flat MEDIUM
external_CodeQL:py/path-injection      CRITICAL  ait/gui/__init__.py:990, 1190, 1194
external_CodeQL:py/reflective-xss      CRITICAL  ait/gui/__init__.py:741
external_CodeQL:js/unvalidated-dynamic-method-call  MAJOR  ait/gui/openmct_adapter/ait_integration.js:169
external_CodeQL:js/useless-regexp-character-escape  CRITICAL  ait/gui/static/js/ait/evr.js:131

Those findings are pre-existing and are not addressed here — this PR only turns on the scanning that surfaces them.

Scope

CodeQL analyzes python, javascript-typescript and actions in a single run. Both halves of the application are in scope: ait/gui/__init__.py (the bottle server holding the command, telemetry, sequence, script and file endpoints), ait/gui/static/js (the Mithril front end), and ait/gui/openmct_adapter.

Skipped, with reasons:

path why
ait/gui/static/build/** webpack output — the same source as static/js plus its npm deps, so scanning it double-reports every front-end finding and pulls vendored code into LOC
ait/gui/static/css, static/fonts, *.svg, *.png not code
doc/** Sphinx pages and a conf.py that is not shipped
tests/**, ait/gui/static/test/** the Python and mocha suites
**/package-lock.json, **/node_modules/** covered by Dependabot

.github/ is a Sonar source so CodeQL's actions findings have files to attach to.

Notes for the reviewer

  • sonar.branch.name is pinned to master. Leaving it unset does not publish into the project's main analysis — this project is ALM-bound to GitHub, so the scanner auto-detects the branch from the Actions environment and creates a short-lived SonarQube branch (observed on run 34522749731, since deleted). Switch to ${{ github.ref_name }} when per-branch attribution is wanted.
  • CodeQL default setup had to be disabled on this repo; advanced configurations cannot upload while it is on. This workflow replaces that coverage with a richer query suite (security-extended) and the shared path exclusions.
  • SonarCloud Automatic Analysis had to be disabled for NASA-AMMOS_AIT-GUI; it cannot coexist with CI analysis and cannot import CodeQL SARIF.
  • The workflow triggers on push to master and on manual dispatch.

https://claude.ai/code/session_01Bv21RHa8B3VAfPkBLU5M11

Adds the AMMOS-guide scanning pipeline, in the shape worked out for MMGIS
and astria_ui:

    CodeQL -> nasa-scrub translate_results -> fix_sarif_paths.py
           -> sonarqube-scan-action

scrub is the step the AMMOS guide prescribes, but it is lossy: it
rewrites CodeQL's relative URIs to absolute paths and puts the absolute
source root in uriBaseId, so SonarQube cannot map findings to files; and
it drops tool.extensions -- where CodeQL keeps its real query metadata --
rebuilding driver.rules as id-only stubs, so every finding imports as
MEDIUM. fix_sarif_paths.py repairs both from the pre-scrub report, which
keeps the guide's pipeline intact while making the import correct.

Verified on run 34523549184: the seven imported findings carry
external_CodeQL rule keys rather than external_python/external_javascript,
CRITICAL and MAJOR severities rather than a flat MEDIUM, and real file
paths and line numbers -- so all three repairs are doing their job.

CodeQL runs python, javascript-typescript and actions: AIT-GUI is both a
bottle server and a Mithril front end, and both halves are in scope. The
server in ait/gui/__init__.py holds the command, telemetry, sequence,
script and file endpoints; ait/gui/static/js renders telemetry into the
DOM; ait/gui/openmct_adapter is the OpenMCT integration.

ait/gui/static/build/ is excluded from both configs. It is the webpack
output -- the same front-end source as static/js concatenated with its npm
dependencies -- so scanning it would double-report every finding in js/
and add a large body of vendored library code that Dependabot covers.
Fonts, stylesheets under static/css, the Sphinx tree in doc/, the Python
suite in tests/ and the mocha suite in static/test are also left out.

sonar.branch.name is pinned to master while the pipeline is validated.
Leaving it unset does not publish into the project's main analysis: these
projects are ALM-bound to GitHub, so the scanner auto-detects the branch
from the Actions environment and creates a short-lived SonarQube Cloud
branch named after the git branch (measured on run 34522749731).
Switch to ${{ github.ref_name }} once scans should be attributed to the
branch actually analyzed.

The workflow triggers on push to master and on manual dispatch. The
bootstrap trigger used to run the first scan from this branch has been
removed now that the pipeline is validated.

Claude-Session: https://claude.ai/code/session_01Bv21RHa8B3VAfPkBLU5M11
@jl-0
jl-0 requested review from a team as code owners September 10, 2026 21:04
@EmilyPascua
EmilyPascua self-requested a review September 10, 2026 21:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant