You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GitHub Workflows中Gradle发布自托管仓库报403 Forbidden(仅jar.sha1上传失败)

GitHub Workflows中Gradle发布自托管仓库报403 Forbidden(仅jar.sha1上传失败)

这问题确实够诡异的——明明本地发布一切正常,CI里jar能传上去,偏偏sha1文件报403还连服务端日志都没记录,换谁都会头大。我先帮你梳理下核心矛盾点,再给你一些针对性的排查和解决建议:


核心问题梳理

你遇到的关键异常点结合起来指向了非典型的权限问题:

  1. .jar文件上传完全正常:服务端返回201,Nexus/Nginx日志能明确看到请求记录
  2. .jar.sha1文件上传失败:报403 Forbidden,但服务端完全没收到这个请求
  3. 本地对比正常:用相同凭证、相同Gradle任务执行,所有 artifacts(包括sha1文件)都能正常发布

可能的原因分析

结合你的描述,我把可能性按优先级排序:

  1. 403来自中间层而非Nexus:因为服务端没收到请求,这个403大概率是GitHub Actions出站代理、或者你这边的防火墙/WAF返回的,不是Nexus本身的权限拦截
  2. Gradle在CI环境下的发布逻辑异常:比如CI环境的Gradle版本、配置和本地不一致,导致sha1文件的请求发送逻辑出问题
  3. Gradle发布任务的“dirty”配置触发了CI专属异常:你提到发布任务比较“dirty”,可能存在只在CI环境下触发的逻辑漏洞

具体排查与解决建议

一、先确认403的实际来源

既然服务端没收到请求,第一步要搞清楚这个403是谁返回的:
在你的Workflow的Publish Artifacts步骤之前,添加一个手动测试sha1文件上传的步骤,用curl直接发送请求:

- name: Test SHA1 File Upload
  run: |
    # 创建一个测试用的sha1文件
    echo "test-sha1-content" > test.jar.sha1
    # 手动发送PUT请求到Nexus,替换成你实际的路径前缀
    curl -v -u ${{ secrets.REPOSITORY_USER }}:${{ secrets.REPOSITORY_PASSWORD }} -T test.jar.sha1 "https://repository.atlasworld.fr/repository/maven-snapshots/fr/atlasworld/fresco-core/test-version/test.jar.sha1"
  • 如果这个curl请求也报403且服务端无日志:说明是网络中间层(GitHub出站策略、你的防火墙/WAF)拦截了sha1后缀的请求,需要针对性调整网络规则
  • 如果curl请求成功:说明是Gradle在CI环境下的发布逻辑有问题,继续往下排查

二、排查Gradle在CI环境下的行为

  1. 开启Gradle详细日志
    修改Workflow的发布步骤,加上--info参数查看详细日志,重点关注sha1文件的发布请求细节:

    - name: Publish Artifacts
      run: ./gradlew publish --info
      env:
        REPO_USERNAME: ${{ secrets.REPOSITORY_USER }}
        REPO_PASSWORD: ${{ secrets.REPOSITORY_PASSWORD }}
        RELEASE: false
        VERSION: ${{ steps.version.outputs.version }}
    

    查看日志中关于fresco-core-xxx.jar.sha1的请求构建、发送过程,有没有连接异常、凭证未传递等信息

  2. 对齐本地与CI的Gradle版本
    CI中gradle/actions/setup-gradle@v3会自动安装Gradle wrapper指定的版本,但可以先确认本地和CI的版本是否一致:

    - name: Check Gradle Version
      run: ./gradlew --version
    

    对比本地的./gradlew --version输出,如果版本不一致,尝试在CI中指定和本地相同的Gradle版本测试

  3. 简化Gradle发布配置
    你提到发布任务比较“dirty”,可以先简化配置测试,比如暂时注释掉metadataSources,或者手动指定要发布的artifacts:
    修改build.gradle.kts的发布配置:

    publishing {
        publications {
            create<MavenPublication>("core") {
                // 手动指定要发布的文件,绕过默认组件的可能问题
                artifact(tasks.jar.get())
                artifact(tasks.javadocJar.get())
                // 手动添加sha1文件
                val jarFile = tasks.jar.get().outputs.files.singleFile
                artifact(File(jarFile.absolutePath + ".sha1")) {
                    classifier = null
                    extension = "jar.sha1"
                }
            }
        }
        repositories {
            mavenLocal()
            maven {
                name = "AtlasWorld-Repository"
                url = URI.create("https://repository.atlasworld.fr/repository/maven-snapshot/")
                credentials {
                    username = System.getenv("REPO_USERNAME")
                    password = System.getenv("REPO_PASSWORD")
                }
                // 暂时注释掉metadataSources测试
                // metadataSources {
                //     gradleMetadata()
                // }
            }
        }
    }
    

三、网络与防火墙排查

  • 检查你的Nexus服务器的防火墙/WAF日志,看是否有来自GitHub Actions IP段的请求被拦截(尤其是针对.sha1后缀的文件)
  • 可以尝试在本地搭建一个Ubuntu容器(模拟GitHub Actions的ubuntu-latest环境),在容器内执行完整的发布流程,看是否能复现问题,排除GitHub Actions本身的网络问题

补充:你的Workflow与Build配置参考

为了方便其他人参考,这里整理了你提供的关键配置:

Workflow文件(/.github/workflows/publish-snapshot.yml)

name: Publish - Snapshot
on: push
jobs:
  publish:
    strategy:
      matrix:
        java: [ 21 ]
        os: [ ubuntu-latest ]
    runs-on: ${{ matrix.os }}
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4
      - name: Setup Java
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: ${{ matrix.java }}
      - name: Make Gradle Executable
        run: chmod +x ./gradlew
      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@v3
      - name: Determine Version
        id: version
        run: |
          GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
          GIT_HASH=$(git rev-parse HEAD)
          VERSION="${GIT_BRANCH}-${GIT_HASH:0:7}"
          echo "version=$VERSION" >> "$GITHUB_OUTPUT"
          echo "Version: ${VERSION}" >> $GITHUB_STEP_SUMMARY
      - name: Publish Artifacts
        run: ./gradlew publish
        env:
          REPO_USERNAME: ${{ secrets.REPOSITORY_USER }}
          REPO_PASSWORD: ${{ secrets.REPOSITORY_PASSWORD }}
          RELEASE: false
          VERSION: ${{ steps.version.outputs.version }}

Build配置(/build.gradle.kts)

import java.net.URI

plugins {
    id("java-library")
    id("maven-publish")
}

java {
    withJavadocJar()
}

dependencies {
}

publishing {
    publications {
        create<MavenPublication>("core") {
            from(components["java"])
        }
    }
    repositories {
        mavenLocal()
        maven {
            name = "AtlasWorld-Repository"
            url = URI.create("https://repository.atlasworld.fr/repository/maven-snapshot/")
            credentials {
                username = System.getenv("REPO_USERNAME")
                password = System.getenv("REPO_PASSWORD")
            }
            metadataSources {
                gradleMetadata()
            }
        }
    }
}

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 06:50:32