oci-zero 0.2.0

A no-std, allocation-free streaming core for OCI registries
Documentation
name: CI

on:
  # `pull_request` is what validates changes: it builds the merge result rather
  # than the branch tip, and for forks it runs with a read-only token and no
  # secrets. An unfiltered `push` would duplicate every one of those runs while
  # never covering fork PRs at all, so `push` is scoped to the default branch to
  # validate merges and keep the badge on main meaningful.
  push:
    branches: [main]
  pull_request:

permissions:
  contents: read

# Superseded pull-request runs are worth cancelling; runs on main are not.
concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
  quality:
    name: Stable Rust
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@d1031067263f94b142dd6c0ce24c5eb9d02d52a0 # v1
        with:
          toolchain: stable
          components: clippy, rustfmt
          targets: wasm32-unknown-unknown
      - run: cargo fmt --all --check
      - run: cargo clippy --workspace --exclude oci-zero-no-std-extract --all-targets --all-features -- -D warnings
      - run: cargo clippy --release -p oci-zero-no-std-extract -- -D warnings
      - run: cargo test --workspace --exclude oci-zero-no-std-extract --all-features
      - name: WebAssembly and Chrome extension checks
        run: |
          cargo check -p oci-zero-web --target wasm32-unknown-unknown
          node --check web/app.js
          node --check web/background.js
          node --check web/build-flash.mjs
          node --check web/flash.js
          node --check web/playwright.config.mjs
          node --check web/scan-worker.js
          node --check web/tests/browser.spec.mjs
          node --check web/tests/firmware-fixture.mjs
          node --check web/tests/flash.spec.mjs
          node --check web/tests/server.mjs
          python3 -m json.tool web/manifest.json > /dev/null
          sh -n tools/build-firmware-artifact.sh
          # bash, not sh: the walk over a nested index recurses and uses arrays.
          bash -n tools/publish-static-registry.sh
      # The QR code committed to examples/esp32c3-ota/README.md is generated from
      # rs-matter's commissioning constants. Regenerate and diff, so changing them
      # fails the build until the README is regenerated too.
      - name: Committed Matter onboarding data is current
        run: |
          cargo run -q -p oci-zero-matter-qr
          git diff --exit-code -- examples/esp32c3-ota/onboarding-qr.svg \
            examples/esp32c3-ota/onboarding-qr.txt \
            examples/esp32c3-ota/onboarding.txt

      - name: Public OCI artifact metadata smoke tests
        run: cargo test --release --test metadata_smoke inspects_public_registry_fixtures -- --ignored --nocapture
      - name: no_std MbedTLS streamed extraction smoke test
        run: |
          cargo build --release -p oci-zero-no-std-extract
          target/release/oci-zero-no-std-extract \
            'https://install.datadoghq.com/v2/agent-package/blobs/sha256:bc219703080f03ad836d51bf7f72cc3ced34f5ba440a49f450d6a5dea98ceff4' \
            application_monitoring.yaml.example > /dev/null
      - name: Official zstd decodeCorpus conformance
        run: |
          curl -fsSLo /tmp/zstd-1.5.7.tar.gz https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz
          echo "eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3  /tmp/zstd-1.5.7.tar.gz" | sha256sum --check
          tar -xzf /tmp/zstd-1.5.7.tar.gz -C /tmp
          make -C /tmp/zstd-1.5.7/tests decodecorpus
          DECODECORPUS=/tmp/zstd-1.5.7/tests/decodecorpus cargo test -p zstd-zero --test conformance decodes_official_decodecorpus_frames -- --ignored
      - run: cargo doc --workspace --exclude oci-zero-no-std-extract --no-deps --all-features
        env:
          RUSTDOCFLAGS: -D warnings
      - run: cargo package -p gzip-zero
      - run: cargo package -p zstd-zero
      # Packaged last: it depends on the two crates above via path + version, so
      # this only resolves once they are published. release-plz publishes it
      # automatically, and this is the only place a broken manifest would surface
      # before release time.
      - run: cargo package -p oci-zero

  supply-chain:
    name: Advisories
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@d1031067263f94b142dd6c0ce24c5eb9d02d52a0 # v1
        with:
          toolchain: stable
      - uses: taiki-e/install-action@d438492cf8a250514fa2d34b30bc3c0dc37c65ff # v2.87.8
        with:
          tool: cargo-deny
      # Gates on the shipped graph only (deny.toml sets exclude-dev).
      - name: Advisories in published dependencies
        run: cargo deny check advisories
      # Test-only stack is pinned for the Rust 1.75 MSRV and has known,
      # currently unfixable advisories, so report without failing the build.
      - name: Advisories in dev-dependencies (informational)
        continue-on-error: true
        run: cargo deny --config deny-dev.toml check advisories

  # Runs the real pages against the real WASM: the registry browser against the
  # local fixture registry, and the flasher against layout tars — including one
  # built by tools/build-firmware-artifact.sh, so the script and the test fixture
  # cannot drift apart unnoticed. No hardware is involved; esptool-js is
  # substituted inside the page.
  browser:
    name: Browser end-to-end
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@d1031067263f94b142dd6c0ce24c5eb9d02d52a0 # v1
        with:
          toolchain: stable
          targets: wasm32-unknown-unknown
      - name: Install wasm-pack
        run: curl -sSf https://rustwasm.github.io/wasm-pack/installer/init.sh | sh
      - name: Build WebAssembly package
        run: web/build.sh
      - run: npm ci
        working-directory: web
      - run: npx playwright install --with-deps chromium
        working-directory: web
      - name: Build a firmware layout tar with the real script
        run: |
          set -eu
          # A stand-in for an espflash image: enough of an esp_app_desc_t for the
          # page's version readback, which is all the layout builder cares about.
          python3 - <<'PY'
          import struct
          image = bytearray(8192)
          image[0:2] = b"\xe9\x01"
          struct.pack_into("<I", image, 0x20, 0xABCD5432)
          image[0x30:0x30 + len("0.0.0-ci")] = b"0.0.0-ci"
          open("firmware.bin", "wb").write(image)
          PY
          ./tools/build-firmware-artifact.sh \
            --image firmware.bin:0x10000 \
            --version 0.0.0-ci \
            --revision "$GITHUB_SHA" \
            --output /tmp/ci-layout
          tar -cf /tmp/ci-firmware.oci.tar -C /tmp/ci-layout .
      - run: npm run test:e2e
        working-directory: web
        env:
          OCI_ZERO_FIRMWARE_TAR: /tmp/ci-firmware.oci.tar
          OCI_ZERO_FIRMWARE_VERSION: 0.0.0-ci
      - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        if: failure()
        with:
          name: playwright-report
          path: web/playwright-report
          retention-days: 7

  msrv:
    name: Rust 1.75 / no_std
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@d1031067263f94b142dd6c0ce24c5eb9d02d52a0 # v1
        with:
          toolchain: "1.75.0"
          targets: thumbv7em-none-eabi
      - run: cargo check -p oci-zero -p gzip-zero -p zstd-zero --lib --no-default-features --target thumbv7em-none-eabi
      - run: cargo check -p oci-zero --lib --no-default-features --features gzip,zstd --target thumbv7em-none-eabi