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
61 changes: 61 additions & 0 deletions .github/docker/wolfcose-ci/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Shared dependencies for wolfCOSE Linux CI. Rebuild through publish-ci-image.yml.
FROM ubuntu:24.04

LABEL org.opencontainers.image.source="https://github.com/wolfSSL/wolfCOSE" \
org.opencontainers.image.description="wolfCOSE Linux CI toolchains and test dependencies" \
org.opencontainers.image.licenses="GPL-3.0-or-later"

SHELL ["/bin/bash", "-o", "pipefail", "-c"]

ENV DEBIAN_FRONTEND=noninteractive \
RUSTUP_HOME=/opt/rustup \
CARGO_HOME=/opt/cargo \
PATH=/opt/python-cwt/bin:/opt/ci-tools/bin:/usr/local/go/bin:/opt/cargo/bin:$PATH

# Package installation belongs here, rather than in individual CI jobs.
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential gcc-11 gcc-12 gcc-13 \
clang clang-14 clang-15 clang-17 clang-tools clang-tidy \
libclang-rt-18-dev cppcheck=2.13.0-2ubuntu3 \
autoconf automake libtool libtool-bin pkg-config m4 \
libssl-dev libffi-dev \
lcov bc valgrind \
git gh curl ca-certificates jq \
python3 python3-dev python3-pip python3-venv \
zip unzip xz-utils zstd file procps \
&& rm -rf /var/lib/apt/lists/*

# Preserve the existing Go 1.24.x and stable Rust policies, resolved at image
# build time rather than downloaded in every interop job.
RUN curl --fail --silent --show-error --location \
'https://go.dev/dl/?mode=json&include=all' -o /tmp/go-releases.json \
&& read -r go_archive go_sha < <(jq -r \
'[.[] | select(.stable and (.version | test("^go1\\.24\\.[0-9]+$")))] \
| first | .files[] \
| select(.os == "linux" and .arch == "amd64" and .kind == "archive") \
| [.filename, .sha256] | @tsv' /tmp/go-releases.json) \
&& test -n "$go_archive" && test -n "$go_sha" \
&& curl --fail --silent --show-error --location \
"https://go.dev/dl/$go_archive" -o /tmp/go.tar.gz \
&& echo "$go_sha /tmp/go.tar.gz" | sha256sum --check - \
&& tar -xzf /tmp/go.tar.gz -C /usr/local \
&& rm /tmp/go.tar.gz /tmp/go-releases.json

RUN curl --fail --silent --show-error --location \
https://sh.rustup.rs -o /tmp/rustup-init.sh \
&& sh /tmp/rustup-init.sh -y --profile minimal \
--default-toolchain stable --no-modify-path \
&& rm /tmp/rustup-init.sh

# Keep the pinned interop environment independent of analysis-tool dependencies.
COPY tests/interop/python_cwt/requirements.txt /tmp/python-cwt-requirements.txt
RUN python3 -m venv /opt/python-cwt \
&& /opt/python-cwt/bin/python -m pip install --no-cache-dir \
--requirement /tmp/python-cwt-requirements.txt \
&& python3 -m venv /opt/ci-tools \
&& /opt/ci-tools/bin/python -m pip install --no-cache-dir semgrep codespell \
&& rm /tmp/python-cwt-requirements.txt

COPY .github/docker/wolfcose-ci/smoke-test.sh /usr/local/bin/wolfcose-ci-smoke
RUN chmod +x /usr/local/bin/wolfcose-ci-smoke && wolfcose-ci-smoke
10 changes: 10 additions & 0 deletions .github/docker/wolfcose-ci/Dockerfile.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Only send the image assets and pinned Python peer requirements to Docker.
**
!.github/
!.github/docker/
!.github/docker/wolfcose-ci/
!.github/docker/wolfcose-ci/**
!tests/
!tests/interop/
!tests/interop/python_cwt/
!tests/interop/python_cwt/requirements.txt
49 changes: 49 additions & 0 deletions .github/docker/wolfcose-ci/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# wolfCOSE CI image

Linux workflows pin `ghcr.io/wolfssl/wolfcose-ci` by its immutable image digest.
Native macOS builds retain their Homebrew dependencies. The image contains the
C compiler matrix, analysis and coverage tools, Go 1.24.x, stable Rust, and
Python 3.12 peers.
The GitHub CLI supports the existing wiki publishing action.
Python interop requirements come from the existing pinned requirements file;
Semgrep and Codespell use a separate environment.

From the repository root:

```sh
docker build --platform linux/amd64 \
-f .github/docker/wolfcose-ci/Dockerfile -t wolfcose-ci .
docker run --rm --platform linux/amd64 wolfcose-ci wolfcose-ci-smoke
```

The Dockerfile-specific ignore file restricts the build context to image assets
and Python interop requirements. Add shared dependencies here instead of
installing them in workflow jobs. Go patch releases, stable Rust, Semgrep, and
Codespell are resolved when the image is rebuilt.

In `wolfSSL/wolfCOSE`, `publish-ci-image.yml` runs on relevant pushes to
`main` and manual dispatches targeting `main`. Publication is restricted to
`refs/heads/main`. It builds and smoke-tests the image, then publishes
`latest` and `sha-<commit>` tags. Publication is serialized and uses the
repository's `GITHUB_TOKEN`. The GHCR package must be public so fork PRs can
pull anonymously.

After publishing, a container job uses the build's output digest to repeat the
smoke checks in the GitHub runner environment and exercises the wiki action in
dry-run mode without publishing documentation.

Consumers should never fall back to building the image or installing packages.

Container jobs trust the mounted GitHub workspace after checkout so Git can
read a repository owned by the host runner. Their explicit Bash command keeps
the previous host shell's error behavior.

Linux wolfSSL caches use the `wolfcose-ci-v1` prefix to separate them from
previous host builds. Bump this prefix if an image change makes cached builds
incompatible.

To adopt a rebuilt image, inspect its `sha-<commit>` tag with
`docker buildx imagetools inspect` and copy the reported image digest into the
consumer workflows in a reviewed change. The publisher's smoke job tests the
new digest immediately, while consumer jobs keep using their reviewed digest.
To roll back, restore the previous digest in those workflows.
35 changes: 35 additions & 0 deletions .github/docker/wolfcose-ci/smoke-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/bin/bash
# Exercise the installed toolchains before an image is published.
set -euo pipefail

smoke_dir=$(mktemp -d)
trap 'rm -rf "$smoke_dir"' EXIT
cat > "$smoke_dir/main.c" <<'EOF'
int main(void)
{
return 0;
}
EOF

for compiler in gcc gcc-11 gcc-12 gcc-13 clang clang-14 clang-15 clang-17; do
"$compiler" --version | head -n 1
"$compiler" -std=c99 -Wall -Wextra -Werror "$smoke_dir/main.c" \
-o "$smoke_dir/compiler-test"
"$smoke_dir/compiler-test"
done

test "$(cppcheck --version)" = 'Cppcheck 2.13.0'
cppcheck --addon=misra --error-exitcode=1 "$smoke_dir/main.c"
for tool in autoconf automake libtool pkg-config clang-tidy scan-build \
lcov bc valgrind git gh curl jq zip unzip; do
command -v "$tool"
done
pkg-config --exists openssl
go version
rustc --version
cargo --version
python -c 'import sys; assert sys.version_info[:2] == (3, 12); import cbor2, cwt, cryptography, pyhpke'
python -m pip check
/opt/ci-tools/bin/python -m pip check
semgrep --version
codespell --version
6 changes: 6 additions & 0 deletions .github/workflows/_resolve-wolfssl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,16 @@ on:
permissions:
contents: read

defaults:
run:
shell: bash -e {0}

jobs:
resolve:
name: Resolve wolfSSL version matrix
runs-on: ubuntu-latest
container:
image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
refs: ${{ steps.set-matrix.outputs.refs }}
Expand Down
51 changes: 31 additions & 20 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

defaults:
run:
shell: bash -e {0}

jobs:
discover:
uses: ./.github/workflows/_resolve-wolfssl.yml
Expand All @@ -19,20 +23,24 @@ jobs:
name: ${{ matrix.os }} (wolfSSL ${{ matrix.wolfssl-ref }})
needs: discover
runs-on: ${{ matrix.os }}
container: ${{ matrix.container }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-22.04, macos-latest]
os: [ubuntu-latest, macos-latest]
wolfssl-ref: ${{ fromJson(needs.discover.outputs.refs) }}
include:
- os: ubuntu-latest
container: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc
- os: macos-latest
container: ''

steps:
- uses: actions/checkout@v4

- name: Install dependencies (Linux)
- name: Trust workspace
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y autoconf automake libtool
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"

- name: Install dependencies (macOS)
if: runner.os == 'macOS'
Expand All @@ -44,7 +52,7 @@ jobs:
uses: actions/cache@v4
with:
path: ~/wolfssl-install
key: wolfssl-${{ matrix.os }}-${{ matrix.wolfssl-ref }}-v5-lms
key: ${{ runner.os == 'Linux' && 'wolfcose-ci-v1-' || '' }}wolfssl-${{ matrix.os }}-${{ matrix.wolfssl-ref }}-v5-lms

- name: Build wolfSSL (${{ matrix.wolfssl-ref }})
if: matrix.wolfssl-ref == 'master' || steps.cache-wolfssl.outputs.cache-hit != 'true'
Expand Down Expand Up @@ -208,6 +216,8 @@ jobs:
name: LMS lean profiles (wolfSSL ${{ matrix.wolfssl-ref }})
needs: discover
runs-on: ubuntu-latest
container:
image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc
strategy:
fail-fast: false
matrix:
Expand All @@ -216,18 +226,17 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y autoconf automake libtool
- name: Trust workspace
if: runner.os == 'Linux'
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"

- name: Cache wolfSSL (${{ matrix.wolfssl-ref }})
if: matrix.wolfssl-ref != 'master'
id: cache-wolfssl
uses: actions/cache@v4
with:
path: ~/wolfssl-install
key: wolfssl-ubuntu-latest-${{ matrix.wolfssl-ref }}-v5-lms
key: wolfcose-ci-v1-wolfssl-ubuntu-latest-${{ matrix.wolfssl-ref }}-v5-lms

- name: Build wolfSSL (${{ matrix.wolfssl-ref }})
if: matrix.wolfssl-ref == 'master' || steps.cache-wolfssl.outputs.cache-hit != 'true'
Expand Down Expand Up @@ -282,14 +291,15 @@ jobs:
lms-verify-only:
name: LMS verify-only wolfSSL profile
runs-on: ubuntu-latest
container:
image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc

steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y autoconf automake libtool
- name: Trust workspace
if: runner.os == 'Linux'
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"

# Build wolfSSL with LMS support that cannot sign, mirroring a verifier
# deployment. --enable-lms=verify-only records WOLFSSL_LMS_VERIFY_ONLY in
Expand Down Expand Up @@ -342,25 +352,26 @@ jobs:
name: Code Coverage (wolfSSL ${{ matrix.wolfssl-version }})
needs: discover
runs-on: ubuntu-latest
container:
image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.discover.outputs.matrix) }}

steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y autoconf automake libtool lcov
- name: Trust workspace
if: runner.os == 'Linux'
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"

- name: Cache wolfSSL (${{ matrix.wolfssl-version }})
if: matrix.wolfssl-version != 'master'
id: cache-wolfssl
uses: actions/cache@v4
with:
path: ~/wolfssl-install
key: wolfssl-coverage-${{ matrix.wolfssl-version }}-v5-lms
key: wolfcose-ci-v1-wolfssl-coverage-${{ matrix.wolfssl-version }}-v5-lms

- name: Build wolfSSL (${{ matrix.wolfssl-version }})
if: matrix.wolfssl-version == 'master' || steps.cache-wolfssl.outputs.cache-hit != 'true'
Expand Down
15 changes: 10 additions & 5 deletions .github/workflows/c99-compliance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

defaults:
run:
shell: bash -e {0}

jobs:
c99-check:
name: ISO C99 conformance (${{ matrix.cc }})
runs-on: ubuntu-latest
container:
image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc
strategy:
fail-fast: false
matrix:
Expand All @@ -23,10 +29,9 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y autoconf automake libtool
- name: Trust workspace
if: runner.os == 'Linux'
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"

- name: Resolve wolfSSL master commit
id: wolfssl-rev
Expand All @@ -36,7 +41,7 @@ jobs:
uses: actions/cache@v4
with:
path: ~/wolfssl-install
key: wolfssl-ubuntu-latest-v3-full-${{ steps.wolfssl-rev.outputs.sha }}
key: wolfcose-ci-v1-wolfssl-ubuntu-latest-v3-full-${{ steps.wolfssl-rev.outputs.sha }}

- name: Build wolfSSL
if: steps.cache-wolfssl.outputs.cache-hit != 'true'
Expand Down
15 changes: 10 additions & 5 deletions .github/workflows/cmdline-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

defaults:
run:
shell: bash -e {0}

jobs:
discover:
uses: ./.github/workflows/_resolve-wolfssl.yml
Expand All @@ -19,25 +23,26 @@ jobs:
name: Command-line tool (wolfSSL ${{ matrix.wolfssl-version }})
needs: discover
runs-on: ubuntu-latest
container:
image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.discover.outputs.matrix) }}

steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y autoconf automake libtool
- name: Trust workspace
if: runner.os == 'Linux'
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"

- name: Cache wolfSSL (${{ matrix.wolfssl-version }})
if: matrix.wolfssl-version != 'master'
id: cache-wolfssl
uses: actions/cache@v4
with:
path: ~/wolfssl-install
key: wolfssl-clitest-${{ matrix.wolfssl-version }}-v3
key: wolfcose-ci-v1-wolfssl-clitest-${{ matrix.wolfssl-version }}-v3

- name: Build wolfSSL (${{ matrix.wolfssl-version }})
if: matrix.wolfssl-version == 'master' || steps.cache-wolfssl.outputs.cache-hit != 'true'
Expand Down
Loading
Loading