louislam/uptime-kuma

18 workflows · maturity 100% · 8 patterns · GitHub ↗

Security 34.72/100

Practices

✓ Matrix✓ Permissions✓ Security scan✓ AI review✓ Cache✓ Concurrency○ Reusable workflows

Detected patterns

Security dimensions

permissions
22.2
security scan
12.5
supply chain
0
secret handling
0
harden runner
0

Tools: github/codeql-action/analyze, github/codeql-action/autobuild, github/codeql-action/init

Workflows (18)

auto-test matrix perms .github/workflows/auto-test.yml
Triggers
push, pull_request
Runs on
${{ matrix.os }}, ubuntu-latest, ubuntu-latest, ubuntu-22.04-arm
Jobs
auto-test, armv7-simple-test, check-linters, e2e-test
Matrix
include, include.node, include.os, node, os→ 20, 22, 24, 25, macos-latest, ubuntu-22.04, ubuntu-22.04-arm, windows-latest
Actions
docker/setup-qemu-action, docker/setup-buildx-action
Commands
  • git config --global core.autocrlf false
  • npm clean-install --no-fund
  • npm rebuild @louislam/sqlite3
  • npm run build
  • npm run test-backend
  • docker run --rm --platform linux/arm/v7 \ -v $PWD:/workspace \ -w /workspace \ arm32v7/node:${{ matrix.node }} \ npm clean-install --no-fund --production
  • git config --global core.autocrlf false
  • npm clean-install --no-fund
View raw YAML
name: Auto Test

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-server
  cancel-in-progress: true

on:
  push:
    branches: [master, 1.23.X, 3.0.0]
  pull_request:
permissions: {}

jobs:
  auto-test:
    runs-on: ${{ matrix.os }}
    permissions:
      contents: read

    strategy:
      fail-fast: false
      matrix:
        os: [macos-latest, ubuntu-22.04, windows-latest, ubuntu-22.04-arm]
        # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
        node: [20, 24]
        # Also test non-LTS, but only on Ubuntu.
        include:
          - os: ubuntu-22.04
            node: 25

    steps:
      - run: git config --global core.autocrlf false # Mainly for Windows
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with: { persist-credentials: false }

      - name: Cache/Restore node_modules
        uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
        id: node-modules-cache
        with:
          path: node_modules
          key: node-modules-${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }}

      - name: Use Node.js ${{ matrix.node }}
        uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
        with:
          node-version: ${{ matrix.node }}
      - run: npm clean-install --no-fund

      - name: Rebuild native modules for ARM64
        if: matrix.os == 'ubuntu-22.04-arm'
        run: npm rebuild @louislam/sqlite3

      - run: npm run build
      - run: npm run test-backend
        env:
          HEADLESS_TEST: 1
          JUST_FOR_TEST: ${{ secrets.JUST_FOR_TEST }}

  # As a lot of dev dependencies are not supported on ARMv7, we have to test it separately and just test if `npm ci --production` works
  armv7-simple-test:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        node: [20, 22]
        # See supported Node.js release schedule at https://nodejs.org/en/about/releases/

    steps:
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with: { persist-credentials: false }

      - name: Set up QEMU
        uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
        with:
          platforms: linux/arm/v7

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1

      - name: Test on ARMv7 using Docker with QEMU
        run: |
          docker run --rm --platform linux/arm/v7 \
            -v $PWD:/workspace \
            -w /workspace \
            arm32v7/node:${{ matrix.node }} \
            npm clean-install --no-fund --production

  check-linters:
    runs-on: ubuntu-latest
    permissions:
      contents: read

    steps:
      - run: git config --global core.autocrlf false # Mainly for Windows
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with: { persist-credentials: false }

      - name: Cache/Restore node_modules
        uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
        id: node-modules-cache
        with:
          path: node_modules
          key: node-modules-${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }}

      - name: Use Node.js 20
        uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
        with:
          node-version: 20
      - run: npm clean-install --no-fund
      - run: npm run lint:prod

  e2e-test:
    runs-on: ubuntu-22.04-arm
    permissions:
      contents: read
    env:
      PLAYWRIGHT_VERSION: ~1.39.0
    steps:
      - run: git config --global core.autocrlf false # Mainly for Windows
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with: { persist-credentials: false }

      - name: Cache/Restore node_modules
        uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
        id: node-modules-cache
        with:
          path: node_modules
          key: node-modules-${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }}

      - name: Setup Node.js
        uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
        with:
          node-version: 22
      - run: npm clean-install --no-fund

      - name: Rebuild native modules for ARM64
        run: npm rebuild @louislam/sqlite3

      - name: Install Playwright ${{ env.PLAYWRIGHT_VERSION }}
        run: npx playwright@${{ env.PLAYWRIGHT_VERSION }} install

      - run: npm run build
      - run: npm run test-e2e
autofix perms .github/workflows/autofix.yml
Triggers
push, pull_request
Runs on
ubuntu-latest
Jobs
autofix
Actions
autofix-ci/action
Commands
  • npm ci
  • npm run lint-fix:js
  • npm run lint-fix:style
  • npm run fmt
  • npm run tsc
View raw YAML
name: autofix.ci

on:
  push:
    branches: ["master", "1.23.X"]
  pull_request:
permissions: {}

jobs:
  autofix:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with: { persist-credentials: false }

      - name: Cache/Restore node_modules
        uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
        id: node-modules-cache
        with:
          path: node_modules
          key: node-modules-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}

      - name: Setup Node.js
        uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
        with:
          node-version: 20

      - name: Install dependencies
        run: npm ci

      - name: Auto-fix JavaScript/Vue linting issues
        run: npm run lint-fix:js
        continue-on-error: true

      - name: Auto-fix CSS/SCSS linting issues
        run: npm run lint-fix:style
        continue-on-error: true

      - name: Auto-format code with Prettier
        run: npm run fmt
        continue-on-error: true

      - name: Compile TypeScript
        run: npm run tsc
        continue-on-error: true

      - uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27
build-docker-base perms .github/workflows/build-docker-base.yml
Triggers
workflow_dispatch
Runs on
ubuntu-latest
Jobs
build-docker-base
Actions
docker/setup-qemu-action, docker/setup-buildx-action, docker/login-action, docker/login-action
Commands
  • npm run build-docker-base-slim
  • npm run build-docker-base
View raw YAML
name: Build Docker Base Images

on:
  workflow_dispatch: # Allow manual trigger

permissions: {}

jobs:
  build-docker-base:
    runs-on: ubuntu-latest
    timeout-minutes: 120
    permissions:
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with: { persist-credentials: false }

      - name: Set up QEMU
        uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1

      - name: Login to Docker Hub
        uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Login to GitHub Container Registry
        uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
        with:
          registry: ghcr.io
          username: ${{ secrets.GHCR_USERNAME }}
          password: ${{ secrets.GHCR_TOKEN }}

      - name: Use Node.js 20
        uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
        with:
          node-version: 20

      - name: Build and push base2-slim image
        run: npm run build-docker-base-slim

      - name: Build and push base2 image
        run: npm run build-docker-base
build-docker-push perms .github/workflows/build-docker-push.yml
Triggers
schedule, workflow_dispatch
Runs on
ubuntu-latest
Jobs
build-docker-push
Actions
docker/setup-qemu-action, docker/setup-buildx-action, docker/login-action
Commands
  • npm install -g cross-env
  • npm run build-docker
View raw YAML
name: Build Docker Push Image

on:
  schedule:
    # Runs at 2:00 AM UTC on the 1st of every month
    - cron: "0 2 1 * *"
  workflow_dispatch: # Allow manual trigger

permissions: {}

jobs:
  build-docker-push:
    # Only run on the original repository, not on forks
    if: github.repository == 'louislam/uptime-kuma'
    runs-on: ubuntu-latest
    timeout-minutes: 120
    permissions:
      contents: read

    steps:
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with: { persist-credentials: false }

      - name: Set up QEMU
        uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1

      - name: Login to Docker Hub
        uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Use Node.js 20
        uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
        with:
          node-version: 20

      - name: Set up Go
        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0

      - name: Install cross-env
        run: npm install -g cross-env

      - name: Build and push Docker image
        working-directory: extra/uptime-kuma-push
        run: npm run build-docker
close-incorrect-issue matrix perms .github/workflows/close-incorrect-issue.yml
Triggers
issues
Runs on
${{ matrix.os }}
Jobs
close-incorrect-issue
Matrix
node-version, os→ 20, ubuntu-latest
Commands
  • npm ci
  • node extra/close-incorrect-issue.js ${{ secrets.GITHUB_TOKEN }} ${{ github.event.issue.number }} "$ISSUE_USER_LOGIN"
View raw YAML
name: Close Incorrect Issue

on:
  issues:
    types: [opened]
permissions: {}

jobs:
  close-incorrect-issue:
    runs-on: ${{ matrix.os }}
    permissions:
      issues: write

    strategy:
      matrix:
        os: [ubuntu-latest]
        node-version: [20]

    steps:
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with: { persist-credentials: false }

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - name: Close incorrect issue
        run: node extra/close-incorrect-issue.js ${{ secrets.GITHUB_TOKEN }} ${{ github.event.issue.number }} "$ISSUE_USER_LOGIN"
        env:
          ISSUE_USER_LOGIN: ${{ github.event.issue.user.login }}
codeql-analysis matrix security .github/workflows/codeql-analysis.yml
Triggers
push, pull_request, schedule
Runs on
ubuntu-latest, ubuntu-latest
Jobs
analyze, zizmor
Matrix
language→ go, javascript-typescript
Actions
github/codeql-action/init, github/codeql-action/autobuild, github/codeql-action/analyze, zizmorcore/zizmor-action
View raw YAML
name: "CodeQL"

on:
  push:
    branches: ["master", "1.23.X"]
  pull_request:
    branches: ["master", "1.23.X"]
  schedule:
    - cron: "16 22 * * 0"

jobs:
  analyze:
    # Only run scheduled analysis on the original repository, not on forks
    if: github.event_name != 'schedule' || github.repository == 'louislam/uptime-kuma'
    name: Analyze
    runs-on: ubuntu-latest
    timeout-minutes: 360

    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language: ["go", "javascript-typescript"]

    steps:
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with: { persist-credentials: false }

      # Initializes the CodeQL tools for scanning.
      - name: Initialize CodeQL
        uses: github/codeql-action/init@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
        with:
          languages: ${{ matrix.language }}

      - name: Autobuild
        uses: github/codeql-action/autobuild@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
        with:
          category: "/language:${{matrix.language}}"
  zizmor:
    # Only run scheduled analysis on the original repository, not on forks
    if: github.event_name != 'schedule' || github.repository == 'louislam/uptime-kuma'
    runs-on: ubuntu-latest
    permissions:
      security-events: write
      contents: read
      actions: read
    steps:
      - name: Checkout repository
        uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with: { persist-credentials: false }
      - name: Run zizmor
        uses: zizmorcore/zizmor-action@e639db99335bc9038abc0e066dfcd72e23d26fb4 # v0.3.0
conflict-labeler .github/workflows/conflict-labeler.yml
Triggers
push, pull_request_target
Runs on
ubuntu-latest
Jobs
label
Actions
eps1lon/actions-label-merge-conflict
View raw YAML
name: Merge Conflict Labeler

# pull_request_target is safe here because:
# 1. Only uses a pinned trusted action (by SHA)
# 2. Has minimal permissions (contents: read, pull-requests: write)
# 3. Doesn't checkout or execute any untrusted code from PRs
# 4. Only adds/removes labels based on merge conflict status
on: # zizmor: ignore[dangerous-triggers]
  push:
    branches:
      - master
  pull_request_target:
    branches:
      - master
    types: [synchronize]

jobs:
  label:
    name: Labeling
    runs-on: ubuntu-latest
    if: ${{ github.repository == 'louislam/uptime-kuma' }}
    permissions:
      contents: read
      pull-requests: write
    steps:
      - name: Apply label
        uses: eps1lon/actions-label-merge-conflict@1df065ebe6e3310545d4f4c4e862e43bdca146f0 # v3.0.3
        with:
          dirtyLabel: "needs:resolve-merge-conflict"
          repoToken: "${{ secrets.GITHUB_TOKEN }}"
mark-as-draft-on-requesting-changes perms .github/workflows/mark-as-draft-on-requesting-changes.yml
Triggers
pull_request_target
Runs on
ubuntu-latest, ubuntu-latest
Jobs
mark-draft, ready-for-review
Commands
  • gh issue edit "${{ github.event.pull_request.number }}" \ --repo "${{ github.repository }}" \ --add-label "pr:please address review comments"
  • gh pr ready "${{ github.event.pull_request.number }}" \ --repo "${{ github.repository }}" \ --undo || true # || true to ignore the case where the pr is already a draft
  • gh issue edit "${{ github.event.pull_request.number }}" \ --repo "${{ github.repository }}" \ --remove-label "pr:please address review comments" || true gh issue edit "${{ github.event.pull_request.number }}" \ --repo "${{ github.repository }}" \ --add-label "pr:needs review"
View raw YAML
name: Mark PR as draft when changes are requested

# pull_request_target is safe here because:
# 1. Does not use any external actions; only uses the GitHub CLI via run commands
# 2. Has minimal permissions
# 3. Doesn't checkout or execute any untrusted code from PRs
# 4. Only adds/removes labels or changes the draft status
on: # zizmor: ignore[dangerous-triggers]
  pull_request_target:
    types:
      - review_submitted
      - labeled
      - ready_for_review

permissions: {}

jobs:
  mark-draft:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    if: |
      (
        github.event.action == 'review_submitted' &&
        github.event.review.state == 'changes_requested'
      ) || (
        github.event.action == 'labeled' &&
        github.event.label.name == 'pr:please address review comments'
      )
    steps:
      - name: Add label on requested changes
        if: github.event.review.state == 'changes_requested'
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          gh issue edit "${{ github.event.pull_request.number }}" \
            --repo "${{ github.repository }}" \
            --add-label "pr:please address review comments"

      - name: Mark PR as draft
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          gh pr ready "${{ github.event.pull_request.number }}" \
            --repo "${{ github.repository }}" \
            --undo || true
          # || true to ignore the case where the pr is already a draft

  ready-for-review:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    if: github.event.action == 'ready_for_review'
    steps:
      - name: Update labels for review
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          gh issue edit "${{ github.event.pull_request.number }}" \
            --repo "${{ github.repository }}" \
            --remove-label "pr:please address review comments" || true

          gh issue edit "${{ github.event.pull_request.number }}" \
            --repo "${{ github.repository }}" \
            --add-label "pr:needs review"
new-contributor-pr perms .github/workflows/new-contributor-pr.yml
Triggers
pull_request_target
Runs on
ubuntu-latest
Jobs
build
Actions
plbstl/first-contribution
View raw YAML
name: New contributor message

on:
  # Safety
  # This workflow uses pull_request_target so it can run with write permissions on first-time contributor PRs.
  # It is safe because it does not check out or execute any code from the pull request and
  # only uses the pinned, trusted plbstl/first-contribution action
  pull_request_target: # zizmor: ignore[dangerous-triggers]
    types: [opened, closed]
    branches:
      - master

permissions:
  pull-requests: write

jobs:
  build:
    if: github.repository == 'louislam/uptime-kuma'
    name: Hello new contributor
    runs-on: ubuntu-latest
    timeout-minutes: 60
    steps:
      - uses: plbstl/first-contribution@4b2b042fffa26792504a18e49aa9543a87bec077 # v4.1.0
        with:
          pr-reactions: rocket
          pr-opened-msg: >
            Hello and thanks for lending a paw to Uptime Kuma! 🐻👋

            As this is your first contribution, please be sure to check out our [Pull Request guidelines](https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md#can-i-create-a-pull-request-for-uptime-kuma).

            In particular:
            - Mark your PR as Draft while you’re still making changes
            - Mark it as Ready for review once it’s fully ready

            If you have any design or process questions, feel free to ask them right here in this pull request - unclear documentation is a bug too.
          pr-merged-msg: >
            @{fc-author} congrats on your first contribution to Uptime Kuma! 🐻

            We hope you enjoy contributing to our project and look forward to seeing more of your work in the future!
            If you want to see your contribution in action, please see our [nightly builds here](https://hub.docker.com/layers/louislam/uptime-kuma/nightly2).
npm-update perms .github/workflows/npm-update.yml
Triggers
workflow_dispatch, schedule
Runs on
ubuntu-latest
Jobs
npm-update
Commands
  • rm -f package-lock.json npm install --package-lock-only
  • if git diff --quiet package-lock.json; then echo "has_changes=false" >> $GITHUB_OUTPUT else echo "has_changes=true" >> $GITHUB_OUTPUT fi
  • git config --global user.name "github-actions[bot]" git config --global user.email "github-actions[bot]@users.noreply.github.com"
  • git add package-lock.json git commit -m "chore: Update dependencies"
  • git push -f origin HEAD:npm-update
  • PR_EXISTS=$(gh pr list --base master --head npm-update --json number --jq 'length') if [ "$PR_EXISTS" -eq "0" ]; then echo "pr_exists=false" >> $GITHUB_OUTPUT else echo "pr_exists=true" >> $GITHUB_OUTPUT fi
  • gh pr create \ --base master \ --head npm-update \ --title "chore: Update dependencies" \ --body ""
View raw YAML
name: NPM Update

on:
  workflow_dispatch:
  schedule:
    - cron: "0 0 * * *" # Run daily at midnight UTC

permissions:
  contents: write
  pull-requests: write

jobs:
  npm-update:
    # Only run on the original repository, not on forks
    if: github.repository == 'louislam/uptime-kuma'
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write

    steps:
      - name: Checkout master branch
        uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with:
          ref: master
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Setup Node.js
        uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
        with:
          node-version: 20

      - name: Generate lockfile from scratch
        run: |
          rm -f package-lock.json
          npm install --package-lock-only

      - name: Check if there are changes
        id: check_changes
        run: |
          if git diff --quiet package-lock.json; then
            echo "has_changes=false" >> $GITHUB_OUTPUT
          else
            echo "has_changes=true" >> $GITHUB_OUTPUT
          fi

      - name: Configure git
        if: steps.check_changes.outputs.has_changes == 'true'
        run: |
          git config --global user.name "github-actions[bot]"
          git config --global user.email "github-actions[bot]@users.noreply.github.com"

      - name: Commit changes
        if: steps.check_changes.outputs.has_changes == 'true'
        run: |
          git add package-lock.json
          git commit -m "chore: Update dependencies"

      - name: Force push to npm-update branch
        if: steps.check_changes.outputs.has_changes == 'true'
        run: |
          git push -f origin HEAD:npm-update

      - name: Check if PR exists
        if: steps.check_changes.outputs.has_changes == 'true'
        id: check_pr
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          PR_EXISTS=$(gh pr list --base master --head npm-update --json number --jq 'length')
          if [ "$PR_EXISTS" -eq "0" ]; then
            echo "pr_exists=false" >> $GITHUB_OUTPUT
          else
            echo "pr_exists=true" >> $GITHUB_OUTPUT
          fi

      - name: Create Pull Request
        if: steps.check_changes.outputs.has_changes == 'true' && steps.check_pr.outputs.pr_exists == 'false'
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh pr create \
            --base master \
            --head npm-update \
            --title "chore: Update dependencies" \
            --body ""
pr-description-check perms .github/workflows/pr-description-check.yml
Triggers
pull_request_target
Runs on
ubuntu-latest
Jobs
check-pr-description
View raw YAML
name: "PR description template check"

on: # zizmor: ignore[dangerous-triggers]
  pull_request_target:
    types: [opened, reopened]

permissions:
  pull-requests: write
  issues: write
  contents: read

jobs:
  check-pr-description:
    name: Check PR description and close if missing template phrase
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
      issues: write
    steps:
      - name: Check PR description
        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
        with:
          script: |
            const pr = context.payload.pull_request;
            const body = (pr && pr.body) ? pr.body : "";
            const requiredPhrase = "avoid unnecessary back and forth";

            const exclude = ["UptimeKumaBot", "Copilot", "copilot-swe-agent"];
            const excludeLower = exclude.map((e) => e.toLowerCase());
            const author = pr?.user?.login || "";

            // If author is in exclude list, skip
            if (author && excludeLower.includes(author.toLowerCase())) {
              core.info(`PR #${pr.number} opened by excluded user '${author}', skipping template check.`);
              return;
            }

            if (!body || !body.toLowerCase().includes(requiredPhrase.toLowerCase())) {
              const owner = context.repo.owner;
              const repo = context.repo.repo;
              const number = pr.number;

              const commentBody = `Hello! This pull request does not follow the repository's PR template and is being closed automatically.`;

              // Post comment
              await github.rest.issues.createComment({ owner, repo, issue_number: number, body: commentBody });

              // Close
              await github.rest.pulls.update({ owner, repo, pull_number: number, state: "closed" });

              core.info(`Closed PR #${number} because required phrase was not present.`);
            } else {
              core.info("PR description contains required phrase; no action taken.");
            }
pr-title perms .github/workflows/pr-title.yml
Triggers
pull_request_target
Runs on
ubuntu-latest
Jobs
pr-title
Actions
amannn/action-semantic-pull-request
View raw YAML
name: "PR Metadata"
# if someone opens a PR, edits it, or reopens it we want to validate the title
# This is separate from the rest of the CI as the title may change without code changes

on:
  # SECURITY: pull_request_target is used here to allow validation of PRs from forks.
  # This is safe because:
  # 1. No code from the PR is checked out
  # 2. Permissions are restricted to pull-requests: read
  # 3. Only a trusted third-party action is used to validate the PR title
  # 4. No user-controlled code is executed
  pull_request_target: # zizmor: ignore[dangerous-triggers]
    types:
      - opened
      - edited
      - reopened
      - synchronize

permissions:
  pull-requests: read

jobs:
  pr-title:
    name: Validate PR title follows https://conventionalcommits.org
    runs-on: ubuntu-latest
    permissions:
      pull-requests: read
    steps:
      - uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
prevent-file-change perms AI .github/workflows/prevent-file-change.yml
Triggers
pull_request
Runs on
ubuntu-latest
Jobs
check-file-changes
Actions
xalvarez/prevent-file-change-action
View raw YAML
name: prevent-file-change

on:
  pull_request:
permissions: {}

jobs:
  check-file-changes:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: read
    steps:
      - name: Prevent file change
        uses: xalvarez/prevent-file-change-action@004d9f17c2e4a7afa037cda5f38dc55a5e9c9c06 # v1.9.1
        with:
          githubToken: ${{ secrets.GITHUB_TOKEN }}
          # Regex, /src/lang/*.json is not allowed to be changed, except for /src/lang/en.json
          pattern: '^(?!src/lang/en\.json$)src/lang/.*\.json$'
          trustedAuthors: UptimeKumaBot
release-beta perms .github/workflows/release-beta.yml
Triggers
workflow_dispatch
Runs on
ubuntu-latest
Jobs
beta-release
Actions
docker/setup-buildx-action, docker/setup-qemu-action, docker/login-action, docker/login-action
Commands
  • git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git" # Delete remote branch if it exists git push origin --delete "release-${VERSION}" || true # Delete local branch if it exists git branch -D "release-${VERSION}" || true # For testing purpose # git checkout beta-workflow git checkout -b "release-${VERSION}"
  • npm clean-install --no-fund
  • npm run release-beta
View raw YAML
name: Beta Release

on:
  workflow_dispatch:
    inputs:
      version:
        description: "Beta version number (e.g., 2.1.0-beta.2)"
        required: true
        type: string
      previous_version:
        description: "Previous version tag for changelog (e.g., 2.1.0-beta.1)"
        required: true
        type: string
      dry_run:
        description: "Dry Run (The docker image will not be pushed to registries. PR will still be created.)"
        required: false
        type: boolean
        default: false

permissions:
  contents: write
  pull-requests: write

jobs:
  beta-release:
    runs-on: ubuntu-latest
    timeout-minutes: 120

    steps:
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with:
          ref: master
          persist-credentials: true
          fetch-depth: 0 # Fetch all history for changelog generation

      - name: Set up Node.js
        uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
        with:
          node-version: 24

      - name: Create release branch
        env:
          VERSION: ${{ inputs.version }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git"
          # Delete remote branch if it exists
          git push origin --delete "release-${VERSION}" || true
          # Delete local branch if it exists
          git branch -D "release-${VERSION}" || true
          # For testing purpose
          # git checkout beta-workflow
          git checkout -b "release-${VERSION}"

      - name: Install dependencies
        run: npm clean-install --no-fund

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1

      - name: Set up QEMU
        uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0

      - name: Login to Docker Hub
        uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Login to GitHub Container Registry
        uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
        with:
          registry: ghcr.io
          username: ${{ secrets.GHCR_USERNAME }}
          password: ${{ secrets.GHCR_TOKEN }}

      - name: Run release-beta
        env:
          RELEASE_BETA_VERSION: ${{ inputs.version }}
          RELEASE_PREVIOUS_VERSION: ${{ inputs.previous_version }}
          DRY_RUN: ${{ inputs.dry_run }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITHUB_RUN_ID: ${{ github.run_id }}
        run: npm run release-beta

      - name: Upload dist.tar.gz as artifact
        uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
        with:
          name: dist-${{ inputs.version }}
          path: ./tmp/dist.tar.gz
          retention-days: 90
release-final perms .github/workflows/release-final.yml
Triggers
workflow_dispatch
Runs on
ubuntu-latest
Jobs
release
Actions
docker/setup-buildx-action, docker/setup-qemu-action, docker/login-action, docker/login-action
Commands
  • git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git" # Delete remote branch if it exists git push origin --delete "release-${VERSION}" || true # Delete local branch if it exists git branch -D "release-${VERSION}" || true # For testing purpose # git checkout beta-workflow git checkout -b "release-${VERSION}"
  • npm clean-install --no-fund
  • npm run release-final
View raw YAML
name: Final Release

on:
  workflow_dispatch:
    inputs:
      version:
        description: "Release version number (e.g., 2.1.0)"
        required: true
        type: string
      previous_version:
        description: "Previous version tag for changelog (e.g., 2.1.0-beta.3)"
        required: true
        type: string
      dry_run:
        description: "Dry Run (The docker image will not be pushed to registries. PR will still be created.)"
        required: false
        type: boolean
        default: false

permissions:
  contents: write
  pull-requests: write

jobs:
  release:
    runs-on: ubuntu-latest
    timeout-minutes: 120

    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          ref: master
          persist-credentials: true
          fetch-depth: 0 # Fetch all history for changelog generation

      - name: Set up Node.js
        uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
        with:
          node-version: 24

      - name: Create release branch
        env:
          VERSION: ${{ inputs.version }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git"
          # Delete remote branch if it exists
          git push origin --delete "release-${VERSION}" || true
          # Delete local branch if it exists
          git branch -D "release-${VERSION}" || true
          # For testing purpose
          # git checkout beta-workflow
          git checkout -b "release-${VERSION}"

      - name: Install dependencies
        run: npm clean-install --no-fund

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0

      - name: Set up QEMU
        uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0

      - name: Login to Docker Hub
        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Login to GitHub Container Registry
        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
        with:
          registry: ghcr.io
          username: ${{ secrets.GHCR_USERNAME }}
          password: ${{ secrets.GHCR_TOKEN }}

      - name: Run release-final
        env:
          RELEASE_VERSION: ${{ inputs.version }}
          RELEASE_PREVIOUS_VERSION: ${{ inputs.previous_version }}
          DRY_RUN: ${{ inputs.dry_run }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITHUB_RUN_ID: ${{ github.run_id }}
        run: npm run release-final

      - name: Upload dist.tar.gz as artifact
        uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
        with:
          name: dist-${{ inputs.version }}
          path: ./tmp/dist.tar.gz
          retention-days: 90
release-nightly perms .github/workflows/release-nightly.yml
Triggers
schedule, workflow_dispatch
Runs on
ubuntu-latest
Jobs
release-nightly
Actions
docker/setup-qemu-action, docker/setup-buildx-action, docker/login-action, docker/login-action
Commands
  • npm clean-install --no-fund
  • npm run release-nightly
View raw YAML
name: Nightly Release

on:
  schedule:
    # Runs at 2:00 AM UTC every day
    - cron: "0 2 * * *"
  workflow_dispatch: # Allow manual trigger

permissions: {}

jobs:
  release-nightly:
    # Only run on the original repository, not on forks
    if: github.repository == 'louislam/uptime-kuma'
    runs-on: ubuntu-latest
    timeout-minutes: 120
    permissions:
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with: { persist-credentials: false }

      - name: Set up QEMU
        uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1

      - name: Login to Docker Hub
        uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Login to GitHub Container Registry
        uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
        with:
          registry: ghcr.io
          username: ${{ secrets.GHCR_USERNAME }}
          password: ${{ secrets.GHCR_TOKEN }}

      - name: Use Node.js 20
        uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
        with:
          node-version: 20

      - name: Cache/Restore node_modules
        uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
        id: node-modules-cache
        with:
          path: node_modules
          key: node-modules-${{ runner.os }}-node20-${{ hashFiles('**/package-lock.json') }}

      - name: Install dependencies
        run: npm clean-install --no-fund

      - name: Run release-nightly
        run: npm run release-nightly
stale-bot perms .github/workflows/stale-bot.yml
Triggers
workflow_dispatch, schedule
Runs on
ubuntu-latest
Jobs
stale
Actions
actions/stale, actions/stale
View raw YAML
name: "Automatically close stale issues"
on:
  workflow_dispatch:
  schedule:
    - cron: "0 */6 * * *"
#Run every 6 hours
permissions: {}

jobs:
  stale:
    # Only run on the original repository, not on forks
    if: github.repository == 'louislam/uptime-kuma'
    runs-on: ubuntu-latest
    permissions:
      actions: write
      issues: write
    steps:
      - uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1
        with:
          stale-issue-message: |-
            We are clearing up our old `help`-issues and your issue has been open for 60 days with no activity.
            If no comment is made and the stale label is not removed, this issue will be closed in 7 days.
          days-before-stale: 60
          days-before-close: 7
          days-before-pr-stale: -1
          days-before-pr-close: -1
          exempt-issue-labels: "News,discussion,bug,doc,feature-request"
          exempt-issue-assignees: "louislam"
          operations-per-run: 200
      - uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1
        with:
          stale-issue-message: |-
            This issue was marked as `cannot-reproduce` by a maintainer.
            If an issue is non-reproducible, we cannot fix it, as we do not know what the underlying issue is.
            If you have any ideas how we can reproduce this issue, we would love to hear them.

            We don't have a good way to deal with truely unreproducible issues and are going to close this issue in a month.
            If think there might be other differences in our environment or in how we tried to reproduce this, we would appreciate any ideas.
          close-issue-message: |-
            This issue will be closed as no way to reproduce it has been found.
            If you/somebody finds a way how to (semi-reliably) reproduce this, we can reopen this issue. ^^
          days-before-stale: 180
          days-before-close: 30
          days-before-pr-stale: -1
          days-before-pr-close: -1
          any-of-issue-labels: "cannot-reproduce"
          operations-per-run: 200
validate perms .github/workflows/validate.yml
Triggers
push, pull_request, workflow_dispatch
Runs on
ubuntu-latest, ubuntu-latest
Jobs
json-yaml-validate, validate
Actions
GrantBirki/json-yaml-validate
Commands
  • node ./extra/check-lang-json.js
  • node ./extra/check-knex-filenames.mjs
  • node ./extra/check-package-json.mjs
View raw YAML
name: validate
on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
      - 1.23.X
  workflow_dispatch:
permissions: {}

jobs:
  json-yaml-validate:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write # enable write permissions for pull request comments
    steps:
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with: { persist-credentials: false }

      - name: json-yaml-validate
        id: json-yaml-validate
        uses: GrantBirki/json-yaml-validate@9bbaa8474e3af4e91f25eda8ac194fdc30564d96 # v4.0.0
        with:
          comment: "true" # enable comment mode
          exclude_file: ".github/config/exclude.txt" # gitignore style file for exclusions

  # General validations
  validate:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with: { persist-credentials: false }
      - name: Use Node.js 25
        uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
        with:
          node-version: 25

      - name: Validate language JSON files
        run: node ./extra/check-lang-json.js

      - name: Validate knex migrations filename
        run: node ./extra/check-knex-filenames.mjs

      - name: Validate package.json
        run: node ./extra/check-package-json.mjs