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
62 changes: 1 addition & 61 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ name: Build
on:
push:
branches: [ main ]
tags: [ 'v*' ]
pull_request:
branches: [ main ]

Expand All @@ -12,10 +11,6 @@ env:
GHCR_REGISTRY: ghcr.io
GHCR_IMAGE_REPO: ${{ format('{0}/{1}', 'ghcr.io', github.repository) }}

# Quay configuration
QUAY_REGISTRY: quay.io
QUAY_IMAGE_REPO: quay.io/aipcc-cicd/claudio

jobs:
build-and-upload:
name: Build and Upload Images
Expand All @@ -34,11 +29,7 @@ jobs:

- name: Set image repo and tag based on event
run: |
if [[ "${{ github.ref_type }}" == "tag" ]]; then
# Tag events: build for Quay
echo "IMAGE_REPO=${{ env.QUAY_IMAGE_REPO }}" >> $GITHUB_ENV
echo "IMAGE_TAG=${{ github.ref_name }}" >> $GITHUB_ENV
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
# PRs: build for GHCR with pr-X tag
echo "IMAGE_REPO=${{ env.GHCR_IMAGE_REPO }}" >> $GITHUB_ENV
echo "IMAGE_TAG=pr-${{ github.event.number }}" >> $GITHUB_ENV
Expand Down Expand Up @@ -126,54 +117,3 @@ jobs:
make oci-manifest-build
make oci-manifest-push

push-quay:
name: Push to Quay (tag release)
if: startsWith(github.ref, 'refs/tags/v')
needs: build-and-upload
runs-on: ubuntu-24.04
permissions:
contents: read

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Download claudio images
uses: actions/download-artifact@v8
with:
pattern: claudio-*

- name: Log in to Quay Container Registry
uses: docker/login-action@v4
with:
registry: ${{ env.QUAY_REGISTRY }}
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_PASSWORD }}

- name: Load and push images to Quay
env:
IMAGE_REPO: ${{ env.QUAY_IMAGE_REPO }}
IMAGE_TAG: ${{ github.ref_name }}
run: |
make oci-load
make oci-push-arch
make oci-manifest-build
make oci-manifest-push

create-release:
name: Create GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
needs: push-quay
runs-on: ubuntu-24.04
permissions:
contents: write

steps:
- name: Create release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "${{ github.ref_name }}" \
--repo "${{ github.repository }}" \
--title "${{ github.ref_name }}" \
--generate-notes
159 changes: 159 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
name: Release

on:
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g. v0.8.0)'
required: true
type: string
skills_ref:
description: 'claudio-skills tag to pin (e.g. v0.5.5)'
required: true
type: string
Comment thread
coderabbitai[bot] marked this conversation as resolved.

permissions: {}

env:
QUAY_REGISTRY: quay.io
QUAY_IMAGE_REPO: quay.io/aipcc-cicd/claudio

jobs:
authorize:
name: Authorize
runs-on: ubuntu-24.04
environment: release
steps:
- name: Verify team membership
env:
GH_TOKEN: ${{ secrets.RELEASE_PAT }}
ACTOR: ${{ github.actor }}
run: |
gh api "orgs/aipcc-cicd/teams/aipcc-productization/memberships/${ACTOR}" --silent \
|| (echo "::error::${ACTOR} is not a member of aipcc-cicd/aipcc-productization" && exit 1)
Comment on lines +27 to +33

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the referenced portion of the workflow (with line numbers)
nl -ba .github/workflows/release.yml | sed -n '1,120p'

# Narrow to the Verify team membership step (lines 20-60 if present)
nl -ba .github/workflows/release.yml | sed -n '20,70p'

# Show any "authorize" job/steps to confirm how this check is used
rg -n "authorize|Verify team membership|team membership|memberships/" .github/workflows/release.yml

Repository: aipcc-cicd/claudio

Length of output: 105


🌐 Web query:

GitHub REST API team memberships endpoint response fields state active pending

💡 Result:

In the GitHub REST API, the state field within team and organization membership objects indicates the current status of the user's membership [1][2][3]. This field is a string with two possible values: active and pending [1][3][4]. The pending state typically indicates that an invitation has been sent to the user, but they have not yet accepted it [1][4]. Once the user accepts the invitation, the state transitions to active [1]. Key API endpoints that include this state field include: - Get team membership for a user: GET /orgs/{org}/teams/{team_slug}/memberships/{username} [1][2] - Get organization membership for a user: GET /orgs/{org}/memberships/{username} [3][4] - List organization memberships for the authenticated user: GET /user/memberships/orgs [5] When querying organization memberships, if a state parameter is available in the request, it can be used to filter results; if left unspecified, the API commonly returns both active and pending memberships [3][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Verify team membership step context ==="
# Show a small window around the step by line numbers (cat -n since nl is unavailable)
cat -n .github/workflows/release.yml | sed -n '1,120p' | sed -n '/Verify team membership/,+20p'

echo "=== Exact step block ==="
rg -n --context=2 "name: Verify team membership|memberships/\\$\\{ACTOR\\}|GH_TOKEN: \\$\\{\\{ secrets\\.RELEASE_PAT \\}\\}" .github/workflows/release.yml

Repository: aipcc-cicd/claudio

Length of output: 1776


🏁 Script executed:

rg -n "\bjq\b|--jq" .github/workflows/release.yml

Repository: aipcc-cicd/claudio

Length of output: 44


Require an active team membership (not just any membership record).

The “Verify team membership” step currently authorizes on any successful response from gh api .../memberships/${ACTOR} and never checks the membership state (active vs pending), so a pending membership could still pass.

Suggested fix
     - name: Verify team membership
       env:
         GH_TOKEN: ${{ secrets.RELEASE_PAT }}
         ACTOR: ${{ github.actor }}
       run: |
-        gh api "orgs/aipcc-cicd/teams/aipcc-productization/memberships/${ACTOR}" --silent \
-          || (echo "::error::${ACTOR} is not a member of aipcc-cicd/aipcc-productization" && exit 1)
+        membership_state="$(gh api "orgs/aipcc-cicd/teams/aipcc-productization/memberships/${ACTOR}" --jq '.state' 2>/dev/null || true)"
+        if [[ "${membership_state}" != "active" ]]; then
+          echo "::error::${ACTOR} does not have an active aipcc-cicd/aipcc-productization membership"
+          exit 1
+        fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 27 - 33, The Verify team
membership step currently treats any membership record as valid; change the
script to capture the JSON output of gh api
"orgs/aipcc-cicd/teams/aipcc-productization/memberships/${ACTOR}" into a
variable, parse the membership state (e.g., using jq or gh api --jq '.state'),
and only succeed when the state equals "active" (otherwise echo an error and
exit 1). Ensure the step still uses the GH_TOKEN/ACTOR env vars and clearly logs
the actor and the returned state when rejecting non-active memberships.


- name: Validate inputs
env:
INPUT_VERSION: ${{ inputs.version }}
INPUT_SKILLS_REF: ${{ inputs.skills_ref }}
run: |
if [[ ! "${INPUT_VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
echo "::error::Invalid version '${INPUT_VERSION}'. Expected format: v0.8.0 or v0.8.0-rc1"
exit 1
fi
if [[ ! "${INPUT_SKILLS_REF}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
echo "::error::Invalid skills_ref '${INPUT_SKILLS_REF}'. Expected format: v0.5.5 or v0.5.5-rc1"
exit 1
fi
Comment on lines +35 to +47

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
ls -la
fd -a -t f "release.yml" .github/workflows || true
sed -n '1,200p' .github/workflows/release.yml

Repository: aipcc-cicd/claudio

Length of output: 5418


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "authorize|gh release create|--target|workflow_dispatch|ref_name|github\\.sha|target \"\\$\\{\\{ github\\.sha \\}\\}\"" .github/workflows/release.yml
sed -n '200,400p' .github/workflows/release.yml

Repository: aipcc-cicd/claudio

Length of output: 221


Restrict manual release runs to an allowed ref (e.g., main) before creating the GitHub release
workflow_dispatch has no branch restriction, and the authorize job only validates inputs + team membership. Since create-release uses gh release create ... --target ${{ github.sha }}, a release will be created for the SHA from whatever branch the operator chose. Add a ref/name gate in authorize (main or allowlist).

Suggested fix
     - name: Validate inputs
       env:
+        INPUT_REF_NAME: ${{ github.ref_name }}
         INPUT_VERSION: ${{ inputs.version }}
         INPUT_SKILLS_REF: ${{ inputs.skills_ref }}
       run: |
+        if [[ "${INPUT_REF_NAME}" != "main" ]]; then
+          echo "::error::Releases must be cut from 'main'. Current ref: '${INPUT_REF_NAME}'"
+          exit 1
+        fi
         if [[ ! "${INPUT_VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
           echo "::error::Invalid version '${INPUT_VERSION}'. Expected format: v0.8.0 or v0.8.0-rc1"
           exit 1
         fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 35 - 47, The authorize job
currently only validates inputs and membership but doesn't prevent
workflow_dispatch from running against arbitrary refs, so add a gate that
verifies the workflow was triggered for an allowed ref (e.g., refs/heads/main or
an allowlist) before proceeding to release creation; implement this by adding a
step in the authorize job (near the existing "Validate inputs" step) that reads
github.ref (or GITHUB_REF) and checks it matches "refs/heads/main" or matches an
allowlist variable (e.g., ALLOWED_REFS) and fails with an error if not matched,
so that the later create-release step (which runs gh release create --target ${{
github.sha }}) cannot create releases for disallowed branches.


- name: Check release does not exist
env:
GH_TOKEN: ${{ secrets.RELEASE_PAT }}
INPUT_VERSION: ${{ inputs.version }}
run: |
if gh release view "${INPUT_VERSION}" &>/dev/null; then
echo "::error::Release ${INPUT_VERSION} already exists"
Comment on lines +49 to +55

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ls -la .github/workflows || true
sed -n '1,200p' .github/workflows/release.yml
echo '---'
# Show the exact lines around the referenced snippet
nl -ba .github/workflows/release.yml | sed -n '35,80p'

Repository: aipcc-cicd/claudio

Length of output: 4522


🌐 Web query:

GitHub CLI gh release view infer repository without git checkout --repo or env variables GH_REPO GITHUB_REPOSITORY

💡 Result:

Yes—gh release view can infer the repository from the local working directory when you’re in a local git repo; otherwise you must provide the repository explicitly (e.g., with --repo or via the GH_REPO env var). 1) What gh release view supports - gh release view has a --repo option: “Select another repository using the [HOST/]OWNER/REPO format” [1]. - If you don’t provide a tag argument, it shows the latest release for the project in that repository [1]. 2) How it infers the repository (no checkout required) - In general, gh determines “the repository for the current directory” when you omit --repo [2]. - For environment-variable use (e.g., in CI), gh documents that GH_REPO can be used to specify the GitHub repository for commands that otherwise operate on a local repository [3]. 3) About GITHUB_REPOSITORY vs GH_REPO - GitHub Actions sets GITHUB_REPOSITORY, but gh historically reads GH_REPO (not GITHUB_REPOSITORY) [4]. - A design discussion notes the intended precedence order when multiple repo lookup mechanisms are present: 1) --repo flag, 2) GH_REPO env var, 3) local git repo, 4) GITHUB_REPOSITORY env var [4]. Practical answers to your exact question - If you want to avoid “git checkout” but still want gh to infer the repo, you can run the command from within any existing local clone of the repo (even if you’re not on the release tag you’re viewing). gh will infer from the current directory’s repository context [2]. - If you’re not in a local git working directory for that repo, you can’t rely on inference; provide --repo [1] or set GH_REPO [3]. - Setting GITHUB_REPOSITORY alone may not work unless gh is also configured to read it for your gh version; gh’s own issue discussion indicates it may be a lower-precedence fallback compared with GH_REPO and local git repo [4].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "skills_ref" .github/workflows || true
rg -n "CS_REF|CS_REF_TYPE|Validate.*skills|skills tag|skills_ref.*validate" .github/workflows || true

Repository: aipcc-cicd/claudio

Length of output: 415


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "skills_ref" . || true
rg -n "Invalid.*skills|skills.*invalid|validate.*skills|CS_REF" . || true

Repository: aipcc-cicd/claudio

Length of output: 1593


Pin repo context for gh release view and validate skills_ref.

  • authorize doesn’t checkout code, so the Check release does not exist step’s gh release view "${INPUT_VERSION}" can’t reliably infer repo context; pass --repo "${{ github.repository }}" so the duplicate-release gate works.
  • inputs.skills_ref isn’t validated (only inputs.version is), so invalid refs fail later in the build/container steps with unclear errors—add a quick format/emptiness check in authorize.
Suggested fix
     - name: Check release does not exist
       env:
         GH_TOKEN: ${{ secrets.RELEASE_PAT }}
         INPUT_VERSION: ${{ inputs.version }}
       run: |
-        if gh release view "${INPUT_VERSION}" &>/dev/null; then
+        if gh release view "${INPUT_VERSION}" --repo "${{ github.repository }}" &>/dev/null; then
           echo "::error::Release ${INPUT_VERSION} already exists"
           exit 1
         fi
📝 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.

Suggested change
- name: Check release does not exist
env:
GH_TOKEN: ${{ secrets.RELEASE_PAT }}
INPUT_VERSION: ${{ inputs.version }}
run: |
if gh release view "${INPUT_VERSION}" &>/dev/null; then
echo "::error::Release ${INPUT_VERSION} already exists"
- name: Check release does not exist
env:
GH_TOKEN: ${{ secrets.RELEASE_PAT }}
INPUT_VERSION: ${{ inputs.version }}
run: |
if gh release view "${INPUT_VERSION}" --repo "${{ github.repository }}" &>/dev/null; then
echo "::error::Release ${INPUT_VERSION} already exists"
exit 1
fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 44 - 50, The "Check release does
not exist" step uses `gh release view "${INPUT_VERSION}"` without repo context
and the `authorize` step doesn't validate `inputs.skills_ref`; update the `Check
release does not exist` step (the step named "Check release does not exist") to
call `gh release view "${INPUT_VERSION}" --repo "${{ github.repository }}"` so
it can resolve repo context when `authorize` hasn't checked out code, and add a
quick validation in the `authorize` step to ensure `inputs.skills_ref` is
present and well-formed (non-empty and matches the expected ref pattern) before
proceeding so invalid `skills_ref` values fail fast with a clear error message.

exit 1
fi

build-and-upload:
name: Build Images
needs: authorize
runs-on: ${{ matrix.runner }}
permissions:
contents: read
strategy:
matrix:
include:
- arch: amd64
runner: ubuntu-24.04
- arch: arm64
runner: ubuntu-24.04-arm

steps:
- name: Checkout code
uses: actions/checkout@v6
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all unpinned action references in workflows.
rg -nP '^\s*uses:\s*[^@]+@v[0-9]+' .github/workflows

Repository: aipcc-cicd/claudio

Length of output: 1116


Pin GitHub Actions uses: to immutable commit SHAs

Workflow steps use floating version tags (not commit SHAs). Update each uses: to a full commit SHA (or other pinned ref) in:

  • .github/workflows/release.yml: 33 (actions/checkout@v6), 49 (actions/upload-artifact@v7), 63 (actions/checkout@v6), 66 (actions/download-artifact@v8), 71 (docker/login-action@v4)
  • .github/workflows/push-pr-images.yml: 29 (actions/checkout@v6), 32 (actions/download-artifact@v8), 80 (docker/login-action@v4)
  • .github/workflows/build.yml: 28 (actions/checkout@v6), 51 (actions/upload-artifact@v7), 64 (actions/download-artifact@v8), 73 (actions/upload-artifact@v7), 89 (actions/checkout@v6), 92 (actions/download-artifact@v8), 97 (docker/login-action@v4)
🧰 Tools
🪛 zizmor (1.25.2)

[warning] 32-33: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 33-33: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 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/release.yml at line 33, Replace all floating GitHub
Actions refs with immutable commit SHAs (or other pinned refs) for each usage of
the actions listed: actions/checkout@v6, actions/upload-artifact@v7,
actions/download-artifact@v8, and docker/login-action@v4; locate every
occurrence of those strings in the workflow files and update the uses: lines to
a full commit SHA or pinned tag (e.g., actions/checkout@<commit-sha>) and ensure
consistency across release.yml, push-pr-images.yml, and build.yml.

with:
persist-credentials: false

- name: Build image (${{ matrix.arch }})
env:
VERSION: ${{ inputs.version }}
CS_REF_TYPE: tag
CS_REF: ${{ inputs.skills_ref }}
IMAGE_REPO: ${{ env.QUAY_IMAGE_REPO }}
IMAGE_TAG: ${{ inputs.version }}
IMAGE_NAME: ${{ env.QUAY_IMAGE_REPO }}:${{ inputs.version }}-${{ matrix.arch }}
ARTIFACT_NAME: claudio-${{ matrix.arch }}
run: |
make oci-build
make oci-save

- name: Upload image artifact
uses: actions/upload-artifact@v7

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

My claude is flagging that actions/upload-artifact@v7 and actions/download-artifact@v8 must be the same version.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

These are separate actions with independent version lines — they don't need to match. The existing build.yml (already working in CI) uses the same combination: upload-artifact@v7 + download-artifact@v8. The release workflow just mirrors what's already there.

with:
name: claudio-${{ matrix.arch }}
path: claudio-${{ matrix.arch }}.tar

push-quay:
name: Push to Quay
needs: build-and-upload
runs-on: ubuntu-24.04
permissions:
contents: read

steps:
- name: Checkout code
uses: actions/checkout@v6
with:
persist-credentials: false

- name: Download claudio images
uses: actions/download-artifact@v8
with:
pattern: claudio-*

- name: Log in to Quay Container Registry
uses: docker/login-action@v4
with:
registry: ${{ env.QUAY_REGISTRY }}
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_PASSWORD }}

- name: Load and push images to Quay
env:
IMAGE_REPO: ${{ env.QUAY_IMAGE_REPO }}
IMAGE_TAG: ${{ inputs.version }}
run: |
make oci-load
make oci-push-arch
make oci-manifest-build
make oci-manifest-push
Comment thread
jrusz marked this conversation as resolved.

- name: Tag and push as latest
env:
IMAGE_REPO: ${{ env.QUAY_IMAGE_REPO }}
IMAGE_TAG: latest
IMAGE_SOURCE_TAG: ${{ inputs.version }}
run: |
make oci-manifest-build
make oci-manifest-push

create-release:
name: Create GitHub Release
needs: push-quay
runs-on: ubuntu-24.04
permissions:
contents: write

steps:
- name: Create release and tag
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_VERSION: ${{ inputs.version }}
run: |
gh release create "$RELEASE_VERSION" \
--repo "${{ github.repository }}" \
--target "${{ github.sha }}" \
--title "$RELEASE_VERSION" \
--generate-notes
Comment thread
coderabbitai[bot] marked this conversation as resolved.
8 changes: 3 additions & 5 deletions Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,10 @@ ARG CS_REF_TYPE
ARG CS_REF
ARG CS_CACHE_KEY
RUN echo "cs-cache-key: ${CS_CACHE_KEY}" \
&& if [ "${CS_REF_TYPE}" = "branch" ]; then \
claude plugin marketplace add aipcc-cicd/claudio-skills#${CS_REF}; \
elif [ "${CS_REF_TYPE}" != "pr" ]; then \
claude plugin marketplace add aipcc-cicd/claudio-skills@v${CS_REF}; \
&& if [ "${CS_REF_TYPE}" = "pr" ]; then \
claude plugin marketplace add /home/claudio/claudio-skills; \
else \
claude plugin marketplace add /home/claudio/claudio-skills; \
claude plugin marketplace add aipcc-cicd/claudio-skills@${CS_REF}; \
fi; \
claude plugin install --scope user claudio-plugin; \
pt-manager.sh
Expand Down
22 changes: 6 additions & 16 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,23 @@
#
# SPDX-License-Identifier: Apache-2.0

VERSION ?= 0.6.1
VERSION ?= dev
CONTAINER_MANAGER ?= podman

# Image configuration
IMAGE_REPO ?= quay.io/aipcc-cicd/claudio
IMAGE_TAG ?= v${VERSION}
IMAGE_TAG ?= ${VERSION}
IMAGE_NAME ?= $(IMAGE_REPO):$(IMAGE_TAG)
IMAGE_SOURCE_TAG ?= $(IMAGE_TAG)

# Artifact naming
ARTIFACT_NAME ?= claudio

# Claudio skills
#
# CS_REF_TYPE can be branch, tag, or pr
# Example when we create a tag version for claudio
CS_REF_TYPE ?= tag
CS_REF ?= 0.5.3
# Claudio skills — ref type (branch, tag, or pr) and ref value.
# Override via env vars for release builds: CS_REF_TYPE=tag CS_REF=v0.5.5
CS_REF_TYPE ?= branch
CS_REF ?= main
CS_REPO ?= https://github.com/aipcc-cicd/claudio-skills.git
# For CS PR 41
# CS_REF_TYPE = pr
# CS_REF = 41
# Resolve the remote HEAD SHA for the skills ref so the build cache
# invalidates automatically when the PR/branch gets new commits.
CS_CACHE_KEY_CMD = $(if $(filter pr,$(CS_REF_TYPE)), \
Expand Down Expand Up @@ -78,8 +73,3 @@ oci-tag:
oci-push:
${CONTAINER_MANAGER} push $(IMAGE_NAME)

# Integrations
.PHONY: integrations-update

integrations-update:
sed -e 's%<IMAGE>%$(IMAGE_NAME)%g' integrations/gitlab-ci/template/claudio.yml > integrations/gitlab-ci/claudio.yml
25 changes: 20 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ Available targets:
- `oci-tag` - Tag existing image with new tag
- `oci-manifest-build` - Create multi-arch manifest from arch-tagged images
- `oci-manifest-push` - Push manifest to registry
- `integrations-update` - Regenerate CI templates with current image version

## Claudio Skills Reference

Expand Down Expand Up @@ -68,7 +67,7 @@ When developing changes to claudio-skills that affect a downstream image (e.g. a
```bash
CS_REF_TYPE=pr CS_REF=9 make oci-build
```
This produces a local image tagged `quay.io/aipcc-cicd/claudio:v1.0.0-dev`.
This produces a local image tagged `quay.io/aipcc-cicd/claudio:dev`.
3. In the downstream repo, point the `FROM` line at that local image (or tag it to match the expected base tag) and build:
```bash
# In aipcc-claudio
Expand Down Expand Up @@ -153,7 +152,7 @@ The `.claudio` template uses the claudio image directly as the job container. Yo

Available variables:
- `CLAUDIO_PROMPT` (required) — the prompt to run
- `CLAUDIO_IMAGE` — override the claudio image (default: current release version)
- `CLAUDIO_IMAGE` — override the claudio image (default: `quay.io/aipcc-cicd/claudio:latest`)
- `CLAUDIO_EXTRA_ARGS` — extra arguments passed to claudio
- `CLAUDIO_STREAM` — set to `1` to enable human-readable streaming output in the job log
- `CLAUDIO_LOG_FILE` — write a plain-text log (no ANSI codes) to this path (streaming mode only)
Expand All @@ -173,6 +172,22 @@ my-claudio-job:
CLAUDIO_PROMPT: "Do something useful"
```

The template is generated from `integrations/gitlab-ci/template/claudio.yml`. When preparing a release, run `make integrations-update` to regenerate the template with the current version, then commit the result.

Downstream projects can extend this template to add their own secret management.

## Releasing

Releases are fully automated via GitHub Actions — no manual commits or version bumps needed.

1. Go to **Actions** → **Release** → **Run workflow**
2. Enter the version (e.g. `v0.8.0`) and the claudio-skills tag to pin (e.g. `v0.5.5`)
3. Click **Run workflow**

The workflow builds multi-arch images, pushes to Quay (`quay.io/aipcc-cicd/claudio:v0.8.0`), creates a git tag, and publishes a GitHub Release with auto-generated notes.

### Patch releases

If you need to patch an older release:

1. Create a release branch from the tag: `git checkout -b release-0.7 v0.7.0`
2. Cherry-pick the fix(es) and push the branch: `git push origin release-0.7`
3. Run the release workflow, selecting the release branch as the target
4 changes: 2 additions & 2 deletions integrations/gitlab-ci/claudio.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# CLAUDIO_PROMPT: "Analyze the latest MRs and report to Slack"
#
# Optional variables to override:
# CLAUDIO_IMAGE - claudio container image (default: quay.io/aipcc-cicd/claudio:<VERSION>)
# CLAUDIO_IMAGE - claudio container image (default: quay.io/aipcc-cicd/claudio:latest)
# CLAUDIO_EXTRA_ARGS - Extra arguments passed to claudio
#

Expand All @@ -23,7 +23,7 @@
name: ${CLAUDIO_IMAGE}
entrypoint: [""]
variables:
CLAUDIO_IMAGE: "quay.io/aipcc-cicd/claudio:v0.5.0-dev"
CLAUDIO_IMAGE: "quay.io/aipcc-cicd/claudio:latest"
CLAUDIO_EXTRA_ARGS: ""
script:
- |
Expand Down
Loading