Introduce OCI image unpack feature #443
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Static analyzers over the macOS Apple Silicon build. | |
| # | |
| # tidy-macos : clang-tidy via `make lint` | |
| # scan-macos : LLVM scan-build via `make analyze` | |
| # infer-macos : Facebook Infer capture + analyze over the full build | |
| name: Static analysis | |
| # All three jobs analyze "make elfuse" and nothing else, so tests/ joins the | |
| # prose and configuration below: a change there cannot alter a single | |
| # translation unit any of them sees. paths-ignore skips the run only when EVERY | |
| # changed file matches, and anything not listed still runs the full set, which | |
| # is the safe direction for a path that turns out to matter after all. | |
| # | |
| # On pull_request only, and the same conditions build.yml states at length: one | |
| # list per file so nothing can drift, and a path filter skips the whole run, so | |
| # a REQUIRED check that never reports would stay pending. main has no branch | |
| # protection today; making these required means moving the filter into the | |
| # jobs. | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| paths-ignore: | |
| - '**.md' | |
| - 'docs/**' | |
| - 'LICENSE' | |
| - 'tests/**' | |
| - '.agents/**' | |
| - '.claude/**' | |
| - '.editorconfig' | |
| - '.clang-format' | |
| - 'frama-c-stubs/**' | |
| - '.github/workflows/build.yml' | |
| - '.github/workflows/lint.yml' | |
| - '.github/workflows/verify.yml' | |
| workflow_dispatch: | |
| # A merge queue runs the merged result, not the PR, and merge_group carries | |
| # no path filter and no pull_request payload: every check runs in full there. | |
| # Without this trigger a queue would merge with nothing having run at all. | |
| merge_group: | |
| # Cancel in-progress runs for the same PR; keep main runs going. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| permissions: | |
| contents: read | |
| jobs: | |
| # clang-tidy via `make lint`. Runs in parallel with build/scan jobs. | |
| # Mostly advisory: findings are logged for review. The exception is | |
| # readability-function-size, which .clang-tidy names in WarningsAsErrors, | |
| # so a function crossing the 400-line ceiling fails this job. | |
| tidy-macos: | |
| name: clang-tidy (macOS Apple Silicon) | |
| runs-on: macos-15 | |
| timeout-minutes: 20 | |
| env: | |
| GNU_OBJCOPY: /opt/homebrew/opt/binutils/bin/objcopy | |
| HOMEBREW_NO_INSTALL_CLEANUP: 1 | |
| HOMEBREW_NO_AUTO_UPDATE: 1 | |
| # binutils is needed because make lint depends on the shim_blob.h | |
| # generated by the assembly + objcopy pipeline. | |
| BREW_PKGS: binutils llvm | |
| CLANG_TIDY: /opt/homebrew/opt/llvm/bin/clang-tidy | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - name: Cache Homebrew downloads | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/Library/Caches/Homebrew/downloads | |
| key: brew-${{ runner.os }}-${{ runner.arch }}-${{ env.BREW_PKGS }} | |
| - name: Install Homebrew packages | |
| # shellcheck disable=SC2086 -- BREW_PKGS is a space-separated list. | |
| run: | | |
| set -euo pipefail | |
| brew install --quiet $BREW_PKGS | |
| "$CLANG_TIDY" --version | head -1 | |
| - name: clang-tidy (make lint) | |
| run: make lint | |
| # LLVM scan-build via `make analyze`. Runs in parallel with build/tidy. | |
| # Advisory: scan-build's Make target does not pass --status-bugs, so | |
| # findings appear in logs and in the uploaded HTML report but do not | |
| # gate the job. | |
| scan-macos: | |
| name: scan-build (macOS Apple Silicon) | |
| runs-on: macos-15 | |
| timeout-minutes: 25 | |
| env: | |
| GNU_OBJCOPY: /opt/homebrew/opt/binutils/bin/objcopy | |
| HOMEBREW_NO_INSTALL_CLEANUP: 1 | |
| HOMEBREW_NO_AUTO_UPDATE: 1 | |
| BREW_PKGS: binutils llvm | |
| LLVM_BIN: /opt/homebrew/opt/llvm/bin | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - name: Cache Homebrew downloads | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/Library/Caches/Homebrew/downloads | |
| key: brew-${{ runner.os }}-${{ runner.arch }}-${{ env.BREW_PKGS }} | |
| - name: Install Homebrew packages | |
| # shellcheck disable=SC2086 -- BREW_PKGS is a space-separated list. | |
| # scan-build has no --version; piping --help into `head -1` makes | |
| # perl take SIGPIPE on the closed stdout and exit non-zero, which | |
| # under pipefail fails the step. Just confirm the binary exists. | |
| run: | | |
| set -euo pipefail | |
| brew install --quiet $BREW_PKGS | |
| test -x "$LLVM_BIN/scan-build" | |
| "$LLVM_BIN/clang" --version | head -1 | |
| - name: scan-build (make analyze) | |
| run: | | |
| set -euo pipefail | |
| export PATH="$LLVM_BIN:$PATH" | |
| mkdir -p build/scan-build | |
| scan-build -o build/scan-build --use-cc="$(command -v clang)" \ | |
| make -B elfuse | |
| - name: Upload scan-build report | |
| if: ${{ !cancelled() }} | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: scan-build-${{ runner.os }}-${{ runner.arch }} | |
| path: build/scan-build | |
| retention-days: 7 | |
| if-no-files-found: ignore | |
| # Facebook Infer over the full elfuse build. Must run on macOS Apple | |
| # Silicon because the build needs Hypervisor.framework and -arch arm64; | |
| # Infer captures the real clang invocations, so it sees every TU. | |
| # | |
| # Gating (unlike tidy-macos/scan-macos): a separate step turns Infer's | |
| # report.json into inline ::error:: annotations plus a job summary, then | |
| # fails the job. Findings surface on the PR instead of a silent exit code, | |
| # so bugs are pruned at PR time instead of merged. | |
| infer-macos: | |
| name: Infer (macOS Apple Silicon) | |
| runs-on: macos-15 | |
| timeout-minutes: 25 | |
| env: | |
| GNU_OBJCOPY: /opt/homebrew/opt/binutils/bin/objcopy | |
| HOMEBREW_NO_INSTALL_CLEANUP: 1 | |
| HOMEBREW_NO_AUTO_UPDATE: 1 | |
| BREW_PKGS: binutils | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - name: Cache Homebrew downloads | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/Library/Caches/Homebrew/downloads | |
| key: brew-${{ runner.os }}-${{ runner.arch }}-${{ env.BREW_PKGS }} | |
| - name: Install GNU objcopy | |
| # shellcheck disable=SC2086 -- BREW_PKGS is a space-separated list. | |
| run: | | |
| set -euo pipefail | |
| brew install --quiet $BREW_PKGS | |
| "$GNU_OBJCOPY" --version | head -1 | |
| - name: Setup Infer | |
| # infer_version pins the Infer binary; the action itself tracks the v1 | |
| # tag. | |
| uses: srz-zumix/setup-infer@v1 | |
| with: | |
| infer_version: v1.3.0 | |
| # .inferconfig disables PULSE_UNINITIALIZED_VALUE repo-wide. Pulse cannot | |
| # prove guest_copy's chunked "while (copied < len)" loop fills its | |
| # destination, so every guest_read_small caller looks uninitialized; the | |
| # findings were audited and every caller checks the return value. The rest | |
| # of the Infer gate is untouched: null dereference, use-after-free, leaks, | |
| # dead stores and stack-address escape all still fail the job. | |
| # | |
| # The cost is real and repo-wide: a genuinely uninitialized read added | |
| # after this point is not caught here. Scoping it narrower was tried and | |
| # is worse -- the findings span thirteen files including syscall.c and | |
| # proc.c, so a path block list suppresses the same class over most of the | |
| # syscall surface while being harder to read, and censor-report does not | |
| # take effect through `infer run` in v1.3.0. `make infer-uninit` re-runs | |
| # the analysis with the checker back on and prints the count, so whether | |
| # an Infer upgrade has made this unnecessary is one command away. | |
| - name: Infer capture + analyze (make -B elfuse) | |
| # -B forces a clean rebuild so Infer captures every translation unit. | |
| # Non-C build steps (shim.S assembly, objcopy) pass through untouched. | |
| # No --fail-on-issue here: `infer run` must exit 0 so the reporting | |
| # step below runs and surfaces findings before the job fails. | |
| # --keep-going tolerates a frontend failure on an odd TU, but that can | |
| # also mask a total capture miss (wrapper never intercepts clang, 0 | |
| # files analyzed). The count guard fails the job on that silent no-op. | |
| run: | | |
| set -euo pipefail | |
| infer run --keep-going -- make -B elfuse 2>&1 | tee infer-run.log | |
| n=$(grep -oE 'Found [0-9]+ source file' infer-run.log \ | |
| | grep -oE '[0-9]+' | tail -1 || true) | |
| echo "Infer captured ${n:-0} source files" | |
| test "${n:-0}" -gt 0 | |
| - name: Report Infer findings | |
| # Emit GitHub annotations + a job summary from report.json, then exit | |
| # non-zero if any finding exists. Runs even when a prior step failed so | |
| # a partial report is still surfaced. | |
| if: ${{ !cancelled() }} | |
| run: python3 scripts/infer-annotate.py infer-out/report.json | |
| - name: Upload Infer report | |
| if: ${{ !cancelled() }} | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: infer-${{ runner.os }}-${{ runner.arch }} | |
| path: infer-out/report.txt | |
| retention-days: 7 | |
| if-no-files-found: warn |