diff --git a/.github/workflows/rust-publish.yml b/.github/workflows/rust-publish.yml index cdab048..d28a801 100644 --- a/.github/workflows/rust-publish.yml +++ b/.github/workflows/rust-publish.yml @@ -8,6 +8,12 @@ name: Publish Rust client to crates.io # matching GitHub release. The release tag is derived from the single source of truth (the # `version` field in Cargo.toml, which is also what `CLIENT_VERSION` reads via CARGO_PKG_VERSION) # so the published crate version, the git tag, and the in-code client version can never disagree. +# +# Authentication to crates.io uses Trusted Publishing (OIDC) via `rust-lang/crates-io-auth-action`, +# the registry's recommended mechanism — no long-lived crates.io API token is stored as a secret. +# A Trusted Publisher must be configured for the crate on crates.io (this repository + this +# workflow file). The only repository secret still used is the built-in GITHUB_TOKEN, for pushing +# the tag and creating the GitHub release. on: workflow_dispatch: inputs: @@ -23,9 +29,12 @@ concurrency: cancel-in-progress: false # The default GITHUB_TOKEN needs write access to push the release tag and create the GitHub -# release. The crates.io registry token is provided separately as a repository secret. +# release. `id-token: write` lets the job mint a short-lived OpenID Connect token that +# `rust-lang/crates-io-auth-action` exchanges for an ephemeral crates.io publish token +# (Trusted Publishing) — so no long-lived crates.io registry secret is stored in the repo. permissions: contents: write + id-token: write jobs: publish: @@ -107,23 +116,11 @@ jobs: exit 1 fi - # Fail early with a clear message if the registry token is not configured, instead of - # letting `cargo publish` fail later with a less obvious authentication error. - - name: Require CARGO_REGISTRY_TOKEN secret - env: - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} - run: | - if [ -z "${CARGO_REGISTRY_TOKEN}" ]; then - echo "::error::CARGO_REGISTRY_TOKEN secret is empty or missing; cannot publish to crates.io." - exit 1 - fi - # Always verify packaging works (this also runs as part of `cargo publish`, but doing it # explicitly surfaces packaging problems before any registry interaction or tag creation). + # No registry credentials are needed for `--dry-run`: it only packages and verifies the + # crate locally without contacting the registry for authentication. - name: Verify package (dry run) - env: - # The crates.io registry token is stored as a repository secret. - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} run: cargo publish --dry-run --verbose # Ordering rationale (deliberate): the git tag and GitHub release are created and pushed @@ -200,10 +197,20 @@ jobs: --notes "${RELEASE_NOTES}" fi + # Trusted Publishing: exchange the GitHub Actions OIDC identity for a short-lived crates.io + # token instead of storing a long-lived registry secret. The action sets a `token` output + # and automatically revokes it in its post step when the job finishes. This requires a + # matching Trusted Publisher to be configured for the crate on crates.io (organization, + # repository and workflow file name). + - name: Authenticate to crates.io (Trusted Publishing) + id: auth + if: ${{ github.event.inputs.dry_run != 'true' }} + uses: rust-lang/crates-io-auth-action@v1 + - name: Publish to crates.io # Skip the actual publish when the run was dispatched as a dry run. if: ${{ github.event.inputs.dry_run != 'true' }} env: - # The crates.io registry token is stored as a repository secret. - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + # Short-lived token minted by Trusted Publishing (no stored registry secret). + CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} run: cargo publish --verbose diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d91f7d..468669f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,27 @@ All notable changes to the Rust Apify API client are documented here. The format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/). +## [0.4.1] - 2026-06-29 + +Compliance pass against the updated client requirements (no OpenAPI spec change; still +`v2-2026-06-25T142310Z`). No changes to the public API surface, so this is a patch release. + +### Changed +- Documentation now states the client is **"official, but experimental"** (previously worded as + "not (yet) an officially supported Apify product"), keeping the AI-generated and AI-maintained + disclaimer. Updated consistently in the crate-level rustdoc (`src/lib.rs`), `README.md`, + `docs/README.md`, and the crate `description` in `Cargo.toml`, per the documentation requirement + that the docs clearly state the clients are official, but experimental and AI-generated/maintained. +- The crates.io publish workflow (`.github/workflows/rust-publish.yml`) now authenticates with + **Trusted Publishing** (OIDC) via `rust-lang/crates-io-auth-action@v1` instead of a stored + `CARGO_REGISTRY_TOKEN` secret, per the publishing requirement to use a Trusted Publisher when the + language's distribution process supports it (crates.io does). The job gains `id-token: write` + permission to mint the OIDC token, which the action exchanges for a short-lived crates.io token + (auto-revoked at job end); the `cargo publish --dry-run` verification step needs no credentials. + A Trusted Publisher must be configured for the crate on crates.io (this repository + workflow + file). The only remaining repository secret used for publishing is the built-in `GITHUB_TOKEN` + (tag push and GitHub release creation). + ## [0.4.0] - 2026-06-26 Updated to Apify OpenAPI specification `v2-2026-06-25T142310Z` (previously diff --git a/Cargo.toml b/Cargo.toml index 5d6339e..2d56991 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "apify-client" -version = "0.4.0" +version = "0.4.1" authors = ["Apify Technologies "] -description = "An experimental, AI-generated and AI-maintained Rust client for the Apify API (https://apify.com)." +description = "An official, but experimental, AI-generated and AI-maintained Rust client for the Apify API (https://apify.com)." license = "Apache-2.0" edition = "2021" repository = "https://github.com/apify/apify-client-rust" diff --git a/README.md b/README.md index a4832ff..0ad7f2e 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Apify API client for Rust -> **Experimental — AI-generated and AI-maintained.** This client is experimental. It is -> generated and maintained by AI, and is not (yet) an officially supported Apify product. Review -> the code before relying on it in production and report issues on the repository. +> **Official, but experimental — AI-generated and AI-maintained.** This is an official Apify +> client, but it is experimental: it is generated and maintained by AI. Review the code before +> relying on it in production and report issues on the repository. An idiomatic Rust client for the [Apify API](https://docs.apify.com/api/v2). It provides a resource-oriented, async interface that mirrors the official @@ -129,14 +129,20 @@ GitHub release whose notes are the corresponding `CHANGELOG.md` section (falling one-liner if that section is missing), and finally runs `cargo publish`. The workflow **only runs from `master`** — it hard-fails on any other ref — and refuses to run if -the resolved tag already exists, so a release can never clobber a prior one. It also fails early -with a clear message if the `CARGO_REGISTRY_TOKEN` secret is missing. A `dry_run` input runs all -checks but performs no publish, tag, or release. +the resolved tag already exists, so a release can never clobber a prior one. A `dry_run` input runs +all checks but performs no publish, tag, or release. + +Authentication to crates.io uses **Trusted Publishing** (OIDC): the job has `id-token: write` +permission and `rust-lang/crates-io-auth-action@v1` exchanges the GitHub Actions identity for a +short-lived crates.io token at publish time (auto-revoked when the job ends). No long-lived +crates.io API token is stored as a repository secret; the only publishing secret used is the +built-in `GITHUB_TOKEN` (for the tag push and GitHub release). Prerequisites and steps to cut a release: -1. Configure the `CARGO_REGISTRY_TOKEN` repository secret with a crates.io API token (one-time - setup). The tag and GitHub release use the default `GITHUB_TOKEN`, so no other secret is needed. +1. Configure a **Trusted Publisher** for the `apify-client` crate on crates.io (one-time setup), + pointing at this repository and the `rust-publish.yml` workflow. No `CARGO_REGISTRY_TOKEN` secret + is needed; the tag and GitHub release use the default `GITHUB_TOKEN`. 2. Bump `version` in `Cargo.toml` and add a matching dated entry to `CHANGELOG.md` (the release notes are extracted from that section), then merge to `master`. 3. Trigger the workflow from `master`. diff --git a/docs/README.md b/docs/README.md index 733b761..2059beb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,8 +1,8 @@ # Apify Rust client — documentation -> **Experimental — AI-generated and AI-maintained.** This client is experimental. It is -> generated and maintained by AI, and is not (yet) an officially supported Apify product. Review -> the code before relying on it in production and report issues on the repository. +> **Official, but experimental — AI-generated and AI-maintained.** This is an official Apify +> client, but it is experimental: it is generated and maintained by AI. Review the code before +> relying on it in production and report issues on the repository. This directory documents the public API of the Apify Rust client. The same descriptions are available as rustdoc comments and can be browsed with `cargo doc --open`. diff --git a/src/lib.rs b/src/lib.rs index 60f972f..2161bcc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ //! # apify-client //! -//! **Experimental — AI-generated and AI-maintained.** This client is experimental. It is -//! generated and maintained by AI, and is not (yet) an officially supported Apify product. -//! Review the code before relying on it in production and report issues on the repository. +//! **Official, but experimental — AI-generated and AI-maintained.** This is an official Apify +//! client, but it is experimental: it is generated and maintained by AI. Review the code before +//! relying on it in production and report issues on the repository. //! //! An idiomatic Rust client for the [Apify API](https://docs.apify.com/api/v2). //!