Jelajahi Sumber

Fix CI setup and errors

Joe Chen 2 minggu lalu
induk
melakukan
9ea429faaf

+ 0 - 35
.github/workflows/codeball.yml

@@ -1,35 +0,0 @@
-# Docs: https://github.com/sturdy-dev/codeball-action
-name: Codeball
-on: [ pull_request ]
-
-permissions:
-  contents: read
-  issues: write
-  pull-requests: write
-
-jobs:
-  codeball:
-    runs-on: ubuntu-latest
-    name: Codeball
-    steps:
-
-      # Start a new Codeball review job
-      # This step is asynchronous and will return a job id
-      - name: Trigger Codeball
-        id: codeball_baller
-        uses: sturdy-dev/codeball-action/baller@v2
-
-
-      # Wait for Codeball to return the status
-      - name: Get Status
-        id: codeball_status
-        uses: sturdy-dev/codeball-action/status@v2
-        with:
-          codeball-job-id: ${{ steps.codeball_baller.outputs.codeball-job-id }}
-
-      # If Codeball approved the contribution, approve the PR
-      - name: Approve PR
-        uses: sturdy-dev/codeball-action/approver@v2
-        if: ${{ steps.codeball_status.outputs.approved == 'true' }}
-        with:
-          message: "Codeball: LGTM! :+1:"

+ 4 - 4
.github/workflows/codeql.yml

@@ -39,7 +39,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v2
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
         with:
           # We must fetch at least the immediate parents so that if this is
           # a pull request then we can checkout the head.
@@ -47,7 +47,7 @@ jobs:
 
       # Initializes the CodeQL tools for scanning.
       - name: Initialize CodeQL
-        uses: github/codeql-action/init@v1
+        uses: github/codeql-action/init@fdbfb4d2750291e159f0156def62b853c2798ca2 # v3.28.3
         with:
           languages: ${{ matrix.language }}
           # If you wish to specify custom queries, you can do so here or in a config file.
@@ -58,7 +58,7 @@ jobs:
       # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
       # If this step fails, then you should remove it and run the build manually (see below)
       - name: Autobuild
-        uses: github/codeql-action/autobuild@v1
+        uses: github/codeql-action/autobuild@fdbfb4d2750291e159f0156def62b853c2798ca2 # v3.28.3
 
       # ℹ️ Command-line programs to run using the OS shell.
       # 📚 https://git.io/JvXDl
@@ -72,4 +72,4 @@ jobs:
       #   make release
 
       - name: Perform CodeQL Analysis
-        uses: github/codeql-action/analyze@v1
+        uses: github/codeql-action/analyze@fdbfb4d2750291e159f0156def62b853c2798ca2 # v3.28.3

+ 267 - 37
.github/workflows/docker.yml

@@ -5,37 +5,36 @@ on:
       - main
   pull_request:
     paths:
+      - '.trivy.yaml'
       - 'Dockerfile'
+      - 'Dockerfile.next'
       - 'docker/**'
+      - 'docker-next/**'
       - '.github/workflows/docker.yml'
   release:
     types: [ published ]
 
 jobs:
   buildx:
-    if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
+    if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository == 'gogs/gogs' }}
+    concurrency:
+      group: ${{ github.workflow }}-${{ github.ref }}
+      cancel-in-progress: true
     runs-on: ubuntu-latest
     permissions:
       actions: write
       contents: read
       packages: write
     steps:
-      - name: Canel previous runs
-        uses: styfle/cancel-workflow-action@0.9.1
-        with:
-          all_but_latest: true
-          access_token: ${{ secrets.GITHUB_TOKEN }}
       - name: Checkout code
-        uses: actions/checkout@v2
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
       - name: Set up QEMU
-        uses: docker/setup-qemu-action@v1
+        uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
+        with:
+          platforms: linux/amd64,linux/arm64,linux/arm/v7
       - name: Set up Docker Buildx
         id: buildx
-        uses: docker/setup-buildx-action@v1
-        with:
-          config-inline: |
-            [worker.oci]
-              max-parallelism = 2
+        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
       - name: Inspect builder
         run: |
           echo "Name:      ${{ steps.buildx.outputs.name }}"
@@ -44,18 +43,18 @@ jobs:
           echo "Flags:     ${{ steps.buildx.outputs.flags }}"
           echo "Platforms: ${{ steps.buildx.outputs.platforms }}"
       - name: Login to Docker Hub
-        uses: docker/login-action@v1
+        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
         with:
           username: ${{ secrets.DOCKERHUB_USERNAME }}
           password: ${{ secrets.DOCKERHUB_TOKEN }}
       - name: Login to GitHub Container registry
-        uses: docker/login-action@v1
+        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
         with:
           registry: ghcr.io
           username: ${{ github.repository_owner }}
           password: ${{ secrets.GITHUB_TOKEN }}
       - name: Build and push images
-        uses: docker/build-push-action@v2
+        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
         with:
           context: .
           platforms: linux/amd64,linux/arm64,linux/arm/v7
@@ -63,14 +62,126 @@ jobs:
           tags: |
             gogs/gogs:latest
             ghcr.io/gogs/gogs:latest
-            registry.digitalocean.com/gogs/gogs:latest
       - name: Scan for container vulnerabilities
-        uses: aquasecurity/trivy-action@master
+        uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
         with:
           image-ref: gogs/gogs:latest
           exit-code: '1'
       - name: Send email on failure
-        uses: dawidd6/action-send-mail@v3
+        uses: dawidd6/action-send-mail@2cea9617b09d79a095af21254fbcb7ae95903dde # v3.12.0
+        if: ${{ failure() }}
+        with:
+          server_address: smtp.mailgun.org
+          server_port: 465
+          username: ${{ secrets.SMTP_USERNAME }}
+          password: ${{ secrets.SMTP_PASSWORD }}
+          subject: GitHub Actions (${{ github.repository }}) job result
+          to: github-actions-8ce6454@unknwon.io
+          from: GitHub Actions (${{ github.repository }})
+          reply_to: noreply@unknwon.io
+          body: |
+            The job "${{ github.job }}" of ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }} completed with "${{ job.status }}".
+
+            View the job run at: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+
+  buildx-next:
+    if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository == 'gogs/gogs' }}
+    concurrency:
+      group: ${{ github.workflow }}-next-${{ github.ref }}
+      cancel-in-progress: true
+    runs-on: ubuntu-latest
+    permissions:
+      actions: write
+      contents: read
+      packages: write
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+      - name: Set up QEMU
+        uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
+        with:
+          platforms: linux/amd64,linux/arm64,linux/arm/v7
+      - name: Set up Docker Buildx
+        id: buildx
+        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+      - name: Inspect builder
+        run: |
+          echo "Name:      ${{ steps.buildx.outputs.name }}"
+          echo "Endpoint:  ${{ steps.buildx.outputs.endpoint }}"
+          echo "Status:    ${{ steps.buildx.outputs.status }}"
+          echo "Flags:     ${{ steps.buildx.outputs.flags }}"
+          echo "Platforms: ${{ steps.buildx.outputs.platforms }}"
+      - name: Login to Docker Hub
+        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+        with:
+          username: ${{ secrets.DOCKERHUB_USERNAME }}
+          password: ${{ secrets.DOCKERHUB_TOKEN }}
+      - name: Login to GitHub Container registry
+        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+        with:
+          registry: ghcr.io
+          username: ${{ github.repository_owner }}
+          password: ${{ secrets.GITHUB_TOKEN }}
+      - name: Login to DigitalOcean Container registry
+        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+        with:
+          registry: registry.digitalocean.com
+          username: ${{ secrets.DIGITALOCEAN_USERNAME }}
+          password: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
+      - name: Build and push next-gen images
+        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+        with:
+          context: .
+          file: Dockerfile.next
+          platforms: linux/amd64,linux/arm64,linux/arm/v7
+          push: true
+          tags: |
+            gogs/gogs:next-latest
+            ghcr.io/gogs/gogs:next-latest
+            registry.digitalocean.com/gogs/gogs:next-latest
+      - name: Scan for container vulnerabilities
+        uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
+        with:
+          image-ref: gogs/gogs:next-latest
+          exit-code: '1'
+      - name: Send email on failure
+        uses: dawidd6/action-send-mail@2cea9617b09d79a095af21254fbcb7ae95903dde # v3.12.0
+        if: ${{ failure() }}
+        with:
+          server_address: smtp.mailgun.org
+          server_port: 465
+          username: ${{ secrets.SMTP_USERNAME }}
+          password: ${{ secrets.SMTP_PASSWORD }}
+          subject: GitHub Actions (${{ github.repository }}) job result
+          to: github-actions-8ce6454@unknwon.io
+          from: GitHub Actions (${{ github.repository }})
+          reply_to: noreply@unknwon.io
+          body: |
+            The job "${{ github.job }}" of ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }} completed with "${{ job.status }}".
+
+            View the job run at: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+
+  deploy-demo:
+    if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository == 'gogs/gogs' }}
+    needs: buildx-next
+    runs-on: ubuntu-latest
+    permissions:
+      contents: read
+    steps:
+      - name: Configure kubectl
+        run: |
+          mkdir -p ~/.kube
+          echo "${KUBECONFIG}" | base64 -d > ~/.kube/config
+        env:
+          KUBECONFIG: ${{ secrets.DIGITALOCEAN_K8S_CLUSTER_KUBECONFIG }}
+      - name: Restart gogs-demo deployment
+        timeout-minutes: 5
+        run: |
+          set -ex
+          kubectl rollout restart deployment gogs-demo -n gogs
+          kubectl rollout status deployment gogs-demo -n gogs
+      - name: Send email on failure
+        uses: dawidd6/action-send-mail@2cea9617b09d79a095af21254fbcb7ae95903dde # v3.12.0
         if: ${{ failure() }}
         with:
           server_address: smtp.mailgun.org
@@ -93,10 +204,10 @@ jobs:
       contents: read
     steps:
       - name: Checkout code
-        uses: actions/checkout@v2
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
       - name: Set up Docker Buildx
         id: buildx
-        uses: docker/setup-buildx-action@v1
+        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
         with:
           config-inline: |
             [worker.oci]
@@ -110,19 +221,59 @@ jobs:
           echo "Platforms: ${{ steps.buildx.outputs.platforms }}"
       - name: Compute short commit SHA
         id: short-sha
-        uses: benjlevesque/short-sha@v2.1
+        uses: benjlevesque/short-sha@599815c8ee942a9616c92bcfb4f947a3b670ab0b # v3.0
       - name: Build and push images
-        uses: docker/build-push-action@v2
+        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
         with:
           context: .
           platforms: linux/amd64
           push: true
           tags: |
-            ttl.sh/gogs/gogs-${{ steps.short-sha.outputs.sha }}:1d
+            ttl.sh/gogs/gogs-${{ steps.short-sha.outputs.sha }}:7d
       - name: Scan for container vulnerabilities
-        uses: aquasecurity/trivy-action@master
+        uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
         with:
-          image-ref: ttl.sh/gogs/gogs-${{ steps.short-sha.outputs.sha }}:1d
+          image-ref: ttl.sh/gogs/gogs-${{ steps.short-sha.outputs.sha }}:7d
+          exit-code: '1'
+
+  buildx-next-pull-request:
+    if: ${{ github.event_name == 'pull_request'}}
+    runs-on: ubuntu-latest
+    permissions:
+      contents: read
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+      - name: Set up Docker Buildx
+        id: buildx
+        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+        with:
+          config-inline: |
+            [worker.oci]
+              max-parallelism = 2
+      - name: Inspect builder
+        run: |
+          echo "Name:      ${{ steps.buildx.outputs.name }}"
+          echo "Endpoint:  ${{ steps.buildx.outputs.endpoint }}"
+          echo "Status:    ${{ steps.buildx.outputs.status }}"
+          echo "Flags:     ${{ steps.buildx.outputs.flags }}"
+          echo "Platforms: ${{ steps.buildx.outputs.platforms }}"
+      - name: Compute short commit SHA
+        id: short-sha
+        uses: benjlevesque/short-sha@599815c8ee942a9616c92bcfb4f947a3b670ab0b # v3.0
+      - name: Build and push next-gen images
+        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+        with:
+          context: .
+          file: Dockerfile.next
+          platforms: linux/amd64
+          push: true
+          tags: |
+            ttl.sh/gogs/gogs-next-${{ steps.short-sha.outputs.sha }}:7d
+      - name: Scan for container vulnerabilities
+        uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
+        with:
+          image-ref: ttl.sh/gogs/gogs-next-${{ steps.short-sha.outputs.sha }}:7d
           exit-code: '1'
 
   # Updates to the following section needs to be synced to all release branches within their lifecycles.
@@ -137,16 +288,14 @@ jobs:
       - name: Compute image tag name
         run: echo "IMAGE_TAG=$(echo $GITHUB_REF_NAME | cut -c 2-)" >> $GITHUB_ENV
       - name: Checkout code
-        uses: actions/checkout@v2
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
       - name: Set up QEMU
-        uses: docker/setup-qemu-action@v1
+        uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
+        with:
+          platforms: linux/amd64,linux/arm64,linux/arm/v7
       - name: Set up Docker Buildx
         id: buildx
-        uses: docker/setup-buildx-action@v1
-        with:
-          config-inline: |
-            [worker.oci]
-              max-parallelism = 2
+        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
       - name: Inspect builder
         run: |
           echo "Name:      ${{ steps.buildx.outputs.name }}"
@@ -155,18 +304,18 @@ jobs:
           echo "Flags:     ${{ steps.buildx.outputs.flags }}"
           echo "Platforms: ${{ steps.buildx.outputs.platforms }}"
       - name: Login to Docker Hub
-        uses: docker/login-action@v1
+        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
         with:
           username: ${{ secrets.DOCKERHUB_USERNAME }}
           password: ${{ secrets.DOCKERHUB_TOKEN }}
       - name: Login to GitHub Container registry
-        uses: docker/login-action@v1
+        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
         with:
           registry: ghcr.io
           username: ${{ github.repository_owner }}
           password: ${{ secrets.GITHUB_TOKEN }}
       - name: Build and push images
-        uses: docker/build-push-action@v2
+        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
         with:
           context: .
           platforms: linux/amd64,linux/arm64,linux/arm/v7
@@ -175,7 +324,72 @@ jobs:
             gogs/gogs:${{ env.IMAGE_TAG }}
             ghcr.io/gogs/gogs:${{ env.IMAGE_TAG }}
       - name: Send email on failure
-        uses: dawidd6/action-send-mail@v3
+        uses: dawidd6/action-send-mail@2cea9617b09d79a095af21254fbcb7ae95903dde # v3.12.0
+        if: ${{ failure() }}
+        with:
+          server_address: smtp.mailgun.org
+          server_port: 465
+          username: ${{ secrets.SMTP_USERNAME }}
+          password: ${{ secrets.SMTP_PASSWORD }}
+          subject: GitHub Actions (${{ github.repository }}) job result
+          to: github-actions-8ce6454@unknwon.io
+          from: GitHub Actions (${{ github.repository }})
+          reply_to: noreply@unknwon.io
+          body: |
+            The job "${{ github.job }}" of ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }} completed with "${{ job.status }}".
+
+            View the job run at: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+
+  # Updates to the following section needs to be synced to all release branches within their lifecycles.
+  buildx-next-release:
+    if: ${{ github.event_name == 'release' }}
+    runs-on: ubuntu-latest
+    permissions:
+      actions: write
+      contents: read
+      packages: write
+    steps:
+      - name: Compute image tag name
+        run: echo "IMAGE_TAG=$(echo $GITHUB_REF_NAME | cut -c 2-)" >> $GITHUB_ENV
+      - name: Checkout code
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+      - name: Set up QEMU
+        uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
+        with:
+          platforms: linux/amd64,linux/arm64,linux/arm/v7
+      - name: Set up Docker Buildx
+        id: buildx
+        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+      - name: Inspect builder
+        run: |
+          echo "Name:      ${{ steps.buildx.outputs.name }}"
+          echo "Endpoint:  ${{ steps.buildx.outputs.endpoint }}"
+          echo "Status:    ${{ steps.buildx.outputs.status }}"
+          echo "Flags:     ${{ steps.buildx.outputs.flags }}"
+          echo "Platforms: ${{ steps.buildx.outputs.platforms }}"
+      - name: Login to Docker Hub
+        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+        with:
+          username: ${{ secrets.DOCKERHUB_USERNAME }}
+          password: ${{ secrets.DOCKERHUB_TOKEN }}
+      - name: Login to GitHub Container registry
+        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+        with:
+          registry: ghcr.io
+          username: ${{ github.repository_owner }}
+          password: ${{ secrets.GITHUB_TOKEN }}
+      - name: Build and push next-gen images
+        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+        with:
+          context: .
+          file: Dockerfile.next
+          platforms: linux/amd64,linux/arm64,linux/arm/v7
+          push: true
+          tags: |
+            gogs/gogs:next-${{ env.IMAGE_TAG }}
+            ghcr.io/gogs/gogs:next-${{ env.IMAGE_TAG }}
+      - name: Send email on failure
+        uses: dawidd6/action-send-mail@2cea9617b09d79a095af21254fbcb7ae95903dde # v3.12.0
         if: ${{ failure() }}
         with:
           server_address: smtp.mailgun.org
@@ -190,3 +404,19 @@ jobs:
             The job "${{ github.job }}" of ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }} completed with "${{ job.status }}".
 
             View the job run at: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+
+  digitalocean-gc:
+    if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository == 'gogs/gogs' }}
+    needs: buildx-next
+    permissions:
+      contents: read
+    uses: ./.github/workflows/digitalocean_gc.yml
+    secrets: inherit
+
+  digitalocean-gc-pull-request:
+    if: ${{ github.event_name == 'pull_request' && github.repository == 'gogs/gogs' }}
+    needs: buildx-next-pull-request
+    permissions:
+      contents: read
+    uses: ./.github/workflows/digitalocean_gc.yml
+    secrets: inherit

+ 31 - 31
.github/workflows/go.yml

@@ -30,13 +30,13 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout code
-        uses: actions/checkout@v4
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
       - name: Install Go
-        uses: actions/setup-go@v5
+        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
         with:
-          go-version: 1.23.x
+          go-version: 1.25.x
       - name: Install Task
-        uses: arduino/setup-task@v2
+        uses: arduino/setup-task@b91d5d2c96a56797b48ac1e0e89220bf64044611 # v2.0.0
         with:
           repo-token: ${{ secrets.GITHUB_TOKEN }}
       - name: Check Go module tidiness and generated files
@@ -52,7 +52,7 @@ jobs:
             exit 1
           fi
       - name: Run golangci-lint
-        uses: golangci/golangci-lint-action@v4
+        uses: golangci/golangci-lint-action@9fae48acfc02a90574d7c304a1758ef9895495fa # v7.0.1
         with:
           version: latest
           args: --timeout=30m
@@ -61,25 +61,25 @@ jobs:
     name: Test
     strategy:
       matrix:
-        go-version: [ 1.23.x ]
+        go-version: [ 1.25.x ]
         platform: [ ubuntu-latest, macos-latest ]
     runs-on: ${{ matrix.platform }}
     steps:
+      - name: Checkout code
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
       - name: Install Go
-        uses: actions/setup-go@v2
+        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
         with:
           go-version: ${{ matrix.go-version }}
-      - name: Checkout code
-        uses: actions/checkout@v2
       - name: Run tests with coverage
         run: go test -shuffle=on -v -race -coverprofile=coverage -covermode=atomic ./...
       - name: Upload coverage report to Codecov
-        uses: codecov/codecov-action@v1.5.0
+        uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
         with:
           file: ./coverage
           flags: unittests
       - name: Send email on failure
-        uses: dawidd6/action-send-mail@v3
+        uses: dawidd6/action-send-mail@2cea9617b09d79a095af21254fbcb7ae95903dde # v3.12.0
         if: ${{ failure() && github.event_name == 'push' && github.ref == 'refs/heads/main' }}
         with:
           server_address: smtp.mailgun.org
@@ -98,28 +98,28 @@ jobs:
   # Running tests with race detection consumes too much memory on Windows,
   # see https://github.com/golang/go/issues/46099 for details.
   test-windows:
-    name: Test
+    name: Test Windows
     strategy:
       matrix:
-        go-version: [ 1.23.x ]
+        go-version: [ 1.25.x ]
         platform: [ windows-latest ]
     runs-on: ${{ matrix.platform }}
     steps:
+      - name: Checkout code
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
       - name: Install Go
-        uses: actions/setup-go@v2
+        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
         with:
           go-version: ${{ matrix.go-version }}
-      - name: Checkout code
-        uses: actions/checkout@v2
       - name: Run tests with coverage
         run: go test -shuffle=on -v -coverprofile=coverage -covermode=atomic ./...
       - name: Upload coverage report to Codecov
-        uses: codecov/codecov-action@v1.5.0
+        uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
         with:
           file: ./coverage
           flags: unittests
       - name: Send email on failure
-        uses: dawidd6/action-send-mail@v3
+        uses: dawidd6/action-send-mail@2cea9617b09d79a095af21254fbcb7ae95903dde # v3.12.0
         if: ${{ failure() && github.event_name == 'push' && github.ref == 'refs/heads/main' }}
         with:
           server_address: smtp.mailgun.org
@@ -139,7 +139,7 @@ jobs:
     name: Postgres
     strategy:
       matrix:
-        go-version: [ 1.23.x ]
+        go-version: [ 1.25.x ]
         platform: [ ubuntu-latest ]
     runs-on: ${{ matrix.platform }}
     services:
@@ -155,12 +155,12 @@ jobs:
         ports:
           - 5432:5432
     steps:
+      - name: Checkout code
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
       - name: Install Go
-        uses: actions/setup-go@v2
+        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
         with:
           go-version: ${{ matrix.go-version }}
-      - name: Checkout code
-        uses: actions/checkout@v2
       - name: Run tests with coverage
         run: go test -shuffle=on -v -race -coverprofile=coverage -covermode=atomic ./internal/db/...
         env:
@@ -175,18 +175,18 @@ jobs:
     name: MySQL
     strategy:
       matrix:
-        go-version: [ 1.23.x ]
-        platform: [ ubuntu-22.04 ]
+        go-version: [ 1.25.x ]
+        platform: [ ubuntu-22.04 ] # Use the lowest version possible for backwards compatibility
     runs-on: ${{ matrix.platform }}
     steps:
       - name: Start MySQL server
         run: sudo systemctl start mysql
+      - name: Checkout code
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
       - name: Install Go
-        uses: actions/setup-go@v2
+        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
         with:
           go-version: ${{ matrix.go-version }}
-      - name: Checkout code
-        uses: actions/checkout@v2
       - name: Run tests with coverage
         run: go test -shuffle=on -v -race -coverprofile=coverage -covermode=atomic ./internal/db/...
         env:
@@ -200,16 +200,16 @@ jobs:
     name: SQLite - Go
     strategy:
       matrix:
-        go-version: [ 1.23.x ]
+        go-version: [ 1.25.x ]
         platform: [ ubuntu-latest ]
     runs-on: ${{ matrix.platform }}
     steps:
+      - name: Checkout code
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
       - name: Install Go
-        uses: actions/setup-go@v2
+        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
         with:
           go-version: ${{ matrix.go-version }}
-      - name: Checkout code
-        uses: actions/checkout@v2
       - name: Run tests with coverage
         run: go test -shuffle=on -v -race -parallel=1 -coverprofile=coverage -covermode=atomic ./internal/db/...
         env:

+ 1 - 1
.github/workflows/lock.yml

@@ -16,7 +16,7 @@ jobs:
   action:
     runs-on: ubuntu-latest
     steps:
-      - uses: dessant/lock-threads@v3
+      - uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1
         with:
           github-token: ${{ github.token }}
           issue-inactive-days: '90'

+ 2 - 2
.github/workflows/shell.yml

@@ -12,6 +12,6 @@ jobs:
     name: Shellcheck
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
       - name: Run ShellCheck
-        uses: ludeeus/action-shellcheck@master
+        uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # 2.0.0

+ 36 - 23
.golangci.yml

@@ -1,29 +1,42 @@
-linters-settings:
-  staticcheck:
-    checks: [
-      "all",
-      "-SA1019" # There are valid use cases of strings.Title
-    ]
-  nakedret:
-    max-func-lines: 0 # Disallow any unnamed return statement
-  govet:
-    disable:
-      # printf: non-constant format string in call to fmt.Errorf (govet)
-      # showing up since golangci-lint version 1.60.1
-      - printf
-
+version: "2"
 linters:
   enable:
-    - unused
-    - errcheck
-    - gosimple
-    - govet
-    - ineffassign
-    - staticcheck
-    - typecheck
     - nakedret
-    - gofmt
     - rowserrcheck
     - unconvert
-    - goimports
     - unparam
+  settings:
+    govet:
+      disable:
+        # printf: non-constant format string in call to fmt.Errorf (govet)
+        # showing up since golangci-lint version 1.60.1
+        - printf
+    staticcheck:
+      checks:
+        - all
+        - "-SA1019" # This project is under active refactoring and not all code is up to date.
+        - "-QF1001" # I'm a math noob
+        - "-ST1016" # Some legit code uses this pattern
+    nakedret:
+      max-func-lines: 0 # Disallow any unnamed return statement
+  exclusions:
+    generated: lax
+    presets:
+      - comments
+      - common-false-positives
+      - legacy
+      - std-error-handling
+    paths:
+      - third_party$
+      - builtin$
+      - examples$
+formatters:
+  enable:
+    - gofmt
+    - goimports
+  exclusions:
+    generated: lax
+    paths:
+      - third_party$
+      - builtin$
+      - examples$

+ 2 - 2
gen.go

@@ -4,5 +4,5 @@
 
 package main
 
-//go:generate go install golang.org/x/tools/cmd/goimports@v0.17.0
-//go:generate go run github.com/derision-test/go-mockgen/v2/cmd/go-mockgen@v2.0.1
+//go:generate go install golang.org/x/tools/cmd/goimports@v0.33.0
+//go:generate go run github.com/unknwon/go-mockgen/cmd/go-mockgen@v0.0.0-20251002032800-a9a94b119e3b

+ 1 - 1
internal/db/mocks_test.go

@@ -1,4 +1,4 @@
-// Code generated by go-mockgen 1.3.7; DO NOT EDIT.
+// Code generated by go-mockgen 2.1.1; DO NOT EDIT.
 //
 // This file was generated by running `go-mockgen` at the root of this repository.
 // To add additional mocks to this or another package, add a new entry to the

+ 0 - 6
internal/db/ssh_key_test.go

@@ -21,12 +21,6 @@ func Test_SSHParsePublicKey(t *testing.T) {
 		expType   string
 		expLength int
 	}{
-		{
-			name:      "dsa-1024",
-			content:   "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment",
-			expType:   "dsa",
-			expLength: 1024,
-		},
 		{
 			name:      "rsa-1024",
 			content:   "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment",

+ 14 - 12
internal/db/two_factors_test.go

@@ -141,54 +141,56 @@ func twoFactorsIsEnabled(t *testing.T, db *twoFactors) {
 	assert.False(t, db.IsEnabled(ctx, 2))
 }
 
-func twoFactorsUseRecoveryCode(t *testing.T, ctx context.Context, s *TwoFactorsStore) {
+func twoFactorsUseRecoveryCode(t *testing.T, db *twoFactors) {
+	ctx := context.Background()
+
 	// Create 2FA tokens for two users
-	err := s.Create(ctx, 1, "secure-key", "secure-secret")
+	err := db.Create(ctx, 1, "secure-key", "secure-secret")
 	require.NoError(t, err)
-	err = s.Create(ctx, 2, "secure-key", "secure-secret")
+	err = db.Create(ctx, 2, "secure-key", "secure-secret")
 	require.NoError(t, err)
 
 	// Get recovery codes for both users
 	var user1Codes []TwoFactorRecoveryCode
-	err = s.db.Where("user_id = ?", 1).Find(&user1Codes).Error
+	err = db.DB.Where("user_id = ?", 1).Find(&user1Codes).Error
 	require.NoError(t, err)
 	require.NotEmpty(t, user1Codes)
 
 	var user2Codes []TwoFactorRecoveryCode
-	err = s.db.Where("user_id = ?", 2).Find(&user2Codes).Error
+	err = db.DB.Where("user_id = ?", 2).Find(&user2Codes).Error
 	require.NoError(t, err)
 	require.NotEmpty(t, user2Codes)
 
 	// User 1 should be able to use their own recovery code
-	err = s.UseRecoveryCode(ctx, 1, user1Codes[0].Code)
+	err = db.UseRecoveryCode(ctx, 1, user1Codes[0].Code)
 	require.NoError(t, err)
 
 	// Verify the code is now marked as used
 	var usedCode TwoFactorRecoveryCode
-	err = s.db.Where("id = ?", user1Codes[0].ID).First(&usedCode).Error
+	err = db.DB.Where("id = ?", user1Codes[0].ID).First(&usedCode).Error
 	require.NoError(t, err)
 	assert.True(t, usedCode.IsUsed)
 
 	// User 1 should NOT be able to use user 2's recovery code
 	// This is the key security test - recovery codes must be scoped by user
-	err = s.UseRecoveryCode(ctx, 1, user2Codes[0].Code)
+	err = db.UseRecoveryCode(ctx, 1, user2Codes[0].Code)
 	assert.True(t, IsTwoFactorRecoveryCodeNotFound(err), "expected recovery code not found error when using another user's code")
 
 	// User 2's code should still be unused
 	var user2Code TwoFactorRecoveryCode
-	err = s.db.Where("id = ?", user2Codes[0].ID).First(&user2Code).Error
+	err = db.DB.Where("id = ?", user2Codes[0].ID).First(&user2Code).Error
 	require.NoError(t, err)
 	assert.False(t, user2Code.IsUsed, "user 2's recovery code should not be marked as used")
 
 	// User 2 should be able to use their own code
-	err = s.UseRecoveryCode(ctx, 2, user2Codes[0].Code)
+	err = db.UseRecoveryCode(ctx, 2, user2Codes[0].Code)
 	require.NoError(t, err)
 
 	// Using an already-used code should fail
-	err = s.UseRecoveryCode(ctx, 1, user1Codes[0].Code)
+	err = db.UseRecoveryCode(ctx, 1, user1Codes[0].Code)
 	assert.True(t, IsTwoFactorRecoveryCodeNotFound(err), "expected error when reusing a recovery code")
 
 	// Using a non-existent code should fail
-	err = s.UseRecoveryCode(ctx, 1, "invalid-code")
+	err = db.UseRecoveryCode(ctx, 1, "invalid-code")
 	assert.True(t, IsTwoFactorRecoveryCodeNotFound(err), "expected error for invalid recovery code")
 }

+ 127 - 1
internal/route/lfs/mocks_test.go

@@ -1,4 +1,4 @@
-// Code generated by go-mockgen 1.3.7; DO NOT EDIT.
+// Code generated by go-mockgen 2.1.1; DO NOT EDIT.
 //
 // This file was generated by running `go-mockgen` at the root of this repository.
 // To add additional mocks to this or another package, add a new entry to the
@@ -2780,6 +2780,9 @@ type MockTwoFactorsStore struct {
 	// IsEnabledFunc is an instance of a mock function object controlling
 	// the behavior of the method IsEnabled.
 	IsEnabledFunc *TwoFactorsStoreIsEnabledFunc
+	// UseRecoveryCodeFunc is an instance of a mock function object
+	// controlling the behavior of the method UseRecoveryCode.
+	UseRecoveryCodeFunc *TwoFactorsStoreUseRecoveryCodeFunc
 }
 
 // NewMockTwoFactorsStore creates a new mock of the TwoFactorsStore
@@ -2802,6 +2805,11 @@ func NewMockTwoFactorsStore() *MockTwoFactorsStore {
 				return
 			},
 		},
+		UseRecoveryCodeFunc: &TwoFactorsStoreUseRecoveryCodeFunc{
+			defaultHook: func(context.Context, int64, string) (r0 error) {
+				return
+			},
+		},
 	}
 }
 
@@ -2824,6 +2832,11 @@ func NewStrictMockTwoFactorsStore() *MockTwoFactorsStore {
 				panic("unexpected invocation of MockTwoFactorsStore.IsEnabled")
 			},
 		},
+		UseRecoveryCodeFunc: &TwoFactorsStoreUseRecoveryCodeFunc{
+			defaultHook: func(context.Context, int64, string) error {
+				panic("unexpected invocation of MockTwoFactorsStore.UseRecoveryCode")
+			},
+		},
 	}
 }
 
@@ -2841,6 +2854,9 @@ func NewMockTwoFactorsStoreFrom(i db.TwoFactorsStore) *MockTwoFactorsStore {
 		IsEnabledFunc: &TwoFactorsStoreIsEnabledFunc{
 			defaultHook: i.IsEnabled,
 		},
+		UseRecoveryCodeFunc: &TwoFactorsStoreUseRecoveryCodeFunc{
+			defaultHook: i.UseRecoveryCode,
+		},
 	}
 }
 
@@ -3168,6 +3184,116 @@ func (c TwoFactorsStoreIsEnabledFuncCall) Results() []interface{} {
 	return []interface{}{c.Result0}
 }
 
+// TwoFactorsStoreUseRecoveryCodeFunc describes the behavior when the
+// UseRecoveryCode method of the parent MockTwoFactorsStore instance is
+// invoked.
+type TwoFactorsStoreUseRecoveryCodeFunc struct {
+	defaultHook func(context.Context, int64, string) error
+	hooks       []func(context.Context, int64, string) error
+	history     []TwoFactorsStoreUseRecoveryCodeFuncCall
+	mutex       sync.Mutex
+}
+
+// UseRecoveryCode delegates to the next hook function in the queue and
+// stores the parameter and result values of this invocation.
+func (m *MockTwoFactorsStore) UseRecoveryCode(v0 context.Context, v1 int64, v2 string) error {
+	r0 := m.UseRecoveryCodeFunc.nextHook()(v0, v1, v2)
+	m.UseRecoveryCodeFunc.appendCall(TwoFactorsStoreUseRecoveryCodeFuncCall{v0, v1, v2, r0})
+	return r0
+}
+
+// SetDefaultHook sets function that is called when the UseRecoveryCode
+// method of the parent MockTwoFactorsStore instance is invoked and the hook
+// queue is empty.
+func (f *TwoFactorsStoreUseRecoveryCodeFunc) SetDefaultHook(hook func(context.Context, int64, string) error) {
+	f.defaultHook = hook
+}
+
+// PushHook adds a function to the end of hook queue. Each invocation of the
+// UseRecoveryCode method of the parent MockTwoFactorsStore instance invokes
+// the hook at the front of the queue and discards it. After the queue is
+// empty, the default hook function is invoked for any future action.
+func (f *TwoFactorsStoreUseRecoveryCodeFunc) PushHook(hook func(context.Context, int64, string) error) {
+	f.mutex.Lock()
+	f.hooks = append(f.hooks, hook)
+	f.mutex.Unlock()
+}
+
+// SetDefaultReturn calls SetDefaultHook with a function that returns the
+// given values.
+func (f *TwoFactorsStoreUseRecoveryCodeFunc) SetDefaultReturn(r0 error) {
+	f.SetDefaultHook(func(context.Context, int64, string) error {
+		return r0
+	})
+}
+
+// PushReturn calls PushHook with a function that returns the given values.
+func (f *TwoFactorsStoreUseRecoveryCodeFunc) PushReturn(r0 error) {
+	f.PushHook(func(context.Context, int64, string) error {
+		return r0
+	})
+}
+
+func (f *TwoFactorsStoreUseRecoveryCodeFunc) nextHook() func(context.Context, int64, string) error {
+	f.mutex.Lock()
+	defer f.mutex.Unlock()
+
+	if len(f.hooks) == 0 {
+		return f.defaultHook
+	}
+
+	hook := f.hooks[0]
+	f.hooks = f.hooks[1:]
+	return hook
+}
+
+func (f *TwoFactorsStoreUseRecoveryCodeFunc) appendCall(r0 TwoFactorsStoreUseRecoveryCodeFuncCall) {
+	f.mutex.Lock()
+	f.history = append(f.history, r0)
+	f.mutex.Unlock()
+}
+
+// History returns a sequence of TwoFactorsStoreUseRecoveryCodeFuncCall
+// objects describing the invocations of this function.
+func (f *TwoFactorsStoreUseRecoveryCodeFunc) History() []TwoFactorsStoreUseRecoveryCodeFuncCall {
+	f.mutex.Lock()
+	history := make([]TwoFactorsStoreUseRecoveryCodeFuncCall, len(f.history))
+	copy(history, f.history)
+	f.mutex.Unlock()
+
+	return history
+}
+
+// TwoFactorsStoreUseRecoveryCodeFuncCall is an object that describes an
+// invocation of method UseRecoveryCode on an instance of
+// MockTwoFactorsStore.
+type TwoFactorsStoreUseRecoveryCodeFuncCall struct {
+	// Arg0 is the value of the 1st argument passed to this method
+	// invocation.
+	Arg0 context.Context
+	// Arg1 is the value of the 2nd argument passed to this method
+	// invocation.
+	Arg1 int64
+	// Arg2 is the value of the 3rd argument passed to this method
+	// invocation.
+	Arg2 string
+	// Result0 is the value of the 1st result returned from this method
+	// invocation.
+	Result0 error
+}
+
+// Args returns an interface slice containing the arguments of this
+// invocation.
+func (c TwoFactorsStoreUseRecoveryCodeFuncCall) Args() []interface{} {
+	return []interface{}{c.Arg0, c.Arg1, c.Arg2}
+}
+
+// Results returns an interface slice containing the results of this
+// invocation.
+func (c TwoFactorsStoreUseRecoveryCodeFuncCall) Results() []interface{} {
+	return []interface{}{c.Result0}
+}
+
 // MockUsersStore is a mock implementation of the UsersStore interface (from
 // the package gogs.io/gogs/internal/db) used for unit testing.
 type MockUsersStore struct {