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
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -576,10 +576,25 @@ Single artifact:
timeout: 8m
```

Command mode — run your project's own loader on every matrix kernel (the
per-kernel verdict is the loader's exit code), against the built-in
[library of known-tricky vendor kernels](docs/kernel-quirk-library.md):

```yaml
- uses: Kernel-Guard/bpfcompat@v0.2.0
with:
command: $BPFCOMPAT_BIN --self-test
command-binary: build/myloader # static or fully self-contained binary
matrix: quirk-library # bare name -> matrices/ shipped with the action
out: reports/bpfcompat.json
```

Marketplace quick start:

1. Add a self-hosted Linux runner with KVM enabled.
2. Commit compiled `.bpf.o` artifacts, manifests, and a matrix YAML.
1. Use a stock `ubuntu-latest` runner (it exposes `/dev/kvm`); a self-hosted
KVM runner is only needed for wide matrices or ARM64.
2. Commit compiled `.bpf.o` artifacts (or point `command` at your loader),
plus a matrix YAML — or use a built-in matrix name like `quirk-library`.
3. Use the action in CI to produce JSON, Markdown, and job-summary evidence.
4. Treat exit code `2` as a compatibility gate failure.

Expand Down
60 changes: 55 additions & 5 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,20 @@ inputs:
description: Path to compiled .bpf.o artifact.
required: false
default: ""
command:
description: "Command-mode validation: shell command run as root inside each kernel VM; the per-kernel verdict is its exit code. Use instead of (or alongside) artifact to validate via your project's own loader binary. Exposes $BPFCOMPAT_BIN, $BPFCOMPAT_ARTIFACT, and $BPFCOMPAT_REMOTE_ROOT."
required: false
default: ""
command-binary:
description: Local loader executable shipped into each guest and exposed to command as $BPFCOMPAT_BIN.
required: false
default: ""
command-expect-exit:
description: Exit code that counts as a pass in command mode.
required: false
default: "0"
matrix:
description: Path to matrix YAML.
description: "Path to matrix YAML. A bare name (for example quirk-library) that does not exist in the caller repository resolves to the matching matrices/<name>.yaml shipped with the action."
required: false
default: ""
out:
Expand Down Expand Up @@ -125,6 +137,12 @@ runs:

- name: Run bpfcompat
shell: bash
env:
# Free-text inputs go through the environment, never inline
# interpolation, so they cannot inject host-side shell syntax.
INPUT_COMMAND: ${{ inputs.command }}
INPUT_COMMAND_BINARY: ${{ inputs.command-binary }}
INPUT_COMMAND_EXPECT_EXIT: ${{ inputs.command-expect-exit }}
run: |
set -euo pipefail

Expand All @@ -146,6 +164,19 @@ runs:

artifact_path="$(resolve_path "${{ inputs.artifact }}")"
matrix_path="$(resolve_path "${{ inputs.matrix }}")"
command_binary_path="$(resolve_path "$INPUT_COMMAND_BINARY")"

# Built-in matrix convenience: a bare name (e.g. quirk-library) that
# does not exist in the caller repo resolves to the matrices/ directory
# shipped with the action.
if [[ -n "$matrix_path" && ! -f "$matrix_path" ]]; then
matrix_input="${{ inputs.matrix }}"
if [[ "$matrix_input" != /* && -f "$action_root/matrices/${matrix_input}.yaml" ]]; then
matrix_path="$action_root/matrices/${matrix_input}.yaml"
elif [[ "$matrix_input" != /* && -f "$action_root/$matrix_input" ]]; then
matrix_path="$action_root/$matrix_input"
fi
fi
out_path="$(resolve_path "${{ inputs.out }}")"
manifest_path="$(resolve_path "${{ inputs.manifest }}")"
markdown_path="$(resolve_path "${{ inputs.markdown }}")"
Expand Down Expand Up @@ -218,8 +249,8 @@ runs:
exit "$status"
fi

if [[ -z "$artifact_path" ]]; then
echo "::error::artifact is required unless suite is set"
if [[ -z "$artifact_path" && -z "$INPUT_COMMAND" ]]; then
echo "::error::artifact or command is required unless suite is set"
exit 1
fi
if [[ -z "$matrix_path" ]]; then
Expand All @@ -231,10 +262,18 @@ runs:
exit 1
fi

if [[ ! -f "$artifact_path" ]]; then
if [[ -n "$artifact_path" && ! -f "$artifact_path" ]]; then
echo "::error::artifact not found: $artifact_path"
exit 1
fi
if [[ -n "$command_binary_path" && ! -f "$command_binary_path" ]]; then
echo "::error::command-binary not found: $command_binary_path"
exit 1
fi
if [[ -n "$command_binary_path" && -z "$INPUT_COMMAND" ]]; then
echo "::error::command-binary requires command"
exit 1
fi
if [[ ! -f "$matrix_path" ]]; then
echo "::error::matrix not found: $matrix_path"
exit 1
Expand All @@ -249,14 +288,25 @@ runs:
cmd=(
"$binary_path"
test
--artifact "$artifact_path"
--matrix "$matrix_path"
--out "$out_path"
--timeout "${{ inputs.timeout }}"
--workdir "$workdir_path"
--concurrency "${{ inputs.concurrency }}"
)

if [[ -n "$artifact_path" ]]; then
cmd+=(--artifact "$artifact_path")
fi
if [[ -n "$INPUT_COMMAND" ]]; then
cmd+=(--command "$INPUT_COMMAND")
if [[ -n "$command_binary_path" ]]; then
cmd+=(--command-binary "$command_binary_path")
fi
if [[ -n "$INPUT_COMMAND_EXPECT_EXIT" && "$INPUT_COMMAND_EXPECT_EXIT" != "0" ]]; then
cmd+=(--command-expect-exit "$INPUT_COMMAND_EXPECT_EXIT")
fi
fi
if [[ -n "$manifest_path" ]]; then
cmd+=(--manifest "$manifest_path")
fi
Expand Down
22 changes: 22 additions & 0 deletions docs/command-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,28 @@ inside it freely: pipes, `&&`, redirects.
artifact identity is content-addressed from the command string
(`command://<name>`), so `compare`/history still work.

## GitHub Action

The composite action supports command mode directly, so a project can gate CI
on its own loader with one step. A bare `matrix` name resolves to the
`matrices/` directory shipped with the action — `quirk-library` gives you the
[library of known-tricky vendor kernels](kernel-quirk-library.md) with no file
to copy:

```yaml
- uses: Kernel-Guard/bpfcompat@v0.2.0
with:
command: $BPFCOMPAT_BIN --self-test
command-binary: build/myloader
command-expect-exit: "0" # optional, default 0
matrix: quirk-library
out: reports/bpfcompat.json
```

The `command` string is passed to the runner through the environment (never
interpolated into the action's shell), and inside the guest it is executed as a
single quoted `bash -lc` operand, exactly as in the CLI flow.

## Scope / limitations (first cut)

- Command mode currently supports the **`vm`** runner only (the default). It is
Expand Down
Loading