mirror of
https://github.com/dgtlmoon/changedetection.io.git
synced 2026-10-15 00:09:26 +00:00
* ci: pin third party actions to commit SHAs A tag or branch ref is a movable pointer, whoever controls the action repository can repoint it and the next run executes their code with this repo's secrets, here the Docker Hub tokens and the container publish path. The March 2025 tj-actions/changed-files incident (CVE-2025-30066) worked exactly that way. Each pin keeps the resolved tag in a comment and dependabot's weekly github-actions config bumps SHA pins like tags, so they self-maintain. The pypi publish action moves from the floating release/v1 branch to its current release. * ci: declare least-privilege workflow permissions Without a permissions block every job token inherits the repository default scope. Each workflow now declares what it uses. The test and build workflows get read-only tokens, CodeQL keeps its code scanning upload, the container publish job keeps packages write for the ghcr push, and the pypi publish job already carried its own id-token block for trusted publishing, untouched. * ci: pass release metadata to inline scripts through env The two debug steps interpolated the release tag name and the workflow_run branch directly into bash. Those strings are event metadata that can carry shell syntax, and the workflow runs on release events with the publish credentials in reach. Routed through env they arrive as plain data, output unchanged. * ci: stop persisting the checkout token in .git/config actions/checkout writes the job token into .git/config so later steps can push. None of these 21 jobs push with git: the containers are published with registry credentials, PyPI uses trusted publishing, and the test and CodeQL jobs only read the tree. A token left in .git/config is one more credential for a compromised step or a packed artifact to pick up, so each checkout now sets persist-credentials: false.
200 lines
7.8 KiB
YAML
200 lines
7.8 KiB
YAML
name: Build and push containers
|
|
|
|
on:
|
|
# Automatically triggered by a testing workflow passing, but this is only checked when it lands in the `master`/default branch
|
|
# workflow_run:
|
|
# workflows: ["ChangeDetection.io Test"]
|
|
# branches: [master]
|
|
# tags: ['0.*']
|
|
# types: [completed]
|
|
|
|
# Or a new tagged release
|
|
release:
|
|
types: [published, edited]
|
|
|
|
push:
|
|
branches:
|
|
- master
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
metadata:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Show metadata
|
|
# Event-derived strings go through env so they reach the shell as
|
|
# data, a release tag or branch name can carry shell syntax.
|
|
env:
|
|
RUN_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
|
|
RUN_INFO: ${{ toJSON(github.event.workflow_run) }}
|
|
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
|
run: |
|
|
echo SHA ${{ github.sha }}
|
|
echo github.ref: ${{ github.ref }}
|
|
echo github_ref: $GITHUB_REF
|
|
echo Event name: ${{ github.event_name }}
|
|
echo Ref ${{ github.ref }}
|
|
echo c: "$RUN_CONCLUSION"
|
|
echo r: "$RUN_INFO"
|
|
echo tname: "$RELEASE_TAG"
|
|
echo headbranch: -"$HEAD_BRANCH"-
|
|
set
|
|
|
|
build-push-containers:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
# The ghcr push authenticates with the workflow token.
|
|
packages: write
|
|
# If the testing workflow has a success, then we build to :latest
|
|
# Or if we are in a tagged release scenario.
|
|
if: ${{ github.event.workflow_run.conclusion == 'success' }} || ${{ github.event.release.tag_name }} != ''
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
with:
|
|
persist-credentials: false
|
|
- name: Set up Python 3.11
|
|
uses: actions/setup-python@v7
|
|
with:
|
|
python-version: 3.11
|
|
|
|
- name: Cache pip packages
|
|
uses: actions/cache@v6
|
|
with:
|
|
path: ~/.cache/pip
|
|
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-pip-
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
python -m pip install --upgrade pip
|
|
pip install flake8 pytest
|
|
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
|
|
|
|
- name: Create release metadata
|
|
run: |
|
|
# COPY'ed by Dockerfile into changedetectionio/ of the image, then read by the server in store.py
|
|
echo ${{ github.sha }} > changedetectionio/source.txt
|
|
echo ${{ github.ref }} > changedetectionio/tag.txt
|
|
|
|
- name: Set up QEMU
|
|
uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0
|
|
with:
|
|
image: tonistiigi/binfmt:latest
|
|
platforms: all
|
|
|
|
- name: Login to GitHub Container Registry
|
|
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Login to Docker Hub Container Registry
|
|
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
|
with:
|
|
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
|
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
|
|
|
- name: Set up Docker Buildx
|
|
id: buildx
|
|
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
|
|
with:
|
|
install: true
|
|
version: latest
|
|
driver-opts: image=moby/buildkit:master
|
|
|
|
# master branch -> :dev container tag
|
|
- name: Docker meta :dev
|
|
if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'release' }}
|
|
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
|
|
id: meta_dev
|
|
with:
|
|
images: |
|
|
${{ secrets.DOCKER_HUB_USERNAME }}/changedetection.io
|
|
ghcr.io/${{ github.repository }}
|
|
tags: |
|
|
type=raw,value=dev
|
|
labels: |
|
|
org.opencontainers.image.created=${{ github.event.release.published_at }}
|
|
org.opencontainers.image.description=Website, webpage change detection, monitoring and notifications.
|
|
org.opencontainers.image.documentation=https://changedetection.io
|
|
org.opencontainers.image.revision=${{ github.sha }}
|
|
org.opencontainers.image.source=https://github.com/dgtlmoon/changedetection.io
|
|
org.opencontainers.image.title=changedetection.io
|
|
org.opencontainers.image.url=https://changedetection.io
|
|
|
|
- name: Build and push :dev
|
|
id: docker_build
|
|
if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'release' }}
|
|
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
|
|
with:
|
|
context: ./
|
|
file: ./Dockerfile
|
|
push: true
|
|
tags: ${{ steps.meta_dev.outputs.tags }}
|
|
labels: ${{ steps.meta_dev.outputs.labels }}
|
|
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v8
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|
|
|
|
# Looks like this was disabled
|
|
# provenance: false
|
|
|
|
# A new tagged release is required, which builds :tag and :latest
|
|
- name: Debug release info
|
|
if: github.event_name == 'release' && startsWith(github.event.release.tag_name, '0.')
|
|
env:
|
|
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
run: |
|
|
echo "Release tag: $RELEASE_TAG"
|
|
echo "Github ref: ${{ github.ref }}"
|
|
echo "Github ref name: ${{ github.ref_name }}"
|
|
|
|
- name: Docker meta :tag
|
|
if: github.event_name == 'release' && startsWith(github.event.release.tag_name, '0.')
|
|
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
|
|
id: meta
|
|
with:
|
|
images: |
|
|
${{ secrets.DOCKER_HUB_USERNAME }}/changedetection.io
|
|
ghcr.io/dgtlmoon/changedetection.io
|
|
tags: |
|
|
type=semver,pattern={{version}},value=${{ github.event.release.tag_name }}
|
|
type=semver,pattern={{major}}.{{minor}},value=${{ github.event.release.tag_name }}
|
|
type=semver,pattern={{major}},value=${{ github.event.release.tag_name }}
|
|
type=raw,value=latest
|
|
labels: |
|
|
org.opencontainers.image.created=${{ github.event.release.published_at }}
|
|
org.opencontainers.image.description=Website, webpage change detection, monitoring and notifications.
|
|
org.opencontainers.image.documentation=https://changedetection.io
|
|
org.opencontainers.image.revision=${{ github.sha }}
|
|
org.opencontainers.image.source=https://github.com/dgtlmoon/changedetection.io
|
|
org.opencontainers.image.title=changedetection.io
|
|
org.opencontainers.image.url=https://changedetection.io
|
|
org.opencontainers.image.version=${{ github.event.release.tag_name }}
|
|
|
|
- name: Build and push :tag
|
|
id: docker_build_tag_release
|
|
if: github.event_name == 'release' && startsWith(github.event.release.tag_name, '0.')
|
|
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
|
|
with:
|
|
context: ./
|
|
file: ./Dockerfile
|
|
push: true
|
|
tags: ${{ steps.meta.outputs.tags }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v8
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|
|
# Looks like this was disabled
|
|
# provenance: false
|
|
|
|
- name: Image digest
|
|
run: echo step SHA ${{ steps.vars.outputs.sha_short }} tag ${{steps.vars.outputs.tag}} branch ${{steps.vars.outputs.branch}} digest ${{ steps.docker_build.outputs.digest }}
|
|
|