Skip to content

Create GitHub Releases after publish - #406

Closed
Alek99 wants to merge 11 commits into
mainfrom
agent/fix-398-github-release-job
Closed

Create GitHub Releases after publish#406
Alek99 wants to merge 11 commits into
mainfrom
agent/fix-398-github-release-job

Conversation

@Alek99

@Alek99 Alek99 commented Jul 31, 2026

Copy link
Copy Markdown
Member

What changed

  • Added a tag-only github-release job after the verified PyPI publish job.
  • Download the already-verified distribution artifacts and create the GitHub Release with generated notes and attached wheels/sdist.
  • Mark alpha, beta, and release-candidate tags as prereleases and make reruns replace assets safely.
  • Kept all workflow_dispatch runs, including dry runs, unable to create a release.
  • Aligned docs-promotion comments/runbook text and added workflow invariants.

Why

Docs promotion requires both the PyPI version and a GitHub Release, but the core release workflow previously created only the PyPI publication. No automated owner completed the second half of that contract.

Impact

A real v* tag now produces the GitHub Release only after publication succeeds, while manual validation remains non-publishing.

Validation

  • .venv/bin/pytest -q tests/test_verify_ci_workflow.py — 59 passed
  • .venv/bin/python scripts/verify_ci_workflow.py
  • Ruff lint and format checks on verifier code/tests

Fixes #398

Review in cubic

Summary by CodeRabbit

  • New Features

    • GitHub Releases are created automatically after successful PyPI publication.
    • Verified packages and signed provenance are attached to releases.
    • Release assets, metadata, notes, and PyPI packages are cross-checked for consistency.
    • Pre-release tags are detected automatically, with safe retry handling for updates.
    • Documentation deployments undergo bounded readiness and integrity checks before promotion.
  • Documentation

    • Updated release and production-readiness guidance.
  • Tests

    • Expanded validation for releases, documentation deployment, package contents, and promotion safeguards.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The release workflow now creates or reconciles GitHub Releases after PyPI publication. Validators enforce tag, artifact, provenance, permission, retry, and promotion requirements. The sdist includes and structurally validates the documentation deployment workflow.

Changes

Release and promotion flow

Layer / File(s) Summary
Tag-triggered GitHub Release publication
.github/workflows/release.yml
Creates or reconciles GitHub Releases after PyPI publication. It generates signed provenance and validates release assets, notes, tags, and hashes.
Release and promotion workflow validation
scripts/verify_ci_workflow.py, tests/test_verify_ci_workflow.py
Adds workflow parsing, release-job invariants, provenance checks, tag guards, bounded retries, termination checks, and runtime simulations.
Documentation promotion readiness gate
.github/workflows/deploy-docs-stg.yml, spec/process/production-readiness.md
Requires matching GitHub Release and PyPI metadata, signed provenance, non-yanked assets, matching hashes, and bounded polling before promotion.
Distribution packaging and archived workflow validation
pyproject.toml, scripts/verify_sdist.py, tests/test_verify_sdist.py
Includes the documentation deployment workflow in the sdist and replaces substring checks with structural validation and tests.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TagPush
  participant ReleaseWorkflow
  participant PyPI
  participant GitHubRelease
  participant DocsPromotion
  TagPush->>ReleaseWorkflow: verify tag source commit
  ReleaseWorkflow->>PyPI: publish distributions
  ReleaseWorkflow->>GitHubRelease: generate provenance and create or reconcile release
  DocsPromotion->>GitHubRelease: poll metadata and verify assets
  DocsPromotion->>PyPI: verify non-yanked files and hashes
  DocsPromotion->>DocsPromotion: allow promotion after matching checks
Loading

Possibly related PRs

Suggested reviewers: masenf

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.30% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: creating GitHub Releases after the package publish step.
Linked Issues check ✅ Passed The changes satisfy issue [#398] by adding tag-only release creation, dry-run protection, documentation, aligned docs promotion checks, and invariant tests.
Out of Scope Changes check ✅ Passed The workflow, verifier, documentation, packaging, and test changes support the release path and docs promotion requirements in [#398].
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/fix-398-github-release-job

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

@codspeed-hq

codspeed-hq Bot commented Jul 31, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 109 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing agent/fix-398-github-release-job (55da823) with main (d505ef5)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@Alek99
Alek99 marked this pull request as ready for review July 31, 2026 03:57

@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: 2

🤖 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/release.yml:
- Around line 335-338: Update the existing-release branch around gh release view
to query and validate isDraft, name, and isPrerelease before uploading assets.
If the release state or metadata is incorrect, publish it with the required
metadata; otherwise preserve the asset refresh and successful retry path, and
fail the job when validation or correction cannot succeed.

In `@scripts/verify_ci_workflow.py`:
- Around line 826-850: The github-release workflow contract does not enforce the
no-artifact failure guard. In scripts/verify_ci_workflow.py lines 826-850,
extend the _require_job_contains assertion to require nullglob, the artifacts
array, and the zero-artifact exit check; in tests/test_verify_ci_workflow.py
lines 772-790, update the mutation test to remove that guard from the workflow
and assert validation fails.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 154c7bbd-51be-414d-a490-21b9db65e5ea

📥 Commits

Reviewing files that changed from the base of the PR and between d505ef5 and af08b2c.

📒 Files selected for processing (5)
  • .github/workflows/deploy-docs-stg.yml
  • .github/workflows/release.yml
  • scripts/verify_ci_workflow.py
  • spec/process/production-readiness.md
  • tests/test_verify_ci_workflow.py

Comment thread .github/workflows/release.yml Outdated
Comment thread scripts/verify_ci_workflow.py
@Alek99 Alek99 closed this Jul 31, 2026
@Alek99 Alek99 reopened this Jul 31, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 5 files

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread scripts/verify_ci_workflow.py Outdated
Comment thread scripts/verify_ci_workflow.py Outdated
Comment thread scripts/verify_ci_workflow.py Outdated
Comment thread scripts/verify_ci_workflow.py Outdated
Comment thread scripts/verify_ci_workflow.py Outdated
Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/release.yml Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 7 files (changes from recent commits).

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/deploy-docs-stg.yml Outdated
Comment thread .github/workflows/deploy-docs-stg.yml Outdated
Comment thread .github/workflows/deploy-docs-stg.yml Outdated
Comment thread scripts/verify_ci_workflow.py Outdated
Comment thread scripts/verify_ci_workflow.py Outdated
Comment thread scripts/verify_ci_workflow.py Outdated
Comment thread .github/workflows/release.yml Outdated
Comment thread scripts/verify_sdist.py Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 6 files (changes from recent commits).

Tip: instead of fixing issues one by one fix them all with cubic
Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread scripts/verify_ci_workflow.py Outdated
Comment thread .github/workflows/deploy-docs-stg.yml Outdated
Comment thread scripts/verify_ci_workflow.py Outdated
Comment thread .github/workflows/deploy-docs-stg.yml Outdated
Comment thread .github/workflows/release.yml
Comment thread scripts/verify_sdist.py Outdated
Comment thread .github/workflows/deploy-docs-stg.yml
Comment thread scripts/verify_ci_workflow.py Outdated

@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.

🧹 Nitpick comments (1)
tests/test_verify_ci_workflow.py (1)

2109-2117: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Align the simulated shell options with the shell the workflow actually uses.

The simulations invoke bash -e -o pipefail. The github-release steps in .github/workflows/release.yml and the release gate step in .github/workflows/deploy-docs-stg.yml declare no shell: key, so GitHub Actions runs them with the default bash -e {0} and does not enable pipefail.

The simulation is therefore stricter than production. A pipeline whose non-final element fails aborts in the test but continues in production, for example sha256sum "$file" | cut -d ' ' -f 1. That failure mode stays untested.

Choose one of two options:

  • Drop -o pipefail from the simulations so they match production.
  • Add shell: bash to the affected workflow steps so production enables pipefail, and keep the simulations as they are.

The second option is the safer one for the release path.

♻️ Option 2: make production match the simulations
       - name: Prepare release provenance
         if: steps.release_state.outputs.immutable != 'true'
+        shell: bash
         env:
           GH_TOKEN: ${{ github.token }}

Apply the same shell: bash key to Inspect existing release, Create GitHub Release and attach distributions, and Await GitHub Release and PyPI availability.

Also applies to: 2135-2143, 2244-2252, 2452-2460, 2736-2744

🤖 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 `@tests/test_verify_ci_workflow.py` around lines 2109 - 2117, Add shell: bash
to the workflow steps corresponding to Inspect existing release, Create GitHub
Release and attach distributions, and Await GitHub Release and PyPI
availability, including every affected occurrence. Keep the existing bash -e -o
pipefail simulations unchanged so production uses the same pipefail behavior.
🤖 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.

Nitpick comments:
In `@tests/test_verify_ci_workflow.py`:
- Around line 2109-2117: Add shell: bash to the workflow steps corresponding to
Inspect existing release, Create GitHub Release and attach distributions, and
Await GitHub Release and PyPI availability, including every affected occurrence.
Keep the existing bash -e -o pipefail simulations unchanged so production uses
the same pipefail behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4b75fe48-e412-4b74-9441-05ebbbe93524

📥 Commits

Reviewing files that changed from the base of the PR and between af08b2c and 04d71b4.

📒 Files selected for processing (8)
  • .github/workflows/deploy-docs-stg.yml
  • .github/workflows/release.yml
  • pyproject.toml
  • scripts/verify_ci_workflow.py
  • scripts/verify_sdist.py
  • spec/process/production-readiness.md
  • tests/test_verify_ci_workflow.py
  • tests/test_verify_sdist.py

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 7 files (changes from recent commits).

Tip: instead of fixing issues one by one fix them all with cubic
Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread scripts/verify_ci_workflow.py Outdated
Comment thread scripts/verify_ci_workflow.py Outdated
Comment thread scripts/verify_ci_workflow.py
Comment thread scripts/verify_ci_workflow.py Outdated
Comment thread .github/workflows/release.yml
Comment thread .github/workflows/release.yml
Comment thread scripts/verify_ci_workflow.py Outdated

@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: 2

🧹 Nitpick comments (1)
scripts/verify_ci_workflow.py (1)

2654-2693: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Report which invariant failed instead of one aggregated message.

This composite check combines about fifteen independent conditions, several of which depend on hard-coded logical-line offsets such as tag_resolution_positions[0] + 10. When a maintainer edits .github/workflows/release.yml, the verifier emits one generic sentence that does not name the violated invariant. The same pattern repeats at lines 2130-2154 and 2426-2449.

Consider evaluating a list of (condition, message) pairs and appending each failed message. The check semantics stay the same, and the failure output identifies the broken invariant.

🤖 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 `@scripts/verify_ci_workflow.py` around lines 2654 - 2693, Replace the
aggregated composite checks in the affected verifier sections, including the
block around _has_exact_tag_source_function and its counterparts near the other
reported ranges, with individual condition/message evaluations. Build
condition-message pairs for each invariant, append the corresponding specific
message whenever its condition fails, and preserve all existing boolean
expressions and validation semantics, including offset-based checks.
🤖 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 `@scripts/verify_ci_workflow.py`:
- Around line 435-449: Reset double_bracket_open for each shell command record,
matching arithmetic_open’s per-record lifecycle, so multi-line [[ conditions do
not suppress command-start scanning on later logical lines. Preserve
expression_positions handling within the current record while ensuring command
substitutions such as $(...) are still inspected by the indirect-execution
check.

In `@tests/test_verify_ci_workflow.py`:
- Around line 1444-1450: Ensure every workflow marker substitution in the
affected tests—including the sites around the existing replacement and the other
listed cases—asserts that the marker exists before calling replace. Prefer
introducing a small shared helper that checks marker presence with a clear
assertion and performs a single replacement, then update each injection site to
use it.

---

Nitpick comments:
In `@scripts/verify_ci_workflow.py`:
- Around line 2654-2693: Replace the aggregated composite checks in the affected
verifier sections, including the block around _has_exact_tag_source_function and
its counterparts near the other reported ranges, with individual
condition/message evaluations. Build condition-message pairs for each invariant,
append the corresponding specific message whenever its condition fails, and
preserve all existing boolean expressions and validation semantics, including
offset-based checks.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5f1f75f6-e55b-4cfc-8412-89785be46fa2

📥 Commits

Reviewing files that changed from the base of the PR and between 04d71b4 and 1a34af6.

📒 Files selected for processing (2)
  • scripts/verify_ci_workflow.py
  • tests/test_verify_ci_workflow.py

Comment thread scripts/verify_ci_workflow.py
Comment thread tests/test_verify_ci_workflow.py

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 7 files (changes from recent commits).

Tip: instead of fixing issues one by one fix them all with cubic
Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread scripts/verify_ci_workflow.py
Comment thread scripts/verify_ci_workflow.py
Comment thread scripts/verify_ci_workflow.py
Comment thread scripts/verify_ci_workflow.py
Comment thread .github/workflows/release.yml

@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.

🧹 Nitpick comments (2)
scripts/verify_ci_workflow.py (2)

1562-1577: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

_gh_api_write_requests matches only the bare token gh.

Line 1567 compares the raw token. _has_gh_release_mutation (Line 1521) instead compares token.rsplit("/", 1)[-1]. A path-qualified invocation such as /usr/bin/gh api --method POST ... therefore returns no write requests from this helper.

Every current caller runs _has_indirect_shell_execution on the same shell first, and _has_unapproved_shell_command rejects path-qualified command heads, so the release path stays fail-closed today. Align the two helpers so the guarantee does not depend on call order.

♻️ Proposed alignment
-            if token != "gh" or not _shell_token_starts_command(tokens, index):
+            if token.rsplit("/", 1)[-1] != "gh" or not _shell_token_starts_command(tokens, index):
                 continue
🤖 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 `@scripts/verify_ci_workflow.py` around lines 1562 - 1577, Update
_gh_api_write_requests to identify the gh executable by its basename, matching
_has_gh_release_mutation’s token.rsplit("/", 1)[-1] behavior, so path-qualified
invocations such as /usr/bin/gh are processed. Preserve the existing
command-start, api-subcommand, and non-GET/HEAD filtering logic.

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

_step_scalar_values ignores the first-line - key: form.

_step_uses (Line 146) and _step_direct_keys (Line 178) both accept a key on the step's first line. _step_scalar_values matches only the 8-space continuation form. Therefore _step_declares_run, _step_scalar, and _step_has_exact_bash_run all return "absent" for a step written as - run: | or - shell: bash.

The current call sites stay fail-closed, because the exact _step_direct_keys and step_identities comparisons reject such a step. The asymmetry is still a trap for any future call site that treats an absent run as safe. Align the two parsers.

♻️ Proposed alignment
 def _step_scalar_values(step_text: str, key: str) -> list[str]:
     """Return every direct scalar value for one step key."""
     values: list[str] = []
     for match in re.finditer(
-        rf"^        {re.escape(key)}\s*:\s*(.*?)\s*$",
+        rf"^(?:      -\s+|        ){re.escape(key)}\s*:\s*(.*?)\s*$",
         step_text,
         re.MULTILINE,
     ):
         values.append(_strip_yaml_inline_comment(match.group(1)))
     return values
🤖 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 `@scripts/verify_ci_workflow.py` around lines 154 - 168, Update
_step_scalar_values to also match direct scalar keys on a step’s first line
using the 6-space “- key:” form, while preserving the existing 8-space
continuation matching and comment stripping. Align it with _step_uses and
_step_direct_keys so _step_declares_run, _step_scalar, and
_step_has_exact_bash_run recognize first-line run and shell declarations.
🤖 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.

Nitpick comments:
In `@scripts/verify_ci_workflow.py`:
- Around line 1562-1577: Update _gh_api_write_requests to identify the gh
executable by its basename, matching _has_gh_release_mutation’s
token.rsplit("/", 1)[-1] behavior, so path-qualified invocations such as
/usr/bin/gh are processed. Preserve the existing command-start, api-subcommand,
and non-GET/HEAD filtering logic.
- Around line 154-168: Update _step_scalar_values to also match direct scalar
keys on a step’s first line using the 6-space “- key:” form, while preserving
the existing 8-space continuation matching and comment stripping. Align it with
_step_uses and _step_direct_keys so _step_declares_run, _step_scalar, and
_step_has_exact_bash_run recognize first-line run and shell declarations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a5b3bcba-08a4-413c-8e71-837f05ec9d3c

📥 Commits

Reviewing files that changed from the base of the PR and between 1a34af6 and 599d0b9.

📒 Files selected for processing (4)
  • .github/workflows/deploy-docs-stg.yml
  • .github/workflows/release.yml
  • scripts/verify_ci_workflow.py
  • tests/test_verify_ci_workflow.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • .github/workflows/deploy-docs-stg.yml
  • .github/workflows/release.yml
  • tests/test_verify_ci_workflow.py

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 7 files (changes from recent commits).

Not reviewed (too large): scripts/verify_ci_workflow.py (~3,281 lines), tests/test_verify_ci_workflow.py (~2,798 lines) - if these are generated or fixture files, add them to ignored paths to exclude them from future reviews.

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread .github/workflows/release.yml Outdated
Comment thread spec/process/production-readiness.md Outdated

@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.

🧹 Nitpick comments (2)
tests/test_verify_ci_workflow.py (2)

3296-3319: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a near-miss "release not found" case.

The step compares stderr for exact equality with release not found\n. The current parameters cover an unrelated auth error, a timeout, and malformed metadata. They do not cover a message that contains release not found plus extra text.

That near-miss is the most likely regression for an equality check. A future gh version can emit release not found for tag v1.2.3. The step must still fail closed, and the test named test_release_state_preflight_treats_only_exact_not_found_as_absent currently does not prove it.

Add a fake gh mode that prints a superset message, then assert the fail-closed outcome.

♻️ Proposed additional case
 case "$GH_MODE" in
   success)
     printf '%s\\n' "$GH_RESPONSE"
     ;;
   not-found)
     printf 'release not found\\n' >&2
     exit 1
     ;;
+  not-found-superset)
+    printf 'release not found for tag %s\\n' "$TAG" >&2
+    exit 1
+    ;;
   auth-error)
     [
         ("auth-error", ""),
+        ("not-found-superset", ""),
         ("timeout", ""),
         ("success", "{"),
🤖 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 `@tests/test_verify_ci_workflow.py` around lines 3296 - 3319, Add a
parameterized near-miss case to
test_release_state_preflight_treats_only_exact_not_found_as_absent (or the
visible fail-closed test if that is the current name), using a fake gh mode that
emits “release not found” with additional text. Assert the same fail-closed
result: nonzero return code, empty output, and no leftovers, while preserving
the exact-message absent-release behavior separately.

3228-3237: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider an allowlisted environment instead of inheriting os.environ.

os.environ | {...} passes every ambient variable into the simulated step. The overrides cover GITHUB_OUTPUT and RUNNER_TEMP, so the main collisions are handled. Other inherited variables remain, for example GITHUB_REPOSITORY and GH_HOST. If the step ever reads one of them, the assertions on exact github_output content become environment dependent.

Pass only the variables the step needs, plus PATH.

♻️ Proposed hermetic environment
-    env = os.environ | {
+    env = {
         "GITHUB_OUTPUT": str(github_output),
         "GH_MODE": mode,
         "GH_RESPONSE": response,
         "GH_TOKEN": "test-token",
-        "PATH": f"{fake_bin}{os.pathsep}{os.environ.get('PATH', '')}",
+        "HOME": str(tmp_path),
+        "PATH": f"{fake_bin}{os.pathsep}{os.environ.get('PATH', '')}",
         "REPO": "reflex-dev/xy",
         "RUNNER_TEMP": str(runner_temp),
         "TAG": "v1.2.3",
     }
🤖 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 `@tests/test_verify_ci_workflow.py` around lines 3228 - 3237, Update the test
environment setup around the env mapping to stop inheriting os.environ
wholesale. Construct an allowlisted environment containing only the variables
required by the simulated step, the existing test overrides, and PATH,
preserving the current values for GITHUB_OUTPUT and RUNNER_TEMP so assertions
remain hermetic.
🤖 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.

Nitpick comments:
In `@tests/test_verify_ci_workflow.py`:
- Around line 3296-3319: Add a parameterized near-miss case to
test_release_state_preflight_treats_only_exact_not_found_as_absent (or the
visible fail-closed test if that is the current name), using a fake gh mode that
emits “release not found” with additional text. Assert the same fail-closed
result: nonzero return code, empty output, and no leftovers, while preserving
the exact-message absent-release behavior separately.
- Around line 3228-3237: Update the test environment setup around the env
mapping to stop inheriting os.environ wholesale. Construct an allowlisted
environment containing only the variables required by the simulated step, the
existing test overrides, and PATH, preserving the current values for
GITHUB_OUTPUT and RUNNER_TEMP so assertions remain hermetic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3dab0d3d-2114-495e-8ddc-1729849cc57a

📥 Commits

Reviewing files that changed from the base of the PR and between 599d0b9 and 55da823.

📒 Files selected for processing (4)
  • .github/workflows/release.yml
  • scripts/verify_ci_workflow.py
  • spec/process/production-readiness.md
  • tests/test_verify_ci_workflow.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • spec/process/production-readiness.md
  • .github/workflows/release.yml
  • scripts/verify_ci_workflow.py

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/verify_ci_workflow.py">

<violation number="1">
P2: The “exact” preflight check still accepts comment-only lines because `_step_run()` removes them; a comment after the timeout line’s trailing `\` makes Bash run `gh release view` separately and without the 30-second bound. Comparing comment-preserving text or rejecting comments in this protected step would close the bypass.

(Based on your team's feedback about exact protected step shape.) [FEEDBACK_USED]</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Core release workflow does not create the GitHub Release required by docs promotion

1 participant