build: cache docker layers, configurable engine, bump owasp/pnpm

- CI workflow uses BuildKit inline cache + --cache-from previous :latest;
  NVD_REFRESH build-arg busts the OWASP layer on schedule/dispatch so
  weekly rebuilds still refresh NVD while push builds reuse cached layers.
- build-and-push.ps1 reads CONTAINER_ENGINE from .env (docker default,
  podman supported); add .env.example.
- Bump OWASP Dependency-Check 12.2.1 -> 12.2.2 and pnpm 11.0.6 -> 11.1.1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-14 09:43:21 +08:00
parent f257a1b039
commit 8376250940
4 changed files with 62 additions and 12 deletions
+16
View File
@@ -0,0 +1,16 @@
# Copy this file to .env and fill in the values.
# .env is gitignored — never commit real credentials.
# ── Container engine (docker | podman) ──
CONTAINER_ENGINE=docker
# ── Docker Registry ──
REGISTRY=kcr.kollect.biz
REGISTRY_USER='robot$kollect-tools+ci-builder'
REGISTRY_PASS=harbor-robot-password
IMAGE_TAG=latest
# ── OWASP Dependency-Check ──
# Get an API key at https://nvd.nist.gov/developers/request-an-api-key
# Optional but strongly recommended — without it NVD rate-limits to 5 req / 30s.
NVD_API_KEY=<nvd-api-key>
+18
View File
@@ -74,8 +74,26 @@ jobs:
--password-stdin
- name: Build image
env:
DOCKER_BUILDKIT: "1"
run: |
# Pull the previous :latest to use as a layer cache source.
# First builds (no prior image) fail this pull — that's fine.
docker pull "${{ steps.meta.outputs.tag_latest }}" || true
# On schedule / manual dispatch, bust the OWASP NVD layer so the
# weekly rebuild actually refreshes the NVD database. Push builds
# leave it empty so unchanged layers stay cached.
NVD_REFRESH=""
if [ "${{ github.event_name }}" = "schedule" ] || \
[ "${{ github.event_name }}" = "workflow_dispatch" ]; then
NVD_REFRESH="$(date +%Y%m%d)"
fi
docker build \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--build-arg NVD_REFRESH="${NVD_REFRESH}" \
--cache-from "${{ steps.meta.outputs.tag_latest }}" \
--label "org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}" \
--label "org.opencontainers.image.revision=${{ github.sha }}" \
-t "${{ steps.meta.outputs.tag_sha }}" \
+22 -9
View File
@@ -1,7 +1,10 @@
#Requires -Version 5.1
<#
.SYNOPSIS
Build and push a CI image to the Harbor registry using podman.
Build and push a CI image to the Harbor registry.
The container engine is read from CONTAINER_ENGINE in .env
(docker | podman). Defaults to docker when unset.
.EXAMPLE
.\build-and-push.ps1 -Image ci/java-builder
@@ -36,6 +39,16 @@ foreach ($v in 'REGISTRY', 'REGISTRY_USER', 'REGISTRY_PASS') {
}
}
# --- Resolve container engine ---
$engine = if ($env:CONTAINER_ENGINE) { $env:CONTAINER_ENGINE.Trim().ToLower() } else { 'docker' }
if ($engine -notin @('docker', 'podman')) {
throw "CONTAINER_ENGINE must be 'docker' or 'podman' (got '$engine')"
}
if (-not (Get-Command $engine -ErrorAction SilentlyContinue)) {
throw "Container engine '$engine' not found on PATH"
}
Write-Host "=> Using container engine: $engine"
# --- Resolve paths ---
# $Image is the path to the image directory relative to the repo root, and
# also the image name pushed to the registry (e.g. "ci/java-builder").
@@ -72,7 +85,7 @@ $tags = @('latest', $Version, $date)
# (PowerShell's native pipe appends CRLF, which breaks --password-stdin).
Write-Host "=> Logging in to $regHost"
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = 'podman'
$psi.FileName = $engine
$psi.Arguments = "login $regHost --username `"$($env:REGISTRY_USER)`" --password-stdin"
$psi.RedirectStandardInput = $true
$psi.UseShellExecute = $false
@@ -80,7 +93,7 @@ $proc = [System.Diagnostics.Process]::Start($psi)
$proc.StandardInput.Write($env:REGISTRY_PASS)
$proc.StandardInput.Close()
$proc.WaitForExit()
if ($proc.ExitCode -ne 0) { throw "podman login failed (exit $($proc.ExitCode))" }
if ($proc.ExitCode -ne 0) { throw "$engine login failed (exit $($proc.ExitCode))" }
# --- Build ---
Write-Host "=> Building ${repo}:latest"
@@ -90,21 +103,21 @@ if ($env:NVD_API_KEY) {
}
$buildArgs += $imageDir
& podman @buildArgs
if ($LASTEXITCODE -ne 0) { throw "podman build failed" }
& $engine @buildArgs
if ($LASTEXITCODE -ne 0) { throw "$engine build failed" }
# --- Tag ---
foreach ($tag in $Version, $date) {
Write-Host "=> Tagging ${repo}:$tag"
podman tag "${repo}:latest" "${repo}:$tag"
if ($LASTEXITCODE -ne 0) { throw "podman tag failed for $tag" }
& $engine tag "${repo}:latest" "${repo}:$tag"
if ($LASTEXITCODE -ne 0) { throw "$engine tag failed for $tag" }
}
# --- Push ---
foreach ($tag in $tags) {
Write-Host "=> Pushing ${repo}:$tag"
podman push "${repo}:$tag"
if ($LASTEXITCODE -ne 0) { throw "podman push failed for $tag" }
& $engine push "${repo}:$tag"
if ($LASTEXITCODE -ne 0) { throw "$engine push failed for $tag" }
}
Write-Host "Done. Pushed $($tags.Count) tags to $repo"
+6 -3
View File
@@ -66,11 +66,14 @@ RUN curl -fsSL "https://dlcdn.apache.org/maven/maven-3/${MAVEN_VERSION}/binaries
#
# Rebuild this image weekly to keep the NVD database fresh.
# ─────────────────────────────────────────────────────────────────────
ARG OWASP_DC_VERSION=12.2.1
ARG OWASP_DC_VERSION=12.2.2
ARG NVD_API_KEY=""
# Bump to invalidate the cached NVD layer (e.g. weekly date stamp from CI).
ARG NVD_REFRESH=""
ENV OWASP_DATA_DIR=/opt/owasp/dependency-check-data
RUN if [ -n "${NVD_API_KEY}" ]; then \
RUN echo "NVD_REFRESH=${NVD_REFRESH}" \
&& if [ -n "${NVD_API_KEY}" ]; then \
echo "NVD API key: set (length=$(printf %s "${NVD_API_KEY}" | wc -c))"; \
else \
echo "WARNING: NVD_API_KEY is empty — NVD will rate-limit at 5 req / 30s"; \
@@ -113,7 +116,7 @@ RUN curl -fsSL "https://github.com/bufbuild/buf/releases/download/v${BUF_VERSION
# Last because it's the most volatile pin and corepack prepare is the
# cheapest layer; bumping pnpm shouldn't force any other layer to rebuild.
# ─────────────────────────────────────────────────────────────────────
ARG PNPM_VERSION=11.0.6
ARG PNPM_VERSION=11.1.1
RUN corepack enable \
&& corepack prepare "pnpm@${PNPM_VERSION}" --activate