fix(ci): sign APT Release files manually instead of via reprepro gpgme

reprepro uses gpgme for signing which fails in CI environments because
gpgme cannot access pinentry. Instead, remove SignWith from the reprepro
distributions config and sign Release files manually with gpg after
reprepro finishes, producing both Release.gpg and InRelease.
This commit is contained in:
kolaente 2026-04-12 17:31:39 +02:00
parent 160495b84e
commit 80ecaeb567
No known key found for this signature in database
GPG Key ID: F40E70337AB24C9B
3 changed files with 38 additions and 9 deletions

View File

@ -259,19 +259,15 @@ jobs:
gpg-passphrase: "${{ secrets.RELEASE_GPG_PASSPHRASE }}"
gpg-sign-key: "${{ secrets.RELEASE_GPG_SIGN_KEY }}"
- name: Configure GPG for non-interactive signing
run: |
echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf
echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
gpg-connect-agent reloadagent /bye
- name: Export GPG public key
run: |
mkdir -p dist/repo-output
gpg --export --armor 7D061A4AA61436B40713D42EFF054DACD908493A > dist/repo-output/gpg.key
- name: Generate APT repo metadata
env:
RELEASE_GPG_KEY: 7D061A4AA61436B40713D42EFF054DACD908493A
RELEASE_GPG_PASSPHRASE: ${{ secrets.RELEASE_GPG_PASSPHRASE }}
run: |
chmod +x ./mage-static
./mage-static release:repo-apt

View File

@ -4,7 +4,6 @@ Codename: stable
Architectures: amd64 arm64 armhf
Components: main
Description: The Vikunja package repository.
SignWith: 7D061A4AA61436B40713D42EFF054DACD908493A
Origin: dl.vikunja.io
Label: Vikunja
@ -12,4 +11,3 @@ Codename: unstable
Architectures: amd64 arm64 armhf
Components: main
Description: The Vikunja unstable package repository.
SignWith: 7D061A4AA61436B40713D42EFF054DACD908493A

View File

@ -1216,7 +1216,9 @@ func repoSuite() string {
// RepoApt generates APT repository metadata using reprepro.
// It expects .deb files in <DIST>/repo-work/incoming/ and outputs to <DIST>/repo-output/apt/.
// The reprepro config is read from build/reprepro-dist-conf.
// Signing is done manually after reprepro finishes to avoid gpgme pinentry issues in CI.
// Environment: REPO_SUITE controls the target suite (default: "stable").
// Environment: RELEASE_GPG_KEY, RELEASE_GPG_PASSPHRASE must be set for signing.
func (Release) RepoApt(ctx context.Context) error {
mg.Deps(initVars)
@ -1256,6 +1258,39 @@ func (Release) RepoApt(ctx context.Context) error {
}
}
// Sign Release files manually (reprepro's gpgme signing doesn't work in CI)
gpgKey := os.Getenv("RELEASE_GPG_KEY")
gpgPassphrase := os.Getenv("RELEASE_GPG_PASSPHRASE")
releaseFile := filepath.Join(outputBase, "dists", suite, "Release")
if _, err := os.Stat(releaseFile); err == nil {
// Generate Release.gpg (detached signature)
if err := runAndStreamOutput(ctx, "gpg",
"--default-key", gpgKey,
"--batch", "--yes",
"--passphrase", gpgPassphrase,
"--pinentry-mode", "loopback",
"--detach-sign", "--armor",
"-o", releaseFile+".gpg",
releaseFile,
); err != nil {
return fmt.Errorf("signing Release (detached): %w", err)
}
// Generate InRelease (clearsigned)
if err := runAndStreamOutput(ctx, "gpg",
"--default-key", gpgKey,
"--batch", "--yes",
"--passphrase", gpgPassphrase,
"--pinentry-mode", "loopback",
"--clearsign",
"-o", filepath.Join(filepath.Dir(releaseFile), "InRelease"),
releaseFile,
); err != nil {
return fmt.Errorf("signing Release (clearsign): %w", err)
}
}
fmt.Println("APT repo metadata generated in", outputBase)
return nil
}