diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..6c58f60 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,125 @@ +name: Release + +on: + push: + tags: + - "v*" + +permissions: + contents: read + +jobs: + test: + name: Test before release + runs-on: ubuntu-latest + steps: + - name: Step Security + uses: step-security/harden-runner@6c3c2f2c1c457b00c10c4848d6f5491db3b629df # v2.18.0 + with: + disable-sudo-and-containers: true + egress-policy: block + allowed-endpoints: > + api.github.com:443 + objects.githubusercontent.com:443 + release-assets.githubusercontent.com:443 + github.com:443 + index.crates.io:443 + static.crates.io:443 + static.rust-lang.org:443 + proxy.golang.org:443 + + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Install Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version: stable + + - name: Install Rust + uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 + with: + toolchain: stable + + - name: cargo build + run: cargo build --locked --verbose + env: + CARGO_TERM_COLOR: always + + - name: cargo test + run: cargo test --locked --verbose + env: + CARGO_TERM_COLOR: always + + - name: go test + run: | + go generate ./... + go test ./... + + - name: run snapshot tests + run: cargo test --locked --verbose --test cli + + publish: + name: Publish to crates.io + needs: test + runs-on: ubuntu-latest + environment: + name: release + permissions: + id-token: write + steps: + - name: Step Security + uses: step-security/harden-runner@6c3c2f2c1c457b00c10c4848d6f5491db3b629df # v2.18.0 + with: + disable-sudo-and-containers: true + egress-policy: block + allowed-endpoints: > + crates.io:443 + index.crates.io:443 + static.crates.io:443 + static.rust-lang.org:443 + github.com:443 + token.actions.githubusercontent.com:443 + + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Install Rust + uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 + with: + toolchain: stable + + - name: Authenticate with crates.io + id: auth + uses: rust-lang/crates-io-auth-action@bbd81622f20ce9e2dd9622e3218b975523e45bbe # v1.0.4 + + - name: Publish + run: cargo publish -p arcjet-gravity --locked + env: + CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} + CARGO_TERM_COLOR: always + + github-release: + name: Create GitHub Release + needs: publish + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Step Security + uses: step-security/harden-runner@6c3c2f2c1c457b00c10c4848d6f5491db3b629df # v2.18.0 + with: + disable-sudo-and-containers: true + egress-policy: block + allowed-endpoints: > + api.github.com:443 + github.com:443 + uploads.github.com:443 + + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Create GitHub Release + env: + GH_TOKEN: ${{ github.token }} + run: gh release create "${{ github.ref_name }}" --generate-notes diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..58e49fa --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,62 @@ +# Release + +Publishing to crates.io is automated via GitHub Actions but requires a manual +tag push to initiate. + +## Prerequisites + +The release workflow uses [crates.io Trusted Publishing][trusted-publishing] +to authenticate via OIDC, so no long-lived `CARGO_REGISTRY_TOKEN` is required. +The following one-time setup must be in place: + +1. The repository's `release` GitHub Environment exists (Settings → + Environments). Required reviewers can be configured here to gate the + publish step on a manual approval. +2. A Trusted Publisher entry exists on + [crates.io for `arcjet-gravity`](https://crates.io/crates/arcjet-gravity/settings) + with: + - Repository owner: `arcjet` + - Repository name: `gravity` + - Workflow filename: `release.yml` + - Environment: `release` + + This must be added by a crate owner. Members of the `arcjet/rust-team` + GitHub team inherit owner access via the team owner on the crate. + +[trusted-publishing]: https://crates.io/docs/trusted-publishing + +## Process + +1. Update the version in `cmd/gravity/Cargo.toml` and land the change on `main`. +2. Tag the release commit and push the tag: + ```sh + git tag v0.1.0 + git push origin v0.1.0 + ``` +3. The [Release workflow](.github/workflows/release.yml) runs automatically: + 1. **Test** — runs the full test suite (cargo test, go test, snapshot tests). + 2. **Publish** — authenticates to crates.io via Trusted Publishing and + publishes `arcjet-gravity`. If required reviewers are configured on the + `release` environment, this step waits for approval first. + 3. **GitHub Release** — creates a GitHub Release with auto-generated notes. +4. Verify the release on [crates.io](https://crates.io/crates/arcjet-gravity) + and on the repository's + [Releases page](https://github.com/arcjet/gravity/releases). + +## Versioning + +This project follows [Semantic Versioning](https://semver.org/). While the +project is in early development (`0.x`), minor version bumps may include +breaking changes. + +## Troubleshooting + +- **Publish fails with an authentication error**: confirm the Trusted Publisher + entry on crates.io matches the repository, workflow filename, and environment + name exactly. The `permissions: id-token: write` block must be present on + the `publish` job. +- **Publish fails with version conflict**: the version in `Cargo.toml` must be + greater than the latest published version on crates.io. You cannot re-publish + a version that has already been published. +- **Tests fail**: the release is aborted. Fix the issue on `main`, delete the + tag (`git push origin :refs/tags/v0.1.0`), and start again. diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..d638770 --- /dev/null +++ b/renovate.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [":dependencyDashboardApproval"], + "enabledManagers": ["cargo", "github-actions"], + "minimumReleaseAge": "7 days", + "schedule": [], + "updateNotScheduled": false, + "semanticCommitScope": "", + "semanticCommitType": "deps", + "packageRules": [ + { + "matchManagers": ["github-actions"], + "dependencyDashboardCategory": "GitHub Actions updates" + }, + { + "matchManagers": ["cargo"], + "dependencyDashboardCategory": "Rust updates" + }, + { + "matchDepTypes": ["devDependencies"], + "semanticCommitScope": "dev", + "semanticCommitType": "deps", + "automerge": true + }, + { + "matchUpdateTypes": ["patch"], + "automerge": true + }, + { + "matchUpdateTypes": ["lockFileMaintenance"], + "automerge": true + } + ], + "lockFileMaintenance": { + "enabled": true + }, + "prBodyTemplate": "{{{header}}}{{{table}}}{{{warnings}}}{{{notes}}}{{{changelogs}}}", + "prBodyColumns": ["Package", "Change"], + "ignorePresets": ["mergeConfidence:all-badges"], + "vulnerabilityAlerts": { + "groupName": null, + "dependencyDashboardApproval": true, + "rangeStrategy": "update-lockfile", + "commitMessageSuffix": "[security]", + "branchTopic": "{{{datasource}}}-{{{depNameSanitized}}}-vulnerability", + "prCreation": "immediate", + "vulnerabilityFixStrategy": "lowest" + } +}