Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3c28f7c
Refactor Dockerfiles to use ARG for base images and add ACR sync work…
maxmartin-cgi Jul 10, 2026
7989da0
Documentation changes
maxmartin-cgi Jul 10, 2026
c0f93b3
Merge branch 'main' into maxmartin-cgi/utilise-acr-for-docker-pulls
maxmartin-cgi Jul 10, 2026
fefe1b9
Iterate minor version
maxmartin-cgi Jul 10, 2026
cc297b9
Iterate minor version (again)
maxmartin-cgi Jul 10, 2026
598eca1
Merge branch 'maxmartin-cgi/utilise-acr-for-docker-pulls' of https://…
maxmartin-cgi Jul 10, 2026
687fa04
Fix issues raised by linter
maxmartin-cgi Jul 10, 2026
593e48f
Iterate minor versions for workspace templates
maxmartin-cgi Jul 10, 2026
879410e
Merge branch 'main' into maxmartin-cgi/utilise-acr-for-docker-pulls
maxmartin-cgi Jul 13, 2026
72ed8ef
Pin GitHub Actions in ACR sync workflow
Copilot Jul 13, 2026
d8f6e60
Merge branch 'main' into maxmartin-cgi/utilise-acr-for-docker-pulls
maxmartin-cgi Jul 13, 2026
c89d837
Bump versions
maxmartin-cgi Jul 14, 2026
9eabe13
Merge branch 'main' into maxmartin-cgi/utilise-acr-for-docker-pulls
maxmartin-cgi Jul 16, 2026
e2a617b
Refactor Dockerfiles to use ARG for base images and tags for improved…
maxmartin-cgi Jul 17, 2026
1962e38
Update version numbers in multiple porter.yaml files and add build ar…
maxmartin-cgi Jul 17, 2026
c8fee2d
Bump airlock processor version
maxmartin-cgi Jul 17, 2026
5bcc4d8
Update Docker build workflows to utilize ACR for base images and tags
maxmartin-cgi Jul 17, 2026
fb6537a
Fix ACR mirror review feedback
Copilot Jul 20, 2026
ae5b101
fix: use VARIANT directly in FROM tag, drop DEVCONTAINER_TAG ARG
Copilot Jul 20, 2026
f95fe43
Merge branch 'main' into maxmartin-cgi/utilise-acr-for-docker-pulls
maxmartin-cgi Jul 22, 2026
d7b2a0f
Bump api version
maxmartin-cgi Jul 23, 2026
c2541a5
Merge branch 'main' into maxmartin-cgi/utilise-acr-for-docker-pulls
maxmartin-cgi Jul 23, 2026
5f25c64
Potential fix for pull request finding
maxmartin-cgi Jul 23, 2026
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
3 changes: 2 additions & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

# [Choice] Python version: 3.11 3.12, 3.13
ARG VARIANT="3.12"
ARG DEVCONTAINER_BASE_IMAGE=mcr.microsoft.com/vscode/devcontainers/python
ARG TARGETPLATFORM="linux/amd64"
FROM --platform="${TARGETPLATFORM}" mcr.microsoft.com/vscode/devcontainers/python:dev-${VARIANT}-bookworm
FROM --platform="${TARGETPLATFORM}" ${DEVCONTAINER_BASE_IMAGE}:dev-${VARIANT}-bookworm

# This will be set to true when running in VSCode
ARG INTERACTIVE="false"
Expand Down
97 changes: 97 additions & 0 deletions .github/workflows/build_docker_images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,16 @@ jobs:
docker_build:
name: Build images
runs-on: ubuntu-latest
env:
PYTHON_TAG: 3.12-slim-bookworm
AIRLOCK_PYTHON_TAG: 4-python3.12
MAVEN_TAG: 3.9-eclipse-temurin-17-alpine
GUACD_TAG: 1.6.0
GITEA_TAG: 1.15
Comment thread
maxmartin-cgi marked this conversation as resolved.
permissions:
contents: read
actions: write # For uploading artifacts
id-token: write # For Azure OIDC login when using ACR mirrors
pull-requests: read # For path filter
steps:
- name: Upload Event File
Expand All @@ -38,6 +45,68 @@ jobs:
with:
persist-credentials: false

- name: Determine ACR mirror availability
id: acr_mirror
env:
ACR_BASE_IMAGE_PREFIX: ${{ vars.ACR_BASE_IMAGE_PREFIX }}
ACR_NAME: ${{ secrets.ACR_NAME }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
run: |
use_acr_mirrors=false

if [[ -n "${ACR_BASE_IMAGE_PREFIX}" &&
-n "${ACR_NAME}" &&
-n "${AZURE_CLIENT_ID}" &&
-n "${AZURE_TENANT_ID}" &&
-n "${AZURE_SUBSCRIPTION_ID}" ]]; then
use_acr_mirrors=true
fi

echo "use_acr_mirrors=${use_acr_mirrors}" >> "${GITHUB_OUTPUT}"
Comment thread
maxmartin-cgi marked this conversation as resolved.

- name: Azure Login for ACR mirror
if: ${{ steps.acr_mirror.outputs.use_acr_mirrors == 'true' }}
uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
environment: ${{ (vars.AZURE_ENVIRONMENT != '' && vars.AZURE_ENVIRONMENT) || 'AzureCloud' }}

- name: Login to ACR mirror
if: ${{ steps.acr_mirror.outputs.use_acr_mirrors == 'true' }}
run: az acr login --name "${{ secrets.ACR_NAME }}"

- name: Select Docker base image sources
env:
ACR_BASE_IMAGE_PREFIX: ${{ vars.ACR_BASE_IMAGE_PREFIX }}
run: |
prefix="${ACR_BASE_IMAGE_PREFIX}"

python_base_image="python"
airlock_python_base_image="mcr.microsoft.com/azure-functions/python"
maven_base_image="maven"
guacd_base_image="guacamole/guacd"
gitea_base_image_repo="gitea/gitea"

if [[ "${{ steps.acr_mirror.outputs.use_acr_mirrors }}" == 'true' ]]; then
python_base_image="${prefix}/mirror/library/python"
airlock_python_base_image="${prefix}/mirror/mcr/azure-functions/python"
maven_base_image="${prefix}/mirror/library/maven"
guacd_base_image="${prefix}/mirror/guacamole/guacd"
gitea_base_image_repo="${prefix}/mirror/gitea/gitea"
fi

{
echo "PYTHON_BASE_IMAGE=${python_base_image}"
echo "AIRLOCK_PYTHON_BASE_IMAGE=${airlock_python_base_image}"
echo "MAVEN_BASE_IMAGE=${maven_base_image}"
echo "GUACD_BASE_IMAGE=${guacd_base_image}"
echo "GITEA_BASE_IMAGE_REPO=${gitea_base_image_repo}"
} >> "${GITHUB_ENV}"

- name: Filter changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: filter
Expand Down Expand Up @@ -137,6 +206,9 @@ jobs:
with:
context: ./api_app/
file: ./api_app/Dockerfile
build-args: |
PYTHON_BASE_IMAGE=${{ env.PYTHON_BASE_IMAGE }}
PYTHON_TAG=${{ env.PYTHON_TAG }}
outputs: type=local,dest=test-results
target: test-results
cache-from: type=gha
Expand All @@ -157,6 +229,9 @@ jobs:
with:
context: ./api_app/
file: ./api_app/Dockerfile
build-args: |
PYTHON_BASE_IMAGE=${{ env.PYTHON_BASE_IMAGE }}
PYTHON_TAG=${{ env.PYTHON_TAG }}
cache-from: type=gha
cache-to: type=gha,mode=max

Expand All @@ -168,6 +243,9 @@ jobs:
with:
context: ./resource_processor
file: ./resource_processor/vmss_porter/Dockerfile
build-args: |
PYTHON_BASE_IMAGE=${{ env.PYTHON_BASE_IMAGE }}
PYTHON_TAG=${{ env.PYTHON_TAG }}
cache-from: type=gha
cache-to: type=gha,mode=max

Expand All @@ -179,6 +257,11 @@ jobs:
with:
context: ./templates/workspace_services/guacamole/guacamole-server
file: ./templates/workspace_services/guacamole/guacamole-server/docker/Dockerfile
build-args: |
MAVEN_BASE_IMAGE=${{ env.MAVEN_BASE_IMAGE }}
MAVEN_TAG=${{ env.MAVEN_TAG }}
GUACD_BASE_IMAGE=${{ env.GUACD_BASE_IMAGE }}
GUACD_TAG=${{ env.GUACD_TAG }}
outputs: type=local,dest=test-results
target: test-results
cache-from: type=gha
Expand All @@ -199,6 +282,11 @@ jobs:
with:
context: ./templates/workspace_services/guacamole/guacamole-server
file: ./templates/workspace_services/guacamole/guacamole-server/docker/Dockerfile
build-args: |
MAVEN_BASE_IMAGE=${{ env.MAVEN_BASE_IMAGE }}
MAVEN_TAG=${{ env.MAVEN_TAG }}
GUACD_BASE_IMAGE=${{ env.GUACD_BASE_IMAGE }}
GUACD_TAG=${{ env.GUACD_TAG }}
cache-from: type=gha
cache-to: type=gha,mode=max

Expand All @@ -210,6 +298,9 @@ jobs:
with:
context: ./templates/shared_services/gitea/docker
file: ./templates/shared_services/gitea/docker/Dockerfile
build-args: |
GITEA_BASE_IMAGE_REPO=${{ env.GITEA_BASE_IMAGE_REPO }}
GITEA_TAG=${{ env.GITEA_TAG }}
cache-from: type=gha
cache-to: type=gha,mode=max

Expand All @@ -227,6 +318,9 @@ jobs:
with:
context: ./airlock_processor/
file: ./airlock_processor/Dockerfile
build-args: |
PYTHON_BASE_IMAGE=${{ env.AIRLOCK_PYTHON_BASE_IMAGE }}
PYTHON_TAG=${{ env.AIRLOCK_PYTHON_TAG }}
outputs: type=local,dest=test-results
target: test-results
cache-from: type=gha
Expand All @@ -247,6 +341,9 @@ jobs:
with:
context: ./airlock_processor/
file: ./airlock_processor/Dockerfile
build-args: |
PYTHON_BASE_IMAGE=${{ env.AIRLOCK_PYTHON_BASE_IMAGE }}
PYTHON_TAG=${{ env.AIRLOCK_PYTHON_TAG }}
cache-from: type=gha
cache-to: type=gha,mode=max

Expand Down
161 changes: 161 additions & 0 deletions .github/workflows/sync_acr_base_images.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
---
name: Sync ACR Base Images

on: # yamllint disable-line rule:truthy
schedule:
- cron: "23 2 * * *"
workflow_dispatch:

permissions:
contents: read
id-token: write

jobs:
sync:
name: Import newer upstream base images into ACR
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd

- name: Validate required secrets
run: |
if [ "${{ secrets.ACR_NAME }}" = '' ]; then
echo "Missing secret: ACR_NAME" && exit 1
fi
if [ "${{ secrets.AZURE_CLIENT_ID }}" = '' ]; then
echo "Missing secret: AZURE_CLIENT_ID" && exit 1
fi
if [ "${{ secrets.AZURE_TENANT_ID }}" = '' ]; then
echo "Missing secret: AZURE_TENANT_ID" && exit 1
fi
if [ "${{ secrets.AZURE_SUBSCRIPTION_ID }}" = '' ]; then
echo "Missing secret: AZURE_SUBSCRIPTION_ID" && exit 1
fi

- name: Azure Login
uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
environment: ${{ (vars.AZURE_ENVIRONMENT != '' && vars.AZURE_ENVIRONMENT) || 'AzureCloud' }}

- name: Login to ACR
run: az acr login --name "${{ secrets.ACR_NAME }}"

- name: Sync image mirrors
env:
ACR_NAME: ${{ secrets.ACR_NAME }}
run: |
set -euo pipefail

acr_domain_suffix=$(az cloud show --query suffixes.acrLoginServerEndpoint --output tsv)
ACR_LOGIN_SERVER="${ACR_NAME}${acr_domain_suffix}"

# source_repo|target_repo|tag
IMAGES=(
"docker.io/library/python|mirror/library/python|3.12-slim-bookworm"
"docker.io/library/maven|mirror/library/maven|3.9-eclipse-temurin-17-alpine"
"docker.io/guacamole/guacd|mirror/guacamole/guacd|1.6.0"
"docker.io/gitea/gitea|mirror/gitea/gitea|1.15"
"docker.io/gitea/gitea|mirror/gitea/gitea|1.17.3"
"mcr.microsoft.com/azure-functions/python|mirror/mcr/azure-functions/python|4-python3.12"
"docker.io/library/debian|mirror/library/debian|bookworm-slim"
"docker.io/library/debian|mirror/library/debian|bullseye-slim"
)
Comment thread
maxmartin-cgi marked this conversation as resolved.

sync_image() {
local source_repo="$1"
local target_repo="$2"
local tag="$3"
local source_ref="${source_repo}:${tag}"
local target_ref="${ACR_LOGIN_SERVER}/${target_repo}:${tag}"
local digest_format='{{json .Manifest.Digest}}'

local source_digest
local target_digest

if ! source_digest=$(docker buildx imagetools inspect "${source_ref}" \
--format "${digest_format}" | tr -d '"'); then
echo "::error::Failed to inspect source image ${source_ref}. Aborting to avoid unintended forced import."
return 1
fi

if ! target_digest=$(docker buildx imagetools inspect "${target_ref}" \
--format "${digest_format}" | tr -d '"'); then
echo "::warning::Failed to inspect target image ${target_ref}. Proceeding with import."
target_digest=""
fi

if [[ -z "${source_digest}" ]]; then
echo "::error::Source digest for ${source_ref} is empty. Aborting to avoid unintended forced import."
return 1
fi

if [[ -z "${target_digest}" ]]; then
echo "::warning::Target digest for ${target_ref} is empty. Import will proceed."
fi

if [[ -n "${source_digest}" && -n "${target_digest}" && "${source_digest}" == "${target_digest}" ]]; then
echo "Up-to-date: ${target_repo}:${tag} (${source_digest})"
return 0
fi

echo "Importing ${source_ref} -> ${target_repo}:${tag}"
az acr import \
--name "${ACR_NAME}" \
--source "${source_ref}" \
--image "${target_repo}:${tag}" \
--force
}

for image in "${IMAGES[@]}"; do
IFS='|' read -r source_repo target_repo tag <<< "${image}"
sync_image "${source_repo}" "${target_repo}" "${tag}"
done

- name: Publish sync summary
env:
ACR_NAME: ${{ secrets.ACR_NAME }}
CURRENT_ACR_BASE_IMAGE_PREFIX: ${{ vars.ACR_BASE_IMAGE_PREFIX }}
run: |
set -euo pipefail

acr_domain_suffix=$(az cloud show --query suffixes.acrLoginServerEndpoint --output tsv)
expected_prefix="${ACR_NAME}${acr_domain_suffix}"

{
echo "## ACR base image sync summary"
echo
echo "- Expected ACR_BASE_IMAGE_PREFIX: ${expected_prefix}"

if [[ -n "${CURRENT_ACR_BASE_IMAGE_PREFIX}" ]]; then
echo "- Current ACR_BASE_IMAGE_PREFIX: ${CURRENT_ACR_BASE_IMAGE_PREFIX}"
else
echo "- Current ACR_BASE_IMAGE_PREFIX: (not set)"
fi

echo
if [[ -z "${CURRENT_ACR_BASE_IMAGE_PREFIX}" ]]; then
echo "Repository variable ACR_BASE_IMAGE_PREFIX is not set."
echo "Please set it to ${expected_prefix}."
echo "See: Repository Settings > Secrets and variables > Actions > Variables"
elif [[ "${CURRENT_ACR_BASE_IMAGE_PREFIX}" != "${expected_prefix}" ]]; then
echo "Repository variable ACR_BASE_IMAGE_PREFIX does not match the expected value."
echo "Please update it to ${expected_prefix}."
else
echo "Repository variable ACR_BASE_IMAGE_PREFIX is correctly configured."
fi
} >> "${GITHUB_STEP_SUMMARY}"

if [[ -z "${CURRENT_ACR_BASE_IMAGE_PREFIX}" ]]; then
echo "::warning::Repository variable ACR_BASE_IMAGE_PREFIX is not set. Expected: ${expected_prefix}"
elif [[ "${CURRENT_ACR_BASE_IMAGE_PREFIX}" != "${expected_prefix}" ]]; then
echo "::warning::Repository variable ACR_BASE_IMAGE_PREFIX mismatch. Current: ${CURRENT_ACR_BASE_IMAGE_PREFIX}, Expected: ${expected_prefix}"
fi
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ ENHANCEMENTS:
* Add Windows Server 2025 image support to Guacamole. ([#4890](https://github.com/microsoft/AzureTRE/issues/4890))
* Add support for setting resource processor VMSS SKU via environment variables ([#4936](https://github.com/microsoft/AzureTRE/issues/4936))
* Exclude recovery service vaults from e2e tests ([#4920](https://github.com/microsoft/AzureTRE/issues/4920))
* Add ACR base-image mirroring workflow and configurable Docker base-image arguments for CI builds ([#4952](https://github.com/microsoft/AzureTRE/pull/4952))
* Update API, CLI, and UI dependencies to address high-severity Dependabot alerts, including `PyJWT`, `Vite`, `lodash`, `fast-uri`, `flatted`, `immutable`, and `minimatch`.
* Update dependencies to address Dependabot security alerts: `aiohttp` to 3.14.1, `Pygments` to 2.20.0, `esbuild`, `ws`, `js-yaml`, `@babel/core`, `flatted` (via vitest upgrade), and `react-router-dom`. ([#4950](https://github.com/microsoft/AzureTRE/issues/4950))
* Added support for formatting UI code via `pre-commit` and fixed existing formatting issues. ([#4955](https://github.com/microsoft/AzureTRE/issues/4955))
* Updated the version of `super-linter` used in the `build_validation_develop` workflow ([#4957](https://github.com/microsoft/AzureTRE/issues/4957))

BUG FIXES:
* Fix Docker image workflows to authenticate before using private ACR mirrors and skip redundant runtime-image imports when the target tag is already present. ([#4952](https://github.com/microsoft/AzureTRE/pull/4952))
* Fix UI TypeScript deprecation warning by updating `moduleResolution` to `bundler` in `tsconfig.json`. ([#4968](https://github.com/microsoft/AzureTRE/issues/4968))
* Fix API timeout and name collision failures on workspace creation by checking storage account name availability and improved logging. ([#4946](https://github.com/microsoft/AzureTRE/pull/4946))
* Fix error handling in airlock processor ([#4929](https://github.com/microsoft/AzureTRE/pull/4929))
Expand Down
4 changes: 3 additions & 1 deletion airlock_processor/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# To enable ssh & remote debugging on app service change the base image to the one below
# FROM mcr.microsoft.com/azure-functions/python:4-python3.8-appservice as base
FROM mcr.microsoft.com/azure-functions/python:4-python3.12 AS base
ARG PYTHON_TAG=4-python3.12
ARG PYTHON_BASE_IMAGE=mcr.microsoft.com/azure-functions/python
FROM ${PYTHON_BASE_IMAGE}:${PYTHON_TAG} AS base

COPY requirements.txt /
RUN pip install --no-cache-dir -r /requirements.txt
Expand Down
2 changes: 1 addition & 1 deletion airlock_processor/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.8.11"
__version__ = "0.8.12"
4 changes: 3 additions & 1 deletion api_app/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
FROM python:3.12-slim-bookworm AS base
ARG PYTHON_TAG=3.12-slim-bookworm
ARG PYTHON_BASE_IMAGE=python
FROM ${PYTHON_BASE_IMAGE}:${PYTHON_TAG} AS base

COPY requirements.txt /.
RUN pip3 install --no-cache-dir -r requirements.txt
Expand Down
2 changes: 1 addition & 1 deletion api_app/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.25.29"
__version__ = "0.25.30"
Loading
Loading