Compare commits

...
10 Commits
Author SHA1 Message Date
mdaleo404 e05e6a34cd Merge pull request 'Update Node.js to 2117f71' (#5) from renovate/container-image-digests into main
Build, Scan & Publish Dev / build-scan-push (push) Successful in 12m55s
Reviewed-on: #5
2026-10-29 06:37:06 +00:00
kamabot dc1c2d2766 Update Node.js to 2117f71
CI / test (pull_request) Successful in 1m2s
2026-10-29 03:03:01 +00:00
mdaleo404 520cf73c13 Merge pull request 'Update Node.js to 96c9160' (#4) from renovate/container-image-digests into main
Build, Scan & Publish Dev / build-scan-push (push) Successful in 12m52s
Reviewed-on: #4
2026-10-28 10:13:08 +00:00
kamabot 44f539a9dc Update Node.js to 96c9160
CI / test (pull_request) Successful in 1m42s
2026-10-28 03:02:43 +00:00
mdaleo404 e056c864ed Merge pull request 'Update Node.js to 8eb619e' (#3) from renovate/container-image-digests into main
Build, Scan & Publish Dev / build-scan-push (push) Successful in 12m55s
Reviewed-on: #3
2026-10-22 05:41:41 +00:00
kamabot aa0468a219 Update Node.js to 8eb619e
CI / test (pull_request) Successful in 1m38s
2026-10-22 03:15:55 +00:00
mdaleo404 6a3e01e127 Add .gitignore
Build, Scan & Publish Dev / build-scan-push (push) Successful in 13m19s
2026-10-12 07:12:03 +01:00
mdaleo404 853103d93d Merge pull request 'chore(grype): reconcile ignores for kovi' (#2) from chore/reconcile-grype into main
Build, Scan & Publish Dev / build-scan-push (push) Successful in 12m44s
Reviewed-on: #2
2026-10-10 17:57:05 +00:00
kamabot 866cf4ca50 chore(grype): reconcile ignores for kovi
CI / test (pull_request) Successful in 1m48s
2026-10-10 17:54:04 +00:00
mdaleo404 41512c340c Split build workflow to integrate dev build
Build, Scan & Publish Dev / build-scan-push (push) Successful in 12m22s
2026-10-10 18:41:55 +01:00
6 changed files with 147 additions and 170 deletions

No files matched your search

-169
View File
@@ -1,169 +0,0 @@
name: Build, Scan & Publish Image
# Publishing a Gitea release (for example with tag 2026.09.25) builds the image,
# scans it with Grype (fails on fixable HIGH/CRITICAL findings), and pushes it to
# this repository's registry. A release pushes the release tag plus "latest"
# (non-prereleases only). A manual run builds and pushes only the tag supplied
# in the input.
on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: Image tag to build and push when run manually
required: false
default: latest
concurrency:
group: image-${{ github.ref }}
cancel-in-progress: false
jobs:
build-scan-push:
runs-on: running-man
env:
REGISTRY: git.sysmd.uk
IMAGE: git.sysmd.uk/mdaleo404/kovi
COSIGN_VERSION: v3.0.5
GRYPE_VERSION: v0.110.0
steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false
submodules: false
fetch-depth: 0
- name: Resolve release tag
env:
EVENT_TAG: ${{ github.event.release.tag_name }}
INPUT_TAG: ${{ github.event.inputs.tag }}
run: |
set -euo pipefail
TAG="${EVENT_TAG:-}"
if [ -z "$TAG" ]; then TAG="${INPUT_TAG:-}"; fi
if [ -z "$TAG" ]; then TAG="${GITHUB_REF_NAME:-}"; fi
if [ -z "$TAG" ]; then TAG="$(git describe --tags --exact-match 2>/dev/null || echo "")"; fi
if [ -z "$TAG" ]; then echo "Could not determine a tag for this run." >&2; exit 1; fi
SAFE_TAG="${TAG//\//-}"
case "$SAFE_TAG" in
[A-Za-z0-9_]*) ;;
*) SAFE_TAG="v$SAFE_TAG" ;;
esac
{
echo "TAG=$SAFE_TAG"
echo "IMAGE_REF=${IMAGE}:${SAFE_TAG}"
} >> "$GITHUB_ENV"
if [ -n "${EVENT_TAG:-}" ] && [ "${{ github.event.release.prerelease }}" != "true" ]; then
echo "PUSH_LATEST=1" >> "$GITHUB_ENV"
fi
echo "Resolved image reference: ${IMAGE}:${SAFE_TAG}"
- name: Login to registry
run: |
echo "$REGISTRY_TOKEN" | docker login "${REGISTRY}" -u "$REGISTRY_USER" --password-stdin
env:
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build image
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: |
set -euo pipefail
TAGS=(-t "${IMAGE_REF}")
if [ "${PUSH_LATEST:-}" = "1" ]; then TAGS+=(-t "${IMAGE}:latest"); fi
docker buildx build \
--load \
--no-cache \
--secret id=gitea_token,env=GITEA_TOKEN \
"${TAGS[@]}" \
.
- name: Install Cosign
run: |
set -euo pipefail
curl -fLO "https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign-linux-amd64"
chmod +x cosign-linux-amd64
mv cosign-linux-amd64 /usr/local/bin/cosign
- name: Install Grype
run: |
set -euo pipefail
VERSION_NO_V="${GRYPE_VERSION#v}"
FILE="grype_${VERSION_NO_V}_linux_amd64.tar.gz"
BASE="https://github.com/anchore/grype/releases/download/${GRYPE_VERSION}"
curl -fLO "${BASE}/${FILE}"
curl -fLO "${BASE}/grype_${VERSION_NO_V}_checksums.txt"
curl -fLO "${BASE}/grype_${VERSION_NO_V}_checksums.txt.sig"
curl -fLO "${BASE}/grype_${VERSION_NO_V}_checksums.txt.pem"
cosign verify-blob \
--signature "grype_${VERSION_NO_V}_checksums.txt.sig" \
--certificate "grype_${VERSION_NO_V}_checksums.txt.pem" \
--certificate-identity-regexp "https://github.com/anchore/grype" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
"grype_${VERSION_NO_V}_checksums.txt"
CHECK=$(grep " ${FILE}$" "grype_${VERSION_NO_V}_checksums.txt")
[ -n "$CHECK" ] || { echo "Missing checksum"; exit 1; }
echo "$CHECK" | sha256sum -c -
tar -xzf "${FILE}"
mv grype /usr/local/bin/
- name: Scan image with Grype
id: grype
run: |
grype "${IMAGE_REF}" -o json > grype.json
echo "Fixable HIGH/CRITICAL vulnerabilities:"
jq -r '
.matches[]
| select(
(
.vulnerability.severity == "High" or
.vulnerability.severity == "Critical"
)
and
(
(.vulnerability.fix.versions | length) > 0
)
)
| "\(.artifact.name)@\(.artifact.version) -> \(.vulnerability.id) [\(.vulnerability.severity)] | fixed: \(.vulnerability.fix.versions[0])"
' grype.json
# Fail the build on fixable HIGH/CRITICAL vulnerabilities.
COUNT=$(jq '
[
.matches[]
| select(
(
.vulnerability.severity == "High" or
.vulnerability.severity == "Critical"
)
and
(
(.vulnerability.fix.versions | length) > 0
)
)
]
| length
' grype.json)
echo "Fixable HIGH/CRITICAL count: ${COUNT}"
if [ "$COUNT" != "0" ]; then
echo "::error::Grype found ${COUNT} fixable HIGH/CRITICAL vulnerabilities."
exit 1
fi
- name: Push image
run: |
docker push "${IMAGE_REF}"
if [ "${PUSH_LATEST:-}" = "1" ]; then docker push "${IMAGE}:latest"; fi
+91
View File
@@ -0,0 +1,91 @@
name: Build, Scan & Publish Dev
# Build, scan, and reconcile on push to main and nightly. Publishes a moving
# "dev" tag on real pushes only, once the reconciler gate passes.
on:
push:
branches:
- main
schedule:
- cron: "0 3 * * *"
workflow_dispatch:
concurrency:
group: image-main
cancel-in-progress: false
jobs:
build-scan-push:
runs-on: running-man
env:
REGISTRY: git.sysmd.uk
IMAGE: git.sysmd.uk/mdaleo404/kovi
steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false
submodules: false
fetch-depth: 0
- name: Resolve dev tag
run: |
set -euo pipefail
echo "IMAGE_REF=${IMAGE}:dev" >> "$GITHUB_ENV"
echo "Dev image: ${IMAGE}:dev"
- name: Login to registry
run: |
echo "$REGISTRY_TOKEN" | docker login "${REGISTRY}" -u "$REGISTRY_USER" --password-stdin
env:
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build image
run: |
set -euo pipefail
docker buildx build --load --no-cache -t "${IMAGE_REF}" .
- name: Install Grype
uses: https://git.sysmd.uk/mdaleo404/actions/install-grype@v1
- name: Scan image with Grype
id: scan
continue-on-error: true
uses: https://git.sysmd.uk/mdaleo404/actions/scan-image@v1
with:
image: ${{ env.IMAGE_REF }}
fail-on-fixable: 'false'
- name: Reconcile Grype ignores
id: reconcile
continue-on-error: true
env:
GITEA_TOKEN: ${{ secrets.AUTOUPDATE_TOKEN }}
run: |
set -euo pipefail
curl -fsSL -H "Authorization: token ${GITEA_TOKEN}" \
"https://git.sysmd.uk/api/v1/repos/Homelab/renovate-runner/raw/scripts/reconcile-grype.sh?ref=main" \
-o /tmp/reconcile-grype.sh
bash /tmp/reconcile-grype.sh
- name: Notify Node-RED on vulnerabilities
if: steps.reconcile.outcome == 'failure'
run: |
jq -n --arg repo "${GITHUB_REPOSITORY,,}" '{ repo: $repo }' \
| curl -s -X POST https://nodered.sysmd.uk/vulns-alert \
-H "Content-Type: application/json" \
--data-binary @-
- name: Fail on actionable vulnerabilities
if: steps.reconcile.outcome == 'failure'
run: exit 1
- name: Push dev image
if: github.event_name != 'schedule' && steps.reconcile.outcome != 'failure'
run: |
set -euo pipefail
docker push "${IMAGE_REF}"
+50
View File
@@ -0,0 +1,50 @@
name: Publish Release Image
# Promote the scanned dev image to the release tag (and latest); never rebuilds.
on:
release:
types: [published]
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
jobs:
promote:
runs-on: running-man
env:
REGISTRY: git.sysmd.uk
IMAGE: git.sysmd.uk/mdaleo404/kovi
steps:
- name: Login to registry
run: |
echo "$REGISTRY_TOKEN" | docker login "${REGISTRY}" -u "$REGISTRY_USER" --password-stdin
env:
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Resolve tags
env:
EVENT_TAG: ${{ github.event.release.tag_name }}
PRERELEASE: ${{ github.event.release.prerelease }}
run: |
set -euo pipefail
TAG="${EVENT_TAG:?release tag missing}"
{
echo "TAG=${TAG}"
echo "SOURCE_REF=${IMAGE}:dev"
} >> "$GITHUB_ENV"
if [ "${PRERELEASE:-}" != "true" ]; then
echo "PUSH_LATEST=1" >> "$GITHUB_ENV"
fi
echo "Promoting ${IMAGE}:dev -> ${IMAGE}:${TAG}"
- name: Promote image
run: |
set -euo pipefail
TAGS=(-t "${IMAGE}:${TAG}")
if [ "${PUSH_LATEST:-}" = "1" ]; then TAGS+=(-t "${IMAGE}:latest"); fi
docker buildx imagetools create "${TAGS[@]}" "${SOURCE_REF}"
+2
View File
@@ -0,0 +1,2 @@
data/
tests/fixture-statistics.sqlite3
+3
View File
@@ -0,0 +1,3 @@
# Managed by renovate-runner/scripts/reconcile-grype.sh - do not edit by hand.
# Entries are High,Critical findings with a fix that no base image update provides.
ignore: []
+1 -1
View File
@@ -1,4 +1,4 @@
FROM node:22-trixie-slim@sha256:154ba2f4d6fec323d28e4f4bb86bba4677f1223391a1979cf521304e03a98dfa
FROM node:22-trixie-slim@sha256:2117f713a417f3aff682ac8f5bc2ebbdf1beed51f36e67ab1e0fd3866b6d2d8f
# kovi does not vendor or copy Calibre code. The container installs Debian's
# unmodified Calibre package and calls its fetch-ebook-metadata CLI as a separate