Docker Image CI workflow (krkn-chaos/krkn)
The Docker Image CI workflow from krkn-chaos/krkn, explained and optimized by Latchkey.
CI health: C - fair
Point runs-on at Latchkey and get run de-duplication, job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Docker Image CI workflow from the krkn-chaos/krkn repository, a real project running GitHub Actions. It is shown here with attribution under its Apache-2.0 license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: Docker Image CI
on:
push:
tags: ['v[0-9].[0-9]+.[0-9]+']
branches:
- main
pull_request:
jobs:
security-scan-source:
name: Security Scan - Source Code & Dependencies
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Check out code
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
- name: Install Grype
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
- name: Scan source code and dependencies
run: |
echo "π Scanning source code and dependencies for vulnerabilities..."
grype dir:. --only-fixed -o table > /tmp/grype-source.txt || true
SCAN_OUTPUT=$(grype dir:. --only-fixed -o json)
CRITICAL=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "Critical")] | length')
HIGH=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "High")] | length')
MEDIUM=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "Medium")] | length')
# Create Job Summary with table
echo "## π Security Scan - Source Code & Dependencies" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Severity | Count | Status |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| π΄ Critical | $CRITICAL | $([ $CRITICAL -eq 0 ] && echo 'β
' || echo 'β οΈ') |" >> $GITHUB_STEP_SUMMARY
echo "| π High | $HIGH | $([ $HIGH -eq 0 ] && echo 'β
' || echo 'β οΈ') |" >> $GITHUB_STEP_SUMMARY
echo "| π‘ Medium | $MEDIUM | $([ $MEDIUM -eq 0 ] && echo 'β
' || echo 'β οΈ') |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "$CRITICAL" -gt 0 ] || [ "$HIGH" -gt 0 ]; then
echo "β οΈ **Found $CRITICAL Critical and $HIGH High vulnerabilities with available fixes**" >> $GITHUB_STEP_SUMMARY
else
echo "β
**No Critical or High vulnerabilities found**" >> $GITHUB_STEP_SUMMARY
fi
# Add collapsible full scan results
echo "" >> $GITHUB_STEP_SUMMARY
echo "<details>" >> $GITHUB_STEP_SUMMARY
echo "<summary>π Full Scan Results</summary>" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
cat /tmp/grype-source.txt >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "</details>" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
build:
runs-on: ${{ matrix.runner }}
strategy:
matrix:
include:
- platform: amd64
runner: ubuntu-latest
- platform: arm64
runner: ubuntu-24.04-arm
steps:
- name: Check out code
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Test Build the Docker images
if: github.event_name == 'pull_request'
run: |
./containers/compile_dockerfile.sh
docker buildx build --no-cache \
--platform linux/${{ matrix.platform }} \
-t quay.io/krkn-chaos/krkn:pr-${{ github.event.pull_request.number }}-${{ matrix.platform }} \
-t quay.io/redhat-chaos/krkn:pr-${{ github.event.pull_request.number }}-${{ matrix.platform }} \
containers/ \
--build-arg PR_NUMBER=${{ github.event.pull_request.number }} \
--load
- name: Install Grype
if: github.event_name == 'pull_request'
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
- name: Scan Docker image for vulnerabilities
if: github.event_name == 'pull_request'
run: |
IMAGE_NAME="quay.io/krkn-chaos/krkn:pr-${{ github.event.pull_request.number }}-${{ matrix.platform }}"
echo "π Scanning Docker image: $IMAGE_NAME"
grype "$IMAGE_NAME" --only-fixed -o table > /tmp/grype-image-${{ matrix.platform }}.txt || true
SCAN_OUTPUT=$(grype "$IMAGE_NAME" --only-fixed -o json)
CRITICAL=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "Critical")] | length')
HIGH=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "High")] | length')
MEDIUM=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "Medium")] | length')
# Create Job Summary with table
echo "## π³ Docker Image Security Scan - ${{ matrix.platform }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Severity | Count | Status |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| π΄ Critical | $CRITICAL | $([ $CRITICAL -eq 0 ] && echo 'β
' || echo 'β οΈ') |" >> $GITHUB_STEP_SUMMARY
echo "| π High | $HIGH | $([ $HIGH -eq 0 ] && echo 'β
' || echo 'β οΈ') |" >> $GITHUB_STEP_SUMMARY
echo "| π‘ Medium | $MEDIUM | $([ $MEDIUM -eq 0 ] && echo 'β
' || echo 'β οΈ') |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "$CRITICAL" -gt 0 ] || [ "$HIGH" -gt 0 ]; then
echo "β οΈ **Found $CRITICAL Critical and $HIGH High vulnerabilities with available fixes**" >> $GITHUB_STEP_SUMMARY
else
echo "β
**No Critical or High vulnerabilities found**" >> $GITHUB_STEP_SUMMARY
fi
# Add collapsible full scan results
echo "" >> $GITHUB_STEP_SUMMARY
echo "<details>" >> $GITHUB_STEP_SUMMARY
echo "<summary>π Full Scan Results</summary>" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
cat /tmp/grype-image-${{ matrix.platform }}.txt >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "</details>" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
- name: Login to krkn-chaos quay
if: startsWith(github.ref, 'refs/tags')
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_PASSWORD }}
- name: Build and push krkn-chaos images
if: startsWith(github.ref, 'refs/tags')
run: |
./containers/compile_dockerfile.sh
TAG=${GITHUB_REF#refs/tags/}
docker buildx build --no-cache \
--platform linux/${{ matrix.platform }} \
--provenance=false \
-t quay.io/krkn-chaos/krkn:latest-${{ matrix.platform }} \
-t quay.io/krkn-chaos/krkn:${TAG}-${{ matrix.platform }} \
containers/ \
--build-arg TAG=${TAG} \
--push --load
- name: Login to redhat-chaos quay
if: startsWith(github.ref, 'refs/tags')
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: quay.io
username: ${{ secrets.QUAY_USER_1 }}
password: ${{ secrets.QUAY_TOKEN_1 }}
- name: Push redhat-chaos images
if: startsWith(github.ref, 'refs/tags')
run: |
TAG=${GITHUB_REF#refs/tags/}
docker tag quay.io/krkn-chaos/krkn:${TAG}-${{ matrix.platform }} quay.io/redhat-chaos/krkn:${TAG}-${{ matrix.platform }}
docker tag quay.io/krkn-chaos/krkn:${TAG}-${{ matrix.platform }} quay.io/redhat-chaos/krkn:latest-${{ matrix.platform }}
docker push quay.io/redhat-chaos/krkn:${TAG}-${{ matrix.platform }}
docker push quay.io/redhat-chaos/krkn:latest-${{ matrix.platform }}
manifest:
runs-on: ubuntu-latest
needs: build
if: startsWith(github.ref, 'refs/tags')
steps:
- name: Login to krkn-chaos quay
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_PASSWORD }}
- name: Create and push KrknChaos manifests
run: |
TAG=${GITHUB_REF#refs/tags/}
docker manifest create quay.io/krkn-chaos/krkn:${TAG} \
quay.io/krkn-chaos/krkn:${TAG}-amd64 \
quay.io/krkn-chaos/krkn:${TAG}-arm64
docker manifest push quay.io/krkn-chaos/krkn:${TAG}
docker manifest create quay.io/krkn-chaos/krkn:latest \
quay.io/krkn-chaos/krkn:latest-amd64 \
quay.io/krkn-chaos/krkn:latest-arm64
docker manifest push quay.io/krkn-chaos/krkn:latest
- name: Login to redhat-chaos quay
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: quay.io
username: ${{ secrets.QUAY_USER_1 }}
password: ${{ secrets.QUAY_TOKEN_1 }}
- name: Create and push RedHat Chaos manifests
run: |
TAG=${GITHUB_REF#refs/tags/}
docker manifest create quay.io/redhat-chaos/krkn:${TAG} \
quay.io/redhat-chaos/krkn:${TAG}-amd64 \
quay.io/redhat-chaos/krkn:${TAG}-arm64
docker manifest push quay.io/redhat-chaos/krkn:${TAG}
docker manifest create quay.io/redhat-chaos/krkn:latest \
quay.io/redhat-chaos/krkn:latest-amd64 \
quay.io/redhat-chaos/krkn:latest-arm64
docker manifest push quay.io/redhat-chaos/krkn:latest
- name: Rebuild krkn-hub
uses: redhat-chaos/actions/krkn-hub@aa421229ca6d4ad13785039d0736611c6439fc3e # main
with:
QUAY_USER: ${{ secrets.QUAY_USERNAME }}
QUAY_TOKEN: ${{ secrets.QUAY_PASSWORD }}
AUTOPUSH: ${{ secrets.AUTOPUSH }}
security-badge:
permissions:
contents: write
name: Generate Security Badge
runs-on: ubuntu-latest
needs:
- build
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- name: Check out code
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
- name: Check out doc repo
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
with:
repository: krkn-chaos/krkn-lib-docs
path: krkn-lib-docs
ssh-key: ${{ secrets.KRKN_LIB_DOCS_PRIV_KEY }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Build image for security scan
run: |
./containers/compile_dockerfile.sh
docker buildx build --no-cache \
--platform linux/amd64 \
-t krkn-chaos/krkn:security-scan \
containers/ \
--load
- name: Install Grype
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
- name: Scan and generate security badge
run: |
# Scan with grype (no --only-fixed to get all CVEs for baseline)
SCAN_OUTPUT=$(grype krkn-chaos/krkn:security-scan -o json)
# Count vulnerabilities by severity
CRITICAL=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "Critical")] | length')
HIGH=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "High")] | length')
MEDIUM=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "Medium")] | length')
TOTAL=$(echo "$SCAN_OUTPUT" | jq '[.matches[]] | length')
# Determine badge color based on severity
if [ $CRITICAL -gt 0 ]; then
COLOR="critical"
elif [ $HIGH -gt 10 ]; then
COLOR="important"
elif [ $HIGH -gt 5 ]; then
COLOR="orange"
elif [ $HIGH -gt 0 ]; then
COLOR="yellow"
else
COLOR="brightgreen"
fi
echo "Security Scan Results:"
echo " Critical: $CRITICAL"
echo " High: $HIGH"
echo " Medium: $MEDIUM"
echo " Total: $TOTAL"
echo " Badge Color: $COLOR"
# Generate detailed badge: "C:0 H:7 M:3"
curl "https://img.shields.io/badge/security-C:$CRITICAL%20H:$HIGH%20M:$MEDIUM-$COLOR" > ./krkn-lib-docs/security_badge_krkn.svg
- name: Push updated Security Badge
run: |
cd krkn-lib-docs
git add .
git config user.name "krkn-chaos"
git config user.email "krkn-actions@users.noreply.github.com"
git commit -m "[KRKN] Security Badge ${GITHUB_REF##*/}" || echo "no changes to commit"
git push
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Docker Image CI on: push: tags: ['v[0-9].[0-9]+.[0-9]+'] branches: - main pull_request: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: security-scan-source: timeout-minutes: 30 name: Security Scan - Source Code & Dependencies runs-on: latchkey-small if: github.event_name == 'pull_request' steps: - name: Check out code uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 - name: Install Grype run: | curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin - name: Scan source code and dependencies run: | echo "π Scanning source code and dependencies for vulnerabilities..." grype dir:. --only-fixed -o table > /tmp/grype-source.txt || true SCAN_OUTPUT=$(grype dir:. --only-fixed -o json) CRITICAL=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "Critical")] | length') HIGH=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "High")] | length') MEDIUM=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "Medium")] | length') # Create Job Summary with table echo "## π Security Scan - Source Code & Dependencies" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Severity | Count | Status |" >> $GITHUB_STEP_SUMMARY echo "|----------|-------|--------|" >> $GITHUB_STEP_SUMMARY echo "| π΄ Critical | $CRITICAL | $([ $CRITICAL -eq 0 ] && echo 'β ' || echo 'β οΈ') |" >> $GITHUB_STEP_SUMMARY echo "| π High | $HIGH | $([ $HIGH -eq 0 ] && echo 'β ' || echo 'β οΈ') |" >> $GITHUB_STEP_SUMMARY echo "| π‘ Medium | $MEDIUM | $([ $MEDIUM -eq 0 ] && echo 'β ' || echo 'β οΈ') |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY if [ "$CRITICAL" -gt 0 ] || [ "$HIGH" -gt 0 ]; then echo "β οΈ **Found $CRITICAL Critical and $HIGH High vulnerabilities with available fixes**" >> $GITHUB_STEP_SUMMARY else echo "β **No Critical or High vulnerabilities found**" >> $GITHUB_STEP_SUMMARY fi # Add collapsible full scan results echo "" >> $GITHUB_STEP_SUMMARY echo "<details>" >> $GITHUB_STEP_SUMMARY echo "<summary>π Full Scan Results</summary>" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY cat /tmp/grype-source.txt >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY echo "</details>" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY build: timeout-minutes: 30 runs-on: ${{ matrix.runner }} strategy: matrix: include: - platform: amd64 runner: ubuntu-latest - platform: arm64 runner: ubuntu-24.04-arm steps: - name: Check out code uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - name: Test Build the Docker images if: github.event_name == 'pull_request' run: | ./containers/compile_dockerfile.sh docker buildx build --no-cache \ --platform linux/${{ matrix.platform }} \ -t quay.io/krkn-chaos/krkn:pr-${{ github.event.pull_request.number }}-${{ matrix.platform }} \ -t quay.io/redhat-chaos/krkn:pr-${{ github.event.pull_request.number }}-${{ matrix.platform }} \ containers/ \ --build-arg PR_NUMBER=${{ github.event.pull_request.number }} \ --load - name: Install Grype if: github.event_name == 'pull_request' run: | curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin - name: Scan Docker image for vulnerabilities if: github.event_name == 'pull_request' run: | IMAGE_NAME="quay.io/krkn-chaos/krkn:pr-${{ github.event.pull_request.number }}-${{ matrix.platform }}" echo "π Scanning Docker image: $IMAGE_NAME" grype "$IMAGE_NAME" --only-fixed -o table > /tmp/grype-image-${{ matrix.platform }}.txt || true SCAN_OUTPUT=$(grype "$IMAGE_NAME" --only-fixed -o json) CRITICAL=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "Critical")] | length') HIGH=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "High")] | length') MEDIUM=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "Medium")] | length') # Create Job Summary with table echo "## π³ Docker Image Security Scan - ${{ matrix.platform }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Severity | Count | Status |" >> $GITHUB_STEP_SUMMARY echo "|----------|-------|--------|" >> $GITHUB_STEP_SUMMARY echo "| π΄ Critical | $CRITICAL | $([ $CRITICAL -eq 0 ] && echo 'β ' || echo 'β οΈ') |" >> $GITHUB_STEP_SUMMARY echo "| π High | $HIGH | $([ $HIGH -eq 0 ] && echo 'β ' || echo 'β οΈ') |" >> $GITHUB_STEP_SUMMARY echo "| π‘ Medium | $MEDIUM | $([ $MEDIUM -eq 0 ] && echo 'β ' || echo 'β οΈ') |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY if [ "$CRITICAL" -gt 0 ] || [ "$HIGH" -gt 0 ]; then echo "β οΈ **Found $CRITICAL Critical and $HIGH High vulnerabilities with available fixes**" >> $GITHUB_STEP_SUMMARY else echo "β **No Critical or High vulnerabilities found**" >> $GITHUB_STEP_SUMMARY fi # Add collapsible full scan results echo "" >> $GITHUB_STEP_SUMMARY echo "<details>" >> $GITHUB_STEP_SUMMARY echo "<summary>π Full Scan Results</summary>" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY cat /tmp/grype-image-${{ matrix.platform }}.txt >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY echo "</details>" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - name: Login to krkn-chaos quay if: startsWith(github.ref, 'refs/tags') uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 with: registry: quay.io username: ${{ secrets.QUAY_USERNAME }} password: ${{ secrets.QUAY_PASSWORD }} - name: Build and push krkn-chaos images if: startsWith(github.ref, 'refs/tags') run: | ./containers/compile_dockerfile.sh TAG=${GITHUB_REF#refs/tags/} docker buildx build --no-cache \ --platform linux/${{ matrix.platform }} \ --provenance=false \ -t quay.io/krkn-chaos/krkn:latest-${{ matrix.platform }} \ -t quay.io/krkn-chaos/krkn:${TAG}-${{ matrix.platform }} \ containers/ \ --build-arg TAG=${TAG} \ --push --load - name: Login to redhat-chaos quay if: startsWith(github.ref, 'refs/tags') uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 with: registry: quay.io username: ${{ secrets.QUAY_USER_1 }} password: ${{ secrets.QUAY_TOKEN_1 }} - name: Push redhat-chaos images if: startsWith(github.ref, 'refs/tags') run: | TAG=${GITHUB_REF#refs/tags/} docker tag quay.io/krkn-chaos/krkn:${TAG}-${{ matrix.platform }} quay.io/redhat-chaos/krkn:${TAG}-${{ matrix.platform }} docker tag quay.io/krkn-chaos/krkn:${TAG}-${{ matrix.platform }} quay.io/redhat-chaos/krkn:latest-${{ matrix.platform }} docker push quay.io/redhat-chaos/krkn:${TAG}-${{ matrix.platform }} docker push quay.io/redhat-chaos/krkn:latest-${{ matrix.platform }} manifest: timeout-minutes: 30 runs-on: latchkey-small needs: build if: startsWith(github.ref, 'refs/tags') steps: - name: Login to krkn-chaos quay uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 with: registry: quay.io username: ${{ secrets.QUAY_USERNAME }} password: ${{ secrets.QUAY_PASSWORD }} - name: Create and push KrknChaos manifests run: | TAG=${GITHUB_REF#refs/tags/} docker manifest create quay.io/krkn-chaos/krkn:${TAG} \ quay.io/krkn-chaos/krkn:${TAG}-amd64 \ quay.io/krkn-chaos/krkn:${TAG}-arm64 docker manifest push quay.io/krkn-chaos/krkn:${TAG} docker manifest create quay.io/krkn-chaos/krkn:latest \ quay.io/krkn-chaos/krkn:latest-amd64 \ quay.io/krkn-chaos/krkn:latest-arm64 docker manifest push quay.io/krkn-chaos/krkn:latest - name: Login to redhat-chaos quay uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 with: registry: quay.io username: ${{ secrets.QUAY_USER_1 }} password: ${{ secrets.QUAY_TOKEN_1 }} - name: Create and push RedHat Chaos manifests run: | TAG=${GITHUB_REF#refs/tags/} docker manifest create quay.io/redhat-chaos/krkn:${TAG} \ quay.io/redhat-chaos/krkn:${TAG}-amd64 \ quay.io/redhat-chaos/krkn:${TAG}-arm64 docker manifest push quay.io/redhat-chaos/krkn:${TAG} docker manifest create quay.io/redhat-chaos/krkn:latest \ quay.io/redhat-chaos/krkn:latest-amd64 \ quay.io/redhat-chaos/krkn:latest-arm64 docker manifest push quay.io/redhat-chaos/krkn:latest - name: Rebuild krkn-hub uses: redhat-chaos/actions/krkn-hub@aa421229ca6d4ad13785039d0736611c6439fc3e # main with: QUAY_USER: ${{ secrets.QUAY_USERNAME }} QUAY_TOKEN: ${{ secrets.QUAY_PASSWORD }} AUTOPUSH: ${{ secrets.AUTOPUSH }} security-badge: timeout-minutes: 30 permissions: contents: write name: Generate Security Badge runs-on: latchkey-small needs: - build if: github.ref == 'refs/heads/main' && github.event_name == 'push' steps: - name: Check out code uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 - name: Check out doc repo uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master with: repository: krkn-chaos/krkn-lib-docs path: krkn-lib-docs ssh-key: ${{ secrets.KRKN_LIB_DOCS_PRIV_KEY }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - name: Build image for security scan run: | ./containers/compile_dockerfile.sh docker buildx build --no-cache \ --platform linux/amd64 \ -t krkn-chaos/krkn:security-scan \ containers/ \ --load - name: Install Grype run: | curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin - name: Scan and generate security badge run: | # Scan with grype (no --only-fixed to get all CVEs for baseline) SCAN_OUTPUT=$(grype krkn-chaos/krkn:security-scan -o json) # Count vulnerabilities by severity CRITICAL=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "Critical")] | length') HIGH=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "High")] | length') MEDIUM=$(echo "$SCAN_OUTPUT" | jq '[.matches[] | select(.vulnerability.severity == "Medium")] | length') TOTAL=$(echo "$SCAN_OUTPUT" | jq '[.matches[]] | length') # Determine badge color based on severity if [ $CRITICAL -gt 0 ]; then COLOR="critical" elif [ $HIGH -gt 10 ]; then COLOR="important" elif [ $HIGH -gt 5 ]; then COLOR="orange" elif [ $HIGH -gt 0 ]; then COLOR="yellow" else COLOR="brightgreen" fi echo "Security Scan Results:" echo " Critical: $CRITICAL" echo " High: $HIGH" echo " Medium: $MEDIUM" echo " Total: $TOTAL" echo " Badge Color: $COLOR" # Generate detailed badge: "C:0 H:7 M:3" curl "https://img.shields.io/badge/security-C:$CRITICAL%20H:$HIGH%20M:$MEDIUM-$COLOR" > ./krkn-lib-docs/security_badge_krkn.svg - name: Push updated Security Badge run: | cd krkn-lib-docs git add . git config user.name "krkn-chaos" git config user.email "krkn-actions@users.noreply.github.com" git commit -m "[KRKN] Security Badge ${GITHUB_REF##*/}" || echo "no changes to commit" git push
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Cancel superseded runs when a branch or PR gets a newer push.
- Add a job timeout so a hung step cannot burn hours of runner time.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- Container pulls and builds
- Network fetches
This workflow runs 4 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.