diff --git a/.github/actions/publish-docker/action.yml b/.github/actions/publish-docker/action.yml new file mode 100644 index 0000000..77de85b --- /dev/null +++ b/.github/actions/publish-docker/action.yml @@ -0,0 +1,151 @@ +# Copyright 2025 CS Group +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: publish-docker +description: Publish Docker image + +inputs: + dockerfile: + description: Dockerfile path + required: true + build_context_path: + description: "'docker build' context path" + required: true + image_suffix: + description: Docker image name suffix + required: true + version_name: + description: Version name e.g. 1.2.3a4.dev1a2b3c4d + required: true + github_token: + description: secrets.GITHUB_TOKEN + required: true + docker_tag: + description: Tag the docker images + required: false + image2build: + description: Name of the docker image to build + required: false + secrets: + description: List of secrets to expose to the build (e.g., key=string, GIT_AUTH_TOKEN=mytoken) + required: false + +outputs: + docker_image: + description: Docker image name:tag + value: ${{ steps.docker_image.outputs.docker_image }} + +runs: + using: "composite" + steps: + + # Replace invalid characters in the Docker version name, e.g. 1.2.3a4+dev1a2b3c4d becomes 1.2.3a4.dev1a2b3c4d + # Then we can use ${{ inputs.docker_version_name }} + - run: echo "docker_version_name=$(echo ${{ inputs.version_name }} | tr + .)" >> $GITHUB_ENV + shell: bash + + # This is required to push a docker image from a private repository + - name: Log in to registry + run: echo "${{ inputs.github_token }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + shell: bash + + # Full Docker image name:tag as ghcr.io/csgroup-oss/eo-catalog: in lowercase + - id: docker_image + run: | + docker_image=${{ env.DOCKER_REGISTRY }}/${{ github.repository }}${{ inputs.image_suffix }}:${{ env.docker_version_name }} + docker_image=${docker_image,,} # lowercase + echo docker_image=${docker_image} >> $GITHUB_ENV + echo docker_image=${docker_image} >> $GITHUB_OUTPUT + shell: bash + + # Extract metadata from Git reference and GitHub events + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.DOCKER_REGISTRY }}/${{ github.repository }} # ghcr.io/csgroup-oss/eo-catalog + + # Checkout code from the current branch and build Docker image. + - name: Build Docker image + uses: docker/build-push-action@v5 + with: + context: ${{ inputs.build_context_path }} + file: ${{ inputs.dockerfile }} + load: true + tags: ${{ env.docker_image }} + labels: ${{ steps.meta.outputs.labels }} + push: false # push after the security scans below + secrets: ${{ inputs.secrets }} + + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@master + env: + TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db:2 + with: + image-ref: ${{ env.docker_image }} + format: sarif + output: trivy-results-docker.sarif + exit-code: 0 + #severity: HIGH,CRITICAL + timeout: '30m' + + - name: Upload Trivy scan results to GitHub Security tab + uses: github/codeql-action/upload-sarif@v3 + # TO BE REMOVED once the repository is public + continue-on-error: true + with: + sarif_file: trivy-results-docker.sarif + category: ${{ env.docker_image }} + + - name: Display link to Trivy results + # TO BE REMOVED once the repository is public + continue-on-error: true + run: | + + set -x + + # If this is not a pull request, the query is "is:open+branch:branch_name" + if [[ "${{ github.ref_name }}" != *merge* ]]; then + query="is:open+branch:${{ github.ref_name }}" + + # Else the ref_name is e.g. '13/merge'. Change it into 'pr:13' + else + query=$(sed "s|\(.*\)/merge|pr:\1|g" <<< "${{ github.ref_name }}") + fi + + echo "Trivy scan results:" \ + "https://github.com/${{ github.repository }}/security/code-scanning?query=${query}" \ + >> $GITHUB_STEP_SUMMARY + shell: bash + + # This is required to push a docker image from a private repository + - name: Log in to registry + run: echo "${{ inputs.github_token }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + shell: bash + + - name: Push Docker image + run: docker push ${{ env.docker_image }} + shell: bash + + # Add a docker image tag and push it into the registry. + - name: Push Docker tag e.g. 'latest' + if: always() + run: | # use sed to replace the last : by :docker_tag + set -x + if [[ ${{ inputs.docker_tag }}test != test ]]; then # if variable is defined and not empty + docker_image_tag=$(sed "s|\(:[^:]*\)|:${{ inputs.docker_tag }}|g" <<< ${{ env.docker_image }}) + docker tag ${{ env.docker_image }} ${docker_image_tag} + docker push ${docker_image_tag} + fi + shell: bash diff --git a/.github/workflows/publish-image.yml b/.github/workflows/publish-image.yml new file mode 100644 index 0000000..dc4a46b --- /dev/null +++ b/.github/workflows/publish-image.yml @@ -0,0 +1,119 @@ +# Copyright 2025 CS Group +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Publish Docker image + +# Run workflow only for ... +on: + pull_request: # pull requests + types: [opened, synchronize, reopened] + push: + branches: + - develop # pushes on the 'develop' branch + tags: + - '**' # new git tags (including hierarchical tags like v1.0/beta) + workflow_dispatch: # manual trigger + inputs: + docker_tag: + description: Tag the docker images as e.g. 'latest' + required: false +env: + DOCKER_REGISTRY: ghcr.io + +jobs: + + # Calculate variables for this workflow + set-env: + if: github.actor != 'dependabot[bot]' # ignore pull requests by github bot + runs-on: ubuntu-latest + name: "Set environment" + outputs: + docker_tag: ${{ steps.set-env.outputs.docker_tag }} + branch_name: ${{ steps.set-env.outputs.branch_name }} + steps: + - id: set-env + name: "Set environment" + run: | + set -x + + # Get the current branch name (or source branch for a pull request) + if [[ ${{ github.event_name }} == pull_request ]]; then + branch_name=${{ github.event.pull_request.head.ref }} + else + branch_name=${{ github.ref_name }} + fi + + # Determine the docker tag to set to new docker images. + # For a pull request, use the branch name + if [[ ${{ github.event_name }} == pull_request ]]; then + docker_tag="$branch_name" + + # For a push on develop or a tag, use the docker tag :latest + elif [[ ${{ github.event_name }} == push ]]; then + docker_tag=latest + + # For a manual trigger, use the user-defined tag, or latest if empty + elif [[ ${{ github.event_name }} == workflow_dispatch ]]; then + docker_tag=${{ github.event.inputs.docker_tag }} + if [[ -z "$docker_tag" ]]; then + docker_tag=latest + fi + + else + >&2 echo "Unknown trigger" + exit 1 + fi + + # Replace special characters by - + docker_tag=$(sed "s/[^a-zA-Z0-9]/-/g" <<< "$docker_tag") + + # Save values + echo "branch_name=$branch_name" >> $GITHUB_OUTPUT + echo "docker_tag=$docker_tag" >> $GITHUB_OUTPUT + shell: bash + + publish-docker-matrix: + strategy: + matrix: + image: [cnpgis] + include: + - path: .github/workflows + image: cnpgis + if: github.actor != 'dependabot[bot]' + runs-on: ubuntu-latest + name: "Docker image for ${{ matrix.image }}" + needs: [set-env] + permissions: write-all + outputs: + docker_image: ${{ steps.publish-docker.outputs.docker_image}} + steps: + - uses: actions/checkout@v4 + + # - name: Copy common requirements + # id: copy_common_req + # shell: bash + # run: | + # mkdir -p ./.github/${{ matrix.path }}/resources/ + # cp ./.github/common/resources/* ./.github/${{ matrix.path }}/resources/ + + - id: publish-docker-cnpgis + name: Publish docker cnpgis + if: matrix.image == 'cnpgis' + uses: ./.github/actions/publish-docker + with: + dockerfile: ./dockerfiles/Dockerfile.${{ matrix.image }} + build_context_path: ./${{ matrix.path }}/ + image_suffix: -${{ matrix.image }} + version_name: ${{ needs.set-env.outputs.docker_tag }} + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/dockerfiles/Dockerfile.cnpgis b/dockerfiles/Dockerfile.cnpgis new file mode 100644 index 0000000..cb900bf --- /dev/null +++ b/dockerfiles/Dockerfile.cnpgis @@ -0,0 +1,31 @@ +# Copyright 2025 CS Group +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +ARG PG_MAJOR=17 + +# Base postgis image that pgstac can be installed onto +FROM ghcr.io/cloudnative-pg/postgis:${PG_MAJOR} +ARG PG_MAJOR + +USER root + +RUN \ + apt-get update \ + && apt-get upgrade -y \ + && apt-get install -y --no-install-recommends \ + postgresql-$PG_MAJOR-partman \ + && apt-get remove -y apt-transport-https \ + && apt-get clean && apt-get -y autoremove \ + && rm -rf /var/lib/apt/lists/* + +USER postgres \ No newline at end of file