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
156 changes: 156 additions & 0 deletions .github/workflows/research-repeat-v1.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
name: research-repeat-v1

on:
workflow_dispatch:
pull_request:
paths:
- ".github/workflows/research-repeat-v1.yml"
- "research/repeat/v1/**"
- "research/data/v1/**"
- "research/corpus/v1/**"
- "scripts/research/run-repeat-v1.sh"
- "scripts/research/analyze-repeat-v1.py"
- "scripts/research/materialize-v1.sh"
- "scripts/research/verify-materialization-v1.sh"
- "scripts/research/verify-profile-lock-v1.sh"

permissions:
contents: read

env:
GO_VERSION: "1.25.14"

jobs:
preflight:
name: Repeat stability preflight
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0
persist-credentials: false

- name: Static checks
run: |
set -euo pipefail
bash -n scripts/research/run-repeat-v1.sh
python3 -m py_compile scripts/research/analyze-repeat-v1.py
python3 scripts/research/analyze-repeat-v1.py --self-test
jq -e . research/repeat/v1/stability-sample.json >/dev/null

- name: Verify sample bindings
run: |
set -euo pipefail
python3 - <<'PY'
import json
from pathlib import Path

sample=json.loads(Path("research/repeat/v1/stability-sample.json").read_text())
plan=json.loads(Path("research/corpus/v1/study-plan.json").read_text())
lock=json.loads(Path("research/corpus/v1/profile-identities.json").read_text())
cases={x["id"] for x in plan["cases"]}
profiles={x["id"] for x in lock["profiles"]}
ids=set()
for row in sample["tuples"]:
assert row["id"] not in ids, f"duplicate tuple id: {row['id']}"
ids.add(row["id"])
assert row["case_id"] in cases, row
assert row["profile_id"] in profiles, row
shard=Path("research/data/v1/processed/executions")/f"{row['case_id']}.jsonl"
matches=[json.loads(x) for x in shard.read_text().splitlines()
if x.strip() and json.loads(x)["logical_profile_id"]==row["profile_id"]]
assert len(matches)==1, row
assert sample["repeats_per_tuple"]==3
assert len(sample["tuples"])==7
print("[research-repeat-v1] sample bindings PASS")
PY

execute:
name: Execute 21-attempt repeat stability sample
if: github.event_name == 'workflow_dispatch'
needs: preflight
runs-on: ubuntu-24.04
timeout-minutes: 240
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.sha }}
fetch-depth: 0
persist-credentials: false

- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: ${{ env.GO_VERSION }}
cache: true

- name: Install build and VM dependencies
run: |
set -euo pipefail
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
build-essential cmake clang llvm pkg-config autoconf automake libtool \
libbpf-dev libelf-dev libzstd-dev zlib1g-dev jq curl \
qemu-system-x86 qemu-utils cloud-image-utils openssh-client
if [[ -e /dev/kvm ]]; then
sudo chmod 0666 /dev/kvm
else
echo "::warning::/dev/kvm absent; repeat sample will use TCG."
fi

- name: Install checksum-verified bpftool v7.5.0
run: |
set -euo pipefail
curl -fsSL -o /tmp/bpftool-v7.5.0-amd64.tar.gz \
https://github.com/libbpf/bpftool/releases/download/v7.5.0/bpftool-v7.5.0-amd64.tar.gz
curl -fsSL -o /tmp/bpftool-v7.5.0-amd64.tar.gz.sha256sum \
https://github.com/libbpf/bpftool/releases/download/v7.5.0/bpftool-v7.5.0-amd64.tar.gz.sha256sum
(cd /tmp && sha256sum -c bpftool-v7.5.0-amd64.tar.gz.sha256sum)
tar -xzf /tmp/bpftool-v7.5.0-amd64.tar.gz -C /tmp
sudo install -m 0755 /tmp/bpftool /usr/local/bin/bpftool

- name: Re-materialize frozen v1 inputs
run: |
set -euo pipefail
bash scripts/research/materialize-v1.sh dist/research-corpus-v1
bash scripts/research/verify-materialization-v1.sh dist/research-corpus-v1
bash scripts/research/verify-profile-lock-v1.sh

- name: Execute repeat stability sample
run: >-
bash scripts/research/run-repeat-v1.sh
dist/research-corpus-v1
reports/research-repeat-v1
research/repeat/v1/stability-sample.json

- name: Publish repeat summary
if: always()
run: |
if [[ -s reports/research-repeat-v1/normalized/stability-summary.json ]]; then
{
echo "## Research pilot v1 repeat stability"
echo
echo '~~~json'
cat reports/research-repeat-v1/normalized/stability-summary.json
echo '~~~'
} >> "$GITHUB_STEP_SUMMARY"
fi

- name: Upload repeat evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: research-repeat-v1-${{ github.run_id }}
retention-days: 90
if-no-files-found: warn
path: |
reports/research-repeat-v1/
dist/research-corpus-v1/materialization.json
dist/research-corpus-v1/SHA256SUMS
.bpfcompat/research-repeat-v1/**/targets/**/serial.log
.bpfcompat/research-repeat-v1/**/targets/**/qemu.log
.bpfcompat/research-repeat-v1/**/targets/**/libbpf.log
.bpfcompat/research-repeat-v1/**/targets/**/validator-result.json
.bpfcompat/research-repeat-v1/**/targets/**/validator.stderr
.bpfcompat/research-repeat-v1/**/targets/**/validator-exit-code
46 changes: 46 additions & 0 deletions research/repeat/v1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Pilot v1 Repeat-Run Stability

This directory defines a **post-collection, purposefully stratified** repeat-run
sample for pilot v1. It is not a preregistered sample and it is not intended to
estimate a population-wide nondeterminism rate.

The sample covers seven canonical execution tuples:

- a compatible controlled baseline;
- a known ring-buffer incompatibility below the upstream boundary;
- the AlmaLinux 8 / 4.18 ring-buffer backport case;
- positive and negative Falco real-loader cases;
- a positive cilium/ebpf project-loader case;
- the Oracle logical-profile environment mismatch.

Each tuple is repeated three times in one workflow collection, for 21 planned
attempts. Frozen v1 artifacts, loaders, validation semantics, and profile
definitions are reused.

## Interpretation

The repeat analyzer distinguishes two failure modes:

1. **environment drift** — the repeated execution resolves to a different
`exact_environment_id` than the canonical run. This is environmental
change, not compatibility nondeterminism;
2. **verdict instability** — the repeated execution resolves to the same exact
environment but produces a different compatibility verdict.

A repeat can only be called stable against the canonical observation when both
the exact environment ID and normalized verdict match.

The workflow is manual-only because it boots real vendor VMs and is intended as
a bounded research validation, not a routine CI gate.

## Run

After this protocol lands on `main`:

```bash
gh workflow run research-repeat-v1.yml --repo Kernel-Guard/bpfcompat --ref main
```

The workflow publishes raw repeat reports, logs, a repeat provenance record,
`repeat-executions.jsonl`, `stability-summary.json`, and generated
`RESULTS.md` as a staging Actions artifact.
60 changes: 60 additions & 0 deletions research/repeat/v1/stability-sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"schema_version": "bpfcompat.research.repeat-sample.v1",
"corpus_version": "v1",
"canonical_run_id": "35393833464",
"canonical_run_sha": "5de550e5cc8c659872a90fc262eb0250c229bf23",
"sampling_design": "purposeful_stratified_post_collection",
"repeats_per_tuple": 3,
"interpretation": "This is a post-collection stability check, not a preregistered or population-random sample. It intentionally covers compatible, incompatible, vendor-backport, real-loader, project-loader, and inconclusive environment-mismatch strata.",
"tuples": [
{
"id": "positive-controlled-modern",
"case_id": "simple-pass-libbpf",
"profile_id": "ubuntu-22.04-5.15",
"stratum": "compatible_controlled",
"rationale": "Positive controlled baseline on a modern LTS kernel."
},
{
"id": "negative-ringbuf-boundary",
"case_id": "ringbuf-modern-libbpf",
"profile_id": "ubuntu-20.04-5.4",
"stratum": "incompatible_controlled",
"rationale": "Known below-upstream-threshold ring-buffer rejection."
},
{
"id": "positive-ringbuf-backport",
"case_id": "ringbuf-modern-libbpf",
"profile_id": "almalinux-8-4.18",
"stratum": "compatible_vendor_backport",
"rationale": "Older-numbered vendor kernel that passed the ring-buffer probe."
},
{
"id": "negative-falco-real-loader",
"case_id": "falco-modern-bpf-scap-open",
"profile_id": "amazon-linux-2-4.14",
"stratum": "incompatible_real_loader",
"rationale": "Real Falco loader negative case."
},
{
"id": "positive-falco-real-loader",
"case_id": "falco-modern-bpf-scap-open",
"profile_id": "ubuntu-22.04-5.15",
"stratum": "compatible_real_loader",
"rationale": "Real Falco loader positive case."
},
{
"id": "positive-cilium-project-loader",
"case_id": "cilium-tracepoint-ebpf-go",
"profile_id": "ubuntu-22.04-5.15",
"stratum": "compatible_project_loader",
"rationale": "cilium/ebpf project-loader path."
},
{
"id": "inconclusive-oracle-environment",
"case_id": "simple-pass-libbpf",
"profile_id": "oracle-linux-9-uek7-5.15",
"stratum": "inconclusive_environment_mismatch",
"rationale": "Canonical run requested 5.15 but booted 6.12 UEK; rerun checks whether the exact environment and inconclusive result are stable."
}
]
}
Loading
Loading