ktlint 制品签名实战:基于 SIGNING.md 在本机构建并验证 GPG 签名产物 开发工具代码质量Lint格式化【免费下载链接】ktlintAn anti-bikeshedding Kotlin linter with built-in formatter项目地址https://gitcode.com/gh_mirrors/kt/ktlint点击查看免费下载导读ktlint 是面向 Kotlin 的反自行车棚anti-bikeshedding风格检查器与格式化工具其发布到 Maven 中央仓库的所有制品jar、pom、asc 签名文件、CLI 可执行文件等都经过 GPG 签名以保障供应链安全。本文以仓库根目录的 SIGNING.md 为核心完整讲解 ktlint 制品签名机制的运作方式为什么正式版才签名、CI 如何注入签名密钥、以及如何在本地生成测试 GPG 密钥并复现签名制品构建全过程。读完本文你将能独立在本机执行./gradlew publishToMavenLocal得到带有.asc签名文件的完整本地制品并对发布到中央仓库的签名链路建立源码级认知。一、ktlint 的签名机制概览ktlint 的发布制品默认全部签名这一点由 SIGNING.md 明确说明Release artifacts are signed. This is handled by the GitHub workflow.发布制品已签名该工作由 GitHub workflow 负责。签名的实际编排发生在两处CI 侧真正的发布环境.github/workflows/publish-release-build.yml中的publishjob 在./gradlew ktlintCliFiles publishMavenPublicationToMavenCentralRepository时通过环境变量注入三个签名参数ORG_GRADLE_PROJECT_signingInMemoryKey来自secrets.ORG_GRADLE_PROJECT_SIGNINGKEY_KTLINT_2ORG_GRADLE_PROJECT_signingInMemoryKeyId来自secrets.ORG_GRADLE_PROJECT_SIGNINGKEYID_KTLINT_2ORG_GRADLE_PROJECT_signingInMemoryKeyPassword来自secrets.ORG_GRADLE_PROJECT_SIGNINGPASSWORD_KTLINT_2这些以ORG_GRADLE_PROJECT_前缀开头的环境变量会被 Gradle 自动识别为项目属性project property从而让签名插件在内存中完成对制品的签名无需把私钥落盘。类似的注入也出现在.github/workflows/publish-snapshot-build.yml与.github/workflows/pull-request-with-code.yml中。构建逻辑侧签名开关仓库根目录的build-logic/src/main/kotlin/PublicationPlugin.kt是签名的核心开关。它读取三个可选属性val signingKeyId localGradleProperty(signingInMemoryKeyId).orNull?.takeIf { it.isNotEmpty() } val signingKey localGradleProperty(signingInMemoryKey).orNull?.takeIf { it.isNotEmpty() } val signingPassword localGradleProperty(signingInMemoryKeyPassword).orNull?.takeIf { it.isNotEmpty() } val signingConfigPresent signingKeyId ! null signingKey ! null signingPassword ! null if (signingConfigPresent || useGpgCmd ! null) { signAllPublications() configureSigningExtension { isRequired signingConfigPresent if (useGpgCmd ! null useGpgCmd ! false) { useGpgCmd() } } }从源码可以看出两个关键设计只有三个属性同时非空时才会对所有发布物执行签名signAllPublications()任一缺失都会跳过签名并打印Signing info not complete...提示日志避免 fork 出的 PR 构建因密钥缺失而失败若本机已有 gpg-agent 环境也可以用-PuseGpgCmd让签名插件直接调用本地 gpg 命令而无需导入内存密钥。此外CLI 发布物ktlint可执行文件在ktlint-cli/build.gradle.kts中还有独立的签名任务signKtlintCliFiles通过Sign类型任务对构建出的 CLI 可执行文件做签名见 ktlint-cli/build.gradle.kts。二、为什么-SNAPSHOT版本从不签名SIGNING.md 明确了一个重要规则版本号以-SNAPSHOT结尾时制品永远不会被签名。这一规则的实际效果体现在 gradle.properties 中——当前仓库的VERSION_NAME2.0.0-ALPHA-5-SNAPSHOT也就是说日常构建的本地制品是不签名的。签名只对正式发布版本去掉-SNAPSHOT后缀的版本号生效。这是 Maven 生态的常见约定快照版本用于迭代与联调发布到快照仓库时不需要也不应该携带签名而正式版本发布到 Maven Central 时必须附上*.asc签名文件供消费者校验完整性。因此在本地模拟签名测试时第一步就是临时修改VERSION_NAME去掉-SNAPSHOT后缀。三、本地签名测试前置条件与完整步骤SIGNING.md 提供了完整、可直接执行的本地签名测试流程下面按步骤展开并补充必要的说明。3.1 修改版本号临时、勿提交在 gradle.properties 中修改VERSION_NAME使其不以-SNAPSHOT结尾例如改为2.0.0-ALPHA-5。文档特别提醒此改动不要提交到版本库它只是本地测试用的临时状态。改完记得恢复。3.2 生成 GPG 密钥使用 GPG 生成一个专门用于测试的密钥。Maven 官方建议使用至少 4096 位的 RSA 密钥尽管文档也注明本地发布测试时密钥位数其实关系不大。在终端执行gpg --full-gen-key交互式回答建议如下完全取自 SIGNING.md选择密钥种类1) RSA and RSA密钥位数4096有效期0永不过期Real-namektlint-testEmail addressktlint-testnowhere.comCommentTest signing of ktlint artifacts on local machine onlyPassphrasei-will-try-no-to-forget-this-passphrase生成成功后终端会输出类似如下的密钥信息pub rsa4096 2023-10-08 [SC] 5B0ABB03277D2FEB46FE7E8E22D6006063A5D3C3 uid ktlint-test (Test signing of ktlint artifacts on local machine only) ktlint-testnowhere.com sub rsa4096 2023-10-08 [E]其中5B0ABB03277D2FEB46FE7E8E22D6006063A5D3C3是完整密钥 ID签名时需要取其最后 8 个字符本例为63A5D3C3作为signingInMemoryKeyId。3.3 在同一终端导出密钥到环境变量所有导出命令必须在同一个终端中执行后续 Gradle 命令也必须在同一终端因为密钥以环境变量形式存在跨终端会丢失。依次执行见 SIGNING.md# 1. 导出密钥 ID取公钥完整 ID 的后 8 位 export ORG_GRADLE_PROJECT_signingInMemoryKeyId63A5D3C3 # 2. 导出密钥口令 export ORG_GRADLE_PROJECT_signingInMemoryKeyPasswordi-will-try-no-to-forget-this-passphrase # 3. 导出 ASCII 装甲格式的私钥并写入环境变量。 # 该命令会提示输入私钥口令即上面的 passphrase。 # tail -r / tail -n 3 / tr -d \n 的组合用于剥离 GPG 输出中的多余空行与换行 # 确保密钥以单行无空白字符的形式交给 Gradle。 export ORG_GRADLE_PROJECT_signingInMemoryKey$(gpg --export-secret-keys --armor $ORG_GRADLE_PROJECT_signingInMemoryKeyId | tail -r | tail -n 3 | tail -r | tail -n 3 | tr -d \n)这三个环境变量的含义与 Gradle 属性一一对应也正是 PublicationPlugin.kt 中signingInMemoryKeyId、signingKey、signingPassword三个属性所消费的内容。之所以用ORG_GRADLE_PROJECT_前缀是为了让环境变量被 Gradle 自动提升为同名的 project property无需额外配置。3.4 执行本地发布由于导出私钥时需要手工输入口令发布命令不能与上述 export 语句合并到一条命令中否则无法交互式输入口令。请单独执行./gradlew publishToMavenLocal该命令会构建仓库下所有模块ktlint-rule-engine、ktlint-ruleset-standard、ktlint-cli、各 reporter 模块等并将它们连同签名文件一起安装到本地 Maven 仓库~/.m2/repository。四、如何验证签名是否生效publishToMavenLocal完成后可以检查本地 Maven 仓库中是否存在.asc签名文件。以 ktlint 的 groupIdio.github.ktlint.core见 gradle.properties 中的POM_GROUP_ID为例签名文件应出现在形如~/.m2/repository/io/github/ktlint/core/ktlint-rule-engine/版本号/ktlint-rule-engine-版本号.jar.asc ~/.m2/repository/io/github/ktlint/core/ktlint-rule-engine/版本号/ktlint-rule-engine-版本号.pom.asc的目录中。也可以直接在仓库目录内搜索*.asc文件确认数量与内容。若没有.asc文件请回头检查三点VERSION_NAME是否已去掉-SNAPSHOT后缀三个ORG_GRADLE_PROJECT_signing*环境变量是否在同一终端内设置完整私钥导出时是否输入了正确的 passphrase。另外一个可选的验证途径是使用-PuseGpgCmd如果你的环境已有可用的 gpg-agent可以在发布命令中追加该参数让 Gradle 直接调用本地 gpg 完成签名效果等价。五、从源码理解签名链路的关键细节密钥只存在于内存CI 与本地测试均通过signingInMemoryKey*系列属性把私钥交给 Gradle 签名插件私钥不以文件形式存在于构建机器降低泄露风险这也是 CI 中只把密钥放入 GitHub Secrets 的原因。空属性自动跳过签名PublicationPlugin.kt 中signingConfigPresent的判断保证在 fork 出来的 PR 构建、或本地未配置密钥的情况下构建不会因为缺少签名配置而整体失败只会跳过签名并以日志提示。CLI 制品单独签名除了各 Maven 模块的 jar/pomktlint-cli/build.gradle.kts中注册的signKtlintCliFiles任务会对ktlint-cli/build/run下生成的ktlint可执行文件执行Sign操作这一任务只有在项目应用了signing插件即签名配置就绪时才会作为ktlintCliFiles的 finalizedBy 任务触发。发布目标与签名强绑定CI 的发布命令是./gradlew ktlintCliFiles publishMavenPublicationToMavenCentralRepository见 .github/workflows/publish-release-build.yml签名与发布同在一个 Gradle 调用中完成保证发往 Maven Central 的制品与.asc文件一一对应。六、注意事项与常见问题务必恢复版本号测试完成后把 gradle.properties 中的VERSION_NAME恢复为带-SNAPSHOT的原始值避免误把测试版本提交或推送到远端。同一终端限制环境变量只在当前 shell 会话内有效新开终端后需重新执行 3.3 节的 export 命令。私钥安全本文中的测试密钥与口令均为文档中的示例值仅用于本地验证真实发布时应使用与 CI Secrets 中对应的、妥善保管的生产密钥。关于 passphrase 提示导出私钥命令会触发 gpg 的口令输入因此发布命令必须与 export 语句分开执行这在 SIGNING.md 中有明确说明。结语通过以上步骤你可以在完全不影响线上发布流程的前提下复现 ktlint 的制品签名构建临时修改版本号去掉-SNAPSHOT、生成测试 GPG 密钥、导出内存密钥变量、执行./gradlew publishToMavenLocal并检查.asc文件确认签名链路正常。结合 PublicationPlugin.kt 与.github/workflows/publish-release-build.yml你已对 ktlint 从本地测试到 CI 正式发布的完整签名机制建立了清晰的认知。赞分享开发工具代码质量Lint格式化【免费下载链接】ktlintAn anti-bikeshedding Kotlin linter with built-in formatter项目地址https://gitcode.com/gh_mirrors/kt/ktlint点击查看免费下载相关推荐ArgoCD 中的 GPG 签名验证机制详解ArgoCD 中的 GPG 签名验证机制详解 前言 在持续交付和 GitOps 实践中确保代码变更的真实性和完整性至关重要。ArgoCD 作为一款流行的 Gi云原生CI/CD容器编排DevOps后端AWX 项目签名与校验Project Signing and Verification实战指南基于 ansible-sign 的 GPG 签名与供应链完整性验证AWX 项目签名与校验Project Signing and Verification实战指南基于 ansible sign 的 GPG 签名与供应链完整后端运维任务调度Gradle 制品签名密钥完全指南从密钥管理到 GPG 验证与依赖验证实战Gradle 制品签名密钥完全指南从密钥管理到 GPG 验证与依赖验证实战 Gradle 官方对自身产出的每一个制品无论发布到制品仓库还是通过发行版渠道分发构建工具开发工具上一篇CANN/asc-devkit SIMT API __hmax_nan函数下一篇终极指南JUCE与CMake完美结合的现代C音频开发构建最佳实践创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考