Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/container-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
context_path: "simplerisk/"
dockerfile_path: "simplerisk/Dockerfile"
image_tag: "simplerisk/simplerisk:testing"
build_args: "ubuntu_version_code=jammy"
build_args: "ubuntu_version_code=jammy\nPREGA_BUNDLE_FALLBACK=true"

simplerisk-noble:
name: 'Verify simplerisk/simplerisk image based on Ubuntu 24.04 (Noble)'
Expand All @@ -22,7 +22,7 @@ jobs:
context_path: "simplerisk/"
dockerfile_path: "simplerisk/Dockerfile"
image_tag: "simplerisk/simplerisk:testing"
build_args: "ubuntu_version_code=noble"
build_args: "ubuntu_version_code=noble\nPREGA_BUNDLE_FALLBACK=true"

simplerisk-minimal-php84:
name: 'Verify simplerisk/simplerisk-minimal image based on PHP 8.3 with Apache'
Expand All @@ -31,7 +31,7 @@ jobs:
context_path: "simplerisk-minimal/"
dockerfile_path: "simplerisk-minimal/Dockerfile"
image_tag: "simplerisk/simplerisk-minimal:testing"
build_args: "php_version=8.3"
build_args: "php_version=8.3\nPREGA_BUNDLE_FALLBACK=true"

simplerisk-minimal-php85:
name: 'Verify simplerisk/simplerisk-minimal image based on PHP 8.4 with Apache'
Expand All @@ -40,4 +40,4 @@ jobs:
context_path: "simplerisk-minimal/"
dockerfile_path: "simplerisk-minimal/Dockerfile"
image_tag: "simplerisk/simplerisk-minimal:testing"
build_args: "php_version=8.4"
build_args: "php_version=8.4\nPREGA_BUNDLE_FALLBACK=true"
14 changes: 12 additions & 2 deletions simplerisk-minimal/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,20 @@ ARG php_version=8.4

FROM alpine/curl:8.12.1 AS downloader

# PREGA_BUNDLE_FALLBACK is a CI-ONLY switch, default false. Pre-GA the prod bundle
# for a new version does not exist yet (it lands in public/bundles/ only at GA). CI
# sets this true so a pre-GA build can fall back to the testing bundle WITHOUT hash
# verification (the release has no published hash yet). A released image is ALWAYS
# built from the VERIFIED prod bundle and NEVER from unverified testing bytes.
ARG PREGA_BUNDLE_FALLBACK=false

SHELL [ "/bin/ash", "-eo", "pipefail", "-c" ]

RUN mkdir -p /var/www && \
curl -sL https://simplerisk-downloads.s3.amazonaws.com/public/bundles/simplerisk-20260519-001.tgz | tar xz -C /var/www
# Download the prod bundle, verify its published sha256 (md5 fallback) from the
# updates feed, then extract -- fail-closed unless PREGA_BUNDLE_FALLBACK allows the
# pre-GA path. See common/download_and_verify_bundle.sh.
COPY common/download_and_verify_bundle.sh /download_and_verify_bundle.sh
RUN PREGA_BUNDLE_FALLBACK="$PREGA_BUNDLE_FALLBACK" sh /download_and_verify_bundle.sh 20260519-001

FROM php:${php_version}-apache

Expand Down
61 changes: 61 additions & 0 deletions simplerisk-minimal/common/download_and_verify_bundle.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/bin/sh
# Download the released SimpleRisk bundle for the given version, verify it against
# the sha256 (md5 fallback) published in the production updates feed, then extract
# it into /var/www. Run from the alpine/curl downloader stage of the generated
# Dockerfile.
#
# Fail-closed by default: a RELEASED image (PREGA_BUNDLE_FALLBACK unset/false) is
# built ONLY from the prod bundle and ONLY if it matches its published hash -- a
# missing prod bundle, a missing feed hash, or a mismatch aborts the build, so a
# swapped S3 object can never be baked into a published image. The bundle (S3
# public/bundles) and its hash (served updates feed) are stored independently.
#
# PRE-GA CI ONLY: before GA the prod bundle/hash for a new version do not exist
# yet (they land at GA). When PREGA_BUNDLE_FALLBACK=true AND the prod bundle is
# absent, fall back to the testing bundle WITHOUT verification (there is no
# published hash to check yet) and warn loudly. This path is never taken for a
# released image.
set -eu

VERSION="${1:?usage: download_and_verify_bundle.sh <YYYYMMDD-NNN>}"
case "$VERSION" in
[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9]) : ;;
*) echo "ERROR: bad version format: $VERSION" >&2; exit 1 ;;
esac

FEED="https://updates.simplerisk.com/releases.xml"
PROD_URL="https://simplerisk-downloads.s3.amazonaws.com/public/bundles/simplerisk-${VERSION}.tgz"
TEST_URL="https://bundles-test.simplerisk.com/simplerisk-${VERSION}.tgz"
TGZ="/tmp/simplerisk-${VERSION}.tgz"

if curl -fsSL -o "$TGZ" "$PROD_URL"; then
echo "Downloaded prod bundle for ${VERSION}; resolving published hash from ${FEED} ..."
ENTRY="$(curl -fsSL "$FEED" | sed -n "/<release version=\"${VERSION}\">/,/<\/release>/p")"
EXPECTED="$(printf '%s\n' "$ENTRY" | grep -oE '<bundle_sha256>[0-9a-f]{64}</bundle_sha256>' | grep -oE '[0-9a-f]{64}' | head -1 || true)"
ALGO=sha256
if [ -z "$EXPECTED" ]; then
EXPECTED="$(printf '%s\n' "$ENTRY" | grep -oE '<bundle_md5>[0-9a-f]{32}</bundle_md5>' | grep -oE '[0-9a-f]{32}' | head -1 || true)"
ALGO=md5
fi
if [ -z "$EXPECTED" ]; then
echo "ERROR: no bundle_sha256 or bundle_md5 for ${VERSION} in ${FEED} -- refusing to extract an unverifiable prod bundle" >&2
exit 1
fi
ACTUAL="$(${ALGO}sum "$TGZ" | cut -d' ' -f1)"
if [ "$ACTUAL" != "$EXPECTED" ]; then
echo "ERROR: bundle ${ALGO} mismatch for ${VERSION} -- expected ${EXPECTED}, got ${ACTUAL}" >&2
exit 1
fi
echo "Bundle ${ALGO} verified (${ACTUAL})."
elif [ "${PREGA_BUNDLE_FALLBACK:-false}" = "true" ]; then
echo "WARNING: prod bundle simplerisk-${VERSION}.tgz absent -- PRE-GA CI fallback to bundles-test (UNVERIFIED: the release has no published hash yet)." >&2
curl -fsSL -o "$TGZ" "$TEST_URL"
else
echo "ERROR: prod bundle simplerisk-${VERSION}.tgz not found and PREGA_BUNDLE_FALLBACK != true -- refusing to build a release from unverified bytes" >&2
exit 1
fi

mkdir -p /var/www
tar xzf "$TGZ" -C /var/www
rm -f "$TGZ"
echo "Extracted bundle to /var/www."
14 changes: 12 additions & 2 deletions simplerisk-minimal/generate_dockerfile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,20 @@ if [ "$release" != "testing" ]; then
cat << EOF >> "${SCRIPT_LOCATION}/Dockerfile"
FROM alpine/curl:8.12.1 AS downloader

# PREGA_BUNDLE_FALLBACK is a CI-ONLY switch, default false. Pre-GA the prod bundle
# for a new version does not exist yet (it lands in public/bundles/ only at GA). CI
# sets this true so a pre-GA build can fall back to the testing bundle WITHOUT hash
# verification (the release has no published hash yet). A released image is ALWAYS
# built from the VERIFIED prod bundle and NEVER from unverified testing bytes.
ARG PREGA_BUNDLE_FALLBACK=false

SHELL [ "/bin/ash", "-eo", "pipefail", "-c" ]

RUN mkdir -p /var/www && \\
curl -sL https://simplerisk-downloads.s3.amazonaws.com/public/bundles/simplerisk-$release.tgz | tar xz -C /var/www
# Download the prod bundle, verify its published sha256 (md5 fallback) from the
# updates feed, then extract -- fail-closed unless PREGA_BUNDLE_FALLBACK allows the
# pre-GA path. See common/download_and_verify_bundle.sh.
COPY common/download_and_verify_bundle.sh /download_and_verify_bundle.sh
RUN PREGA_BUNDLE_FALLBACK="\$PREGA_BUNDLE_FALLBACK" sh /download_and_verify_bundle.sh $release

EOF
fi
Expand Down
13 changes: 10 additions & 3 deletions simplerisk/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,18 @@ FROM alpine/curl:8.12.1 AS downloader

ARG DB_LANG=en

# CI-ONLY pre-GA switch (default false) -- see common/download_and_verify_bundle.sh.
ARG PREGA_BUNDLE_FALLBACK=false

SHELL [ "/bin/ash", "-eo", "pipefail", "-c" ]

RUN mkdir -p /var/www && \
curl -sL https://simplerisk-downloads.s3.amazonaws.com/public/bundles/simplerisk-20260519-001.tgz | tar xz -C /var/www && \
curl -sL "https://github.com/simplerisk/database/raw/master/simplerisk-$DB_LANG-20260519-001.sql" > /simplerisk.sql
# Download the prod bundle, verify its published sha256 (md5 fallback) from the
# updates feed, then extract (fail-closed) -- then fetch the release SQL schema.
# -fsSL on the SQL fetch too: without --fail, curl writes the 404 body into
# /simplerisk.sql and the image ships an HTML error page as its schema.
COPY common/download_and_verify_bundle.sh /download_and_verify_bundle.sh
RUN PREGA_BUNDLE_FALLBACK="$PREGA_BUNDLE_FALLBACK" sh /download_and_verify_bundle.sh 20260519-001 && \
curl -fsSL "https://github.com/simplerisk/database/raw/master/simplerisk-$DB_LANG-20260519-001.sql" > /simplerisk.sql

# Using Ubuntu image
FROM ubuntu:${ubuntu_version_code}
Expand Down
61 changes: 61 additions & 0 deletions simplerisk/common/download_and_verify_bundle.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/bin/sh
# Download the released SimpleRisk bundle for the given version, verify it against
# the sha256 (md5 fallback) published in the production updates feed, then extract
# it into /var/www. Run from the alpine/curl downloader stage of the generated
# Dockerfile.
#
# Fail-closed by default: a RELEASED image (PREGA_BUNDLE_FALLBACK unset/false) is
# built ONLY from the prod bundle and ONLY if it matches its published hash -- a
# missing prod bundle, a missing feed hash, or a mismatch aborts the build, so a
# swapped S3 object can never be baked into a published image. The bundle (S3
# public/bundles) and its hash (served updates feed) are stored independently.
#
# PRE-GA CI ONLY: before GA the prod bundle/hash for a new version do not exist
# yet (they land at GA). When PREGA_BUNDLE_FALLBACK=true AND the prod bundle is
# absent, fall back to the testing bundle WITHOUT verification (there is no
# published hash to check yet) and warn loudly. This path is never taken for a
# released image.
set -eu

VERSION="${1:?usage: download_and_verify_bundle.sh <YYYYMMDD-NNN>}"
case "$VERSION" in
[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9]) : ;;
*) echo "ERROR: bad version format: $VERSION" >&2; exit 1 ;;
esac

FEED="https://updates.simplerisk.com/releases.xml"
PROD_URL="https://simplerisk-downloads.s3.amazonaws.com/public/bundles/simplerisk-${VERSION}.tgz"
TEST_URL="https://bundles-test.simplerisk.com/simplerisk-${VERSION}.tgz"
TGZ="/tmp/simplerisk-${VERSION}.tgz"

if curl -fsSL -o "$TGZ" "$PROD_URL"; then
echo "Downloaded prod bundle for ${VERSION}; resolving published hash from ${FEED} ..."
ENTRY="$(curl -fsSL "$FEED" | sed -n "/<release version=\"${VERSION}\">/,/<\/release>/p")"
EXPECTED="$(printf '%s\n' "$ENTRY" | grep -oE '<bundle_sha256>[0-9a-f]{64}</bundle_sha256>' | grep -oE '[0-9a-f]{64}' | head -1 || true)"
ALGO=sha256
if [ -z "$EXPECTED" ]; then
EXPECTED="$(printf '%s\n' "$ENTRY" | grep -oE '<bundle_md5>[0-9a-f]{32}</bundle_md5>' | grep -oE '[0-9a-f]{32}' | head -1 || true)"
ALGO=md5
fi
if [ -z "$EXPECTED" ]; then
echo "ERROR: no bundle_sha256 or bundle_md5 for ${VERSION} in ${FEED} -- refusing to extract an unverifiable prod bundle" >&2
exit 1
fi
ACTUAL="$(${ALGO}sum "$TGZ" | cut -d' ' -f1)"
if [ "$ACTUAL" != "$EXPECTED" ]; then
echo "ERROR: bundle ${ALGO} mismatch for ${VERSION} -- expected ${EXPECTED}, got ${ACTUAL}" >&2
exit 1
fi
echo "Bundle ${ALGO} verified (${ACTUAL})."
elif [ "${PREGA_BUNDLE_FALLBACK:-false}" = "true" ]; then
echo "WARNING: prod bundle simplerisk-${VERSION}.tgz absent -- PRE-GA CI fallback to bundles-test (UNVERIFIED: the release has no published hash yet)." >&2
curl -fsSL -o "$TGZ" "$TEST_URL"
else
echo "ERROR: prod bundle simplerisk-${VERSION}.tgz not found and PREGA_BUNDLE_FALLBACK != true -- refusing to build a release from unverified bytes" >&2
exit 1
fi

mkdir -p /var/www
tar xzf "$TGZ" -C /var/www
rm -f "$TGZ"
echo "Extracted bundle to /var/www."
13 changes: 10 additions & 3 deletions simplerisk/generate_dockerfile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,18 @@ FROM alpine/curl:8.12.1 AS downloader

ARG DB_LANG=en

# CI-ONLY pre-GA switch (default false) -- see common/download_and_verify_bundle.sh.
ARG PREGA_BUNDLE_FALLBACK=false

SHELL [ "/bin/ash", "-eo", "pipefail", "-c" ]

RUN mkdir -p /var/www && \\
curl -sL https://simplerisk-downloads.s3.amazonaws.com/public/bundles/simplerisk-$release.tgz | tar xz -C /var/www && \\
curl -sL "https://github.com/simplerisk/database/raw/master/simplerisk-\$DB_LANG-$release.sql" > /simplerisk.sql
# Download the prod bundle, verify its published sha256 (md5 fallback) from the
# updates feed, then extract (fail-closed) -- then fetch the release SQL schema.
# -fsSL on the SQL fetch too: without --fail, curl writes the 404 body into
# /simplerisk.sql and the image ships an HTML error page as its schema.
COPY common/download_and_verify_bundle.sh /download_and_verify_bundle.sh
RUN PREGA_BUNDLE_FALLBACK="\$PREGA_BUNDLE_FALLBACK" sh /download_and_verify_bundle.sh $release && \\
curl -fsSL "https://github.com/simplerisk/database/raw/master/simplerisk-\$DB_LANG-$release.sql" > /simplerisk.sql

EOF
fi
Expand Down