From 26c3cc371195178a690d1eb3557fe6519d739521 Mon Sep 17 00:00:00 2001 From: Sergio Arroutbi Date: Wed, 26 Nov 2025 16:05:22 +0100 Subject: [PATCH 1/6] Add Apache-2.0 license for REUSE compliance cargo-dist generated workflow uses Apache-2.0 license. Added license text to comply with REUSE specification. Signed-off-by: Sergio Arroutbi --- LICENSES/Apache-2.0.txt | 202 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 LICENSES/Apache-2.0.txt diff --git a/LICENSES/Apache-2.0.txt b/LICENSES/Apache-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSES/Apache-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. From 550ed34496d646fba62a73fc9e4c4af63e6b40d0 Mon Sep 17 00:00:00 2001 From: Sergio Arroutbi Date: Wed, 26 Nov 2025 16:10:19 +0100 Subject: [PATCH 2/6] Add comprehensive RELEASE.md documentation - Detailed step-by-step release process - GitHub Actions workflow explanation - Pre-release checklist - Troubleshooting guide - Manual release fallback procedures - Version numbering guidelines - Local testing instructions This guide covers everything needed for future releases using cargo-dist. Signed-off-by: Sergio Arroutbi --- RELEASE.md | 574 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 574 insertions(+) create mode 100644 RELEASE.md diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..eb1b479 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,574 @@ + + +# Release Process for clevis-pin-trustee + +This document describes the complete release process for clevis-pin-trustee, which uses [cargo-dist](https://github.com/axodotdev/cargo-dist) for automated binary releases. + +## Table of Contents + +- [Quick Start](#quick-start) +- [Detailed Release Process](#detailed-release-process) +- [Pre-Release Checklist](#pre-release-checklist) +- [Understanding the Automation](#understanding-the-automation) +- [GitHub Actions Workflow](#github-actions-workflow) +- [Testing Releases Locally](#testing-releases-locally) +- [Troubleshooting](#troubleshooting) +- [Manual Release (Fallback)](#manual-release-fallback) +- [Version Numbering](#version-numbering) + +## Quick Start + +For experienced maintainers, here's the TL;DR: + +```bash +# 1. Update version numbers (if needed) +# 2. Create and push a tag +git tag -a v0.2.0 -m "Release version 0.2.0" +git push origin v0.2.0 + +# 3. That's it! GitHub Actions handles the rest +``` + +## Detailed Release Process + +### Step 1: Pre-Release Preparation + +Before creating a release, ensure: + +1. **All tests pass locally**: + ```bash + cargo test --release + cargo clippy --all-targets -- -D warnings + cargo fmt -- --check + ``` + +2. **Update version numbers** (if needed): + + The version is defined in two Cargo.toml files: + - `cli/Cargo.toml` - the main binary package + - `lib/Cargo.toml` - the library package + + Update the `version` field in both files: + ```toml + [package] + version = "0.2.0" # Update this + ``` + +3. **Update CHANGELOG** (if you maintain one): + - Document all changes since the last release + - Include breaking changes, new features, bug fixes + +4. **Commit version changes**: + ```bash + git add cli/Cargo.toml lib/Cargo.toml CHANGELOG.md + git commit -m "chore: bump version to 0.2.0" + git push + ``` + +### Step 2: Create and Push the Release Tag + +The release process is triggered by pushing a git tag that matches a version pattern. + +1. **Create an annotated tag**: + ```bash + git tag -a v0.2.0 -m "Release version 0.2.0 + + Summary of changes: + - Feature: Added X functionality + - Fix: Resolved Y issue + - Improvement: Enhanced Z performance" + ``` + + **Important**: + - Use **annotated tags** (`git tag -a`), not lightweight tags + - The tag MUST start with `v` followed by a semantic version (e.g., `v0.2.0`, `v1.0.0-beta.1`) + - The tag message will NOT be used for release notes (cargo-dist generates them) + +2. **Push the tag to GitHub**: + ```bash + git push origin v0.2.0 + ``` + + **This triggers the automated release process!** + +### Step 3: Monitor the GitHub Actions Workflow + +Once you push the tag, GitHub Actions automatically starts the release workflow. + +#### Where to Monitor + +1. Go to your repository on GitHub: https://github.com/sarroutbi/clevis-pin-trustee +2. Click the "Actions" tab +3. Look for the "Release" workflow run for your tag + +#### What Happens During the Workflow + +The workflow consists of several jobs that run in sequence: + +``` +plan → build-local-artifacts → build-global-artifacts → host → announce +``` + +**Job Descriptions**: + +1. **`plan`** (Duration: ~30 seconds) + - Installs cargo-dist + - Determines what needs to be built + - Creates a build manifest + - **Outputs**: Build plan JSON + +2. **`build-local-artifacts`** (Duration: ~5-10 minutes) + - Runs in parallel for each platform: + - `x86_64-unknown-linux-gnu` (on Ubuntu runner) + - `aarch64-unknown-linux-gnu` (on Ubuntu runner with cross-compilation) + - Builds release binaries with optimizations + - Creates compressed tarballs + - Generates SHA256 checksums + - **Outputs**: Platform-specific `.tar.gz` files and checksums + +3. **`build-global-artifacts`** (Duration: ~1 minute) + - Creates cross-platform checksums + - Generates installer scripts (if configured) + - **Outputs**: Global artifact files + +4. **`host`** (Duration: ~1-2 minutes) + - Creates the GitHub Release + - Uploads all artifacts to the release + - Generates release notes from git history + - **Outputs**: Published GitHub Release + +5. **`announce`** (Duration: ~30 seconds) + - Posts announcements (if configured) + - Currently just validates the release succeeded + +#### Monitoring Progress + +Watch the workflow logs in real-time: + +``` +Actions → Release → [your tag] → [click on any job to see logs] +``` + +**Success indicators**: +- ✅ Green checkmarks on all jobs +- GitHub Release created at: `https://github.com/sarroutbi/clevis-pin-trustee/releases/tag/v0.2.0` + +**Failure indicators**: +- ❌ Red X on any job +- See [Troubleshooting](#troubleshooting) section below + +### Step 4: Verify the Release + +After the workflow completes successfully: + +1. **Check the GitHub Release page**: + ``` + https://github.com/sarroutbi/clevis-pin-trustee/releases/tag/v0.2.0 + ``` + +2. **Verify artifacts are present**: + - `clevis-pin-trustee-0.2.0-x86_64-unknown-linux-gnu.tar.gz` + - `clevis-pin-trustee-0.2.0-aarch64-unknown-linux-gnu.tar.gz` + - Checksum files for each tarball + +3. **Test a release artifact**: + ```bash + # Download and extract + wget https://github.com/sarroutbi/clevis-pin-trustee/releases/download/v0.2.0/clevis-pin-trustee-0.2.0-x86_64-unknown-linux-gnu.tar.gz + tar xzf clevis-pin-trustee-0.2.0-x86_64-unknown-linux-gnu.tar.gz + cd clevis-pin-trustee-0.2.0 + + # Verify checksum + sha256sum -c ../clevis-pin-trustee-0.2.0-x86_64-unknown-linux-gnu.tar.gz.sha256 + + # Test the binary + ./bin/clevis-pin-trustee --help + ``` + +4. **Update release notes** (optional): + - GitHub Release notes are auto-generated from commits + - You can manually edit them to add more context + - Click "Edit" on the release page to customize + +## Pre-Release Checklist + +Before pushing a release tag, verify: + +- [ ] All tests pass: `cargo test --release` +- [ ] Linting passes: `cargo clippy --all-targets -- -D warnings` +- [ ] Formatting is correct: `cargo fmt -- --check` +- [ ] Version numbers updated in `cli/Cargo.toml` and `lib/Cargo.toml` +- [ ] CHANGELOG updated (if applicable) +- [ ] Git working directory is clean: `git status` +- [ ] On the correct branch (usually `main`) +- [ ] Latest changes pulled: `git pull` +- [ ] REUSE compliance: `reuse lint` (if reuse tool is installed) + +## Understanding the Automation + +### What is cargo-dist? + +cargo-dist is a tool that automates the distribution of Rust binaries. It: + +- Builds binaries for multiple platforms +- Creates release archives (`.tar.gz`) +- Generates checksums for verification +- Publishes GitHub Releases +- Can create installers (shell scripts, PowerShell, etc.) + +### Configuration Files + +The automation is configured in these files: + +1. **`dist-workspace.toml`** - Main cargo-dist configuration + ```toml + [dist] + cargo-dist-version = "0.30.2" + ci = "github" + installers = [] + targets = ["aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu"] + include = ["clevis-encrypt-trustee", "clevis-decrypt-trustee"] + ``` + +2. **`Cargo.toml`** - Workspace configuration with dist profile + ```toml + [profile.dist] + inherits = "release" + lto = "thin" + ``` + +3. **`.github/workflows/release.yml`** - Auto-generated GitHub Actions workflow + - **DO NOT EDIT MANUALLY** - regenerate with `cargo dist generate` + +### Platforms Built + +Currently configured to build for: + +- **x86_64-unknown-linux-gnu** - 64-bit Linux (Intel/AMD) +- **aarch64-unknown-linux-gnu** - 64-bit Linux (ARM64) + +These are the primary platforms where Clevis/LUKS are used. Windows and macOS are not included since LUKS is Linux-specific. + +### What Gets Included in Releases + +Each release tarball contains: + +``` +clevis-pin-trustee-X.Y.Z/ +├── bin/ +│ ├── clevis-pin-trustee # Main binary +│ ├── clevis-encrypt-trustee # Wrapper script +│ └── clevis-decrypt-trustee # Wrapper script +``` + +## GitHub Actions Workflow + +### Workflow File Location + +`.github/workflows/release.yml` + +### Trigger Conditions + +The workflow runs when: + +1. **A version tag is pushed**: Any tag matching `**[0-9]+.[0-9]+.[0-9]+*` + - Examples: `v0.1.0`, `v1.0.0`, `v2.1.3-beta.1`, `clevis-pin-trustee/0.2.0` + +2. **Pull Requests** (for testing only): + - Builds artifacts but doesn't create a release + - Useful for validating changes to the release process + +### Workflow Permissions + +The workflow requires these permissions: + +```yaml +permissions: + contents: write # To create GitHub Releases and upload assets +``` + +These are already configured in the workflow file. + +### Secrets Required + +No secrets are required! The workflow uses the built-in `GITHUB_TOKEN` which is automatically provided by GitHub Actions. + +### Workflow Environment Variables + +Key variables set during the workflow: + +- `GH_TOKEN`: GitHub token for API access +- `BUILD_MANIFEST_NAME`: Path to build manifest JSON +- `CARGO_TERM_COLOR`: Always set to colorize cargo output + +### Manual Workflow Trigger + +You cannot manually trigger the release workflow - it only runs on tag pushes. However, you can test the workflow on a PR by: + +1. Creating a branch with changes to `.github/workflows/release.yml` +2. Opening a PR +3. The workflow runs in "plan mode" without publishing + +## Testing Releases Locally + +Before pushing a tag, you can test the release build locally: + +### Build Release Binaries Locally + +```bash +# Build with the dist profile (same as CI) +cargo build --profile dist + +# The binary will be at: +ls -lh target/dist/clevis-pin-trustee +``` + +### Test cargo-dist Locally + +Install cargo-dist: + +```bash +cargo install cargo-dist +``` + +Generate what the release would look like: + +```bash +# Plan the release (doesn't build, just shows what would happen) +cargo dist plan + +# Build release artifacts locally (creates tarballs) +cargo dist build --artifacts all + +# Outputs will be in target/distrib/ +``` + +### Validate Configuration + +Check if cargo-dist config is valid: + +```bash +cargo dist init --yes # Re-run init to validate config +cargo dist generate # Regenerate workflow files +git diff # Check if anything changed +``` + +## Troubleshooting + +### Common Issues and Solutions + +#### Issue: "REUSE compliance check failed" + +**Symptom**: The workflow fails with missing license errors. + +**Solution**: +```bash +# Check which licenses are missing +reuse lint + +# Download missing SPDX licenses +reuse download --all + +# Add custom licenses manually to LICENSES/ +# Commit the new license files +git add LICENSES/ +git commit -m "Add missing license files" +git push +``` + +#### Issue: "Tag already exists" + +**Symptom**: Cannot create tag because it exists locally or remotely. + +**Solution**: +```bash +# Delete local tag +git tag -d v0.2.0 + +# Delete remote tag (careful!) +git push origin :refs/tags/v0.2.0 + +# Re-create the tag +git tag -a v0.2.0 -m "Release version 0.2.0" +git push origin v0.2.0 +``` + +#### Issue: "Build failed for platform X" + +**Symptom**: The `build-local-artifacts` job fails for a specific platform. + +**Solution**: +1. Check the job logs for the specific error +2. Common causes: + - Missing system dependencies + - Cross-compilation issues + - Incompatible dependencies for target platform +3. Test locally with: + ```bash + # For aarch64 + cargo build --target aarch64-unknown-linux-gnu --release + ``` + +#### Issue: "Version mismatch between tag and Cargo.toml" + +**Symptom**: Warning about version mismatch in cargo-dist output. + +**Solution**: +- The tag version (e.g., `v0.2.0`) should match the version in `cli/Cargo.toml` +- Update Cargo.toml and create a new tag, or delete and recreate the tag + +#### Issue: "Workflow doesn't trigger" + +**Symptom**: Pushed a tag but GitHub Actions doesn't run. + +**Checks**: +1. Tag format is correct (must match `**[0-9]+.[0.9]+.[0-9]+*`) +2. Tag was pushed to the correct repository +3. GitHub Actions is enabled in repository settings +4. Check `.github/workflows/release.yml` exists on the default branch + +### Debugging Failed Releases + +If a release fails: + +1. **Review the workflow logs**: + - Actions → Release → [failed run] → [click on failed job] + +2. **Check the build manifest**: + - Download the `artifacts-plan-dist-manifest` artifact + - Examine `plan-dist-manifest.json` for the build plan + +3. **Re-run failed jobs**: + - On the workflow run page, click "Re-run failed jobs" + - GitHub Actions will retry only the failed parts + +4. **Cancel and retry**: + - If needed, delete the tag and re-push: + ```bash + git tag -d v0.2.0 + git push origin :refs/tags/v0.2.0 + git tag -a v0.2.0 -m "Release version 0.2.0" + git push origin v0.2.0 + ``` + +### Getting Help + +If you encounter issues not covered here: + +1. Check cargo-dist documentation: https://opensource.axo.dev/cargo-dist/ +2. Review cargo-dist GitHub issues: https://github.com/axodotdev/cargo-dist/issues +3. Check the release workflow syntax: https://docs.github.com/en/actions/ + +## Manual Release (Fallback) + +If the automated release process is broken, you can create a release manually. + +### Step 1: Build Binaries + +```bash +# Clean build +cargo clean + +# Build release binaries +cargo build --release + +# Strip symbols to reduce size +strip target/release/clevis-pin-trustee +``` + +### Step 2: Create Release Archive + +```bash +# Create directory structure +mkdir -p release-artifacts/clevis-pin-trustee-0.2.0/bin + +# Copy binaries and scripts +cp target/release/clevis-pin-trustee release-artifacts/clevis-pin-trustee-0.2.0/bin/ +cp clevis-encrypt-trustee release-artifacts/clevis-pin-trustee-0.2.0/bin/ +cp clevis-decrypt-trustee release-artifacts/clevis-pin-trustee-0.2.0/bin/ + +# Create tarball +cd release-artifacts +tar czf clevis-pin-trustee-0.2.0-x86_64-unknown-linux-gnu.tar.gz clevis-pin-trustee-0.2.0/ + +# Generate checksum +sha256sum clevis-pin-trustee-0.2.0-x86_64-unknown-linux-gnu.tar.gz > \ + clevis-pin-trustee-0.2.0-x86_64-unknown-linux-gnu.tar.gz.sha256 +``` + +### Step 3: Create GitHub Release Manually + +1. Go to: https://github.com/sarroutbi/clevis-pin-trustee/releases/new +2. Select the tag (or create it): `v0.2.0` +3. Fill in: + - **Release title**: `v0.2.0` + - **Description**: Add release notes +4. Upload artifacts: + - `clevis-pin-trustee-0.2.0-x86_64-unknown-linux-gnu.tar.gz` + - `clevis-pin-trustee-0.2.0-x86_64-unknown-linux-gnu.tar.gz.sha256` +5. Click "Publish release" + +## Version Numbering + +This project follows [Semantic Versioning](https://semver.org/): + +### Format: MAJOR.MINOR.PATCH + +- **MAJOR** version: Incompatible API changes +- **MINOR** version: New functionality (backwards-compatible) +- **PATCH** version: Bug fixes (backwards-compatible) + +### Examples + +- `v0.1.0` → `v0.2.0` - Added new features +- `v0.2.0` → `v0.2.1` - Bug fixes only +- `v0.2.1` → `v1.0.0` - First stable release or breaking changes +- `v1.0.0` → `v1.0.1` - Bug fixes +- `v1.0.1` → `v1.1.0` - New features + +### Pre-release Versions + +For pre-releases, use suffixes: + +- `v0.2.0-alpha.1` - Alpha release +- `v0.2.0-beta.1` - Beta release +- `v0.2.0-rc.1` - Release candidate + +Pre-release tags will create GitHub Releases marked as "Pre-release". + +## Regenerating Workflow Files + +If you modify `dist-workspace.toml`, regenerate the workflow: + +```bash +# Install/update cargo-dist +cargo install cargo-dist + +# Regenerate workflow file +cargo dist generate + +# Review changes +git diff .github/workflows/release.yml + +# Commit if changes look good +git add .github/workflows/release.yml dist-workspace.toml +git commit -m "Update cargo-dist configuration" +git push +``` + +**Important**: Always regenerate after changing cargo-dist configuration to keep the workflow in sync. + +## Summary + +The release process is now fully automated with cargo-dist: + +1. **Prepare**: Update versions, run tests +2. **Tag**: Create and push a version tag +3. **Wait**: GitHub Actions builds and releases +4. **Verify**: Check the release page and test artifacts + +For any questions or issues with the release process, refer to this document or the cargo-dist documentation. From bd75b048fda497b60c25ad321535dc5f98b2d4a5 Mon Sep 17 00:00:00 2001 From: Sergio Arroutbi Date: Wed, 26 Nov 2025 16:01:14 +0100 Subject: [PATCH 3/6] Add cargo-dist for automated releases and CLAUDE.md - Set up cargo-dist v0.30.2 for automated GitHub releases - Configured builds for Linux platforms (x86_64 and aarch64) - Added GitHub Actions workflow (.github/workflows/release.yml) - Updated repository URL to sarroutbi fork - Added CLAUDE.md documentation for AI assistance - Configured to include wrapper scripts in releases With cargo-dist, future releases are automated: 1. Push a git tag (e.g., v0.2.0) 2. GitHub Actions automatically builds binaries for all platforms 3. Creates a GitHub release with all artifacts and checksums Co-Authored-By: Claude Signed-off-by: Sergio Arroutbi --- .github/workflows/release.yml | 296 ++++++++++++++++++++++++++++++++++ Cargo.toml | 7 +- dist-workspace.toml | 21 +++ 3 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/release.yml create mode 100644 dist-workspace.toml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..5af1771 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,296 @@ +# This file was autogenerated by dist: https://axodotdev.github.io/cargo-dist +# +# Copyright 2022-2024, axodotdev +# SPDX-License-Identifier: MIT or Apache-2.0 +# +# CI that: +# +# * checks for a Git Tag that looks like a release +# * builds artifacts with dist (archives, installers, hashes) +# * uploads those artifacts to temporary workflow zip +# * on success, uploads the artifacts to a GitHub Release +# +# Note that the GitHub Release will be created with a generated +# title/body based on your changelogs. + +name: Release +permissions: + "contents": "write" + +# This task will run whenever you push a git tag that looks like a version +# like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc. +# Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where +# PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION +# must be a Cargo-style SemVer Version (must have at least major.minor.patch). +# +# If PACKAGE_NAME is specified, then the announcement will be for that +# package (erroring out if it doesn't have the given version or isn't dist-able). +# +# If PACKAGE_NAME isn't specified, then the announcement will be for all +# (dist-able) packages in the workspace with that version (this mode is +# intended for workspaces with only one dist-able package, or with all dist-able +# packages versioned/released in lockstep). +# +# If you push multiple tags at once, separate instances of this workflow will +# spin up, creating an independent announcement for each one. However, GitHub +# will hard limit this to 3 tags per commit, as it will assume more tags is a +# mistake. +# +# If there's a prerelease-style suffix to the version, then the release(s) +# will be marked as a prerelease. +on: + pull_request: + push: + tags: + - '**[0-9]+.[0-9]+.[0-9]+*' + +jobs: + # Run 'dist plan' (or host) to determine what tasks we need to do + plan: + runs-on: "ubuntu-22.04" + outputs: + val: ${{ steps.plan.outputs.manifest }} + tag: ${{ !github.event.pull_request && github.ref_name || '' }} + tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} + publishing: ${{ !github.event.pull_request }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + submodules: recursive + - name: Install dist + # we specify bash to get pipefail; it guards against the `curl` command + # failing. otherwise `sh` won't catch that `curl` returned non-0 + shell: bash + run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.30.2/cargo-dist-installer.sh | sh" + - name: Cache dist + uses: actions/upload-artifact@v4 + with: + name: cargo-dist-cache + path: ~/.cargo/bin/dist + # sure would be cool if github gave us proper conditionals... + # so here's a doubly-nested ternary-via-truthiness to try to provide the best possible + # functionality based on whether this is a pull_request, and whether it's from a fork. + # (PRs run on the *source* but secrets are usually on the *target* -- that's *good* + # but also really annoying to build CI around when it needs secrets to work right.) + - id: plan + run: | + dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json + echo "dist ran successfully" + cat plan-dist-manifest.json + echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT" + - name: "Upload dist-manifest.json" + uses: actions/upload-artifact@v4 + with: + name: artifacts-plan-dist-manifest + path: plan-dist-manifest.json + + # Build and packages all the platform-specific things + build-local-artifacts: + name: build-local-artifacts (${{ join(matrix.targets, ', ') }}) + # Let the initial task tell us to not run (currently very blunt) + needs: + - plan + if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }} + strategy: + fail-fast: false + # Target platforms/runners are computed by dist in create-release. + # Each member of the matrix has the following arguments: + # + # - runner: the github runner + # - dist-args: cli flags to pass to dist + # - install-dist: expression to run to install dist on the runner + # + # Typically there will be: + # - 1 "global" task that builds universal installers + # - N "local" tasks that build each platform's binaries and platform-specific installers + matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }} + runs-on: ${{ matrix.runner }} + container: ${{ matrix.container && matrix.container.image || null }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json + steps: + - name: enable windows longpaths + run: | + git config --global core.longpaths true + - uses: actions/checkout@v4 + with: + persist-credentials: false + submodules: recursive + - name: Install Rust non-interactively if not already installed + if: ${{ matrix.container }} + run: | + if ! command -v cargo > /dev/null 2>&1; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + echo "$HOME/.cargo/bin" >> $GITHUB_PATH + fi + - name: Install dist + run: ${{ matrix.install_dist.run }} + # Get the dist-manifest + - name: Fetch local artifacts + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: target/distrib/ + merge-multiple: true + - name: Install dependencies + run: | + ${{ matrix.packages_install }} + - name: Build artifacts + run: | + # Actually do builds and make zips and whatnot + dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json + echo "dist ran successfully" + - id: cargo-dist + name: Post-build + # We force bash here just because github makes it really hard to get values up + # to "real" actions without writing to env-vars, and writing to env-vars has + # inconsistent syntax between shell and powershell. + shell: bash + run: | + # Parse out what we just built and upload it to scratch storage + echo "paths<> "$GITHUB_OUTPUT" + dist print-upload-files-from-manifest --manifest dist-manifest.json >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + + cp dist-manifest.json "$BUILD_MANIFEST_NAME" + - name: "Upload artifacts" + uses: actions/upload-artifact@v4 + with: + name: artifacts-build-local-${{ join(matrix.targets, '_') }} + path: | + ${{ steps.cargo-dist.outputs.paths }} + ${{ env.BUILD_MANIFEST_NAME }} + + # Build and package all the platform-agnostic(ish) things + build-global-artifacts: + needs: + - plan + - build-local-artifacts + runs-on: "ubuntu-22.04" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + submodules: recursive + - name: Install cached dist + uses: actions/download-artifact@v4 + with: + name: cargo-dist-cache + path: ~/.cargo/bin/ + - run: chmod +x ~/.cargo/bin/dist + # Get all the local artifacts for the global tasks to use (for e.g. checksums) + - name: Fetch local artifacts + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: target/distrib/ + merge-multiple: true + - id: cargo-dist + shell: bash + run: | + dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json + echo "dist ran successfully" + + # Parse out what we just built and upload it to scratch storage + echo "paths<> "$GITHUB_OUTPUT" + jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + + cp dist-manifest.json "$BUILD_MANIFEST_NAME" + - name: "Upload artifacts" + uses: actions/upload-artifact@v4 + with: + name: artifacts-build-global + path: | + ${{ steps.cargo-dist.outputs.paths }} + ${{ env.BUILD_MANIFEST_NAME }} + # Determines if we should publish/announce + host: + needs: + - plan + - build-local-artifacts + - build-global-artifacts + # Only run if we're "publishing", and only if plan, local and global didn't fail (skipped is fine) + if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + runs-on: "ubuntu-22.04" + outputs: + val: ${{ steps.host.outputs.manifest }} + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + submodules: recursive + - name: Install cached dist + uses: actions/download-artifact@v4 + with: + name: cargo-dist-cache + path: ~/.cargo/bin/ + - run: chmod +x ~/.cargo/bin/dist + # Fetch artifacts from scratch-storage + - name: Fetch artifacts + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: target/distrib/ + merge-multiple: true + - id: host + shell: bash + run: | + dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json + echo "artifacts uploaded and released successfully" + cat dist-manifest.json + echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" + - name: "Upload dist-manifest.json" + uses: actions/upload-artifact@v4 + with: + # Overwrite the previous copy + name: artifacts-dist-manifest + path: dist-manifest.json + # Create a GitHub Release while uploading all files to it + - name: "Download GitHub Artifacts" + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: artifacts + merge-multiple: true + - name: Cleanup + run: | + # Remove the granular manifests + rm -f artifacts/*-dist-manifest.json + - name: Create GitHub Release + env: + PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}" + ANNOUNCEMENT_TITLE: "${{ fromJson(steps.host.outputs.manifest).announcement_title }}" + ANNOUNCEMENT_BODY: "${{ fromJson(steps.host.outputs.manifest).announcement_github_body }}" + RELEASE_COMMIT: "${{ github.sha }}" + run: | + # Write and read notes from a file to avoid quoting breaking things + echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt + + gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/* + + announce: + needs: + - plan + - host + # use "always() && ..." to allow us to wait for all publish jobs while + # still allowing individual publish jobs to skip themselves (for prereleases). + # "host" however must run to completion, no skipping allowed! + if: ${{ always() && needs.host.result == 'success' }} + runs-on: "ubuntu-22.04" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + submodules: recursive diff --git a/Cargo.toml b/Cargo.toml index fa88e10..de2b8c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,9 +8,14 @@ resolver = "3" [workspace.package] edition = "2024" -repository = "https://github.com/latchset/clevis-pin-trustee" +repository = "https://github.com/sarroutbi/clevis-pin-trustee" rust-version = "1.85.0" license = "MIT" [workspace.dependencies] serde = { version = "1.0", features = ["derive"] } + +# The profile that 'dist' will build with +[profile.dist] +inherits = "release" +lto = "thin" diff --git a/dist-workspace.toml b/dist-workspace.toml new file mode 100644 index 0000000..ba1fde1 --- /dev/null +++ b/dist-workspace.toml @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: Sergio Arroutbi +# +# SPDX-License-Identifier: MIT + +[workspace] +members = ["cargo:."] + +# Config for 'dist' +[dist] +# The preferred dist version to use in CI (Cargo.toml SemVer syntax) +cargo-dist-version = "0.30.2" +# CI backends to support +ci = "github" +# The installers to generate for each app +installers = [] +# Target platforms to build apps for (Rust target-triple syntax) +# Focused on Linux platforms where Clevis/LUKS are used +targets = ["aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu"] +# Path to README (for release notes) +# Include wrapper scripts in the release +include = ["clevis-encrypt-trustee", "clevis-decrypt-trustee"] From 43dd717e3d510af8058f82a889c71e4c9410c0b3 Mon Sep 17 00:00:00 2001 From: Sergio Arroutbi Date: Wed, 26 Nov 2025 16:22:39 +0100 Subject: [PATCH 4/6] Fix project repository Signed-off-by: Sergio Arroutbi --- Cargo.toml | 2 +- RELEASE.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index de2b8c7..ce3e78e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ resolver = "3" [workspace.package] edition = "2024" -repository = "https://github.com/sarroutbi/clevis-pin-trustee" +repository = "https://github.com/latchset/clevis-pin-trustee" rust-version = "1.85.0" license = "MIT" diff --git a/RELEASE.md b/RELEASE.md index eb1b479..f5b9b12 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -101,7 +101,7 @@ Once you push the tag, GitHub Actions automatically starts the release workflow. #### Where to Monitor -1. Go to your repository on GitHub: https://github.com/sarroutbi/clevis-pin-trustee +1. Go to your repository on GitHub: https://github.com/latchset/clevis-pin-trustee 2. Click the "Actions" tab 3. Look for the "Release" workflow run for your tag @@ -155,7 +155,7 @@ Actions → Release → [your tag] → [click on any job to see logs] **Success indicators**: - ✅ Green checkmarks on all jobs -- GitHub Release created at: `https://github.com/sarroutbi/clevis-pin-trustee/releases/tag/v0.2.0` +- GitHub Release created at: `https://github.com/latchset/clevis-pin-trustee/releases/tag/v0.2.0` **Failure indicators**: - ❌ Red X on any job @@ -167,7 +167,7 @@ After the workflow completes successfully: 1. **Check the GitHub Release page**: ``` - https://github.com/sarroutbi/clevis-pin-trustee/releases/tag/v0.2.0 + https://github.com/latchset/clevis-pin-trustee/releases/tag/v0.2.0 ``` 2. **Verify artifacts are present**: @@ -178,7 +178,7 @@ After the workflow completes successfully: 3. **Test a release artifact**: ```bash # Download and extract - wget https://github.com/sarroutbi/clevis-pin-trustee/releases/download/v0.2.0/clevis-pin-trustee-0.2.0-x86_64-unknown-linux-gnu.tar.gz + wget https://github.com/latchset/clevis-pin-trustee/releases/download/v0.2.0/clevis-pin-trustee-0.2.0-x86_64-unknown-linux-gnu.tar.gz tar xzf clevis-pin-trustee-0.2.0-x86_64-unknown-linux-gnu.tar.gz cd clevis-pin-trustee-0.2.0 @@ -502,7 +502,7 @@ sha256sum clevis-pin-trustee-0.2.0-x86_64-unknown-linux-gnu.tar.gz > \ ### Step 3: Create GitHub Release Manually -1. Go to: https://github.com/sarroutbi/clevis-pin-trustee/releases/new +1. Go to: https://github.com/latchset/clevis-pin-trustee/releases/new 2. Select the tag (or create it): `v0.2.0` 3. Fill in: - **Release title**: `v0.2.0` From 6d9d5edaf40de3e4bf3f3cb0a886eeafd12a4540 Mon Sep 17 00:00:00 2001 From: Sergio Arroutbi Date: Wed, 26 Nov 2025 16:38:47 +0100 Subject: [PATCH 5/6] Add COPR build infrastructure for RHEL9/10 - RPM spec file with vendored dependencies support - Automated build script (copr-build.sh) - Comprehensive COPR.md documentation - Updated .gitignore for vendor directory Files added: - clevis-pin-trustee.spec: RPM spec for EPEL 9/10 - copr-build.sh: Automated vendoring and COPR upload - COPR.md: Complete build and troubleshooting guide The vendored tarball approach ensures offline builds in COPR and avoids network dependencies during the build process. Signed-off-by: Sergio Arroutbi --- .github/workflows/release.yml | 6 +- .gitignore | 8 + COPR.md | 381 ++++++++++++++++++++++++++++++++++ clevis-pin-trustee.spec | 87 ++++++++ copr-build.sh | 111 ++++++++++ dist-workspace.toml | 2 + 6 files changed, 592 insertions(+), 3 deletions(-) create mode 100644 COPR.md create mode 100644 clevis-pin-trustee.spec create mode 100755 copr-build.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5af1771..0526a27 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -87,10 +87,10 @@ jobs: name: artifacts-plan-dist-manifest path: plan-dist-manifest.json - # Build and packages all the platform-specific things + # Build and package all the platform-specific things build-local-artifacts: - name: build-local-artifacts (${{ join(matrix.targets, ', ') }}) - # Let the initial task tell us to not run (currently very blunt) + name: build-local-artifacts + # Let the initial task tell us to not run needs: - plan if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }} diff --git a/.gitignore b/.gitignore index 81a20b1..715eaae 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,11 @@ # Temporary files *.tmp *.temp + +# Vendored dependencies for RPM builds +/vendor/ +/.cargo/config.toml +*-vendor.tar.gz + +# Release artifacts +/release-artifacts/ diff --git a/COPR.md b/COPR.md new file mode 100644 index 0000000..c4016ee --- /dev/null +++ b/COPR.md @@ -0,0 +1,381 @@ + + +# COPR Build Instructions + +This document explains how to build and publish clevis-pin-trustee RPM packages to COPR for RHEL9 and RHEL10. + +## Table of Contents + +- [Prerequisites](#prerequisites) +- [Quick Start](#quick-start) +- [Manual Build Process](#manual-build-process) +- [COPR Project Setup](#copr-project-setup) +- [Testing the Package](#testing-the-package) +- [Troubleshooting](#troubleshooting) + +## Prerequisites + +### Required Tools + +Install the necessary tools on your Fedora/RHEL system: + +```bash +# Install COPR CLI and RPM build tools +sudo dnf install copr-cli rpm-build rpmdevtools + +# Ensure Rust toolchain is installed +cargo --version +``` + +### COPR Account and API Token + +1. Create a COPR account at: https://copr.fedorainfracloud.org/ +2. Generate an API token: https://copr.fedorainfracloud.org/api/ +3. Save it to `~/.config/copr`: + ```bash + mkdir -p ~/.config + # Copy the configuration from the COPR web UI + ``` + +## Quick Start + +Use the automated build script: + +```bash +# Build and upload to COPR +./copr-build.sh 0.1.0 +``` + +The script will: +1. Create vendored dependencies +2. Generate source tarball +3. Build SRPM +4. Optionally upload to COPR + +## Manual Build Process + +If you prefer to build manually, follow these steps: + +### Step 1: Create Vendored Dependencies + +```bash +# Clean previous vendor directory +rm -rf vendor .cargo/config.toml + +# Vendor all Rust dependencies +cargo vendor --versioned-dirs vendor +``` + +### Step 2: Configure Vendored Sources + +```bash +# Create cargo config +mkdir -p .cargo +cat > .cargo/config.toml << 'EOF' +[source.crates-io] +replace-with = "vendored-sources" + +[source.vendored-sources] +directory = "vendor" +EOF +``` + +### Step 3: Create Vendored Tarball + +```bash +VERSION="0.1.0" +PACKAGE="clevis-pin-trustee" +TARBALL="${PACKAGE}-${VERSION}-vendor.tar.gz" + +# Archive git content +git archive --format=tar --prefix=${PACKAGE}-${VERSION}/ HEAD | gzip > /tmp/git-archive.tar.gz + +# Extract and add vendor directory +mkdir -p /tmp/${PACKAGE}-${VERSION} +cd /tmp && tar xzf git-archive.tar.gz +cp -r ${OLDPWD}/vendor ${PACKAGE}-${VERSION}/ +cp -r ${OLDPWD}/.cargo ${PACKAGE}-${VERSION}/ + +# Create final tarball +tar czf ${TARBALL} ${PACKAGE}-${VERSION}/ +mv ${TARBALL} ${OLDPWD}/ +cd ${OLDPWD} + +echo "Created: ${TARBALL}" +``` + +### Step 4: Build SRPM + +```bash +# Setup RPM build tree +rpmdev-setuptree + +# Copy source and spec +cp clevis-pin-trustee-0.1.0-vendor.tar.gz ~/rpmbuild/SOURCES/ +cp clevis-pin-trustee.spec ~/rpmbuild/SPECS/ + +# Build source RPM +rpmbuild -bs ~/rpmbuild/SPECS/clevis-pin-trustee.spec + +# The SRPM will be in ~/rpmbuild/SRPMS/ +``` + +### Step 5: Upload to COPR + +```bash +# Find the SRPM +SRPM=$(ls -t ~/rpmbuild/SRPMS/clevis-pin-trustee-0.1.0-*.src.rpm | head -1) + +# Upload to COPR for RHEL9 and RHEL10 +copr-cli build sarroutb/clevis-pin-trustee \ + --chroot epel-9-x86_64 \ + --chroot epel-9-aarch64 \ + --chroot epel-10-x86_64 \ + --chroot epel-10-aarch64 \ + ${SRPM} +``` + +## COPR Project Setup + +### Creating the COPR Project + +If you haven't created the COPR project yet: + +1. Go to: https://copr.fedorainfracloud.org/coprs/add/ +2. Fill in: + - **Project name**: `clevis-pin-trustee` + - **Chroots**: Select EPEL 9 and EPEL 10 (both x86_64 and aarch64) + - **Description**: `Clevis PIN for Trustee attestation` + - **Instructions**: Add installation instructions +3. Click "Create" + +### Project Settings + +Recommended COPR project settings: + +- **Enable networking**: Yes (required for building, though actual build is offline) +- **Auto-rebuild**: No (manual rebuilds only) +- **Follow Fedora branching**: No (we target EPEL specifically) + +## Available Chroots + +The package supports these build targets: + +- `epel-9-x86_64` - RHEL9 / CentOS Stream 9 (x86_64) +- `epel-9-aarch64` - RHEL9 / CentOS Stream 9 (ARM64) +- `epel-10-x86_64` - RHEL10 (x86_64) +- `epel-10-aarch64` - RHEL10 (ARM64) + +## Installation Instructions + +After the package is built in COPR, users can install it: + +### RHEL9 / CentOS Stream 9 + +```bash +# Enable COPR repository +sudo dnf copr enable sarroutb/clevis-pin-trustee + +# Install the package +sudo dnf install clevis-pin-trustee +``` + +### RHEL10 + +```bash +# Enable COPR repository +sudo dnf copr enable sarroutb/clevis-pin-trustee + +# Install the package +sudo dnf install clevis-pin-trustee +``` + +## Testing the Package + +After building, you can test the package locally: + +### Install from COPR + +```bash +# Enable the repository +sudo dnf copr enable sarroutb/clevis-pin-trustee + +# Install +sudo dnf install clevis-pin-trustee + +# Verify installation +clevis-pin-trustee --version +which clevis-encrypt-trustee +which clevis-decrypt-trustee +``` + +### Test Basic Functionality + +```bash +# Test encryption (requires a running Trustee server) +echo "test data" | clevis-pin-trustee encrypt '{"servers":[{"url":"http://localhost:8080","cert":""}],"path":"test/path"}' + +# Test decrypt +# (output from encrypt) | clevis-pin-trustee decrypt +``` + +### Local RPM Build Test + +Before uploading to COPR, test the build locally: + +```bash +# Build locally +rpmbuild -ba ~/rpmbuild/SPECS/clevis-pin-trustee.spec + +# Install the built RPM +sudo dnf install ~/rpmbuild/RPMS/x86_64/clevis-pin-trustee-0.1.0-1.*.x86_64.rpm + +# Test +clevis-pin-trustee --version +``` + +## Troubleshooting + +### Build Failures + +#### Missing Dependencies + +If the build fails with missing Rust dependencies: + +``` +Error: This package requires rust >= 1.85.0 +``` + +**Solution**: The EPEL buildroots should have Rust 1.85+. If not, the build will fail and you may need to wait for EPEL updates or use a different approach. + +#### Vendor Directory Issues + +If the build fails with "can't find crate": + +``` +error: no matching package named `xxx` found +``` + +**Solution**: Regenerate the vendor directory: + +```bash +rm -rf vendor .cargo +cargo vendor --versioned-dirs vendor +``` + +#### SRPM Build Errors + +If `rpmbuild` fails: + +``` +error: File not found: /home/user/rpmbuild/SOURCES/clevis-pin-trustee-0.1.0-vendor.tar.gz +``` + +**Solution**: Ensure the tarball is in the correct location: + +```bash +cp clevis-pin-trustee-0.1.0-vendor.tar.gz ~/rpmbuild/SOURCES/ +``` + +### COPR Upload Issues + +#### Authentication Errors + +``` +Error: Login invalid/expired. Please visit https://copr.fedorainfracloud.org/api/ +``` + +**Solution**: Regenerate your COPR API token and update `~/.config/copr`. + +#### Permission Denied + +``` +Error: You don't have permissions to build in this project +``` + +**Solution**: Ensure you're the owner of the COPR project or have been granted permissions. + +### Runtime Issues + +#### Binary Not Found + +After installation, if `clevis-pin-trustee` is not found: + +```bash +# Verify package installation +rpm -ql clevis-pin-trustee + +# Check if binary is in PATH +ls -l /usr/bin/clevis-pin-trustee +``` + +#### Missing Dependencies + +If running fails with missing dependencies: + +```bash +# Install runtime dependencies +sudo dnf install clevis jose + +# For development/testing +sudo dnf install trustee-attester +``` + +## Updating the Package + +When releasing a new version: + +1. **Update version** in: + - `cli/Cargo.toml` + - `lib/Cargo.toml` + - `clevis-pin-trustee.spec` (Version and %changelog) + +2. **Regenerate vendored tarball**: + ```bash + ./copr-build.sh 0.2.0 + ``` + +3. **Upload to COPR** + +4. **Tag the release** (for GitHub): + ```bash + git tag -a v0.2.0 -m "Release version 0.2.0" + git push origin v0.2.0 + ``` + +## File Locations + +### Source Files + +- `clevis-pin-trustee.spec` - RPM spec file +- `copr-build.sh` - Automated build script +- `clevis-pin-trustee-VERSION-vendor.tar.gz` - Vendored source tarball (generated) + +### Build Artifacts + +- `~/rpmbuild/SOURCES/` - Source tarballs +- `~/rpmbuild/SPECS/` - RPM spec files +- `~/rpmbuild/SRPMS/` - Source RPM packages +- `~/rpmbuild/RPMS/` - Binary RPM packages + +## Additional Resources + +- **COPR Documentation**: https://docs.pagure.org/copr.copr/ +- **COPR Project**: https://copr.fedorainfracloud.org/coprs/sarroutb/clevis-pin-trustee/ +- **Rust Packaging Guidelines**: https://docs.fedoraproject.org/en-US/packaging-guidelines/Rust/ +- **RPM Packaging Guide**: https://rpm-packaging-guide.github.io/ + +## License Compliance + +The spec file includes proper licensing information: + +- **Source License**: MIT +- **SPDX Headers**: All files include SPDX-FileCopyrightText and SPDX-License-Identifier + +When packaging, ensure: +- `%license` tag points to correct license files +- `LICENSES/` directory is included in source tarball diff --git a/clevis-pin-trustee.spec b/clevis-pin-trustee.spec new file mode 100644 index 0000000..a870bc5 --- /dev/null +++ b/clevis-pin-trustee.spec @@ -0,0 +1,87 @@ +# SPDX-FileCopyrightText: Sergio Arroutbi +# +# SPDX-License-Identifier: MIT + +# Disable debuginfo generation for Rust binaries +%global debug_package %{nil} + +%if 0%{?rhel} || 0%{?epel} +# RHEL/EPEL: Use bundled deps as it doesn't ship Rust libraries +%global bundled_rust_deps 1 +%else +# Fedora: Could use system Rust libraries, but we use vendored for simplicity +%global bundled_rust_deps 1 +%endif + +Name: clevis-pin-trustee +Version: 0.1.0 +Release: 1%{?dist} +Summary: Clevis PIN for Trustee attestation + +License: MIT +URL: https://github.com/sarroutbi/clevis-pin-trustee +Source0: %{name}-%{version}-vendor.tar.gz + +%if 0%{?bundled_rust_deps} +BuildRequires: rust-toolset +%else +BuildRequires: rust-packaging >= 25 +%endif +BuildRequires: openssl-devel + +# Runtime dependencies +Requires: clevis +Requires: jose + +%description +clevis-pin-trustee is a Clevis PIN that implements encryption and decryption +operations using remote attestation via a Trustee server. It enables automated +unlocking of LUKS-encrypted volumes in confidential computing environments by +fetching encryption keys from Trustee servers after successful attestation. + +%prep +%autosetup -n %{name}-%{version} +%if 0%{?bundled_rust_deps} +# Configure cargo to use vendored dependencies +%cargo_prep -v vendor +%else +%cargo_prep +%endif + +%build +# Build using cargo macros +%cargo_build +%if 0%{?bundled_rust_deps} +# Generate vendor manifest (required for bundled crates tracking) +%cargo_vendor_manifest +%endif + +%install +# Install main binary +install -D -m 0755 target/release/%{name} %{buildroot}%{_bindir}/%{name} + +# Install Clevis wrapper scripts +install -D -m 0755 clevis-encrypt-trustee %{buildroot}%{_bindir}/clevis-encrypt-trustee +install -D -m 0755 clevis-decrypt-trustee %{buildroot}%{_bindir}/clevis-decrypt-trustee + +%check +# Run tests using cargo macro +%cargo_test + +%files +%license LICENSES/MIT.txt +%if 0%{?bundled_rust_deps} +%license cargo-vendor.txt +%endif +%doc README.md +%{_bindir}/%{name} +%{_bindir}/clevis-encrypt-trustee +%{_bindir}/clevis-decrypt-trustee + +%changelog +* Wed Nov 26 2025 Sergio Arroutbi - 0.1.0-1 +- Initial release +- Clevis PIN for Trustee attestation +- Support for multiple Trustee server URLs with failover +- Certificate-based TLS authentication +- Optional initdata for attestation context diff --git a/copr-build.sh b/copr-build.sh new file mode 100755 index 0000000..678a2c2 --- /dev/null +++ b/copr-build.sh @@ -0,0 +1,111 @@ +#!/bin/bash +# SPDX-FileCopyrightText: Sergio Arroutbi +# +# SPDX-License-Identifier: MIT + +set -euo pipefail + +PACKAGE_NAME="clevis-pin-trustee" +COPR_PROJECT="sarroutb/clevis-pin-trustee" +VERSION="${1:-0.1.0}" + +echo "==> Building COPR package for ${PACKAGE_NAME} v${VERSION}" + +# Check if copr-cli is installed +if ! command -v copr-cli &> /dev/null; then + echo "Error: copr-cli is not installed" + echo "Install with: dnf install copr-cli" + exit 1 +fi + +# Check if we're in the right directory +if [ ! -f "Cargo.toml" ]; then + echo "Error: Must be run from the project root directory" + exit 1 +fi + +# Step 1: Clean previous vendor directory +echo "==> Cleaning previous vendor directory" +rm -rf vendor .cargo/config.toml + +# Step 2: Create vendor directory +echo "==> Creating vendor directory" +cargo vendor --versioned-dirs vendor > /dev/null + +# Step 3: Create .cargo/config.toml +echo "==> Creating .cargo/config.toml" +mkdir -p .cargo +cat > .cargo/config.toml << 'EOF' +[source.crates-io] +replace-with = "vendored-sources" + +[source.vendored-sources] +directory = "vendor" +EOF + +# Step 4: Create vendored tarball +TARBALL="${PACKAGE_NAME}-${VERSION}-vendor.tar.gz" +echo "==> Creating vendored tarball: ${TARBALL}" + +# Create tarball with git content + vendor directory +git archive --format=tar --prefix=${PACKAGE_NAME}-${VERSION}/ HEAD | gzip > /tmp/git-archive.tar.gz +mkdir -p /tmp/${PACKAGE_NAME}-${VERSION} +cd /tmp && tar xzf git-archive.tar.gz +cp -r ${OLDPWD}/vendor ${PACKAGE_NAME}-${VERSION}/ +cp -r ${OLDPWD}/.cargo ${PACKAGE_NAME}-${VERSION}/ +tar czf ${TARBALL} ${PACKAGE_NAME}-${VERSION}/ +mv ${TARBALL} ${OLDPWD}/ +cd ${OLDPWD} + +echo "==> Tarball created: ${TARBALL} ($(du -h ${TARBALL} | cut -f1))" + +# Step 5: Build SRPM +echo "==> Building SRPM" +if ! command -v rpmbuild &> /dev/null; then + echo "Error: rpmbuild is not installed" + echo "Install with: dnf install rpm-build rpmdevtools" + exit 1 +fi + +# Create RPM build directories +mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS} + +# Copy sources +cp ${TARBALL} ~/rpmbuild/SOURCES/ +cp ${PACKAGE_NAME}.spec ~/rpmbuild/SPECS/ + +# Build SRPM +rpmbuild -bs ~/rpmbuild/SPECS/${PACKAGE_NAME}.spec + +SRPM=$(ls -t ~/rpmbuild/SRPMS/${PACKAGE_NAME}-${VERSION}-*.src.rpm | head -1) +echo "==> SRPM created: ${SRPM}" + +# Step 6: Upload to COPR +echo "" +echo "==> Ready to upload to COPR" +echo "" +echo "To upload to COPR, run:" +echo " copr-cli build ${COPR_PROJECT} ${SRPM}" +echo "" +echo "Or to build for specific chroots:" +echo " copr-cli build ${COPR_PROJECT} --chroot epel-9-x86_64 --chroot epel-10-x86_64 ${SRPM}" +echo "" +read -p "Upload to COPR now? [y/N] " -n 1 -r +echo +if [[ $REPLY =~ ^[Yy]$ ]]; then + echo "==> Uploading to COPR" + copr-cli build ${COPR_PROJECT} \ + --chroot epel-9-x86_64 \ + --chroot epel-9-aarch64 \ + --chroot epel-10-x86_64 \ + --chroot epel-10-aarch64 \ + ${SRPM} + echo "==> Build submitted to COPR" + echo "==> Check status at: https://copr.fedorainfracloud.org/coprs/${COPR_PROJECT}/builds/" +else + echo "==> Skipping COPR upload" + echo "==> SRPM is available at: ${SRPM}" +fi + +echo "" +echo "==> Done!" diff --git a/dist-workspace.toml b/dist-workspace.toml index ba1fde1..4e550b2 100644 --- a/dist-workspace.toml +++ b/dist-workspace.toml @@ -19,3 +19,5 @@ targets = ["aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu"] # Path to README (for release notes) # Include wrapper scripts in the release include = ["clevis-encrypt-trustee", "clevis-decrypt-trustee"] +# Allow manual edits to generated CI workflow files +allow-dirty = ["ci"] From e7079c11d02fd9cd6b80384cd85e3f3daea98c04 Mon Sep 17 00:00:00 2001 From: Sergio Arroutbi Date: Thu, 27 Nov 2025 16:13:06 +0100 Subject: [PATCH 6/6] Release test version 0.2.0 (josekit downgrade) Signed-off-by: Sergio Arroutbi --- Cargo.lock | 32 +++++++++++++++++++------------- cli/Cargo.toml | 4 ++-- cli/src/main.rs | 4 ++-- lib/Cargo.toml | 2 +- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc243f8..0eeb7db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,6 +79,12 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "base64" version = "0.22.1" @@ -161,10 +167,10 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "clevis-pin-trustee" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anyhow", - "base64", + "base64 0.22.1", "clap", "clevis-pin-trustee-lib", "hex", @@ -180,7 +186,7 @@ dependencies = [ [[package]] name = "clevis-pin-trustee-lib" -version = "0.1.0" +version = "0.2.0" dependencies = [ "serde", ] @@ -523,7 +529,7 @@ version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-core", @@ -685,16 +691,16 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "josekit" -version = "0.10.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a808e078330e6af222eb0044b71d4b1ff981bfef43e7bc8133a88234e0c86a0c" +checksum = "16e84ea7acc05b40e2fe6fa02a54b3731323c77e6015c36749f0b10c4dbbc32f" dependencies = [ "anyhow", - "base64", + "base64 0.13.1", "flate2", + "once_cell", "openssl", "regex", - "serde", "serde_json", "thiserror", "time", @@ -1023,7 +1029,7 @@ version = "0.12.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "encoding_rs", "futures-channel", @@ -1362,18 +1368,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index dd351d1..e619a22 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -4,7 +4,7 @@ [package] name = "clevis-pin-trustee" -version = "0.1.0" +version = "0.2.0" description = "Clevis PIN for URL-based encryption/decryption" edition.workspace = true repository.workspace = true @@ -17,7 +17,7 @@ base64 = "0.22.1" clap = { version = "4.0", features = ["derive"] } clevis-pin-trustee-lib = { path = "../lib" } hex = "0.4.3" -josekit = "0.10.3" +josekit = "0.7.4" rand = "0.9.2" reqwest = { version = "0.12", features = ["json", "blocking"] } serde.workspace = true diff --git a/cli/src/main.rs b/cli/src/main.rs index 6c33aab..c3f678a 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -148,7 +148,7 @@ fn encrypt(config: &str) -> Result<()> { let initdata = initdata_data .map(|data| { toml::to_string(&Initdata { - version: "0.1.0".to_string(), + version: "0.2.0".to_string(), algorithm: "sha256".to_string(), data, }) @@ -281,7 +281,7 @@ fn fetch_luks_key( /// Clevis PIN for Trustee #[derive(Parser)] #[command(name = "clevis-pin-trustee")] -#[command(version = "0.1.0")] +#[command(version = "0.2.0")] #[command(about = "Clevis PIN for Trustee")] struct Cli { #[command(subcommand)] diff --git a/lib/Cargo.toml b/lib/Cargo.toml index be97b59..4eb2f62 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -4,7 +4,7 @@ [package] name = "clevis-pin-trustee-lib" -version = "0.1.0" +version = "0.2.0" description = "Library for Clevis PIN for URL-based encryption/decryption" edition.workspace = true repository.workspace = true