diff --git a/.github/actions/build-spine/action.yml b/.github/actions/build-spine/action.yml new file mode 100644 index 00000000..3a0897f1 --- /dev/null +++ b/.github/actions/build-spine/action.yml @@ -0,0 +1,60 @@ +name: Build Spine +description: Install the build dependencies, then bootstrap and configure Spine. + +inputs: + extra-packages: + description: Additional apt packages, beyond the set every Spine build needs. + required: false + default: '' + configure-args: + description: Arguments passed through to ./configure. + required: false + default: '' + cflags: + description: CFLAGS for ./configure. + required: false + default: '' + ldflags: + description: LDFLAGS for ./configure. + required: false + default: '' + +runs: + using: composite + steps: + # mysql-server is deliberately absent: configure only looks for mysql.h and + # libmysqlclient, both of which come from libmysqlclient-dev, and no job + # starts or connects to a server. + - name: Install build dependencies + shell: bash + env: + EXTRA_PACKAGES: ${{ inputs.extra-packages }} + run: | + set -euo pipefail + sudo apt-get update + # shellcheck disable=SC2086 + sudo apt-get install -y \ + autoconf automake libtool build-essential help2man dos2unix \ + libmysqlclient-dev libsnmp-dev libssl-dev libcmocka-dev \ + $EXTRA_PACKAGES + + - name: Bootstrap and configure + shell: bash + env: + CONFIGURE_ARGS: ${{ inputs.configure-args }} + IN_CFLAGS: ${{ inputs.cflags }} + IN_LDFLAGS: ${{ inputs.ldflags }} + run: | + set -euo pipefail + ./bootstrap + args=() + if [ -n "$CONFIGURE_ARGS" ]; then + read -ra args <<< "$CONFIGURE_ARGS" + fi + if [ -n "$IN_CFLAGS" ]; then + args+=("CFLAGS=$IN_CFLAGS") + fi + if [ -n "$IN_LDFLAGS" ]; then + args+=("LDFLAGS=$IN_LDFLAGS") + fi + ./configure ${args[@]+"${args[@]}"} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c317e160..dcfa1747 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,23 +24,15 @@ jobs: env: CC: ${{ matrix.compiler }} steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Install build dependencies - run: | - sudo apt-get update - sudo apt-get install -y \ - mysql-server libmysqlclient-dev \ - libsnmp-dev libssl-dev build-essential \ - help2man autoconf automake libtool dos2unix libcmocka-dev - - - name: Prepare for Spine Build - run: | - ./bootstrap - ./configure --enable-warnings + - uses: ./.github/actions/build-spine + with: + configure-args: --enable-warnings - name: Build Spine run: | + set -euo pipefail make -j"$(nproc)" - name: Run the unit tests @@ -48,58 +40,29 @@ jobs: set -euo pipefail make check -# cppcheck: -# runs-on: ubuntu-latest -# steps: -# - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 -# -# - name: Install cppcheck -# run: | -# sudo apt-get update -# sudo apt-get install -y cppcheck build-essential -# -# - name: Run cppcheck -# run: | -# cppcheck \ -# --enable=all \ -# --std=c11 \ -# --error-exitcode=1 \ -# --suppress=missingIncludeSystem \ -# --suppress=unusedFunction \ -# --suppress=checkersReport \ -# --suppress=variableScope \ -# --suppress=unreadVariable \ -# --suppress=shadowVariable \ -# --suppress=constVariablePointer \ -# --suppress=redundantAssignment \ -# --suppress=toomanyconfigs \ -# *.c *.h - # Coverage is reported, not gated. The number is only meaningful once # something measures it; the threshold conversation comes after that. coverage: runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Install build dependencies - run: | - set -euo pipefail - sudo apt-get update - sudo apt-get install -y mysql-server libmysqlclient-dev libsnmp-dev \ - libssl-dev build-essential help2man autoconf automake libtool \ - dos2unix libcmocka-dev gcovr + - uses: ./.github/actions/build-spine + with: + extra-packages: gcovr + cflags: -g -O0 --coverage + ldflags: --coverage - name: Build instrumented run: | set -euo pipefail - ./bootstrap - ./configure CFLAGS="-g -O0 --coverage" LDFLAGS="--coverage" make -j"$(nproc)" - name: Run the unit tests - run: make check + run: | + set -euo pipefail + make check - name: Report coverage run: | @@ -113,9 +76,9 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.x" @@ -127,6 +90,7 @@ jobs: # informational so we have a baseline to chip away at. - name: Run flawfinder run: | + set -euo pipefail flawfinder \ --minlevel=3 \ --error-level=5 \ @@ -134,64 +98,58 @@ jobs: --context \ . | tee flawfinder-report.txt - - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: always() with: name: flawfinder-report path: flawfinder-report.txt # Spine is a threaded network daemon; ASan and UBSan are the checks most - # likely to catch a real defect here. + # likely to catch a real defect here. The unit tests are what actually + # exercises the code, so they are what runs instrumented. sanitizers: runs-on: ubuntu-latest timeout-minutes: 20 + env: + CC: clang + ASAN_OPTIONS: detect_leaks=1:exitcode=1 + UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Install build dependencies - run: | - set -euo pipefail - sudo apt-get update - sudo apt-get install -y clang mysql-server libmysqlclient-dev libsnmp-dev \ - libssl-dev build-essential help2man autoconf automake libtool dos2unix libcmocka-dev + - uses: ./.github/actions/build-spine + with: + extra-packages: clang + cflags: -fsanitize=address,undefined -fno-omit-frame-pointer -g -O1 + ldflags: -fsanitize=address,undefined - name: Build with ASan and UBSan - env: - CC: clang run: | set -euo pipefail - ./bootstrap - ./configure \ - CFLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer -g -O1" \ - LDFLAGS="-fsanitize=address,undefined" make -j"$(nproc)" - - name: Run the binary under the sanitizers - env: - ASAN_OPTIONS: detect_leaks=1:exitcode=1 - UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1 + - name: Run the unit tests under the sanitizers + run: | + set -euo pipefail + make check + + - name: Smoke-test the binary under the sanitizers run: | set -euo pipefail ./spine --version ./spine --help > /dev/null + # A release tarball that cannot be compiled is a release blocker, and the # only way to catch it is to build from the tarball the way a packager does. distcheck: runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Install build dependencies - run: | - set -euo pipefail - sudo apt-get update - sudo apt-get install -y mysql-server libmysqlclient-dev libsnmp-dev \ - libssl-dev build-essential help2man autoconf automake libtool dos2unix libcmocka-dev + - uses: ./.github/actions/build-spine - name: make distcheck run: | set -euo pipefail - ./bootstrap - ./configure make distcheck diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index f35834ce..28d6da0e 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -20,20 +20,11 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Install build dependencies - run: | - set -euo pipefail - sudo apt-get update - sudo apt-get install -y clang libmysqlclient-dev libsnmp-dev libssl-dev \ - autoconf automake libtool help2man pkg-config - - - name: Generate config.h - run: | - set -euo pipefail - ./bootstrap - ./configure + - uses: ./.github/actions/build-spine + with: + extra-packages: clang pkg-config # A pull request gets a short regression run against the committed corpus. # The weekly schedule runs long enough to explore. @@ -47,7 +38,7 @@ jobs: fi make -C tests/fuzz FUZZ_SECONDS="$seconds" run - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() with: name: fuzz-crashes diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 1ad5bd82..fc18e7c4 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -18,15 +18,18 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 # Brings up MariaDB and an snmpd, then polls a real device through # poll_host() and checks the value lands in poller_output. - name: Poll an SNMPv3 device end to end - run: tests/snmpv3/scripts/run-integration.sh + run: | + set -euo pipefail + tests/snmpv3/scripts/run-integration.sh - name: Show container logs on failure if: failure() run: | + set -euo pipefail cd tests/snmpv3 docker compose logs --no-color || true