Skip to content

Harden degraded-mode contract coverage #768

Harden degraded-mode contract coverage

Harden degraded-mode contract coverage #768

Workflow file for this run

name: CI
on:
push:
branches: [main, develop]
pull_request:
workflow_dispatch:
jobs:
build:
name: build (${{ matrix.os }})
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- ubuntu-24.04
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang llvm libbpf-dev libsystemd-dev pkg-config cmake ninja-build python3-jsonschema libgtest-dev linux-tools-common linux-tools-$(uname -r) || sudo apt-get install -y clang llvm libbpf-dev libsystemd-dev pkg-config cmake ninja-build python3-jsonschema libgtest-dev linux-tools-common
- name: Configure
run: cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DSKIP_BPF_BUILD=ON
- name: Build
run: cmake --build build
- name: Binary-hardening contract
run: bash scripts/check_hardening.sh build/aegisbpf
test:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang llvm libbpf-dev libsystemd-dev pkg-config cmake ninja-build python3-jsonschema libgtest-dev linux-tools-common linux-tools-$(uname -r) || sudo apt-get install -y clang llvm libbpf-dev libsystemd-dev pkg-config cmake ninja-build python3-jsonschema libgtest-dev linux-tools-common
- name: Configure
run: cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -DSKIP_BPF_BUILD=ON
- name: Build
run: cmake --build build
- name: Run tests
run: ctest --test-dir build --output-on-failure --timeout 120
sanitizers:
name: sanitizers (${{ matrix.sanitizer }})
strategy:
fail-fast: false
matrix:
sanitizer:
- asan
- ubsan
- tsan
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang llvm libbpf-dev libsystemd-dev pkg-config cmake ninja-build linux-tools-common linux-tools-$(uname -r) || sudo apt-get install -y clang llvm libbpf-dev libsystemd-dev pkg-config cmake ninja-build linux-tools-common
- name: Configure with ${{ matrix.sanitizer }}
run: |
cmake -S . -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Debug \
-DBUILD_TESTING=ON \
-DBUILD_BENCHMARKS=OFF \
-DSKIP_BPF_BUILD=ON \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DENABLE_ASAN=${{ matrix.sanitizer == 'asan' && 'ON' || 'OFF' }} \
-DENABLE_UBSAN=${{ matrix.sanitizer == 'ubsan' && 'ON' || 'OFF' }} \
-DENABLE_TSAN=${{ matrix.sanitizer == 'tsan' && 'ON' || 'OFF' }}
- name: Build
run: cmake --build build
- name: Run tests with sanitizer
run: |
ctest --test-dir build --output-on-failure --timeout 300
env:
ASAN_OPTIONS: abort_on_error=1:halt_on_error=1
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
TSAN_OPTIONS: abort_on_error=1:halt_on_error=1
coverage:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang llvm libbpf-dev libsystemd-dev pkg-config cmake ninja-build gcovr python3-jsonschema libgtest-dev linux-tools-common linux-tools-$(uname -r) || sudo apt-get install -y clang llvm libbpf-dev libsystemd-dev pkg-config cmake ninja-build gcovr python3-jsonschema libgtest-dev linux-tools-common
- name: Configure with coverage
run: cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -DENABLE_COVERAGE=ON -DSKIP_BPF_BUILD=ON
- name: Build
run: cmake --build build
- name: Run tests
run: ctest --test-dir build --output-on-failure --timeout 120
- name: Load coverage thresholds
run: |
python3 - <<'PY'
import os
import json
cfg = json.load(open("config/coverage_thresholds.json", "r", encoding="utf-8"))
with open(os.environ["GITHUB_ENV"], "a", encoding="utf-8") as env:
env.write(f"COVERAGE_MIN_LINE={int(cfg['line_min'])}\n")
env.write(f"COVERAGE_MIN_BRANCH={int(cfg['branch_min'])}\n")
PY
- name: Generate coverage report
run: |
gcovr --root . --object-directory build --exclude tests --exclude build/_deps \
--merge-mode-functions=merge-use-line-min \
--print-summary \
--fail-under-line ${COVERAGE_MIN_LINE} \
--fail-under-branch ${COVERAGE_MIN_BRANCH} \
--xml coverage.xml \
--html coverage.html \
--html-details
- name: Upload coverage to Codecov
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
files: coverage.xml
flags: unittests
fail_ci_if_error: false
- name: Upload coverage HTML
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: coverage-report
path: coverage*.html
smoke-test:
runs-on: ubuntu-24.04
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang llvm libbpf-dev libsystemd-dev pkg-config cmake ninja-build linux-tools-common linux-tools-$(uname -r) || sudo apt-get install -y clang llvm libbpf-dev libsystemd-dev pkg-config cmake ninja-build linux-tools-common
- name: Check BPF LSM availability
id: check_lsm
run: |
if grep -q bpf /sys/kernel/security/lsm 2>/dev/null; then
echo "bpf_lsm=true" >> $GITHUB_OUTPUT
else
echo "bpf_lsm=false" >> $GITHUB_OUTPUT
fi
- name: Configure
run: cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF -DSKIP_BPF_BUILD=ON
- name: Build
run: cmake --build build
- name: Detect built BPF object
id: bpf_obj
run: |
if [[ -f build/aegis.bpf.o ]]; then
echo "present=true" >> "$GITHUB_OUTPUT"
else
echo "present=false" >> "$GITHUB_OUTPUT"
fi
- name: Run health check
if: steps.bpf_obj.outputs.present == 'true'
run: sudo ./build/aegisbpf health
- name: Skip health check when BPF object is not built
if: steps.bpf_obj.outputs.present != 'true'
run: echo "Skipping health check because SKIP_BPF_BUILD=ON (no build/aegis.bpf.o)."
- name: Run smoke test (audit mode)
if: steps.check_lsm.outputs.bpf_lsm == 'true' && steps.bpf_obj.outputs.present == 'true'
timeout-minutes: 1
run: |
sudo timeout 5 ./build/aegisbpf run --audit || true
echo "Smoke test completed"
build-arm64:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
- name: Build (arm64 via QEMU)
run: |
docker run --rm --platform linux/arm64 \
-v "$PWD":/src \
-v /sys:/sys:ro \
-w /src \
ubuntu:24.04 \
bash -lc "apt-get update && apt-get install -y clang llvm libbpf-dev libsystemd-dev pkg-config cmake ninja-build && cmake -S . -B build-arm64 -G Ninja -DBUILD_TESTING=OFF -DSKIP_BPF_BUILD=ON && cmake --build build-arm64"
lint:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang-format cppcheck
- name: Check clang-format
run: |
find src tests -name '*.cpp' -o -name '*.hpp' | xargs clang-format --dry-run --Werror
- name: Run cppcheck
run: |
cppcheck --std=c++20 --enable=all --error-exitcode=1 --inline-suppr \
--suppress=missingIncludeSystem \
--suppress=unmatchedSuppression \
--suppress=syntaxError:tests/test_commands.cpp \
--suppress=syntaxError:tests/test_kernel_features.cpp \
--suppress=syntaxError:tests/test_metrics.cpp \
--suppress=syntaxError:tests/test_tracing.cpp \
--suppress=syntaxError:tests/test_crypto_safe.cpp \
--suppress=syntaxError:tests/test_bpf_integrity.cpp \
--suppress=syntaxError:tests/test_bpf_signing.cpp \
--suppress=syntaxError:tests/test_exec_identity.cpp \
--suppress=syntaxError:tests/test_ocsf_formatter.cpp \
--suppress=syntaxError:tests/test_cef_formatter.cpp \
--suppress=syntaxError:tests/test_bpf_link_pin.cpp \
--suppress=syntaxError:tests/test_posture_gate.cpp \
--suppress=syntaxError:tests/bpf/test_bpf_prog_run.cpp \
--suppress=useStlAlgorithm \
--suppress=constParameterReference \
--suppress=constVariablePointer \
--suppress=knownConditionTrueFalse \
--suppress=unusedFunction \
--suppress=checkersReport \
--suppress=checkLevelNormal \
-I src \
src/ tests/
policy-tags:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Validate MITRE ATT&CK tag headers
run: ./scripts/validate_mitre_tags.sh
required-checks-contract:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y python3-yaml
- name: Validate required check definitions
run: |
python3 scripts/validate_required_checks.py \
--required config/required_checks.txt \
--required config/required_checks_release.txt
python3 scripts/validate_ci_workflow_policy.py
label-contract:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y python3-yaml
- name: Validate label contract
run: python3 scripts/validate_label_contract.py
capability-contract:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Validate capability posture contract
run: python3 scripts/validate_capability_posture_contract.py
enforcement-proof-contract:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Validate enforcement proof contract
run: python3 scripts/validate_enforcement_proof_contract.py
- name: Machine-checked enforcement proofs (Z3) + model-fidelity guard
run: proofs/run.sh
- name: Validate kernel-compat manifest is in sync with the source of truth
run: python3 scripts/gen_kernel_compat_manifest.py --check
- name: Validate bpfcompat manifest is in sync with the BPF source
run: python3 scripts/gen_bpfcompat_manifest.py --check
helm-posture-contract:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Validate Helm posture contract
run: python3 tests/check_helm_posture_contract.py
ops-observability-contract:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Validate ops observability contract
run: |
python3 scripts/validate_grafana_dashboard.py config/grafana/aegisbpf-ops-minimal.json
python3 tests/check_ops_observability_contract.py
k8s-rollout-contract:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Validate Kubernetes rollout contract
run: python3 tests/check_k8s_rollout_contract.py
guarantees-contract:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Validate enforcement guarantees contract
run: python3 tests/check_guarantees_contract.py
clang-tidy:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang-tidy clang llvm libbpf-dev libsystemd-dev pkg-config cmake ninja-build libgtest-dev libbenchmark-dev
- name: Configure
run: cmake -S . -B build-clang-tidy -G Ninja -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -DSKIP_BPF_BUILD=ON
- name: Run clang-tidy on changed files
env:
BASE_REF: ${{ github.base_ref }}
DIFF_RANGE: ${{ github.event_name == 'push' && format('{0}...{1}', github.event.before, github.sha) || '' }}
BUILD_DIR: build-clang-tidy
run: scripts/run_clang_tidy_changed.sh
smoke-fuzz:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang llvm libbpf-dev pkg-config cmake ninja-build
- name: Configure with fuzzing
env:
CC: clang
CXX: clang++
run: cmake -S . -B build-fuzz -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_FUZZING=ON -DBUILD_TESTING=OFF -DSKIP_BPF_BUILD=ON
- name: Build fuzz targets
run: cmake --build build-fuzz --target fuzz_policy fuzz_bundle fuzz_network fuzz_path fuzz_event
- name: Smoke fuzz (60s per target, seeded corpus)
run: |
# Use a writable copy of the seed corpus so libFuzzer can add
# discovered inputs during the run without modifying the tree.
for target in fuzz_policy fuzz_bundle fuzz_network fuzz_path fuzz_event; do
echo "Fuzzing ${target}..."
runtime_corpus="$(mktemp -d)/${target}"
mkdir -p "${runtime_corpus}"
if [ -d "tests/fuzz/corpus/${target}" ]; then
cp -a "tests/fuzz/corpus/${target}/." "${runtime_corpus}/"
fi
# fuzz_event prints JSON to stdout for every mutation; silence it
# so CI logs stay readable. libFuzzer stats go to stderr.
if [ "${target}" = "fuzz_event" ]; then
./build-fuzz/${target} "${runtime_corpus}" -max_total_time=60 -print_final_stats=1 >/dev/null
else
./build-fuzz/${target} "${runtime_corpus}" -max_total_time=60 -print_final_stats=1
fi
done
- name: Upload fuzz crash artifacts
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fuzz-crashes
path: |
crash-*
build-fuzz/crash-*
parser-fuzz:
runs-on: ubuntu-24.04
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang llvm libbpf-dev pkg-config cmake ninja-build
- name: Configure with fuzzing
env:
CC: clang
CXX: clang++
run: cmake -S . -B build-fuzz -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_FUZZING=ON -DBUILD_TESTING=OFF -DSKIP_BPF_BUILD=ON
- name: Build parser fuzz targets
run: cmake --build build-fuzz --target fuzz_policy fuzz_bundle fuzz_network fuzz_path fuzz_event
- name: Run parser fuzz gate on changed files
env:
BASE_REF: ${{ github.base_ref }}
DIFF_RANGE: ${{ github.event_name == 'push' && format('{0}...{1}', github.event.before, github.sha) || '' }}
BUILD_DIR: build-fuzz
FUZZ_SECONDS: "120"
run: scripts/run_parser_fuzz_changed.sh
sbom:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Generate SBOM
uses: anchore/sbom-action@d94f46e13c6c62f59525ac9a1e147a99dc0b9bf5 # v0.17.0
with:
format: spdx-json
output-file: sbom.spdx.json
- name: Upload SBOM
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sbom
path: sbom.spdx.json