Skip to content

Add Protected Semantic Version Releases#30

Merged
PSchmiedmayer merged 1 commit into
mainfrom
feature/release-gating
Jul 13, 2026
Merged

Add Protected Semantic Version Releases#30
PSchmiedmayer merged 1 commit into
mainfrom
feature/release-gating

Conversation

@PSchmiedmayer

@PSchmiedmayer PSchmiedmayer commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

♻️ Current Situation & Problem

Native release assets are built when a GitHub Release is published, but publication is not bound to the successful main checks for the exact tagged commit. A release can therefore exist before native packaging succeeds, main-only CPU and GPU image publication is not part of the gate, and no protected approval separates candidate verification from publication.

⚙️ Release Notes

  • Add a manually dispatched release workflow that accepts strict Semantic Versioning without a v prefix and binds publication to the current main commit.
  • Require every declared main check, verify immutable generic, Terra, generic GPU, and Terra GPU candidates, and rebuild and test native assets before approval.
  • Publish digest-preserving Semantic Version image tags, attest native assets, create a complete draft, and publish the Git tag and immutable GitHub Release only after approval.
  • Run native asset validation on every pull request and main commit.
  • Configure the release environment with required maintainer approval and self-review enabled, enable immutable releases, protect tags against mutation, and add native assets to the main merge ruleset.

📚 Documentation

The release guide documents version syntax, the maintainer command, automated gates, self-approval, artifact names, image tags, build-metadata mapping, interruption behavior, and maintenance of the required-check manifest. The development, container, and delivery documents now distinguish implemented release governance from remaining signing, retention, notice, compatibility, and support work.

✅ Testing

  • 431 Python tests pass with 90.09% aggregate branch coverage.
  • Release tests cover valid and invalid Semantic Versions, paginated and duplicate check runs, commit-status contexts, failure and incomplete states, all four image mappings, OCI-safe build metadata, Terra flattening, and idempotent promotion.
  • Ruff formatting and lint, strict mypy, actionlint, shell syntax, Markdown whitespace, native installer packaging and installation smoke, and REUSE 3.3 compliance pass locally.
  • The verifier was exercised against the actual merged main commit and correctly reported still-running main-only image jobs plus the native check that this pull request adds to main.

Code of Conduct & Contributing Guidelines

By creating and submitting this pull request, you agree to follow our Code of Conduct and Contributing Guidelines:

Copilot AI review requested due to automatic review settings July 13, 2026 00:34
@github-project-automation github-project-automation Bot moved this to Backlog in Heartwood Jul 13, 2026
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@PSchmiedmayer, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 10 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0ad81a33-b9aa-4950-a505-dde5dc4adbe4

📥 Commits

Reviewing files that changed from the base of the PR and between e539c6a and 1e50ab0.

⛔ Files ignored due to path filters (2)
  • packages/webui/package-lock.json is excluded by !**/package-lock.json
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (45)
  • .github/release-required-checks.txt
  • .github/workflows/create-release.yml
  • .github/workflows/native-release.yml
  • README.md
  • VERSION.toml
  • deploy/promote-release-images.sh
  • deploy/verify_release_candidate.py
  • design/08-development.md
  • design/09-implementation-plan.md
  • docs/README.md
  • docs/carina-cli.md
  • docs/container-images.md
  • docs/platform-support.md
  • docs/releases.md
  • docs/terra-jupyter-demo.ipynb
  • docs/terra-jupyter-demo.md
  • packages/adapters/pyproject.toml
  • packages/adapters/src/heartwood/adapters/__init__.py
  • packages/audit/pyproject.toml
  • packages/audit/src/heartwood/audit/__init__.py
  • packages/cli/pyproject.toml
  • packages/cli/src/heartwood/cli/__init__.py
  • packages/cli/tests/test_cli.py
  • packages/compliance/pyproject.toml
  • packages/compliance/src/heartwood/compliance/__init__.py
  • packages/compliance/tests/test_container_assets.py
  • packages/compliance/tests/test_documentation_assets.py
  • packages/compliance/tests/test_release_governance.py
  • packages/core-adapter/pyproject.toml
  • packages/core-adapter/src/heartwood/core_adapter/__init__.py
  • packages/detector/pyproject.toml
  • packages/detector/src/heartwood/detector/__init__.py
  • packages/fixtures/pyproject.toml
  • packages/fixtures/src/heartwood/fixtures/__init__.py
  • packages/gateway/pyproject.toml
  • packages/model-policy/pyproject.toml
  • packages/model-policy/src/heartwood/model_policy/__init__.py
  • packages/notebook/pyproject.toml
  • packages/notebook/src/heartwood/notebook/__init__.py
  • packages/schemas/pyproject.toml
  • packages/schemas/src/heartwood/schemas/__init__.py
  • packages/session/pyproject.toml
  • packages/session/src/heartwood/session/__init__.py
  • packages/skills/pyproject.toml
  • packages/webui/package.json
📝 Walkthrough

Walkthrough

This change adds a protected, manually triggered release workflow using strict Semantic Versioning. It validates required checks for the exact main commit, verifies immutable container candidates, rebuilds and tests native assets, promotes verified image tags, attests artifacts, and publishes a GitHub Release after approval. Supporting scripts, required-check configuration, compliance tests, native workflow triggers, and release documentation are added or updated.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: protected Semantic Version releases.
Description check ✅ Passed The description is clearly related to the release-governance and documentation changes in the pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@PSchmiedmayer
PSchmiedmayer force-pushed the feature/release-gating branch 2 times, most recently from 4821ba6 to 018a4c0 Compare July 13, 2026 00:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a protected, manually-dispatched release workflow that enforces strict Semantic Versioning, binds publication to the exact main commit after all required checks pass, and gates final publication behind a protected GitHub Actions environment approval.

Changes:

  • Adds a two-phase create-release.yml workflow to verify the main candidate (required checks, container candidates, native assets) and then publish immutable image tags + a draft GitHub Release after environment approval.
  • Introduces release-governance tooling and tests (verify_release_candidate.py, promote-release-images.sh, and compliance tests) to validate SemVer, required-check status, and idempotent image promotion.
  • Updates documentation to describe the new release governance and Semantic Version container tagging (including +_ mapping for OCI tags).

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
README.md Adds a maintainer-facing pointer to the protected release workflow and SemVer rules.
packages/compliance/tests/test_release_governance.py New tests for SemVer validation, required-check status parsing, and image promotion idempotency.
packages/compliance/tests/test_container_assets.py Extends compliance assertions to cover the new release workflow and native-release trigger expectations.
docs/releases.md New release guide documenting version rules, gating, approval, and artifact/tag behavior.
docs/README.md Adds the Releases doc to the documentation index.
docs/container-images.md Documents protected SemVer container tags and release gating behavior.
design/09-implementation-plan.md Updates implementation status language to reflect implemented release governance and remaining assurance work.
design/08-development.md Adds release-governance workflow details to the development/testing posture.
deploy/verify_release_candidate.py Implements SemVer validation + required check-run / commit-status evaluation for the release gate.
deploy/promote-release-images.sh Verifies/publishes digest-preserving SemVer image tags from immutable sha-<gitsha> candidates.
.github/workflows/native-release.yml Ensures native assets are built/verified on PRs and main (and removes release-published upload path in favor of the protected workflow).
.github/workflows/create-release.yml New protected release workflow with verification and approval-gated publication.
.github/release-required-checks.txt New manifest declaring the set of required main checks used by the release gate.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/release-required-checks.txt
Comment thread .github/release-required-checks.txt

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
deploy/promote-release-images.sh (1)

46-53: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add descriptive errors for the manifest-shape checks.

Unlike the digest-mismatch checks (lines 60, 72), a failed jq -e assertion here aborts silently via set -e with no message identifying which tag/shape check failed — makes a release-pipeline failure harder to diagnose.

🛠️ Proposed fix to add explicit error messages
   if [[ "${media_shape}" == "single" ]]; then
-    jq -e '
-      .mediaType == "application/vnd.docker.distribution.manifest.v2+json"
-      and .config.mediaType == "application/vnd.docker.container.image.v1+json"
-    ' <<<"${raw}" >/dev/null
+    if ! jq -e '
+      .mediaType == "application/vnd.docker.distribution.manifest.v2+json"
+      and .config.mediaType == "application/vnd.docker.container.image.v1+json"
+    ' <<<"${raw}" >/dev/null; then
+      echo "candidate is not a single-platform image manifest: ${source_ref}" >&2
+      exit 1
+    fi
   else
-    jq -e '.manifests | length > 0' <<<"${raw}" >/dev/null
+    if ! jq -e '.manifests | length > 0' <<<"${raw}" >/dev/null; then
+      echo "candidate is not a multi-platform manifest list: ${source_ref}" >&2
+      exit 1
+    fi
   fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/promote-release-images.sh` around lines 46 - 53, Update the
manifest-shape checks in the media_shape conditional to handle failed jq -e
assertions explicitly, emitting descriptive errors that identify the affected
tag and whether the single or multi-manifest validation failed before exiting.
Preserve the existing validation expressions and success behavior.
packages/compliance/tests/test_release_governance.py (1)

91-154: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test only covers the promote happy path.

This test exercises promote mode's create-then-idempotent-skip path, but never runs verify mode (which must exit without calling imagetools create, per promote-release-images.sh lines 55-57) and never exercises the digest-mismatch failure branches (lines 59-62, 71-74). These are the exact policy-decision branches most likely to hide a regression in a release-gating script.

As per coding guidelines, "Add or update tests when changing detector logic, policy decisions, adapter behavior, skill validation, audit records, attestation export, CLI output, notebook view models, or web-UI view models" for **/*.{py,ts,tsx}.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/compliance/tests/test_release_governance.py` around lines 91 - 154,
Add coverage alongside test_release_image_promotion_is_complete_and_idempotent
for promote-release-images.sh verify mode, asserting it exits successfully
without invoking imagetools create. Also add cases for each digest-mismatch
failure branch in promote and verify, asserting a nonzero exit and the expected
failure behavior while preserving the existing happy-path and idempotency
assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/create-release.yml:
- Around line 58-85: Update the “Wait for required checks on the exact commit”
retry loop so transient failures from either gh api call are handled within the
loop instead of triggering immediate bash errexit termination. Capture each API
command’s status, log the polling failure, sleep, and retry while preserving
verify_release_candidate.py’s existing exit-code handling and the 60-attempt
timeout.
- Around line 86-91: Add a docker/login-action step before “Verify immutable
container candidates” in the release workflow, authenticating to GHCR with the
existing registry credentials and appropriate GitHub token. Keep the verify
command and its RELEASE_VERSION/GITHUB_SHA inputs unchanged.
- Around line 160-179: The release-existence handling should distinguish draft
releases from published releases so reruns can resume after the draft creation
step. Update the existing release freshness-check flow to branch on isDraft,
publishing the existing draft via the release-edit path and only failing for an
already published release; preserve the normal create-then-publish flow for new
releases.

---

Nitpick comments:
In `@deploy/promote-release-images.sh`:
- Around line 46-53: Update the manifest-shape checks in the media_shape
conditional to handle failed jq -e assertions explicitly, emitting descriptive
errors that identify the affected tag and whether the single or multi-manifest
validation failed before exiting. Preserve the existing validation expressions
and success behavior.

In `@packages/compliance/tests/test_release_governance.py`:
- Around line 91-154: Add coverage alongside
test_release_image_promotion_is_complete_and_idempotent for
promote-release-images.sh verify mode, asserting it exits successfully without
invoking imagetools create. Also add cases for each digest-mismatch failure
branch in promote and verify, asserting a nonzero exit and the expected failure
behavior while preserving the existing happy-path and idempotency assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c9d4c87e-95bf-4cf4-9c72-27488ef9bc41

📥 Commits

Reviewing files that changed from the base of the PR and between 90b5f42 and e539c6a.

📒 Files selected for processing (13)
  • .github/release-required-checks.txt
  • .github/workflows/create-release.yml
  • .github/workflows/native-release.yml
  • README.md
  • deploy/promote-release-images.sh
  • deploy/verify_release_candidate.py
  • design/08-development.md
  • design/09-implementation-plan.md
  • docs/README.md
  • docs/container-images.md
  • docs/releases.md
  • packages/compliance/tests/test_container_assets.py
  • packages/compliance/tests/test_release_governance.py

Comment thread .github/workflows/create-release.yml
Comment thread .github/workflows/create-release.yml
Comment thread .github/workflows/create-release.yml
@PSchmiedmayer
PSchmiedmayer force-pushed the feature/release-gating branch 4 times, most recently from 1fc50fc to 73d0f42 Compare July 13, 2026 01:20
@PSchmiedmayer
PSchmiedmayer force-pushed the feature/release-gating branch from 73d0f42 to 1e50ab0 Compare July 13, 2026 01:24
@PSchmiedmayer
PSchmiedmayer merged commit 3845860 into main Jul 13, 2026
19 checks passed
@PSchmiedmayer
PSchmiedmayer deleted the feature/release-gating branch July 13, 2026 01:35
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Heartwood Jul 13, 2026
PSchmiedmayer added a commit that referenced this pull request Jul 18, 2026
### ♻️ Current Situation & Problem

Native release assets are built when a GitHub Release is published, but
publication is not bound to the successful `main` checks for the exact
tagged commit. A release can therefore exist before native packaging
succeeds, main-only CPU and GPU image publication is not part of the
gate, and no protected approval separates candidate verification from
publication.

### ⚙️ Release Notes

- Add a manually dispatched release workflow that accepts strict
Semantic Versioning without a `v` prefix and binds publication to the
current `main` commit.
- Require every declared main check, verify immutable generic, Terra,
generic GPU, and Terra GPU candidates, and rebuild and test native
assets before approval.
- Publish digest-preserving Semantic Version image tags, attest native
assets, create a complete draft, and publish the Git tag and immutable
GitHub Release only after approval.
- Run native asset validation on every pull request and `main` commit.
- Configure the `release` environment with required maintainer approval
and self-review enabled, enable immutable releases, protect tags against
mutation, and add native assets to the main merge ruleset.

### 📚 Documentation

The release guide documents version syntax, the maintainer command,
automated gates, self-approval, artifact names, image tags,
build-metadata mapping, interruption behavior, and maintenance of the
required-check manifest. The development, container, and delivery
documents now distinguish implemented release governance from remaining
signing, retention, notice, compatibility, and support work.

### ✅ Testing

- 431 Python tests pass with 90.09% aggregate branch coverage.
- Release tests cover valid and invalid Semantic Versions, paginated and
duplicate check runs, commit-status contexts, failure and incomplete
states, all four image mappings, OCI-safe build metadata, Terra
flattening, and idempotent promotion.
- Ruff formatting and lint, strict mypy, actionlint, shell syntax,
Markdown whitespace, native installer packaging and installation smoke,
and REUSE 3.3 compliance pass locally.
- The verifier was exercised against the actual merged `main` commit and
correctly reported still-running main-only image jobs plus the native
check that this pull request adds to `main`.

### Code of Conduct & Contributing Guidelines

By creating and submitting this pull request, you agree to follow our
[Code of
Conduct](https://github.com/SchmiedmayerLab/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/SchmiedmayerLab/.github/blob/main/CONTRIBUTING.md):
- [x] I agree to follow the [Code of
Conduct](https://github.com/SchmiedmayerLab/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/SchmiedmayerLab/.github/blob/main/CONTRIBUTING.md).
@PSchmiedmayer PSchmiedmayer self-assigned this Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants