diff --git a/.forgejo/actions/build-release/action.yml b/.forgejo/actions/build-release/action.yml
deleted file mode 100644
index 01fdfdedfc..0000000000
--- a/.forgejo/actions/build-release/action.yml
+++ /dev/null
@@ -1,154 +0,0 @@
-name: 'Build release'
-author: 'Forgejo authors'
-description: |
-  Build release
-
-inputs:
-  forgejo:
-    description: 'URL of the Forgejo instance where the release is uploaded'
-    required: true
-  owner:
-    description: 'User or organization where the release is uploaded, relative to the Forgejo instance'
-    required: true
-  repository:
-    description: 'Repository where the release is uploaded, relative to the owner'
-    required: true
-  doer:
-    description: 'Name of the user authoring the release'
-    required: true
-  tag-version:
-    description: 'Version of the release derived from the tag withint the leading v'
-    required: true
-  suffix:
-    description: 'Suffix to add to the image tag'
-  token:
-    description: 'token'
-    required: true
-  dockerfile:
-    description: 'path to the dockerfile'
-    default: 'Dockerfile'
-  platforms:
-    description: 'Coma separated list of platforms'
-    default: 'linux/amd64,linux/arm64'
-  release-notes:
-    description: 'Full text of the release notes'
-    default: 'Release notes placeholder'
-  binary-name:
-    description: 'Name of the binary'
-  binary-path:
-    description: 'Path of the binary within the container to extract into binary-name'
-  verbose:
-    description: 'Increase the verbosity level'
-    default: 'false'
-
-runs:
-  using: "composite"
-  steps:
-    - run: echo "${{ github.action_path }}" >> $GITHUB_PATH
-      shell: bash
-
-    - name: Install dependencies
-      run: |
-        apt-get install -y -qq xz-utils
-
-    - name: set -x if verbose is required
-      id: verbose
-      run: |
-        if ${{ inputs.verbose }} ; then
-          echo "shell=set -x" >> "$GITHUB_OUTPUT"
-        fi
-
-    - name: Create the insecure and buildx-config variables for the container registry
-      id: registry
-      run: |
-        ${{ steps.verbose.outputs.shell }}
-        url="${{ inputs.forgejo }}"
-        hostport=${url##http*://}
-        hostport=${hostport%%/}
-        echo "host-port=${hostport}" >> "$GITHUB_OUTPUT"
-        if ! [[ $url =~ ^http:// ]] ; then
-           exit 0
-        fi
-        cat >> "$GITHUB_OUTPUT" <<EOF
-        insecure=true
-        buildx-config<<ENDVAR
-        [registry."${hostport}"]
-          http = true
-        ENDVAR
-        EOF
-
-    - name: Allow docker pull/push to forgejo
-      if: ${{ steps.registry.outputs.insecure }}
-      run: |-
-        mkdir -p /etc/docker
-        cat > /etc/docker/daemon.json <<EOF
-          {
-            "insecure-registries" : ["${{ steps.registry.outputs.host-port }}"],
-            "bip": "172.26.0.1/16"
-          }
-        EOF
-
-    - name: Install docker
-      run: |
-        echo deb http://deb.debian.org/debian bullseye-backports main | tee /etc/apt/sources.list.d/backports.list && apt-get -qq update
-        DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -qq -y -t bullseye-backports docker.io
-
-    - uses: https://github.com/docker/setup-buildx-action@v2
-      with:
-        config-inline: |
-         ${{ steps.registry.outputs.buildx-config }}
-
-    - name: Login to the container registry
-      run: |
-        BASE64_AUTH=`echo -n "${{ inputs.doer }}:${{ inputs.token }}" | base64 -w0`
-        mkdir -p ~/.docker
-        echo "{\"auths\": {\"$CI_REGISTRY\": {\"auth\": \"$BASE64_AUTH\"}}}" > ~/.docker/config.json
-      env:
-        CI_REGISTRY: "${{ steps.registry.outputs.host-port }}"
-
-    - name: Build the container image for each architecture
-      uses: https://github.com/docker/build-push-action@v4
-      # workaround until https://github.com/docker/build-push-action/commit/d8823bfaed2a82c6f5d4799a2f8e86173c461aba is in @v4 or @v5 is released
-      env:
-        ACTIONS_RUNTIME_TOKEN: ''
-      with:
-        context: .
-        push: true
-        file: ${{ inputs.dockerfile }}
-        platforms: ${{ inputs.platforms }}
-        tags: ${{ steps.registry.outputs.host-port }}/${{ inputs.owner }}/${{ inputs.repository }}:${{ inputs.tag-version }}${{ inputs.suffix }}
-
-    - name: Extract the binary from the container images into the release directory
-      if: inputs.binary-name != ''
-      run: |
-        ${{ steps.verbose.outputs.shell }}
-        mkdir -p release
-        cd release
-        for platform in $(echo ${{ inputs.platforms }} | tr ',' ' '); do
-          arch=$(echo $platform | sed -e 's|linux/||g' -e 's|arm/v6|arm-6|g')
-          docker create --platform $platform --name forgejo-$arch ${{ steps.registry.outputs.host-port }}/${{ inputs.owner }}/${{ inputs.repository }}:${{ inputs.tag-version }}${{ inputs.suffix }}
-          binary="${{ inputs.binary-name }}-${{ inputs.tag-version }}-linux"
-          docker cp forgejo-$arch:${{ inputs.binary-path }} $binary-$arch
-          chmod +x $binary-$arch
-          # the displayed version has a + instead of the first -, deal with it
-          pattern=$(echo "${{ inputs.tag-version }}" | tr - .)
-          if ! ./$binary-$arch --version | grep "$pattern" ; then
-            echo "ERROR: expected version pattern $pattern not found in the output of $binary-$arch --version"
-            ./$binary-$arch --version
-            exit 1
-          fi
-          xz --keep -9 $binary-$arch
-          shasum -a 256 $binary-$arch > $binary-$arch.sha256
-          shasum -a 256 $binary-$arch.xz > $binary-$arch.xz.sha256
-          docker rm forgejo-$arch
-        done
-
-    - name: publish release
-      if: inputs.binary-name != ''
-      uses: https://code.forgejo.org/actions/forgejo-release@v1
-      with:
-        direction: upload
-        release-dir: release
-        release-notes: "${{ inputs.release-notes }}"
-        token: ${{ inputs.token }}
-        verbose: ${{ steps.verbose.outputs.value }}
diff --git a/.forgejo/actions/publish-release/action.yml b/.forgejo/actions/publish-release/action.yml
deleted file mode 100644
index 42b6097ee0..0000000000
--- a/.forgejo/actions/publish-release/action.yml
+++ /dev/null
@@ -1,110 +0,0 @@
-name: 'Publish release'
-author: 'Forgejo authors'
-description: |
-  Publish release
-
-inputs:
-  forgejo:
-    description: 'URL of the Forgejo instance where the release is uploaded (e.g. https://codeberg.org)'
-    required: true
-  from-owner:
-    description: 'the owner from which a release is to be copied (e.g forgejo-integration)'
-    required: true
-  to-owner:
-    description: 'the owner to which a release is to be copied (e.g. forgejo-experimental). It has be an organization in which doer has the required permissions. Or be the same as the doer'
-    required: true
-  repo:
-    description: 'the repository from which a release is to be copied relative to from-owner and to-owner'
-    default: 'forgejo'
-  ref-name:
-    description: 'ref_name of the tag of the release to be copied (e.g. github.ref_name)'
-    required: true
-  doer:
-    description: 'Name of the user authoring the release (e.g. release-team). The user must be authorized to create packages in to-owner and releases in to-owner/repo'
-    required: true
-  token:
-    description: 'application token created on forgejo by the doer, with a scope allowing it to create packages in to-owner and releases in to-owner/repo'
-    required: true
-  gpg-private-key:
-    description: 'GPG Private Key to sign the release artifacts'
-  gpg-passphrase:
-    description: 'Passphrase of the GPG Private Key'
-  verbose:
-    description: 'Increase the verbosity level'
-    default: 'false'
-
-runs:
-  using: "composite"
-  steps:
-    - id: hostport
-      run: |
-         url="${{ inputs.forgejo }}"
-         hostport=${url##http*://}
-         hostport=${hostport%%/}
-         echo "value=$hostport" >> "$GITHUB_OUTPUT"    
-
-    - id: tag-version
-      run: |
-        version="${{ inputs.ref-name }}"
-        version=${version##*v}
-        echo "value=$version" >> "$GITHUB_OUTPUT"
-
-    - name: Create the release notes
-      id: release-notes
-      run: |
-          anchor=${{ steps.tag-version.outputs.value }}
-          anchor=${anchor//./-}
-          cat >> "$GITHUB_OUTPUT" <<EOF
-          value<<ENDVAR
-          See https://codeberg.org/forgejo/forgejo/src/branch/forgejo/RELEASE-NOTES.md#$anchor
-          ENDVAR
-          EOF
-
-    - name: apt-get install docker.io
-      run: |
-        DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -qq -y docker.io
-
-    - name: download release
-      uses: https://code.forgejo.org/actions/forgejo-release@v1
-      with:
-        url: ${{ inputs.forgejo }}
-        repo: ${{ inputs.from-owner }}/${{ inputs.repo }}
-        direction: download
-        release-dir: release
-        download-retry: 60
-        token: ${{ inputs.token }}
-        verbose: ${{ inputs.verbose }}
-
-    - name: upload release
-      uses: https://code.forgejo.org/actions/forgejo-release@v1
-      with:
-        url: ${{ inputs.forgejo }}
-        repo: ${{ inputs.to-owner }}/${{ inputs.repo }}
-        direction: upload
-        release-dir: release
-        release-notes: ${{ steps.release-notes.outputs.value }}
-        token: ${{ inputs.token }}
-        gpg-private-key: ${{ inputs.gpg-private-key }}
-        gpg-passphrase: ${{ inputs.gpg-passphrase }}
-        verbose: ${{ inputs.verbose }}
-
-    - name: login to the registry
-      uses: https://github.com/docker/login-action@v2
-      with:
-          registry: ${{ steps.hostport.outputs.value }}
-          username: ${{ inputs.doer }}
-          password: ${{ inputs.token }}
-
-    - uses: https://code.forgejo.org/forgejo/forgejo-container-image@v1
-      env:
-        VERIFY: 'false'
-      with:
-        url: https://${{ steps.hostport.outputs.value }}
-        destination-owner: ${{ inputs.to-owner }}
-        owner: ${{ inputs.from-owner }}
-        suffixes: '-rootless'
-        project: ${{ inputs.repo }}
-        tag: ${{ steps.tag-version.outputs.value }}
-        doer: ${{ inputs.doer }}
-        token: ${{ inputs.token }}
-        verbose: ${{ inputs.verbose }}
diff --git a/.forgejo/workflows/build-release-integration.yml b/.forgejo/workflows/build-release-integration.yml
index 1935b86716..89155e9d59 100644
--- a/.forgejo/workflows/build-release-integration.yml
+++ b/.forgejo/workflows/build-release-integration.yml
@@ -7,14 +7,13 @@ on:
       - Dockerfile
       - Dockerfile.rootless
       - docker/**
-      - .forgejo/actions/build-release/action.yml
       - .forgejo/workflows/build-release.yml
       - .forgejo/workflows/build-release-integration.yml
 
 jobs:
   release-simulation:
+    if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
     runs-on: self-hosted
-    if: secrets.ROLE != 'forgejo-integration' && secrets.ROLE != 'forgejo-experimental' && secrets.ROLE != 'forgejo-release'
     steps:
       - uses: actions/checkout@v3
 
@@ -23,7 +22,7 @@ jobs:
         with:
           user: root
           password: admin1234
-          image-version: 1.19
+          image-version: 1.21
           lxc-ip-prefix: 10.0.9
 
       - name: publish the forgejo release
@@ -52,7 +51,6 @@ jobs:
           cp -a .forgejo/testdata/build-release/* $dir
           mkdir -p $dir/.forgejo/workflows
           cp .forgejo/workflows/build-release.yml $dir/.forgejo/workflows
-          cp -a .forgejo/actions $dir/.forgejo/actions
           cp $dir/Dockerfile $dir/Dockerfile.rootless
 
           forgejo-test-helper.sh push $dir $url root forgejo
@@ -62,6 +60,8 @@ jobs:
           # Push a tag to trigger the release workflow and wait for it to complete
           #
           forgejo-curl.sh api_json --data-raw '{"tag_name": "v'$version'", "target": "'$sha'"}' $url/api/v1/repos/root/forgejo/tags
+          forgejo-curl.sh api_json -X PUT --data-raw '{"data":"${{ steps.forgejo.outputs.token }}"}' $url/api/v1/repos/root/forgejo/actions/secrets/TOKEN
+          forgejo-curl.sh api_json -X PUT --data-raw '{"data":"root"}' $url/api/v1/repos/root/forgejo/actions/secrets/DOER
           LOOPS=180 forgejo-test-helper.sh wait_success "$url" root/forgejo $sha
 
           #
diff --git a/.forgejo/workflows/build-release.yml b/.forgejo/workflows/build-release.yml
index e080504261..4a196e1208 100644
--- a/.forgejo/workflows/build-release.yml
+++ b/.forgejo/workflows/build-release.yml
@@ -8,63 +8,40 @@ jobs:
   release:
     runs-on: self-hosted
     # root is used for testing, allow it
-    if: secrets.ROLE == 'forgejo-integration' || github.repository_owner == 'root'
+    if: vars.ROLE == 'forgejo-integration' || github.repository_owner == 'root'
     steps:
       - uses: actions/checkout@v3
 
-      - name: Increase the verbosity when there are no secrets
-        id: verbose
-        run: |
-          if test -z "${{ secrets.TOKEN }}"; then
-            value=true
-          else
-            value=false
-          fi
-          echo "value=$value" >> "$GITHUB_OUTPUT"
-
       - name: Sanitize the name of the repository
         id: repository
         run: |
-          set -x # comment out
           repository="${{ github.repository }}"
           echo "value=${repository##*/}" >> "$GITHUB_OUTPUT"
 
-      - name: When in a test environment, create a token
-        id: token
-        if: ${{ secrets.TOKEN == '' }}
-        run: |
-          apt-get -qq install -y jq
-          url="${{ env.GITHUB_SERVER_URL }}"
-          hostport=${url##http*://}
-          hostport=${hostport%%/}
-          doer=root
-          api=http://$doer:admin1234@$hostport/api/v1/users/$doer/tokens
-          curl -sS -X DELETE $api/release
-          token=$(curl -sS -X POST -H 'Content-Type: application/json' --data-raw '{"name": "release", "scopes": ["all"]}' $api | jq --raw-output .sha1)
-          echo "value=${token}" >> "$GITHUB_OUTPUT"
-
       - uses: https://code.forgejo.org/actions/setup-node@v3
         with:
-          node-version: 18
+          node-version: 20
 
       - uses: https://code.forgejo.org/actions/setup-go@v4
         with:
-          go-version: ">=1.20"
+          go-version: ">=1.21"
           check-latest: true
 
-      - name: Create the version from ref_name
+      - name: version from ref_name
         id: tag-version
         run: |
           version="${{ github.ref_name }}"
           version=${version##*v}
           echo "value=$version" >> "$GITHUB_OUTPUT"
 
-      - name: Create the release notes
+      - name: release notes
         id: release-notes
         run: |
+          anchor=${{ steps.tag-version.outputs.value }}
+          anchor=${anchor//./-}
           cat >> "$GITHUB_OUTPUT" <<EOF
           value<<ENDVAR
-          See https://codeberg.org/forgejo/forgejo/src/branch/forgejo/RELEASE-NOTES.md#${{ steps.tag-version.outputs.value }}
+          See https://codeberg.org/forgejo/forgejo/src/branch/forgejo/RELEASE-NOTES.md#$anchor
           ENDVAR
           EOF
 
@@ -127,40 +104,9 @@ jobs:
             fi
           )
 
-      - name: build container & release (when TOKEN secret is not set)
-        if: ${{ secrets.TOKEN == '' }}
-        uses: ./.forgejo/actions/build-release
-        with:
-          forgejo: "${{ env.GITHUB_SERVER_URL }}"
-          owner: "${{ env.GITHUB_REPOSITORY_OWNER }}"
-          repository: "${{ steps.repository.outputs.value }}"
-          doer: root
-          tag-version: "${{ steps.tag-version.outputs.value }}"
-          token: ${{ steps.token.outputs.value }}
-          platforms: linux/amd64,linux/arm64,linux/arm/v6
-          release-notes: "${{ steps.release-notes.outputs.value }}"
-          binary-name: forgejo
-          binary-path: /app/gitea/gitea
-          verbose: ${{ steps.verbose.outputs.value }}
-
-      - name: build rootless container (when TOKEN secret is not set)
-        if: ${{ secrets.TOKEN == '' }}
-        uses: ./.forgejo/actions/build-release
-        with:
-          forgejo: "${{ env.GITHUB_SERVER_URL }}"
-          owner: "${{ env.GITHUB_REPOSITORY_OWNER }}"
-          repository: "${{ steps.repository.outputs.value }}"
-          doer: root
-          tag-version: "${{ steps.tag-version.outputs.value }}"
-          token: ${{ steps.token.outputs.value }}
-          platforms: linux/amd64,linux/arm64,linux/arm/v6
-          suffix: -rootless
-          dockerfile: Dockerfile.rootless
-          verbose: ${{ steps.verbose.outputs.value }}
-
-      - name: build container & release (when TOKEN secret is set)
+      - name: build container & release
         if: ${{ secrets.TOKEN != '' }}
-        uses: ./.forgejo/actions/build-release
+        uses: https://code.forgejo.org/forgejo/forgejo-build-publish/build@v1
         with:
           forgejo: "${{ env.GITHUB_SERVER_URL }}"
           owner: "${{ env.GITHUB_REPOSITORY_OWNER }}"
@@ -172,11 +118,11 @@ jobs:
           release-notes: "${{ steps.release-notes.outputs.value }}"
           binary-name: forgejo
           binary-path: /app/gitea/gitea
-          verbose: ${{ steps.verbose.outputs.value }}
+          verbose: ${{ vars.VERBOSE || 'false' }}
 
-      - name: build rootless container (when TOKEN secret is set)
+      - name: build rootless container
         if: ${{ secrets.TOKEN != '' }}
-        uses: ./.forgejo/actions/build-release
+        uses: https://code.forgejo.org/forgejo/forgejo-build-publish/build@v1
         with:
           forgejo: "${{ env.GITHUB_SERVER_URL }}"
           owner: "${{ env.GITHUB_REPOSITORY_OWNER }}"
@@ -187,4 +133,4 @@ jobs:
           platforms: linux/amd64,linux/arm64,linux/arm/v6
           suffix: -rootless
           dockerfile: Dockerfile.rootless
-          verbose: ${{ steps.verbose.outputs.value }}
+          verbose: ${{ vars.VERBOSE || 'false' }}
diff --git a/.forgejo/workflows/cascade-setup-end-to-end.yml b/.forgejo/workflows/cascade-setup-end-to-end.yml
index 8f0c736d38..be07d87767 100644
--- a/.forgejo/workflows/cascade-setup-end-to-end.yml
+++ b/.forgejo/workflows/cascade-setup-end-to-end.yml
@@ -9,6 +9,7 @@ env:
 
 jobs:
   info:
+    if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
     runs-on: docker
     container:
       image: node:20-bookworm
@@ -24,7 +25,7 @@ jobs:
           EOF
 
   build:
-    if: github.event.action == 'label_updated' && contains(github.event.pull_request.labels.*.name, 'run-end-to-end-tests')
+    if: ${{ !startsWith(vars.ROLE, 'forgejo-') && github.event.action == 'label_updated' && contains(github.event.pull_request.labels.*.name, 'run-end-to-end-tests') }}
     runs-on: docker
     container:
       image: 'docker.io/node:20-bookworm'
@@ -60,7 +61,7 @@ jobs:
           path: forgejo
 
   cascade:
-    if: github.event.action == 'label_updated' && contains(github.event.pull_request.labels.*.name, 'run-end-to-end-tests')
+    if: ${{ !startsWith(vars.ROLE, 'forgejo-') && github.event.action == 'label_updated' && contains(github.event.pull_request.labels.*.name, 'run-end-to-end-tests') }}
     needs: [build]
     runs-on: docker
     container:
diff --git a/.forgejo/workflows/publish-release.yml b/.forgejo/workflows/publish-release.yml
index d824815b5e..536ac23837 100644
--- a/.forgejo/workflows/publish-release.yml
+++ b/.forgejo/workflows/publish-release.yml
@@ -6,25 +6,27 @@
 #
 #  Copies a release from codeberg.org/forgejo-integration to codeberg.org/forgejo-experimental
 #
-#  ROLE: forgejo-experimental
-#  FORGEJO: https://codeberg.org
-#  FROM_OWNER: forgejo-integration
-#  TO_OWNER: forgejo-experimental
-#  DOER: forgejo-experimental-ci
-#  TOKEN: <generated from codeberg.org/forgejo-experimental-ci>
+#  vars.ROLE: forgejo-experimental
+#  vars.FORGEJO: https://codeberg.org
+#  vars.FROM_OWNER: forgejo-integration
+#  vars.TO_OWNER: forgejo-experimental
+#  vars.REPO: forgejo
+#  vars.DOER: forgejo-experimental-ci
+#  secrets.TOKEN: <generated from codeberg.org/forgejo-experimental-ci>
 #
-# https://forgejo.octopuce.forgejo.org/forgejo/forgejo
+# http://private.forgejo.org/forgejo/forgejo
 #
 #  Copies & sign a release from codeberg.org/forgejo-integration to codeberg.org/forgejo
 #
-#  ROLE: forgejo-release
-#  FORGEJO: https://codeberg.org
-#  FROM_OWNER: forgejo-integration
-#  TO_OWNER: forgejo
-#  DOER: release-team
-#  TOKEN: <generated from codeberg.org/release-team>
-#  GPG_PRIVATE_KEY: <XYZ>
-#  GPG_PASSPHRASE: <ABC>
+#  vars.ROLE: forgejo-release
+#  vars.FORGEJO: https://codeberg.org
+#  vars.FROM_OWNER: forgejo-integration
+#  vars.TO_OWNER: forgejo
+#  vars.REPO: forgejo
+#  vars.DOER: release-team
+#  secrets.TOKEN: <generated from codeberg.org/release-team>
+#  secrets.GPG_PRIVATE_KEY: <XYZ>
+#  secrets.GPG_PASSPHRASE: <ABC>
 #
 name: Pubish release
 
@@ -35,39 +37,34 @@ on:
 jobs:
   publish:
     runs-on: self-hosted
-    if: secrets.DOER != '' && secrets.FORGEJO != '' && secrets.TO_OWNER != '' && secrets.FROM_OWNER != '' && secrets.TOKEN != ''
+    if: vars.DOER != '' && vars.FORGEJO != '' && vars.TO_OWNER != '' && vars.FROM_OWNER != '' && secrets.TOKEN != ''
     steps:
-      - name: install the certificate authority
-        if: secrets.ROLE == 'forgejo-release'
-        run: |
-          apt-get install -qq -y wget
-          wget --no-check-certificate -O /usr/local/share/ca-certificates/enough.crt https://forgejo.octopuce.forgejo.org/forgejo/enough/raw/branch/main/certs/2023-05-13/ca.crt
-          update-ca-certificates --fresh
-
       - uses: actions/checkout@v3
 
-      - name: copy & sign binaries and container images from one owner to another
-        uses: ./.forgejo/actions/publish-release
+      - name: copy & sign
+        uses: https://code.forgejo.org/forgejo/forgejo-build-publish/publish@v1
         with:
-          forgejo: ${{ secrets.FORGEJO }}
-          from-owner: ${{ secrets.FROM_OWNER }}
-          to-owner: ${{ secrets.TO_OWNER }}
+          forgejo: ${{ vars.FORGEJO }}
+          from-owner: ${{ vars.FROM_OWNER }}
+          to-owner: ${{ vars.TO_OWNER }}
+          repo: ${{ vars.REPO }}
           ref-name: ${{ github.ref_name }}
-          doer: ${{ secrets.DOER }}
+          release-notes: "See https://codeberg.org/forgejo/forgejo/src/branch/forgejo/RELEASE-NOTES.md#{ANCHOR}"
+          doer: ${{ vars.DOER }}
           token: ${{ secrets.TOKEN }}
           gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
           gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }}
-          verbose: ${{ secrets.VERBOSE }}
+          verbose: ${{ vars.VERBOSE }}
 
 
       - name: set up go for the DNS update below
+        if: vars.ROLE == 'forgejo-experimental' && secrets.OVH_APP_KEY != ''
         uses: https://code.forgejo.org/actions/setup-go@v4
-        if: secrets.ROLE == 'forgejo-experimental'
         with:
           go-version: ">=1.21"
           check-latest: true
       - name: update the _release.experimental DNS record
-        if: secrets.ROLE == 'forgejo-experimental'
+        if: vars.ROLE == 'forgejo-experimental' && secrets.OVH_APP_KEY != ''
         uses: https://code.forgejo.org/actions/ovh-dns-update@v1
         with:
           subdomain: _release.experimental
diff --git a/.forgejo/workflows/testing.yml b/.forgejo/workflows/testing.yml
index 353549c9a4..f8fcac3c1c 100644
--- a/.forgejo/workflows/testing.yml
+++ b/.forgejo/workflows/testing.yml
@@ -9,6 +9,7 @@ on:
 
 jobs:
   lint-backend:
+    if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
     runs-on: docker
     container:
       image: 'docker.io/node:20-bookworm'
@@ -23,6 +24,7 @@ jobs:
         env:
           TAGS: bindata sqlite sqlite_unlock_notify
   checks-backend:
+    if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
     runs-on: docker
     container:
       image: 'docker.io/node:20-bookworm'
@@ -35,6 +37,7 @@ jobs:
       - run: make deps-backend deps-tools
       - run: make --always-make checks-backend # ensure the "go-licenses" make target runs
   test-unit:
+    if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
     runs-on: docker
     needs: [lint-backend, checks-backend]
     container:
@@ -67,6 +70,7 @@ jobs:
           RACE_ENABLED: 'true'
           TAGS: bindata
   test-mysql:
+    if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
     runs-on: docker
     needs: [lint-backend, checks-backend]
     container:
@@ -109,6 +113,7 @@ jobs:
           TAGS: bindata
           USE_REPO_TEST_DIR: 1
   test-pgsql:
+    if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
     runs-on: docker
     needs: [lint-backend, checks-backend]
     container:
@@ -154,6 +159,7 @@ jobs:
           TEST_TAGS: gogit
           USE_REPO_TEST_DIR: 1
   test-sqlite:
+    if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
     runs-on: docker
     needs: [lint-backend, checks-backend]
     container: