簽署外掛程式新增了數位簽署已建置檔案和成品的能力。這些數位簽章可用於證明建立簽章所附成品的人員,以及其他資訊,例如簽章產生時間。
簽署外掛程式目前僅提供產生 OpenPGP 簽章 的支援(這是 發布到 Maven 中央儲存庫 所需的簽章格式)。
使用方式
若要使用簽署外掛程式,請在建置指令碼中包含下列內容
plugins {
signing
}
plugins {
id 'signing'
}
簽署者憑證
若要建立 OpenPGP 簽章,您需要一組金鑰(使用 GnuPG 工具 建立金鑰組的說明可在 GnuPG HOWTO 中找到)。您需要提供金鑰資訊給簽署外掛程式,這表示三件事
-
公開金鑰 ID(金鑰 ID 的最後 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 裝甲金鑰
在某些設定中,使用環境變數來傳遞用於簽署的機密金鑰和密碼會比較容易。例如,當使用 CI 伺服器來簽署成品時,安全地提供鑰匙圈檔案通常很麻煩。另一方面,大多數 CI 伺服器提供安全儲存環境變數並將其提供給建置的方法。使用以下設定,你可以分別使用 `ORG_GRADLE_PROJECT_signingKey` 和 `ORG_GRADLE_PROJECT_signingPassword` 環境變數傳遞機密金鑰(以 ASCII 裝甲格式)和密碼
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 裝甲 OpenPGP 子金鑰
為了防止共用主金鑰並保持其安全,也可以使用記憶體中的 ASCII 裝甲子金鑰。使用記憶體中的 ASCII 裝甲金鑰和子金鑰之間的主要差異在於,也需要指定金鑰識別碼。使用以下設定,你可以分別使用 `ORG_GRADLE_PROJECT_signingKeyId`、`ORG_GRADLE_PROJECT_signingKey` 和 `ORG_GRADLE_PROJECT_signingPassword` 環境變數傳遞金鑰識別碼、機密金鑰(以 ASCII 裝甲格式)和密碼
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 子金鑰。只要將子金鑰 ID 指定為 `signing.keyId` 屬性中的值即可。
使用 gpg-agent
預設情況下,簽署外掛程式使用 Java-based 的 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
}
這會在您的專案中建立一個任務(類型為Sign),名稱為 signMavenJavaPublication
,它會建立屬於發布的所有成品(如果需要),然後為它們產生簽章。簽章檔案會放置在要簽署的成品旁邊。
範例:簽署發布輸出
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
}
這會在您的專案中建立一個任務(類型為Sign),名稱為 signRuntimeElements
,它會建立任何 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
}
這會在您的專案中建立一個任務(類型為Sign),名稱為 signStuffZip
,它會建立輸入任務的封存(如果需要),然後簽署它。簽章檔案會放置在要簽署的成品旁邊。
範例:簽署任務輸出
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 任務為略過,例如透過附加謂詞,方法如下一個範例所示
tasks.withType<Sign>().configureEach {
onlyIf("isReleaseVersion is set") { project.extra["isReleaseVersion"] as Boolean }
}
tasks.withType(Sign) {
onlyIf("isReleaseVersion is set") { isReleaseVersion }
}