diff --git a/.github/workflows/build-image-on-push.yml b/.github/workflows/build-image-on-push.yml index a10026b..e6f7dad 100644 --- a/.github/workflows/build-image-on-push.yml +++ b/.github/workflows/build-image-on-push.yml @@ -103,14 +103,16 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: ${{ needs.init-vars.outputs.component }} - # Load build result to `docker images` - load: true + provenance: true + sbom: true + push: true tags: | seatable/seatable-python-${{ needs.init-vars.outputs.component }}:commit-${{ steps.get_commit.outputs.short_sha }} seatable/seatable-python-${{ needs.init-vars.outputs.component }}:${{ needs.init-vars.outputs.image_tag_prefix }}${{ needs.init-vars.outputs.version }} + ${{ needs.init-vars.outputs.image_tag_prefix == '' && format('seatable/seatable-python-{0}:latest', needs.init-vars.outputs.component) || '' }} labels: | org.opencontainers.image.title=seatable/seatable-python-${{ needs.init-vars.outputs.component }} org.opencontainers.image.version=${{ needs.init-vars.outputs.image_tag_prefix }}${{ needs.init-vars.outputs.version }} @@ -131,18 +133,4 @@ jobs: ignore-unfixed: true vuln-type: 'os,library' severity: 'CRITICAL,HIGH' - env: - # Use multiple repositories to limit the likelihood of encountering rate limits - TRIVY_DB_REPOSITORY: ghcr.io/aquasecurity/trivy-db,public.ecr.aws/aquasecurity/trivy-db - - name: Push image - id: push_image - run: | - docker push seatable/seatable-python-${{ needs.init-vars.outputs.component }}:commit-${{ steps.get_commit.outputs.short_sha }} - docker push seatable/seatable-python-${{ needs.init-vars.outputs.component }}:${{ needs.init-vars.outputs.image_tag_prefix }}${{ needs.init-vars.outputs.version }} - - - name: Push "latest" tag - run: | - docker tag seatable/seatable-python-${{ needs.init-vars.outputs.component }}:commit-${{ steps.get_commit.outputs.short_sha }} seatable/seatable-python-${{ needs.init-vars.outputs.component }}:latest - docker push seatable/seatable-python-${{ needs.init-vars.outputs.component }}:latest - if: ${{ needs.init-vars.outputs.image_tag_prefix == '' }} diff --git a/runner/Dockerfile b/runner/Dockerfile index fe62057..8898e09 100644 --- a/runner/Dockerfile +++ b/runner/Dockerfile @@ -1,4 +1,6 @@ -FROM python:3.11-alpine AS compile-image +ARG BASE_IMAGE="python:3.12.10-alpine@sha256:9c51ecce261773a684c8345b2d4673700055c513b4d54bc0719337d3e4ee552e" + +FROM ${BASE_IMAGE} AS compile-image RUN apk add --no-cache \ cargo \ @@ -35,9 +37,8 @@ RUN pip install --upgrade setuptools && \ pip install --upgrade --user setuptools && \ pip install -r requirements.txt --no-cache-dir --user - ## Runtime image -FROM python:3.11-alpine AS runtime-image +FROM ${BASE_IMAGE} AS runtime-image RUN apk add --no-cache bash \ python3-dev diff --git a/runner/requirements.txt b/runner/requirements.txt index e4c6f9f..d721b8f 100644 --- a/runner/requirements.txt +++ b/runner/requirements.txt @@ -1,5 +1,5 @@ requests -seatable-api==2.8.2 +seatable-api==3.0.0 dateutils pyOpenSSL pandas diff --git a/scheduler/Dockerfile b/scheduler/Dockerfile index 4ccb293..dcae161 100644 --- a/scheduler/Dockerfile +++ b/scheduler/Dockerfile @@ -1,24 +1,27 @@ -### Compile Image -FROM python:3.11-slim-bookworm AS compile-image +ARG BASE_IMAGE="python:3.12-slim-bookworm@sha256:31a416db24bd8ade7dac5fd5999ba6c234d7fa79d4add8781e95f41b187f4c9a" +FROM ${BASE_IMAGE} AS compile-image # Installation of the pip packages WORKDIR /opt/scheduler COPY ["app/requirements.txt", "/opt/scheduler/requirements.txt"] RUN pip3 install -r /opt/scheduler/requirements.txt --user - ### Runtime Image -FROM python:3.11-slim-bookworm AS runtime-image +FROM ${BASE_IMAGE} AS runtime-image # Clean up && Installation of the apt packages RUN apt-get update --fix-missing && \ - apt-get autoremove -y && \ - apt-get clean && \ + apt-get upgrade -y && \ export DEBIAN_FRONTEND=noninteractive && \ - apt-get install -y tzdata default-mysql-client procps cron logrotate nginx - -# Comment this line for production -# RUN apt-get install -y curl net-tools nano + apt-get install -y \ + tzdata \ + default-mysql-client \ + procps \ + logrotate \ + cron \ + nginx && \ + apt-get autoremove -y && \ + apt-get clean # copy compiled pip packages in runtime-image COPY --from=compile-image /root/.local /root/.local diff --git a/starter/Dockerfile b/starter/Dockerfile index 05abfa7..679209e 100644 --- a/starter/Dockerfile +++ b/starter/Dockerfile @@ -1,8 +1,15 @@ -### Compile Image -FROM python:3.11-slim-bookworm AS compile-image +ARG BASE_IMAGE="python:3.12-slim-bookworm@sha256:31a416db24bd8ade7dac5fd5999ba6c234d7fa79d4add8781e95f41b187f4c9a" +FROM ${BASE_IMAGE} AS compile-image + +ARG DOCKER_VERSION="28.1.1" RUN apt-get update --fix-missing && \ - apt-get install -y gcc + apt-get upgrade -y && \ + apt-get install -y gcc curl bzip2 unzip + +# Get docker binary +ADD https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz / +RUN tar --extract --file docker-${DOCKER_VERSION}.tgz --directory /tmp/ --strip-components 1 WORKDIR /opt/seatable-python-starter COPY ["./requirements.txt", "/opt/seatable-python-starter/"] @@ -10,16 +17,24 @@ COPY ["./requirements.txt", "/opt/seatable-python-starter/"] # Upgrade setuptools to fix vulnerabilities RUN pip install --upgrade setuptools && \ pip install --upgrade --user setuptools && \ - pip install -r /opt/seatable-python-starter/requirements.txt --user --break-system-packages + pip install -r /opt/seatable-python-starter/requirements.txt --user ### Runtime image -FROM python:3.11-slim-bookworm AS runtime-image +FROM ${BASE_IMAGE} AS runtime-image RUN apt-get update --fix-missing && \ - apt-get autoremove -y && \ - apt-get clean && \ + apt-get upgrade -y && \ export DEBIAN_FRONTEND=noninteractive && \ - apt-get install -y tzdata procps cron logrotate docker.io gcc curl + apt-get install -y \ + tzdata \ + procps \ + cron \ + logrotate && \ + apt-get autoremove -y && \ + apt-get clean + +COPY --from=compile-image /tmp/docker /usr/local/bin/docker +RUN chmod +x /usr/local/bin/docker WORKDIR /opt/seatable-python-starter COPY ["./", "./"] diff --git a/starter/entrypoint.sh b/starter/entrypoint.sh index 75f6354..657b286 100755 --- a/starter/entrypoint.sh +++ b/starter/entrypoint.sh @@ -69,11 +69,7 @@ fi echo "** uWSGI is starting now" uwsgi --ini /opt/seatable-python-starter/uwsgi.ini 2>&1 & sleep 1 -if curl -IsSf http://127.0.0.1:8080/ping/ >/dev/null 2>&1; then - echo "** SeaTable Python Starter ready" -else - echo "** Error: SeaTable Python Starter is not ready. uWSGI is not answering." -fi +echo "** SeaTable Python Starter ready" # check cron service cron start & diff --git a/starter/runner.py b/starter/runner.py index 8d66613..b56a8d4 100644 --- a/starter/runner.py +++ b/starter/runner.py @@ -49,6 +49,14 @@ TMPFS_MOUNT_SIZE_IN_BYTES = os.environ.get( "PYTHON_RUNNER_TMPFS_MOUNT_SIZE_IN_BYTES", "104857600" ) +DROPPED_CAPABILITIES = [ + cap + for cap in os.environ.get("PYTHON_RUNNER_DROPPED_CAPABILITIES", "").split(",") + if cap.strip() +] +NO_NEW_PRIVILEGES = ( + os.environ.get("PYTHON_RUNNER_NO_NEW_PRIVILEGES", "false").lower() == "true" +) OTHER_OPTIONS = os.environ.get("PYTHON_RUNNER_OTHER_OPTIONS", "[]") try: OTHER_OPTIONS = ast.literal_eval(OTHER_OPTIONS) @@ -308,6 +316,13 @@ def run_python(data): command.extend( ["--mount", f"type=tmpfs,dst=/tmp,tmpfs-size={TMPFS_MOUNT_SIZE_IN_BYTES}"] ) + if DROPPED_CAPABILITIES: + command.extend( + f"--cap-drop={capability}" for capability in DROPPED_CAPABILITIES + ) + if NO_NEW_PRIVILEGES: + # Prevent container from gaining additional privileges + command.extend(["--security-opt", "no-new-privileges"]) # other options, these options are experimental, may cause failure to start script if OTHER_OPTIONS and isinstance(OTHER_OPTIONS, list): for option in OTHER_OPTIONS: