diff --git a/.editorconfig b/.editorconfig old mode 100755 new mode 100644 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e37342f..8064a41 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -6,7 +6,7 @@ * Read, and fill the Pull Request template * If this is a fix for a typo (in code, documentation, or the README) please file an issue and let us sort it out. We do not need a PR * If the PR is addressing an existing issue include, closes #\, in the body of the PR commit message -* If you want to discuss changes, you can also bring it up in [#dev-talk](https://discordapp.com/channels/354974912613449730/757585807061155840) in our [Discord server](https://discord.gg/YWrKVTn) +* If you want to discuss changes, you can also bring it up in [#dev-talk](https://discordapp.com/channels/354974912613449730/757585807061155840) in our [Discord server](https://linuxserver.io/discord) ## Common files diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 34d3e97..d076084 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,7 +1,7 @@ blank_issues_enabled: false contact_links: - name: Discord chat support - url: https://discord.gg/YWrKVTn + url: https://linuxserver.io/discord about: Realtime support / chat with the community and the team. - name: Discourse discussion forum diff --git a/.github/ISSUE_TEMPLATE/issue.bug.yml b/.github/ISSUE_TEMPLATE/issue.bug.yml old mode 100755 new mode 100644 diff --git a/.github/ISSUE_TEMPLATE/issue.feature.yml b/.github/ISSUE_TEMPLATE/issue.feature.yml old mode 100755 new mode 100644 diff --git a/.github/workflows/call_issue_pr_tracker.yml b/.github/workflows/call_issue_pr_tracker.yml old mode 100755 new mode 100644 index 2c30784..d07cf12 --- a/.github/workflows/call_issue_pr_tracker.yml +++ b/.github/workflows/call_issue_pr_tracker.yml @@ -8,6 +8,9 @@ on: pull_request_review: types: [submitted,edited,dismissed] +permissions: + contents: read + jobs: manage-project: permissions: diff --git a/.github/workflows/call_issues_cron.yml b/.github/workflows/call_issues_cron.yml old mode 100755 new mode 100644 index a991578..4d2bdb4 --- a/.github/workflows/call_issues_cron.yml +++ b/.github/workflows/call_issues_cron.yml @@ -4,6 +4,9 @@ on: - cron: '11 3 * * *' workflow_dispatch: +permissions: + contents: read + jobs: stale: permissions: diff --git a/.github/workflows/external_trigger.yml b/.github/workflows/external_trigger.yml index 3997224..05e680b 100644 --- a/.github/workflows/external_trigger.yml +++ b/.github/workflows/external_trigger.yml @@ -3,6 +3,9 @@ name: External Trigger Main on: workflow_dispatch: +permissions: + contents: read + jobs: external-trigger-main: runs-on: ubuntu-latest @@ -15,7 +18,10 @@ jobs: SKIP_EXTERNAL_TRIGGER: ${{ vars.SKIP_EXTERNAL_TRIGGER }} run: | printf "# External trigger for docker-phpmyadmin\n\n" >> $GITHUB_STEP_SUMMARY - if grep -q "^phpmyadmin_main" <<< "${SKIP_EXTERNAL_TRIGGER}"; then + if grep -q "^phpmyadmin_main_" <<< "${SKIP_EXTERNAL_TRIGGER}"; then + echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY + echo "> Github organizational variable \`SKIP_EXTERNAL_TRIGGER\` contains \`phpmyadmin_main_\`; will skip trigger if version matches." >> $GITHUB_STEP_SUMMARY + elif grep -q "^phpmyadmin_main" <<< "${SKIP_EXTERNAL_TRIGGER}"; then echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY echo "> Github organizational variable \`SKIP_EXTERNAL_TRIGGER\` contains \`phpmyadmin_main\`; skipping trigger." >> $GITHUB_STEP_SUMMARY exit 0 @@ -25,6 +31,11 @@ jobs: printf "\n## Retrieving external version\n\n" >> $GITHUB_STEP_SUMMARY EXT_RELEASE=$(curl -sL 'https://www.phpmyadmin.net/home_page/version.txt' | head -n 1 | cut -d ' ' -f 1) echo "Type is \`custom_version_command\`" >> $GITHUB_STEP_SUMMARY + if grep -q "^phpmyadmin_main_${EXT_RELEASE}" <<< "${SKIP_EXTERNAL_TRIGGER}"; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Github organizational variable \`SKIP_EXTERNAL_TRIGGER\` matches current external release; skipping trigger." >> $GITHUB_STEP_SUMMARY + exit 0 + fi if [ -z "${EXT_RELEASE}" ] || [ "${EXT_RELEASE}" == "null" ]; then echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY echo "> Can't retrieve external version, exiting" >> $GITHUB_STEP_SUMMARY @@ -35,24 +46,43 @@ jobs: "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} exit 1 fi - EXT_RELEASE=$(echo ${EXT_RELEASE} | sed 's/[~,%@+;:/]//g') - echo "External version: \`${EXT_RELEASE}\`" >> $GITHUB_STEP_SUMMARY + EXT_RELEASE_SANITIZED=$(echo ${EXT_RELEASE} | sed 's/[~,%@+;:/]//g') + echo "Sanitized external version: \`${EXT_RELEASE_SANITIZED}\`" >> $GITHUB_STEP_SUMMARY echo "Retrieving last pushed version" >> $GITHUB_STEP_SUMMARY image="linuxserver/phpmyadmin" tag="latest" token=$(curl -sX GET \ "https://ghcr.io/token?scope=repository%3Alinuxserver%2Fphpmyadmin%3Apull" \ | jq -r '.token') - multidigest=$(curl -s \ - --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ - --header "Authorization: Bearer ${token}" \ - "https://ghcr.io/v2/${image}/manifests/${tag}" \ - | jq -r 'first(.manifests[].digest)') - digest=$(curl -s \ + multidigest=$(curl -s \ + --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + --header "Accept: application/vnd.oci.image.index.v1+json" \ + --header "Authorization: Bearer ${token}" \ + "https://ghcr.io/v2/${image}/manifests/${tag}") + if jq -e '.layers // empty' <<< "${multidigest}" >/dev/null 2>&1; then + # If there's a layer element it's a single-arch manifest so just get that digest + digest=$(jq -r '.config.digest' <<< "${multidigest}") + else + # Otherwise it's multi-arch or has manifest annotations + if jq -e '.manifests[]?.annotations // empty' <<< "${multidigest}" >/dev/null 2>&1; then + # Check for manifest annotations and delete if found + multidigest=$(jq 'del(.manifests[] | select(.annotations))' <<< "${multidigest}") + fi + if [[ $(jq '.manifests | length' <<< "${multidigest}") -gt 1 ]]; then + # If there's still more than one digest, it's multi-arch + multidigest=$(jq -r ".manifests[] | select(.platform.architecture == \"amd64\").digest?" <<< "${multidigest}") + else + # Otherwise it's single arch + multidigest=$(jq -r ".manifests[].digest?" <<< "${multidigest}") + fi + if digest=$(curl -s \ --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + --header "Accept: application/vnd.oci.image.manifest.v1+json" \ --header "Authorization: Bearer ${token}" \ - "https://ghcr.io/v2/${image}/manifests/${multidigest}" \ - | jq -r '.config.digest') + "https://ghcr.io/v2/${image}/manifests/${multidigest}"); then + digest=$(jq -r '.config.digest' <<< "${digest}"); + fi + fi image_info=$(curl -sL \ --header "Authorization: Bearer ${token}" \ "https://ghcr.io/v2/${image}/blobs/${digest}") @@ -73,8 +103,8 @@ jobs: exit 1 fi echo "Last pushed version: \`${IMAGE_VERSION}\`" >> $GITHUB_STEP_SUMMARY - if [ "${EXT_RELEASE}" == "${IMAGE_VERSION}" ]; then - echo "Version \`${EXT_RELEASE}\` already pushed, exiting" >> $GITHUB_STEP_SUMMARY + if [ "${EXT_RELEASE_SANITIZED}" == "${IMAGE_VERSION}" ]; then + echo "Sanitized version \`${EXT_RELEASE_SANITIZED}\` already pushed, exiting" >> $GITHUB_STEP_SUMMARY exit 0 elif [ $(curl -s https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-phpmyadmin/job/main/lastBuild/api/json | jq -r '.building') == "true" ]; then echo "New version \`${EXT_RELEASE}\` found; but there already seems to be an active build on Jenkins; exiting" >> $GITHUB_STEP_SUMMARY @@ -89,8 +119,8 @@ jobs: "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} else printf "\n## Trigger new build\n\n" >> $GITHUB_STEP_SUMMARY - echo "New version \`${EXT_RELEASE}\` found; old version was \`${IMAGE_VERSION}\`. Triggering new build" >> $GITHUB_STEP_SUMMARY - if "${artifacts_found}" == "true" ]]; then + echo "New sanitized version \`${EXT_RELEASE_SANITIZED}\` found; old version was \`${IMAGE_VERSION}\`. Triggering new build" >> $GITHUB_STEP_SUMMARY + if [[ "${artifacts_found}" == "true" ]]; then echo "All artifacts seem to be uploaded." >> $GITHUB_STEP_SUMMARY fi response=$(curl -iX POST \ @@ -109,7 +139,7 @@ jobs: --data-urlencode "description=GHA external trigger https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ --data-urlencode "Submit=Submit" echo "**** Notifying Discord ****" - TRIGGER_REASON="A version change was detected for phpmyadmin tag latest. Old version:${IMAGE_VERSION} New version:${EXT_RELEASE}" + TRIGGER_REASON="A version change was detected for phpmyadmin tag latest. Old version:${IMAGE_VERSION} New version:${EXT_RELEASE_SANITIZED}" curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903, "description": "**Build Triggered** \n**Reason:** '"${TRIGGER_REASON}"' \n**Build URL:** '"${buildurl}display/redirect"' \n"}], "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} diff --git a/.github/workflows/external_trigger_scheduler.yml b/.github/workflows/external_trigger_scheduler.yml index dcafde1..c36e482 100644 --- a/.github/workflows/external_trigger_scheduler.yml +++ b/.github/workflows/external_trigger_scheduler.yml @@ -5,6 +5,9 @@ on: - cron: '43 * * * *' workflow_dispatch: +permissions: + contents: read + jobs: external-trigger-scheduler: runs-on: ubuntu-latest diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 8c86d93..182c3be 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -2,8 +2,14 @@ name: Greetings on: [pull_request_target, issues] +permissions: + contents: read + jobs: greeting: + permissions: + issues: write + pull-requests: write runs-on: ubuntu-latest steps: - uses: actions/first-interaction@v1 diff --git a/.github/workflows/package_trigger_scheduler.yml b/.github/workflows/package_trigger_scheduler.yml index ccf441c..3d18f04 100644 --- a/.github/workflows/package_trigger_scheduler.yml +++ b/.github/workflows/package_trigger_scheduler.yml @@ -5,6 +5,9 @@ on: - cron: '24 21 * * 5' workflow_dispatch: +permissions: + contents: read + jobs: package-trigger-scheduler: runs-on: ubuntu-latest @@ -27,9 +30,18 @@ jobs: fi printf "\n## Evaluating \`%s\`\n\n" ${br} >> $GITHUB_STEP_SUMMARY JENKINS_VARS=$(curl -sX GET https://raw.githubusercontent.com/linuxserver/docker-phpmyadmin/${br}/jenkins-vars.yml) - if [[ "${br}" == $(yq -r '.ls_branch' <<< "${JENKINS_VARS}") ]]; then + if ! curl -sfX GET https://raw.githubusercontent.com/linuxserver/docker-phpmyadmin/${br}/Jenkinsfile >/dev/null 2>&1; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> No Jenkinsfile found. Branch is either deprecated or is an early dev branch." >> $GITHUB_STEP_SUMMARY + skipped_branches="${skipped_branches}${br} " + elif [[ "${br}" == $(yq -r '.ls_branch' <<< "${JENKINS_VARS}") ]]; then echo "Branch appears to be live; checking workflow." >> $GITHUB_STEP_SUMMARY - if [[ $(yq -r '.skip_package_check' <<< "${JENKINS_VARS}") == "true" ]]; then + README_VARS=$(curl -sX GET https://raw.githubusercontent.com/linuxserver/docker-phpmyadmin/${br}/readme-vars.yml) + if [[ $(yq -r '.project_deprecation_status' <<< "${README_VARS}") == "true" ]]; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Branch appears to be deprecated; skipping trigger." >> $GITHUB_STEP_SUMMARY + skipped_branches="${skipped_branches}${br} " + elif [[ $(yq -r '.skip_package_check' <<< "${JENKINS_VARS}") == "true" ]]; then echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY echo "> Skipping branch ${br} due to \`skip_package_check\` being set in \`jenkins-vars.yml\`." >> $GITHUB_STEP_SUMMARY skipped_branches="${skipped_branches}${br} " @@ -37,7 +49,7 @@ jobs: echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY echo "> Github organizational variable \`SKIP_PACKAGE_TRIGGER\` contains \`phpmyadmin_${br}\`; skipping trigger." >> $GITHUB_STEP_SUMMARY skipped_branches="${skipped_branches}${br} " - elif [ $(curl -s https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-phpmyadmin/job/${br}/lastBuild/api/json | jq -r '.building') == "true" ]; then + elif [ $(curl -s https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-phpmyadmin/job/${br}/lastBuild/api/json | jq -r '.building' 2>/dev/null) == "true" ]; then echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY echo "> There already seems to be an active build on Jenkins; skipping package trigger for ${br}" >> $GITHUB_STEP_SUMMARY skipped_branches="${skipped_branches}${br} " @@ -49,6 +61,11 @@ jobs: response=$(curl -iX POST \ https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-phpmyadmin/job/${br}/buildWithParameters?PACKAGE_CHECK=true \ --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} | grep -i location | sed "s|^[L|l]ocation: \(.*\)|\1|") + if [[ -z "${response}" ]]; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Jenkins build could not be triggered. Skipping branch." + continue + fi echo "Jenkins [job queue url](${response%$'\r'})" >> $GITHUB_STEP_SUMMARY echo "Sleeping 10 seconds until job starts" >> $GITHUB_STEP_SUMMARY sleep 10 @@ -56,11 +73,14 @@ jobs: buildurl="${buildurl%$'\r'}" echo "Jenkins job [build url](${buildurl})" >> $GITHUB_STEP_SUMMARY echo "Attempting to change the Jenkins job description" >> $GITHUB_STEP_SUMMARY - curl -iX POST \ + if ! curl -ifX POST \ "${buildurl}submitDescription" \ --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} \ --data-urlencode "description=GHA package trigger https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ - --data-urlencode "Submit=Submit" + --data-urlencode "Submit=Submit"; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Unable to change the Jenkins job description." + fi sleep 20 fi else diff --git a/.github/workflows/permissions.yml b/.github/workflows/permissions.yml old mode 100755 new mode 100644 diff --git a/Dockerfile b/Dockerfile index 3cad6ff..6b3782a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1 -FROM ghcr.io/linuxserver/baseimage-alpine-nginx:3.20 +FROM ghcr.io/linuxserver/baseimage-alpine-nginx:3.23 # set version label ARG BUILD_DATE @@ -11,9 +11,9 @@ LABEL maintainer="thespad" # environment settings ARG PHPMYADMIN_RELEASE_GPG_KEY="3D06A59ECE730EB71B511C17CE752F178259BD92" -ENV MAX_EXECUTION_TIME 600 -ENV MEMORY_LIMIT 512M -ENV UPLOAD_LIMIT 8192K +ENV MAX_EXECUTION_TIME=600 +ENV MEMORY_LIMIT=512M +ENV UPLOAD_LIMIT=8192K RUN \ apk add --no-cache --virtual=build-dependencies \ @@ -21,17 +21,16 @@ RUN \ gpg-agent \ gnupg-dirmngr && \ apk add --no-cache \ - php83-bz2 \ - php83-dom \ - php83-gd \ - php83-mysqli \ - php83-opcache \ - php83-pecl-uploadprogress \ - php83-tokenizer && \ + php85-bz2 \ + php85-dom \ + php85-gd \ + php85-mysqli \ + php85-pecl-uploadprogress \ + php85-tokenizer && \ echo "**** configure php-fpm to pass env vars ****" && \ - sed -E -i 's/^;?clear_env ?=.*$/clear_env = no/g' /etc/php83/php-fpm.d/www.conf && \ - grep -qxF 'clear_env = no' /etc/php83/php-fpm.d/www.conf || echo 'clear_env = no' >> /etc/php83/php-fpm.d/www.conf && \ - echo "env[PATH] = /usr/local/bin:/usr/bin:/bin" >> /etc/php83/php-fpm.conf && \ + sed -E -i 's/^;?clear_env ?=.*$/clear_env = no/g' /etc/php85/php-fpm.d/www.conf && \ + if ! grep -qxF 'clear_env = no' /etc/php85/php-fpm.d/www.conf; then echo 'clear_env = no' >> /etc/php85/php-fpm.d/www.conf; fi && \ + echo "env[PATH] = /usr/local/bin:/usr/bin:/bin" >> /etc/php85/php-fpm.conf && \ echo "**** setup php opcache ****" && \ { \ echo 'opcache.memory_consumption=128'; \ @@ -39,12 +38,12 @@ RUN \ echo 'opcache.max_accelerated_files=4000'; \ echo 'opcache.revalidate_freq=2'; \ echo 'opcache.fast_shutdown=1'; \ - } > /etc/php83/conf.d/opcache-recommended.ini; \ + } > /etc/php85/conf.d/opcache-recommended.ini; \ \ { \ echo 'session.cookie_httponly=1'; \ echo 'session.use_strict_mode=1'; \ - } > /etc/php83/conf.d/session-strict.ini; \ + } > /etc/php85/conf.d/session-strict.ini; \ \ { \ echo 'allow_url_fopen=Off'; \ @@ -53,7 +52,7 @@ RUN \ echo 'memory_limit=${MEMORY_LIMIT}'; \ echo 'post_max_size=${UPLOAD_LIMIT}'; \ echo 'upload_max_filesize=${UPLOAD_LIMIT}'; \ - } > /etc/php83/conf.d/phpmyadmin-misc.ini && \ + } > /etc/php85/conf.d/phpmyadmin-misc.ini && \ echo "**** install phpmyadmin ****" && \ mkdir -p /app/www/public && \ if [ -z ${PHPMYADMIN_VERSION+x} ]; then \ diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64 index 9ad7aa0..eacb3e6 100644 --- a/Dockerfile.aarch64 +++ b/Dockerfile.aarch64 @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1 -FROM ghcr.io/linuxserver/baseimage-alpine-nginx:arm64v8-3.20 +FROM ghcr.io/linuxserver/baseimage-alpine-nginx:arm64v8-3.23 # set version label ARG BUILD_DATE @@ -11,9 +11,9 @@ LABEL maintainer="thespad" # environment settings ARG PHPMYADMIN_RELEASE_GPG_KEY="3D06A59ECE730EB71B511C17CE752F178259BD92" -ENV MAX_EXECUTION_TIME 600 -ENV MEMORY_LIMIT 512M -ENV UPLOAD_LIMIT 8192K +ENV MAX_EXECUTION_TIME=600 +ENV MEMORY_LIMIT=512M +ENV UPLOAD_LIMIT=8192K RUN \ apk add --no-cache --virtual=build-dependencies \ @@ -21,17 +21,16 @@ RUN \ gpg-agent \ gnupg-dirmngr && \ apk add --no-cache \ - php83-bz2 \ - php83-dom \ - php83-gd \ - php83-mysqli \ - php83-opcache \ - php83-pecl-uploadprogress \ - php83-tokenizer && \ + php85-bz2 \ + php85-dom \ + php85-gd \ + php85-mysqli \ + php85-pecl-uploadprogress \ + php85-tokenizer && \ echo "**** configure php-fpm to pass env vars ****" && \ - sed -E -i 's/^;?clear_env ?=.*$/clear_env = no/g' /etc/php83/php-fpm.d/www.conf && \ - grep -qxF 'clear_env = no' /etc/php83/php-fpm.d/www.conf || echo 'clear_env = no' >> /etc/php83/php-fpm.d/www.conf && \ - echo "env[PATH] = /usr/local/bin:/usr/bin:/bin" >> /etc/php83/php-fpm.conf && \ + sed -E -i 's/^;?clear_env ?=.*$/clear_env = no/g' /etc/php85/php-fpm.d/www.conf && \ + if ! grep -qxF 'clear_env = no' /etc/php85/php-fpm.d/www.conf; then echo 'clear_env = no' >> /etc/php85/php-fpm.d/www.conf; fi && \ + echo "env[PATH] = /usr/local/bin:/usr/bin:/bin" >> /etc/php85/php-fpm.conf && \ echo "**** setup php opcache ****" && \ { \ echo 'opcache.memory_consumption=128'; \ @@ -39,12 +38,12 @@ RUN \ echo 'opcache.max_accelerated_files=4000'; \ echo 'opcache.revalidate_freq=2'; \ echo 'opcache.fast_shutdown=1'; \ - } > /etc/php83/conf.d/opcache-recommended.ini; \ + } > /etc/php85/conf.d/opcache-recommended.ini; \ \ { \ echo 'session.cookie_httponly=1'; \ echo 'session.use_strict_mode=1'; \ - } > /etc/php83/conf.d/session-strict.ini; \ + } > /etc/php85/conf.d/session-strict.ini; \ \ { \ echo 'allow_url_fopen=Off'; \ @@ -53,7 +52,7 @@ RUN \ echo 'memory_limit=${MEMORY_LIMIT}'; \ echo 'post_max_size=${UPLOAD_LIMIT}'; \ echo 'upload_max_filesize=${UPLOAD_LIMIT}'; \ - } > /etc/php83/conf.d/phpmyadmin-misc.ini && \ + } > /etc/php85/conf.d/phpmyadmin-misc.ini && \ echo "**** install phpmyadmin ****" && \ mkdir -p /app/www/public && \ if [ -z ${PHPMYADMIN_VERSION+x} ]; then \ diff --git a/Jenkinsfile b/Jenkinsfile index dbd93e2..7287564 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,7 +8,7 @@ pipeline { } // Input to determine if this is a package check parameters { - string(defaultValue: 'false', description: 'package check run', name: 'PACKAGE_CHECK') + string(defaultValue: 'false', description: 'package check run', name: 'PACKAGE_CHECK') } // Configuration for the variables used for this specific repo environment { @@ -59,13 +59,27 @@ pipeline { steps{ echo "Running on node: ${NODE_NAME}" sh '''#! /bin/bash - containers=$(docker ps -aq) + echo "Pruning builder" + docker builder prune -f --builder container || : + containers=$(docker ps -q) if [[ -n "${containers}" ]]; then - docker stop ${containers} + BUILDX_CONTAINER_ID=$(docker ps -qf 'name=buildx_buildkit') + for container in ${containers}; do + if [[ "${container}" == "${BUILDX_CONTAINER_ID}" ]]; then + echo "skipping buildx container in docker stop" + else + echo "Stopping container ${container}" + docker stop ${container} + fi + done fi - docker system prune -af --volumes || : ''' + docker system prune -f --volumes || : + docker image prune -af || : + ''' script{ env.EXIT_STATUS = '' + env.CI_TEST_ATTEMPTED = '' + env.PUSH_ATTEMPTED = '' env.LS_RELEASE = sh( script: '''docker run --rm quay.io/skopeo/stable:v1 inspect docker://ghcr.io/${LS_USER}/${CONTAINER_NAME}:latest 2>/dev/null | jq -r '.Labels.build_version' | awk '{print $3}' | grep '\\-ls' || : ''', returnStdout: true).trim() @@ -85,7 +99,11 @@ pipeline { env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.DOCKERHUB_IMAGE + '/tags/' env.PULL_REQUEST = env.CHANGE_ID env.TEMPLATED_FILES = 'Jenkinsfile README.md LICENSE .editorconfig ./.github/CONTRIBUTING.md ./.github/FUNDING.yml ./.github/ISSUE_TEMPLATE/config.yml ./.github/ISSUE_TEMPLATE/issue.bug.yml ./.github/ISSUE_TEMPLATE/issue.feature.yml ./.github/PULL_REQUEST_TEMPLATE.md ./.github/workflows/external_trigger_scheduler.yml ./.github/workflows/greetings.yml ./.github/workflows/package_trigger_scheduler.yml ./.github/workflows/call_issue_pr_tracker.yml ./.github/workflows/call_issues_cron.yml ./.github/workflows/permissions.yml ./.github/workflows/external_trigger.yml' + if ( env.SYFT_IMAGE_TAG == null ) { + env.SYFT_IMAGE_TAG = 'latest' + } } + echo "Using syft image tag ${SYFT_IMAGE_TAG}" sh '''#! /bin/bash echo "The default github branch detected as ${GH_DEFAULT_BRANCH}" ''' script{ @@ -194,6 +212,8 @@ pipeline { env.VERSION_TAG = env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER env.META_TAG = env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN + env.BUILDCACHE = 'docker.io/lsiodev/buildcache,registry.gitlab.com/linuxserver.io/docker-jenkins-builder/lsiodev-buildcache,ghcr.io/linuxserver/lsiodev-buildcache,quay.io/linuxserver.io/lsiodev-buildcache' + env.CITEST_IMAGETAG = 'latest' } } } @@ -218,6 +238,8 @@ pipeline { env.META_TAG = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.DEV_DOCKERHUB_IMAGE + '/tags/' + env.BUILDCACHE = 'docker.io/lsiodev/buildcache,registry.gitlab.com/linuxserver.io/docker-jenkins-builder/lsiodev-buildcache,ghcr.io/linuxserver/lsiodev-buildcache,quay.io/linuxserver.io/lsiodev-buildcache' + env.CITEST_IMAGETAG = 'develop' } } } @@ -242,6 +264,8 @@ pipeline { env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN env.CODE_URL = 'https://github.com/' + env.LS_USER + '/' + env.LS_REPO + '/pull/' + env.PULL_REQUEST env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.PR_DOCKERHUB_IMAGE + '/tags/' + env.BUILDCACHE = 'docker.io/lsiodev/buildcache,registry.gitlab.com/linuxserver.io/docker-jenkins-builder/lsiodev-buildcache,ghcr.io/linuxserver/lsiodev-buildcache,quay.io/linuxserver.io/lsiodev-buildcache' + env.CITEST_IMAGETAG = 'develop' } } } @@ -264,7 +288,7 @@ pipeline { -v ${WORKSPACE}:/mnt \ -e AWS_ACCESS_KEY_ID=\"${S3_KEY}\" \ -e AWS_SECRET_ACCESS_KEY=\"${S3_SECRET}\" \ - ghcr.io/linuxserver/baseimage-alpine:3.20 s6-envdir -fn -- /var/run/s6/container_environment /bin/bash -c "\ + ghcr.io/linuxserver/baseimage-alpine:3.23 s6-envdir -fn -- /var/run/s6/container_environment /bin/bash -c "\ apk add --no-cache python3 && \ python3 -m venv /lsiopy && \ pip install --no-cache-dir -U pip && \ @@ -338,6 +362,35 @@ pipeline { else echo "No templates to delete" fi + echo "Starting Stage 2.5 - Update init diagram" + if ! grep -q 'init_diagram:' readme-vars.yml; then + echo "Adding the key 'init_diagram' to readme-vars.yml" + sed -i '\\|^#.*changelog.*$|d' readme-vars.yml + sed -i 's|^changelogs:|# init diagram\\ninit_diagram:\\n\\n# changelog\\nchangelogs:|' readme-vars.yml + fi + mkdir -p ${TEMPDIR}/d2 + docker run --rm -v ${TEMPDIR}/d2:/output -e PUID=$(id -u) -e PGID=$(id -g) -e RAW="true" ghcr.io/linuxserver/d2-builder:latest ${CONTAINER_NAME}:latest + ls -al ${TEMPDIR}/d2 + yq -ei ".init_diagram |= load_str(\\"${TEMPDIR}/d2/${CONTAINER_NAME}-latest.d2\\")" readme-vars.yml + if [[ $(md5sum readme-vars.yml | cut -c1-8) != $(md5sum ${TEMPDIR}/docker-${CONTAINER_NAME}/readme-vars.yml | cut -c1-8) ]]; then + echo "'init_diagram' has been updated. Updating repo and exiting build, new one will trigger based on commit." + mkdir -p ${TEMPDIR}/repo + git clone https://github.com/${LS_USER}/${LS_REPO}.git ${TEMPDIR}/repo/${LS_REPO} + cd ${TEMPDIR}/repo/${LS_REPO} + git checkout -f main + cp ${WORKSPACE}/readme-vars.yml ${TEMPDIR}/repo/${LS_REPO}/readme-vars.yml + git add readme-vars.yml + git commit -m 'Bot Updating Templated Files' + git pull https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git main + git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git main + echo "true" > /tmp/${COMMIT_SHA}-${BUILD_NUMBER} + echo "Updating templates and exiting build, new one will trigger based on commit" + rm -Rf ${TEMPDIR} + exit 0 + else + echo "false" > /tmp/${COMMIT_SHA}-${BUILD_NUMBER} + echo "Init diagram is unchanged" + fi echo "Starting Stage 3 - Update templates" CURRENTHASH=$(grep -hs ^ ${TEMPLATED_FILES} | md5sum | cut -c1-8) cd ${TEMPDIR}/docker-${CONTAINER_NAME} @@ -546,8 +599,45 @@ pipeline { --label \"org.opencontainers.image.title=Phpmyadmin\" \ --label \"org.opencontainers.image.description=[Phpmyadmin](https://github.com/phpmyadmin/phpmyadmin/) is a free software tool written in PHP, intended to handle the administration of MySQL over the Web. phpMyAdmin supports a wide range of operations on MySQL and MariaDB. \" \ --no-cache --pull -t ${IMAGE}:${META_TAG} --platform=linux/amd64 \ - --provenance=false --sbom=false \ + --provenance=true --sbom=true --builder=container --load \ --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${VERSION_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." + sh '''#! /bin/bash + set -e + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + docker tag ${IMAGE}:${META_TAG} ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} + done + ''' + withCredentials([ + [ + $class: 'UsernamePasswordMultiBinding', + credentialsId: 'Quay.io-Robot', + usernameVariable: 'QUAYUSER', + passwordVariable: 'QUAYPASS' + ] + ]) { + retry_backoff(5,5) { + sh '''#! /bin/bash + set -e + echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin + echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin + echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin + echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin + + if [[ "${PACKAGE_CHECK}" != "true" ]]; then + declare -A pids + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + docker push ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} & + pids[$!]="$i" + done + for p in "${!pids[@]}"; do + wait "$p" || { [[ "${pids[$p]}" != *"quay.io"* ]] && exit 1; } + done + fi + ''' + } + } } } // Build MultiArch Docker containers for push to LS Repo @@ -578,8 +668,45 @@ pipeline { --label \"org.opencontainers.image.title=Phpmyadmin\" \ --label \"org.opencontainers.image.description=[Phpmyadmin](https://github.com/phpmyadmin/phpmyadmin/) is a free software tool written in PHP, intended to handle the administration of MySQL over the Web. phpMyAdmin supports a wide range of operations on MySQL and MariaDB. \" \ --no-cache --pull -t ${IMAGE}:amd64-${META_TAG} --platform=linux/amd64 \ - --provenance=false --sbom=false \ + --provenance=true --sbom=true --builder=container --load \ --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${VERSION_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." + sh '''#! /bin/bash + set -e + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + docker tag ${IMAGE}:amd64-${META_TAG} ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} + done + ''' + withCredentials([ + [ + $class: 'UsernamePasswordMultiBinding', + credentialsId: 'Quay.io-Robot', + usernameVariable: 'QUAYUSER', + passwordVariable: 'QUAYPASS' + ] + ]) { + retry_backoff(5,5) { + sh '''#! /bin/bash + set -e + echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin + echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin + echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin + echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin + + if [[ "${PACKAGE_CHECK}" != "true" ]]; then + declare -A pids + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + docker push ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} & + pids[$!]="$i" + done + for p in "${!pids[@]}"; do + wait "$p" || { [[ "${pids[$p]}" != *"quay.io"* ]] && exit 1; } + done + fi + ''' + } + } } } stage('Build ARM64') { @@ -588,10 +715,6 @@ pipeline { } steps { echo "Running on node: ${NODE_NAME}" - echo 'Logging into Github' - sh '''#! /bin/bash - echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin - ''' sh "sed -r -i 's|(^FROM .*)|\\1\\n\\nENV LSIO_FIRST_PARTY=true|g' Dockerfile.aarch64" sh "docker buildx build \ --label \"org.opencontainers.image.created=${GITHUB_DATE}\" \ @@ -607,18 +730,52 @@ pipeline { --label \"org.opencontainers.image.title=Phpmyadmin\" \ --label \"org.opencontainers.image.description=[Phpmyadmin](https://github.com/phpmyadmin/phpmyadmin/) is a free software tool written in PHP, intended to handle the administration of MySQL over the Web. phpMyAdmin supports a wide range of operations on MySQL and MariaDB. \" \ --no-cache --pull -f Dockerfile.aarch64 -t ${IMAGE}:arm64v8-${META_TAG} --platform=linux/arm64 \ - --provenance=false --sbom=false \ + --provenance=true --sbom=true --builder=container --load \ --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${VERSION_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." - sh "docker tag ${IMAGE}:arm64v8-${META_TAG} ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER}" - retry_backoff(5,5) { - sh "docker push ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER}" + sh '''#! /bin/bash + set -e + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + docker tag ${IMAGE}:arm64v8-${META_TAG} ${i}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} + done + ''' + withCredentials([ + [ + $class: 'UsernamePasswordMultiBinding', + credentialsId: 'Quay.io-Robot', + usernameVariable: 'QUAYUSER', + passwordVariable: 'QUAYPASS' + ] + ]) { + retry_backoff(5,5) { + sh '''#! /bin/bash + set -e + echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin + echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin + echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin + echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin + if [[ "${PACKAGE_CHECK}" != "true" ]]; then + declare -A pids + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + docker push ${i}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} & + pids[$!]="$i" + done + for p in "${!pids[@]}"; do + wait "$p" || { [[ "${pids[$p]}" != *"quay.io"* ]] && exit 1; } + done + fi + ''' + } } sh '''#! /bin/bash containers=$(docker ps -aq) if [[ -n "${containers}" ]]; then docker stop ${containers} fi - docker system prune -af --volumes || : ''' + docker system prune -f --volumes || : + docker image prune -af || : + ''' } } } @@ -643,7 +800,7 @@ pipeline { docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock:ro \ -v ${TEMPDIR}:/tmp \ - ghcr.io/anchore/syft:latest \ + ghcr.io/anchore/syft:${SYFT_IMAGE_TAG} \ ${LOCAL_CONTAINER} -o table=/tmp/package_versions.txt NEW_PACKAGE_TAG=$(md5sum ${TEMPDIR}/package_versions.txt | cut -c1-8 ) echo "Package tag sha from current packages in buit container is ${NEW_PACKAGE_TAG} comparing to old ${PACKAGE_TAG} from github" @@ -719,6 +876,7 @@ pipeline { script{ env.CI_URL = 'https://ci-tests.linuxserver.io/' + env.IMAGE + '/' + env.META_TAG + '/index.html' env.CI_JSON_URL = 'https://ci-tests.linuxserver.io/' + env.IMAGE + '/' + env.META_TAG + '/report.json' + env.CI_TEST_ATTEMPTED = 'true' } sh '''#! /bin/bash set -e @@ -730,7 +888,7 @@ pipeline { CI_DOCKERENV="LSIO_FIRST_PARTY=true" fi fi - docker pull ghcr.io/linuxserver/ci:latest + docker pull ghcr.io/linuxserver/ci:${CITEST_IMAGETAG} if [ "${MULTIARCH}" == "true" ]; then docker pull ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} --platform=arm64 docker tag ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} ${IMAGE}:arm64v8-${META_TAG} @@ -753,7 +911,10 @@ pipeline { -e WEB_AUTH=\"${CI_AUTH}\" \ -e WEB_PATH=\"${CI_WEBPATH}\" \ -e NODE_NAME=\"${NODE_NAME}\" \ - -t ghcr.io/linuxserver/ci:latest \ + -e SYFT_IMAGE_TAG=\"${CI_SYFT_IMAGE_TAG:-${SYFT_IMAGE_TAG}}\" \ + -e COMMIT_SHA=\"${COMMIT_SHA}\" \ + -e BUILD_NUMBER=\"${BUILD_NUMBER}\" \ + -t ghcr.io/linuxserver/ci:${CITEST_IMAGETAG} \ python3 test_build.py''' } } @@ -768,37 +929,28 @@ pipeline { environment name: 'EXIT_STATUS', value: '' } steps { - withCredentials([ - [ - $class: 'UsernamePasswordMultiBinding', - credentialsId: 'Quay.io-Robot', - usernameVariable: 'QUAYUSER', - passwordVariable: 'QUAYPASS' - ] - ]) { - retry_backoff(5,5) { - sh '''#! /bin/bash - set -e - echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin - echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin - echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin - echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin - for PUSHIMAGE in "${GITHUBIMAGE}" "${GITLABIMAGE}" "${QUAYIMAGE}" "${IMAGE}"; do - docker tag ${IMAGE}:${META_TAG} ${PUSHIMAGE}:${META_TAG} - docker tag ${PUSHIMAGE}:${META_TAG} ${PUSHIMAGE}:latest - docker tag ${PUSHIMAGE}:${META_TAG} ${PUSHIMAGE}:${EXT_RELEASE_TAG} - if [ -n "${SEMVER}" ]; then - docker tag ${PUSHIMAGE}:${META_TAG} ${PUSHIMAGE}:${SEMVER} - fi - docker push ${PUSHIMAGE}:latest - docker push ${PUSHIMAGE}:${META_TAG} - docker push ${PUSHIMAGE}:${EXT_RELEASE_TAG} - if [ -n "${SEMVER}" ]; then - docker push ${PUSHIMAGE}:${SEMVER} - fi + script{ + env.PUSH_ATTEMPTED = 'true' + } + retry_backoff(5,5) { + sh '''#! /bin/bash + set -e + for PUSHIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do + [[ ${PUSHIMAGE%%/*} =~ \\. ]] && PUSHIMAGEPLUS="${PUSHIMAGE}" || PUSHIMAGEPLUS="docker.io/${PUSHIMAGE}" + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + if [[ "${PUSHIMAGEPLUS}" == "$(cut -d "/" -f1 <<< ${i})"* ]]; then + CACHEIMAGE=${i} + fi done - ''' - } + docker buildx imagetools create --prefer-index=false -t ${PUSHIMAGE}:${META_TAG} -t ${PUSHIMAGE}:latest -t ${PUSHIMAGE}:${EXT_RELEASE_TAG} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${PUSHIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + if [ -n "${SEMVER}" ]; then + docker buildx imagetools create --prefer-index=false -t ${PUSHIMAGE}:${SEMVER} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${PUSHIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + fi + done + ''' } } } @@ -809,57 +961,48 @@ pipeline { environment name: 'EXIT_STATUS', value: '' } steps { - withCredentials([ - [ - $class: 'UsernamePasswordMultiBinding', - credentialsId: 'Quay.io-Robot', - usernameVariable: 'QUAYUSER', - passwordVariable: 'QUAYPASS' - ] - ]) { - retry_backoff(5,5) { - sh '''#! /bin/bash - set -e - echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin - echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin - echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin - echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin - if [ "${CI}" == "false" ]; then - docker pull ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} --platform=arm64 - docker tag ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} ${IMAGE}:arm64v8-${META_TAG} + script{ + env.PUSH_ATTEMPTED = 'true' + } + retry_backoff(5,5) { + sh '''#! /bin/bash + set -e + for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do + if [[ "${MANIFESTIMAGE%%/*}" =~ \\. ]]; then + MANIFESTIMAGEPLUS="${MANIFESTIMAGE}" + else + MANIFESTIMAGEPLUS="docker.io/${MANIFESTIMAGE}" fi - for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do - docker tag ${IMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG} - docker tag ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-latest - docker tag ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} - docker tag ${IMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG} - docker tag ${MANIFESTIMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-latest - docker tag ${MANIFESTIMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} - if [ -n "${SEMVER}" ]; then - docker tag ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-${SEMVER} - docker tag ${MANIFESTIMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${SEMVER} - fi - docker push ${MANIFESTIMAGE}:amd64-${META_TAG} - docker push ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} - docker push ${MANIFESTIMAGE}:amd64-latest - docker push ${MANIFESTIMAGE}:arm64v8-${META_TAG} - docker push ${MANIFESTIMAGE}:arm64v8-latest - docker push ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} - if [ -n "${SEMVER}" ]; then - docker push ${MANIFESTIMAGE}:amd64-${SEMVER} - docker push ${MANIFESTIMAGE}:arm64v8-${SEMVER} - fi + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + if [[ "${MANIFESTIMAGEPLUS}" == "$(cut -d "/" -f1 <<< ${i})"* ]]; then + CACHEIMAGE=${i} + fi done - for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do - docker buildx imagetools create -t ${MANIFESTIMAGE}:latest ${MANIFESTIMAGE}:amd64-latest ${MANIFESTIMAGE}:arm64v8-latest - docker buildx imagetools create -t ${MANIFESTIMAGE}:${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG} - docker buildx imagetools create -t ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} - if [ -n "${SEMVER}" ]; then - docker buildx imagetools create -t ${MANIFESTIMAGE}:${SEMVER} ${MANIFESTIMAGE}:amd64-${SEMVER} ${MANIFESTIMAGE}:arm64v8-${SEMVER} - fi - done - ''' - } + docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:amd64-${META_TAG} -t ${MANIFESTIMAGE}:amd64-latest -t ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:arm64v8-${META_TAG} -t ${MANIFESTIMAGE}:arm64v8-latest -t ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} ${CACHEIMAGE}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + if [ -n "${SEMVER}" ]; then + docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:amd64-${SEMVER} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:arm64v8-${SEMVER} ${CACHEIMAGE}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + fi + done + for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do + docker buildx imagetools create -t ${MANIFESTIMAGE}:latest ${MANIFESTIMAGE}:amd64-latest ${MANIFESTIMAGE}:arm64v8-latest || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + docker buildx imagetools create -t ${MANIFESTIMAGE}:${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + docker buildx imagetools create -t ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + if [ -n "${SEMVER}" ]; then + docker buildx imagetools create -t ${MANIFESTIMAGE}:${SEMVER} ${MANIFESTIMAGE}:amd64-${SEMVER} ${MANIFESTIMAGE}:arm64v8-${SEMVER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + fi + done + ''' } } } @@ -874,23 +1017,41 @@ pipeline { environment name: 'EXIT_STATUS', value: '' } steps { - echo "Pushing New tag for current commit ${META_TAG}" - sh '''curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/git/tags \ - -d '{"tag":"'${META_TAG}'",\ - "object": "'${COMMIT_SHA}'",\ - "message": "Tagging Release '${EXT_RELEASE_CLEAN}'-ls'${LS_TAG_NUMBER}' to main",\ - "type": "commit",\ - "tagger": {"name": "LinuxServer-CI","email": "ci@linuxserver.io","date": "'${GITHUB_DATE}'"}}' ''' - echo "Pushing New release for Tag" sh '''#! /bin/bash + echo "Auto-generating release notes" + if [ "$(git tag --points-at HEAD)" != "" ]; then + echo "Existing tag points to current commit, suggesting no new LS changes" + AUTO_RELEASE_NOTES="No changes" + else + AUTO_RELEASE_NOTES=$(curl -fsL -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github+json" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/releases/generate-notes \ + -d '{"tag_name":"'${META_TAG}'",\ + "target_commitish": "main"}' \ + | jq -r '.body' | sed 's|## What.s Changed||') + fi + echo "Pushing New tag for current commit ${META_TAG}" + curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/git/tags \ + -d '{"tag":"'${META_TAG}'",\ + "object": "'${COMMIT_SHA}'",\ + "message": "Tagging Release '${EXT_RELEASE_CLEAN}'-ls'${LS_TAG_NUMBER}' to main",\ + "type": "commit",\ + "tagger": {"name": "LinuxServer-CI","email": "ci@linuxserver.io","date": "'${GITHUB_DATE}'"}}' + echo "Pushing New release for Tag" echo "Updating to ${EXT_RELEASE_CLEAN}" > releasebody.json - echo '{"tag_name":"'${META_TAG}'",\ - "target_commitish": "main",\ - "name": "'${META_TAG}'",\ - "body": "**CI Report:**\\n\\n'${CI_URL:-N/A}'\\n\\n**LinuxServer Changes:**\\n\\n'${LS_RELEASE_NOTES}'\\n\\n**Remote Changes:**\\n\\n' > start - printf '","draft": false,"prerelease": false}' >> releasebody.json - paste -d'\\0' start releasebody.json > releasebody.json.done - curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/releases -d @releasebody.json.done''' + jq -n \ + --arg tag_name "$META_TAG" \ + --arg target_commitish "main" \ + --arg ci_url "${CI_URL:-N/A}" \ + --arg ls_notes "$AUTO_RELEASE_NOTES" \ + --arg remote_notes "$(cat releasebody.json)" \ + '{ + "tag_name": $tag_name, + "target_commitish": $target_commitish, + "name": $tag_name, + "body": ("**CI Report:**\\n\\n" + $ci_url + "\\n\\n**LinuxServer Changes:**\\n\\n" + $ls_notes + "\\n\\n**Remote Changes:**\\n\\n" + $remote_notes), + "draft": false, + "prerelease": false }' > releasebody.json.done + curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/releases -d @releasebody.json.done + ''' } } // Add protection to the release branch @@ -928,98 +1089,13 @@ EOF ) ''' } } - // If this is a Pull request send the CI link as a comment on it - stage('Pull Request Comment') { - when { - not {environment name: 'CHANGE_ID', value: ''} - environment name: 'EXIT_STATUS', value: '' - } - steps { - sh '''#! /bin/bash - # Function to retrieve JSON data from URL - get_json() { - local url="$1" - local response=$(curl -s "$url") - if [ $? -ne 0 ]; then - echo "Failed to retrieve JSON data from $url" - return 1 - fi - local json=$(echo "$response" | jq .) - if [ $? -ne 0 ]; then - echo "Failed to parse JSON data from $url" - return 1 - fi - echo "$json" - } - - build_table() { - local data="$1" - - # Get the keys in the JSON data - local keys=$(echo "$data" | jq -r 'to_entries | map(.key) | .[]') - - # Check if keys are empty - if [ -z "$keys" ]; then - echo "JSON report data does not contain any keys or the report does not exist." - return 1 - fi - - # Build table header - local header="| Tag | Passed |\\n| --- | --- |\\n" - - # Loop through the JSON data to build the table rows - local rows="" - for build in $keys; do - local status=$(echo "$data" | jq -r ".[\\"$build\\"].test_success") - if [ "$status" = "true" ]; then - status="✅" - else - status="❌" - fi - local row="| "$build" | "$status" |\\n" - rows="${rows}${row}" - done - - local table="${header}${rows}" - local escaped_table=$(echo "$table" | sed 's/\"/\\\\"/g') - echo "$escaped_table" - } - - if [[ "${CI}" = "true" ]]; then - # Retrieve JSON data from URL - data=$(get_json "$CI_JSON_URL") - # Create table from JSON data - table=$(build_table "$data") - echo -e "$table" - - curl -X POST -H "Authorization: token $GITHUB_TOKEN" \ - -H "Accept: application/vnd.github.v3+json" \ - "https://api.github.com/repos/$LS_USER/$LS_REPO/issues/$PULL_REQUEST/comments" \ - -d "{\\"body\\": \\"I am a bot, here are the test results for this PR: \\n${CI_URL}\\n${SHELLCHECK_URL}\\n${table}\\"}" - else - curl -X POST -H "Authorization: token $GITHUB_TOKEN" \ - -H "Accept: application/vnd.github.v3+json" \ - "https://api.github.com/repos/$LS_USER/$LS_REPO/issues/$PULL_REQUEST/comments" \ - -d "{\\"body\\": \\"I am a bot, here is the pushed image/manifest for this PR: \\n\\n\\`${GITHUBIMAGE}:${META_TAG}\\`\\"}" - fi - ''' - - } - } } /* ###################### - Send status to Discord + Comment on PR and Send status to Discord ###################### */ post { always { - sh '''#!/bin/bash - rm -rf /config/.ssh/id_sign - rm -rf /config/.ssh/id_sign.pub - git config --global --unset gpg.format - git config --global --unset user.signingkey - git config --global --unset commit.gpgsign - ''' - script{ + script { env.JOB_DATE = sh( script: '''date '+%Y-%m-%dT%H:%M:%S%:z' ''', returnStdout: true).trim() @@ -1062,15 +1138,113 @@ EOF "username": "Jenkins"}' ${BUILDS_DISCORD} ''' } } + script { + if (env.GITHUBIMAGE =~ /lspipepr/){ + if (env.CI_TEST_ATTEMPTED == "true" || env.PUSH_ATTEMPTED == "true"){ + sh '''#! /bin/bash + # Function to retrieve JSON data from URL + get_json() { + local url="$1" + local response=$(curl -s "$url") + if [ $? -ne 0 ]; then + echo "Failed to retrieve JSON data from $url" + return 1 + fi + local json=$(echo "$response" | jq .) + if [ $? -ne 0 ]; then + echo "Failed to parse JSON data from $url" + return 1 + fi + echo "$json" + } + + build_table() { + local data="$1" + + # Get the keys in the JSON data + local keys=$(echo "$data" | jq -r 'to_entries | map(.key) | .[]') + + # Check if keys are empty + if [ -z "$keys" ]; then + echo "JSON report data does not contain any keys or the report does not exist." + return 1 + fi + + # Build table header + local header="| Tag | Passed |\\n| --- | --- |\\n" + + # Loop through the JSON data to build the table rows + local rows="" + for build in $keys; do + local status=$(echo "$data" | jq -r ".[\\"$build\\"].test_success") + if [ "$status" = "true" ]; then + status="✅" + else + status="❌" + fi + local row="| "$build" | "$status" |\\n" + rows="${rows}${row}" + done + + local table="${header}${rows}" + local escaped_table=$(echo "$table" | sed 's/\"/\\\\"/g') + echo "$escaped_table" + } + + if [[ "${CI}" = "true" ]]; then + # Retrieve JSON data from URL + data=$(get_json "$CI_JSON_URL") + # Create table from JSON data + table=$(build_table "$data") + echo -e "$table" + + curl -X POST -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/$LS_USER/$LS_REPO/issues/$PULL_REQUEST/comments" \ + -d "{\\"body\\": \\"I am a bot, here are the test results for this PR for commit ${COMMIT_SHA:0:7} : \\n${CI_URL}\\n${SHELLCHECK_URL}\\n${table}\\"}" + else + curl -X POST -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/$LS_USER/$LS_REPO/issues/$PULL_REQUEST/comments" \ + -d "{\\"body\\": \\"I am a bot, here is the pushed image/manifest for this PR for commit ${COMMIT_SHA:0:7} : \\n\\n\\`${GITHUBIMAGE}:${META_TAG}\\`\\"}" + fi + ''' + } else { + sh '''#! /bin/bash + curl -X POST -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/$LS_USER/$LS_REPO/issues/$PULL_REQUEST/comments" \ + -d "{\\"body\\": \\"I am a bot, the build for PR commit ${COMMIT_SHA:0:7} failed and as a result no CI test was attempted and no images were pushed.\\"}" + ''' + } + } + } + sh '''#!/bin/bash + rm -rf /config/.ssh/id_sign + rm -rf /config/.ssh/id_sign.pub + git config --global --unset gpg.format + git config --global --unset user.signingkey + git config --global --unset commit.gpgsign + ''' } cleanup { sh '''#! /bin/bash - echo "Performing docker system prune!!" - containers=$(docker ps -aq) + echo "Pruning builder!!" + docker builder prune -f --builder container || : + containers=$(docker ps -q) if [[ -n "${containers}" ]]; then - docker stop ${containers} + BUILDX_CONTAINER_ID=$(docker ps -qf 'name=buildx_buildkit') + for container in ${containers}; do + if [[ "${container}" == "${BUILDX_CONTAINER_ID}" ]]; then + echo "skipping buildx container in docker stop" + else + echo "Stopping container ${container}" + docker stop ${container} + fi + done fi - docker system prune -af --volumes || : + docker system prune -f --volumes || : + docker image prune -af || : ''' cleanWs() } diff --git a/README.md b/README.md index 9761983..0b980d0 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,8 @@ [![linuxserver.io](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/linuxserver_medium.png)](https://linuxserver.io) [![Blog](https://img.shields.io/static/v1.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=linuxserver.io&message=Blog)](https://blog.linuxserver.io "all the things you can do with our containers including How-To guides, opinions and much more!") -[![Discord](https://img.shields.io/discord/354974912613449730.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=Discord&logo=discord)](https://discord.gg/YWrKVTn "realtime support / chat with the community and the team.") +[![Discord](https://img.shields.io/discord/354974912613449730.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=Discord&logo=discord)](https://linuxserver.io/discord "realtime support / chat with the community and the team.") [![Discourse](https://img.shields.io/discourse/https/discourse.linuxserver.io/topics.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&logo=discourse)](https://discourse.linuxserver.io "post on our community forum.") -[![Fleet](https://img.shields.io/static/v1.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=linuxserver.io&message=Fleet)](https://fleet.linuxserver.io "an online web interface which displays all of our maintained images.") [![GitHub](https://img.shields.io/static/v1.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=linuxserver.io&message=GitHub&logo=github)](https://github.com/linuxserver "view the source for all of our repositories.") [![Open Collective](https://img.shields.io/opencollective/all/linuxserver.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=Supporters&logo=open%20collective)](https://opencollective.com/linuxserver "please consider helping us by either donating or contributing to our budget") @@ -20,9 +19,8 @@ The [LinuxServer.io](https://linuxserver.io) team brings you another container r Find us at: * [Blog](https://blog.linuxserver.io) - all the things you can do with our containers including How-To guides, opinions and much more! -* [Discord](https://discord.gg/YWrKVTn) - realtime support / chat with the community and the team. +* [Discord](https://linuxserver.io/discord) - realtime support / chat with the community and the team. * [Discourse](https://discourse.linuxserver.io) - post on our community forum. -* [Fleet](https://fleet.linuxserver.io) - an online web interface which displays all of our maintained images. * [GitHub](https://github.com/linuxserver) - view the source for all of our repositories. * [Open Collective](https://opencollective.com/linuxserver) - please consider helping us by either donating or contributing to our budget @@ -55,7 +53,6 @@ The architectures supported by this image are: | :----: | :----: | ---- | | x86-64 | ✅ | amd64-\ | | arm64 | ✅ | arm64v8-\ | -| armhf | ❌ | | ## Application Setup @@ -65,11 +62,30 @@ We support all of the official [environment variables](https://docs.phpmyadmin.n For more information check out the [phpmyadmin documentation](https://www.phpmyadmin.net/docs/). - +## Read-Only Operation + +This image can be run with a read-only container filesystem. For details please [read the docs](https://docs.linuxserver.io/misc/read-only/). + +### Caveats + +* `/tmp` must be mounted to tmpfs +* Custom themes are not supported + +## Non-Root Operation + +This image can be run with a non-root user. For details please [read the docs](https://docs.linuxserver.io/misc/non-root/). + +### Caveats + +* Custom themes are not supported + ## Usage To help you get started creating a container from this image you can either use docker-compose or the docker cli. +>[!NOTE] +>Unless a parameter is flagged as 'optional', it is *mandatory* and a value must be provided. + ### docker-compose (recommended, [click here for more info](https://docs.linuxserver.io/general/docker-compose)) ```yaml @@ -113,13 +129,15 @@ Containers are configured using parameters passed at runtime (such as those abov | Parameter | Function | | :----: | --- | -| `-p 80` | Port for web frontend | +| `-p 80:80` | Port for web frontend | | `-e PUID=1000` | for UserID - see below for explanation | | `-e PGID=1000` | for GroupID - see below for explanation | | `-e TZ=Etc/UTC` | specify a timezone to use, see this [list](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List). | | `-e PMA_ARBITRARY=1` | Set to `1` to allow you to connect to any server. Setting to `0` will only allow you to connect to specified hosts (See Application Setup) | | `-e PMA_ABSOLUTE_URI=https://phpmyadmin.example.com` | Set the URL you will use to access the web frontend | | `-v /config` | Persistent config files | +| `--read-only=true` | Run container with a read-only filesystem. Please [read the docs](https://docs.linuxserver.io/misc/read-only/). | +| `--user=1000:1000` | Run container with a non-root user. Please [read the docs](https://docs.linuxserver.io/misc/non-root/). | ## Environment variables from files (Docker secrets) @@ -283,6 +301,10 @@ Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64 ## Versions +* **28.12.25:** - Rebase to Alpine 3.23. +* **23.08.25:** - Add support for mTLS. Existing users will need to delete their config.inc.php and restart the container. +* **05.07.25:** - Rebase to Alpine 3.22. +* **19.12.24:** - Rebase to Alpine 3.21. * **27.05.24:** - Existing users should update their nginx confs to avoid http2 deprecation warnings. * **24.05.24:** - Rebase to Alpine 3.20. * **28.12.23:** - Rebase to Alpine 3.19 with php 8.3. diff --git a/package_versions.txt b/package_versions.txt index f19b2f7..46c1078 100755 --- a/package_versions.txt +++ b/package_versions.txt @@ -1,170 +1,173 @@ -NAME VERSION TYPE -alpine-baselayout 3.6.5-r0 apk -alpine-baselayout-data 3.6.5-r0 apk -alpine-keys 2.4-r1 apk -alpine-release 3.20.3-r0 apk -aom-libs 3.9.1-r0 apk -apache2-utils 2.4.62-r0 apk -apk-tools 2.14.4-r0 apk -apr 1.7.5-r0 apk -apr-util 1.6.3-r1 apk -argon2-libs 20190702-r5 apk -bacon/bacon-qr-code 2.0.8 php-composer -bash 5.2.26-r0 apk -beberlei/assert v3.3.2 php-composer -brick/math 0.8.17 php-composer -brotli-libs 1.1.0-r2 apk -busybox 1.36.1-r29 apk -busybox-binsh 1.36.1-r29 apk -c-ares 1.33.1-r0 apk -ca-certificates 20240705-r0 apk -ca-certificates-bundle 20240705-r0 apk -catatonit 0.2.0-r0 apk -code-lts/u2f-php-server v1.2.1 php-composer -composer 2.8.3 binary -composer/ca-bundle 1.3.5 php-composer -coreutils 9.5-r1 apk -coreutils-env 9.5-r1 apk -coreutils-fmt 9.5-r1 apk -coreutils-sha512sum 9.5-r1 apk -curl 8.9.1-r2 apk -dasprid/enum 1.0.3 php-composer -fgrosse/phpasn1 v2.5.0 php-composer -fig/http-message-util 1.1.5 php-composer -findutils 4.9.0-r5 apk -freetype 2.13.2-r0 apk -git 2.45.2-r0 apk -git-init-template 2.45.2-r0 apk -google/recaptcha 1.2.4 php-composer -jq 1.7.1-r0 apk -league/uri 6.4.0 php-composer -league/uri-interfaces 2.3.0 php-composer -libacl 2.3.2-r0 apk -libattr 2.5.2-r0 apk -libavif 1.0.4-r0 apk -libbsd 0.12.2-r0 apk -libbz2 1.0.8-r6 apk -libcrypto3 3.3.2-r1 apk -libcurl 8.9.1-r2 apk -libdav1d 1.4.2-r0 apk -libedit 20240517.3.1-r0 apk -libexpat 2.6.4-r0 apk -libgcc 13.2.1_git20240309-r0 apk -libice 1.1.1-r6 apk -libidn2 2.3.7-r0 apk -libintl 0.22.5-r0 apk -libjpeg-turbo 3.0.3-r0 apk -libmd 1.1.0-r0 apk -libncursesw 6.4_p20240420-r1 apk -libpng 1.6.44-r0 apk -libproc2 4.0.4-r0 apk -libpsl 0.21.5-r1 apk -libsharpyuv 1.3.2-r0 apk -libsm 1.2.4-r4 apk -libssl3 3.3.2-r1 apk -libunistring 1.2-r0 apk -libuuid 2.40.1-r1 apk -libwebp 1.3.2-r0 apk -libx11 1.8.9-r1 apk -libxau 1.0.11-r4 apk -libxcb 1.16.1-r0 apk -libxdmcp 1.1.5-r1 apk -libxext 1.3.6-r2 apk -libxml2 2.12.7-r0 apk -libxpm 3.5.17-r0 apk -libxt 1.3.0-r5 apk -libzip 1.10.1-r0 apk -linux-pam 1.6.0-r0 apk -logrotate 3.21.0-r1 apk -musl 1.2.5-r0 apk -musl-utils 1.2.5-r0 apk -nano 8.0-r0 apk -ncurses-terminfo-base 6.4_p20240420-r1 apk -netcat-openbsd 1.226-r0 apk -nghttp2-libs 1.62.1-r0 apk -nginx 1.26.2-r0 apk -nikic/fast-route v1.3.0 php-composer -oniguruma 6.9.9-r0 apk -openssl 3.3.2-r1 apk -paragonie/constant_time_encoding v2.6.3 php-composer -paragonie/random_compat v9.99.100 php-composer -paragonie/sodium_compat v1.19.0 php-composer -pcre 8.45-r3 apk -pcre2 10.43-r0 apk -php83 8.3.14-r0 apk -php83-bz2 8.3.14-r0 apk -php83-common 8.3.14-r0 apk -php83-ctype 8.3.14-r0 apk -php83-curl 8.3.14-r0 apk -php83-dom 8.3.14-r0 apk -php83-fileinfo 8.3.14-r0 apk -php83-fpm 8.3.14-r0 apk -php83-gd 8.3.14-r0 apk -php83-iconv 8.3.14-r0 apk -php83-mbstring 8.3.14-r0 apk -php83-mysqli 8.3.14-r0 apk -php83-mysqlnd 8.3.14-r0 apk -php83-opcache 8.3.14-r0 apk -php83-openssl 8.3.14-r0 apk -php83-pecl-uploadprogress 2.0.2-r1 apk -php83-phar 8.3.14-r0 apk -php83-session 8.3.14-r0 apk -php83-simplexml 8.3.14-r0 apk -php83-tokenizer 8.3.14-r0 apk -php83-xml 8.3.14-r0 apk -php83-xmlwriter 8.3.14-r0 apk -php83-zip 8.3.14-r0 apk -phpmyadmin 5.2.1 npm -phpmyadmin/motranslator 5.3.0 php-composer -phpmyadmin/shapefile 3.0.1 php-composer -phpmyadmin/sql-parser 5.7.0 php-composer -phpmyadmin/twig-i18n-extension v4.0.1 php-composer -popt 1.19-r3 apk -pragmarx/google2fa v8.0.1 php-composer -pragmarx/google2fa-qrcode v2.1.1 php-composer -procps-ng 4.0.4-r0 apk -psr/cache 1.0.1 php-composer -psr/container 1.1.1 php-composer -psr/http-client 1.0.1 php-composer -psr/http-factory 1.0.1 php-composer -psr/http-message 1.0.1 php-composer -psr/log 1.1.4 php-composer -ralouphie/getallheaders 3.0.3 php-composer -ramsey/collection 1.1.4 php-composer -ramsey/uuid 4.2.3 php-composer -readline 8.2.10-r0 apk -scanelf 1.3.7-r2 apk -shadow 4.15.1-r0 apk -skalibs 2.14.1.1-r0 apk -slim/psr7 1.4 php-composer -spomky-labs/base64url v2.0.4 php-composer -spomky-labs/cbor-php v1.1.1 php-composer -ssl_client 1.36.1-r29 apk -symfony/cache v5.4.19 php-composer -symfony/cache-contracts v2.5.2 php-composer -symfony/config v5.4.19 php-composer -symfony/dependency-injection v5.4.20 php-composer -symfony/deprecation-contracts v2.5.2 php-composer -symfony/expression-language v5.4.19 php-composer -symfony/filesystem v5.4.19 php-composer -symfony/polyfill-ctype v1.27.0 php-composer -symfony/polyfill-mbstring v1.27.0 php-composer -symfony/polyfill-php73 v1.27.0 php-composer -symfony/polyfill-php80 v1.27.0 php-composer -symfony/polyfill-php81 v1.27.0 php-composer -symfony/process v5.4.19 php-composer -symfony/service-contracts v2.5.2 php-composer -symfony/var-exporter v5.4.19 php-composer -tecnickcom/tcpdf 6.6.2 php-composer -thecodingmachine/safe v1.3.3 php-composer -twig/twig v3.5.0 php-composer -tzdata 2024b-r0 apk -utmps-libs 0.1.2.2-r1 apk -web-auth/cose-lib v3.3.12 php-composer -web-auth/metadata-service v3.3.12 php-composer -web-auth/webauthn-lib v3.3.12 php-composer -webmozart/assert 1.11.0 php-composer -williamdes/mariadb-mysql-kbs v1.2.14 php-composer -xz-libs 5.6.2-r0 apk -zlib 1.3.1-r1 apk -zstd-libs 1.5.6-r0 apk +NAME VERSION TYPE +acl-libs 2.3.2-r1 apk +alpine-baselayout 3.7.2-r0 apk +alpine-baselayout-data 3.7.2-r0 apk +alpine-keys 2.6-r0 apk +alpine-release 3.23.4-r0 apk +aom-libs 3.13.1-r1 apk +apache2-utils 2.4.67-r0 apk +apk-tools 3.0.6-r0 apk +apr 1.7.6-r0 apk +apr-util 1.6.3-r2 apk +argon2-libs 20190702-r5 apk +bacon/bacon-qr-code 2.0.8 php-composer +bash 5.3.3-r1 apk +beberlei/assert v3.3.3 php-composer +brick/math 0.8.17 php-composer +brotli-libs 1.2.0-r0 apk +busybox 1.37.0-r30 apk +busybox-binsh 1.37.0-r30 apk +c-ares 1.34.6-r0 apk +ca-certificates 20260413-r0 apk +ca-certificates-bundle 20260413-r0 apk +catatonit 0.2.1-r0 apk +code-lts/u2f-php-server v1.2.2 php-composer +composer 2.9.8 binary +composer/ca-bundle 1.5.8 php-composer +coreutils 9.8-r1 apk +coreutils-env 9.8-r1 apk +coreutils-fmt 9.8-r1 apk +coreutils-sha512sum 9.8-r1 apk +curl 8.19.0-r0 apk +dasprid/enum 1.0.7 php-composer +fgrosse/phpasn1 v2.5.0 php-composer +fig/http-message-util 1.1.5 php-composer +findutils 4.10.0-r0 apk +freetype 2.14.1-r0 apk +git 2.52.0-r0 apk +git-init-template 2.52.0-r0 apk +google/recaptcha 1.2.4 php-composer +jq 1.8.1-r0 apk +league/uri 6.4.0 php-composer +league/uri-interfaces 2.3.0 php-composer +libapk 3.0.6-r0 apk +libattr 2.5.2-r2 apk +libavif 1.3.0-r0 apk +libbsd 0.12.2-r0 apk +libbz2 1.0.8-r6 apk +libcrypto3 3.5.6-r0 apk +libcurl 8.19.0-r0 apk +libdav1d 1.5.2-r0 apk +libedit 20251016.3.1-r0 apk +libexpat 2.7.5-r0 apk +libgcc 15.2.0-r2 apk +libice 1.1.2-r0 apk +libidn2 2.3.8-r0 apk +libintl 0.24.1-r1 apk +libjpeg-turbo 3.1.2-r0 apk +libmd 1.1.0-r0 apk +libncursesw 6.5_p20251123-r0 apk +libpng 1.6.58-r1 apk +libproc2 4.0.5-r0 apk +libpsl 0.21.5-r3 apk +libsharpyuv 1.6.0-r0 apk +libsm 1.2.6-r0 apk +libssl3 3.5.6-r0 apk +libstdc++ 15.2.0-r2 apk +libunistring 1.4.1-r0 apk +libuuid 2.41.4-r0 apk +libwebp 1.6.0-r0 apk +libx11 1.8.12-r1 apk +libxau 1.0.12-r0 apk +libxcb 1.17.0-r1 apk +libxdmcp 1.1.5-r1 apk +libxext 1.3.6-r2 apk +libxml2 2.13.9-r0 apk +libxpm 3.5.19-r0 apk +libxt 1.3.1-r0 apk +libyuv 0.0.1887.20251502-r1 apk +libzip 1.11.4-r1 apk +linux-pam 1.7.1-r2 apk +logrotate 3.22.0-r0 apk +musl 1.2.5-r23 apk +musl-utils 1.2.5-r23 apk +nano 8.7-r0 apk +ncurses-terminfo-base 6.5_p20251123-r0 apk +netcat-openbsd 1.234.1-r0 apk +nghttp2-libs 1.69.0-r0 apk +nginx 1.28.3-r1 apk +nikic/fast-route v1.3.0 php-composer +oniguruma 6.9.10-r0 apk +openssl 3.5.6-r0 apk +paragonie/constant_time_encoding v2.8.2 php-composer +paragonie/random_compat v9.99.100 php-composer +paragonie/sodium_compat v1.23.0 php-composer +pcre2 10.47-r0 apk +php85 8.5.6-r0 apk +php85-bz2 8.5.6-r0 apk +php85-common 8.5.6-r0 apk +php85-ctype 8.5.6-r0 apk +php85-curl 8.5.6-r0 apk +php85-dom 8.5.6-r0 apk +php85-fileinfo 8.5.6-r0 apk +php85-fpm 8.5.6-r0 apk +php85-gd 8.5.6-r0 apk +php85-iconv 8.5.6-r0 apk +php85-mbstring 8.5.6-r0 apk +php85-mysqli 8.5.6-r0 apk +php85-mysqlnd 8.5.6-r0 apk +php85-openssl 8.5.6-r0 apk +php85-pecl-uploadprogress 2.0.2-r1 apk +php85-phar 8.5.6-r0 apk +php85-session 8.5.6-r0 apk +php85-simplexml 8.5.6-r0 apk +php85-tokenizer 8.5.6-r0 apk +php85-xml 8.5.6-r0 apk +php85-xmlwriter 8.5.6-r0 apk +php85-zip 8.5.6-r0 apk +phpmyadmin 5.2.3 npm +phpmyadmin/motranslator 5.4.0 php-composer +phpmyadmin/shapefile 3.0.2 php-composer +phpmyadmin/sql-parser 5.11.1 php-composer +phpmyadmin/twig-i18n-extension 4.1.5 php-composer +popt 1.19-r4 apk +pragmarx/google2fa v9.0.0 php-composer +pragmarx/google2fa-qrcode v2.1.1 php-composer +procps-ng 4.0.5-r0 apk +psr/cache 1.0.1 php-composer +psr/container 1.1.1 php-composer +psr/http-client 1.0.3 php-composer +psr/http-factory 1.1.0 php-composer +psr/http-message 1.1 php-composer +psr/log 1.1.4 php-composer +ralouphie/getallheaders 3.0.3 php-composer +ramsey/collection 1.1.4 php-composer +ramsey/uuid 4.2.3 php-composer +readline 8.3.1-r0 apk +scanelf 1.3.8-r2 apk +shadow 4.18.0-r0 apk +skalibs-libs 2.14.4.0-r0 apk +slim/psr7 1.4.2 php-composer +spomky-labs/base64url v2.0.4 php-composer +spomky-labs/cbor-php v1.1.1 php-composer +ssl_client 1.37.0-r30 apk +symfony/cache v5.4.46 php-composer +symfony/cache-contracts v2.5.4 php-composer +symfony/config v5.4.46 php-composer +symfony/dependency-injection v5.4.48 php-composer +symfony/deprecation-contracts v2.5.4 php-composer +symfony/expression-language v5.4.45 php-composer +symfony/filesystem v5.4.45 php-composer +symfony/polyfill-ctype v1.33.0 php-composer +symfony/polyfill-iconv v1.33.0 php-composer +symfony/polyfill-mbstring v1.33.0 php-composer +symfony/polyfill-php73 v1.33.0 php-composer +symfony/polyfill-php80 v1.33.0 php-composer +symfony/polyfill-php81 v1.33.0 php-composer +symfony/polyfill-php84 v1.33.0 php-composer +symfony/process v5.4.47 php-composer +symfony/service-contracts v2.5.4 php-composer +symfony/var-exporter v5.4.45 php-composer +tecnickcom/tcpdf 6.10.0 php-composer +thecodingmachine/safe v1.3.3.1 php-composer +twig/twig v3.11.3 php-composer +tzdata 2026b-r0 apk +utmps-libs 0.1.3.1-r0 apk +web-auth/cose-lib v3.3.12 php-composer +web-auth/metadata-service v3.3.12 php-composer +web-auth/webauthn-lib v3.3.12 php-composer +webmozart/assert 1.11.0 php-composer +williamdes/mariadb-mysql-kbs v1.3.0 php-composer +xz-libs 5.8.3-r0 apk +zlib 1.3.2-r0 apk +zstd-libs 1.5.7-r2 apk diff --git a/readme-vars.yml b/readme-vars.yml index ed33831..051aa7f 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -6,34 +6,34 @@ project_url: "https://github.com/phpmyadmin/phpmyadmin/" project_logo: "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/phpmyadmin-logo.png" project_blurb: | [{{ project_name|capitalize }}]({{ project_url }}) is a free software tool written in PHP, intended to handle the administration of MySQL over the Web. phpMyAdmin supports a wide range of operations on MySQL and MariaDB. - project_lsio_github_repo_url: "https://github.com/linuxserver/docker-{{ project_name }}" - +project_categories: "Databases" # supported architectures available_architectures: - - { arch: "{{ arch_x86_64 }}", tag: "amd64-latest"} - - { arch: "{{ arch_arm64 }}", tag: "arm64v8-latest"} - + - {arch: "{{ arch_x86_64 }}", tag: "amd64-latest"} + - {arch: "{{ arch_arm64 }}", tag: "arm64v8-latest"} # container parameters common_param_env_vars_enabled: true param_container_name: "{{ project_name }}" - param_usage_include_env: false - opt_param_usage_include_env: true opt_param_env_vars: - - { env_var: "PMA_ARBITRARY", env_value: "1", desc: "Set to `1` to allow you to connect to any server. Setting to `0` will only allow you to connect to specified hosts (See Application Setup)"} - - { env_var: "PMA_ABSOLUTE_URI", env_value: "https://phpmyadmin.example.com", desc: "Set the URL you will use to access the web frontend"} - + - {env_var: "PMA_ARBITRARY", env_value: "1", desc: "Set to `1` to allow you to connect to any server. Setting to `0` will only allow you to connect to specified hosts (See Application Setup)"} + - {env_var: "PMA_ABSOLUTE_URI", env_value: "https://phpmyadmin.example.com", desc: "Set the URL you will use to access the web frontend"} param_usage_include_ports: true param_ports: - - { external_port: "80", internal_port: "80", port_desc: "Port for web frontend" } - + - {external_port: "80", internal_port: "80", port_desc: "Port for web frontend"} param_usage_include_vols: true param_volumes: - - { vol_path: "/config", vol_host_path: "/path/to/{{ project_name }}/config", desc: "Persistent config files" } - + - {vol_path: "/config", vol_host_path: "/path/to/{{ project_name }}/config", desc: "Persistent config files"} # application setup block +readonly_supported: true +readonly_message: | + * `/tmp` must be mounted to tmpfs + * Custom themes are not supported +nonroot_supported: true +nonroot_message: | + * Custom themes are not supported app_setup_block_enabled: true app_setup_block: | This image uses nginx, in contrast to the official images which offer fpm-only or Apache variants. @@ -41,18 +41,73 @@ app_setup_block: | We support all of the official [environment variables](https://docs.phpmyadmin.net/en/latest/setup.html#docker-environment-variables) for configuration as well as directly editing the config files. For more information check out the [phpmyadmin documentation](https://www.phpmyadmin.net/docs/). - +# init diagram +init_diagram: | + "phpmyadmin:latest": { + docker-mods + base { + fix-attr +\nlegacy cont-init + } + docker-mods -> base + legacy-services + custom services + init-services -> legacy-services + init-services -> custom services + custom services -> legacy-services + legacy-services -> ci-service-check + init-migrations -> init-adduser + init-nginx-end -> init-config + init-os-end -> init-config + init-config -> init-config-end + init-crontab-config -> init-config-end + init-phpmyadmin-config -> init-config-end + init-config -> init-crontab-config + init-mods-end -> init-custom-files + init-adduser -> init-device-perms + base -> init-envfile + init-os-end -> init-folders + init-php -> init-keygen + base -> init-migrations + init-config-end -> init-mods + init-mods-package-install -> init-mods-end + init-mods -> init-mods-package-install + init-samples -> init-nginx + init-version-checks -> init-nginx-end + init-adduser -> init-os-end + init-device-perms -> init-os-end + init-envfile -> init-os-end + init-keygen -> init-permissions + init-nginx -> init-php + init-nginx-end -> init-phpmyadmin-config + init-folders -> init-samples + init-custom-files -> init-services + init-permissions -> init-version-checks + init-services -> svc-cron + svc-cron -> legacy-services + init-services -> svc-nginx + svc-nginx -> legacy-services + init-services -> svc-php-fpm + svc-php-fpm -> legacy-services + } + Base Images: { + "baseimage-alpine-nginx:3.23" <- "baseimage-alpine:3.23" + } + "phpmyadmin:latest" <- Base Images # changelog changelogs: - - { date: "27.05.24:", desc: "Existing users should update their nginx confs to avoid http2 deprecation warnings." } - - { date: "24.05.24:", desc: "Rebase to Alpine 3.20." } - - { date: "28.12.23:", desc: "Rebase to Alpine 3.19 with php 8.3." } - - { date: "25.12.23:", desc: "Existing users should update: site-confs/default.conf - Cleanup default site conf." } - - { date: "06.09.23:", desc: "Add support for custom themes." } - - { date: "25.05.23:", desc: "Rebase to Alpine 3.18, deprecate armhf." } - - { date: "13.04.23:", desc: "Move ssl.conf include to default.conf." } - - { date: "20.01.23:", desc: "Rebase to alpine 3.17 with php8.1." } - - { date: "18.11.22:", desc: "Rebasing to Alpine 3.16, migrate to s6v3." } - - { date: "20.08.22:", desc: "Rebasing to Alpine 3.15 with php8. Restructure nginx configs ([see changes announcement](https://info.linuxserver.io/issues/2022-08-20-nginx-base))." } - - { date: "23.01.22:", desc: "Pin versions to 5.x.x." } - - { date: "14.06.21:", desc: "Initial Release." } + - {date: "28.12.25:", desc: "Rebase to Alpine 3.23."} + - {date: "23.08.25:", desc: "Add support for mTLS. Existing users will need to delete their config.inc.php and restart the container."} + - {date: "05.07.25:", desc: "Rebase to Alpine 3.22."} + - {date: "19.12.24:", desc: "Rebase to Alpine 3.21."} + - {date: "27.05.24:", desc: "Existing users should update their nginx confs to avoid http2 deprecation warnings."} + - {date: "24.05.24:", desc: "Rebase to Alpine 3.20."} + - {date: "28.12.23:", desc: "Rebase to Alpine 3.19 with php 8.3."} + - {date: "25.12.23:", desc: "Existing users should update: site-confs/default.conf - Cleanup default site conf."} + - {date: "06.09.23:", desc: "Add support for custom themes."} + - {date: "25.05.23:", desc: "Rebase to Alpine 3.18, deprecate armhf."} + - {date: "13.04.23:", desc: "Move ssl.conf include to default.conf."} + - {date: "20.01.23:", desc: "Rebase to alpine 3.17 with php8.1."} + - {date: "18.11.22:", desc: "Rebasing to Alpine 3.16, migrate to s6v3."} + - {date: "20.08.22:", desc: "Rebasing to Alpine 3.15 with php8. Restructure nginx configs ([see changes announcement](https://info.linuxserver.io/issues/2022-08-20-nginx-base))."} + - {date: "23.01.22:", desc: "Pin versions to 5.x.x."} + - {date: "14.06.21:", desc: "Initial Release."} diff --git a/root/defaults/config.inc.php b/root/defaults/config.inc.php index c94aef8..c0fa35c 100644 --- a/root/defaults/config.inc.php +++ b/root/defaults/config.inc.php @@ -2,10 +2,11 @@ // Sourced from https://github.com/phpmyadmin/docker/blob/master/config.inc.php -require('/config/phpmyadmin/config.secret.inc.php'); +require_once '/config/phpmyadmin/config.secret.inc.php'; +require_once '/config/phpmyadmin/helpers.php'; /* Ensure we got the environment */ -$vars = array( +$vars = [ 'PMA_ARBITRARY', 'PMA_HOST', 'PMA_HOSTS', @@ -26,20 +27,45 @@ 'PMA_QUERYHISTORYDB', 'PMA_QUERYHISTORYMAX', 'MAX_EXECUTION_TIME', - 'MEMORY_LIMIT' -); + 'MEMORY_LIMIT', + 'PMA_UPLOADDIR', + 'PMA_SAVEDIR', + 'PMA_SSL', + 'PMA_SSLS', + 'PMA_SSL_DIR', + 'PMA_SSL_VERIFY', + 'PMA_SSL_VERIFIES', + 'PMA_SSL_CA', + 'PMA_SSL_CAS', + 'PMA_SSL_CA_BASE64', + 'PMA_SSL_CAS_BASE64', + 'PMA_SSL_KEY', + 'PMA_SSL_KEYS', + 'PMA_SSL_KEY_BASE64', + 'PMA_SSL_KEYS_BASE64', + 'PMA_SSL_CERT', + 'PMA_SSL_CERTS', + 'PMA_SSL_CERT_BASE64', + 'PMA_SSL_CERTS_BASE64', +]; + foreach ($vars as $var) { $env = getenv($var); if (!isset($_ENV[$var]) && $env !== false) { $_ENV[$var] = $env; } } + +if (! defined('PMA_SSL_DIR')) { + define('PMA_SSL_DIR', $_ENV['PMA_SSL_DIR'] ?? '/config/phpmyadmin/ssl'); +} + if (isset($_ENV['PMA_QUERYHISTORYDB'])) { - $cfg['QueryHistoryDB'] = boolval($_ENV['PMA_QUERYHISTORYDB']); + $cfg['QueryHistoryDB'] = (bool) $_ENV['PMA_QUERYHISTORYDB']; } if (isset($_ENV['PMA_QUERYHISTORYMAX'])) { - $cfg['QueryHistoryMax'] = intval($_ENV['PMA_QUERYHISTORYMAX']); + $cfg['QueryHistoryMax'] = (int) $_ENV['PMA_QUERYHISTORYMAX']; } /* Arbitrary server connection */ @@ -52,29 +78,84 @@ $cfg['PmaAbsoluteUri'] = trim($_ENV['PMA_ABSOLUTE_URI']); } +if (isset($_ENV['PMA_SSL_CA_BASE64'])) { + $_ENV['PMA_SSL_CA'] = decodeBase64AndSaveFiles($_ENV['PMA_SSL_CA_BASE64'], 'phpmyadmin-ssl-CA', 'pem', PMA_SSL_DIR); +} + +/* Decode and save the SSL key from base64 */ +if (isset($_ENV['PMA_SSL_KEY_BASE64'])) { + $_ENV['PMA_SSL_KEY'] = decodeBase64AndSaveFiles($_ENV['PMA_SSL_KEY_BASE64'], 'phpmyadmin-ssl-CERT', 'cert', PMA_SSL_DIR); +} + +/* Decode and save the SSL certificate from base64 */ +if (isset($_ENV['PMA_SSL_CERT_BASE64'])) { + $_ENV['PMA_SSL_CERT'] = decodeBase64AndSaveFiles($_ENV['PMA_SSL_CERT_BASE64'], 'phpmyadmin-ssl-CERT', 'cert', PMA_SSL_DIR); +} + +/* Decode and save multiple SSL CA certificates from base64 */ +if (isset($_ENV['PMA_SSL_CAS_BASE64'])) { + $_ENV['PMA_SSL_CAS'] = decodeBase64AndSaveFiles($_ENV['PMA_SSL_CAS_BASE64'], 'phpmyadmin-ssl-CA', 'pem', PMA_SSL_DIR); +} + +/* Decode and save multiple SSL keys from base64 */ +if (isset($_ENV['PMA_SSL_KEYS_BASE64'])) { + $_ENV['PMA_SSL_KEYS'] = decodeBase64AndSaveFiles($_ENV['PMA_SSL_KEYS_BASE64'], 'phpmyadmin-ssl-CERT', 'cert', PMA_SSL_DIR); +} + +/* Decode and save multiple SSL certificates from base64 */ +if (isset($_ENV['PMA_SSL_CERTS_BASE64'])) { + $_ENV['PMA_SSL_CERTS'] = decodeBase64AndSaveFiles($_ENV['PMA_SSL_CERTS_BASE64'], 'phpmyadmin-ssl-KEY', 'key', PMA_SSL_DIR); +} + /* Figure out hosts */ /* Fallback to default linked */ -$hosts = array('db'); +$hosts = ['db']; /* Set by environment */ -if (!empty($_ENV['PMA_HOST'])) { - $hosts = array($_ENV['PMA_HOST']); - $verbose = array($_ENV['PMA_VERBOSE']); - $ports = array($_ENV['PMA_PORT']); -} elseif (!empty($_ENV['PMA_HOSTS'])) { +if (! empty($_ENV['PMA_HOST'])) { + $hosts = [$_ENV['PMA_HOST']]; + $verbose = [$_ENV['PMA_VERBOSE']]; + $ports = [$_ENV['PMA_PORT']]; + $ssls = [$_ENV['PMA_SSL']]; + $ssl_verifies = [$_ENV['PMA_SSL_VERIFY']]; + $ssl_cas = [$_ENV['PMA_SSL_CA']]; + $ssl_keys = [$_ENV['PMA_SSL_KEY']]; + $ssl_certs = [$_ENV['PMA_SSL_CERT']]; +} elseif (! empty($_ENV['PMA_HOSTS'])) { $hosts = array_map('trim', explode(',', $_ENV['PMA_HOSTS'])); $verbose = array_map('trim', explode(',', $_ENV['PMA_VERBOSES'])); $ports = array_map('trim', explode(',', $_ENV['PMA_PORTS'])); + $ssls = array_map('trim', explode(',', $_ENV['PMA_SSLS'])); + $ssl_verifies = array_map('trim', explode(',', $_ENV['PMA_SSL_VERIFIES'])); + $ssl_cas = array_map('trim', explode(',', $_ENV['PMA_SSL_CAS'])); + $ssl_keys = array_map('trim', explode(',', $_ENV['PMA_SSL_KEYS'])); + $ssl_certs = array_map('trim', explode(',', $_ENV['PMA_SSL_CERTS'])); } -if (!empty($_ENV['PMA_SOCKET'])) { - $sockets = array($_ENV['PMA_SOCKET']); -} elseif (!empty($_ENV['PMA_SOCKETS'])) { + +if (! empty($_ENV['PMA_SOCKET'])) { + $sockets = [$_ENV['PMA_SOCKET']]; +} elseif (! empty($_ENV['PMA_SOCKETS'])) { $sockets = explode(',', $_ENV['PMA_SOCKETS']); } /* Server settings */ for ($i = 1; isset($hosts[$i - 1]); $i++) { + if (isset($ssls[$i - 1]) && $ssls[$i - 1] === '1') { + $cfg['Servers'][$i]['ssl'] = $ssls[$i - 1]; + } + if (isset($ssl_verifies[$i - 1]) && $ssl_verifies[$i - 1] === '1') { + $cfg['Servers'][$i]['ssl_verify'] = $ssl_verifies[$i - 1]; + } + if (isset($ssl_cas[$i - 1])) { + $cfg['Servers'][$i]['ssl_ca'] = $ssl_cas[$i - 1]; + } + if (isset($ssl_keys[$i - 1])) { + $cfg['Servers'][$i]['ssl_key'] = $ssl_keys[$i - 1]; + } + if (isset($ssl_certs[$i - 1])) { + $cfg['Servers'][$i]['ssl_cert'] = $ssl_certs[$i - 1]; + } $cfg['Servers'][$i]['host'] = $hosts[$i - 1]; if (isset($verbose[$i - 1])) { $cfg['Servers'][$i]['verbose'] = $verbose[$i - 1]; @@ -126,9 +207,10 @@ $cfg['Servers'][$i]['compress'] = false; $cfg['Servers'][$i]['AllowNoPassword'] = true; } -for ($i = 1; isset($sockets[$i - 1]); $i++) { - $cfg['Servers'][$i]['socket'] = $sockets[$i - 1]; - $cfg['Servers'][$i]['host'] = 'localhost'; +// Avoid overwriting the last server id $i, use another variable name +for ($socketHostId = 1; isset($sockets[$socketHostId - 1]); $socketHostId++) { + $cfg['Servers'][$socketHostId]['socket'] = $sockets[$socketHostId - 1]; + $cfg['Servers'][$socketHostId]['host'] = 'localhost'; } /* * Revert back to last configured server to make @@ -137,8 +219,13 @@ $i--; /* Uploads setup */ -$cfg['UploadDir'] = ''; -$cfg['SaveDir'] = ''; +if (isset($_ENV['PMA_UPLOADDIR'])) { + $cfg['UploadDir'] = $_ENV['PMA_UPLOADDIR']; +} + +if (isset($_ENV['PMA_SAVEDIR'])) { + $cfg['SaveDir'] = $_ENV['PMA_SAVEDIR']; +} if (isset($_ENV['MAX_EXECUTION_TIME'])) { $cfg['ExecTimeLimit'] = $_ENV['MAX_EXECUTION_TIME']; @@ -150,5 +237,12 @@ /* Include User Defined Settings Hook */ if (file_exists('/config/phpmyadmin/config.user.inc.php')) { - include('/config/phpmyadmin/config.user.inc.php'); + include '/config/phpmyadmin/config.user.inc.php'; +} + +/* Support additional configurations */ +if (is_dir('/config/phpmyadmin/conf.d/')) { + foreach (glob('/config/phpmyadmin/conf.d/*.php') as $filename) { + include $filename; + } } diff --git a/root/defaults/helpers.php b/root/defaults/helpers.php new file mode 100644 index 0000000..807ac5a --- /dev/null +++ b/root/defaults/helpers.php @@ -0,0 +1,53 @@ +/config/phpmyadmin/config.secret.inc.php <