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 }