diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..e912774c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,19 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "cargo" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "daily" + cooldown: + default-days: 7 + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "daily" + cooldown: + default-days: 7 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..dedcc7cb --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,108 @@ +name: Release +on: + push: + tags: ['v*'] + workflow_dispatch: + inputs: + dry-run: + description: 'Run cargo publish with --dry-run (skips registry push and GH release)' + type: boolean + default: false + +jobs: + verify-version: + if: ${{ startsWith(github.ref, 'refs/tags/v') }} + runs-on: ubuntu-latest + outputs: + version: ${{ steps.v.outputs.version }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - id: v + run: | + TAG_VERSION="${GITHUB_REF_NAME#v}" + # workspace.package.version lives in the root Cargo.toml + CRATE_VERSION=$(grep -m1 '^version' Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/') + if [ "$TAG_VERSION" != "$CRATE_VERSION" ]; then + echo "Tag version ($TAG_VERSION) does not match workspace version ($CRATE_VERSION)" >&2 + exit 1 + fi + echo "version=$TAG_VERSION" >> "$GITHUB_OUTPUT" + + package-crate: + needs: [verify-version] + runs-on: ubuntu-latest + permissions: + contents: read + env: + CARGO_REGISTRIES_GEN0SEC_INDEX: sparse+https://crates-internal.g0s.dev/api/v1/crates/ + CARGO_REGISTRIES_GEN0SEC_TOKEN: ${{ secrets.GEN0SEC_CARGO_TOKEN }} + CARGO_REGISTRIES_GEN0SEC_CREDENTIAL_PROVIDER: cargo:token + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable + - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + - name: cargo package (wirefilter-engine) + run: cargo package -p wirefilter-engine --registry gen0sec --locked + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: wirefilter-engine-crate + path: target/package/wirefilter-engine-${{ needs.verify-version.outputs.version }}.crate + if-no-files-found: error + retention-days: 7 + + publish: + needs: [verify-version, package-crate] + runs-on: ubuntu-latest + environment: release + permissions: + contents: read + env: + CARGO_REGISTRIES_GEN0SEC_INDEX: sparse+https://crates-internal.g0s.dev/api/v1/crates/ + CARGO_REGISTRIES_GEN0SEC_TOKEN: ${{ secrets.GEN0SEC_CARGO_TOKEN }} + CARGO_REGISTRIES_GEN0SEC_CREDENTIAL_PROVIDER: cargo:token + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable + - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + - name: Cargo publish (wirefilter-engine) + env: + DRY_RUN: ${{ inputs.dry-run }} + CARGO_HTTP_TIMEOUT: '300' + CARGO_HTTP_LOW_SPEED_LIMIT: '1' + CARGO_NET_RETRY: '5' + run: | + ARGS="-p wirefilter-engine --registry gen0sec --locked" + if [ "$DRY_RUN" = "true" ]; then + ARGS="$ARGS --dry-run" + fi + for attempt in 1 2 3; do + if cargo publish $ARGS; then exit 0; fi + echo "Publish attempt $attempt failed, retrying in 15s..." + sleep 15 + done + echo "Publish failed after 3 attempts" >&2 + exit 1 + + gh-release: + needs: [verify-version, package-crate, publish] + if: ${{ startsWith(github.ref, 'refs/tags/v') && inputs.dry-run != true }} + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: wirefilter-engine-crate + path: release-assets + - name: SHA256 checksums + run: | + set -euo pipefail + cd release-assets + for f in *; do [ -f "$f" ] && sha256sum "$f" > "${f}.sha256"; done + ls -la + - uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0 + with: + draft: false + generate_release_notes: true + files: release-assets/* + make_latest: true diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 94cf9aa7..f2881fe0 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -8,12 +8,15 @@ on: env: CARGO_TERM_COLOR: always + CARGO_REGISTRIES_GEN0SEC_INDEX: sparse+https://crates-internal.g0s.dev/api/v1/crates/ + CARGO_REGISTRIES_GEN0SEC_TOKEN: ${{ secrets.GEN0SEC_CARGO_TOKEN }} + CARGO_REGISTRIES_GEN0SEC_CREDENTIAL_PROVIDER: cargo:token jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions-rust-lang/setup-rust-toolchain@v1 + - uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 with: toolchain: stable components: clippy @@ -33,17 +36,17 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions-rust-lang/setup-rust-toolchain@v1 + - uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 with: toolchain: nightly components: rustfmt - - uses: tombi-toml/setup-tombi@v1 + - uses: tombi-toml/setup-tombi@9880d1d3ba5e745d410c697366c513b337704388 - name: Print versions run: | cargo fmt --version tombi --version - name: Check code formatting - uses: actions-rust-lang/rustfmt@v1 + uses: actions-rust-lang/rustfmt@4066006ec54a31931b9b1fddfd38f2fdf2d27143 - name: Check toml formatting run: tombi format --check @@ -54,7 +57,7 @@ jobs: RUSTDOCFLAGS: -D warnings steps: - uses: actions/checkout@v4 - - uses: actions-rust-lang/setup-rust-toolchain@v1 + - uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 with: toolchain: stable - name: Print versions @@ -74,7 +77,7 @@ jobs: MIRIFLAGS: -Zmiri-disable-isolation steps: - uses: actions/checkout@v4 - - uses: actions-rust-lang/setup-rust-toolchain@v1 + - uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 with: toolchain: nightly components: miri @@ -90,7 +93,7 @@ jobs: sanitizer: [address, thread, leak] steps: - uses: actions/checkout@v4 - - uses: actions-rust-lang/setup-rust-toolchain@v1 + - uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 with: toolchain: nightly components: rust-src diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 79bd2f61..1655ce13 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -6,10 +6,16 @@ edition.workspace = true description = "An execution engine for Wireshark-like filters" readme = "README.md" repository = "https://github.com/cloudflare/wirefilter" +license = "MIT" keywords = ["engine", "filter", "parser", "runtime", "wireshark"] categories = ["config", "parser-implementations"] +links = "wirefilter-engine" publish.workspace = true +[package.metadata.release] +publish = false +tag-name = "v{{version}}" + [lib] bench = false name = "wirefilter" diff --git a/engine/README.md b/engine/README.md index 85396b8b..f941ca0d 100644 --- a/engine/README.md +++ b/engine/README.md @@ -95,3 +95,60 @@ Try deleting the compiled binary and re-building with `cargo afl build`. ## Licensing Licensed under the MIT license. See the [LICENSE](LICENSE) file for details. + +## Release Process + +The `wirefilter-engine` crate (workspace member) is published to the +private `gen0sec` Cargo registry (`https://crates-internal.g0s.dev`). +The other workspace members (`wirefilter-ffi`, `wirefilter-wasm`, fuzz +targets) are marked `publish = false` and are not released. Releases +are driven by `vX.Y.Z` git tags — `.github/workflows/release.yaml` +handles build, publish, and GitHub Release creation. + +### One-time setup + +- **Repo secret**: `GEN0SEC_CARGO_TOKEN` — bearer token for the registry. +- **`release` GitHub environment** (Settings → Environments → New) for + optional manual approval gating before publish. +- **Local cargo config** (`~/.cargo/config.toml`): + + ```toml + [registries.gen0sec] + index = "sparse+https://crates-internal.g0s.dev/api/v1/crates/" + credential-provider = ["cargo:token"] + token = "" + ``` + +### Cutting a release + +The workspace version lives in `[workspace.package]` in the root +`Cargo.toml`. Use `cargo-release` from the workspace root: + +```bash +cargo install cargo-release +cargo release patch --execute # or minor / major / 1.2.3 +``` + +It bumps the workspace version + `Cargo.lock`, commits, creates +`vX.Y.Z`, and pushes. CI publishes on the tag push. +`[package.metadata.release] publish = false` in `engine/Cargo.toml` +keeps the local command from publishing — that is left to CI. + +### CI jobs on `v*` tag + +1. **`verify-version`** — fails if tag does not match the workspace + version. +2. **`package-crate`** — `cargo package -p wirefilter-engine --registry gen0sec --locked`, + uploads `wirefilter-engine-X.Y.Z.crate`. +3. **`publish`** — `release` environment-gated + `cargo publish -p wirefilter-engine` with retry/timeout hardening. +4. **`gh-release`** — downloads `.crate`, generates SHA256 sidecars, + creates a GitHub Release. + +### Required Cargo.toml metadata + +The gen0sec registry enforces these `[package]` fields on +`wirefilter-engine`: + +`name`, `description`, `repository`, `license`, `authors`, `categories`, +`keywords`, `links`, `readme`. diff --git a/engine/build.rs b/engine/build.rs new file mode 100644 index 00000000..c2bce4fe --- /dev/null +++ b/engine/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo:rerun-if-changed=build.rs"); +}