Skip to content
Latchkey

Docker Image CI workflow (krkn-chaos/krkn)

The Docker Image CI workflow from krkn-chaos/krkn, explained and optimized by Latchkey.

C

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.

Grade your own workflow free or run it on Latchkey →
Source: krkn-chaos/krkn.github/workflows/docker-image.ymlLicense Apache-2.0View source

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

workflow (.yml)
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

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:

This workflow runs 4 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.

Actions used in this workflow