Skip to content
Closed
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
51 changes: 37 additions & 14 deletions template/.github/workflows/kernel-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,20 @@ name: kernel-matrix
# QEMU/KVM on the runner. Each job writes a detail table to its step summary and
# uploads its result; the final `matrix` job pivots them into one ✅/❌ grid.
#
# Tune `matrix.kernel` to the kernels your script must support. Available tags
# live at https://quay.io/repository/lvh-images/kind?tab=tags — the `<ver>-main`
# entries track the latest build of each line. The example probes are CO-RE
# tracepoint programs, so they need a BTF-capable kernel (~5.4+); a program that
# uses newer features (ringbuf, sched_ext, …) will legitimately fail to load on
# kernels that predate them — which is exactly what this matrix surfaces.
# Tune `matrix.kernel` to the kernel lines your script must support (`6.6`,
# `bpf-next`, …); available lines live at
# https://quay.io/repository/lvh-images/kind?tab=tags. Each line is resolved to
# a concrete image at run time rather than using the floating `<ver>-main` tag,
# which the action can't consume: little-vm-helper@v0.0.30 derives the VM image
# filename by stripping a trailing *numeric* build stamp, so a `-main` tag
# yields a name that doesn't match the file `lvh` actually unpacks and the run
# dies with "invalid reference format". So each job looks up the newest
# date-stamped tag (`<ver>-YYYYMMDD.HHMMSS`, which the action handles) — always
# tracking the latest build, with no tag to bump and immune to quay's pruning of
# old stamps. The example probes are CO-RE tracepoint programs, so they need a
# BTF-capable kernel (~5.4+); a program that uses newer features (ringbuf,
# sched_ext, …) will legitimately fail to load on kernels that predate them —
# which is exactly what this matrix surfaces.

on:
workflow_dispatch:
Expand All @@ -29,17 +37,32 @@ jobs:
strategy:
fail-fast: false
matrix:
# Kernel lines to verify. Each is resolved to its newest date-stamped
# lvh image at run time (see the header).
kernel:
- '5.10-main'
- '5.15-main'
- '6.1-main'
- '6.6-main'
- '6.12-main'
- 'bpf-next-main'
- '6.1'
- '6.6'
- '6.12'
- 'bpf-next'
name: kernel ${{ matrix.kernel }}
steps:
- uses: actions/checkout@v4

- name: Resolve newest lvh image tag
id: img
env:
KERNEL: ${{ matrix.kernel }}
run: |
set -euo pipefail
# Newest <line>-YYYYMMDD.HHMMSS tag (date-stamps sort
# lexicographically, so tail -1 is the most recent build).
newest="$(curl -sf "https://quay.io/api/v1/repository/lvh-images/kind/tag/?onlyActiveTags=true&limit=100&filter_tag_name=like:${KERNEL}-" \
| jq -r '.tags[].name' \
| grep -E "^${KERNEL}-[0-9]{8}\.[0-9]+$" | sort | tail -1)"
[ -n "$newest" ] || { echo "::error::no date-stamped tag found for kernel line '${KERNEL}'"; exit 1; }
echo "resolved ${KERNEL} -> ${newest}"
echo "tag=${newest}" >> "$GITHUB_OUTPUT"

- name: Build BPF object + stage veristat
run: |
set -euo pipefail
Expand All @@ -65,7 +88,7 @@ jobs:
with:
test-name: veristat-${{ matrix.kernel }}
image: kind
image-version: ${{ matrix.kernel }}
image-version: ${{ steps.img.outputs.tag }}
host-mount: ${{ github.workspace }}
install-dependencies: 'true'
cmd: |
Expand Down Expand Up @@ -140,7 +163,7 @@ jobs:
m = re.match(r"(\d+)\.(\d+)", k)
return (1, 0, 0) if not m else (0, int(m.group(1)), int(m.group(2)))
kernels.sort(key=keyf)
short = lambda k: k.replace("-main", "")
short = lambda k: re.sub(r"-(main|\d{8}\.\d+)$", "", k)

print("## 🐧 Kernel verification matrix\n")
if not progs:
Expand Down
27 changes: 11 additions & 16 deletions template/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,31 +24,26 @@
include build/toolchain.mk
include build/bpf.mk

NPM ?= npm

all: bpf bundle

# Bundle the entry with the vendored esbuild. esbuild inlines node_modules
# and honors tsconfig `paths` (so `@/` resolves at bundle time), while
# `yeet:*` builtins and `*.bpf.o` objects stay external. The bundle is
# written to src/index.jsx, which the entry ladder prefers over src/main.jsx
# — so once built, that is what runs. The .jsx extension keeps the bundle
# eligible for component auto-mount. Compiled BPF objects in bin/ are loaded
# by path at runtime, never imported, so they are not bundled.
# Bundle the entry with the vendored esbuild. esbuild honors tsconfig `paths`
# (so `@/` resolves at bundle time), while `yeet:*` builtins and `*.bpf.o`
# objects stay external. The bundle is written to src/index.jsx, which the
# entry ladder prefers over src/main.jsx — so once built, that is what runs.
# The .jsx extension keeps the bundle eligible for component auto-mount.
# Compiled BPF objects in bin/ are loaded by path at runtime, never imported,
# so they are not bundled.
#
# `npm install` still runs first: esbuild resolves the project's own
# dependencies out of node_modules when inlining them.
# No npm step: esbuild is the vendored toolchain binary and the starter pulls
# in no npm packages. Add a package.json + `npm install` only if you import
# one (see README) — esbuild then inlines node_modules at bundle time.
ESBUILD_FLAGS := --bundle --format=esm --platform=neutral \
--main-fields=module,main --conditions=import,module \
--outfile=src/index.jsx --jsx=automatic --jsx-import-source=yeet:tui

bundle: node_modules | toolchain
bundle: | toolchain
$(ESBUILD) src/main.jsx $(ESBUILD_FLAGS) '--external:yeet:*' '--external:*.bpf.o'

node_modules: package.json
$(NPM) install
@touch node_modules

# Post-generation finalize: initialize a git repository with the vendored git
# (fetched via `vendored-git`). Idempotent — skipped if this is already a repo.
# The scaffolders (`yeet new`, `scripts/new`) run `make postgen` after creating
Expand Down
21 changes: 13 additions & 8 deletions template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ shares its `control`; each probe module attaches its own maps.
Makefile build frontend — orchestrates the two compilers
build/bpf.mk clang + bpftool rules: src/bpf/*.bpf.c -> bin/probe.bpf.o
build/gen-vmlinux.sh generates src/bpf/include/vmlinux.h from kernel BTF
package.json esbuild bundle script + npm deps
tsconfig.json `#/` -> project root, `@/` -> ./src path aliases
src/main.jsx entry — composition root: input + mount
src/probes/probe.js loads the shared BPF object (binds maps, start())
Expand Down Expand Up @@ -68,8 +67,9 @@ yeet run . # runs the bundled src/index.jsx (needs root for BPF)

`make` runs two independent compilers: **clang + bpftool** compile
`src/bpf/*.bpf.c` and link them into one loadable object `bin/probe.bpf.o`;
**esbuild** bundles `src/main.jsx` into `src/index.jsx`, inlining npm deps and
the `@/` alias and leaving `yeet:*` builtins external.
**esbuild** bundles `src/main.jsx` into `src/index.jsx`, resolving the `@/`
alias and leaving `yeet:*` builtins external. Both come from the vendored
toolchain — the build needs no system toolchain and no Node/npm.

The data layer loads the object at runtime:

Expand Down Expand Up @@ -122,9 +122,12 @@ which is why the BPF object is located with `import.meta.dirname`.

## npm / jsr packages

Add dependencies to `package.json` and import them normally; esbuild inlines
them at bundle time. Only packages that run in bare V8 work — no Node builtins
(`fs`, `net`, …), and no `Intl` / `TextEncoder` / `TextDecoder`.
The starter pulls in none, so there's no `package.json` and the build never
touches npm. To add one: create a `package.json`, `npm install` your dep, and
import it normally — esbuild inlines it from `node_modules` at bundle time
(this is the only step that needs Node/npm, and only when you opt in). Only
packages that run in bare V8 work — no Node builtins (`fs`, `net`, …), and no
`Intl` / `TextEncoder` / `TextDecoder`.

## Pure-JS scripts

Expand All @@ -135,5 +138,7 @@ feed the components from any source that exposes the same signals.

- `clang` and `bpftool` (for the BPF leg; `bpftool` generates
`src/bpf/include/vmlinux.h` from the host kernel, which needs `CONFIG_DEBUG_INFO_BTF`)
- `node` + `npm` at build time for esbuild (authoring only — not needed on
hosts that merely *run* the built project)

All of these come from the vendored toolchain, so a stock build needs no
system toolchain and no Node/npm. (Node/npm are only needed if you add an npm
package — see above.)
2 changes: 1 addition & 1 deletion template/build/toolchain.lock
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ GIT_SHA256_aarch64=19c6dda22c811324649e6e4aa8c369a8d822463d61d794d0e23e72fb77b53

# esbuild — official static (Go) binary from the @esbuild/<platform> npm
# package, re-hosted on our "toolchain" release. CI records the binary
# checksum. Keep ESBUILD_VERSION in sync with template/package.json.
# checksum.
ESBUILD_VERSION=0.28.1
ESBUILD_SHA256_x86_64=0c6588b092a2c291a72bab90659f3c9e0e25e0fe59c9ac12b4dae4d945e5548c
ESBUILD_SHA256_aarch64=51e829ba36f36be6d9aea6e329ddc4f9350302339b16aaca96a3cb97f64a8ebb
Expand Down
Loading
Loading