From b920d7f421cc6ee8e6fd11edb75e900cf557d1b9 Mon Sep 17 00:00:00 2001 From: mlevkov Date: Sun, 5 Jul 2026 14:27:09 -0700 Subject: [PATCH 1/5] chore(release): prepare v0.2.0 - Cargo.toml/Cargo.lock version 0.1.0 -> 0.2.0 (pre-1.0 minor bump: this release carries two breaking changes - default port 3000 -> 8000 and MSRV 1.90 -> 1.93) - CHANGELOG: promote [Unreleased] to [0.2.0] - 2026-07-05 with fresh empty Unreleased section and updated compare links - README: health-response example version updated --- CHANGELOG.md | 7 ++++++- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d09bdcb..0570859 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +Nothing yet. + +## [0.2.0] - 2026-07-05 + ### Security - Refreshed `Cargo.lock` to patch 10 RUSTSEC advisories in transitive @@ -125,5 +129,6 @@ triggers (`docs/tech-debt/`): - Trusted proxy configuration for X-Forwarded-For validation - Input validation to prevent injection attacks -[Unreleased]: https://github.com/mlevkov/iggy_sample/compare/v0.1.0...HEAD +[Unreleased]: https://github.com/mlevkov/iggy_sample/compare/v0.2.0...HEAD +[0.2.0]: https://github.com/mlevkov/iggy_sample/compare/v0.1.0...v0.2.0 [0.1.0]: https://github.com/mlevkov/iggy_sample/releases/tag/v0.1.0 diff --git a/Cargo.lock b/Cargo.lock index 9edbd90..3a7b865 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2283,7 +2283,7 @@ dependencies = [ [[package]] name = "iggy_sample" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anyhow", "axum", diff --git a/Cargo.toml b/Cargo.toml index 8301531..1b7050b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "iggy_sample" -version = "0.1.0" +version = "0.2.0" edition = "2024" rust-version = "1.93.0" description = "A comprehensive demonstration of Apache Iggy message streaming with Axum" diff --git a/README.md b/README.md index 3347a24..b912863 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ Expected response: { "status": "healthy", "iggy_connected": true, - "version": "0.1.0", + "version": "0.2.0", "timestamp": "2024-01-15T10:30:00Z" } ``` From 684cf7d116c9325c961affa6011fa9aea8bd359c Mon Sep 17 00:00:00 2001 From: mlevkov Date: Sun, 5 Jul 2026 14:59:40 -0700 Subject: [PATCH 2/5] chore(release): enforce repo-level releases only (no crates.io) - Cargo.toml: publish = false - cargo itself now refuses any publish, so the guarantee lives in the manifest, not just CI; documentation URL points at the GitHub Pages docs the release pipeline actually deploys instead of a docs.rs page that will never exist - release.yml: crates.io publish job removed - CLAUDE.md release section and CHANGELOG updated to record the policy --- .github/workflows/release.yml | 18 ------------------ CHANGELOG.md | 3 +++ CLAUDE.md | 2 +- Cargo.toml | 5 ++++- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d97d6b4..a1eefbd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -191,24 +191,6 @@ jobs: files: artifacts/**/* generate_release_notes: true - # ========================================================================== - # Publish to crates.io (optional) - # ========================================================================== - publish: - name: Publish to crates.io - runs-on: ubuntu-latest - needs: [validate, release] - # Only publish stable releases - if: needs.validate.outputs.is_prerelease == 'false' - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - - - name: Publish to crates.io - run: cargo publish --token ${{ secrets.CRATES_IO_TOKEN }} - continue-on-error: true # Don't fail if already published - # ========================================================================== # Deploy documentation # ========================================================================== diff --git a/CHANGELOG.md b/CHANGELOG.md index 0570859..a463c45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,9 @@ Nothing yet. - CI now fails on `cargo deny check advisories licenses` (previously licenses-only and non-blocking); weekly stress tests pin `apache/iggy:0.8.0` instead of `latest` +- Crate marked `publish = false` and the crates.io publish job removed + from the release pipeline: releases are repo-level only (GitHub + Releases + GitHub Pages docs), by design - Updated `docker-compose.yaml` with full observability stack configuration - Simplified documentation section in README.md to reference `docs/` directory diff --git a/CLAUDE.md b/CLAUDE.md index 83193af..350e65e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -793,7 +793,7 @@ Triggered on version tags (`v*.*.*`): - Multi-platform builds (Linux x86/ARM, macOS x86/ARM, Windows) - GitHub Release with changelog - Documentation deployment to GitHub Pages -- Optional crates.io publishing +- No crates.io publishing: the crate is `publish = false` (repo-level releases only) ### Extended Tests (`extended-tests.yml`) Weekly scheduled runs: diff --git a/Cargo.toml b/Cargo.toml index 1b7050b..f04911e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,9 +5,12 @@ edition = "2024" rust-version = "1.93.0" description = "A comprehensive demonstration of Apache Iggy message streaming with Axum" license = "MIT" +# Repo-level releases only - never published to crates.io (enforced here, +# not just in CI: cargo refuses to publish with this set) +publish = false repository = "https://github.com/mlevkov/iggy_sample" homepage = "https://github.com/mlevkov/iggy_sample" -documentation = "https://docs.rs/iggy_sample" +documentation = "https://mlevkov.github.io/iggy_sample" authors = ["Maxim Levkov"] keywords = ["iggy", "message-streaming", "axum", "async", "event-driven"] categories = ["web-programming", "asynchronous", "network-programming"] From 2b58c238bb4d27aa01a767ed8ffd5d8e9eb94441 Mon Sep 17 00:00:00 2001 From: mlevkov Date: Sun, 5 Jul 2026 15:00:19 -0700 Subject: [PATCH 3/5] chore(release): keep the crates.io publish job; publish=false is the gate Per review: the pipeline job stays as-is for future flexibility. The manifest-level publish = false remains the enforcement - cargo refuses to publish (verified via --dry-run), and the job's continue-on-error makes the step a harmless no-op on tagged releases. --- .github/workflows/release.yml | 18 ++++++++++++++++++ CHANGELOG.md | 6 +++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a1eefbd..d97d6b4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -191,6 +191,24 @@ jobs: files: artifacts/**/* generate_release_notes: true + # ========================================================================== + # Publish to crates.io (optional) + # ========================================================================== + publish: + name: Publish to crates.io + runs-on: ubuntu-latest + needs: [validate, release] + # Only publish stable releases + if: needs.validate.outputs.is_prerelease == 'false' + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + + - name: Publish to crates.io + run: cargo publish --token ${{ secrets.CRATES_IO_TOKEN }} + continue-on-error: true # Don't fail if already published + # ========================================================================== # Deploy documentation # ========================================================================== diff --git a/CHANGELOG.md b/CHANGELOG.md index a463c45..1f62a96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,9 +48,9 @@ Nothing yet. - CI now fails on `cargo deny check advisories licenses` (previously licenses-only and non-blocking); weekly stress tests pin `apache/iggy:0.8.0` instead of `latest` -- Crate marked `publish = false` and the crates.io publish job removed - from the release pipeline: releases are repo-level only (GitHub - Releases + GitHub Pages docs), by design +- Crate marked `publish = false`: releases are repo-level only (GitHub + Releases + GitHub Pages docs) - cargo itself refuses to publish, so + the release pipeline's publish step is a harmless no-op - Updated `docker-compose.yaml` with full observability stack configuration - Simplified documentation section in README.md to reference `docs/` directory From 052202f9ed9ac4a32a2327ec8e908a3dde238198 Mon Sep 17 00:00:00 2001 From: mlevkov Date: Sun, 5 Jul 2026 15:01:20 -0700 Subject: [PATCH 4/5] docs(tech-debt): TD-2026-07-07 - pin third-party actions to SHAs Automated security review flagged the (pre-existing, repo-wide) mutable action tags when the publish job was restored. Recorded with a binding trigger rather than one-off pinning a single block: pinning is a repo-wide policy change belonging to a CI-focused pass. publish=false already neutralizes the CRATES_IO_TOKEN exposure path. --- docs/tech-debt/README.md | 1 + docs/tech-debt/TD-2026-07-07.md | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 docs/tech-debt/TD-2026-07-07.md diff --git a/docs/tech-debt/README.md b/docs/tech-debt/README.md index 751ea0e..b74b450 100644 --- a/docs/tech-debt/README.md +++ b/docs/tech-debt/README.md @@ -11,3 +11,4 @@ condition under which the record MUST be resolved (not "someday"). | [TD-2026-07-04](TD-2026-07-04.md) | X-Request-Timeout enforcement | Review session 01 (silentfail M4) | Before advertising the header in any client-facing docs beyond CLAUDE.md | | [TD-2026-07-05](TD-2026-07-05.md) | Metrics exporter smoke test | Review session 01 (tests #7) | Next metrics-exporter-prometheus major/minor bump | | [TD-2026-07-06](TD-2026-07-06.md) | Durable-storage guide config re-validation | Review session 01 (consistency #10) | Next server image bump past 0.8.x | +| [TD-2026-07-07](TD-2026-07-07.md) | Pin third-party GitHub Actions to commit SHAs | Security review on v0.2.0 release PR | Next CI-focused change, or any new repo secret | diff --git a/docs/tech-debt/TD-2026-07-07.md b/docs/tech-debt/TD-2026-07-07.md new file mode 100644 index 0000000..8db3804 --- /dev/null +++ b/docs/tech-debt/TD-2026-07-07.md @@ -0,0 +1,28 @@ +# TD-2026-07-07: Pin third-party GitHub Actions to commit SHAs + +**Source:** automated security review on the v0.2.0 release PR (MEDIUM). +**Status:** open + +## Problem + +All four workflows reference third-party actions by mutable tag +(`dtolnay/rust-toolchain@stable`, `Swatinem/rust-cache@v2`, +`taiki-e/install-action@...`, `codecov/codecov-action@v4`, etc.). A +compromised or force-moved tag executes attacker-controlled code in CI with +access to the workflow's permissions and any secrets passed to that job +(supply-chain risk of the tj-actions/changed-files class). + +## Mitigations in place + +- The crate is `publish = false`, so `CRATES_IO_TOKEN` (if ever configured) + cannot result in a publish — cargo refuses before the token is used. +- Workflow permissions are narrowly scoped per job where elevated. + +## Binding trigger + +At the next CI-focused change (or if any secret beyond `GITHUB_TOKEN` is +added to the repo), pin every third-party action across all workflows to a +full 40-char commit SHA with a version comment +(`uses: owner/action@ # vX`), and enable Dependabot's +`github-actions` ecosystem updates to keep the pins fresh (already +configured for version updates — verify it bumps SHA pins too). From 40db2c91e422aea4916801bd203228a3408bcd65 Mon Sep 17 00:00:00 2001 From: mlevkov Date: Sun, 5 Jul 2026 15:20:52 -0700 Subject: [PATCH 5/5] docs(readme): add dynamic GitHub release badge Self-updates from the latest semver tag, so the README never needs a manual version bump again; links to the releases page. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b912863..84ae578 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Iggy Sample Application [![CI](https://github.com/mlevkov/iggy_sample/actions/workflows/ci.yml/badge.svg)](https://github.com/mlevkov/iggy_sample/actions/workflows/ci.yml) +[![Release](https://img.shields.io/github/v/release/mlevkov/iggy_sample?sort=semver)](https://github.com/mlevkov/iggy_sample/releases/latest) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Rust](https://img.shields.io/badge/rust-1.93%2B-blue.svg)](https://www.rust-lang.org)