diff --git a/.dockerignore b/.dockerignore index ef1376f..1c46254 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,4 +6,4 @@ !LICENSE !README.md !entrypoint.sh -!pip +!alpine-packages.txt diff --git a/Dockerfile b/Dockerfile index 5dfd9ff..94d288e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,33 +1,20 @@ -FROM ubuntu:questing-20251217 - -# Disable interactive mode -ENV DEBIAN_FRONTEND=noninteractive +FROM alpine:3.23.4 # Copy all needed files COPY entrypoint.sh / +COPY alpine-packages.txt /tmp/alpine-packages.txt # Install needed packages -SHELL ["/bin/bash", "-euxo", "pipefail", "-c"] -# hadolint ignore=DL3008 -RUN chmod +x /entrypoint.sh ;\ - apt-get update -y ;\ - apt-get install --no-install-recommends -y \ - gpg-agent \ - software-properties-common ;\ - echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections ;\ - add-apt-repository ppa:git-core/ppa ;\ - apt-get update -y ;\ - apt-get install --no-install-recommends -y \ - git ;\ - # Install git-lfs without post-install configuration to avoid dpkg errors \ - apt-get download git-lfs ;\ - dpkg --unpack git-lfs*.deb ;\ - rm -f /var/lib/dpkg/info/git-lfs.postinst ;\ - dpkg --configure git-lfs ;\ - apt-get install -f --no-install-recommends -y ;\ - rm git-lfs*.deb ;\ - apt-get clean ;\ - rm -rf /var/lib/apt/lists/* +SHELL ["/bin/sh", "-euxo", "pipefail", "-c"] +# hadolint ignore=DL3018 +RUN set -eux; \ + xargs -r apk add --no-cache < /tmp/alpine-packages.txt; \ + chmod +x /entrypoint.sh; \ + git --version; \ + git-lfs version; \ + rm -rf /var/cache/*; \ + rm -rf /root/.cache/*; \ + rm -rf /tmp/* # Finish up WORKDIR /github/workspace diff --git a/Taskfile.cicd.yml b/Taskfile.cicd.yml index c6baf70..97d0074 100644 --- a/Taskfile.cicd.yml +++ b/Taskfile.cicd.yml @@ -44,9 +44,9 @@ tasks: - task: scripts:lint:yamllint dependency:update: - desc: 'No-op: no dedicated dependency updater configured for this profile' + desc: Update repository dependencies not covered by Dependabot cmds: - - task: scripts:dependency:update + - task: scripts:packages:update version:set: desc: Update version in README.md and action.yml diff --git a/Taskfile.scripts.yml b/Taskfile.scripts.yml index 1d9bf48..2c3b32f 100644 --- a/Taskfile.scripts.yml +++ b/Taskfile.scripts.yml @@ -75,12 +75,9 @@ tasks: fi dependency:update: - desc: 'No-op: no dedicated dependency updater configured for this profile' + desc: Update dependency metadata for this repository cmds: - - | - echo "INFO: No dedicated dependency updater configured for this repository profile." - echo "INFO: Dependabot handles GitHub Actions and package metadata updates." - echo "INFO: Keep this task as a safe no-op until a repo-specific dependency updater is defined." + - task: packages:update version:get: desc: Get current version @@ -255,7 +252,22 @@ tasks: exit 0 fi - base_image="$(sed -nE 's/^FROM[[:space:]]+([^[:space:]]+).*/\1/p' Dockerfile | head -1)" + base_image="$(awk ' + toupper($1) == "FROM" { + i = 2 + while (i <= NF && $i ~ /^--/) { + i++ + } + if (i <= NF) { + image = $i + } + } + END { + if (image != "") { + print image + } + } + ' Dockerfile)" if [ -z "$base_image" ]; then echo "INFO: Could not resolve base image; nothing to update" exit 0 diff --git a/alpine-packages.txt b/alpine-packages.txt new file mode 100644 index 0000000..c8ceb79 --- /dev/null +++ b/alpine-packages.txt @@ -0,0 +1,3 @@ +bash~=5.3 +git~=2.52 +git-lfs~=3.7 diff --git a/entrypoint.sh b/entrypoint.sh index 607a26c..26891fa 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -38,8 +38,60 @@ if [[ "${REPOSITORY_PATH}" == /* ]]; then exit 1 fi -WORKSPACE_DIR="$(realpath -m "${GITHUB_WORKSPACE}")" -REPO_DIR="$(realpath -m "${GITHUB_WORKSPACE}/${REPOSITORY_PATH}")" +if [[ -z "${GITHUB_WORKSPACE}" || ! -d "${GITHUB_WORKSPACE}" ]]; then + echo "[ERROR] GITHUB_WORKSPACE must point to an existing directory." + exit 1 +fi + +normalize_relative_path() { + local path part normalized + local -a parts stack + + path="${1:-.}" + IFS='/' read -r -a parts <<< "${path}" + stack=() + + for part in "${parts[@]}"; do + case "${part}" in + ""|".") + ;; + "..") + if (( ${#stack[@]} > 0 )) && [[ "${stack[-1]}" != ".." ]]; then + unset 'stack[-1]' + else + stack+=("..") + fi + ;; + *) + stack+=("${part}") + ;; + esac + done + + if (( ${#stack[@]} == 0 )); then + printf '.' + return + fi + + normalized="${stack[0]}" + for part in "${stack[@]:1}"; do + normalized+="/${part}" + done + printf '%s' "${normalized}" +} + +WORKSPACE_DIR="$(cd "${GITHUB_WORKSPACE}" && pwd -P)" +NORMALIZED_REPOSITORY_PATH="$(normalize_relative_path "${REPOSITORY_PATH}")" +if [[ "${NORMALIZED_REPOSITORY_PATH}" == ".." || "${NORMALIZED_REPOSITORY_PATH}" == ../* ]]; then + echo "[ERROR] Input 'repository_path' resolves outside GITHUB_WORKSPACE." + exit 1 +fi + +if [[ "${NORMALIZED_REPOSITORY_PATH}" == "." ]]; then + REPO_DIR="${WORKSPACE_DIR}" +else + REPO_DIR="${WORKSPACE_DIR}/${NORMALIZED_REPOSITORY_PATH}" +fi if [[ "${REPO_DIR}" != "${WORKSPACE_DIR}" && "${REPO_DIR}" != "${WORKSPACE_DIR}"/* ]]; then echo "[ERROR] Input 'repository_path' resolves outside GITHUB_WORKSPACE." exit 1 diff --git a/tests/docker/local-image.yml b/tests/docker/local-image.yml index fc52939..7c5f3d8 100644 --- a/tests/docker/local-image.yml +++ b/tests/docker/local-image.yml @@ -4,7 +4,7 @@ commandTests: - name: OS version check command: cat args: [/etc/os-release] - expectedOutput: [VERSION_ID="25\.10"] + expectedOutput: [VERSION_ID=3\.23] - name: Required tools installed command: bash @@ -12,17 +12,14 @@ commandTests: - -lc - command -v bash >/dev/null 2>&1 && command -v git >/dev/null 2>&1 && command -v git-lfs >/dev/null 2>&1 - - name: Apt cache cleaned + - name: Temporary and APK cache cleaned command: bash args: - -lc - - test ! -d /var/lib/apt/lists || test -z "$(find /var/lib/apt/lists -mindepth 1 -maxdepth 1 2>/dev/null)" - - - name: Temporary apt artifacts removed - command: bash - args: - - -lc - - test ! -e /git-lfs*.deb + - >- + test ! -f /tmp/alpine-packages.txt && + (test ! -d /var/cache/apk || test -z "$(find /var/cache/apk -mindepth 1 -maxdepth 1 2>/dev/null)") && + (test ! -d /root/.cache || test -z "$(find /root/.cache -mindepth 1 -maxdepth 1 2>/dev/null)") - name: Entrypoint handles default repository path command: bash