Add build-scan-push workflow
Build Docker Image & Security / build-scan-push (push) Successful in 2m21s

This commit is contained in:
2026-07-07 11:27:14 +01:00
parent 890a16aef9
commit 68223b681a
+169
View File
@@ -0,0 +1,169 @@
name: Build Docker Image & Security
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build-scan-push:
runs-on: running-man
env:
# The image is under "homelab" namespace so it can stay private
IMAGE: git.sysmd.uk/homelab/sysmd-games:latest
COSIGN_VERSION: v3.0.5
GRYPE_VERSION: v0.110.0
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Login to registry
run: |
echo "$REGISTRY_TOKEN" | docker login git.sysmd.uk -u "$REGISTRY_USER" --password-stdin
env:
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
- name: Build image
run: |
docker build --no-cache -t ${IMAGE} .
- 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
continue-on-error: true
run: |
grype ${IMAGE} -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 only on fixable HIGH/CRITICAL
jq -e '
[
.matches[]
| select(
(
.vulnerability.severity == "High" or
.vulnerability.severity == "Critical"
)
and
(
(.vulnerability.fix.versions | length) > 0
)
)
]
| length == 0
' grype.json
- name: Notify Node-RED on vulnerabilities
if: steps.grype.outcome == 'failure'
run: |
jq '
{
repo: "mdaleo404/games",
image: "'${IMAGE}'",
summary: (
"Total: " +
(
[
.matches[]
| select(
(
.vulnerability.severity == "High" or
.vulnerability.severity == "Critical"
)
and
(
(.vulnerability.fix.versions | length) > 0
)
)
] | length | tostring
)
),
vulnerabilities: [
.matches[]
| select(
(
.vulnerability.severity == "High" or
.vulnerability.severity == "Critical"
)
and
(
(.vulnerability.fix.versions | length) > 0
)
)
| {
library: .artifact.name,
cve: .vulnerability.id,
severity: .vulnerability.severity,
installed: .artifact.version,
fixed: (.vulnerability.fix.versions[0]),
title: .vulnerability.description,
url: .vulnerability.dataSource
}
]
}
' grype.json \
| curl -s -X POST https://nodered.sysmd.uk/vulns-alert \
-H "Content-Type: application/json" \
--data-binary @-
- name: Fail workflow if vulnerabilities found
if: steps.grype.outcome == 'failure'
run: exit 1
- name: Push image
if: steps.grype.outcome != 'failure'
run: |
docker push ${IMAGE}
- name: Deploy to server
if: steps.grype.outcome != 'failure'
uses: appleboy/ssh-action@v1.2.0
with:
host: ${{ secrets.DEPLOYMENT_HOST }}
username: ${{ secrets.DEPLOYMENT_USER }}
key: ${{ secrets.DEPLOYMENT_SSH_KEY }}
port: ${{ secrets.DEPLOYMENT_SSH_PORT }}
script: |
sudo docker compose -f /opt/sysmd-games/docker-compose.yml pull && \
sudo docker compose -f /opt/sysmd-games/docker-compose.yml up -d
host_key: 'false'