Skip to content

ci: add GitHub Actions test pipeline#5

Closed
Frauschi wants to merge 1 commit into
wolfSSL:mainfrom
Frauschi:ci
Closed

ci: add GitHub Actions test pipeline#5
Frauschi wants to merge 1 commit into
wolfSSL:mainfrom
Frauschi:ci

Conversation

@Frauschi

Copy link
Copy Markdown
Contributor

ci: add GitHub Actions test pipeline

Summary

Adds a full GitHub Actions CI pipeline for wolfCert, plus the supporting scripts and a couple of adjacent fixes surfaced while building it out. CI builds (or restores from cache) a named wolfSSL configuration, builds wolfCert to match, and runs the tests. The design splits work into a fast per-PR merge gate and a nightly job set that owns the heavier matrix, cache seeding, sanitizers, and interop.

Workflows

Workflow Trigger What it does
pr.yml PR + push to main/master Merge gate: canonical config on CMake (-Werror), autoconf, and ASan/UBSan, plus per-PR feature/config gating — EST-only, SCEP-only, server-off, key-alg variants (NO_RSA, ECC-only, RSA-only, no-3DES), TLS 1.3-only, ML-DSA per-level, static-mem, no-malloc, the header-only user_settings.h build, a macOS build, and the two cheapest configure-must-fail assertions.
lint.yml PR + push GPL license-header check and CMake↔autoconf parity of both the library and test source lists. No wolfSSL build — fails in seconds.
nightly.yml schedule + dispatch Re-runs the wolfSSL-variant matrix against fresh wolfSSL master, seeds the wolfSSL prefix caches so next-day PRs restore instead of build, and runs the macOS extras + full negative-config set.
sanitizers.yml schedule + dispatch ASan/UBSan over the full suite, TSan over the threaded roundtrips, valgrind over a representative subset.
interop.yml schedule + dispatch Third-party EST/SCEP interop (openssl, micromdm/scep, globalsign/est, cisco/libest, smallstep/step-ca). Best-effort: a dependency that fails to install exits 77 (neutral skip); a real regression fails.

Key design decisions

  • PR gate vs nightly split. Feature-gating and build-config variants run on every PR so #ifdef/feature-flag breakage is caught before merge, not after. Nightly keeps the same variant matrix to (a) seed the caches and (b) retest against a fresh wolfSSL master, and owns the slow work (sanitizers, interop, macOS extras, full negative-config set).
  • Caching strategy. scripts/ci/build-wolfssl.sh is the single source of truth mapping a config name → wolfSSL ./configure flags. The build-wolfssl composite action caches the install prefix, keyed on the resolved wolfSSL commit + a hash of the exact flags. Nightly owns the shared caches (save: true); PR and interop jobs are restore-only (save: false) so concurrent scheduled jobs never race to save the same key. Footprint is ~5–8 MB/entry, ~0.1 GB steady-state (worst case ~0.6 GB), well under GitHub's self-evicting 10 GB-per-repo cache.
  • No source changes for CI plumbing. SIGPIPE from a benign socket teardown race is handled by sigpipe-launcher.sh (CMake, via CMAKE_CROSSCOMPILING_EMULATOR) and a trap '' PIPE shell (autoconf) — neither touches library or test source.
  • macOS is bash 3.2. Every step that can run on macos-* stays bash-3.2-clean (no mapfile, guarded empty-array expansion).

Build-system parity (make check == ctest)

  • Registered the 6 EST integration tests Makefile.am was missing, so the autoconf make check and CMake ctest now run the identical test set.
  • Extended check-buildsystem-parity.sh to machine-enforce test-source parity in addition to library sources — a test added to one build system but not the other now fails lint.yml in seconds.

Code change (not CI): CSR-attribute enforcement

src/est/est_server.c — refactor + hardening of the est_require_csr_attributes enforcement path:

  • Collapsed csr_attrs_enforce's err_oid_cap / err_oid_len out-parameters into a single value-result size_t* (capacity in, length out), matching wolfCrypt's word32* outLen convention.
  • Hardening: the out-length is reset to 0 on every non-missing path and the caller gates on it, so no current or future error path can render an unpopulated stack buffer into the client-visible HTTP 400 body.
  • Added an end-to-end test asserting the 400 response body names the exact missing OID (1.2.840.113549.1.9.7), covering the OID copy that the client-path test can't observe.

Testing

Reproduce a CI job locally:

# Build the wolfSSL config the job uses.
scripts/ci/build-wolfssl.sh full --prefix /tmp/wolfssl

# Build wolfCert against it and run the tests (CMake).
cmake -S . -B build -DWITH_WOLFSSL=/tmp/wolfssl -DWOLFCERT_ENABLE_TESTS=ON
cmake --build build -j
ctest --test-dir build --output-on-failure

# autoconf equivalent
./autogen.sh
PKG_CONFIG_PATH=/tmp/wolfssl/lib/pkgconfig ./configure \
    --with-wolfssl=/tmp/wolfssl --enable-tests
make -j && make check
  • All 18 EST/CSR/SCEP unit + integration tests pass locally against the canonical full config.
  • A skoll code review of the diff is clean at the Medium+ confidence threshold; the findings it surfaced (interop cache-save race, the CSR-attr enforcement hardening, the missing OID-body assertion) are addressed here.

Notes

  • wolfSSL is tracked at master, unpinned (per project decision).
  • docs/CI.md documents the pipeline, the config names, and how to reproduce and debug a job locally.

Add the wolfCert CI pipeline and supporting scripts, plus the adjacent
build-system and code fixes surfaced while building it out.

Workflows (.github/workflows):
- pr.yml: the merge gate. Canonical config on CMake (-Werror), autoconf and
  ASan/UBSan, plus per-PR feature/config gating -- EST-only, SCEP-only,
  server-off, the key-alg variants (NO_RSA, ECC-only, RSA-only, no-3DES),
  TLS 1.3-only, ML-DSA per-level, static-mem, no-malloc, the header-only
  user_settings build, a macOS build, and the cheap configure-must-fail
  assertions.
- nightly.yml: re-runs the wolfSSL-variant matrix against fresh master,
  seeds the wolfSSL prefix caches for PR restores, and runs the macOS
  extras and the full negative-config set.
- lint.yml: GPL header check and CMake<->autoconf source/test-list parity.
- sanitizers.yml, interop.yml: ASan/UBSan/TSan/valgrind and third-party
  EST/SCEP interop (best-effort, neutral-skip on dependency failure).

Scripts and actions (scripts/ci, .github/actions):
- build-wolfssl.sh: single source of truth mapping a config name to wolfSSL
  ./configure flags; the composite build-wolfssl action caches the install
  prefix keyed on the wolfSSL commit + flag hash. interop restores only.
- assert-configure-fails.sh, check-buildsystem-parity.sh (guards both the
  library- and test-source lists), sigpipe-launcher.sh.

Build-system parity:
- Register the EST integration tests Makefile.am was missing so
  `make check` and ctest run the same set.

CSR-attribute enforcement (src/est/est_server.c):
- Collapse csr_attrs_enforce's out-parameters into a single value-result
  size_t* (capacity in, length out), reset it to 0 on every non-missing
  path, and gate the caller on it so no error path can leak an unpopulated
  stack buffer into the HTTP 400 body. Add an end-to-end test asserting the
  400 body names the missing OID.

docs/CI.md documents the pipeline and how to reproduce a job locally.
@Frauschi

Copy link
Copy Markdown
Contributor Author

Closing in favor of #6 to make sure the new CI tests run in the PR ahead of merging

@Frauschi Frauschi closed this Jul 13, 2026
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