Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/codeql/codeql-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: openswmm.engine CodeQL config

# security-extended adds higher-precision security queries beyond the
# default suite without pulling in the style/quality noise from
# security-and-quality. Adjust here if signal-to-noise needs tuning.
queries:
- uses: security-extended

paths-ignore:
# ── EPA SWMM 5.x legacy tree ──────────────────────────────────────────
# The legacy C solver, output reader, and CLI must remain byte-for-byte
# identical to the upstream EPA reference to preserve the regression
# baseline (see src/legacy/engine/CMakeLists.txt). CodeQL findings here
# cannot be acted on, so we exclude the whole tree to keep the alert
# list focused on the new C++20 engine and Python bindings.
- src/legacy/**

# ── Generated / build outputs ─────────────────────────────────────────
- build*/**
- cmake-build*/**
- python/build/**
- "**/_export.h"
- "**/legacy_version.h"
- "**/version.h"

# ── Test data and golden files (not code) ─────────────────────────────
- tests/regression/data/**
- tests/regression_testing/results/**
- tests/unit/**/data/**

# ── Vendored third-party (if ever checked in) ─────────────────────────
- vcpkg/**
- vcpkg_installed/**

# ── Non-code ──────────────────────────────────────────────────────────
- docs/**
- paper/**
109 changes: 109 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: CodeQL

on:
push:
branches: [main, develop, swmm6_rel]
pull_request:
branches: [main, develop, swmm6_rel]
schedule:
# Weekly scan so newly disclosed CWE queries hit dormant branches too.
# Mondays at 06:00 UTC — outside US-business hours but before EU-morning.
- cron: "0 6 * * 1"
workflow_dispatch:

env:
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"

jobs:
analyze:
name: Analyze (${{ matrix.language }})
runs-on: ubuntu-latest
timeout-minutes: 60
permissions:
actions: read
contents: read
security-events: write

strategy:
fail-fast: false
matrix:
include:
# C/C++ requires a real compile so CodeQL can hook every translation unit.
- language: c-cpp
build-mode: manual
# Python is scanned from source — no build needed.
- language: python
build-mode: none

steps:
- name: Checkout repository
uses: actions/checkout@v5

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
config-file: ./.github/codeql/codeql-config.yml

# ── C/C++ build pipeline (mirrors unit_testing.yml) ────────────────
- name: Checkout vcpkg
if: matrix.language == 'c-cpp'
uses: actions/checkout@v5
with:
repository: microsoft/vcpkg
ref: 2025.02.14
path: vcpkg

- name: Install Ninja
if: matrix.language == 'c-cpp'
run: sudo apt-get update && sudo apt-get install -y ninja-build

- name: Bootstrap vcpkg
if: matrix.language == 'c-cpp'
working-directory: ${{ env.VCPKG_ROOT }}
run: |
./bootstrap-vcpkg.sh
chmod +x vcpkg

- name: Export GitHub Actions cache variables
if: matrix.language == 'c-cpp'
uses: actions/github-script@v8
with:
script: |
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');

- name: Cache vcpkg downloads (source tarballs)
if: matrix.language == 'c-cpp'
uses: actions/cache@v4
with:
path: ${{ env.VCPKG_ROOT }}/downloads
key: vcpkg-downloads-codeql-${{ hashFiles('vcpkg.json') }}
restore-keys: |
vcpkg-downloads-codeql-
vcpkg-downloads-Linux-x64-linux-

# Tests are off by default — CodeQL needs the engine libs compiled,
# not the test exes, so we skip them to keep the analysis window tight.
- name: Configure
if: matrix.language == 'c-cpp'
run: >
cmake
--preset=Linux-debug
-B build-codeql
-DOPENSWMM_BUILD_TESTS=OFF
-DOPENSWMM_BUILD_UNIT_TESTS=OFF
-DOPENSWMM_BUILD_REGRESSION_TESTS=OFF
-DOPENSWMM_BUILD_BENCHMARKS=OFF
-DOPENSWMM_BUILD_PYTHON=OFF

- name: Build
if: matrix.language == 'c-cpp'
run: cmake --build build-codeql --config Debug

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{ matrix.language }}"
15 changes: 12 additions & 3 deletions .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ name: Documentation
on:
push:
branches: [main, develop, swmm6_rel]
# branches: [main, develop]
tags: ["v*.*.*"]
pull_request:
branches: [main]
branches: [main, develop, swmm6_rel]
workflow_dispatch:

# Allow only one concurrent deployment. Do NOT cancel in-progress runs so
Expand Down Expand Up @@ -95,7 +94,17 @@ jobs:
# ─────────────────────────────────────────────────────────────────────────────
deploy:
name: Deploy to GitHub Pages
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/swmm6_rel')
# Deploys fire on direct pushes to a whitelisted branch and on manual
# workflow_dispatch runs targeting one of those same branches. PR events
# are intentionally excluded — PR builds verify the docs compile but must
# not overwrite the live Pages site. To preview a PR, push the source
# branch (swmm6_rel) or dispatch the workflow manually against it from
# the Actions tab.
if: |
(github.event_name == 'push' || github.event_name == 'workflow_dispatch')
&& (github.ref == 'refs/heads/main'
|| github.ref == 'refs/heads/develop'
|| github.ref == 'refs/heads/swmm6_rel')
needs: [build_python_docs, build_doxygen_docs]
runs-on: ubuntu-latest
permissions:
Expand Down
42 changes: 36 additions & 6 deletions .github/workflows/regression_testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ name: Regression Testing
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]

workflow_dispatch:

env:
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
# Pull only what the regression-test build needs: default features (2d) + tests.
VCPKG_MANIFEST_FEATURES: "tests"
OMP_NUM_THREADS: 1

jobs:
Expand Down Expand Up @@ -59,6 +60,10 @@ jobs:
ref: 2025.02.14
path: vcpkg

- name: Install OpenMP (macOS)
if: runner.os == 'macOS'
run: brew install libomp

- name: Install Ninja (Linux)
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y ninja-build
Expand Down Expand Up @@ -104,13 +109,14 @@ jobs:
python -m pip install pytest numpy

- name: Configure
# The *-tests preset sets VCPKG_MANIFEST_FEATURES=tests and enables
# both OPENSWMM_BUILD_UNIT_TESTS and OPENSWMM_BUILD_REGRESSION_TESTS
# as CMake cache vars (env-var-only propagation isn't honored by the
# vcpkg toolchain at configure time).
run: >
cmake
--preset=${{ matrix.cmake_preset }}-debug
--preset=${{ matrix.cmake_preset }}-tests
-B build-${{ matrix.vcpkg_triplet }}
-DOPENSWMM_BUILD_TESTS=OFF
-DOPENSWMM_BUILD_UNIT_TESTS=ON
-DOPENSWMM_BUILD_REGRESSION_TESTS=ON
-DCMAKE_OSX_ARCHITECTURES=${{ matrix.cmake_osx_arch }}

- name: Build
Expand All @@ -119,11 +125,34 @@ jobs:
- name: Unit tests (sanity check)
run: ctest --test-dir build-${{ matrix.vcpkg_triplet }} -C Debug -L unit --output-on-failure

- name: Diagnose Linux unit-test segfaults (gdb)
if: failure() && runner.os == 'Linux'
working-directory: tests/unit/legacy/engine/data
run: |
sudo apt-get install -y gdb
for t in test_solver_api test_solver_errors test_solver_hotstart test_solver_shapes test_solver_expanded_api; do
bin=$(find ${{ github.workspace }}/build-${{ matrix.vcpkg_triplet }} -name "$t" -type f -executable | head -1)
if [ -z "$bin" ]; then echo "Binary $t not found"; continue; fi
echo "==================================================="
echo "==== gdb backtrace: $t"
echo "==================================================="
gdb -batch \
-ex 'set pagination off' \
-ex 'set confirm off' \
-ex 'handle SIGSEGV stop print nopass' \
-ex run \
-ex 'thread apply all bt full' \
-ex quit \
"$bin" 2>&1 | head -400 || true
done

- name: C++ regression tests
run: ctest --test-dir build-${{ matrix.vcpkg_triplet }} -C Debug -L regression --output-on-failure

- name: Python regression tests
working-directory: tests/regression_testing
env:
OPENSWMM_BUILD_DIR: ${{ github.workspace }}/build-${{ matrix.vcpkg_triplet }}
run: python -m pytest -v --tb=short

- name: Upload artifacts
Expand All @@ -132,3 +161,4 @@ jobs:
with:
name: regression-${{ matrix.vcpkg_triplet }}
path: tests/regression_testing/results/
if-no-files-found: ignore
59 changes: 59 additions & 0 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Scorecard supply-chain security

on:
# Some checks (branch protection, code review enforcement) only run when
# the workflow is triggered by a branch-protection-rule change.
branch_protection_rule:
# Weekly scan so new scorecard checks land here as they ship.
schedule:
- cron: "20 7 * * 1"
push:
branches: ["develop"]
workflow_dispatch:

permissions: read-all

jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
# Needed to upload the SARIF results to Security > Code scanning.
security-events: write
# Needed to publish the score to the OpenSSF Scorecard API and to
# mint short-lived OIDC tokens that prove the run came from this repo.
id-token: write
# Read access only — no write to repo contents.
contents: read
actions: read

steps:
- name: Checkout
uses: actions/checkout@v5
with:
persist-credentials: false

- name: Run analysis
uses: ossf/scorecard-action@v2.4.1
with:
results_file: results.sarif
results_format: sarif
# publish_results uploads the score to securityscorecards.dev so
# the README badge and the public dashboard stay current. Toggle
# to false if you'd rather keep results internal to this repo.
publish_results: true

# Persist the SARIF for 5 days so it can be downloaded and inspected
# outside the GitHub Security tab.
- name: Upload artifact
uses: actions/upload-artifact@v5
with:
name: SARIF file
path: results.sarif
retention-days: 5

# Surface findings in Security > Code scanning alongside CodeQL.
- name: Upload to code scanning
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
30 changes: 26 additions & 4 deletions .github/workflows/unit_testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ name: Unit Testing

on:
push:
branches: [master, main, develop]
branches: [main, develop]
pull_request:
branches: [master, main, develop]
branches: [main, develop]

env:
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
VCPKG_EXE: ${{ github.workspace }}/vcpkg/vcpkg
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
# Pull only what the unit-test build needs: default features (2d) + tests.
VCPKG_MANIFEST_FEATURES: "tests"
# Note: the vcpkg `tests` feature is enabled via -DVCPKG_MANIFEST_FEATURES on
# the Configure step below; the env-var form isn't honored by the vcpkg
# toolchain at CMake configure time.
OMP_NUM_THREADS: 1

jobs:
Expand Down Expand Up @@ -121,6 +122,27 @@ jobs:
- name: Unit tests
run: ctest --test-dir build-${{ matrix.vcpkg_triplet }} -C Debug -L unit --output-on-failure

- name: Diagnose Linux unit-test segfaults (gdb)
if: failure() && runner.os == 'Linux'
working-directory: tests/unit/legacy/engine/data
run: |
sudo apt-get install -y gdb
for t in test_solver_api test_solver_errors test_solver_hotstart test_solver_shapes test_solver_expanded_api; do
bin=$(find ${{ github.workspace }}/build-${{ matrix.vcpkg_triplet }} -name "$t" -type f -executable | head -1)
if [ -z "$bin" ]; then echo "Binary $t not found"; continue; fi
echo "==================================================="
echo "==== gdb backtrace: $t"
echo "==================================================="
gdb -batch \
-ex 'set pagination off' \
-ex 'set confirm off' \
-ex 'handle SIGSEGV stop print nopass' \
-ex run \
-ex 'thread apply all bt full' \
-ex quit \
"$bin" 2>&1 | head -400 || true
done

- name: Package
run: cmake --build build-${{ matrix.vcpkg_triplet }} --target package

Expand Down
Loading
Loading