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
121 changes: 45 additions & 76 deletions .github/workflows/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,103 +23,98 @@ env:
jobs:
build:
name: "Build: ${{ matrix.version }}/${{ matrix.arch }}"
runs-on: ubuntu-20.04
runs-on: ${{ matrix.runner }}

strategy:
fail-fast: false # Don't cancel other jobs if one fails
matrix:
include:
-
platform: linux/amd64
arch: amd64
version: "2.4"
runner: ubuntu-24.04
-
platform: linux/arm64
arch: arm64
version: "2.4"
runner: ubuntu-24.04-arm

env:
ARCH: ${{ matrix.arch }}
VERSION_PREFIX: ""
VERSION: ${{ matrix.version }}
UPSTREAM_IMAGE: httpd:${{ matrix.version }}-alpine
BUILD_DIR: "."

steps:
-
name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v6
-
name: Environment variables
run: |
# Export variables for further steps
echo GIT_SHA7="${GITHUB_SHA:0:7}" | tee -a ${GITHUB_ENV}
echo BUILD_IMAGE_TAG="${IMAGE}:${VERSION_PREFIX}${VERSION}-build" | tee -a ${GITHUB_ENV}
# Pull the host public SSH key at runtime instead of relying on a static value stored in secrets.
echo ARM64_HOST_SSH_CERT="$(ssh-keyscan -t rsa ${{ secrets.ARM64_HOST }} 2>/dev/null)" | tee -a ${GITHUB_ENV}
# -
# # Switch docker context to a remote arm64 host
# # Used for building heavy images that take too long to build using QEMU + for native arm64 testing.
# name: Switch to arm64 builder host
# if: ${{ env.ARCH == 'arm64' }}
# uses: arwynfr/actions-docker-context@v2
# with:
# docker_host: "ssh://ubuntu@${{ secrets.ARM64_HOST }}"
# context_name: arm64-host
# ssh_key: "${{ secrets.ARM64_HOST_SSH_KEY }}"
# ssh_cert: "${{ env.ARM64_HOST_SSH_CERT }}"
# use_context: true
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v4
-
name: Check Docker
run: |
docker version
docker info
-
name: Login to Docker Hub
uses: docker/login-action@v1
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
# Build and cache image in the registry
name: Build image
uses: docker/build-push-action@v2
uses: docker/build-push-action@v7
with:
context: ${{ env.BUILD_DIR }}
file: ${{ env.BUILD_DIR }}/Dockerfile
build-args: |
UPSTREAM_IMAGE=${{ env.UPSTREAM_IMAGE }}
VERSION=${{ env.VERSION }}
platforms: linux/${{ env.ARCH }}
# Push intermediate arch-specific build tag to repo
tags: ${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-${{ env.ARCH }}
push: ${{ github.event_name != 'pull_request' }} # Don't push for PRs
# Disable automatic image attestations
# With image attestations enabled, the image tag pushed to the registry is a manifest list.
# That makes it impossible to stitch different platform images together in a manifest list, since you
# cannot have a manifest list of manifest lists.
# See https://docs.docker.com/build/attestations/attestation-storage/
# TODO: Refactor to allow for image attestations
provenance: false
sbom: false
# BUILD_IMAGE_TAG - persistent multi-arch tag, updated at the end of the build (success or failure)
cache-from: type=registry,ref=${{ env.BUILD_IMAGE_TAG }}
cache-to: type=inline # Write the cache metadata into the image configuration
# Use registry cache with max mode to cache all image layers in the registry
cache-from: type=registry,ref=${{ env.BUILD_IMAGE_TAG }}-cache-${{ env.ARCH }}
cache-to: type=registry,ref=${{ env.BUILD_IMAGE_TAG }}-cache-${{ env.ARCH }},mode=max

test:
name: "Test: ${{ matrix.version }}/${{ matrix.arch }}"
runs-on: ubuntu-20.04
runs-on: ${{ matrix.runner }}
needs: build

strategy:
fail-fast: false # Don't cancel other jobs if one fails
matrix:
include:
-
platform: linux/amd64
arch: amd64
version: "2.4"
# Disabled arm64 tests.
# TODO: Refactor tests to be compatible with a remote host test runner.
# TODO: Remember to re-enabled the test results check in "push".
#-
# arch: arm64
# version: 2.4
runner: ubuntu-24.04
-
platform: linux/arm64
arch: arm64
version: "2.4"
runner: ubuntu-24.04-arm

env:
ARCH: ${{ matrix.arch }}
Expand All @@ -129,47 +124,21 @@ jobs:
steps:
-
name: Setup Bats
uses: mig4/setup-bats@v1
with:
bats-version: "1.3.0"
uses: bats-core/bats-action@4.0.0
-
name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v6
-
name: Environment variables
run: |
# Export variables for further steps
echo GIT_SHA7="${GITHUB_SHA:0:7}" | tee -a ${GITHUB_ENV}
echo BUILD_IMAGE_TAG="${IMAGE}:${VERSION_PREFIX}${VERSION}-build" | tee -a ${GITHUB_ENV}
# Pull the host public SSH key at runtime instead of relying on a static value stored in secrets.
echo ARM64_HOST_SSH_CERT="$(ssh-keyscan -t rsa ${{ secrets.ARM64_HOST }} 2>/dev/null)" | tee -a ${GITHUB_ENV}
-
# Switch docker context to a remote arm64 host
# Used for building heavy images that take too long to build using QEMU + for native arm64 testing.
name: Switch to arm64 builder host
if: ${{ env.ARCH == 'arm64' }}
uses: arwynfr/actions-docker-context@v2
with:
docker_host: "ssh://ubuntu@${{ secrets.ARM64_HOST }}"
context_name: arm64-host
ssh_key: "${{ secrets.ARM64_HOST_SSH_KEY }}"
ssh_cert: "${{ env.ARM64_HOST_SSH_CERT }}"
use_context: true
-
name: Check Docker
run: |
docker version
docker info
# -
# name: Test preparations
# working-directory: ${{ env.BUILD_CONTEXT }}
# env:
# BUILD_IMAGE_TAG: ${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-${{ env.ARCH }}
# run: |
# # Install Docksal using the passed DOCKSAL_VERSION value
# curl -sSL http://get.docksal.io | bash
# # Start the service using the build image tag
# make start
-
# Run tests
name: Test
Expand All @@ -186,14 +155,16 @@ jobs:
# Dynamic variable names cannot be used when mapping step outputs to job outputs.
# Step outputs cannot be accessed directly from other jobs. Dead end.
- name: Store test results
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v7
with:
name: test-results
name: test-results-${{ env.GIT_SHA7 }}-${{ env.VERSION_PREFIX }}${{ env.VERSION }}-${{ env.ARCH }}
path: ${{ github.workspace }}/test-results-*.txt
if-no-files-found: error
overwrite: true

push:
name: "Push: ${{ matrix.version }}/multi"
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04

# Wait for test to either succeed or fail
needs: test
Expand All @@ -211,38 +182,35 @@ jobs:
steps:
-
name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v6
-
name: Environment variables
run: |
# Export variables for further steps
echo GIT_SHA7="${GITHUB_SHA:0:7}" | tee -a ${GITHUB_ENV}
echo BUILD_IMAGE_TAG="${IMAGE}:${VERSION_PREFIX}${VERSION}-build" | tee -a ${GITHUB_ENV}
# Pull the host public SSH key at runtime instead of relying on a static value stored in secrets.
echo ARM64_HOST_SSH_CERT="$(ssh-keyscan -t rsa ${{ secrets.ARM64_HOST }} 2>/dev/null)" | tee -a ${GITHUB_ENV}
-
# Login to Docker Hub
name: Login to Docker Hub
uses: docker/login-action@v1
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Retrieve test results
uses: actions/download-artifact@v2
uses: actions/download-artifact@v8
with:
name: test-results
pattern: test-results-${{ env.GIT_SHA7 }}-*
merge-multiple: true
-
# Generate persistent tags (edge, stable, release)
name: Docker image tags
id: docker_tags
# Don't push broken builds to persistent tags (both amd64 and arm64 tests must pass)
# TODO: re-enable the arm64 test results check once those tests are re-enabled
run: |
amd64_tests=$(cat test-results-${VERSION_PREFIX}${VERSION}-amd64.txt)
#arm64_tests=$(cat test-results-${VERSION_PREFIX}${VERSION}-arm64.txt)
# && [[ "${arm64_tests}" == "pass" ]]
if [[ "${amd64_tests}" == "pass" ]]; then
arm64_tests=$(cat test-results-${VERSION_PREFIX}${VERSION}-arm64.txt)
if [[ "${amd64_tests}" == "pass" ]] && [[ "${arm64_tests}" == "pass" ]]; then
.github/scripts/docker-tags.sh
fi
-
Expand All @@ -268,5 +236,6 @@ jobs:
docker manifest push ${tag}
done
# Clean up intermediate arch-specific image tags (DockerHub only)
.github/scripts/docker-tag-delete.sh ${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-amd64
.github/scripts/docker-tag-delete.sh ${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-arm64
# TODO: DISABLED. DOES NOT WORK RELIABLY.
# .github/scripts/docker-tag-delete.sh "${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-amd64"
# .github/scripts/docker-tag-delete.sh "${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-arm64"
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG UPSTREAM_IMAGE
ARG UPSTREAM_IMAGE=httpd:2.4.67-alpine
FROM ${UPSTREAM_IMAGE}

# TODO: Drop this? HTTPS termination should happen at the reverse proxy and this is not used anyway.
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ DOCKER_BUILDKIT=1

IMAGE ?= docksal/apache
VERSION ?= 2.4
UPSTREAM_IMAGE ?= httpd:2.4.52-alpine
UPSTREAM_IMAGE ?= httpd:2.4.67-alpine
BUILD_IMAGE_TAG ?= $(IMAGE):$(VERSION)-build
NAME = docksal-apache-$(VERSION)

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This image(s) is part of the [Docksal](http://docksal.io) image library.

## Versions

- apache2.4 (based on http:2.4-alpine)
- apache2.4 (based on httpd:2.4.67-alpine)

## Features

Expand Down
20 changes: 10 additions & 10 deletions conf/extra/httpd-vhosts.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,33 @@ ServerName ${APACHE_SERVERNAME}

# HTTP (default virtual host)
<VirtualHost *:80>
# Allow virtual-host config overrides (overrides go first, as Apache picks the first instance of a directive)
# Using a glob pattern in the file name to avoid creating an empty config by default
IncludeOptional conf/custom/httpd-vhost-overrides.con[f]
# Standard virtual-host configuration
Include conf/extra/includes/host.conf
# Allow virtual-host config overrides (overrides go last, as Apache uses the last instance of a directive)
# Using a glob pattern in the file name to avoid creating an empty config by default
IncludeOptional conf/custom/httpd-vhost-overrides.con[f]
</VirtualHost>

# HTTPS (default virtual host)
<IfModule mod_ssl.c>
Listen 443
# Restrict mod_ssl to use only TLSv1.2 ciphers
# Restrict mod_ssl to strong ciphers (TLSv1.3 ciphers are configured separately)
SSLCipherSuite HIGH:MEDIUM:!SSLv3:!kRSA
SSLProxyCipherSuite HIGH:MEDIUM:!SSLv3:!kRSA
SSLHonorCipherOrder on
# Only allow the TLSv1.2 protocol
SSLProtocol TLSv1.2
SSLProxyProtocol TLSv1.2
# Allow TLSv1.2 and TLSv1.3
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLProxyProtocol -all +TLSv1.2 +TLSv1.3
# Other SSL settings
SSLSessionCache "shmcb:/usr/local/apache2/logs/ssl_scache(512000)"
SSLSessionCacheTimeout 300

<VirtualHost *:443>
# Allow virtual-host config overrides (overrides go first, as Apache picks the first instance of a directive)
# Using a glob pattern in the file name to avoid creating an empty config by default
IncludeOptional conf/custom/httpd-vhost-overrides.con[f]
# Standard virtual-host configuration
Include conf/extra/includes/host.conf
# Allow virtual-host config overrides (overrides go last, as Apache uses the last instance of a directive)
# Using a glob pattern in the file name to avoid creating an empty config by default
IncludeOptional conf/custom/httpd-vhost-overrides.con[f]

SSLEngine on
SSLCertificateFile /usr/local/apache2/conf/server.crt
Expand Down
5 changes: 5 additions & 0 deletions tests/config-directory-override/httpd-vhost-overrides.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Override the <Directory> block from host.conf to deny access
# This tests that overrides at the same scope (container directive) take effect
<Directory "${APACHE_DOCUMENTROOT}">
Require all denied
</Directory>
5 changes: 4 additions & 1 deletion tests/config/httpd-vhost-overrides.conf
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
DirectoryIndex index2.html
# Test that a <Directory> override takes precedence over VirtualHost-level directives
<Directory "${APACHE_DOCUMENTROOT}">
DirectoryIndex index2.html
</Directory>
29 changes: 29 additions & 0 deletions tests/test.bats
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,32 @@ _healthcheck_wait ()
### Cleanup ###
make clean
}

@test "Configuration overrides - Directory block" {
[[ $SKIP == 1 ]] && skip

### Setup ###
VOLUMES=" \
-v $(pwd)/tests/docroot:/var/www/docroot \
-v $(pwd)/tests/config-directory-override:/var/www/.docksal/etc/apache" \
make start

run _healthcheck_wait
unset output

### Tests ###

# Test that a <Directory> override takes precedence over host.conf's <Directory> block
# This verifies the include order fix (overrides must load after the standard config)
run curl -sSk -m 1 -I http://localhost:2580
[[ "$output" =~ "HTTP/1.1 403 Forbidden" ]]
unset output

# HTTPS should also be overridden
run curl -sSk -m 1 -I https://localhost:25443
[[ "$output" =~ "HTTP/1.1 403 Forbidden" ]]
unset output

### Cleanup ###
make clean
}
Loading