Skip to content

feat(lsm): default-deny IPv4 egress (#54) + AF_UNIX deputy denylist (#55) #48

feat(lsm): default-deny IPv4 egress (#54) + AF_UNIX deputy denylist (#55)

feat(lsm): default-deny IPv4 egress (#54) + AF_UNIX deputy denylist (#55) #48

Workflow file for this run

name: CI
on:
push:
branches: ["main"]
pull_request:
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
# ─────────────────────────────────────────────────────────────────────────────
# Job 1: Release build
# ─────────────────────────────────────────────────────────────────────────────
build:
name: Build (release)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install system dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y libz3-dev keyutils
- name: Cache Cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Cache target directory
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-target-release-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-target-release-
- name: Build release
run: cargo build --release 2>&1
- name: Upload release binary
uses: actions/upload-artifact@v4
with:
name: ts_cli-release-${{ github.sha }}
path: target/release/ts_cli
# ─────────────────────────────────────────────────────────────────────────────
# Job 2: Test suite (unit + integration)
# ─────────────────────────────────────────────────────────────────────────────
test:
name: Tests
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v5
- name: Install system dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y libz3-dev keyutils
- name: Cache Cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Cache target directory
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-target-test-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-target-test-
${{ runner.os }}-cargo-target-release-
- name: Download release binary
uses: actions/download-artifact@v4
with:
name: ts_cli-release-${{ github.sha }}
path: target/release/
- name: Mark binary executable
run: chmod +x target/release/ts_cli
- name: Run all tests
env:
JINNGUARD_TEST_BINARY: ${{ github.workspace }}/target/release/ts_cli
run: cargo test --workspace 2>&1
# Anti-lockout / safe-mode invariants in the LSM verdict loop only build
# under the kernel feature. Run them so a regression that could strand the
# operator fails CI.
- name: Run kernel-feature safety invariants
run: cargo test --bin ts_cli --features kernel_telemetry 2>&1
# ─────────────────────────────────────────────────────────────────────────────
# Job 2b: Fleet feature gate (open-core enterprise client)
# The signed-bundle client (`--fleet-policy-url`) compiles only with the
# `fleet` feature (off by default). The other jobs build feature-off; this one
# guarantees the gated code still compiles, lints, and that the accept/reject
# decision (apply-forward / reject-rollback / reject-bad-signature) is correct.
# ─────────────────────────────────────────────────────────────────────────────
fleet:
name: Fleet feature gate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install system dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y libz3-dev keyutils
- name: Cache Cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Cache target directory
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-target-fleet-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-target-fleet-
- name: Install clippy
run: rustup component add clippy
- name: Clippy (fleet feature, deny warnings)
run: cargo clippy -p ts_cli --features fleet -- -D warnings 2>&1
- name: Test fleet bundle accept/reject decision
run: cargo test -p ts_cli --features fleet --bin ts_cli fleet_policy 2>&1
# ─────────────────────────────────────────────────────────────────────────────
# Job 3: Benchmark compilation check
# ─────────────────────────────────────────────────────────────────────────────
bench:
name: Bench (compile check)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install system dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y libz3-dev keyutils
- name: Cache Cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Cache target directory
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-target-bench-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-target-bench-
- name: Compile benchmarks (no-run)
run: cargo bench --no-run 2>&1
# ─────────────────────────────────────────────────────────────────────────────
# Job 4: Clippy (deny warnings)
# ─────────────────────────────────────────────────────────────────────────────
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install system dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y libz3-dev keyutils
- name: Cache Cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Install clippy
run: rustup component add clippy
- name: Run clippy
run: cargo clippy -- -D warnings 2>&1
# ─────────────────────────────────────────────────────────────────────────────
# Job 5: Rustfmt check
# ─────────────────────────────────────────────────────────────────────────────
fmt:
name: Format check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install rustfmt
run: rustup component add rustfmt
- name: Check formatting
run: cargo fmt --check 2>&1
# ─────────────────────────────────────────────────────────────────────────────
# Job 6: eBPF build
# ─────────────────────────────────────────────────────────────────────────────
build-ebpf:
name: Build eBPF LSM objects
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install clang, llvm, libbpf-dev
run: |
sudo apt-get update -qq
sudo apt-get install -y clang llvm libbpf-dev
# Compile each of the five LSM objects the daemon actually loads against the
# vendored bpf/vmlinux.h (committed to the repo). This deliberately does NOT
# use bpftool or the runner's live BTF: obtaining a working bpftool on
# GitHub's Azure-kernel runner is unreliable, and a compile sanity check
# doesn't need the runner's own kernel types. This GATES CI — a change that
# breaks BPF compilation (bad map, missing helper, etc.) fails the build.
- name: Compile LSM objects (gating)
run: |
set -euo pipefail
test -f bpf/vmlinux.h || { echo "ERROR: bpf/vmlinux.h missing (it is vendored)"; exit 1; }
cd bpf
for f in lsm/jg_socket_connect lsm/jg_socket_sendmsg \
lsm/jg_bprm_check_security lsm/jg_inode_create lsm/jg_inode_unlink; do
echo " CLANG $f.o"
clang -O2 -g -target bpf -D__TARGET_ARCH_x86 -I/usr/include -I. -c "$f.c" -o "$f.o"
done
- name: Upload eBPF LSM objects
uses: actions/upload-artifact@v4
with:
name: jinnguard-lsm-objects-${{ github.sha }}
path: bpf/lsm/*.o
if-no-files-found: error