Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions .agentic-ci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# agentic-ci configuration for autofix runs on this repository.
#
# `sandbox:` is a repo overlay for the agentic-ci sandbox profile (see
# https://github.com/opendatahub-io/agentic-ci, docs/sandbox-profiles.md).
# autofix reads it from the base branch before the agent runs. An overlay
# may set toolchains, setup, validate, skips and env, and open only the
# goproxy, npm and pypi egress presets; anything wider is configured
# centrally in autofix.
#
# Toolchains come from the agentic-ci catalog at the versions pinned in
# mise.toml (python reads .python-version). If an upstream sync bumps a
# version in mise.toml, bump it here too: mise does not install it, so
# the validate steps fail until the pins match. Setup installs mise from
# npm, links the catalog toolchains into mise so it never downloads
# them, and installs the mise npm/go tools through the presets. Rust and
# container, cluster and VM tasks cannot run in the sandbox and are
# declared as skips.

sandbox:
toolchains:
python: auto # reads .python-version
node: "24.15.0"
go: "1.26.7"
buf: "1.72.0"
helm: "4.2.0"

egress:
- goproxy
- npm
- pypi

env:
MISE_YES: "1"
MISE_AUTO_INSTALL: "false"
MISE_DISABLE_TOOLS: "rust,kubectl,uv,protoc,helm-docs,yq,skaffold,k3d,zig,github:anchore/syft,github:EmbarkStudios/cargo-about,github:EmbarkStudios/cargo-deny,github:rust-secure-code/cargo-auditable,github:nextest-rs/nextest,github:rust-cross/cargo-zigbuild,github:mozilla/sccache"

setup:
- name: mise
timeout: 900
run: |
set -euo pipefail
case "$(uname -m)" in
x86_64) arch=x64 ;;
aarch64) arch=arm64 ;;
*) echo "unsupported machine: $(uname -m)" >&2; exit 1 ;;
esac
# Keep in sync with min_version in mise.toml.
npm install --prefix "$HOME/.local/share/mise-npm" --no-audit --no-fund \
"@jdxcode/mise-linux-${arch}@2026.9.9"
mkdir -p "$HOME/.local/bin"
ln -sf "$HOME/.local/share/mise-npm/node_modules/@jdxcode/mise-linux-${arch}/bin/mise" \
"$HOME/.local/bin/mise"
export PATH="$HOME/.local/bin:$PATH"
mise trust
# Link the catalog toolchains into mise under the versions they
# report, so the versions are pinned only in `toolchains` above.
root() { dirname "$(dirname "$(command -v "$1")")"; }
mise link "go@$(go env GOVERSION | sed 's/^go//')" "$(root go)"
mise link "node@$(node --version | sed 's/^v//')" "$(root node)"
mise link "python@$(python3 -c 'import platform; print(platform.python_version())')" \
"$(root python3)"
mise link "buf@$(buf --version)" "$(root buf)"
mise link "helm@$(helm version --template '{{.Version}}' | sed 's/^v//')" \
"$(dirname "$(command -v helm)")"
mise install \
npm:markdownlint-cli2 \
go:github.com/golangci/golangci-lint/v2/cmd/golangci-lint \
go:google.golang.org/protobuf/cmd/protoc-gen-go \
go:google.golang.org/grpc/cmd/protoc-gen-go-grpc \
go:golang.org/x/tools/cmd/goimports

validate:
- {name: python-lint, kind: lint, run: mise run python:lint, timeout: 600}
- {name: python-format, kind: lint, run: mise run python:format:check, timeout: 600}
- {name: markdown-lint, kind: lint, run: mise run markdown:lint:md, timeout: 600}
- {name: proto-lint, kind: lint, run: mise run proto:lint, timeout: 600}
- {name: helm-lint, kind: lint, run: mise run helm:lint, timeout: 600}
- {name: go-format, kind: lint, run: mise run go:format:check, timeout: 600}
- {name: go-lint, kind: lint, run: mise run go:lint, timeout: 900}

skips:
- match: "rust:*, cargo, clippy, nextest, cargo-deny"
reason: "No Rust toolchain or C compiler in the sandbox, so Rust builds, tests, lints and dependency checks rely on CI"
- match: "docker:*, gateway:*, sandbox:*, vm:*, package:*"
reason: "Image, VM and package builds need a container runtime or privileged features the sandbox blocks"
- match: "e2e:*, test:*, helm:test"
reason: "End-to-end and cluster tests need a container runtime, a running gateway or a live cluster"
- match: "license:check"
reason: "Fails on main today: midstream files such as .tekton/*.yaml have no SPDX header"
1 change: 1 addition & 0 deletions .agents/skills/helm-dev-environment/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ for dependencies still declared in `Chart.yaml`.
| `deploy/helm/openshell/ci/values-cert-manager.yaml` | cert-manager PKI overlay (opt-in; disables pkiInitJob) |
| `deploy/helm/openshell/ci/values-gateway.yaml` | Envoy Gateway GRPCRoute + Gateway overlay |
| `deploy/helm/openshell/ci/values-high-availability.yaml` | HA test overlay (`replicaCount: 2` with external PostgreSQL Secret) |
| `deploy/helm/openshell/ci/values-autoscaling.yaml` | Render-only overlay for the optional gateway HorizontalPodAutoscaler (helm lint and helm-unittest) |
| `deploy/helm/openshell/ci/values-keycloak.yaml` | Keycloak OIDC overlay |
| `deploy/helm/openshell/ci/values-spire.yaml` | SPIFFE/SPIRE provider token grant overlay |
| `deploy/helm/openshell/ci/values-spire-stack.yaml` | SPIRE hardened chart values for local dev |
Expand Down
9 changes: 6 additions & 3 deletions .agents/skills/watch-github-actions/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,12 @@ During `0.x`, a minor train permits compatibility findings
as warnings; a patch train or no active train rejects them. Compare the current
train's version with the latest stable release; commit messages are irrelevant.
Compilation, baseline, and tool errors remain fatal. The `protobuf_compatibility` suite participates in
the `release-tag-v1` qualification profile. Failed qualification prevents stable
publication but still allows pre-release artifacts to publish with the failure
recorded.
the `release-tag-v1` qualification profile. Both tagged pre-release and stable
publication require this profile to pass. Failed, cancelled, or skipped suites
block publication; build artifacts and qualification evidence remain in Actions
storage for diagnosis. Source-SHA images are staging inputs for qualification.
Snap builds run in parallel with qualification, but tagged stable Store uploads
consume those built artifacts only after qualification passes.

View logs for a specific run:

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/branch-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -305,9 +305,9 @@ jobs:
integration-inputs-artifact-id: ${{ needs.prepare-integration.outputs.integration_inputs_artifact_id }}
test-matrix: >-
[
{"environment":"fedora-podman-rootful","installer":"binaries","testsuite":"driver-podman"},
{"environment":"fedora-podman-rootless","installer":"binaries","testsuite":"e2e-podman"},
{"environment":"fedora-podman-rootless","installer":"binaries","testsuite":"driver-podman"}
{"environment":"fedora-podman-rootful","installer":"rpm","testsuite":"driver-podman"},
{"environment":"fedora-podman-rootless","installer":"rpm","testsuite":"e2e-podman"},
{"environment":"fedora-podman-rootless","installer":"rpm","testsuite":"driver-podman"}
]

docker-e2e:
Expand Down
16 changes: 11 additions & 5 deletions .github/workflows/release-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,6 @@ jobs:
uses: ./.github/workflows/snap-package.yml
with:
checkout-ref: ${{ github.sha }}
upload-channel: latest/edge
github-environment: latest/edge
secrets:
publish-credentials: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}

build-rpm:
name: Build RPM Packages
Expand All @@ -264,6 +260,16 @@ jobs:
rpm-release: ${{ needs.compute-versions.outputs.rpm_release }}
cargo-version: ${{ needs.compute-versions.outputs.cargo_version }}

publish-snap:
name: Publish Snap
needs: build-snap
uses: ./.github/workflows/snap-publish.yml
with:
upload-channel: latest/edge
github-environment: latest/edge
secrets:
publish-credentials: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}

# ---------------------------------------------------------------------------
# Create / update the dev GitHub Release with CLI, gateway, driver, and wheels
# ---------------------------------------------------------------------------
Expand All @@ -279,7 +285,7 @@ jobs:
- vm-e2e
- build-deb
- build-rpm
- build-snap
- publish-snap
runs-on: linux-amd64-cpu8
timeout-minutes: 10
permissions:
Expand Down
58 changes: 48 additions & 10 deletions .github/workflows/release-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -311,10 +311,10 @@ jobs:
retention-days: 90
if-no-files-found: error

- name: Require current qualification profile for stable releases
if: needs.compute-versions.outputs.is_prerelease != 'true' && steps.summary.outputs.current-profile-passed != 'true'
- name: Require current qualification profile before publication
if: steps.summary.outputs.current-profile-passed != 'true'
run: |
echo "Stable release ${RELEASE_TAG} did not pass the current release-tag-v1 qualification profile." >&2
echo "Release ${RELEASE_TAG} did not pass the current release-tag-v1 qualification profile." >&2
exit 1

build-python-wheel:
Expand Down Expand Up @@ -370,11 +370,6 @@ jobs:
uses: ./.github/workflows/snap-package.yml
with:
checkout-ref: ${{ needs.compute-versions.outputs.source_sha }}
upload-channel: ${{ needs.compute-versions.outputs.is_prerelease == 'true' && 'latest/edge' || 'latest/stable' }}
github-environment: ${{ needs.compute-versions.outputs.is_prerelease == 'true' && 'latest/edge' || 'latest/stable' }}
publish: ${{ needs.compute-versions.outputs.is_prerelease != 'true' }}
secrets:
publish-credentials: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}

build-rpm:
name: Build RPM Packages
Expand All @@ -386,11 +381,23 @@ jobs:
rpm-release: ${{ needs.compute-versions.outputs.rpm_release }}
cargo-version: ${{ needs.compute-versions.outputs.cargo_version }}

publish-snap:
name: Publish Snap
needs: [compute-versions, release, qualification-result]
if: needs.compute-versions.outputs.is_prerelease != 'true' && needs.qualification-result.outputs.current-profile-passed == 'true'
uses: ./.github/workflows/snap-publish.yml
with:
upload-channel: latest/stable
github-environment: latest/stable
secrets:
publish-credentials: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}

# ---------------------------------------------------------------------------
# Assemble release artifacts. Stable publication remains qualification-gated.
# Assemble release artifacts after the current qualification profile passes.
# ---------------------------------------------------------------------------
release:
name: Release
if: needs.qualification-result.outputs.current-profile-passed == 'true'
needs:
- compute-versions
- package-binaries
Expand Down Expand Up @@ -740,9 +747,10 @@ jobs:
publish-qualification:
name: Publish Qualification Summary (OCI)
if: >-
always()
!cancelled()
&& needs.release.result == 'success'
&& needs.qualification-result.result == 'success'
&& needs.qualification-result.outputs.current-profile-passed == 'true'
needs: [compute-versions, qualification-result, release]
runs-on: ubuntu-latest
timeout-minutes: 5
Expand Down Expand Up @@ -777,6 +785,36 @@ jobs:

echo "Published qualification summary to \`${ref}\`." >> "${GITHUB_STEP_SUMMARY}"

notify-prerelease-failure:
name: Notify Prerelease Failure
needs: [release-helm, publish-qualification]
if: failure() && contains(inputs.tag || github.ref_name, '-pre.')
runs-on: ubuntu-latest
timeout-minutes: 2
permissions: {}
steps:
- name: Send Slack notification
continue-on-error: true
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_OPENSHELL_TRIAGE_WEBHOOK_URL }}
SLACK_MENTION: ${{ secrets.SLACK_OPENSHELL_TRIAGE_MENTION }}
RUN_URL: ${{ format('{0}/{1}/actions/runs/{2}/attempts/{3}', github.server_url, github.repository, github.run_id, github.run_attempt) }}
run: |
set -euo pipefail
if [[ -z "${SLACK_WEBHOOK_URL}" ]]; then
echo "::notice::SLACK_OPENSHELL_TRIAGE_WEBHOOK_URL is unset; skipping Slack notification."
exit 0
fi

message=":x: OpenShell prerelease ${RELEASE_TAG} failed (attempt ${GITHUB_RUN_ATTEMPT})."
if [[ -n "${SLACK_MENTION}" ]]; then
message+=" ${SLACK_MENTION}"
fi
jq -n --arg text "${message}" --arg run_url "${RUN_URL}" \
'{text: ($text + "\n<" + $run_url + "|View failed release run>"), unfurl_links: false, unfurl_media: false}' |
curl --fail --silent --show-error --connect-timeout 5 --max-time 15 \
--header 'Content-Type: application/json' --data-binary @- "${SLACK_WEBHOOK_URL}"

publish-fern-docs:
name: Sync and Publish Fern Docs
needs: [compute-versions, release, publish-sdk-typescript, release-helm, trigger-wheel-publish]
Expand Down
40 changes: 0 additions & 40 deletions .github/workflows/snap-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,6 @@ on:
checkout-ref:
required: true
type: string
upload-channel:
required: true
type: string
description: "Snap Store channel to upload to (e.g., latest/edge, latest/candidate, latest/stable)"
github-environment:
required: true
type: string
description: "GitHub deployment environment for approval gates (e.g., latest/edge, latest/stable)"
publish:
required: false
type: boolean
default: true
description: "Whether to upload the built snap to the Snap Store"

secrets:
publish-credentials:
required: true
description: "Snap Store credentials (SNAPCRAFT_STORE_CREDENTIALS)"

permissions:
contents: read
Expand All @@ -49,7 +31,6 @@ jobs:
runner: linux-arm64-cpu8
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
environment: ${{ inputs.github-environment }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand Down Expand Up @@ -172,24 +153,3 @@ jobs:
${{ steps.capture.outputs.snap-file }}
*.comp
retention-days: 5

- name: Upload snap to Snap Store
if: inputs.publish
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.publish-credentials }}
INPUTS_UPLOAD_CHANNEL: ${{ inputs.upload-channel }}
run: |
set -euo pipefail
SNAP_FILE="${{ steps.capture.outputs.snap-file }}"
SNAP_NAME="${SNAP_FILE%.snap}"
SNAP_NAME="${SNAP_NAME%%_*}"

COMPONENT_ARGS=()
shopt -s nullglob
for comp in "${SNAP_NAME}"+*.comp; do
echo "Adding component: $comp"
COMPONENT_ARGS+=(--component "$comp")
done

echo "Uploading $SNAP_FILE to ${INPUTS_UPLOAD_CHANNEL}"
snapcraft upload --release "${INPUTS_UPLOAD_CHANNEL}" "$SNAP_FILE" "${COMPONENT_ARGS[@]}"
74 changes: 74 additions & 0 deletions .github/workflows/snap-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

name: Publish Snap

on:
workflow_call:
inputs:
upload-channel:
required: true
type: string
github-environment:
required: true
type: string
secrets:
publish-credentials:
required: true

permissions:
contents: read

defaults:
run:
shell: bash

jobs:
publish:
name: Publish Snap (Linux ${{ matrix.arch }})
strategy:
matrix:
include:
- arch: amd64
runner: linux-amd64-cpu8
- arch: arm64
runner: linux-arm64-cpu8
runs-on: ${{ matrix.runner }}
timeout-minutes: 10
environment: ${{ inputs.github-environment }}
steps:
- name: Download built snap and components
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: snap-linux-${{ matrix.arch }}

- name: Install snapcraft
run: |
set -euo pipefail
sudo apt-get update
sudo apt-get install -y snapd
sudo systemctl enable --now snapd.socket
sudo systemctl start snapd
sudo snap wait system seed.loaded
sudo snap install snapcraft --classic

- name: Upload snap to Snap Store
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.publish-credentials }}
INPUTS_UPLOAD_CHANNEL: ${{ inputs.upload-channel }}
run: |
set -euo pipefail
shopt -s nullglob
snaps=(*.snap)
if [[ "${#snaps[@]}" -ne 1 ]]; then
echo "Expected exactly one built snap, found ${#snaps[@]}" >&2
exit 1
fi
snap_file="${snaps[0]}"
snap_name="${snap_file%.snap}"
snap_name="${snap_name%%_*}"
component_args=()
for comp in "${snap_name}"+*.comp; do
component_args+=(--component "$comp")
done
snapcraft upload --release "${INPUTS_UPLOAD_CHANNEL}" "$snap_file" "${component_args[@]}"
Loading
Loading