libxml-rs 0.1.0-alpha.49

Native-Rust forensic reimplementation of libxml2+libxslt with C ABI drop-in replacement. Cross-version oracle matrix (libxml2 2.7.8-2.15.3, libxslt 1.1.26-1.1.45) with semantic epochs; full xmllint/xmlcatalog/xsltproc CLIs; differential-court-verified C API closure; three-DSO ELF packaging (libxml2.so.16 core + libxslt.so.1/libexslt.so.0 facades, upstream NEEDED chain); fail-closed oracle-isolated ABI-FUNCTION-SIGNATURE plane (SOURCE_PROTOTYPE + MACHINE_ABI fingerprints, zero silent omissions); Phase-12 real downstream substitution (binary/static/docker substitution, export-surface disposition, ELF version graphs); Phase-13 hostile audit courts (ABI/ownership/allocator/callbacks/failure/threads/oracle-contamination) byte-identical vs the system oracle incl. the upstream thread-local globals model; Phase-14 downstream custodian validation courts (lxml/Nokogiri/PHP/Debian). Test counts live in atlas/TEST_COUNTS.json, residuals in atlas/RESIDUAL_LEDGER.json (generated evidence).
Documentation
name: ci

# libxml-rs drop-in regression gate. The single source of truth for "did a
# change regress the library" is `tools/courts/regression.sh`, which runs the
# unit/integration suite (including the proptest fuzz smoke) and links the
# three-DSO drop-in in release. This workflow adds the oracle-vs-candidate
# Pareto matrix and a coverage-guided fuzz smoke on nightly.

on:
  push:
    branches: [main]
  pull_request:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  test:
    name: test + release link + bench compile (stable)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@stable

      - uses: Swatinem/rust-cache@v2

      # Regression gate: unit + integration + proptest fuzz smoke.
      - name: cargo test --lib
        run: cargo test --lib

      # The three-DSO drop-in actually links in release (custom linker wrapper
      # + facade generation exercise the full packaging path).
      - name: cargo build --release --lib
        run: cargo build --release --lib

      # Criterion benchmarks must at least compile (criterion needs unwind,
      # which [profile.bench] provides independently of the release cdylib).
      - name: cargo bench --no-run
        run: cargo bench --bench benchmarks --no-run

      # Fail-closed regression gate (equivalent to the two commands above, run
      # as the authoritative assertion). Kept separate so a failure is legible.
      - name: regression court
        run: sh tools/courts/regression.sh

  fuzz:
    name: coverage-guided fuzz smoke (nightly)
    runs-on: ubuntu-latest
    continue-on-error: true
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@nightly

      - uses: Swatinem/rust-cache@v2

      - name: install cargo-fuzz
        run: cargo install cargo-fuzz --locked

      # Each target compiles against libFuzzer and runs a 30-second smoke so
      # a broken target (rather than a found crash) fails the job.
      - name: fuzz parse (30s)
        run: cargo fuzz run parse -- -max_total_time=30

      - name: fuzz html (30s)
        run: cargo fuzz run html -- -max_total_time=30

      - name: fuzz xpath (30s)
        run: cargo fuzz run xpath -- -max_total_time=30

  pareto:
    name: oracle-vs-candidate Pareto matrix
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@stable

      - uses: Swatinem/rust-cache@v2

      # Build the optimized candidate DSOs, then run the matrix in the minimal
      # Docker image that also ships the upstream oracle at /usr/local.
      - name: build release drop-in
        # facade-gen.sh must run AFTER cargo build: build.rs emits the
        # whole-archive libxslt.so.1 facade BEFORE the core lib is linked on a
        # clean checkout ("Library not yet built — symlinks will be recreated
        # on a later build"), and a timestamp-skip leaves it stale after core
        # edits. Without the explicit regen the matrix candidate segfaults in
        # xslt_apply (the XSLT engine lives inside the facade).
        run: |
          cargo build --release --lib
          sh tools/packaging/facade-gen.sh target/release

      # Build the oracle court image from the pinned-source Dockerfile so the
      # matrix never depends on a host-only image (the earlier
      # libxml-rs/phase14-debian:1 reference only exists on the developer
      # host). The build fetches the pinned libxml2 2.15.3 / libxslt 1.1.45
      # tarballs from GNOME and verifies their SHA-256 before compiling into
      # /usr/local (same receipt as the local court image).
      - name: build oracle court image
        run: |
          docker build -t libxml-rs/oracle:2.15.3 \
            --build-arg LIBXML2_SHA256=78262a6e7ac170d6528ebfe2efccdf220191a5af6a6cd61ea4a9a9a5042c7a07 \
            --build-arg LIBSXLT_SHA256=9acfe68419c4d06a45c550321b3212762d92f41465062ca4ea19e632ee5d216e \
            -f docker/Dockerfile.oracle .

      - name: Pareto matrix (docker)
        run: sh tools/bench/run_in_docker.sh target/bench-matrix
        env:
          BENCH_IMAGE: libxml-rs/oracle:2.15.3

      - name: upload matrix
        uses: actions/upload-artifact@v4
        with:
          name: bench-matrix
          path: target/bench-matrix/