Skip to content

chore(deps): bump the github-actions group across 1 directory with 12 updates #139

chore(deps): bump the github-actions group across 1 directory with 12 updates

chore(deps): bump the github-actions group across 1 directory with 12 updates #139

Workflow file for this run

name: Docker (beta)
# Build the container images on every PR (validation only, no push) and publish
# the beta channel to GHCR on every push to master. Two images are built from one
# Dockerfile: the HTTP API (:beta) and the web UI (:beta-ui).
on:
push:
branches: [master]
pull_request:
branches: [master]
workflow_dispatch:
# Least privilege at the top level; the build job below opts into exactly the
# write scopes it needs (top-level write would fail OpenSSF Token-Permissions).
permissions:
contents: read
concurrency:
group: docker-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
IMAGE_NAME: ghcr.io/neverdecel/coderag
jobs:
# Compute ONE timestamp + short SHA shared by both matrix targets, so the server
# and UI images carry the *same* sortable base tag (`beta-<ts>-<sha>` /
# `beta-<ts>-<sha>-ui`). A GitOps image-updater (Flux ImagePolicy) needs a
# chronologically sortable tag to pick "the newest beta"; the rolling `:beta`
# tag is mutable and `:sha-<commit>` is not orderable. Computing the timestamp in
# one place keeps the two images' base tags byte-identical, so a single policy on
# the server tag also resolves the UI tag (UI = base tag + `-ui` suffix).
prepare:
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
outputs:
version: ${{ steps.ver.outputs.version }}
steps:
- id: ver
run: echo "version=beta-$(date -u +%Y%m%d%H%M%S)-${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
build:
needs: prepare
# `needs: prepare` is skipped-but-not-blocking on PRs (prepare is gated to
# non-PR events); always() keeps the build job running for PR validation.
if: always()
runs-on: ubuntu-latest
timeout-minutes: 30
# Write scopes are scoped to this job only; the prepare job needs none.
permissions:
contents: read # checkout
packages: write # push images to GHCR
id-token: write # OIDC for build provenance / keyless signing
attestations: write # SLSA provenance + SBOM attestations
strategy:
fail-fast: false
matrix:
include:
- target: server # HTTP/REST API
suffix: ""
- target: ui # Web UI
suffix: "-ui"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up QEMU (arm64 emulation)
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4
- name: Log in to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Derive image tags & labels
id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6
with:
images: ${{ env.IMAGE_NAME }}
flavor: |
latest=false
suffix=${{ matrix.suffix }}
tags: |
type=raw,value=beta
type=raw,value=${{ needs.prepare.outputs.version }},enable=${{ github.event_name != 'pull_request' }}
type=edge,branch=master
type=sha,prefix=sha-
- name: Build${{ github.event_name != 'pull_request' && ' and push' || ' (validate, no push)' }}
id: build
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
with:
context: .
target: ${{ matrix.target }}
# Multi-arch on master; amd64-only on PRs to keep validation fast.
platforms: ${{ github.event_name == 'pull_request' && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
push: ${{ github.event_name != 'pull_request' }}
# On PRs (no push) load the single-arch image into the local daemon so the
# Trivy step below can scan the exact artifact that was just built.
load: ${{ github.event_name == 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
cache-from: type=gha,scope=${{ matrix.target }}
# Cache in GitHub Actions storage (not GHCR, so no buildcache* tags). The
# transient export blip ("error writing layer blob: not_found") that used to
# fail the build is swallowed by ignore-error=true, now honored by the newer
# buildkit that ships with setup-buildx-action@v4 / build-push-action@v7.
cache-to: type=gha,mode=max,scope=${{ matrix.target }},ignore-error=true
provenance: ${{ github.event_name != 'pull_request' }}
sbom: ${{ github.event_name != 'pull_request' }}
# Vulnerability-scan the exact image we just built. On PRs the image is loaded
# into the local daemon (load: true above) and scanned by its concrete `beta`
# tag; on master the image is pushed and scanned by digest. Fails the build on
# any fixable HIGH/CRITICAL OS or library CVE.
- name: Scan image with Trivy
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
image-ref: >-
${{ github.event_name == 'pull_request'
&& format('{0}:beta{1}', env.IMAGE_NAME, matrix.suffix)
|| format('{0}@{1}', env.IMAGE_NAME, steps.build.outputs.digest) }}
format: table
exit-code: "1"
ignore-unfixed: true
vuln-type: os,library
severity: HIGH,CRITICAL
env:
# Avoid GHCR rate limits when pulling the Trivy vulnerability DB.
TRIVY_USERNAME: ${{ github.actor }}
TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}