diff --git a/.github/workflows/check-pr.yaml b/.github/workflows/check-pr.yaml index 503bd0e..7474af2 100644 --- a/.github/workflows/check-pr.yaml +++ b/.github/workflows/check-pr.yaml @@ -13,7 +13,6 @@ jobs: permissions: contents: read - pull-requests: write steps: - name: Checkout repository @@ -34,27 +33,3 @@ jobs: working-directory: backend run: | task test-container - - - name: Build backend image - working-directory: backend - run: | - task image-build - - - name: Scan backend image - id: scan - uses: ovsds/run-with-output-action@v1 - continue-on-error: true - with: - run: task backend:image-scan - - - name: Report vulnerabilities - uses: ovsds/create-or-update-unique-comment-action@v1 - with: - issue-number: ${{ github.event.number }} - body: | - ## Vulnerabilities found - ``` - ${{ steps.scan.outputs.stdout }} - ``` - unique-body-includes: "## Vulnerabilities found" - delete: ${{ steps.scan.outputs.exit_code == 0 }} diff --git a/.github/workflows/release-pr-cleanup.yaml b/.github/workflows/release-pr-cleanup.yaml new file mode 100644 index 0000000..b569800 --- /dev/null +++ b/.github/workflows/release-pr-cleanup.yaml @@ -0,0 +1,23 @@ +name: 🧹 Release PR Cleanup + +on: + schedule: + - cron: 0 0 * * 0 # Every Sunday at 00:00 UTC + workflow_dispatch: + +jobs: + release-pr-cleanup: + runs-on: ubuntu-22.04 + + permissions: + contents: read + packages: write + + steps: + - uses: ovsds/package-lifecycle-action@v1 + with: + package-name: ${{ github.event.repository.name }}-beta + expire-period-days: 7 + untagged: true + retained-tagged-top: 1 + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release-pr.yaml b/.github/workflows/release-pr.yaml new file mode 100644 index 0000000..07640ff --- /dev/null +++ b/.github/workflows/release-pr.yaml @@ -0,0 +1,76 @@ +name: Release PR + +on: + pull_request: + types: + - opened + - reopened + - synchronize + +jobs: + release-pr: + runs-on: ubuntu-latest + + permissions: + contents: read + pull-requests: write + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup_environment + with: + with-python: "false" + with-poetry: "false" + + - name: Get Image Data + id: get-image-data + run: | + echo "registry=ghcr.io/${{ github.repository_owner }}" >> $GITHUB_OUTPUT + echo "name=${{ github.event.repository.name }}-beta" >> $GITHUB_OUTPUT + echo "tag=${{ github.event.number }}-${{ github.event.pull_request.head.sha }}" >> $GITHUB_OUTPUT + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Configure Docker Builder + run: task configure-builder + + - name: Build backend images + working-directory: backend + env: + IMAGE_REGISTRY: ${{ steps.get-image-data.outputs.registry }} + IMAGE_NAME: ${{ steps.get-image-data.outputs.name }} + IMAGE_TAG: ${{ steps.get-image-data.outputs.tag }} + run: | + task ci-image-push + + - name: Scan backend image + id: scan + uses: ovsds/run-with-output-action@v1 + continue-on-error: true + with: + run: | + task backend:ci-image-scan \ + IMAGE_REGISTRY="${{ steps.get-image-data.outputs.registry }}" \ + IMAGE_NAME="${{ steps.get-image-data.outputs.name }}" \ + IMAGE_TAG="${{ steps.get-image-data.outputs.tag }}" + + - name: Report vulnerabilities + uses: ovsds/create-or-update-unique-comment-action@v1 + with: + issue-number: ${{ github.event.number }} + body: | + ## Vulnerabilities found + ``` + ${{ steps.scan.outputs.stdout }} + ``` + unique-body-includes: "## Vulnerabilities found" + delete: ${{ steps.scan.outputs.exit_code == 0 }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 45912d3..e493d1d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -30,11 +30,14 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Configure Docker Builder + run: task configure-builder + - name: Build backend images working-directory: backend env: IMAGE_TAG: ${{ github.event.release.tag_name }} + IMAGE_NAME: ${{ github.event.repository.name }} IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }} run: | - task ci-image-build task ci-image-push diff --git a/Taskfile.yaml b/Taskfile.yaml index 6bf0d48..b12b7a9 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -134,3 +134,11 @@ tasks: services='backend' vars: TEMPLATE_PATH: '{{.TEMPLATE_PATH | default "https://github.com/ovsds/template-repository"}}' + + configure-builder: + desc: Configure buildx for multi-arch builds + cmds: + - echo 'Configuring buildx...' + - docker buildx create + --driver docker-container + --use diff --git a/backend/Dockerfile b/backend/Dockerfile index 7f15868..9b4417a 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,24 +1,21 @@ -ARG BASE_BUILDER_IMAGE=python:3.12.7-bookworm -ARG BASE_RUNTIME_IMAGE=python:3.12.7-slim-bookworm - -FROM ${BASE_BUILDER_IMAGE} AS builder +FROM base_builder AS builder RUN python -m pip install 'poetry>=1.7.0,<1.8.0' RUN mkdir --parents /opt/app -COPY pyproject.toml /opt/app/pyproject.toml -COPY poetry.lock /opt/app/poetry.lock -COPY poetry.toml /opt/app/poetry.toml +COPY --from=sources pyproject.toml /opt/app/pyproject.toml +COPY --from=sources poetry.lock /opt/app/poetry.lock +COPY --from=sources poetry.toml /opt/app/poetry.toml WORKDIR /opt/app RUN poetry install -FROM ${BASE_RUNTIME_IMAGE} AS runtime +FROM base_runtime AS runtime RUN mkdir --parents /opt/app COPY --from=builder /opt/app/.venv /opt/app/.venv -COPY bin /opt/app/bin -COPY lib /opt/app/lib +COPY --from=sources bin /opt/app/bin +COPY --from=sources lib /opt/app/lib WORKDIR /opt/app CMD [".venv/bin/python", "-m", "bin.main"] @@ -27,18 +24,18 @@ FROM builder AS builder_dev RUN poetry install --with dev -FROM ${BASE_RUNTIME_IMAGE} AS runtime_dev +FROM base_runtime AS runtime_dev RUN mkdir --parents /opt/app COPY --from=builder_dev /opt/app/.venv /opt/app/.venv -COPY bin /opt/app/bin -COPY lib /opt/app/lib -COPY pyproject.toml /opt/app/pyproject.toml +COPY --from=sources bin /opt/app/bin +COPY --from=sources lib /opt/app/lib +COPY --from=sources pyproject.toml /opt/app/pyproject.toml WORKDIR /opt/app FROM runtime_dev AS tests -COPY tests /opt/app/tests +COPY --from=sources tests /opt/app/tests CMD [".venv/bin/python", "-m", "pytest", "tests"] diff --git a/backend/Taskfile.yaml b/backend/Taskfile.yaml index 858e624..97df77a 100644 --- a/backend/Taskfile.yaml +++ b/backend/Taskfile.yaml @@ -114,18 +114,9 @@ tasks: - echo 'Running pyright fixes...' - task: _pyright - image-build: - desc: Build image target for local usage + bake: cmds: - - echo 'Building image {{.TARGET}} target...' - - docker build - --tag {{.IMAGE_NAME}}:{{.TARGET}} - {{ if .TAG }}--tag {{.TAG}}{{ end }} - --target {{.TARGET}} - --load - . - vars: - TARGET: '{{.TARGET | default "runtime"}}' + - docker buildx bake {{.COMMAND}} image-scan: desc: Scan image for vulnerabilities @@ -146,8 +137,8 @@ tasks: test-container: desc: Run tests in container cmds: - - task: image-build - vars: { TARGET: tests } + - task: bake + vars: { COMMAND: tests_docker } - echo 'Running tests...' - docker run @@ -212,11 +203,13 @@ tasks: dev-server-start-container: desc: Start development application in container cmds: - - task: image-build - vars: { TARGET: runtime } + - task: bake + vars: { COMMAND: runtime_docker } - echo 'Running container...' - docker run + -e GITHUB_WATCHER_SETTINGS_YAML=example/settings.yaml + -v $(pwd)/example:/opt/app/example {{.IMAGE_NAME}}:runtime update-from-template: @@ -234,18 +227,6 @@ tasks: vars: TEMPLATE_PATH: '{{.TEMPLATE_PATH | default "https://github.com/ovsds/template-service-python"}}' - ci-image-build: - desc: Build image target for CI usage - requires: - vars: - - IMAGE_TAG - - IMAGE_REGISTRY - cmds: - - task: image-build - vars: - TARGET: runtime - TAG: "{{.IMAGE_REGISTRY}}/{{.IMAGE_NAME}}:{{.IMAGE_TAG}}" - ci-image-push: desc: Push image to registry for CI usage requires: @@ -254,7 +235,8 @@ tasks: - IMAGE_REGISTRY cmds: - echo 'Uploading backend image...' - - docker push {{.IMAGE_REGISTRY}}/{{.IMAGE_NAME}}:{{.IMAGE_TAG}} + - task: bake + vars: { COMMAND: runtime } ci-image-scan: desc: Scan image for vulnerabilities diff --git a/backend/docker-bake.hcl b/backend/docker-bake.hcl new file mode 100644 index 0000000..6fcea32 --- /dev/null +++ b/backend/docker-bake.hcl @@ -0,0 +1,45 @@ +variable "IMAGE_REGISTRY" {} +variable "IMAGE_NAME" { default = "github-watcher" } +variable "IMAGE_TAG" {} +variable "PLATFORMS" { + default = [ + "linux/amd64", + "linux/arm64", + ] +} + +target "base" { + dockerfile = "Dockerfile" + contexts = { + "base_builder" = "docker-image://docker.io/library/python:3.12.7-bookworm" + "base_runtime" = "docker-image://docker.io/library/python:3.12.7-slim-bookworm" + "sources" = "." + } +} + +target "runtime" { + inherits = ["base"] + target = "runtime" + tags = ["${IMAGE_REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}"] + output = ["type=image,push=true"] + platforms = PLATFORMS + attest = [ + "type=provenance,mode=max", + "type=sbom", + ] +} + +target "runtime_docker" { + inherits = ["base"] + target = "runtime" + output = ["type=docker"] + tags = ["${IMAGE_NAME}:runtime"] +} + +target "tests_docker" { + inherits = ["base"] + output = ["type=docker"] + tags = ["${IMAGE_NAME}:tests"] + target = "tests" +} +