Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
1c6b569
ci: add Socket Firewall (SFW) composite action and test workflow
nebasuke Mar 9, 2026
5fc3ebf
ci: add packages:read permission to sfw-test workflow
nebasuke Mar 9, 2026
5b7d36f
ci(docker): add Node.js 24 to CI runner image
nebasuke Mar 9, 2026
7c6e63b
ci: update CI image digest to include Node.js
nebasuke Mar 9, 2026
38d3826
ci: add Windows and macOS x86 SFW support
nebasuke Mar 9, 2026
98c4ba6
ci: wrap cargo commands with SFW in test.yaml
nebasuke Mar 10, 2026
b4d2efd
ci(sfw): add CA cert trust for cargo behind SFW MITM proxy
nebasuke Mar 15, 2026
25d49ad
ci(sfw): replace `sfw sh -c` with `sfw node -e` for Windows compat
nebasuke Mar 15, 2026
91b20c4
ci(sfw): use temp file for CA cert discovery to fix stdout pollution
nebasuke Mar 15, 2026
e4749ca
ci(sfw): export SSL_CERT_FILE so rustup trusts SFW CA cert
nebasuke Mar 15, 2026
62543a2
ci(sfw): use git CLI for cargo fetch to fix MITM cert rejection
nebasuke Mar 15, 2026
6b30472
ci(sfw): restrict SFW to Linux only, drop macOS/Windows
nebasuke Mar 15, 2026
447ad91
ci(sfw): address PR #250 review comments
nebasuke Mar 17, 2026
e95ffc3
ci: update CI runner image digest to include Node.js
nebasuke Mar 23, 2026
d84562d
Merge remote-tracking branch 'origin/main' into add-sfw-ci
nebasuke Mar 23, 2026
9cd5f97
ci(sfw): prefix all cargo commands and pin sfw version
nebasuke Mar 23, 2026
0355d02
ci(sfw): consolidate SFW setup into reusable composite action
nebasuke Mar 23, 2026
5461c81
Merge branch 'main' into add-sfw-ci
nebasuke Mar 23, 2026
b177df7
Merge branch 'main' into add-sfw-ci
nebasuke Mar 23, 2026
5e16085
Merge branch 'main' into add-sfw-ci
nebasuke Mar 25, 2026
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
2 changes: 1 addition & 1 deletion .github/actions/build-llvm/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ runs:
if: steps.llvm-artifact-cache.outputs.cache-hit != 'true'
working-directory: ${{ inputs.working-dir }}
shell: ${{ runner.os == 'Windows' && 'msys2 {0}' || 'bash' }}
run: cargo fetch --locked && cargo build --frozen --release --bin solx-dev
run: ${SFW_PREFIX:-} cargo fetch --locked && ${SFW_PREFIX:-} cargo build --frozen --release --bin solx-dev

- name: Build LLVM
if: steps.llvm-artifact-cache.outputs.cache-hit != 'true'
Expand Down
4 changes: 2 additions & 2 deletions .github/actions/build-rust/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ runs:
SOLC_PREFIX BOOST_PREFIX CARGO_BIN_EXE_SOLX \
2>/dev/null || true
for var in $(env | awk -F= '/^(LLVM_SYS|MLIR_SYS|TABLEGEN)_/ {print $1}'); do unset "$var"; done
cargo fetch --locked
${SFW_PREFIX:-} cargo fetch --locked
if [ '${{ inputs.sanitizer }}' != '' ]; then
export RUSTFLAGS="-Z sanitizer=${{ inputs.sanitizer }}"
BUILD_STD_LIB='-Zbuild-std'
Expand All @@ -82,7 +82,7 @@ runs:
if [[ "${RUNNER_OS}" == "Windows" ]] || [[ "${RUNNER_OS}" == "Linux" ]]; then
export RUSTFLAGS="${RUSTFLAGS} -C link-arg=-fuse-ld=lld"
fi
cargo ${BUILD_STD_LIB} build --frozen ${RELEASE} ${{ steps.build-target.outputs.target }}
${SFW_PREFIX:-} cargo ${BUILD_STD_LIB} build --frozen ${RELEASE} ${{ steps.build-target.outputs.target }}
if [ '${{ inputs.target }}' != '' ]; then
BINARY_DIR="${PWD}/target/${{ inputs.target }}/${{ inputs.build-type }}"
else
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/build-solc/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ runs:
# Run from the checkout root that owns solx-solidity
working-directory: ${{ inputs.working-dir }}/..
shell: ${{ runner.os == 'Windows' && 'msys2 {0}' || 'bash' }}
run: cargo fetch --locked && cargo build --frozen --release --bin solx-dev
run: ${SFW_PREFIX:-} cargo fetch --locked && ${SFW_PREFIX:-} cargo build --frozen --release --bin solx-dev

- name: Build solc
if: steps.solc-artifact-cache.outputs.cache-hit != 'true'
Expand Down
4 changes: 2 additions & 2 deletions .github/actions/cargo-check/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ runs:

- name: Fetch dependencies
shell: ${{ runner.os == 'Windows' && 'msys2 {0}' || 'bash' }}
run: cargo fetch --locked
run: ${SFW_PREFIX:-} cargo fetch --locked

- name: Cargo check
shell: ${{ runner.os == 'Windows' && 'msys2 {0}' || 'bash' }}
Expand All @@ -36,6 +36,6 @@ runs:
- name: Cargo udeps
shell: ${{ runner.os == 'Windows' && 'msys2 {0}' || 'bash' }}
run: |
cargo install cargo-udeps@0.1.60 --locked
${SFW_PREFIX:-} cargo install cargo-udeps@0.1.60 --locked
cargo +nightly udeps --frozen --all-targets
Comment on lines +39 to 40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cargo install cargo-udeps is prefixed (line 39) but cargo +nightly udeps --frozen on the next line is not. The --frozen flag means it doesn't hit the network, so this is functionally fine, but it's inconsistent with the approach in rust-unit-tests which prefixes all cargo commands including --frozen ones.


14 changes: 7 additions & 7 deletions .github/actions/rust-unit-tests/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,16 @@ runs:

- name: Fetch dependencies
shell: ${{ runner.os == 'Windows' && 'msys2 {0}' || 'bash' }}
run: cargo fetch --locked
run: ${SFW_PREFIX:-} cargo fetch --locked

# Versions pinned to match .github/docker/Dockerfile — on container
# jobs these are already installed and `cargo install` is a no-op.
- name: Prepare test env
shell: ${{ runner.os == 'Windows' && 'msys2 {0}' || 'bash' }}
run: |
cargo install cargo2junit@0.1.15 --locked
${SFW_PREFIX:-} cargo install cargo2junit@0.1.15 --locked
if [ '${{ inputs.enable-coverage }}' = 'true' ]; then
cargo install cargo-llvm-cov@0.8.4 --locked
${SFW_PREFIX:-} cargo install cargo-llvm-cov@0.8.4 --locked
fi

- name: Run unit tests (release)
Expand All @@ -76,8 +76,8 @@ runs:
if [[ ${RUNNER_OS} = Windows ]] || [[ ${RUNNER_OS} = Linux ]]; then
export RUSTFLAGS="${RUSTFLAGS} -C link-arg=-fuse-ld=lld"
fi
if [ "${TEST_COMMAND}" = "test" ]; then cargo build --frozen; fi
cargo ${TEST_COMMAND} --frozen --release ${{ steps.build-target.outputs.target }} -- -Z unstable-options \
if [ "${TEST_COMMAND}" = "test" ]; then ${SFW_PREFIX:-} cargo build --frozen; fi
${SFW_PREFIX:-} cargo ${TEST_COMMAND} --frozen --release ${{ steps.build-target.outputs.target }} -- -Z unstable-options \
--format json | tee -a release-results.json | grep 'failed'
if [ $? -eq 0 ]; then
cargo2junit < release-results.json > "release-${{ inputs.results-xml }}"
Expand Down Expand Up @@ -125,8 +125,8 @@ runs:
if [ '${{ inputs.target }}' != '' ]; then
export CARGO_BIN_EXE_SOLX="./target/${{ inputs.target }}/debug/solx"
fi
if [ "${{ inputs.cargo-test-command }}" = "test" ]; then cargo build --frozen ${{ steps.build-target.outputs.target }}; fi
cargo ${{ inputs.cargo-test-command }} --frozen ${{ steps.build-target.outputs.target }} -- -Z unstable-options \
if [ "${{ inputs.cargo-test-command }}" = "test" ]; then ${SFW_PREFIX:-} cargo build --frozen ${{ steps.build-target.outputs.target }}; fi
${SFW_PREFIX:-} cargo ${{ inputs.cargo-test-command }} --frozen ${{ steps.build-target.outputs.target }} -- -Z unstable-options \
--format json | tee -a debug-results.json | grep 'failed'
if [ $? -eq 0 ]; then
cargo2junit < debug-results.json > "debug-${{ inputs.results-xml }}"
Expand Down
124 changes: 124 additions & 0 deletions .github/actions/setup-sfw/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
name: Setup Socket Firewall (SFW)
description: >
Installs and configures Socket Firewall to monitor package installations.
On bare-metal Linux runners, installs via socketdev/action with MITM proxy
and CA cert trust. Inside containers, installs the sfw CLI via npm.
Skips on macOS/Windows where the MITM proxy is incompatible.

inputs:
mode:
description: 'SFW mode: "firewall" blocks risky packages, "audit" only warns'
required: false
default: 'firewall'

outputs:
available:
description: 'Whether SFW is available for use (true/false)'
value: ${{ steps.set-prefix.outputs.available }}

runs:
using: composite
steps:
- name: Detect platform support
id: detect
shell: bash
run: |
# SFW's MITM proxy is only compatible with Linux TLS stacks.
# macOS (LibreSSL) and Windows (Schannel) reject the SFW cert
# at the crypto level — not a CA trust issue.
if [[ "$RUNNER_OS" != "Linux" ]]; then
echo "::notice::SFW skipped: MITM proxy not compatible with $RUNNER_OS TLS stack"
echo "method=none" >> "$GITHUB_OUTPUT"
exit 0
fi

# Inside containers, the socketdev/action MITM proxy doesn't work,
# but the sfw CLI wrapper can be installed directly via npm.
# (GitHub sets 'container' env var for container jobs;
# /.dockerenv is a fallback heuristic)
if [[ -n "${container:-}" ]] || [[ -f /.dockerenv ]]; then
Comment on lines +37 to +39
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says "GitHub sets 'container' env var for container jobs" but GitHub Actions exposes the container configuration through the job.container expression context, not as a shell environment variable. ${container:-} will always be empty in bash. The detection works correctly via the /.dockerenv fallback, but the first condition is dead code and the comment is misleading.

Consider simplifying to just [[ -f /.dockerenv ]] or passing ${{ job.container.id }} as an input to the action.

echo "method=npm" >> "$GITHUB_OUTPUT"
exit 0
fi

echo "method=action" >> "$GITHUB_OUTPUT"

- name: Install SFW (container)
if: steps.detect.outputs.method == 'npm'
shell: bash
run: npm install -g sfw@2.0.4

- name: Install SFW
if: steps.detect.outputs.method == 'action'
uses: socketdev/action@4337a545deecc20f19a909e52db7a2f6ba292f42 # v1
with:
mode: ${{ inputs.mode }}

- name: Configure cargo TLS trust for SFW
if: steps.detect.outputs.method == 'action'
shell: bash
run: |
# Trigger SFW cert generation (may be lazy)
sfw npm ping > /dev/null 2>&1 || true

# Discover SFW CA cert path via temp file to avoid
# stdout pollution (sfw prepends/appends banner lines)
cat > "${RUNNER_TEMP}/sfw-get-cert.js" << 'SCRIPT'
const fs = require("fs");
const p = process.env.NODE_EXTRA_CA_CERTS || "";
fs.writeFileSync(process.env.RUNNER_TEMP + "/sfw-cert-path.txt", p);
SCRIPT
sfw node "${RUNNER_TEMP}/sfw-get-cert.js" > /dev/null 2>&1 || true
SFW_CA=""
[ -f "${RUNNER_TEMP}/sfw-cert-path.txt" ] && SFW_CA=$(cat "${RUNNER_TEMP}/sfw-cert-path.txt")
rm -f "${RUNNER_TEMP}/sfw-get-cert.js" "${RUNNER_TEMP}/sfw-cert-path.txt"

if [ -z "$SFW_CA" ] || [ ! -f "$SFW_CA" ]; then
echo "::warning::SFW CA cert not found — cargo may fail with SSL errors under sfw"
exit 0
Comment on lines +76 to +78
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the SFW CA cert isn't found, this warns and exits 0, but the set-prefix step at line 113 still runs and sets SFW_PREFIX=sfw. Subsequent ${SFW_PREFIX:-} cargo commands will route through SFW's MITM proxy without proper CA trust, producing opaque SSL errors.

Consider either skipping the prefix setup on cert failure (e.g. set an output that the set-prefix step checks) or failing the step.

fi

echo "SFW CA cert: $SFW_CA"
BUNDLE="${RUNNER_TEMP}/sfw-ca-bundle.pem"

# Find system CA bundle (Linux paths only — macOS/Windows are skipped above)
FOUND_SYSTEM=false
for f in \
/etc/ssl/certs/ca-certificates.crt \
/etc/ssl/certs/ca-bundle.crt \
/etc/pki/tls/certs/ca-bundle.crt; do
if [ -f "$f" ]; then
cp "$f" "$BUNDLE"
echo "System CA bundle: $f"
FOUND_SYSTEM=true
break
fi
done

if [ "$FOUND_SYSTEM" = false ]; then
echo "::warning::Could not find system CA bundle — using SFW cert only"
cp "$SFW_CA" "$BUNDLE"
else
# Append SFW CA cert to system bundle
echo "" >> "$BUNDLE"
cat "$SFW_CA" >> "$BUNDLE"
fi

# Export for cargo, git, and rustup (SSL_CERT_FILE is needed by rustls-native-certs)
echo "CARGO_HTTP_CAINFO=$BUNDLE" >> "$GITHUB_ENV"
echo "GIT_SSL_CAINFO=$BUNDLE" >> "$GITHUB_ENV"
echo "SSL_CERT_FILE=$BUNDLE" >> "$GITHUB_ENV"
echo "CA bundle created at $BUNDLE ($(wc -l < "$BUNDLE") lines)"

- name: Set SFW prefix
id: set-prefix
if: steps.detect.outputs.method != 'none'
Comment on lines +113 to +115
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When method=none (macOS/Windows), this step is skipped entirely, leaving outputs.available as an empty string rather than "false". The output description on line 16 says true/false, so any consumer checking == 'false' would get wrong results.

Either add a separate step for the none branch that writes available=false, or document that callers must check != 'true'.

shell: bash
run: |
if command -v sfw &>/dev/null; then
echo "SFW_PREFIX=sfw" >> "$GITHUB_ENV"
echo "available=true" >> "$GITHUB_OUTPUT"
else
echo "::warning::SFW command not found after install"
echo "available=false" >> "$GITHUB_OUTPUT"
fi
14 changes: 13 additions & 1 deletion .github/docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# The custom LLVM 21.1 backend is NOT baked into this image — it is built from
# source in every CI job via the build-llvm composite action.

FROM ubuntu:24.04
FROM ubuntu:24.04@sha256:0d39fcc8335d6d74d5502f6df2d30119ff4790ebbb60b364818d5112d9e3e932

LABEL org.opencontainers.image.source="https://github.com/NomicFoundation/solx"
LABEL org.opencontainers.image.description="CI runner image for solx"
Expand Down Expand Up @@ -118,6 +118,16 @@ RUN cargo install \
cargo-udeps@0.1.60 \
--locked

# ── Node.js (for SFW and npm-based CI tools) ─────────────────────────────
ARG NODE_MAJOR=24
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
| gpg --dearmor -o /usr/share/keyrings/nodesource.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/nodesource.gpg] \
https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" \
> /etc/apt/sources.list.d/nodesource.list \
&& apt-get update && apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*

# Smoke-test: ensure key tools are on PATH
RUN set -eux \
&& rustc --version \
Expand All @@ -130,6 +140,8 @@ RUN set -eux \
&& command -v llvm-profdata \
&& command -v llvm-lipo \
&& command -v llvm-symbolizer \
&& node --version \
&& npm --version \
&& valgrind --version \
&& case "${TARGETPLATFORM}" in \
linux/amd64) test -f /usr/lib/x86_64-linux-gnu/libstdc++.a ;; \
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/cache-warmup.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ jobs:
runner: macos-15
- name: "Linux x86 gnu"
runner: ubuntu-24.04
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c0866d146261cd0a51dc7d9077444b8ac3dde12c53d2151137834e6be149dbc7
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c2b03000a1074d2cc3e6cf25a1c4fdc6eb0a61d23e63bef59205050249fa1d6e
- name: "Linux ARM64 gnu"
runner: ubuntu-24.04-arm
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c0866d146261cd0a51dc7d9077444b8ac3dde12c53d2151137834e6be149dbc7
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c2b03000a1074d2cc3e6cf25a1c4fdc6eb0a61d23e63bef59205050249fa1d6e
- name: "Windows"
runner: windows-2025
runs-on: ${{ matrix.runner }}
Expand Down Expand Up @@ -82,10 +82,10 @@ jobs:
runner: macos-15
- name: "Linux x86 gnu"
runner: ubuntu-24.04
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c0866d146261cd0a51dc7d9077444b8ac3dde12c53d2151137834e6be149dbc7
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c2b03000a1074d2cc3e6cf25a1c4fdc6eb0a61d23e63bef59205050249fa1d6e
- name: "Linux ARM64 gnu"
runner: ubuntu-24.04-arm
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c0866d146261cd0a51dc7d9077444b8ac3dde12c53d2151137834e6be149dbc7
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c2b03000a1074d2cc3e6cf25a1c4fdc6eb0a61d23e63bef59205050249fa1d6e
- name: "Windows"
runner: windows-2025
runs-on: ${{ matrix.runner }}
Expand Down Expand Up @@ -118,7 +118,7 @@ jobs:
warm-llvm-sanitizer:
runs-on: ubuntu-24.04
container:
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c0866d146261cd0a51dc7d9077444b8ac3dde12c53d2151137834e6be149dbc7
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c2b03000a1074d2cc3e6cf25a1c4fdc6eb0a61d23e63bef59205050249fa1d6e
name: "LLVM · Sanitizer"
steps:
- name: Checkout
Expand All @@ -142,7 +142,7 @@ jobs:
warm-llvm-coverage:
runs-on: ubuntu-24.04
container:
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c0866d146261cd0a51dc7d9077444b8ac3dde12c53d2151137834e6be149dbc7
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c2b03000a1074d2cc3e6cf25a1c4fdc6eb0a61d23e63bef59205050249fa1d6e
name: "LLVM · Coverage"
steps:
- name: Checkout
Expand All @@ -167,7 +167,7 @@ jobs:
warm-llvm-integration:
runs-on: ubuntu-24.04
container:
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c0866d146261cd0a51dc7d9077444b8ac3dde12c53d2151137834e6be149dbc7
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c2b03000a1074d2cc3e6cf25a1c4fdc6eb0a61d23e63bef59205050249fa1d6e
name: "LLVM + solc · Integration"
steps:
- name: Checkout
Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
pull-requests: write
packages: read
container:
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c0866d146261cd0a51dc7d9077444b8ac3dde12c53d2151137834e6be149dbc7
image: ghcr.io/nomicfoundation/solx-ci-runner@sha256:c2b03000a1074d2cc3e6cf25a1c4fdc6eb0a61d23e63bef59205050249fa1d6e
env:
BOOST_PREFIX: ${{ github.workspace }}/solx-solidity/boost/lib
SOLC_PREFIX: ${{ github.workspace }}/solx-solidity/build
Expand All @@ -63,6 +63,9 @@ jobs:
git config --global --add safe.directory '*'
git submodule update --init --force --depth=1 --recursive --checkout

- name: Setup SFW
uses: ./.github/actions/setup-sfw

- name: Build LLVM
uses: ./.github/actions/build-llvm
with:
Expand Down Expand Up @@ -121,7 +124,7 @@ jobs:
RUSTC_BOOTSTRAP: 1
RUSTFLAGS: '-C target-feature=+crt-static -C instrument-coverage -C link-arg=-fuse-ld=lld'
LLVM_PROFILE_FILE: 'unit-tests-%p-%m.profraw'
run: cargo fetch --locked && cargo test --frozen --release --target x86_64-unknown-linux-gnu
run: ${SFW_PREFIX:-} cargo fetch --locked && ${SFW_PREFIX:-} cargo test --frozen --release --target x86_64-unknown-linux-gnu

# Inkwell feature poisoning: solc path builds inkwell with LLVM linking,
# slang path needs no-llvm-linking. cargo clean cannot reliably clear
Expand All @@ -134,7 +137,7 @@ jobs:
RUSTFLAGS: '-C instrument-coverage -C link-arg=-fuse-ld=lld'
LLVM_PROFILE_FILE: 'slang-tests-%p-%m.profraw'
CARGO_TARGET_DIR: target-slang
run: cargo test-slang --frozen --release --target x86_64-unknown-linux-gnu
run: ${SFW_PREFIX:-} cargo test-slang --frozen --release --target x86_64-unknown-linux-gnu

- name: Preserve slang instrumented binary
if: contains(github.event.pull_request.labels.*.name, 'ci:slang')
Expand Down
Loading
Loading