From 07bfefc8cee2efb7b12f3498debbf587ddb16fb2 Mon Sep 17 00:00:00 2001 From: Vittorio Distefano Date: Fri, 20 Mar 2026 22:31:29 +0100 Subject: [PATCH 1/2] Add automated package content verification --- .forgejo/workflows/ci.yml | 3 ++ .github/workflows/ci.yml | 3 ++ .github/workflows/publish-crates.yml | 3 ++ Makefile | 10 +++++- README.md | 6 ++++ scripts/verify-package.sh | 54 ++++++++++++++++++++++++++++ 6 files changed, 78 insertions(+), 1 deletion(-) create mode 100755 scripts/verify-package.sh diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index df51838..54f3952 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -34,3 +34,6 @@ jobs: - name: Run tests run: cargo test + + - name: Verify package contents + run: ./scripts/verify-package.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a0c5e9..26de168 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,3 +48,6 @@ jobs: - name: Run tests run: cargo test + + - name: Verify package contents + run: ./scripts/verify-package.sh diff --git a/.github/workflows/publish-crates.yml b/.github/workflows/publish-crates.yml index cc378b0..4a620ae 100644 --- a/.github/workflows/publish-crates.yml +++ b/.github/workflows/publish-crates.yml @@ -45,5 +45,8 @@ jobs: - name: Dry-run publish run: cargo publish --dry-run + - name: Verify package contents + run: ./scripts/verify-package.sh + - name: Publish solverforge-ui run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/Makefile b/Makefile index 921096a..cd9d69d 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ JS_SRC := $(sort $(wildcard js-src/*.js)) # ============== Phony Targets ============== .PHONY: banner help assets build build-release test test-quick test-doc test-unit test-one \ - lint fmt fmt-check clippy ci-local pre-release version \ + lint fmt fmt-check clippy ci-local pre-release version package-verify \ bump-patch bump-minor bump-major bump-dry \ publish-dry publish clean watch @@ -195,9 +195,16 @@ pre-release: banner @cargo test --quiet && printf "$(GREEN)$(CHECK) All tests passed$(RESET)\n" @printf "$(PROGRESS) Dry-run publish...\n" @cargo publish --dry-run 2>&1 | tail -1 + @printf "$(PROGRESS) Verifying packaged contents...\n" + @./scripts/verify-package.sh @printf "$(GREEN)$(CHECK) Package valid$(RESET)\n" @printf "\n$(GREEN)$(BOLD)$(CHECK) Ready for release v$(VERSION)$(RESET)\n\n" +package-verify: + @printf "$(PROGRESS) Verifying packaged crate contents...\n" + @./scripts/verify-package.sh + @printf "$(GREEN)$(CHECK) Package contents verified$(RESET)\n" + # ============== Publishing ============== publish-dry: test banner @@ -206,6 +213,7 @@ publish-dry: test banner @printf "$(CYAN)$(BOLD)╚══════════════════════════════════════════════════════════╝$(RESET)\n\n" @printf "$(GREEN)$(CHECK) All tests passed$(RESET)\n" @cargo publish --dry-run && \ + ./scripts/verify-package.sh && \ printf "$(GREEN)$(CHECK) Package valid$(RESET)\n" || \ (printf "$(RED)$(CROSS) Package validation failed$(RESET)\n" && exit 1) @printf "\n$(GRAY)Use 'make publish' to publish v$(VERSION) to crates.io$(RESET)\n\n" diff --git a/README.md b/README.md index 1ecb873..428cf9b 100644 --- a/README.md +++ b/README.md @@ -500,6 +500,12 @@ Consumer integration stays npm-free. Maintainer release automation does not. If you are cutting a release locally, make sure Node.js with `npx` is available before using the `bump-*` targets. After the bump completes, push the release commit and tag with `git push --follow-tags` or an equivalent tag-push command so the release automation actually starts. +## Package Verification + +Use `make package-verify` to inspect the exact crate contents that would be published. + +The verification step checks that required bundled assets and crate metadata are present, and that development-only sources such as `css-src/`, `js-src/`, `scripts/`, and screenshots are not shipped in the published crate. + ## Acknowledgments solverforge-ui builds on these excellent open-source projects: diff --git a/scripts/verify-package.sh b/scripts/verify-package.sh new file mode 100755 index 0000000..364a0ad --- /dev/null +++ b/scripts/verify-package.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +set -euo pipefail + +manifest="$(mktemp)" +trap 'rm -f "$manifest"' EXIT + +cargo package --allow-dirty --list > "$manifest" + +require() { + local path="$1" + if ! rg -Fxq "$path" "$manifest"; then + echo "missing packaged file: $path" >&2 + exit 1 + fi +} + +reject_prefix() { + local prefix="$1" + if rg -q "^${prefix}" "$manifest"; then + echo "unexpected packaged path matching prefix: $prefix" >&2 + exit 1 + fi +} + +reject_exact() { + local path="$1" + if rg -Fxq "$path" "$manifest"; then + echo "unexpected packaged file: $path" >&2 + exit 1 + fi +} + +require "Cargo.toml" +require "Cargo.lock" +require "README.md" +require "LICENSE" +require "CHANGELOG.md" +require "src/lib.rs" +require "static/sf/sf.css" +require "static/sf/sf.js" +require "static/sf/vendor/frappe-gantt/frappe-gantt.min.js" +require "static/sf/vendor/split/split.min.js" +require "static/sf/fonts/space-grotesk.woff2" +require "static/sf/fonts/jetbrains-mono.woff2" +require "static/sf/img/solverforge-logo.svg" + +reject_prefix "css-src/" +reject_prefix "js-src/" +reject_prefix "screenshots/" +reject_prefix "scripts/" +reject_exact "WIREFRAME.md" +reject_exact ".versionrc.json" + +echo "package contents verified" From 69a4486cafa32d0269997b9eefacc0116bde0e9e Mon Sep 17 00:00:00 2001 From: Vittorio Distefano Date: Sat, 21 Mar 2026 14:16:36 +0100 Subject: [PATCH 2/2] Make package verifier portable without rg --- scripts/verify-package.sh | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/scripts/verify-package.sh b/scripts/verify-package.sh index 364a0ad..9a6166e 100755 --- a/scripts/verify-package.sh +++ b/scripts/verify-package.sh @@ -6,9 +6,27 @@ trap 'rm -f "$manifest"' EXIT cargo package --allow-dirty --list > "$manifest" +if command -v rg >/dev/null 2>&1; then + search_exact() { + rg -Fxq "$1" "$manifest" + } + + search_prefix() { + rg -q "^$1" "$manifest" + } +else + search_exact() { + grep -Fxq "$1" "$manifest" + } + + search_prefix() { + grep -Eq "^$1" "$manifest" + } +fi + require() { local path="$1" - if ! rg -Fxq "$path" "$manifest"; then + if ! search_exact "$path"; then echo "missing packaged file: $path" >&2 exit 1 fi @@ -16,7 +34,7 @@ require() { reject_prefix() { local prefix="$1" - if rg -q "^${prefix}" "$manifest"; then + if search_prefix "$prefix"; then echo "unexpected packaged path matching prefix: $prefix" >&2 exit 1 fi @@ -24,7 +42,7 @@ reject_prefix() { reject_exact() { local path="$1" - if rg -Fxq "$path" "$manifest"; then + if search_exact "$path"; then echo "unexpected packaged file: $path" >&2 exit 1 fi