Commit a39ac67a authored by Berk D. Demir's avatar Berk D. Demir
Browse files

_1password-gui: update-sources.py use Sequoia instead of GnuPG

r-ryantm update environment fails to go through GnuPG backed PGP
signature verification due to various intricacies of GnuPG's IPC
requirements to do rather basic things.

See: https://nixpkgs-update-logs.nix-community.org/_1password-gui-beta/2025-08-20.log

Switch from GnuPG to Sequoia, and use `sq` CLI tool for a more
minimalistic signature verification.

This change also simplifies trust anchor key acquisition to downloading
directly from 1Password's HTTPS service, instead of fetching by key id
from a PGP Key Server.

Testing:

  % for pkg in _1password-gui{,-beta}; do
   nix-shell ~nixpkgs/maintainers/scripts/update.nix --argstr commit true --argstr skip-prompt true --argstr commit true --argstr package ${pkg}
  done

  Going to be running update for following packages:
   - 1password-8.11.11

  Running update for:
  Preparing worktree (new branch 'update-tmp_manrfba')
  Updating files: 100% (49124/49124), done.
  HEAD is now at 1c8e629a6193 _1password-gui: update-sources.py use Sequoia
  Enqueuing group of 1 packages
   - 1password-8.11.11: UPDATING ...
  [master 6228d7811fce] _1password-gui: 8.11.11 -> 8.11.14
   Date: Sun Oct 19 22:42:25 2025 +0000
   1 file changed, 10 insertions(+), 10 deletions(-)
  Deleted branch update-tmp_manrfba (was 6228d7811fce).

  Packages updated!

  Going to be running update for following packages:
   - 1password-8.11.14-19.BETA

  Running update for:
  Preparing worktree (new branch 'update-tmpezi_89b8')
  Updating files: 100% (49124/49124), done.
  HEAD is now at 6228d7811fce _1password-gui: 8.11.11 -> 8.11.14
  Enqueuing group of 1 packages
   - 1password-8.11.14-19.BETA: UPDATING ...
  [master cd5f65a2f240] _1password-gui-beta: 8.11.14-19.BETA -> 8.11.16-30.BETA
   Date: Sun Oct 19 22:43:03 2025 +0000
   1 file changed, 10 insertions(+), 10 deletions(-)
  Deleted branch update-tmpezi_89b8 (was cd5f65a2f240).

  Packages updated!
parent 1cb228c5
Loading
Loading
Loading
Loading
+25 −30
Original line number Diff line number Diff line
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p python3 gnupg
#!nix-shell -i python3 -p python3 sequoia-sq
import json
import os
import shutil
@@ -9,8 +9,7 @@ import tempfile
from collections import OrderedDict

DOWNLOADS_BASE_URL = "https://downloads.1password.com"
OP_PGP_KEYID = "3FEF9748469ADBE15DA7CA80AC2D62742012EA22"

OP_PGP_KEY_URL = "https://downloads.1password.com/linux/keys/1password.asc"

class Sources(OrderedDict):
    def __init__(self):
@@ -21,43 +20,39 @@ class Sources(OrderedDict):
        with open("sources.json", "w") as fp:
            print(json.dumps(self, indent=2), file=fp)

class GPG:

class PGP:
    def __new__(cls):
        if not hasattr(cls, "_instance"):
            cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self):
        if hasattr(self, "gnupghome"):
        if hasattr(self, "signer_file"):
            return

        self.gpg = shutil.which("gpg")
        self.gpgv = shutil.which("gpgv")
        self.gnupghome = tempfile.mkdtemp(prefix="1password-gui-gnupghome.")
        self.env = {"GNUPGHOME": self.gnupghome}
        self._run(
            self.gpg,
            "--no-default-keyring",
            "--keyring",
            "trustedkeys.kbx",
            "--keyserver",
            "keyserver.ubuntu.com",
            "--receive-keys",
            OP_PGP_KEYID,
        )
        self.sq = shutil.which("sq")
        if (self.sq is None):
            raise SystemExit(f"sequoia sq not found")

    def __del__(self):
        shutil.rmtree(self.gnupghome)
        self.signer_file, _ = nix_store_prefetch(OP_PGP_KEY_URL)

    def verify(self, sig, tarball):
        args = [
            self.sq,
            "--batch",
            "--home=none",
            "verify",
            f"--signer-file={self.signer_file}",
            f"--signature-file={sig}",
            tarball
        ]

    def _run(self, *args):
        try:
            subprocess.run(args, env=self.env, check=True, capture_output=True)
            subprocess.run(args, check=True, capture_output=True)
        except subprocess.CalledProcessError as cpe:
            print(cpe.stderr, file=sys.stderr)
            raise SystemExit(f"gpg error: {cpe.cmd}")

    def verify(self, sigfile, datafile):
        return self._run(self.gpgv, sigfile, datafile)
            raise SystemExit(f"sq error: {cpe.cmd}")


def nix_store_prefetch(url):
@@ -89,7 +84,7 @@ def download(channel, os, version, arch):
    # Linux release tarballs come with detached PGP signatures.
    if os == "linux":
        store_path_sig, _ = nix_store_prefetch(url + ".sig")
        GPG().verify(store_path_sig, store_path_tarball)
        PGP().verify(store_path_sig, store_path_tarball)

    return url, hash