簽署外掛增加了數位簽署已建置檔案和構件的功能。這些數位簽名可以用來證明誰建置了附加簽名的構件,以及其他資訊,例如簽名何時產生。
簽署外掛目前僅提供產生 OpenPGP 簽名 的支援(這是發布到 Maven Central Repository 所需的簽名格式)。
用法
要使用簽署外掛,請在您的建置腳本中包含以下內容
plugins {
signing
}
plugins {
id 'signing'
}
簽署人憑證
為了建立 OpenPGP 簽名,您需要一個金鑰對(關於使用 GnuPG 工具 建立金鑰對的說明可以在 GnuPG HOWTOs 中找到)。您需要向簽署外掛提供您的金鑰資訊,這表示三件事
-
公開金鑰 ID(keyId 的最後 8 個符號。您可以使用
gpg -K
來取得)。 -
包含您的私密金鑰的私密金鑰環檔案的絕對路徑。(自 gpg 2.1 以來,您需要使用命令
gpg --keyring secring.gpg --export-secret-keys > ~/.gnupg/secring.gpg
匯出金鑰)。 -
用於保護您的私密金鑰的密碼。
這些項目必須分別作為 signing.keyId
、signing.secretKeyRingFile
和 signing.password
屬性的值提供。
鑑於這些值的個人和私密性質,一個好的做法是將它們儲存在使用者 Gradle 主目錄中的 gradle.properties 檔案中(在 系統屬性 中描述),而不是在專案目錄本身中。 |
signing.keyId=24875D73
signing.password=secret
signing.secretKeyRingFile=/Users/me/.gnupg/secring.gpg
如果在使用者 gradle.properties
檔案中指定此資訊(尤其是 signing.password
)在您的環境中不可行,您可以透過命令列提供資訊
> gradle sign -Psigning.secretKeyRingFile=/Users/me/.gnupg/secring.gpg -Psigning.password=secret -Psigning.keyId=24875D73
使用記憶體內 ascii-armored 金鑰
在某些設定中,使用環境變數傳遞用於簽署的私密金鑰和密碼更容易。例如,當使用 CI 伺服器簽署構件時,安全地提供金鑰環檔案通常很麻煩。另一方面,大多數 CI 伺服器都提供安全儲存環境變數並將其提供給建置的方法。使用以下設定,您可以使用 ORG_GRADLE_PROJECT_signingKey
和 ORG_GRADLE_PROJECT_signingPassword
環境變數分別傳遞私密金鑰(以 ascii-armored 格式)和密碼
signing {
val signingKey: String? by project
val signingPassword: String? by project
useInMemoryPgpKeys(signingKey, signingPassword)
sign(tasks["stuffZip"])
}
signing {
def signingKey = findProperty("signingKey")
def signingPassword = findProperty("signingPassword")
useInMemoryPgpKeys(signingKey, signingPassword)
sign stuffZip
}
使用記憶體內 ascii-armored OpenPGP 子金鑰
為了防止共享主金鑰並確保其安全,也可以使用記憶體內 ascii-armored 子金鑰。使用記憶體內 ascii-armored 金鑰和子金鑰之間的主要區別在於,也必須指定金鑰識別符。使用以下設定,您可以使用 ORG_GRADLE_PROJECT_signingKeyId
、ORG_GRADLE_PROJECT_signingKey
和 ORG_GRADLE_PROJECT_signingPassword
環境變數分別傳遞金鑰識別符、私密金鑰(以 ascii-armored 格式)和密碼
signing {
val signingKeyId: String? by project
val signingKey: String? by project
val signingPassword: String? by project
useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)
sign(tasks["stuffZip"])
}
signing {
def signingKeyId = findProperty("signingKeyId")
def signingKey = findProperty("signingKey")
def signingPassword = findProperty("signingPassword")
useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)
sign stuffZip
}
使用 OpenPGP 子金鑰
OpenPGP 支援子金鑰,子金鑰就像普通金鑰一樣,只是它們綁定到主金鑰對。OpenPGP 子金鑰的一個功能是,它們可以獨立於主金鑰撤銷,這使得金鑰管理更容易。關於如何在軟體開發中利用子金鑰的實際案例研究,可以在 Debian wiki 上閱讀。
簽署外掛開箱即用就支援 OpenPGP 子金鑰。只需在 signing.keyId
屬性中指定子金鑰 ID 作為值即可。
使用 gpg-agent
預設情況下,簽署外掛使用基於 Java 的 PGP 實作進行簽署。但是,此實作無法使用 gpg-agent 程式來管理私密金鑰。如果您想使用 gpg-agent,您可以變更簽署外掛使用的簽署人實作
signing {
useGpgCmd()
sign(configurations.runtimeElements.get())
}
signing {
useGpgCmd()
sign configurations.runtimeElements
}
這告訴簽署外掛使用 GnupgSignatory
而不是預設的 PgpSignatory。GnupgSignatory
依賴 gpg2 程式來簽署構件。當然,這需要安裝 GnuPG。
在沒有任何進一步配置的情況下,將使用在 PATH
上找到的 gpg
(在 Windows 上:gpg.exe
)可執行檔。密碼由 gpg-agent
提供,預設金鑰用於簽署。
Gnupg 簽署人配置
GnupgSignatory
支援許多配置選項,用於控制如何調用 gpg。這些通常在 gradle.properties 中設定
範例:配置 GnupgSignatory
signing.gnupg.executable=gpg
signing.gnupg.useLegacyGpg=true
signing.gnupg.homeDir=gnupg-home
signing.gnupg.optionsFile=gnupg-home/gpg.conf
signing.gnupg.keyName=24875D73
signing.gnupg.passphrase=gradle
signing.gnupg.executable
-
用於簽署的 gpg 可執行檔。此屬性的預設值取決於
useLegacyGpg
。如果為true
,則可執行檔的預設值為 "gpg",否則為 "gpg2"。 signing.gnupg.useLegacyGpg
-
如果使用 GnuPG 版本 1,則必須為
true
,否則為false
。該屬性的預設值為false
。 signing.gnupg.homeDir
-
設定 GnuPG 的主目錄。如果未給定,則使用 GnuPG 的預設主目錄。
signing.gnupg.optionsFile
-
為 GnuPG 設定自訂選項檔案。如果未給定,則使用 GnuPG 的預設設定檔。
signing.gnupg.keyName
-
應該用於簽署的金鑰 ID。如果未給定,則將使用在 GnuPG 中配置的預設金鑰。
signing.gnupg.passphrase
-
用於解鎖私密金鑰的密碼。如果未給定,則使用 gpg-agent 程式來取得密碼。
所有配置屬性都是可選的。
指定要簽署的內容
除了配置如何簽署內容(即簽署人配置)之外,您還必須指定要簽署的內容。簽署外掛提供了一個 DSL,允許您指定應該簽署的任務和/或配置。
簽署發布
發布構件時,您通常希望簽署它們,以便您的構件的消費者可以驗證其簽名。例如,Java 外掛 定義了一個元件,您可以使用該元件使用 Maven 發布外掛(或 Ivy 發布外掛,分別)來定義發布到 Maven(或 Ivy)儲存庫的發布。使用簽署 DSL,您可以指定應該簽署此發布的所有構件。
signing {
sign(publishing.publications["mavenJava"])
}
signing {
sign publishing.publications.mavenJava
}
這將在您的專案中建立一個名為 signMavenJavaPublication
的任務(類型為 Sign),它將建置發布中包含的所有構件(如果需要),然後為它們產生簽名。簽名檔案將與正在簽署的構件一起放置。
範例:簽署發布輸出
gradle signMavenJavaPublication
的輸出> gradle signMavenJavaPublication > Task :compileJava > Task :processResources > Task :classes > Task :jar > Task :javadoc > Task :javadocJar > Task :sourcesJar > Task :generateMetadataFileForMavenJavaPublication > Task :generatePomFileForMavenJavaPublication > Task :signMavenJavaPublication BUILD SUCCESSFUL in 0s 9 actionable tasks: 9 executed
此外,上面的 DSL 允許 sign
多個以逗號分隔的發布。或者,您可以指定 publishing.publications
來簽署所有發布,或使用 publishing.publications.matching { … }
來簽署與指定謂詞匹配的所有發布。
簽署配置
通常希望簽署配置的構件。例如,Java 外掛 配置了一個 jar 來建置,並且這個 jar 構件被添加到 runtimeElements
配置中。使用簽署 DSL,您可以指定應該簽署此配置的所有構件。
signing {
sign(configurations.runtimeElements.get())
}
signing {
sign configurations.runtimeElements
}
這將在您的專案中建立一個名為 signRuntimeElements
的任務(類型為 Sign),它將建置任何 runtimeElements
構件(如果需要),然後為它們產生簽名。簽名檔案將與正在簽署的構件一起放置。
範例:簽署配置輸出
gradle signRuntimeElements
的輸出> gradle signRuntimeElements > Task :compileJava > Task :processResources > Task :classes > Task :jar > Task :signRuntimeElements BUILD SUCCESSFUL in 0s 4 actionable tasks: 4 executed
簽署任務輸出
在某些情況下,您需要簽署的構件可能不是配置的一部分。在這種情況下,您可以直接簽署產生要簽署的構件的任務。
tasks.register<Zip>("stuffZip") {
archiveBaseName = "stuff"
from("src/stuff")
}
signing {
sign(tasks["stuffZip"])
}
tasks.register('stuffZip', Zip) {
archiveBaseName = 'stuff'
from 'src/stuff'
}
signing {
sign stuffZip
}
這將在您的專案中建立一個名為 signStuffZip
的任務(類型為 Sign),它將建置輸入任務的封存檔(如果需要),然後對其進行簽署。簽名檔案將與正在簽署的構件一起放置。
範例:簽署任務輸出
gradle signStuffZip
的輸出> gradle signStuffZip > Task :stuffZip > Task :signStuffZip BUILD SUCCESSFUL in 0s 2 actionable tasks: 2 executed
條件式簽署
常見的用法模式是僅在特定條件下才需要簽署建置構件。例如,您可能不需要為非發行版本簽署構件。為了實現這一點,您可以將條件指定為 required()
方法的參數。
version = "1.0-SNAPSHOT"
extra["isReleaseVersion"] = !version.toString().endsWith("SNAPSHOT")
signing {
setRequired({
(project.extra["isReleaseVersion"] as Boolean) && gradle.taskGraph.hasTask("publish")
})
sign(publishing.publications["main"])
}
version = '1.0-SNAPSHOT'
ext.isReleaseVersion = !version.endsWith("SNAPSHOT")
signing {
required = { isReleaseVersion && gradle.taskGraph.hasTask("publish") }
sign publishing.publications.main
}
在本範例中,我們只想在建置發行版本並且我們要發布它時才需要簽署。因為我們正在檢查任務圖以確定我們是否要發布,所以我們必須將 signing.required
屬性設定為閉包以延遲評估。有關更多資訊,請參閱 SigningExtension.setRequired(java.lang.Object)。
如果 required
條件不成立,則僅當配置了簽署人憑證時才會簽署構件。或者,您可能希望完全跳過簽署,無論簽署人憑證是否可用。如果是這樣,您可以配置要跳過的 Sign 任務,例如透過使用 onlyIf()
方法附加謂詞,如下例所示
tasks.withType<Sign>().configureEach {
onlyIf("isReleaseVersion is set") { project.extra["isReleaseVersion"] as Boolean }
}
tasks.withType(Sign) {
onlyIf("isReleaseVersion is set") { isReleaseVersion }
}