From 80ecaeb567dd7beedc74c1aa8984354a7d6fc4de Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 12 Apr 2026 17:31:39 +0200 Subject: [PATCH] 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. --- .github/workflows/release.yml | 10 +++------- build/reprepro-dist-conf | 2 -- magefile.go | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c8aee77f5..b0c734359 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -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 diff --git a/build/reprepro-dist-conf b/build/reprepro-dist-conf index 187ea362a..d0684520a 100644 --- a/build/reprepro-dist-conf +++ b/build/reprepro-dist-conf @@ -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 diff --git a/magefile.go b/magefile.go index c88daaf30..fa96968ba 100644 --- a/magefile.go +++ b/magefile.go @@ -1216,7 +1216,9 @@ func repoSuite() string { // RepoApt generates APT repository metadata using reprepro. // It expects .deb files in /repo-work/incoming/ and outputs to /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 }