diff --git a/.ci/update-test-container-image-reference.py b/.ci/update-test-container-image-reference.py new file mode 100755 index 00000000..46ca9a61 --- /dev/null +++ b/.ci/update-test-container-image-reference.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Update container image digests in configured docker compose files and Dockerfiles. +The script will look for matches for `:@sha256:` in those files and update the digest, +if a different one is found for `:` at the registry. + +Requires: skopeo +""" +import re +import subprocess +import sys + +# Change this to add more files to check. +FILES = { + "compose": [ + "php/tests/compose.yaml", + ], + "dockerfile": [ + "php/tests/Containers/composer/Dockerfile", + ], +} + +PREFIX = { + "compose": "image: ", + "dockerfile": "FROM ", +} + +# Matches `:@sha256:` +IMAGE_RE = r"{prefix}([^\s@]+:[^\s@]+)@(sha256:[a-f0-9]+)" + +if subprocess.run(["which", "skopeo"], capture_output=True).returncode != 0: + sys.exit("Error: skopeo is not installed. Install it from https://github.com/containers/skopeo#installation") + + +def update_image_digest(content, full_ref, current_digest, file_path): + result = subprocess.run( + [ + "skopeo", "inspect", + "--override-os", "linux", + "--no-tags", + "--format", "{{.Digest}}", + f"docker://{full_ref}", + ], + capture_output=True, text=True, check=True, + ) + latest_digest = result.stdout.strip() + + msg_prefix = f"{file_path}: {full_ref}" + if latest_digest == current_digest: + print(f"{msg_prefix}: already up to date.") + return content + + old = f"{full_ref}@{current_digest}" + count = content.count(old) + content = content.replace(old, f"{full_ref}@{latest_digest}") + print(f"{msg_prefix}: updated {count} occurrence(s) to {latest_digest}.") + return content + + +def update_file(file_path, prefix): + with open(file_path) as f: + content = f.read() + + images = re.findall(IMAGE_RE.format(prefix=re.escape(prefix)), content) + if not images: + print(f"{file_path}: no pinned image references found.") + return + + # Run only once for every pair of file_path and image. + unique_images = list(dict.fromkeys(images)) + + for full_ref, current_digest in unique_images: + content = update_image_digest(content, full_ref, current_digest, file_path) + + with open(file_path, "w") as f: + f.write(content) + + +def main(): + for file_type, paths in FILES.items(): + for path in paths: + update_file(path, PREFIX[file_type]) + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/update-test-container-image-references.yml b/.github/workflows/update-test-container-image-references.yml new file mode 100644 index 00000000..1354559c --- /dev/null +++ b/.github/workflows/update-test-container-image-references.yml @@ -0,0 +1,28 @@ +name: update-test-container-image-references + +on: + workflow_dispatch: + schedule: + - cron: '00 5 * * *' + +jobs: + update: + name: Update test container image references + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - name: Install skopeo + run: sudo apt-get install -y skopeo + - name: Run update script + run: python3 .ci/update-image-reference.py + - name: Create Pull Request + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore(tests): update test container image references" + signoff: true + title: Update test container image references + body: Automated update of node and playwright image digests in php/tests/compose.yaml + labels: dependencies, 3. to review + milestone: next + branch: update-test-container-image-references diff --git a/php/tests/Containers/composer/Dockerfile b/php/tests/Containers/composer/Dockerfile index a483458b..004e69bc 100644 --- a/php/tests/Containers/composer/Dockerfile +++ b/php/tests/Containers/composer/Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/library/composer:latest +FROM docker.io/library/composer:2@sha256:7725eb4545c438629ae8bde3ef0bb9a5038ef566126ad878442a69007242d267 RUN pecl bundle -d /usr/src/php/ext apcu \ && docker-php-ext-install apcu \ No newline at end of file diff --git a/php/tests/compose.yaml b/php/tests/compose.yaml index 937b8bb4..73510efb 100644 --- a/php/tests/compose.yaml +++ b/php/tests/compose.yaml @@ -59,21 +59,21 @@ services: - local-code desec-mock: - image: docker.io/library/node:latest + image: docker.io/library/node:26@sha256:b46a10d964ad15136ebdf9012142131481caa0697d7a4d4eafe4bbabd818f876 volumes: - ..:/app/php working_dir: /app command: node php/tests/desec-mock.mjs 8090 2>&1 npm-installer: - image: docker.io/library/node:latest + image: docker.io/library/node:26@sha256:b46a10d964ad15136ebdf9012142131481caa0697d7a4d4eafe4bbabd818f876 volumes: - ..:/app working_dir: /app/tests command: npm ci --omit=optional test-runner-base: - image: mcr.microsoft.com/playwright:v1.56.1 + image: mcr.microsoft.com/playwright:v1.56.1@sha256:f1e7e01021efd65dd1a2c56064be399f3e4de00fd021ac561325f2bfbb2b837a volumes: - ..:/app working_dir: /app/tests