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
12 changes: 12 additions & 0 deletions .github/workflows/build-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ on:
node-mirror-token:
description: Authorization header value for `node-mirror`.
required: false
ca-certificates:
description: >-
Extra CA certificates (PEM) the image build trusts while `apk upgrade`
fetches Alpine fixes — a TLS-intercepting proxy's CA, say. Written
to trusted_certs/ before `docker build`; see the Dockerfile.
required: false
outputs:
image:
description: 'The first pushed image reference, when one was pushed.'
Expand Down Expand Up @@ -251,9 +257,15 @@ jobs:
KB_IMAGE: ${{ inputs.image-name }}
KB_TAGS: ${{ inputs.image-tags }}
KB_SHA: ${{ github.sha }}
KB_CA_CERTIFICATES: ${{ secrets.ca-certificates }}
run: |
set -euo pipefail

# The Dockerfile trusts every *.pem in trusted_certs/ for its apk step.
if [ -n "${KB_CA_CERTIFICATES:-}" ]; then
printf '%s\n' "$KB_CA_CERTIFICATES" > trusted_certs/ca-certificates.pem
fi

tags="${KB_TAGS:-$KB_SHA}"
# Accept either separator; normalise to one tag per line.
tags="$(printf '%s' "$tags" | tr ',' '\n' | sed '/^[[:space:]]*$/d')"
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ test-results/
public/
# Copied from node_modules by scripts/setup-test-apps.mjs on every run.
tests/fixtures/single-page-bundle/*/assets/mermaid.min.js

# Local CA certificates for the image build (see Dockerfile); never committed.
trusted_certs/*
!trusted_certs/.gitkeep
16 changes: 15 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,22 @@ FROM nginxinc/nginx-unprivileged:1.31-alpine@sha256:b5047b9b76845eac124358373c68
# digest pin keeps nginx itself fixed, but upstream rebuilds only every few
# weeks, and a CVE fixed in an Alpine package fails the Trivy scan until then.
# The image runs as UID 101, so switch to root for the upgrade and back after.
#
#
# Behind a TLS-intercepting proxy apk fails with "server certificate not
# trusted". Drop the proxy's CA (PEM, *.pem or *.crt) into trusted_certs/, or
# point TRUSTED_SSL_CERTS at another directory in the build context
# (`docker build --build-arg TRUSTED_SSL_CERTS=./my-certs .`); every file there
# is appended to the system CA bundle before apk runs. The committed directory
# is empty, so a build without one trusts the public CAs only.
ARG TRUSTED_SSL_CERTS=./trusted_certs
COPY $TRUSTED_SSL_CERTS /opt/certs/
USER root
RUN apk upgrade --no-cache
RUN for CERT_PATH in /opt/certs/*.pem /opt/certs/*.crt; do \
[ -e "$CERT_PATH" ] || continue; \
{ cat "$CERT_PATH"; echo; } >> /etc/ssl/certs/ca-certificates.crt; \
done \
&& apk upgrade --no-cache
USER 101

# Overwrite the stock config rather than `RUN rm`-ing it: this image drops to a
Expand Down
2 changes: 2 additions & 0 deletions contract/DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,13 +178,15 @@ three more things and changes nothing else:
npm-token: ${{ secrets.ARTIFACTORY_TOKEN }}
registry-username: ${{ secrets.ARTIFACTORY_USER }}
registry-password: ${{ secrets.ARTIFACTORY_TOKEN }}
ca-certificates: ${{ secrets.CORP_CA_PEM }} # behind a TLS-intercepting proxy
```

| Input | What it covers |
|---|---|
| `runs-on` | A single label as it is; a JSON array or object for several labels or a runner group. Default `ubuntu-latest`. |
| `npm-registry`, `npm-token` (secret) | The `npm ci` of the build's own dependencies. Empty means whatever npm resolves on the runner. |
| `node-mirror`, `node-mirror-token` (secret) | Where `setup-node` downloads Node when it can reach neither the github.com release assets it tries first nor nodejs.org. A mirror of `https://nodejs.org` — an Artifactory generic remote. Not needed when the runner image carries Node 24 in its tool cache. |
| `ca-certificates` (secret) | Extra CA certificates (PEM) for the image build's `apk upgrade`, which otherwise fails behind a TLS-intercepting proxy with `TLS: server certificate not trusted` (exit 99): the base image trusts public CAs only. Written to `trusted_certs/` before `docker build`; the Dockerfile appends every `*.pem`/`*.crt` there to the system CA bundle. A pipeline running `docker build` itself drops the files into `trusted_certs/`, or passes `--build-arg TRUSTED_SSL_CERTS=<dir>`. The certificates stay in the image. |

The publishing actions take the same four inputs, so docs repos on the same
runners publish the same way (`actions/publish-docs/README.md`,
Expand Down
5 changes: 4 additions & 1 deletion tests/private-registry.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,16 @@ test.describe('the private-registry inputs exist on every shared CI piece', () =
for (const input of ['runs-on', 'npm-registry', 'node-mirror']) {
expect(text).toContain(`\n ${input}:\n`);
}
for (const secret of ['npm-token', 'node-mirror-token']) {
for (const secret of ['npm-token', 'node-mirror-token', 'ca-certificates']) {
expect(text).toContain(`\n ${secret}:\n`);
}
expect(text).toContain('KB_NPM_REGISTRY: ${{ inputs.npm-registry }}');
expect(text.split('KB_NPM_TOKEN: ${{ secrets.npm-token }}').length - 1).toBe(2);
expect(text).toContain('mirror: ${{ inputs.node-mirror }}');
expect(text).toContain('mirror-token: ${{ secrets.node-mirror-token }}');
// The proxy CA reaches the Dockerfile's apk step through trusted_certs/.
expect(text).toContain('> trusted_certs/ca-certificates.pem');
expect(read('Dockerfile')).toContain('ARG TRUSTED_SSL_CERTS=./trusted_certs');
expect(text).toMatch(/runs-on: \$\{\{ .*fromJSON\(inputs\.runs-on\).*inputs\.runs-on \}\}/);
// The workflow inlines the script's logic; keep the two token lines identical
// so a fix to one cannot silently miss the other.
Expand Down
Empty file added trusted_certs/.gitkeep
Empty file.
Loading