From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp0.migadu.com ([2001:41d0:303:e16b::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms8.migadu.com with LMTPS id oOBnK3sI9mXorAAAqHPOHw:P1 (envelope-from ) for ; Sat, 16 Mar 2024 22:00:43 +0100 Received: from aspmx1.migadu.com ([2001:41d0:303:e16b::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp0.migadu.com with LMTPS id oOBnK3sI9mXorAAAqHPOHw (envelope-from ) for ; Sat, 16 Mar 2024 22:00:43 +0100 X-Envelope-To: larch@yhetil.org Authentication-Results: aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=wolfsden.cz header.s=mail header.b=xdlnK2va; dkim=fail ("headers rsa verify failed") header.d=wolfsden.cz header.s=mail header.b=Kz33lTUB; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=fail reason="SPF not aligned (relaxed)" header.from=wolfsden.cz (policy=none) ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1710622843; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:resent-cc:resent-from:resent-sender: resent-message-id:in-reply-to:in-reply-to:references:references: list-id:list-help:list-unsubscribe:list-subscribe:list-post: dkim-signature; bh=lCxygFSXSUu1MwlUNVkKTN9e9f8iAdRMp649NBPiJOs=; b=mLIS33OIQfupWN2/U0cnpldBPTGJBbsk4g02tlMRfnuiHEy2o+1nCiI89k9v5T9gxnFhxK BiDMTKYH526sRmk6HY0+qnbq1yRPz2v9fSDSBjBkzpzw1cRoFNxtgvPVKuFDEuvAk3c8lS FSIOjmegGeznfVAlNPRafqAfgkp4F6X8xRSrr7POj3coWbRakJubJ8rkFDWXOx44VyxWxc 4Qdm5eRWWOZE1q3loac4+gYX0mLS8Ti2dLx9VJKE67Wz2moYlxAAsSoNjt/zw8KSoGSWin dSlcudVHtJKFIvGrvC17VHJ3fYpKKvVAIZf+ZEaTc2IUDjAvouHI1zANYNoIww== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=wolfsden.cz header.s=mail header.b=xdlnK2va; dkim=fail ("headers rsa verify failed") header.d=wolfsden.cz header.s=mail header.b=Kz33lTUB; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=fail reason="SPF not aligned (relaxed)" header.from=wolfsden.cz (policy=none) ARC-Seal: i=1; s=key1; d=yhetil.org; t=1710622843; a=rsa-sha256; cv=none; b=k6CS/aVQP3zGwUe5qzn7cpTH9oExN/ZQ9iqr2dqBX73HJZPW/UoPV9LHA1MV0l5nWT1F3s kwj7+Es+0kBF40Il5wA14wRO53Wcx6JGqdFWaww6caS6An+OGs7/pHOlc4QNcS3LV3X8Dr 0K7ZKDsIO6hah7BGUJesZ8pKOwdrDPlnNvIb3Q390yazAmm3O1tqI/4PQSWNCIAhjsPzId MK0Pvld2wt/mzn8QPur7HuqLQ6s6xy3eSIl/DwNnVs3gNWG/WC+YSIu2rHqI0jcm2k0KKu GZWtm1cgXmG80Hvxa5AKe5jM/RMJocJEbQnbidPP3NKHdmR4dcmaujF5svkFVg== Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 27FFC3B526 for ; Sat, 16 Mar 2024 22:00:43 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rlb8u-0002w0-Ps; Sat, 16 Mar 2024 17:00:37 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rlb8j-0002oz-Lb for guix-patches@gnu.org; Sat, 16 Mar 2024 17:00:28 -0400 Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rlb8j-0006v4-BP for guix-patches@gnu.org; Sat, 16 Mar 2024 17:00:25 -0400 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1rlb9K-0007vd-DW for guix-patches@gnu.org; Sat, 16 Mar 2024 17:01:02 -0400 X-Loop: help-debbugs@gnu.org Subject: [bug#69780] [PATCH 1/4] git authenticate: Record introduction and keyring in =?UTF-8?Q?=E2=80=98.git/config=E2=80=99.?= Resent-From: Tomas Volf <~@wolfsden.cz> Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sat, 16 Mar 2024 21:01:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 69780 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: Ludovic =?UTF-8?Q?Court=C3=A8s?= Cc: 69780@debbugs.gnu.org Received: via spool by 69780-submit@debbugs.gnu.org id=B69780.171062284930443 (code B ref 69780); Sat, 16 Mar 2024 21:01:02 +0000 Received: (at 69780) by debbugs.gnu.org; 16 Mar 2024 21:00:49 +0000 Received: from localhost ([127.0.0.1]:57209 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rlb96-0007ux-N8 for submit@debbugs.gnu.org; Sat, 16 Mar 2024 17:00:49 -0400 Received: from wolfsden.cz ([37.205.8.62]:50620) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <~@wolfsden.cz>) id 1rlb93-0007um-Ap for 69780@debbugs.gnu.org; Sat, 16 Mar 2024 17:00:47 -0400 Received: by wolfsden.cz (Postfix, from userid 104) id 613CE28F2F7; Sat, 16 Mar 2024 21:00:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wolfsden.cz; s=mail; t=1710622806; bh=dWi21Ofh+GVZQVs0TKy+KMsnwM8f+Xj9Lx/s+BVhpi8=; h=Date:From:To:Cc:Subject:References:In-Reply-To; b=xdlnK2vaLDTgbabMkMYQN2FjaN6jgnGwJIuyGwqF1eqXBMzuC+cQlUhujdOTSJ4pL JZPZ5JXABhLtg/VFGuc0auy97dGaXAtLUadyySWfRcY7OQSF562NfVAFcwLvOWXvZw pab/GpqoegFfUIgRVZvUpLHNCnQ20HZaaPouvo37Fb9vGETnpVaiJfpkOPU2pvogqB BP1E+e95NaaoMwu3ODkYDogfkckgpHgXUuFTSrw3BTyWumqLIBJzYV90QWs834zegl ZNihLupZe/UMIMizCKw8yD3Ep/F0BMkZ7Vlxc0QeLEUnisxE2Tp/msgT/QCe8Drsqb k3X9tNAi6y8t5Znlaw0XghYpP8QSFJKv8yTYmLqqV5vJH9Etmo9Y6WRKGgrmyPMWyU CYGpb3RaHQSPweTd6+7fiipscXqC+s7l0ZmTQCcb201dBhJzSWopbc/NOpjOt0JYJG w/xdvS+x1eH2W8VfLW35+2wbMc2eh/pekIX0iO9v6nrIjBvRICQ8fAzlFnEgp+yjyZ 0ytgsGv1mh0HRKVGm4QOyW+LhSEI887vQWzUz3isXK5pkQ+U3PU/h439VKGJsSTv2R zYgZI918if7hwZFB2YgVOsOvXgkkz3zPFDVy4lMRcgcz2dIvInTaqlc6wjZq6Dm040 3oduSLFN/hqAgZijHX9J2fGo= Received: from localhost (unknown [146.70.134.188]) by wolfsden.cz (Postfix) with ESMTPSA id 442A02902C6; Sat, 16 Mar 2024 21:00:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wolfsden.cz; s=mail; t=1710622805; bh=dWi21Ofh+GVZQVs0TKy+KMsnwM8f+Xj9Lx/s+BVhpi8=; h=Date:From:To:Cc:Subject:References:In-Reply-To; b=Kz33lTUBqRbOYi9tmRkGCgTogUV8NIBCpa6PueHPdVTMUMHR1Sow1yakszrQ8QqTA Hz005B7OR6QvcI88aPcFSHY/2s8AtfVJ1uoxuZ2zXGc3KGQNjeATJjBbFN8NBT513B o36dmRYjIvkxJWHDupN1oXT13f+KqRejd4CVFHfaRpuRgnP5fM6YoVLsQlmISpmXOA aDEWwewRYcx5O/Zmu9BugrqPiR6Pj8AnlS4BwHjBiSu9f9YLifT2DbP+u1Ns8PX6rD ncqZXgOAi8LRiPnwBeAjtsiIWsJjTwshtbXM7OLF3TS9WcIgMvsY1i8aNnRn3L5crV ExIdN6WAC+jgQwddxkRxuzEfGSP3ZJRknIA0TEKzlkxs00uDRsS0dlMbXe6x+jAp6J 7/3vwwg6GB8bmiG4FY8GZyZ5oMCaFrtxdIs8R1r5ur5s0+k1FtQ+V1Il9JmnAsjiuo 7PiEI1HCbxBOj32A9+fm6nj4Zei1GbBKQiiHfOfJXPBXLps/JlJinrAvd+fk7f65au UbyD6SNVpxpHPBxJQ5vHODR6BkPB0cmd4YrZSEbOXHiwrUFdhq1HAhhZ9PIBOn91Np vnWGOJcRQFlT2Cqgl6wAe2ZM8xuolmPAY4W+MTpitsJiSofqjeEaJByTHS7NQxYDtq q+W3bzNDub7ytzg0RawZWaVQ= Date: Sat, 16 Mar 2024 22:00:04 +0100 From: Tomas Volf <~@wolfsden.cz> Message-ID: References: <40858e56cf55b27711d23add5f3cd2ccc6ea5c58.1710351278.git.ludo@gnu.org> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="pHVZfNUnR6Ndid6e" Content-Disposition: inline In-Reply-To: <40858e56cf55b27711d23add5f3cd2ccc6ea5c58.1710351278.git.ludo@gnu.org> X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+larch=yhetil.org@gnu.org Sender: guix-patches-bounces+larch=yhetil.org@gnu.org X-Migadu-Flow: FLOW_IN X-Migadu-Country: US X-Migadu-Spam-Score: -6.80 X-Spam-Score: -6.80 X-Migadu-Queue-Id: 27FFC3B526 X-Migadu-Scanner: mx13.migadu.com X-TUID: C9KyLJoCdUEp --pHVZfNUnR6Ndid6e Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On 2024-03-13 18:42:19 +0100, Ludovic Court=C3=A8s wrote: > * guix/scripts/git/authenticate.scm (%default-options): Remove > =E2=80=98keyring-reference=E2=80=99. > (config-value, configured-introduction, configured-keyring-reference) > (configured?, record-configuration): New procedures. > (guix-git-authenticate)[missing-arguments]: New procedure. > Use =E2=80=98configured-introduction=E2=80=99 when zero arguments are giv= en. > Use =E2=80=98configured-keyring-reference=E2=80=99 when =E2=80=98-k=E2=80= =99 is not passed. Add call to > =E2=80=98record-configuration=E2=80=99. > * doc/guix.texi (Invoking guix git authenticate): Document it. > > Change-Id: I66e111a83f50407b52da71662629947f83a78bbc > --- > doc/guix.texi | 12 ++- > guix/scripts/git/authenticate.scm | 128 ++++++++++++++++++++++-------- > tests/guix-git-authenticate.sh | 9 ++- > 3 files changed, 112 insertions(+), 37 deletions(-) > > diff --git a/doc/guix.texi b/doc/guix.texi > index 858d5751bf..ac0766b98c 100644 > --- a/doc/guix.texi > +++ b/doc/guix.texi > @@ -7615,8 +7615,16 @@ Invoking guix git authenticate > and non-zero on failure. @var{commit} above denotes the first commit > where authentication takes place, and @var{signer} is the OpenPGP > fingerprint of public key used to sign @var{commit}. Together, they > -form a ``channel introduction'' (@pxref{channel-authentication, channel > -introduction}). The options below allow you to fine-tune the process. > +form a @dfn{channel introduction} (@pxref{channel-authentication, channel > +introduction}). On your first successful run, the introduction is > +recorded in the @file{.git/config} file of your checkout, allowing you > +to omit them from subsequent invocations: > + > +@example > +guix git authenticate [@var{options}@dots{}] > +@end example > + > +The options below allow you to fine-tune the process. > > @table @code > @item --repository=3D@var{directory} > diff --git a/guix/scripts/git/authenticate.scm b/guix/scripts/git/authent= icate.scm > index 6ff5cee682..d3cc4065df 100644 > --- a/guix/scripts/git/authenticate.scm > +++ b/guix/scripts/git/authenticate.scm > @@ -31,6 +31,7 @@ (define-module (guix scripts git authenticate) > #:use-module (srfi srfi-1) > #:use-module (srfi srfi-26) > #:use-module (srfi srfi-37) > + #:use-module (srfi srfi-71) > #:use-module (ice-9 format) > #:use-module (ice-9 match) > #:export (guix-git-authenticate)) > @@ -73,8 +74,60 @@ (define %options > (alist-cons 'show-stats? #t result))))) > > (define %default-options > - '((directory . ".") > - (keyring-reference . "keyring"))) > + '((directory . "."))) > + > +(define (config-value config key) > + "Return the config value associated with KEY, or #f if no such config = was > +found." > + (catch 'git-error > + (lambda () > + (config-entry-value (config-get-entry config key))) > + (const #f))) > + > +(define (configured-introduction repository) > + "Return two values: the commit and signer fingerprint (strings) as > +configured in REPOSITORY. Error out if one or both were missing." > + (let* ((config (repository-config repository)) > + (commit (config-value config "guix.authentication.introduction-= commit")) > + (signer (config-value config "guix.authentication.introduction-= signer"))) > + (unless (and commit signer) > + (leave (G_ "unknown introductory commit and signer~%"))) > + (values commit signer))) > + > +(define (configured-keyring-reference repository) > + "Return the keyring reference configured in REPOSITORY or #f if missin= g." > + (let ((config (repository-config repository))) > + (config-value config "guix.authentication.keyring"))) > + > +(define (configured? repository) > + "Return true if REPOSITORY already container introduction info in its > +'config' file." > + (let ((config (repository-config repository))) > + (and (config-value config "guix.authentication.introduction-commit") > + (config-value config "guix.authentication.introduction-signer")= ))) > + > +(define* (record-configuration repository > + #:key commit signer keyring-reference) > + "Record COMMIT, SIGNER, and KEYRING-REFERENCE in the 'config' file of > +REPOSITORY." > + (define directory > + (repository-directory repository)) > + > + (define config-file > + (in-vicinity directory "config")) I do not think this will work with worktrees. It will create the config fi= le in the worktree's git directory, but that file will be ignored by git. scheme@(guile-user)> (repository-discover "/home/xx/src/guix-wt/patch-1= ") $7 =3D "/home/xx/src/guix/.git/worktrees/orig/" scheme@(guile-user)> (repository-open $7) $8 =3D # scheme@(guile-user)> (repository-directory $8) $9 =3D "/home/xx/src/guix/.git/worktrees/orig/" scheme@(guile-user)> (in-vicinity $9 "config") $10 =3D "/home/xx/src/guix/.git/worktrees/orig/config" The $10 should be "/home/xx/src/guix/.git/config" instead. > + > + (call-with-port (open-file config-file "a") > + (lambda (port) > + (format port " > +# Added by 'guix git authenticate'. > +[guix \"authentication\"] > + introduction-commit =3D ~a > + introduction-signer =3D ~a > + keyring =3D ~a~%" > + commit signer keyring-reference))) I guess these specific values might not need any escaping? But the escaping (and the previous problem) would be solved by just shelling out to the `git config --local ...' to set the value. Something to consider. > + > + (info (G_ "introduction and keyring configuration recorded in '~a'~%") > + config-file)) > > (define (show-stats stats) > "Display STATS, an alist containing commit signing stats as returned by > @@ -156,35 +209,48 @@ (define (guix-git-authenticate . args) > (progress-reporter/bar (length commits)) > progress-reporter/silent)) > > + (define (missing-arguments) > + (leave (G_ "wrong number of arguments; \ > +expected COMMIT and SIGNER~%"))) > + > (with-error-handling > (with-git-error-handling > - (match (command-line-arguments options) > - ((commit signer) > - (let* ((directory (assoc-ref options 'directory)) > - (show-stats? (assoc-ref options 'show-stats?)) > - (keyring (assoc-ref options 'keyring-reference)) > - (repository (repository-open directory)) > - (end (match (assoc-ref options 'end-commit) > - (#f (reference-target > - (repository-head repository))) > - (oid oid))) > - (history (match (assoc-ref options 'historical-author= izations) > - (#f '()) > - (file (call-with-input-file file > - read-authorizations)))) > - (cache-key (or (assoc-ref options 'cache-key) > - (repository-cache-key repository)))) > - (define stats > - (authenticate-repository repository (string->oid commit) > - (openpgp-fingerprint* signer) > - #:end end > - #:keyring-reference keyring > - #:historical-authorizations history > - #:cache-key cache-key > - #:make-reporter make-reporter)) > + (let* ((directory (assoc-ref options 'directory)) > + (show-stats? (assoc-ref options 'show-stats?)) > + (repository (repository-open directory)) > + (commit signer (match (command-line-arguments options) > + ((commit signer) > + (values commit signer)) > + (() > + (configured-introduction repository)) > + (_ > + (missing-arguments)))) > + (keyring (or (assoc-ref options 'keyring-reference) > + (configured-keyring-reference repository) > + "keyring")) > + (end (match (assoc-ref options 'end-commit) > + (#f (reference-target > + (repository-head repository))) > + (oid oid))) > + (history (match (assoc-ref options 'historical-authoriza= tions) > + (#f '()) > + (file (call-with-input-file file > + read-authorizations)))) > + (cache-key (or (assoc-ref options 'cache-key) > + (repository-cache-key repository)))) > + (define stats > + (authenticate-repository repository (string->oid commit) > + (openpgp-fingerprint* signer) > + #:end end > + #:keyring-reference keyring > + #:historical-authorizations history > + #:cache-key cache-key > + #:make-reporter make-reporter)) > > - (when (and show-stats? (not (null? stats))) > - (show-stats stats)))) > - (_ > - (leave (G_ "wrong number of arguments; \ > -expected COMMIT and SIGNER~%"))))))) > + (unless (configured? repository) > + (record-configuration repository > + #:commit commit #:signer signer > + #:keyring-reference keyring)) Hm, so this records the information only on the very first successful authentication? So if I re-run with different values (e.g. I am creating a= new channel and `git commit --amend'-ed after checking the authorization), I am stuck with the (now) invalid values forever until I edit the .git/config by hand? Also (as Skyler Ferris already mentioned) this ignores the case of multiple branches with different authentication origins (I actually do have such use case), so the suggested option of storing it per-branch might be nice. Not= sure how to deal with pruning of old values though (if at all?). > + > + (when (and show-stats? (not (null? stats))) > + (show-stats stats)))))) > diff --git a/tests/guix-git-authenticate.sh b/tests/guix-git-authenticate= =2Esh > index ec89f941e6..db60816d45 100644 > --- a/tests/guix-git-authenticate.sh > +++ b/tests/guix-git-authenticate.sh > @@ -1,5 +1,5 @@ > # GNU Guix --- Functional package management for GNU > -# Copyright =C2=A9 2020, 2022 Ludovic Court=C3=A8s > +# Copyright =C2=A9 2020, 2022, 2024 Ludovic Court=C3=A8s > # > # This file is part of GNU Guix. > # > @@ -40,10 +40,11 @@ guix git authenticate "$intro_commit" "$intro_signer"= \ > --end=3D9549f0283a78fe36f2d4ff2a04ef8ad6b0c02604 && false > > # The v1.2.0 commit is a descendant of $intro_commit and it satisfies the > -# authorization invariant. > +# authorization invariant. No need to repeat $intro_commit and $intro_s= igner > +# because it should have been recorded in '.git/config'. > v1_2_0_commit=3D"a099685659b4bfa6b3218f84953cbb7ff9e88063" > -guix git authenticate "$intro_commit" "$intro_signer" \ > - --cache-key=3D"$cache_key" --stats \ > +guix git authenticate \ > + --cache-key=3D"$cache_key" --stats \ > --end=3D"$v1_2_0_commit" > > rm "$XDG_CACHE_HOME/guix/authentication/$cache_key" > -- > 2.41.0 Have a nice day, Tomas Volf -- There are only two hard things in Computer Science: cache invalidation, naming things and off-by-one errors. --pHVZfNUnR6Ndid6e Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEEt4NJs4wUfTYpiGikL7/ufbZ/wakFAmX2CFMACgkQL7/ufbZ/ wan28A//SXbmEJzadgWsHAh6eY5EVyar+IcNpVePx7neWN2svVpxMqI2M86G8ny9 evfMcpQEd+5z/p/r56wMo3o1ZWMcaIYdwK7l5s7W1EgA3wa8Sl49Z/E43tJuW4oc uLmpjmpuQocAie1M0CHHJOFo4pioLhyMZVpXXl8e/pU6kJxNDzaPdz++oivU9+U7 IGYDCFkEmnafpT/D4v9nZrcgyOA81txMgMYi7f78KU9WE+SNnrU2dtluWFAZ6V2k 92O/0gaZzw4E1nPcBy+uBiCyv8DMFzQ9UJWjYiiRI/1kpL7ea5j5Q7RJB73DP0kR WkbYXdagwOh40Sxw0ciWNXXMhUKjIlv4BzwsQhevcLWf5K5iw8jcEr51NvUKlTs7 lpdqIpYr1d8CnQsnEwoBvBF7Yl4jidD7raWYqMWUJAkuoaDbjjI52gj2c8pmD0+H q7XO6p9GR9MLNOa09a84EHnMPMioHCOuymM4WZEBLMWaRC1piyL0GwgV2eyHiLRH 4lgFbI4A8aWM40bqrvXp12U6AXwvr1qIpNDLLGk4caJzBF6RweaAp0Yy37MDykHv CugkMjARjc0UAaLe4zdIOnxZ7V162Nt0Ylvv6pB1hWNQlqiR8W7D1CmkSJ50yHD5 gU7mZSegn5KaQk8ygMWGkfq1nnDjSLkjTifh6pJ9evwJFLI4wwE= =ntVX -----END PGP SIGNATURE----- --pHVZfNUnR6Ndid6e--