diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e732b7c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +.gitignore +.github \ No newline at end of file diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 710c1ea..187fadf 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -19,8 +19,8 @@ env: REGISTRY: ghcr.io # github.repository as / IMAGE_NAME: ${{ github.repository }} - # Set SSP_VERSION from tag if present, else fetch latest - SSP_VERSION: ${{ github.ref_type == 'tag' && github.ref_name || '' }} + # Set VERSION from tag if present, else fetch latest + VERSION: ${{ github.ref_type == 'tag' && github.ref_name || '' }} jobs: @@ -29,19 +29,21 @@ jobs: permissions: contents: read outputs: - SSP_VERSION: ${{ steps.determine_ssp_version.outputs.SSP_VERSION }} + VERSION: ${{ steps.determine_version.outputs.VERSION }} steps: - - name: Determine SimpleSAMLphp version - id: determine_ssp_version + - name: Determine Moodle version + id: determine_version run: | - if [ -z "${SSP_VERSION}" ]; then - LATEST=$(curl -s https://api.github.com/repos/simplesamlphp/simplesamlphp/releases/latest | jq -r .tag_name | sed 's/^v//') - echo "SSP_VERSION=$LATEST" >> $GITHUB_OUTPUT + if [ -z "${VERSION}" ]; then + # Fetch all tags, filter for stable releases, sort, and pick the highest + TAGS=$(curl -s "https://api.github.com/repos/moodle/moodle/tags?per_page=1000" | jq -r '.[].name' | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+$' | sed 's/^v//') + LATEST=$(echo "$TAGS" | sort -V | tail -n1) + echo "VERSION=$LATEST" >> $GITHUB_OUTPUT else - echo "SSP_VERSION=${SSP_VERSION#v}" >> $GITHUB_OUTPUT + echo "VERSION=${VERSION#v}" >> $GITHUB_OUTPUT fi env: - SSP_VERSION: ${{ env.SSP_VERSION }} + VERSION: ${{ env.VERSION }} docker: needs: prepare @@ -59,7 +61,7 @@ jobs: # with sigstore/fulcio when running outside of PRs. id-token: write env: - SSP_VERSION: ${{ needs.prepare.outputs.SSP_VERSION }} + VERSION: ${{ needs.prepare.outputs.VERSION }} steps: - name: Set platform pair @@ -85,44 +87,41 @@ jobs: - name: Setup Docker buildx uses: docker/setup-buildx-action@v3 - - name: Ensure COMPOSER_HOME exists - run: mkdir -p "$HOME/.composer" - - - name: Install composer/semver - run: composer global require composer/semver - env: - COMPOSER_HOME: $HOME/.composer - - - name: Download SimpleSAMLphp release - run: | - curl -L https://github.com/simplesamlphp/simplesamlphp/releases/download/v${{ env.SSP_VERSION }}/simplesamlphp-${{ env.SSP_VERSION }}-full.tar.gz --output simplesamlphp-version-full.tar.gz - working-directory: ${{ github.workspace }} - - name: Extract composer.json + - name: Parse Moodle major and minor version + id: parse_version run: | - tar -xzf simplesamlphp-version-full.tar.gz simplesamlphp-${{ env.SSP_VERSION }}/composer.json --strip-components=1 - working-directory: ${{ github.workspace }} - - name: Determine latest supported PHP version + VERSION="${{ env.VERSION }}" + MAJOR=$(echo "$VERSION" | cut -d. -f1) + MINOR=$(echo "$VERSION" | cut -d. -f2) + MINOR_PADDED=$(printf "%02d" "$MINOR") + echo "MAJOR=$MAJOR" >> $GITHUB_OUTPUT + echo "MINOR=$MINOR_PADDED" >> $GITHUB_OUTPUT + - name: Checkout Moodle repository + uses: actions/checkout@v3 + with: + repository: moodle/moodle + ref: MOODLE_${{ steps.parse_version.outputs.MAJOR }}${{ steps.parse_version.outputs.MINOR }}_STABLE + path: moodle-src + - name: Determine required PHP version id: php_version run: | - export PATH="$PATH:$HOME/.composer/vendor/bin" - PHP_CONSTRAINT=$(jq -r '.require.php' composer.json) - # Get all PHP tags from Docker Hub (paginated, up to 1000 tags) - TAGS=$(curl -s 'https://registry.hub.docker.com/v2/repositories/library/php/tags?page_size=1000' | jq -r '.results[].name') - # Filter for fpm-alpine tags and extract version numbers - VERSIONS=$(echo "$TAGS" | grep -E '^[0-9]+\.[0-9]+(\.[0-9]+)?-fpm-alpine$' | sed 's/-fpm-alpine//' | sort -V) - # Use composer/semver to find the highest matching version - MATCH=$(echo "$VERSIONS" | xargs -I{} semver "$PHP_CONSTRAINT" {} | tail -n1) - if [ -z "$MATCH" ]; then - # fallback to highest version if no match - PHP_VERSION=$(echo "$VERSIONS" | tail -n1) - else - PHP_VERSION=$MATCH + # Parse minimum PHP version from moodle-src/lib/phpminimumversionlib.php + MIN_PHP=$(grep "minimumversion" moodle-src/lib/phpminimumversionlib.php | head -1 | sed -E \ + -e "s/.*'(.*)'.*/\1/") + echo "Minimum required PHP version: $MIN_PHP" + # Extract the major.minor part + PHP_SERIES=$(echo "$MIN_PHP" | awk -F. '{print $1 "." $2}') + # Fetch all PHP versions from Docker Hub + PHP_TAGS=$(curl -s 'https://registry.hub.docker.com/v2/repositories/library/php/tags?page_size=1000' | jq -r '.results[].name' | grep -E "^$PHP_SERIES\\.[0-9]+-fpm-alpine$" | sed 's/-fpm-alpine//') + # Select the highest bugfix version in the required series + SELECTED_PHP=$(echo "$PHP_TAGS" | sort -V | tail -n1) + if [ -z "$SELECTED_PHP" ]; then + # Fallback: use the minimum required + SELECTED_PHP="$MIN_PHP" fi - echo "PHP_VERSION=$PHP_VERSION" >> $GITHUB_ENV - echo "php_version=$PHP_VERSION" >> $GITHUB_OUTPUT - working-directory: ${{ github.workspace }} - env: - COMPOSER_HOME: $HOME/.composer + echo "Selected PHP version: $SELECTED_PHP" + echo "PHP_VERSION=$SELECTED_PHP" >> $GITHUB_OUTPUT + echo "PHP_VERSION=$SELECTED_PHP" >> $GITHUB_ENV # Login against a Docker registry except on PR # https://github.com/docker/login-action @@ -146,6 +145,9 @@ jobs: uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx + + - name: Remove .git folder + run: rm -rf moodle-src/.git # Build and push Docker image with Buildx (don't push on PR) # https://github.com/docker/build-push-action @@ -157,7 +159,7 @@ jobs: platforms: ${{ matrix.platform }} target: php tags: | - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php:v${{ env.SSP_VERSION }}-${{ steps.set_platform_pair.outputs.platform_pair }} + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php:v${{ env.VERSION }}-${{ steps.set_platform_pair.outputs.platform_pair }} labels: ${{ steps.meta-php.outputs.labels }} outputs: type=image,push=${{ github.event_name != 'pull_request' }} file: ./Dockerfile @@ -171,7 +173,7 @@ jobs: platforms: ${{ matrix.platform }} target: nginx tags: | - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx:v${{ env.SSP_VERSION }}-${{ steps.set_platform_pair.outputs.platform_pair }} + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx:v${{ env.VERSION }}-${{ steps.set_platform_pair.outputs.platform_pair }} labels: ${{ steps.meta-nginx.outputs.labels }} outputs: type=image,push=${{ github.event_name != 'pull_request' }} file: ./Dockerfile @@ -204,7 +206,7 @@ jobs: contents: read packages: write env: - SSP_VERSION: ${{ needs.prepare.outputs.SSP_VERSION }} + VERSION: ${{ needs.prepare.outputs.VERSION }} steps: # Login against a Docker registry except on PR # https://github.com/docker/login-action @@ -216,54 +218,56 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Determine if this is the latest release + - name: Determine if this is the latest version id: is_latest run: | - LATEST=$(curl -s https://api.github.com/repos/simplesamlphp/simplesamlphp/releases/latest | jq -r .tag_name | sed 's/^v//') - if [ "$LATEST" = "${SSP_VERSION}" ]; then + VERSION="${{ env.VERSION }}" + TAGS=$(curl -s "https://api.github.com/repos/moodle/moodle/tags?per_page=1000" | jq -r '.[].name' | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+$' | sed 's/^v//') + LATEST=$(echo "$TAGS" | sort -V | tail -n1) + if [ "$LATEST" = "$VERSION" ]; then echo "is_latest=true" >> $GITHUB_OUTPUT else echo "is_latest=false" >> $GITHUB_OUTPUT fi env: - SSP_VERSION: ${{ env.SSP_VERSION }} + VERSION: ${{ env.VERSION }} - name: Create manifest list and push (php) run: | docker buildx imagetools create \ - -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php:v${{ env.SSP_VERSION }} \ - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php:v${{ env.SSP_VERSION }}-linux-amd64 \ - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php:v${{ env.SSP_VERSION }}-linux-arm64 + -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php:v${{ env.VERSION }} \ + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php:v${{ env.VERSION }}-linux-amd64 \ + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php:v${{ env.VERSION }}-linux-arm64 env: - SSP_VERSION: ${{ env.SSP_VERSION }} + VERSION: ${{ env.VERSION }} - name: Tag PHP image as latest if: steps.is_latest.outputs.is_latest == 'true' run: | docker buildx imagetools create \ -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php:latest \ - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php:v${{ env.SSP_VERSION }}-linux-amd64 \ - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php:v${{ env.SSP_VERSION }}-linux-arm64 + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php:v${{ env.VERSION }}-linux-amd64 \ + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php:v${{ env.VERSION }}-linux-arm64 env: - SSP_VERSION: ${{ env.SSP_VERSION }} + VERSION: ${{ env.VERSION }} - name: Inspect PHP image run: | - docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php:v${{ env.SSP_VERSION }} + docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php:v${{ env.VERSION }} - name: Create manifest list and push (nginx) run: | docker buildx imagetools create \ - -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx:v${{ env.SSP_VERSION }} \ - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx:v${{ env.SSP_VERSION }}-linux-amd64 \ - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx:v${{ env.SSP_VERSION }}-linux-arm64 + -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx:v${{ env.VERSION }} \ + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx:v${{ env.VERSION }}-linux-amd64 \ + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx:v${{ env.VERSION }}-linux-arm64 env: - SSP_VERSION: ${{ env.SSP_VERSION }} + VERSION: ${{ env.VERSION }} - name: Tag nginx image as latest if: steps.is_latest.outputs.is_latest == 'true' run: | docker buildx imagetools create \ -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx:latest \ - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx:v${{ env.SSP_VERSION }}-linux-amd64 \ - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx:v${{ env.SSP_VERSION }}-linux-arm64 + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx:v${{ env.VERSION }}-linux-amd64 \ + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx:v${{ env.VERSION }}-linux-arm64 env: - SSP_VERSION: ${{ env.SSP_VERSION }} + VERSION: ${{ env.VERSION }} - name: Inspect nginx image run: | - docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx:v${{ env.SSP_VERSION }} \ No newline at end of file + docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx:v${{ env.VERSION }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..600d2d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 98dd6ce..12bea60 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,24 +1,12 @@ ARG PHP_VERSION -FROM php:${PHP_VERSION}-cli-alpine AS builder -COPY --from=composer/composer:latest-bin /composer /usr/bin/composer -RUN apk add --no-cache jq icu-dev libldap openldap-dev samba-dev gmp-dev -RUN docker-php-ext-install intl ldap gmp -ADD simplesamlphp-version-full.tar.gz /var/www -WORKDIR /var/www -RUN rm -rf html && mv simplesamlphp-* html -WORKDIR /var/www/html -RUN jq '.repositories += {"repo-name": {"type":"vcs","url":"https://github.com/smeetsee/simplesamlphp-module-openidprovider"}}' composer.json > composer.tmp.json && \ - mv composer.tmp.json composer.json -RUN composer require 'cirrusidentity/simplesamlphp-module-authoauth2:^4.1' 'simplesamlphp/simplesamlphp-module-openidprovider:dev-master' - FROM php:${PHP_VERSION}-fpm-alpine AS php RUN apk add --no-cache icu-dev libldap openldap-dev samba-dev gmp-dev RUN docker-php-ext-install intl ldap gmp -COPY --from=builder /var/www/html /var/www/html +COPY moodle-src /var/www/html EXPOSE 9000 FROM nginx:alpine AS nginx COPY nginx.conf.template /nginx.conf.template -COPY --from=builder /var/www/html /var/www/html +COPY moodle-src /var/www/html CMD ["/bin/sh" , "-c" , "envsubst '${SERVER_NAME}' < /nginx.conf.template > /etc/nginx/nginx.conf && exec nginx -g 'daemon off;'"] EXPOSE 8080 \ No newline at end of file diff --git a/nginx.conf.template b/nginx.conf.template index b701a04..c912c4c 100644 --- a/nginx.conf.template +++ b/nginx.conf.template @@ -26,36 +26,35 @@ http { keepalive_timeout 65; #gzip on; + server { - listen 8080 default; - server_name ${SERVER_NAME}; - - index index.php; - - # See https://hstspreload.org/ before uncommenting the line below. - # add_header Strict-Transport-Security "max-age=15768000; preload;"; - add_header X-Content-Type-Options nosniff; - add_header X-XSS-Protection "1; mode=block"; - add_header X-Robots-Tag none; - add_header X-Frame-Options DENY; - - location = / { - return 301 https://$server_name/module.php/openidProvider/user.php; - } - - location ^~ { - alias /var/www/html/public; - - location ~ \.php(/|$) { - fastcgi_pass phpfpm:9000; - fastcgi_index index.php; - fastcgi_param SCRIPT_FILENAME $request_filename; - fastcgi_split_path_info ^(.+?\.php)(/.*)$; - fastcgi_param PATH_INFO $fastcgi_path_info; - fastcgi_param HTTPS on; - fastcgi_param HTTP_X_FORWARDED_PROTO https; - include fastcgi_params; + listen 8080 default; + server_name ${SERVER_NAME}; + + root /var/www/html; + index index.php; + + # allow larger file uploads and longer script runtimes + client_max_body_size 100m; + client_body_timeout 120s; + + sendfile off; + + # See https://hstspreload.org/ before uncommenting the line below. + # add_header Strict-Transport-Security "max-age=15768000; preload;"; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Robots-Tag none; + add_header X-Frame-Options DENY; + location ~ [^/]\.php(/|$) { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_index index.php; + fastcgi_pass phpfpm:9000; + include fastcgi_params; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param HTTPS on; + fastcgi_param HTTP_X_FORWARDED_PROTO https; } - } } }