From b5795a8b3f961926153d88641265a50cc5746938 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Thu, 6 Nov 2025 16:16:53 -0800 Subject: [PATCH 01/11] Fixed update notice. --- src/app/(main)/UpdateNotice.tsx | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/app/(main)/UpdateNotice.tsx b/src/app/(main)/UpdateNotice.tsx index 35728791..81e2ca3a 100644 --- a/src/app/(main)/UpdateNotice.tsx +++ b/src/app/(main)/UpdateNotice.tsx @@ -1,5 +1,5 @@ import { useEffect, useCallback, useState } from 'react'; -import { Button, AlertBanner, Flexbox } from '@umami/react-zen'; +import { Button, AlertBanner, Column, Row } from '@umami/react-zen'; import { setItem } from '@/lib/storage'; import { useVersion, checkVersion } from '@/store/version'; import { REPO_URL, VERSION_CHECK } from '@/lib/constants'; @@ -47,13 +47,15 @@ export function UpdateNotice({ user, config }) { } return ( - - - - - - + + + + + + + + ); } From 6135ef9dd218186ed663f89a511fa66bfecc6aec Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Thu, 6 Nov 2025 22:24:08 -0800 Subject: [PATCH 02/11] Fixed test. --- src/lib/__tests__/detect.test.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/__tests__/detect.test.ts b/src/lib/__tests__/detect.test.ts index fcf706af..f02ac839 100644 --- a/src/lib/__tests__/detect.test.ts +++ b/src/lib/__tests__/detect.test.ts @@ -1,4 +1,4 @@ -import * as detect from '../detect'; +import { getIpAddress } from '../ip'; const IP = '127.0.0.1'; const BAD_IP = '127.127.127.127'; @@ -6,23 +6,23 @@ const BAD_IP = '127.127.127.127'; test('getIpAddress: Custom header', () => { process.env.CLIENT_IP_HEADER = 'x-custom-ip-header'; - expect(detect.getIpAddress(new Headers({ 'x-custom-ip-header': IP }))).toEqual(IP); + expect(getIpAddress(new Headers({ 'x-custom-ip-header': IP }))).toEqual(IP); }); test('getIpAddress: CloudFlare header', () => { - expect(detect.getIpAddress(new Headers({ 'cf-connecting-ip': IP }))).toEqual(IP); + expect(getIpAddress(new Headers({ 'cf-connecting-ip': IP }))).toEqual(IP); }); test('getIpAddress: Standard header', () => { - expect(detect.getIpAddress(new Headers({ 'x-forwarded-for': IP }))).toEqual(IP); + expect(getIpAddress(new Headers({ 'x-forwarded-for': IP }))).toEqual(IP); }); test('getIpAddress: CloudFlare header is lower priority than standard header', () => { - expect( - detect.getIpAddress(new Headers({ 'cf-connecting-ip': BAD_IP, 'x-forwarded-for': IP })), - ).toEqual(IP); + expect(getIpAddress(new Headers({ 'cf-connecting-ip': BAD_IP, 'x-forwarded-for': IP }))).toEqual( + IP, + ); }); test('getIpAddress: No header', () => { - expect(detect.getIpAddress(new Headers())).toEqual(null); + expect(getIpAddress(new Headers())).toEqual(null); }); From 4272bb4c4d44aec362ecf0e1c16be61c5f053525 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Thu, 6 Nov 2025 22:48:34 -0800 Subject: [PATCH 03/11] Removed db types from docker build. --- .github/workflows/cd.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index a02e9900..1b9e8965 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -15,10 +15,6 @@ jobs: packages: write id-token: write - strategy: - matrix: - db-type: [postgresql] - steps: - uses: actions/checkout@v5 @@ -53,7 +49,6 @@ jobs: ghcr.io/${{ github.repository }} flavor: | latest=auto - prefix=${{ matrix.db-type }}- tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} @@ -65,7 +60,6 @@ jobs: with: context: . platforms: linux/amd64,linux/arm64 - build-args: DATABASE_TYPE=${{ matrix.db-type }} push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From 437c9603dbf9e2362c3a19fd4c5952592867708f Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Thu, 6 Nov 2025 22:58:26 -0800 Subject: [PATCH 04/11] Fixed build. --- .github/workflows/cd.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 1b9e8965..d3ee4ee2 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -53,6 +53,9 @@ jobs: type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}} + type=ref,event=branch + type=ref,event=pr + type=sha - name: Build and push Docker image id: build-and-push From 04a05bbf26b0855441b9c2cc4cfa1a4ad49efa9b Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Thu, 6 Nov 2025 23:35:14 -0800 Subject: [PATCH 05/11] Added workflow input. --- .github/workflows/cd.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index d3ee4ee2..1e070a7c 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -5,6 +5,11 @@ on: tags: - 'v*.*.*' workflow_dispatch: + inputs: + manual_tag: + description: 'Optional image tag (e.g. 1.2.3, beta, nightly)' + required: false + default: '' jobs: build: @@ -54,8 +59,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}} type=ref,event=branch - type=ref,event=pr - type=sha + type=raw,value=latest,enable=${{ github.event_name == 'workflow_dispatch' }} - name: Build and push Docker image id: build-and-push From dd6556968cfbf8d05b18e7e93e2f37963015958a Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Thu, 6 Nov 2025 23:58:12 -0800 Subject: [PATCH 06/11] Updated image tag. --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7b51db66..8c8a47a6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ --- services: umami: - image: ghcr.io/umami-software/umami:postgresql-latest + image: ghcr.io/umami-software/umami:latest ports: - "3000:3000" environment: From a90b7881387ac54d745fd8c11325e312c0fcc0d8 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 7 Nov 2025 00:09:53 -0800 Subject: [PATCH 07/11] Updated cd script. --- .github/workflows/cd.yml | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 1e070a7c..3098d314 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -6,8 +6,8 @@ on: - 'v*.*.*' workflow_dispatch: inputs: - manual_tag: - description: 'Optional image tag (e.g. 1.2.3, beta, nightly)' + version: + description: 'Optional image version (e.g. 3.0.0, beta)' required: false default: '' @@ -23,7 +23,6 @@ jobs: steps: - uses: actions/checkout@v5 - # Install cosign (for image signing) - name: Install cosign uses: sigstore/cosign-installer@v3 @@ -45,6 +44,21 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + # Normalize manual input if provided + - name: Normalize manual version + id: normalize + run: | + INPUT="${{ github.event.inputs.version }}" + if [[ -n "$INPUT" ]]; then + # Strip leading v if present + VERSION="${INPUT#v}" + MAJOR=$(echo "$VERSION" | cut -d. -f1) + MINOR=$(echo "$VERSION" | cut -d. -f2) + echo "version_tags=${VERSION},${MAJOR}.${MINOR},${MAJOR}" >> $GITHUB_ENV + else + echo "version_tags=" >> $GITHUB_ENV + fi + - name: Extract Docker metadata id: meta uses: docker/metadata-action@v5 @@ -55,11 +69,18 @@ jobs: flavor: | latest=auto tags: | + # Semver tags from real Git tags type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}} + + # Manual input derived tags + type=raw,value=${{ env.version_tags }},enable=${{ env.version_tags != '' }} + + # Fallbacks for branches/PRs type=ref,event=branch - type=raw,value=latest,enable=${{ github.event_name == 'workflow_dispatch' }} + type=ref,event=pr + type=sha - name: Build and push Docker image id: build-and-push @@ -73,7 +94,6 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max - # Sign the published image digest - name: Sign the published Docker image env: TAGS: ${{ steps.meta.outputs.tags }} From df3ca02e8b0d8e9f4ba7027e43eb1d35e6f93b80 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 7 Nov 2025 08:52:16 -0800 Subject: [PATCH 08/11] Always push latest for Docker. --- .github/workflows/cd.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 3098d314..515aa2aa 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -54,7 +54,8 @@ jobs: VERSION="${INPUT#v}" MAJOR=$(echo "$VERSION" | cut -d. -f1) MINOR=$(echo "$VERSION" | cut -d. -f2) - echo "version_tags=${VERSION},${MAJOR}.${MINOR},${MAJOR}" >> $GITHUB_ENV + # Include latest explicitly + echo "version_tags=${VERSION},${MAJOR}.${MINOR},${MAJOR},latest" >> $GITHUB_ENV else echo "version_tags=" >> $GITHUB_ENV fi @@ -69,17 +70,16 @@ jobs: flavor: | latest=auto tags: | - # Semver tags from real Git tags + # From real Git tags (v1.2.3) type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}} - # Manual input derived tags + # Manual input tags type=raw,value=${{ env.version_tags }},enable=${{ env.version_tags != '' }} - # Fallbacks for branches/PRs + # Fallbacks type=ref,event=branch - type=ref,event=pr type=sha - name: Build and push Docker image From d2f512cae7af0538fc67231404d9ed31ff2c3adb Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 7 Nov 2025 09:14:19 -0800 Subject: [PATCH 09/11] Don't publish .sig files. --- .github/workflows/cd-manual.yml | 58 --------------------------------- .github/workflows/cd.yml | 21 +++++------- 2 files changed, 9 insertions(+), 70 deletions(-) delete mode 100644 .github/workflows/cd-manual.yml diff --git a/.github/workflows/cd-manual.yml b/.github/workflows/cd-manual.yml deleted file mode 100644 index df6aa628..00000000 --- a/.github/workflows/cd-manual.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Create docker images (manual) - -on: - workflow_dispatch: - inputs: - version: - type: string - description: Version - required: true - -jobs: - build: - name: Build, push, and deploy - runs-on: ubuntu-latest - - strategy: - matrix: - db-type: [postgresql] - - steps: - - uses: actions/checkout@v3 - - - name: Extract version parts from input - id: extract_version - run: | - echo "version=$(echo ${{ github.event.inputs.version }})" >> $GITHUB_ENV - echo "major=$(echo ${{ github.event.inputs.version }} | cut -d. -f1)" >> $GITHUB_ENV - echo "minor=$(echo ${{ github.event.inputs.version }} | cut -d. -f2)" >> $GITHUB_ENV - - - name: Generate tags - id: generate_tags - run: | - echo "tag_major=$(echo ${{ matrix.db-type }}-${{ env.major }})" >> $GITHUB_ENV - echo "tag_minor=$(echo ${{ matrix.db-type }}-${{ env.major }}.${{ env.minor }})" >> $GITHUB_ENV - echo "tag_patch=$(echo ${{ matrix.db-type }}-${{ env.version }})" >> $GITHUB_ENV - echo "tag_latest=$(echo ${{ matrix.db-type }}-latest)" >> $GITHUB_ENV - - - uses: mr-smithers-excellent/docker-build-push@v6 - name: Build & push Docker image to ghcr.io for ${{ matrix.db-type }} - with: - image: umami - tags: ${{ env.tag_major }}, ${{ env.tag_minor }}, ${{ env.tag_patch }}, ${{ env.tag_latest }} - buildArgs: DATABASE_TYPE=${{ matrix.db-type }} - registry: ghcr.io - multiPlatform: true - platform: linux/amd64,linux/arm64 - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - uses: mr-smithers-excellent/docker-build-push@v6 - name: Build & push Docker image to docker.io for ${{ matrix.db-type }} - with: - image: umamisoftware/umami - tags: ${{ env.tag_major }}, ${{ env.tag_minor }}, ${{ env.tag_patch }}, ${{ env.tag_latest }} - buildArgs: DATABASE_TYPE=${{ matrix.db-type }} - registry: docker.io - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 515aa2aa..a4934e79 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -50,11 +50,9 @@ jobs: run: | INPUT="${{ github.event.inputs.version }}" if [[ -n "$INPUT" ]]; then - # Strip leading v if present VERSION="${INPUT#v}" MAJOR=$(echo "$VERSION" | cut -d. -f1) MINOR=$(echo "$VERSION" | cut -d. -f2) - # Include latest explicitly echo "version_tags=${VERSION},${MAJOR}.${MINOR},${MAJOR},latest" >> $GITHUB_ENV else echo "version_tags=" >> $GITHUB_ENV @@ -70,15 +68,10 @@ jobs: flavor: | latest=auto tags: | - # From real Git tags (v1.2.3) type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}} - - # Manual input tags type=raw,value=${{ env.version_tags }},enable=${{ env.version_tags != '' }} - - # Fallbacks type=ref,event=branch type=sha @@ -93,9 +86,13 @@ jobs: labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max + provenance: false # disable automatic attestations + + # Generate a local provenance attestation instead of uploading signatures + - name: Generate provenance attestation + run: | + cosign attest --yes \ + --predicate <(echo '{"build":"github-actions","repo":"${{ github.repository }}","run_id":"${{ github.run_id }}"}') \ + --type slsaprovenance \ + ${{ steps.meta.outputs.tags }} - - name: Sign the published Docker image - env: - TAGS: ${{ steps.meta.outputs.tags }} - DIGEST: ${{ steps.build-and-push.outputs.digest }} - run: echo "${TAGS}" | xargs -I {} cosign sign --yes "{}@${DIGEST}" From 3e9ca8761ee4ae3dab686fd4fceea0f9aec29e20 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 7 Nov 2025 09:15:01 -0800 Subject: [PATCH 10/11] Removed workflow script. --- .github/workflows/delete-untagged-images.yml | 22 -------------------- 1 file changed, 22 deletions(-) delete mode 100644 .github/workflows/delete-untagged-images.yml diff --git a/.github/workflows/delete-untagged-images.yml b/.github/workflows/delete-untagged-images.yml deleted file mode 100644 index a23a1bd2..00000000 --- a/.github/workflows/delete-untagged-images.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Delete untagged GHCR images - -on: - workflow_dispatch: # Run manually from the Actions tab - -jobs: - cleanup: - name: Delete all untagged images - runs-on: ubuntu-latest - - permissions: - packages: write - contents: read - - steps: - - name: Delete untagged GHCR images - uses: actions/delete-package-versions@v5 - with: - package-name: "umami" # 👈 change if your GHCR package name differs - package-type: "container" - delete-only-untagged-versions: true - min-versions-to-keep: 0 From 6ee93f7ac92a49ece115024e46d2dce51c963ebf Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 7 Nov 2025 12:21:17 -0800 Subject: [PATCH 11/11] Updated README and cd.yml. --- .github/workflows/cd.yml | 59 ++++++++++++++++++++++------------------ README.md | 2 +- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index a4934e79..534b2321 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -7,7 +7,7 @@ on: workflow_dispatch: inputs: version: - description: 'Optional image version (e.g. 3.0.0, beta)' + description: 'Optional image version (e.g. 3.0.0, v3.0.0, or 3.0.0-beta.1)' required: false default: '' @@ -29,6 +29,13 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 + - name: Log into GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Log into Docker Hub if: github.repository == 'umami-software/umami' uses: docker/login-action@v3 @@ -37,27 +44,29 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Log into GHCR - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - # Normalize manual input if provided - - name: Normalize manual version - id: normalize + # Compute tags for the image + - name: Compute version tags + id: compute run: | INPUT="${{ github.event.inputs.version }}" + TAGS="" + if [[ -n "$INPUT" ]]; then - VERSION="${INPUT#v}" + VERSION="${INPUT#v}" # strip leading v MAJOR=$(echo "$VERSION" | cut -d. -f1) MINOR=$(echo "$VERSION" | cut -d. -f2) - echo "version_tags=${VERSION},${MAJOR}.${MINOR},${MAJOR},latest" >> $GITHUB_ENV - else - echo "version_tags=" >> $GITHUB_ENV + + # prereleases (e.g., 3.0.0-beta) do NOT get 'latest' + if [[ "$VERSION" == *-* ]]; then + TAGS="${VERSION}" + else + TAGS="${VERSION},${MAJOR}.${MINOR},${MAJOR},latest" + fi fi + echo "tags=$TAGS" >> $GITHUB_OUTPUT + echo "Computed tags: $TAGS" + - name: Extract Docker metadata id: meta uses: docker/metadata-action@v5 @@ -65,34 +74,32 @@ jobs: images: | umamisoftware/umami,enable=${{ github.repository == 'umami-software/umami' }} ghcr.io/${{ github.repository }} - flavor: | - latest=auto tags: | - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - type=raw,value=${{ env.version_tags }},enable=${{ env.version_tags != '' }} + type=semver,pattern={{version}},enable=${{ github.ref_type == 'tag' }} + type=semver,pattern={{major}}.{{minor}},enable=${{ github.ref_type == 'tag' }} + type=semver,pattern={{major}},enable=${{ github.ref_type == 'tag' }} + type=raw,value=${{ steps.compute.outputs.tags }},enable=${{ steps.compute.outputs.tags != '' }} type=ref,event=branch type=sha + # Build and push images - name: Build and push Docker image id: build-and-push uses: docker/build-push-action@v6 with: context: . - platforms: linux/amd64,linux/arm64 push: true + platforms: linux/amd64,linux/arm64 tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max - provenance: false # disable automatic attestations + provenance: false # disable automatic registry attestations - # Generate a local provenance attestation instead of uploading signatures - - name: Generate provenance attestation + # Generate a local provenance attestation (not uploaded) + - name: Generate local provenance attestation run: | cosign attest --yes \ --predicate <(echo '{"build":"github-actions","repo":"${{ github.repository }}","run_id":"${{ github.run_id }}"}') \ --type slsaprovenance \ ${{ steps.meta.outputs.tags }} - diff --git a/README.md b/README.md index 6d166d8c..d3791e26 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ docker compose up -d Alternatively, to pull just the Umami Docker image with PostgreSQL support: ```bash -docker pull docker.umami.is/umami-software/umami:postgresql-latest +docker pull docker.umami.is/umami-software/umami:latest ``` ---