OSAC-3353: GHA workflow to build and validate base SNO snapshot - #34
OSAC-3353: GHA workflow to build and validate base SNO snapshot#34omer-vishlitzky wants to merge 4 commits into
Conversation
…snapshots Adds a GitHub Actions workflow (build-base-sno.yaml) that automates the full lifecycle of a base SNO snapshot: create from a running source cluster, validate by booting a clone and checking node/operator health, then push to the OCI registry. The workflow runs on self-hosted baremetal runners and accepts the OCP version and source clone ID as workflow_dispatch inputs. Validation (OSAC-3357) checks node readiness, ClusterOperator health, and runs cluster-tool verify for DNS and API connectivity. Depends on OSAC-3352 for the scripts/ directory (snapshot_base.py). Signed-off-by: Omer Vishlitzky <ovishlitzky@gmail.com> Assisted-by: Claude Code <noreply@anthropic.com> Signed-off-by: omer-vishlitzky <omer.vishlitzky@gmail.com>
|
Warning Review limit reached
Next review available in: 9 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Repository: osac-project/coderabbit/.coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
WalkthroughThe new workflow builds a base SNO snapshot from a source cluster, boots and validates a fresh cluster, verifies connectivity, destroys the validation cluster, and publishes the validated snapshot to a registry. ChangesBase SNO snapshot workflow
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant GitHubActions
participant SourceCluster
participant ValidationCluster
participant SnapshotRegistry
GitHubActions->>SourceCluster: build snapshot from SOURCE
GitHubActions->>ValidationCluster: boot snapshot and check node/operator health
GitHubActions->>ValidationCluster: verify connectivity and destroy cluster
GitHubActions->>SnapshotRegistry: publish validated snapshot
Caution Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional.
❌ Failed checks (2 errors)
✅ Passed checks (9 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 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/build-base-sno.yaml:
- Line 40: Add SAST and SCA dependency-scanning steps to the workflow before the
cluster operation steps, ensuring both run before the production snapshot build
or publish proceeds. Use the existing workflow conventions and security tooling
configuration where available.
- Around line 150-153: Remove the `|| true` suppression from the “Destroy
validation cluster” step so failures from `cluster-tool destroy validate` fail
the job. If needed, add only bounded retries while preserving the step’s
`always()` execution.
- Around line 23-25: Remove the no-op push trigger from the workflow’s on
configuration, specifically the push block matching the main branch and
scripts/** paths. Preserve the workflow_dispatch trigger and existing job
behavior.
- Around line 60-65: The pull secret is created only in build-snapshot and can
be unavailable to validate-snapshot on another runner, while cleanup may be
skipped on failure. Update the build-snapshot, validate-snapshot, and
publish-only job steps to create the secret within each job that consumes it,
remove the cross-job /tmp dependency, and add cleanup steps guarded with if:
always() so the secret is removed after success or failure.
- Line 35: Declare the custom baremetal runner label in the repository’s
actionlint configuration, preserving the existing self-hosted runner mapping
used by the runs-on entries in build-base-sno.yaml. Add only the necessary
runner-label configuration and keep the workflow unchanged.
- Around line 159-174: Update the publish-snapshot job and cluster-tool push
flow to expose the pushed manifest digest, then sign the immutable image
reference using cosign keyless signing as registry@digest. Grant id-token: write
only in this job’s permissions, while preserving existing read access and
leaving build/validate jobs unchanged; ensure the digest output from
cluster-tool push is consumed by the signing step.
- Around line 67-72: Update the “Create base snapshot” step to construct
KUBECONFIG inside its run script using the shell’s $HOME value and
inputs.source, instead of interpolating env.HOME in the workflow expression.
Preserve the existing kubeconfig path structure and SOURCE environment variable.
🪄 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: Repository: osac-project/coderabbit/.coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 8d43fe13-0fe6-4932-a257-0d154a69af25
📒 Files selected for processing (1)
.github/workflows/build-base-sno.yaml
|
|
||
| jobs: | ||
| build-snapshot: | ||
| runs-on: [self-hosted, baremetal] |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
fd -HI '^actionlint\.ya?ml$' . .github 2>/dev/null || true
rg -n -C2 'self-hosted-runner:|labels:|baremetal' .github actionlint.yaml 2>/dev/null || trueRepository: osac-project/cluster-tool
Length of output: 1531
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo "== workflow outline =="
sed -n '1,190p' .github/workflows/build-base-sno.yaml
echo "== actionlint config files =="
fd -HI 'actionlint\.ya?ml$|^actionlint$|\.actionlint$' . .github 2>/dev/null || true
echo "== actionlint references in repo =="
rg -n 'actionlint|self-hosted-runner|self-hosted runners|baremetal|github.com/rhysd/actionlint' .github . 2>/dev/null | head -200Repository: osac-project/cluster-tool
Length of output: 7755
Declare the custom baremetal runner label to actionlint.
baremetal is used as a self-hosted runner label in .github/workflows/build-base-sno.yaml at lines 35, 76, and 157, but the repository has no actionlint configuration. Add it to the repo’s actionlint config while preserving the intended self-hosted runner mapping.
🧰 Tools
🪛 actionlint (1.7.12)
[error] 35-35: label "baremetal" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2025-vs2026", "windows-2022", "windows-11-arm", "ubuntu-slim", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xlarge", "macos-latest-large", "macos-26-intel", "macos-26-xlarge", "macos-26-large", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xlarge", "macos-14-large", "macos-14", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file
(runner-label)
🤖 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/build-base-sno.yaml at line 35, Declare the custom
baremetal runner label in the repository’s actionlint configuration, preserving
the existing self-hosted runner mapping used by the runs-on entries in
build-base-sno.yaml. Add only the necessary runner-label configuration and keep
the workflow unchanged.
Source: Linters/SAST tools
| github.event_name == 'workflow_dispatch' | ||
| permissions: | ||
| contents: read | ||
| steps: |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Add SAST and SCA before operating the cluster.
This workflow has no SAST or dependency-scanning stage despite building and publishing a production snapshot. As per path instructions, SAST/SCA steps in pipeline.
🤖 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/build-base-sno.yaml at line 40, Add SAST and SCA
dependency-scanning steps to the workflow before the cluster operation steps,
ensuring both run before the production snapshot build or publish proceeds. Use
the existing workflow conventions and security tooling configuration where
available.
Source: Path instructions
| permissions: | ||
| contents: read | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Push snapshot to registry | ||
| run: | | ||
| ./cluster-tool push "$FLAVOR_NAME" \ | ||
| --registry "$REGISTRY" \ | ||
| --tag "$FLAVOR_NAME" | ||
| env: | ||
| FLAVOR_NAME: sno-${{ inputs.ocp_version }} | ||
| REGISTRY: ${{ vars.QUAY_REGISTRY || 'quay.io/osac-project/cluster-flavors' }} |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Tracked workflow files:"
git ls-files '.github/workflows/**/*' | sed -n '1,200p'
echo
echo "Target workflow outline/size:"
wc -l .github/workflows/build-base-sno.yaml
sed -n '1,230p' .github/workflows/build-base-sno.yaml
echo
echo "Cosign/sigstore references:"
rg -n --hidden --glob '!node_modules/**' --glob '!vendor/**' 'cosign|sigstore|oidc|permissions:|id-token|registry@digest|push snapshot|Push snapshot|cluster-tool push' .github . || trueRepository: osac-project/cluster-tool
Length of output: 7144
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Repository root files:"
git ls-files | rg '(^|/)(main|init|go|pyproject|README|Makefile|Dockerfile|cluster-tool|push|registry|oidc|cosign)' || true
echo
echo "Search push command implementation references:"
rg -n --hidden --glob '!node_modules/**' --glob '!vendor/**' --glob '!dist/**' --glob '!build/**' 'func .*push|class .*Push|def .*push|push|registry|oci|cosign|sigstore|oidc|digest|image|artifact' --glob '!*.md' | sed -n '1,240p'
echo
echo "Candidate source files:"
git ls-files | sed -n '1,240p'Repository: osac-project/cluster-tool
Length of output: 257
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "cluster-tool type and size:"
file cluster-tool
wc -c cluster-tool
head -c 8000 cluster-tool | sed -n '1,240p'
echo
echo "Read-only token usage and registry signature references in cluster-tool:"
python3 - <<'PY'
import pathlib, re
p=pathlib.Path('cluster-tool')
text=p.read_text(errors='replace')
pat=r'\b(permissions|id-token|cosign|sigstore|oidc|registry@digest|digest|push\s*$|cmd\.push|push_cmd|oci|image)\b|^\s*echo\s+".*digest|PRINT|print\('
for i,line in enumerate(text.splitlines(),1):
if re.search(pat,line):
print(f"{i}: {line}")
PY
echo
echo "Search cosign/sigstore usage in repo:"
rg -n --hidden --glob '!node_modules/**' --glob '!vendor/**' 'cosign|sigstore|oidc|registry@digest|sign \(|sign.*digest|cosign sign|cluster-tool sign' . || trueRepository: osac-project/cluster-tool
Length of output: 233
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "cluster-tool first lines and size:"
wc -c cluster-tool
sed -n '1,240p' cluster-tool
echo
echo "Push-related text in cluster-tool:"
rg -n --hidden --glob '!node_modules/**' --glob '!vendor/**' 'push\s*$|cmd(.*)push|function .*push|def .*push|subprocess\(|cosign|sigstore|oidc|id-token|token|digest|image|OCI|registry|quay|docker|podman|skopeo' cluster-tool README.md .claude || true
echo
echo "Repo-wide cosign/sigstore/identity token/digest/sign references:"
rg -n --hidden --glob '!node_modules/**' --glob '!vendor/**' 'cosign|sigstore|oidc|id-token|registry@digest|digest|sign \(|cosign sign|cosign sign-blob|cluster-tool sign|skopeo|podman sign' . || trueRepository: osac-project/cluster-tool
Length of output: 22093
Sign the published snapshot by immutable digest.
publish-snapshot only tags and pushes registry:tag; no Sigstore/cosign signing is performed. Have cluster-tool push expose the pushed manifest digest, then sign registry@digest with a keyless identity. Add id-token: write only to this job so GitHub’s OIDC signing flow can request the signing identity token while keeping signing out of the build/validate jobs.
🤖 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/build-base-sno.yaml around lines 159 - 174, Update the
publish-snapshot job and cluster-tool push flow to expose the pushed manifest
digest, then sign the immutable image reference using cosign keyless signing as
registry@digest. Grant id-token: write only in this job’s permissions, while
preserving existing read access and leaving build/validate jobs unchanged;
ensure the digest output from cluster-tool push is consumed by the signing step.
Source: Path instructions
Code Review FindingsCRITICAL — Snapshot is pushed to registry BEFORE validation runs
Fix: Either (a) add a MAJOR — Pull secret cross-job filesystem dependency
Fix: Write the pull secret in each job that needs it, or consolidate into a single job. MAJOR — Credential leak on validation failure
Fix: Add MAJOR — Dead push trigger
Fix: Remove the push trigger. This workflow is manual-only (requires a source clone ID input). MAJOR — Must use OSAC baremetal infrastructureThis workflow boots VMs via libvirt, runs cluster-tool commands, and interacts with live OpenShift clusters — all of this requires bare metal hardware. OSAC already has self-hosted GitHub Actions runners on baremetal machines, registered at the org level with the The workflow should:
MINOR —
|
Signed-off-by: omer-vishlitzky <omer.vishlitzky@gmail.com> Assisted-by: Claude Code <noreply@anthropic.com>
…dation, timeouts Signed-off-by: omer-vishlitzky <omer.vishlitzky@gmail.com> Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: omer-vishlitzky <omer.vishlitzky@gmail.com> Assisted-by: Claude Code <noreply@anthropic.com>
|
Superseded by #38 (unified snapshot pipeline PR) |
Summary
Adds a GitHub Actions workflow (
build-base-sno.yaml) that automates the full lifecycle of a base SNO snapshot:scripts/snapshot_base.pycluster-tool verifyWorkflow inputs
ocp_version4-22)sourcevirsh list)Prerequisites
scripts/directory withsnapshot_base.py(OSAC-3352)Secrets and variables
PULL_SECRETSERVERrdu07DATA_PATH/data/cluster-toolQUAY_REGISTRYquay.io/osac-project/cluster-flavorsDepends on OSAC-3352 for the
scripts/directory (snapshot_base.py).Test plan
actionlintor manual review)workflow_dispatchon a baremetal runner with a running source clusterSummary by CodeRabbit