release: v0.3.0-beta.1 - #156
Conversation
Verify the configured tagger email and SSH signing key against GitHub before a release tag exists. Distinguish local tag validation from GitHub tag-object verification and retain immutable patch-version recovery. GSTACK-Checkpoint: 2026-07-14/release-tag-identity#1 Signed-off-by: Gnani Rahul <gnani.nutakki@gmail.com>
…ag-identity docs(release): preflight GitHub SSH tag identity
Export deterministic gap detail from normalized coverage so policy layers can conservatively abstain without reinterpreting query counters. Preserve stale and unreachable scope evidence, detect unaccounted and inconsistent metadata fail closed, and prove the behavior with unit and real Kind-federation scenarios. GSTACK-Checkpoint: 2026-07-14/e2-coverage-assessment#1 Signed-off-by: Gnani Rahul <gnani.nutakki@gmail.com>
Merged after green hosted CI and CodeQL, a clean local peer review, forced-RLS isolation, release reproducibility, and real two-cluster validation.
GSTACK-Checkpoint: 2026-07-14/e2-vulnerability-report-facts#1 Signed-off-by: Gnani Rahul <gnani.nutakki@gmail.com>
GSTACK-Checkpoint: 2026-07-14/e2-exact-cve-search#1 Signed-off-by: Gnani Rahul <gnani.nutakki@gmail.com>
…cve-search feat(e2): search runtime-proven CVE facts
GSTACK-Checkpoint: 2026-07-14/e9-beta-prerelease#1 Signed-off-by: Gnani Rahul <gnani.nutakki@gmail.com>
…rerelease feat(e9): publish signed beta prereleases
📝 WalkthroughWalkthroughChangesCVE fact vertical
Coverage assessment
Beta release publication
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related issues
Sequence Diagram(s)sequenceDiagram
participant OCM
participant DirectAdapter
participant FleetDB
participant CVESearcher
participant FleetHandler
OCM->>DirectAdapter: list VulnerabilityReport resources
DirectAdapter->>DirectAdapter: match runtime image digest and normalize CVE facts
DirectAdapter->>FleetDB: persist FactCVE snapshot evidence
FleetHandler->>CVESearcher: authorize and execute exact CVE search
CVESearcher->>FleetDB: query FactCVE by digest or identifier
FleetDB-->>FleetHandler: return facts and coverage
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
GSTACK-Checkpoint: 2026-07-14/e9-release-pr-ci-gate#1 Signed-off-by: Gnani Rahul <gnani.nutakki@gmail.com>
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
internal/hubserver/fleet.go (1)
190-235: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winExtract the repeated unescape/escape round-trip check into a helper.
The
url.PathUnescape+ re-url.PathEscapecomparison (rejecting non-canonical percent-encoding) is duplicated for the workspace, CVE identifier, and image digest segments. Since this check is what prevents route-confusion via double-encoding, consolidating it into one helper reduces the risk that a future route addition forgets it.func canonicalPathSegment(segment string) (string, bool) { value, err := url.PathUnescape(segment) if err != nil || url.PathEscape(value) != segment { return "", false } return value, true }🤖 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 `@internal/hubserver/fleet.go` around lines 190 - 235, Extract the repeated url.PathUnescape and url.PathEscape canonicalization logic into a canonicalPathSegment helper. Update the workspace, CVE identifier, and image digest parsing in the route parser to use this helper while preserving their existing validation and rejection 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.
Inline comments:
In `@docs/RELEASE.md`:
- Around line 127-140: Make the shell snippet fail closed by enabling strict
error handling with set -euo pipefail near the start, or explicitly exiting on
failure for every test and grep command. Ensure failures in identity validation,
email lookup, and signing-key verification stop execution rather than allowing
the snippet to report success.
In `@internal/hubdb/fleet.go`:
- Around line 335-345: Add a default branch to the Image-selector switch in
queryFacts that fails closed when query.Kinds[0] is not fleet.FactInventory or
fleet.FactCVE. Ensure unexpected kinds cannot omit the image condition and
broaden the query; use the existing error/validation mechanism for reporting the
invalid selector kind.
In `@internal/hubocm/direct.go`:
- Around line 482-562: Update collectCVEFacts so a fleet.CanonicalCVEObservation
error for one aggregated digest is skipped rather than returned, allowing
processing to continue for remaining digests and preserving non-CVE facts. Keep
JSON marshaling errors and successful evidence generation behavior unchanged.
In `@tests/scripts/release_tag_policy_test.sh`:
- Around line 51-54: Strengthen the release workflow assertions around the
tested classifier so tests/scripts/release_tag_policy_test.sh verifies that
RELEASE_KIND is exported and consumed, the beta branch is selected, and
prerelease=true is set. Keep the existing classifier invocation and
make_latest=false checks, ensuring the complete beta publication contract is
covered.
---
Nitpick comments:
In `@internal/hubserver/fleet.go`:
- Around line 190-235: Extract the repeated url.PathUnescape and url.PathEscape
canonicalization logic into a canonicalPathSegment helper. Update the workspace,
CVE identifier, and image digest parsing in the route parser to use this helper
while preserving their existing validation and rejection behavior.
🪄 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: 7df15ba0-9e99-446d-b0b9-4c364b011141
📒 Files selected for processing (36)
.github/workflows/release.ymlMakefileREADME.mddocs/RELEASE.mddocs/ROADMAP.mdhack/experiments/m0-ocm-falsification.shhack/release-tag-classify.shinternal/fleet/coverage_test.gointernal/fleet/cve.gointernal/fleet/cve_test.gointernal/fleet/model.gointernal/hubdb/fleet.gointernal/hubdb/fleet_query_test.gointernal/hubdb/migrations/0007_fleet_cve_images.sqlinternal/hubdb/migrations/0008_fleet_cve_identifiers.sqlinternal/hubdb/postgres_integration_test.gointernal/hubfleet/collector.gointernal/hubfleet/collector_test.gointernal/hubfleet/cve_search.gointernal/hubfleet/cve_search_test.gointernal/hubocm/direct.gointernal/hubocm/direct_test.gointernal/hubocm/ocm_integration_test.gointernal/hubruntime/config.gointernal/hubruntime/ocm_integration_test.gointernal/hubserver/fleet.gointernal/hubserver/fleet_test.gointernal/pep/pep.gosessions/2026-07-14-e2-coverage-assessment.mdsessions/2026-07-14-e2-exact-cve-search.mdsessions/2026-07-14-e2-vulnerability-report-facts.mdsessions/2026-07-14-e9-beta-prerelease.mdsessions/2026-07-14-release-tag-identity.mdtests/e2e/kind_read_federation_test.gotests/scripts/release_tag_identity_guide_test.shtests/scripts/release_tag_policy_test.sh
| ```bash | ||
| tagger_email="$(git config user.email)" | ||
| test -n "$tagger_email" | ||
| test "$(git config gpg.format)" = ssh | ||
| signing_key_file="$(git config user.signingkey)" | ||
| test -f "$signing_key_file" | ||
| signing_key="$(awk '{print $1 " " $2}' "$signing_key_file")" | ||
| verified_emails="$(gh api user/emails --paginate \ | ||
| --jq '.[] | select(.verified) | .email')" | ||
| grep -Fxq -- "$tagger_email" <<<"$verified_emails" | ||
| github_login="$(gh api user --jq '.login')" | ||
| registered_signing_keys="$(gh api "users/${github_login}/ssh_signing_keys" \ | ||
| --paginate --jq '.[].key' | awk '{print $1 " " $2}')" | ||
| grep -Fxq -- "$signing_key" <<<"$registered_signing_keys" |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
# Inspect the relevant section of docs/RELEASE.md with line numbers.
wc -l docs/RELEASE.md
sed -n '110,155p' docs/RELEASE.md | cat -nRepository: ArdurAI/sith
Length of output: 3559
🏁 Script executed:
#!/bin/bash
set -e
# Read the immediate surrounding context to see whether the block is wrapped
# in error handling or only shown as a standalone preflight.
sed -n '120,150p' docs/RELEASE.mdRepository: ArdurAI/sith
Length of output: 2213
Make this snippet fail closed. Add set -euo pipefail or explicit || exit 1 checks so a failed test/grep cannot fall through and report success on invalid local identity config.
🤖 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 `@docs/RELEASE.md` around lines 127 - 140, Make the shell snippet fail closed
by enabling strict error handling with set -euo pipefail near the start, or
explicitly exiting on failure for every test and grep command. Ensure failures
in identity validation, email lookup, and signing-key verification stop
execution rather than allowing the snippet to report success.
| if query.Selector.Image != "" { | ||
| conditions = append(conditions, "fact.payload->'image_digests' ? "+placeholder(query.Selector.Image)) | ||
| switch query.Kinds[0] { | ||
| case fleet.FactInventory: | ||
| conditions = append(conditions, "fact.payload->'image_digests' ? "+placeholder(query.Selector.Image)) | ||
| case fleet.FactCVE: | ||
| conditions = append(conditions, "fact.payload->>'image' = "+placeholder(query.Selector.Image)) | ||
| } | ||
| } | ||
| if query.Selector.CVE != "" { | ||
| conditions = append(conditions, "(fact.payload -> 'ids') ? "+placeholder(query.Selector.CVE)) | ||
| } |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Add a default case to the Image-selector switch to fail closed.
queryFacts relies entirely on normalizeFleetQuery having already restricted query.Kinds[0] to FactInventory/FactCVE whenever Selector.Image != "". If that invariant is ever broken by a future change, this switch silently omits the image filter instead of failing, letting the query return facts scoped only by kind/workspace — broader than the "exact selector" contract these endpoints (image/CVE search) are supposed to enforce.
🛡️ Proposed fix: fail closed on unexpected kinds
if query.Selector.Image != "" {
switch query.Kinds[0] {
case fleet.FactInventory:
conditions = append(conditions, "fact.payload->'image_digests' ? "+placeholder(query.Selector.Image))
case fleet.FactCVE:
conditions = append(conditions, "fact.payload->>'image' = "+placeholder(query.Selector.Image))
+ default:
+ return nil, fmt.Errorf("image selector is not supported for fact kind %q", query.Kinds[0])
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if query.Selector.Image != "" { | |
| conditions = append(conditions, "fact.payload->'image_digests' ? "+placeholder(query.Selector.Image)) | |
| switch query.Kinds[0] { | |
| case fleet.FactInventory: | |
| conditions = append(conditions, "fact.payload->'image_digests' ? "+placeholder(query.Selector.Image)) | |
| case fleet.FactCVE: | |
| conditions = append(conditions, "fact.payload->>'image' = "+placeholder(query.Selector.Image)) | |
| } | |
| } | |
| if query.Selector.CVE != "" { | |
| conditions = append(conditions, "(fact.payload -> 'ids') ? "+placeholder(query.Selector.CVE)) | |
| } | |
| if query.Selector.Image != "" { | |
| switch query.Kinds[0] { | |
| case fleet.FactInventory: | |
| conditions = append(conditions, "fact.payload->'image_digests' ? "+placeholder(query.Selector.Image)) | |
| case fleet.FactCVE: | |
| conditions = append(conditions, "fact.payload->>'image' = "+placeholder(query.Selector.Image)) | |
| default: | |
| return nil, fmt.Errorf("image selector is not supported for fact kind %q", query.Kinds[0]) | |
| } | |
| } | |
| if query.Selector.CVE != "" { | |
| conditions = append(conditions, "(fact.payload -> 'ids') ? "+placeholder(query.Selector.CVE)) | |
| } |
🤖 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 `@internal/hubdb/fleet.go` around lines 335 - 345, Add a default branch to the
Image-selector switch in queryFacts that fails closed when query.Kinds[0] is not
fleet.FactInventory or fleet.FactCVE. Ensure unexpected kinds cannot omit the
image condition and broaden the query; use the existing error/validation
mechanism for reporting the invalid selector kind.
| func collectCVEFacts( | ||
| ctx context.Context, | ||
| client snapshotClient, | ||
| spokeID string, | ||
| knownDigests map[string]struct{}, | ||
| observedAt time.Time, | ||
| ) ([]fleet.Evidence, error) { | ||
| if len(knownDigests) == 0 { | ||
| return nil, nil | ||
| } | ||
| remaining := maxVulnerabilityReports | ||
| continueToken := "" | ||
| aggregates := make(map[string]cveAggregate) | ||
| for pages := 0; ; pages++ { | ||
| if pages >= maxVulnerabilityReportPages { | ||
| return nil, fmt.Errorf("direct OCM snapshot exceeds the bounded vulnerability report page limit") | ||
| } | ||
| page, err := client.ListVulnerabilityReports(ctx, vulnerabilityReportListOptions(continueToken, remaining)) | ||
| if apierrors.IsNotFound(err) && continueToken == "" { | ||
| return []fleet.Evidence{}, nil | ||
| } | ||
| if err != nil { | ||
| return nil, contextOrGeneric(ctx, "list vulnerability reports") | ||
| } | ||
| if len(page.Items) > remaining || (len(page.Items) == remaining && page.GetContinue() != "") { | ||
| return nil, fmt.Errorf("direct OCM snapshot exceeds the bounded vulnerability report limit") | ||
| } | ||
| for index := range page.Items { | ||
| digest, identifiers, severity, found := reportCVEObservation(page.Items[index], knownDigests) | ||
| if !found { | ||
| continue | ||
| } | ||
| aggregate := aggregates[digest] | ||
| if aggregate.identifiers == nil { | ||
| aggregate.identifiers = make(map[string]struct{}, len(identifiers)) | ||
| } | ||
| for _, identifier := range identifiers { | ||
| aggregate.identifiers[identifier] = struct{}{} | ||
| } | ||
| if cveSeverityRank(severity) > cveSeverityRank(aggregate.severity) { | ||
| aggregate.severity = severity | ||
| } | ||
| aggregates[digest] = aggregate | ||
| } | ||
| remaining -= len(page.Items) | ||
| continueToken = page.GetContinue() | ||
| if continueToken == "" { | ||
| break | ||
| } | ||
| } | ||
| digests := make([]string, 0, len(aggregates)) | ||
| for digest := range aggregates { | ||
| digests = append(digests, digest) | ||
| } | ||
| sort.Strings(digests) | ||
| facts := make([]fleet.Evidence, 0, len(digests)) | ||
| for _, digest := range digests { | ||
| aggregate := aggregates[digest] | ||
| identifiers := make([]string, 0, len(aggregate.identifiers)) | ||
| for identifier := range aggregate.identifiers { | ||
| identifiers = append(identifiers, identifier) | ||
| } | ||
| observation, err := fleet.CanonicalCVEObservation(digest, identifiers, aggregate.severity) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("normalize vulnerability report observation: %w", err) | ||
| } | ||
| payload, err := json.Marshal(observation) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("encode normalized vulnerability report observation: %w", err) | ||
| } | ||
| facts = append(facts, fleet.Evidence{ | ||
| Ref: fleet.ResourceRef{SourceKind: hubfleet.SourceKind, Scope: spokeID, Kind: "Image", Name: digest}, | ||
| Kind: fleet.FactCVE, | ||
| Observed: payload, | ||
| ObservedAt: observedAt, | ||
| Source: spokeID, | ||
| Provenance: fleet.Provenance{Adapter: hubfleet.SourceKind, ProtocolV: protocolVersion}, | ||
| }) | ||
| } | ||
| return facts, nil | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: check maxCVEIdentifiers bound and how likely it is to be exceeded by aggregation.
rg -n 'maxCVEIdentifiers' internal/fleet/cve.goRepository: ArdurAI/sith
Length of output: 549
Skip one bad CVE digest instead of failing the whole snapshot
collectCVEFacts returns an error when fleet.CanonicalCVEObservation rejects an aggregated digest (for example, if the merged ID set exceeds maxCVEIdentifiers), which aborts the entire spoke snapshot and drops already-collected non-CVE facts. Consider skipping just that digest’s CVE evidence and continuing with the rest.
🤖 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 `@internal/hubocm/direct.go` around lines 482 - 562, Update collectCVEFacts so
a fleet.CanonicalCVEObservation error for one aggregated digest is skipped
rather than returned, allowing processing to continue for remaining digests and
preserving non-CVE facts. Keep JSON marshaling errors and successful evidence
generation behavior unchanged.
| grep -Fq 'hack/release-tag-classify.sh "$GITHUB_REF_NAME"' "${workflow}" | ||
| printf '[release-tag-policy] PASS: workflow invokes the tested classifier\n' | ||
| grep -Fq -- '-f make_latest=false' "${workflow}" | ||
| printf '[release-tag-policy] PASS: beta publication cannot replace latest stable\n' |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Assert the complete beta publication contract.
This test would still pass if RELEASE_KIND stopped being exported or consumed, or if prerelease=true were removed. That could publish a beta as a normal release. Add assertions for the environment export, beta branch, and prerelease field.
Proposed test assertions
grep -Fq 'hack/release-tag-classify.sh "$GITHUB_REF_NAME"' "${workflow}"
printf '[release-tag-policy] PASS: workflow invokes the tested classifier\n'
+grep -Fq 'echo "RELEASE_KIND=${release_kind}" >> "$GITHUB_ENV"' "${workflow}"
+grep -Fq 'if [[ "$RELEASE_KIND" == "beta" ]]' "${workflow}"
grep -Fq -- '-f make_latest=false' "${workflow}"
printf '[release-tag-policy] PASS: beta publication cannot replace latest stable\n'
+grep -Fq -- '-F prerelease=true' "${workflow}"
+printf '[release-tag-policy] PASS: beta publication remains a prerelease\n'📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| grep -Fq 'hack/release-tag-classify.sh "$GITHUB_REF_NAME"' "${workflow}" | |
| printf '[release-tag-policy] PASS: workflow invokes the tested classifier\n' | |
| grep -Fq -- '-f make_latest=false' "${workflow}" | |
| printf '[release-tag-policy] PASS: beta publication cannot replace latest stable\n' | |
| grep -Fq 'hack/release-tag-classify.sh "$GITHUB_REF_NAME"' "${workflow}" | |
| printf '[release-tag-policy] PASS: workflow invokes the tested classifier\n' | |
| grep -Fq 'echo "RELEASE_KIND=${release_kind}" >> "$GITHUB_ENV"' "${workflow}" | |
| grep -Fq 'if [[ "$RELEASE_KIND" == "beta" ]]' "${workflow}" | |
| grep -Fq -- '-f make_latest=false' "${workflow}" | |
| printf '[release-tag-policy] PASS: beta publication cannot replace latest stable\n' | |
| grep -Fq -- '-F prerelease=true' "${workflow}" | |
| printf '[release-tag-policy] PASS: beta publication remains a prerelease\n' |
🧰 Tools
🪛 Shellcheck (0.11.0)
[info] 51-51: Expressions don't expand in single quotes, use double quotes for that.
(SC2016)
🤖 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/scripts/release_tag_policy_test.sh` around lines 51 - 54, Strengthen
the release workflow assertions around the tested classifier so
tests/scripts/release_tag_policy_test.sh verifies that RELEASE_KIND is exported
and consumed, the beta branch is selected, and prerelease=true is set. Keep the
existing classifier invocation and make_latest=false checks, ensuring the
complete beta publication contract is covered.
…gate ci(e9): gate dev-to-main release PRs
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
.github/workflows/ci.yml (1)
5-7: 🎯 Functional Correctness | 🔵 TrivialVerify that CI checks are required by branch protection.
These triggers schedule CI for
devandmain, but do not themselves prevent a release PR from merging with failed or missing checks. Confirm that themainruleset/branch protection requires the complete CI workflow before merge and release promotion.🤖 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 @.github/workflows/ci.yml around lines 5 - 7, Verify the branch protection or ruleset configuration for main and require the complete CI workflow checks before merging or promoting releases. Keep the existing workflow triggers for dev and main unchanged, and update the repository protection settings rather than relying on the pull_request configuration alone.
🤖 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 `@sessions/2026-07-14-e9-release-pr-ci-gate.md`:
- Around line 46-47: Remove the leading “#” from the sentence beginning “#157”
in the release documentation so it remains a paragraph and no longer parses as a
malformed ATX heading. Preserve the issue reference and the existing sentence
content.
In `@tests/scripts/release_pr_gate_policy_test.sh`:
- Around line 13-14: Update the branch checks in the release policy test so they
match only active YAML branches keys under the relevant push and pull_request
sections, not commented or unrelated text. Anchor each regex to the YAML key and
preserve the existing dev/main branch validation.
---
Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 5-7: Verify the branch protection or ruleset configuration for
main and require the complete CI workflow checks before merging or promoting
releases. Keep the existing workflow triggers for dev and main unchanged, and
update the repository protection settings rather than relying on the
pull_request configuration alone.
🪄 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: 7c2651d2-cbbe-4d80-8ce7-318dc1746ae9
📒 Files selected for processing (5)
.github/workflows/ci.ymlMakefiledocs/RELEASE.mdsessions/2026-07-14-e9-release-pr-ci-gate.mdtests/scripts/release_pr_gate_policy_test.sh
🚧 Files skipped from review as they are similar to previous changes (2)
- Makefile
- docs/RELEASE.md
| #157 closes only after the resulting `dev` to `main` release PR has an independently green full CI | ||
| run and a later exact `main` push CI record is available for the beta release commit. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Fix the malformed Markdown issue reference.
#157 is not a valid ATX heading prefix and triggers MD018. Keep this as a paragraph, for example:
-#157 closes only after the resulting `dev` to `main` release PR has an independently green full CI
+Issue `#157` closes only after the resulting `dev` to `main` release PR has an independently green full CI📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #157 closes only after the resulting `dev` to `main` release PR has an independently green full CI | |
| run and a later exact `main` push CI record is available for the beta release commit. | |
| Issue `#157` closes only after the resulting `dev` to `main` release PR has an independently green full CI | |
| run and a later exact `main` push CI record is available for the beta release commit. |
🧰 Tools
🪛 markdownlint-cli2 (0.23.0)
[warning] 46-46: No space after hash on atx style heading
(MD018, no-missing-space-atx)
🤖 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 `@sessions/2026-07-14-e9-release-pr-ci-gate.md` around lines 46 - 47, Remove
the leading “#” from the sentence beginning “#157” in the release documentation
so it remains a paragraph and no longer parses as a malformed ATX heading.
Preserve the issue reference and the existing sentence content.
Source: Linters/SAST tools
| section == "push" && /branches: \[dev, main\]/ { push_ok = 1 } | ||
| section == "pull_request" && /branches: \[dev, main\]/ { pull_request_ok = 1 } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Anchor the branch assertions to active YAML keys.
The current regex also matches commented-out or unrelated text, so a removed trigger could still pass if branches: [dev, main] remains in a comment. Anchor the match to the YAML key, or use a YAML parser.
🔧 Proposed fix
- section == "push" && /branches: \[dev, main\]/ { push_ok = 1 }
- section == "pull_request" && /branches: \[dev, main\]/ { pull_request_ok = 1 }
+ section == "push" && /^[[:space:]]+branches:[[:space:]]*\[[[:space:]]*dev,[[:space:]]*main[[:space:]]*\][[:space:]]*$/ { push_ok = 1 }
+ section == "pull_request" && /^[[:space:]]+branches:[[:space:]]*\[[[:space:]]*dev,[[:space:]]*main[[:space:]]*\][[:space:]]*$/ { pull_request_ok = 1 }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| section == "push" && /branches: \[dev, main\]/ { push_ok = 1 } | |
| section == "pull_request" && /branches: \[dev, main\]/ { pull_request_ok = 1 } | |
| section == "push" && /^[[:space:]]+branches:[[:space:]]*\[[[:space:]]*dev,[[:space:]]*main[[:space:]]*\][[:space:]]*$/ { push_ok = 1 } | |
| section == "pull_request" && /^[[:space:]]+branches:[[:space:]]*\[[[:space:]]*dev,[[:space:]]*main[[:space:]]*\][[:space:]]*$/ { pull_request_ok = 1 } |
🤖 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/scripts/release_pr_gate_policy_test.sh` around lines 13 - 14, Update
the branch checks in the release policy test so they match only active YAML
branches keys under the relevant push and pull_request sections, not commented
or unrelated text. Anchor each regex to the YAML key and preserve the existing
dev/main branch validation.
Beta release boundary
Promotes the current tested integration branch to
mainfor the signedv0.3.0-beta.1prerelease.darwin_arm64is built with the same checksum, SPDX SBOM, Sigstore bundle, and attestation chain as the other platformsvMAJOR.MINOR.PATCH-beta.N; it remains a GitHub prerelease and cannot replace the latest stable releasedev, Homebrew beta channel, or registry publication is includedIntegration evidence
devCI on42d3951:29364444017passeddevCodeQL on42d3951:29364462265passedAfter this PR merges, the tagger will run
make ciandmake release-checkonmain, verify SSH tagger identity, push an annotated signedv0.3.0-beta.1tag, and verify the published macOS-arm64 artifact locally.Summary by CodeRabbit
devandmainfor pushes and PRs.