diff --git a/default.nix b/default.nix index 80ccffd..2c93aab 100644 --- a/default.nix +++ b/default.nix @@ -107,6 +107,7 @@ in { btop direnv git-sync + got jq lz4 minisign diff --git a/pkgs/default.nix b/pkgs/default.nix index ca74d72..ccda6d1 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -4,7 +4,6 @@ with pkgs; { environment.systemPackages = with pkgs; [ #(callPackage ./cinny-desktop.nix { inherit isUnstable; }) #(callPackage ./mudita-center.nix { inherit isUnstable; }) - (callPackage ./got.nix { inherit isUnstable; }) (callPackage ./govulncheck.nix { inherit isUnstable; }) ]; } diff --git a/pkgs/got-sigs.diff b/pkgs/got-sigs.diff deleted file mode 100644 index 849c379..0000000 --- a/pkgs/got-sigs.diff +++ /dev/null @@ -1,1751 +0,0 @@ -From owner-gameoftrees+M2377@openbsd.org Fri Jul 1 15:32:58 2022 -Return-Path: -Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) - by sloti51n17 (Cyrus 3.7.0-alpha0-713-g1f035dc716-fm-20220617.001-g1f035dc7) with LMTPA; - Fri, 01 Jul 2022 17:32:58 -0400 -X-Cyrus-Session-Id: sloti51n17-1656711178-2859225-2-6045727934994432308 -X-Sieve: CMU Sieve 3.0 -X-Spam-known-sender: no -X-Spam-sender-reputation: 500 (none) -X-Spam-score: 0.0 -X-Spam-hits: BAYES_50 0.8, DCC_REPUT_70_89 0.1, HEADER_FROM_DIFFERENT_DOMAINS 0.25, - MAILING_LIST_MULTI -1, ME_HAS_VSSU 0.001, ME_SENDERREP_NEUTRAL 0.001, - RCVD_IN_DNSWL_MED -2.3, SPF_HELO_NONE 0.001, SPF_PASS -0.001, - T_SCC_BODY_TEXT_LINE -0.01, LANGUAGES en, BAYES_USED user, - SA_VERSION 3.4.6 -X-Spam-source: IP='199.185.178.25', Host='mail.openbsd.org', Country='CA', - FromHeader='com', MailFrom='org' -X-Spam-charsets: plain='us-ascii' -X-Resolved-to: qbit@fastmail.com -X-Delivered-to: aaron@bolddaemon.com -X-Mail-from: owner-gameoftrees+M2377@openbsd.org -Received: from mx4 ([10.202.2.203]) - by compute4.internal (LMTPProxy); Fri, 01 Jul 2022 17:32:58 -0400 -Received: from mx4.messagingengine.com (localhost [127.0.0.1]) - by mailmx.nyi.internal (Postfix) with ESMTP id 4F9E51F2015B - for ; Fri, 1 Jul 2022 17:32:57 -0400 (EDT) -Received: from mx4.messagingengine.com (localhost [127.0.0.1]) - by mx4.messagingengine.com (Authentication Milter) with ESMTP - id 1E136C19FFD; - Fri, 1 Jul 2022 17:32:57 -0400 -ARC-Seal: i=1; a=rsa-sha256; cv=none; d=messagingengine.com; s=fm2; t= - 1656711177; b=MECs9vhH51TZw6R0i0ZmSqoUz/9WJw3n0hR1h0RQXJNTCEIzOk - uAp9CC7hiENzB20jLY/XdRv8uquFgcsi/WGyB0Doh0COt6ZFqSSR3gXxUtcqq8sY - Zp/gm5EcdmlxKgrj6VGUB9R2DxyMSKSaKDntt9THmvAgyQBwfMoMzgCO+8tDMtJ1 - /JxK+pVO8/j66X3qJ9DfklfDMlC/FukJXcvZmrfH3+c544A+h3+jHE5itknD5D8B - ju4qFSEqAs4OVC/qO9uSUCCPxaVH0IvPPhQJVTbo1kkaiTA9+XDsrd6OZvuBsqEB - yjPeFsDb98chOTF8jP3qwK4WC2TheFpbBFLQ== -ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d= - messagingengine.com; h=date:from:to:subject:message-id - :references:mime-version:content-type:in-reply-to:list-help - :list-id:list-owner:list-post:list-subscribe:list-unsubscribe - :sender; s=fm2; t=1656711177; bh=Eo9QrjLTSve5/c6ZYTKt8UqZNUWrN8y - Pr0Y92XB6bLY=; b=g2yT9DM8+qgIbu8pi1s2kp05tmhUGLr+bHYoAJnfv1o1A/6 - Y47l+aJoSAoorAGUtUhQl8AcYMvMOXdL2GI1Uq8Ft3F3pBoysvCuM+22EDkkHmKx - aUQ1zBCNjFaUuJHAryNIlO0DOK+hipWozGji26qBG3j9NumkQ0gAqhjh8Y0QZgOc - YY+ncg5c+1hNKEkzbP76rgHQJz1ajTYggXi/s4L8479i9Joq6IIuuUZcvQFwefqN - N37CiCMfJb6kviCHpEsAUFibZvCQYOC4ayxHyNfZxFARuQfFk47wRRdQFbZ034Jq - u6dgeeBJha9HM5MVH0mpkxk8srtAIu8pnTbOLKw== -ARC-Authentication-Results: i=1; mx4.messagingengine.com; - x-csa=none; - x-me-sender=none; - x-ptr=pass smtp.helo=mail.openbsd.org policy.ptr=mail.openbsd.org; - bimi=skipped (DMARC did not pass); - arc=none (no signatures found); - dkim=none (no signatures found); - dmarc=fail policy.published-domain-policy=quarantine - policy.applied-disposition=none - policy.evaluated-disposition=quarantine - policy.override-reason=trusted_forwarder policy.arc-aware-result=fail - (p=quarantine,has-list-id=yes,d=none,d.eval=quarantine,override=trusted_forwarder,arc_aware_result=fail) - policy.policy-from=p header.from=zettaport.com; - iprev=pass smtp.remote-ip=199.185.178.25 (mail.openbsd.org); - spf=pass smtp.mailfrom=owner-gameoftrees+M2377@openbsd.org - smtp.helo=mail.openbsd.org -X-ME-Authentication-Results: mx4.messagingengine.com; - x-aligned-from=fail; - x-return-mx=pass header.domain=zettaport.com policy.is_org=yes - (MX Records found: europa.zettaport.com); - x-return-mx=pass smtp.domain=openbsd.org policy.is_org=yes - (MX Records found: mail.openbsd.org); - x-tls=pass smtp.version=TLSv1.3 smtp.cipher=TLS_AES_256_GCM_SHA384 - smtp.bits=256/256; - x-vs=clean score=0 state=0 -Authentication-Results: mx4.messagingengine.com; - x-csa=none; - x-me-sender=none; - x-ptr=pass smtp.helo=mail.openbsd.org policy.ptr=mail.openbsd.org -Authentication-Results: mx4.messagingengine.com; - bimi=skipped (DMARC did not pass) -Authentication-Results: mx4.messagingengine.com; - arc=none (no signatures found) -Authentication-Results: mx4.messagingengine.com; - dkim=none (no signatures found); - dmarc=fail policy.published-domain-policy=quarantine - policy.applied-disposition=none - policy.evaluated-disposition=quarantine - policy.override-reason=trusted_forwarder policy.arc-aware-result=fail - (p=quarantine,has-list-id=yes,d=none,d.eval=quarantine,override=trusted_forwarder,arc_aware_result=fail) - policy.policy-from=p header.from=zettaport.com; - iprev=pass smtp.remote-ip=199.185.178.25 (mail.openbsd.org); - spf=pass smtp.mailfrom=owner-gameoftrees+M2377@openbsd.org - smtp.helo=mail.openbsd.org -X-ME-VSSU: VW5zdWI9bWFpbHRvOm1ham9yZG9tb0BvcGVuYnNkLm9yZz9ib2R5PXVuc3ViJTIwZ2FtZW - 9mdHJlZXM -X-ME-VSCause: gggruggvucftvghtrhhoucdtuddrgedvfedrudehfedgudeifecutefuodetggdotefrod - ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp - uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecunecujfgurhepfffhvf - fukfhfgggtuggjfeejvddutdfjphhssehttddttddttddvnecuhfhrohhmpeflohhshhcu - tfhitghkmhgrrhcuoehophgvnhgsshguodhlihhsthhsseiivghtthgrphhorhhtrdgtoh - hmqeenucggtffrrghtthgvrhhnpefgvdeghfdtiedvteekjeeugfevgfdtgeffleelleff - leevgeejheetffekkeejfeenucffohhmrghinhepfihtrdhgohhtnecukfhppeduleelrd - dukeehrddujeekrddvhedpudegledrvdekrddvfedvrddvgedunecuvehluhhsthgvrhfu - ihiivgeptdenucfrrghrrghmpehinhgvthepudelledrudekhedrudejkedrvdehpdhhvg - hlohepmhgrihhlrdhophgvnhgsshgurdhorhhgpdhmrghilhhfrhhomhepoehofihnvghr - qdhgrghmvghofhhtrhgvvghsodfovdefjeejsehophgvnhgsshgurdhorhhgqe -X-ME-VSScore: 0 -X-ME-VSCategory: clean -X-ME-CSA: none -Received-SPF: pass - (openbsd.org: 199.185.178.25 is authorized to use 'owner-gameoftrees+M2377@openbsd.org' in 'mfrom' identity (mechanism 'mx' matched)) - receiver=mx4.messagingengine.com; - identity=mailfrom; - envelope-from="owner-gameoftrees+M2377@openbsd.org"; - helo=mail.openbsd.org; - client-ip=199.185.178.25 -Received: from mail.openbsd.org (mail.openbsd.org [199.185.178.25]) - (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) - key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) - (No client certificate requested) - by mx4.messagingengine.com (Postfix) with ESMTPS - for ; Fri, 1 Jul 2022 17:32:56 -0400 (EDT) -Received: from openbsd.org (localhost [127.0.0.1]) - by mail.openbsd.org (OpenSMTPD) with ESMTP id 12cabdb7; - Fri, 1 Jul 2022 15:32:47 -0600 (MDT) -Received: from europa.zettaport.com (europa.zettaport.com [149.28.232.241]) - by mail.openbsd.org (OpenSMTPD) with ESMTPS id 9cf59a50 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO) - for ; - Fri, 1 Jul 2022 15:32:20 -0600 (MDT) -Received: - by europa.zettaport.com (OpenSMTPD) with ESMTPSA id 774f76fa (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO) - for ; - Fri, 1 Jul 2022 21:32:19 +0000 (UTC) -Received: from localhost (mail.i.zettaport.com [local]) - by mail.i.zettaport.com (OpenSMTPD) with ESMTPA id 869f35b9 - for ; - Fri, 1 Jul 2022 17:32:15 -0400 (EDT) -Date: Fri, 1 Jul 2022 17:32:15 -0400 -From: Josh Rickmar -To: gameoftrees@openbsd.org -Subject: Re: Tag signing with SSH signatures -Message-ID: -References: -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: -List-Help: -List-ID: -List-Owner: -List-Post: -List-Subscribe: -List-Unsubscribe: -X-Loop: gameoftrees@openbsd.org -Precedence: list -Sender: owner-gameoftrees@openbsd.org - -Updated diff with improvements and suggestions from stsp@ and tracey@ -as well as a regress test. - -diff refs/heads/main refs/heads/ssh_sigs -commit - 917d79a766c47414055c6901624816a41f13597b -commit + bccbae8a0342ccf5043ac731e3b2c17135aabc02 -blob - 8dfd844f3da472b6ed040a62acaf85403cbc07ea -blob + 1b45b53a4efff9977dcd3c2e2e33c499adc94533 ---- got/Makefile -+++ got/Makefile -@@ -13,7 +13,7 @@ SRCS= got.c blame.c commit_graph.c delta.c diff.c \ - diff_myers.c diff_output.c diff_output_plain.c \ - diff_output_unidiff.c diff_output_edscript.c \ - diff_patience.c send.c deltify.c pack_create.c dial.c \ -- bloom.c murmurhash2.c ratelimit.c patch.c -+ bloom.c murmurhash2.c ratelimit.c patch.c sigs.c date.c - - MAN = ${PROG}.1 got-worktree.5 git-repository.5 got.conf.5 - -blob - 5f7f00007937a048564e685aac0a8c6b9e98adab -blob + 92561637b53431f406c97459c28b0ff81903a35d ---- got/got.c -+++ got/got.c -@@ -58,6 +58,8 @@ - #include "got_gotconfig.h" - #include "got_dial.h" - #include "got_patch.h" -+#include "got_sigs.h" -+#include "got_date.h" - - #ifndef nitems - #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) -@@ -687,6 +689,76 @@ get_author(char **author, struct got_repository *repo, - } - - static const struct got_error * -+get_allowed_signers(char **allowed_signers, struct got_repository *repo, -+ struct got_worktree *worktree) -+{ -+ const char *got_allowed_signers = NULL; -+ const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; -+ -+ *allowed_signers = NULL; -+ -+ if (worktree) -+ worktree_conf = got_worktree_get_gotconfig(worktree); -+ repo_conf = got_repo_get_gotconfig(repo); -+ -+ /* -+ * Priority of potential author information sources, from most -+ * significant to least significant: -+ * 1) work tree's .got/got.conf file -+ * 2) repository's got.conf file -+ */ -+ -+ if (worktree_conf) -+ got_allowed_signers = got_gotconfig_get_allowed_signers_file( -+ worktree_conf); -+ if (got_allowed_signers == NULL) -+ got_allowed_signers = got_gotconfig_get_allowed_signers_file( -+ repo_conf); -+ -+ if (got_allowed_signers) { -+ *allowed_signers = strdup(got_allowed_signers); -+ if (*allowed_signers == NULL) -+ return got_error_from_errno("strdup"); -+ } -+ return NULL; -+} -+ -+static const struct got_error * -+get_revoked_signers(char **revoked_signers, struct got_repository *repo, -+ struct got_worktree *worktree) -+{ -+ const char *got_revoked_signers = NULL; -+ const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; -+ -+ *revoked_signers = NULL; -+ -+ if (worktree) -+ worktree_conf = got_worktree_get_gotconfig(worktree); -+ repo_conf = got_repo_get_gotconfig(repo); -+ -+ /* -+ * Priority of potential author information sources, from most -+ * significant to least significant: -+ * 1) work tree's .got/got.conf file -+ * 2) repository's got.conf file -+ */ -+ -+ if (worktree_conf) -+ got_revoked_signers = got_gotconfig_get_revoked_signers_file( -+ worktree_conf); -+ if (got_revoked_signers == NULL) -+ got_revoked_signers = got_gotconfig_get_revoked_signers_file( -+ repo_conf); -+ -+ if (got_revoked_signers) { -+ *revoked_signers = strdup(got_revoked_signers); -+ if (*revoked_signers == NULL) -+ return got_error_from_errno("strdup"); -+ } -+ return NULL; -+} -+ -+static const struct got_error * - get_gitconfig_path(char **gitconfig_path) - { - const char *homedir = getenv("HOME"); -@@ -6837,7 +6909,8 @@ usage_tag(void) - { - fprintf(stderr, - "usage: %s tag [-c commit] [-r repository] [-l] " -- "[-m message] name\n", getprogname()); -+ "[-m message] [-s signer_id] name\n", -+ getprogname()); - exit(1); - } - -@@ -6917,12 +6990,14 @@ get_tag_refname(char **refname, const char *tag_name) - } - - static const struct got_error * --list_tags(struct got_repository *repo, const char *tag_name) -+list_tags(struct got_repository *repo, const char *tag_name, int verify_tags, -+ const char *allowed_signers, const char *revoked_signers, int verbosity) - { - static const struct got_error *err = NULL; - struct got_reflist_head refs; - struct got_reflist_entry *re; - char *wanted_refname = NULL; -+ int bad_sigs = 0; - - TAILQ_INIT(&refs); - -@@ -6946,7 +7021,8 @@ list_tags(struct got_repository *repo, const char *tag - const char *refname; - char *refstr, *tagmsg0, *tagmsg, *line, *id_str, *datestr; - char datebuf[26]; -- const char *tagger; -+ const char *tagger, *ssh_sig = NULL; -+ char *sig_msg = NULL; - time_t tagger_time; - struct got_object_id *id; - struct got_tag_object *tag; -@@ -6962,8 +7038,6 @@ list_tags(struct got_repository *repo, const char *tag - err = got_error_from_errno("got_ref_to_str"); - break; - } -- printf("%stag %s %s\n", GOT_COMMIT_SEP_STR, refname, refstr); -- free(refstr); - - err = got_ref_resolve(&id, repo, re->ref); - if (err) -@@ -6996,6 +7070,22 @@ list_tags(struct got_repository *repo, const char *tag - if (err) - break; - } -+ -+ if (verify_tags) { -+ ssh_sig = got_sigs_get_tagmsg_ssh_signature( -+ got_object_tag_get_message(tag)); -+ if (ssh_sig && allowed_signers == NULL) { -+ err = got_error_msg( -+ GOT_ERR_VERIFY_TAG_SIGNATURE, -+ "SSH signature verification requires " -+ "setting allowed_signers in " -+ "got.conf(5)"); -+ break; -+ } -+ } -+ -+ printf("%stag %s %s\n", GOT_COMMIT_SEP_STR, refname, refstr); -+ free(refstr); - printf("from: %s\n", tagger); - datestr = get_datestr(&tagger_time, datebuf); - if (datestr) -@@ -7025,6 +7115,19 @@ list_tags(struct got_repository *repo, const char *tag - } - } - free(id_str); -+ -+ if (ssh_sig) { -+ err = got_sigs_verify_tag_ssh(&sig_msg, tag, ssh_sig, -+ allowed_signers, revoked_signers, verbosity); -+ if (err && err->code == GOT_ERR_BAD_TAG_SIGNATURE) -+ bad_sigs = 1; -+ else if (err) -+ break; -+ printf("signature: %s", sig_msg); -+ free(sig_msg); -+ sig_msg = NULL; -+ } -+ - if (commit) { - err = got_object_commit_get_logmsg(&tagmsg0, commit); - if (err) -@@ -7050,6 +7153,9 @@ list_tags(struct got_repository *repo, const char *tag - done: - got_ref_list_free(&refs); - free(wanted_refname); -+ -+ if (err == NULL && bad_sigs) -+ err = got_error(GOT_ERR_BAD_TAG_SIGNATURE); - return err; - } - -@@ -7098,9 +7204,6 @@ done: - if (fd != -1 && close(fd) == -1 && err == NULL) - err = got_error_from_errno2("close", *tagmsg_path); - -- /* Editor is done; we can now apply unveil(2) */ -- if (err == NULL) -- err = apply_unveil(repo_path, 0, NULL); - if (err) { - free(*tagmsg); - *tagmsg = NULL; -@@ -7110,7 +7213,8 @@ done: - - static const struct got_error * - add_tag(struct got_repository *repo, const char *tagger, -- const char *tag_name, const char *commit_arg, const char *tagmsg_arg) -+ const char *tag_name, const char *commit_arg, const char *tagmsg_arg, -+ const char *key_file, int verbosity) - { - const struct got_error *err = NULL; - struct got_object_id *commit_id = NULL, *tag_id = NULL; -@@ -7166,10 +7270,18 @@ add_tag(struct got_repository *repo, const char *tagge - preserve_tagmsg = 1; - goto done; - } -+ /* Editor is done; we can now apply unveil(2) */ -+ err = got_sigs_apply_unveil(); -+ if (err) -+ goto done; -+ err = apply_unveil(got_repo_get_path(repo), 0, NULL); -+ if (err) -+ goto done; - } - - err = got_object_tag_create(&tag_id, tag_name, commit_id, -- tagger, time(NULL), tagmsg ? tagmsg : tagmsg_arg, repo); -+ tagger, time(NULL), tagmsg ? tagmsg : tagmsg_arg, key_file, repo, -+ verbosity); - if (err) { - if (tagmsg_path) - preserve_tagmsg = 1; -@@ -7223,11 +7335,13 @@ cmd_tag(int argc, char *argv[]) - struct got_worktree *worktree = NULL; - char *cwd = NULL, *repo_path = NULL, *commit_id_str = NULL; - char *gitconfig_path = NULL, *tagger = NULL; -+ char *allowed_signers = NULL, *revoked_signers = NULL; - const char *tag_name = NULL, *commit_id_arg = NULL, *tagmsg = NULL; -- int ch, do_list = 0; -+ int ch, do_list = 0, verify_tags = 0, verbosity = 0; -+ const char *signer_id = NULL; - int *pack_fds = NULL; - -- while ((ch = getopt(argc, argv, "c:m:r:l")) != -1) { -+ while ((ch = getopt(argc, argv, "c:m:r:ls:Vv")) != -1) { - switch (ch) { - case 'c': - commit_id_arg = optarg; -@@ -7245,6 +7359,18 @@ cmd_tag(int argc, char *argv[]) - case 'l': - do_list = 1; - break; -+ case 's': -+ signer_id = optarg; -+ break; -+ case 'V': -+ verify_tags = 1; -+ break; -+ case 'v': -+ if (verbosity < 0) -+ verbosity = 0; -+ else if (verbosity < 3) -+ verbosity++; -+ break; - default: - usage_tag(); - /* NOTREACHED */ -@@ -7305,26 +7431,40 @@ cmd_tag(int argc, char *argv[]) - } - } - -- if (do_list) { -+ if (do_list || verify_tags) { -+ error = got_repo_open(&repo, repo_path, NULL, pack_fds); -+ if (error != NULL) -+ goto done; -+ error = get_allowed_signers(&allowed_signers, repo, worktree); -+ if (error) -+ goto done; -+ error = get_revoked_signers(&revoked_signers, repo, worktree); -+ if (error) -+ goto done; - if (worktree) { - /* Release work tree lock. */ - got_worktree_close(worktree); - worktree = NULL; - } -- error = got_repo_open(&repo, repo_path, NULL, pack_fds); -- if (error != NULL) -- goto done; - -+ /* -+ * Remove "cpath" promise unless needed for signature tmpfile -+ * creation. -+ */ -+ if (verify_tags) -+ got_sigs_apply_unveil(); -+ else { - #ifndef PROFILE -- /* Remove "cpath" promise. */ -- if (pledge("stdio rpath wpath flock proc exec sendfd unveil", -- NULL) == -1) -- err(1, "pledge"); -+ if (pledge("stdio rpath wpath flock proc exec sendfd " -+ "unveil", NULL) == -1) -+ err(1, "pledge"); - #endif -+ } - error = apply_unveil(got_repo_get_path(repo), 1, NULL); - if (error) - goto done; -- error = list_tags(repo, tag_name); -+ error = list_tags(repo, tag_name, verify_tags, allowed_signers, -+ revoked_signers, verbosity); - } else { - error = get_gitconfig_path(&gitconfig_path); - if (error) -@@ -7344,6 +7484,11 @@ cmd_tag(int argc, char *argv[]) - } - - if (tagmsg) { -+ if (signer_id) { -+ error = got_sigs_apply_unveil(); -+ if (error) -+ goto done; -+ } - error = apply_unveil(got_repo_get_path(repo), 0, NULL); - if (error) - goto done; -@@ -7368,7 +7513,8 @@ cmd_tag(int argc, char *argv[]) - } - - error = add_tag(repo, tagger, tag_name, -- commit_id_str ? commit_id_str : commit_id_arg, tagmsg); -+ commit_id_str ? commit_id_str : commit_id_arg, tagmsg, -+ signer_id, verbosity); - } - done: - if (repo) { -@@ -7389,6 +7535,8 @@ done: - free(gitconfig_path); - free(commit_id_str); - free(tagger); -+ free(allowed_signers); -+ free(revoked_signers); - return error; - } - -@@ -12418,22 +12566,6 @@ cat_tree(struct got_object_id *id, struct got_reposito - return err; - } - --static void --format_gmtoff(char *buf, size_t sz, time_t gmtoff) --{ -- long long h, m; -- char sign = '+'; -- -- if (gmtoff < 0) { -- sign = '-'; -- gmtoff = -gmtoff; -- } -- -- h = (long long)gmtoff / 3600; -- m = ((long long)gmtoff - h*3600) / 60; -- snprintf(buf, sz, "%c%02lld%02lld", sign, h, m); --} -- - static const struct got_error * - cat_commit(struct got_object_id *id, struct got_repository *repo, FILE *outfile) - { -@@ -12465,14 +12597,14 @@ cat_commit(struct got_object_id *id, struct got_reposi - fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_PARENT, pid_str); - free(pid_str); - } -- format_gmtoff(gmtoff, sizeof(gmtoff), -+ got_date_format_gmtoff(gmtoff, sizeof(gmtoff), - got_object_commit_get_author_gmtoff(commit)); - fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_AUTHOR, - got_object_commit_get_author(commit), - (long long)got_object_commit_get_author_time(commit), - gmtoff); - -- format_gmtoff(gmtoff, sizeof(gmtoff), -+ got_date_format_gmtoff(gmtoff, sizeof(gmtoff), - got_object_commit_get_committer_gmtoff(commit)); - fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_COMMITTER, - got_object_commit_get_author(commit), -@@ -12531,7 +12663,7 @@ cat_tag(struct got_object_id *id, struct got_repositor - fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TAG, - got_object_tag_get_name(tag)); - -- format_gmtoff(gmtoff, sizeof(gmtoff), -+ got_date_format_gmtoff(gmtoff, sizeof(gmtoff), - got_object_tag_get_tagger_gmtoff(tag)); - fprintf(outfile, "%s%s %lld %s\n", GOT_TAG_LABEL_TAGGER, - got_object_tag_get_tagger(tag), -blob - 781133bbc9837ad999231c521ae9da3239c0232b -blob + bf9729a9216142455edfd253fb05cd98c0b4b1f1 ---- gotadmin/Makefile -+++ gotadmin/Makefile -@@ -8,7 +8,8 @@ SRCS= gotadmin.c \ - inflate.c lockfile.c object.c object_cache.c object_create.c \ - object_idset.c object_parse.c opentemp.c pack.c pack_create.c \ - path.c privsep.c reference.c repository.c repository_admin.c \ -- worktree_open.c sha1.c bloom.c murmurhash2.c ratelimit.c -+ worktree_open.c sha1.c bloom.c murmurhash2.c ratelimit.c \ -+ sigs.c buf.c date.c - MAN = ${PROG}.1 - - CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib -blob - aa54a17419d407bb09bbc7b00af392c74aa8801f -blob + 948b9b8fc5270878f0eb2aa61a579197663e4827 ---- gotweb/Makefile -+++ gotweb/Makefile -@@ -15,7 +15,7 @@ SRCS = gotweb.c parse.y blame.c commit_graph.c delta. - diff_main.c diff_atomize_text.c diff_myers.c diff_output.c \ - diff_output_plain.c diff_output_unidiff.c \ - diff_output_edscript.c diff_patience.c \ -- bloom.c murmurhash2.c -+ bloom.c murmurhash2.c sigs.c date.c - MAN = ${PROG}.conf.5 ${PROG}.8 - - CPPFLAGS += -I${.CURDIR}/../include -I${.CURDIR}/../lib -I${.CURDIR} \ -blob - /dev/null -blob + b005c2c948e0b4b35147550b1b23fef240ddf8b4 (mode 644) ---- /dev/null -+++ include/got_date.h -@@ -0,0 +1,18 @@ -+/* -+ * Copyright (c) 2022 Josh Rickmar -+ * -+ * Permission to use, copy, modify, and distribute this software for any -+ * purpose with or without fee is hereby granted, provided that the above -+ * copyright notice and this permission notice appear in all copies. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ */ -+ -+void -+got_date_format_gmtoff(char *, size_t, time_t); -blob - 22a9264b9f8d0c0b20b48895dd8ea59708e61d48 -blob + 4bfaed588e2d81e1b0578a939dd96553de6bc11b ---- include/got_error.h -+++ include/got_error.h -@@ -169,6 +169,8 @@ - #define GOT_ERR_PATCH_FAILED 151 - #define GOT_ERR_FILEIDX_DUP_ENTRY 152 - #define GOT_ERR_PIN_PACK 153 -+#define GOT_ERR_BAD_TAG_SIGNATURE 154 -+#define GOT_ERR_VERIFY_TAG_SIGNATURE 155 - - struct got_error { - int code; -blob - 3dbe5d7d43cf45ec0e7997d43f266c3ce0c9fcbe -blob + 26e15d93b91bc42ee028fa8ecf60a8d1ac4dfdc9 ---- include/got_gotconfig.h -+++ include/got_gotconfig.h -@@ -29,3 +29,19 @@ const char *got_gotconfig_get_author(const struct got_ - */ - void got_gotconfig_get_remotes(int *, const struct got_remote_repo **, - const struct got_gotconfig *); -+ -+/* -+ * Obtain the filename of the allowed signers file. -+ * Returns NULL if no configuration file is found or no allowed signers file -+ * is configured. -+ */ -+const char * -+got_gotconfig_get_allowed_signers_file(const struct got_gotconfig *); -+ -+/* -+ * Obtain the filename of the revoked signers file. -+ * Returns NULL if no configuration file is found or no revoked signers file -+ * is configured. -+ */ -+const char * -+got_gotconfig_get_revoked_signers_file(const struct got_gotconfig *); -blob - a8d0318ceaa7152627e8c8718ba039f8517bc3e4 -blob + 1cd6f349912d3e03ebbdccfd4beeeb54663af7fb ---- include/got_object.h -+++ include/got_object.h -@@ -351,4 +351,4 @@ const struct got_error *got_object_commit_add_parent(s - /* Create a new tag object in the repository. */ - const struct got_error *got_object_tag_create(struct got_object_id **, - const char *, struct got_object_id *, const char *, -- time_t, const char *, struct got_repository *); -+ time_t, const char *, const char *, struct got_repository *, int verbosity); -blob - /dev/null -blob + 204a6265963d6dcbf4d6f3de13f4bdbafaafc6fa (mode 644) ---- /dev/null -+++ include/got_sigs.h -@@ -0,0 +1,28 @@ -+/* -+ * Copyright (c) 2022 Josh Rickmar -+ * -+ * Permission to use, copy, modify, and distribute this software for any -+ * purpose with or without fee is hereby granted, provided that the above -+ * copyright notice and this permission notice appear in all copies. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ */ -+ -+const struct got_error * -+got_sigs_apply_unveil(void); -+ -+const struct got_error * -+got_sigs_sign_tag_ssh(pid_t *, int *, int *, const char *, int); -+ -+const char * -+got_sigs_get_tagmsg_ssh_signature(const char *); -+ -+const struct got_error * -+got_sigs_verify_tag_ssh(char **, struct got_tag_object *, const char *, -+ const char *, const char *, int); -blob - /dev/null -blob + 815b291ce868d18136ce8f45fa2f890b6f6c08f9 (mode 644) ---- /dev/null -+++ lib/date.c -@@ -0,0 +1,35 @@ -+/* -+ * Copyright (c) 2022 Josh Rickmar -+ * -+ * Permission to use, copy, modify, and distribute this software for any -+ * purpose with or without fee is hereby granted, provided that the above -+ * copyright notice and this permission notice appear in all copies. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ */ -+ -+#include -+ -+#include "got_date.h" -+ -+void -+got_date_format_gmtoff(char *buf, size_t sz, time_t gmtoff) -+{ -+ long long h, m; -+ char sign = '+'; -+ -+ if (gmtoff < 0) { -+ sign = '-'; -+ gmtoff = -gmtoff; -+ } -+ -+ h = (long long)gmtoff / 3600; -+ m = ((long long)gmtoff - h*3600) / 60; -+ snprintf(buf, sz, "%c%02lld%02lld", sign, h, m); -+} -blob - 3ffd653ef429fab490d06ba6a953185254e7c117 -blob + 3c092e61bab70845c184eb10f359eb6df3ee01ce ---- lib/error.c -+++ lib/error.c -@@ -217,6 +217,8 @@ static const struct got_error got_errors[] = { - { GOT_ERR_PATCH_FAILED, "patch failed to apply" }, - { GOT_ERR_FILEIDX_DUP_ENTRY, "duplicate file index entry" }, - { GOT_ERR_PIN_PACK, "could not pin pack file" }, -+ { GOT_ERR_BAD_TAG_SIGNATURE, "invalid tag signature" }, -+ { GOT_ERR_VERIFY_TAG_SIGNATURE, "cannot verify signature" }, - }; - - static struct got_custom_error { -blob - 5e02aa1efeff0dd226e617da410a4663d8376d9a -blob + 39337ed4d9cbe7dfa5939b3f4dcb38793ccddfbd ---- lib/got_lib_gotconfig.h -+++ lib/got_lib_gotconfig.h -@@ -20,6 +20,8 @@ struct got_gotconfig { - char *author; - int nremotes; - struct got_remote_repo *remotes; -+ char *allowed_signers_file; -+ char *revoked_signers_file; - }; - - const struct got_error *got_gotconfig_read(struct got_gotconfig **, -blob - 6ffe646e98676cf9a0d19fe3ad27f3e63ab04fcc -blob + dac4ab973b68243e262fd1ae6482fffb6dc2bc57 ---- lib/got_lib_privsep.h -+++ lib/got_lib_privsep.h -@@ -172,6 +172,8 @@ enum got_imsg_type { - /* Messages related to gotconfig files. */ - GOT_IMSG_GOTCONFIG_PARSE_REQUEST, - GOT_IMSG_GOTCONFIG_AUTHOR_REQUEST, -+ GOT_IMSG_GOTCONFIG_ALLOWEDSIGNERS_REQUEST, -+ GOT_IMSG_GOTCONFIG_REVOKEDSIGNERS_REQUEST, - GOT_IMSG_GOTCONFIG_REMOTES_REQUEST, - GOT_IMSG_GOTCONFIG_INT_VAL, - GOT_IMSG_GOTCONFIG_STR_VAL, -@@ -760,6 +762,10 @@ const struct got_error *got_privsep_recv_gitconfig_rem - const struct got_error *got_privsep_send_gotconfig_parse_req(struct imsgbuf *, - int); - const struct got_error *got_privsep_send_gotconfig_author_req(struct imsgbuf *); -+const struct got_error *got_privsep_send_gotconfig_allowed_signers_req( -+ struct imsgbuf *); -+const struct got_error *got_privsep_send_gotconfig_revoked_signers_req( -+ struct imsgbuf *); - const struct got_error *got_privsep_send_gotconfig_remotes_req( - struct imsgbuf *); - const struct got_error *got_privsep_recv_gotconfig_str(char **, -blob - 5b602c9f5513aee64b98ca608535d5b85280ec42 -blob + 7fae8306f7aa444e25b71f0a95f8f151ec324a7f ---- lib/gotconfig.c -+++ lib/gotconfig.c -@@ -101,6 +101,24 @@ got_gotconfig_read(struct got_gotconfig **conf, const - if (err) - goto done; - -+ err = got_privsep_send_gotconfig_allowed_signers_req(ibuf); -+ if (err) -+ goto done; -+ -+ err = got_privsep_recv_gotconfig_str(&(*conf)->allowed_signers_file, -+ ibuf); -+ if (err) -+ goto done; -+ -+ err = got_privsep_send_gotconfig_revoked_signers_req(ibuf); -+ if (err) -+ goto done; -+ -+ err = got_privsep_recv_gotconfig_str(&(*conf)->revoked_signers_file, -+ ibuf); -+ if (err) -+ goto done; -+ - err = got_privsep_send_gotconfig_remotes_req(ibuf); - if (err) - goto done; -@@ -158,3 +176,15 @@ got_gotconfig_get_remotes(int *nremotes, const struct - *nremotes = conf->nremotes; - *remotes = conf->remotes; - } -+ -+const char * -+got_gotconfig_get_allowed_signers_file(const struct got_gotconfig *conf) -+{ -+ return conf->allowed_signers_file; -+} -+ -+const char * -+got_gotconfig_get_revoked_signers_file(const struct got_gotconfig *conf) -+{ -+ return conf->revoked_signers_file; -+} -blob - 5036de1b9a6b491a1fc7c0358a03dcd9574f6cf3 -blob + 8f33d6ba0309e1d8f43ef3b0c35b661bd6045211 ---- lib/object_create.c -+++ lib/object_create.c -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -35,6 +36,7 @@ - #include "got_repository.h" - #include "got_opentemp.h" - #include "got_path.h" -+#include "got_sigs.h" - - #include "got_lib_sha1.h" - #include "got_lib_deflate.h" -@@ -45,6 +47,8 @@ - - #include "got_lib_object_create.h" - -+#include "buf.h" -+ - #ifndef nitems - #define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) - #endif -@@ -608,19 +612,21 @@ done: - const struct got_error * - got_object_tag_create(struct got_object_id **id, - const char *tag_name, struct got_object_id *object_id, const char *tagger, -- time_t tagger_time, const char *tagmsg, struct got_repository *repo) -+ time_t tagger_time, const char *tagmsg, const char *key_file, -+ struct got_repository *repo, int verbosity) - { - const struct got_error *err = NULL; - SHA1_CTX sha1_ctx; - char *header = NULL; - char *tag_str = NULL, *tagger_str = NULL; - char *id_str = NULL, *obj_str = NULL, *type_str = NULL; -- size_t headerlen, len = 0, n; -+ size_t headerlen, len = 0, sig_len = 0, n; - FILE *tagfile = NULL; - off_t tagsize = 0; - char *msg0 = NULL, *msg; - const char *obj_type_str; - int obj_type; -+ BUF *buf = NULL; - - *id = NULL; - -@@ -681,9 +687,79 @@ got_object_tag_create(struct got_object_id **id, - while (isspace((unsigned char)msg[0])) - msg++; - -+ if (key_file) { -+ FILE *out; -+ pid_t pid; -+ size_t len; -+ int in_fd, out_fd; -+ int status; -+ -+ err = buf_alloc(&buf, 0); -+ if (err) -+ goto done; -+ -+ /* signed message */ -+ err = buf_puts(&len, buf, obj_str); -+ if (err) -+ goto done; -+ err = buf_puts(&len, buf, type_str); -+ if (err) -+ goto done; -+ err = buf_puts(&len, buf, tag_str); -+ if (err) -+ goto done; -+ err = buf_puts(&len, buf, tagger_str); -+ if (err) -+ goto done; -+ err = buf_putc(buf, '\n'); -+ if (err) -+ goto done; -+ err = buf_puts(&len, buf, msg); -+ if (err) -+ goto done; -+ err = buf_putc(buf, '\n'); -+ if (err) -+ goto done; -+ -+ err = got_sigs_sign_tag_ssh(&pid, &in_fd, &out_fd, key_file, -+ verbosity); -+ if (err) -+ goto done; -+ if (buf_write_fd(buf, in_fd) == -1) { -+ err = got_error_from_errno("write"); -+ goto done; -+ } -+ if (close(in_fd) == -1) { -+ err = got_error_from_errno("close"); -+ goto done; -+ } -+ -+ if (waitpid(pid, &status, 0) == -1) { -+ err = got_error_from_errno("waitpid"); -+ goto done; -+ } -+ -+ out = fdopen(out_fd, "r"); -+ if (out == NULL) { -+ err = got_error_from_errno("fdopen"); -+ goto done; -+ } -+ buf_empty(buf); -+ err = buf_load(&buf, out); -+ if (err) -+ goto done; -+ sig_len = buf_len(buf) + 1; -+ err = buf_putc(buf, '\0'); -+ if (err) -+ goto done; -+ if (close(out_fd) == -1) { -+ err = got_error_from_errno("close"); -+ goto done; -+ } -+ } -+ - len = strlen(obj_str) + strlen(type_str) + strlen(tag_str) + -- strlen(tagger_str) + 1 + strlen(msg) + 1; -- -+ strlen(tagger_str) + 1 + strlen(msg) + 1 + sig_len; - if (asprintf(&header, "%s %zd", GOT_OBJ_LABEL_TAG, len) == -1) { - err = got_error_from_errno("asprintf"); - goto done; -@@ -764,6 +840,17 @@ got_object_tag_create(struct got_object_id **id, - } - tagsize += n; - -+ if (key_file && buf_len(buf) > 0) { -+ len = buf_len(buf); -+ SHA1Update(&sha1_ctx, buf_get(buf), len); -+ n = fwrite(buf_get(buf), 1, len, tagfile); -+ if (n != len) { -+ err = got_ferror(tagfile, GOT_ERR_IO); -+ goto done; -+ } -+ tagsize += n; -+ } -+ - *id = malloc(sizeof(**id)); - if (*id == NULL) { - err = got_error_from_errno("malloc"); -@@ -783,6 +870,8 @@ done: - free(header); - free(obj_str); - free(tagger_str); -+ if (buf) -+ buf_release(buf); - if (tagfile && fclose(tagfile) == EOF && err == NULL) - err = got_error_from_errno("fclose"); - if (err) { -blob - c0bdac7221a79c5ec97d1728e862406152d51eb9 -blob + 07acf70c2c9103549d8dd9f40e6a173d0bb20401 ---- lib/privsep.c -+++ lib/privsep.c -@@ -2365,6 +2365,28 @@ got_privsep_send_gotconfig_author_req(struct imsgbuf * - } - - const struct got_error * -+got_privsep_send_gotconfig_allowed_signers_req(struct imsgbuf *ibuf) -+{ -+ if (imsg_compose(ibuf, -+ GOT_IMSG_GOTCONFIG_ALLOWEDSIGNERS_REQUEST, 0, 0, -1, NULL, 0) == -1) -+ return got_error_from_errno("imsg_compose " -+ "GOTCONFIG_ALLOWEDSIGNERS_REQUEST"); -+ -+ return flush_imsg(ibuf); -+} -+ -+const struct got_error * -+got_privsep_send_gotconfig_revoked_signers_req(struct imsgbuf *ibuf) -+{ -+ if (imsg_compose(ibuf, -+ GOT_IMSG_GOTCONFIG_REVOKEDSIGNERS_REQUEST, 0, 0, -1, NULL, 0) == -1) -+ return got_error_from_errno("imsg_compose " -+ "GOTCONFIG_REVOKEDSIGNERS_REQUEST"); -+ -+ return flush_imsg(ibuf); -+} -+ -+const struct got_error * - got_privsep_send_gotconfig_remotes_req(struct imsgbuf *ibuf) - { - if (imsg_compose(ibuf, -blob - /dev/null -blob + 0b04e3f959ed7aab07534ee9bb5cb4a63e0dd93f (mode 644) ---- /dev/null -+++ lib/sigs.c -@@ -0,0 +1,407 @@ -+/* -+ * Copyright (c) 2022 Josh Rickmar -+ * -+ * Permission to use, copy, modify, and distribute this software for any -+ * purpose with or without fee is hereby granted, provided that the above -+ * copyright notice and this permission notice appear in all copies. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "got_error.h" -+#include "got_date.h" -+#include "got_object.h" -+#include "got_opentemp.h" -+ -+#include "got_sigs.h" -+ -+#include "buf.h" -+ -+#ifndef MIN -+#define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) -+#endif -+ -+#ifndef nitems -+#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) -+#endif -+ -+#ifndef GOT_TAG_PATH_SSH_KEYGEN -+#define GOT_TAG_PATH_SSH_KEYGEN "/usr/bin/ssh-keygen" -+#endif -+ -+#ifndef GOT_TAG_PATH_SIGNIFY -+#define GOT_TAG_PATH_SIGNIFY "/usr/bin/signify" -+#endif -+ -+const struct got_error * -+got_sigs_apply_unveil() -+{ -+ if (unveil(GOT_TAG_PATH_SSH_KEYGEN, "x") != 0) { -+ return got_error_from_errno2("unveil", -+ GOT_TAG_PATH_SSH_KEYGEN); -+ } -+ if (unveil(GOT_TAG_PATH_SIGNIFY, "x") != 0) { -+ return got_error_from_errno2("unveil", -+ GOT_TAG_PATH_SIGNIFY); -+ } -+ -+ return NULL; -+} -+ -+const struct got_error * -+got_sigs_sign_tag_ssh(pid_t *newpid, int *in_fd, int *out_fd, -+ const char* key_file, int verbosity) -+{ -+ const struct got_error *error = NULL; -+ int pid, in_pfd[2], out_pfd[2]; -+ const char* argv[11]; -+ int i = 0, j; -+ -+ *newpid = -1; -+ *in_fd = -1; -+ *out_fd = -1; -+ -+ argv[i++] = GOT_TAG_PATH_SSH_KEYGEN; -+ argv[i++] = "-Y"; -+ argv[i++] = "sign"; -+ argv[i++] = "-f"; -+ argv[i++] = key_file; -+ argv[i++] = "-n"; -+ argv[i++] = "git"; -+ if (verbosity <= 0) { -+ argv[i++] = "-q"; -+ } else { -+ /* ssh(1) allows up to 3 "-v" options. */ -+ for (j = 0; j < MIN(3, verbosity); j++) -+ argv[i++] = "-v"; -+ } -+ argv[i++] = NULL; -+ assert(i <= nitems(argv)); -+ -+ if (pipe2(in_pfd, 0) == -1) -+ return got_error_from_errno("pipe2"); -+ if (pipe2(out_pfd, 0) == -1) -+ return got_error_from_errno("pipe2"); -+ -+ pid = fork(); -+ if (pid == -1) { -+ error = got_error_from_errno("fork"); -+ close(in_pfd[0]); -+ close(in_pfd[1]); -+ close(out_pfd[0]); -+ close(out_pfd[1]); -+ return error; -+ } else if (pid == 0) { -+ if (close(in_pfd[1]) == -1) -+ err(1, "close"); -+ if (close(out_pfd[1]) == -1) -+ err(1, "close"); -+ if (dup2(in_pfd[0], 0) == -1) -+ err(1, "dup2"); -+ if (dup2(out_pfd[0], 1) == -1) -+ err(1, "dup2"); -+ if (execv(GOT_TAG_PATH_SSH_KEYGEN, (char **const)argv) == -1) -+ err(1, "execv"); -+ abort(); /* not reached */ -+ } -+ if (close(in_pfd[0]) == -1) -+ return got_error_from_errno("close"); -+ if (close(out_pfd[0]) == -1) -+ return got_error_from_errno("close"); -+ *newpid = pid; -+ *in_fd = in_pfd[1]; -+ *out_fd = out_pfd[1]; -+ return NULL; -+} -+ -+static char * -+signer_identity(const char *tagger) -+{ -+ char *lt, *gt; -+ -+ lt = strstr(tagger, " <"); -+ gt = strrchr(tagger, '>'); -+ if (lt && gt && lt+1 < gt) -+ return strndup(lt+2, gt-lt-2); -+ return NULL; -+} -+ -+static const char* BEGIN_SSH_SIG = "-----BEGIN SSH SIGNATURE-----\n"; -+static const char* END_SSH_SIG = "-----END SSH SIGNATURE-----\n"; -+ -+const char * -+got_sigs_get_tagmsg_ssh_signature(const char *tagmsg) -+{ -+ const char *s = tagmsg, *begin = NULL, *end = NULL; -+ -+ while ((s = strstr(s, BEGIN_SSH_SIG)) != NULL) { -+ begin = s; -+ s += strlen(BEGIN_SSH_SIG); -+ } -+ if (begin) -+ end = strstr(begin+strlen(BEGIN_SSH_SIG), END_SSH_SIG); -+ if (end == NULL) -+ return NULL; -+ return (end[strlen(END_SSH_SIG)] == '\0') ? begin : NULL; -+} -+ -+static const struct got_error * -+got_tag_write_signed_data(BUF *buf, struct got_tag_object *tag, -+ const char *start_sig) -+{ -+ const struct got_error *err = NULL; -+ struct got_object_id *id; -+ char *id_str = NULL; -+ char *tagger = NULL; -+ const char *tagmsg; -+ char gmtoff[6]; -+ size_t len; -+ -+ id = got_object_tag_get_object_id(tag); -+ err = got_object_id_str(&id_str, id); -+ if (err) -+ goto done; -+ -+ const char *type_label = NULL; -+ switch (got_object_tag_get_object_type(tag)) { -+ case GOT_OBJ_TYPE_BLOB: -+ type_label = GOT_OBJ_LABEL_BLOB; -+ break; -+ case GOT_OBJ_TYPE_TREE: -+ type_label = GOT_OBJ_LABEL_TREE; -+ break; -+ case GOT_OBJ_TYPE_COMMIT: -+ type_label = GOT_OBJ_LABEL_COMMIT; -+ break; -+ case GOT_OBJ_TYPE_TAG: -+ type_label = GOT_OBJ_LABEL_TAG; -+ break; -+ default: -+ break; -+ } -+ got_date_format_gmtoff(gmtoff, sizeof(gmtoff), -+ got_object_tag_get_tagger_gmtoff(tag)); -+ if (asprintf(&tagger, "%s %lld %s", got_object_tag_get_tagger(tag), -+ got_object_tag_get_tagger_time(tag), gmtoff) == -1) { -+ err = got_error_from_errno("asprintf"); -+ goto done; -+ } -+ -+ err = buf_puts(&len, buf, GOT_TAG_LABEL_OBJECT); -+ if (err) -+ goto done; -+ err = buf_puts(&len, buf, id_str); -+ if (err) -+ goto done; -+ err = buf_putc(buf, '\n'); -+ if (err) -+ goto done; -+ err = buf_puts(&len, buf, GOT_TAG_LABEL_TYPE); -+ if (err) -+ goto done; -+ err = buf_puts(&len, buf, type_label); -+ if (err) -+ goto done; -+ err = buf_putc(buf, '\n'); -+ if (err) -+ goto done; -+ err = buf_puts(&len, buf, GOT_TAG_LABEL_TAG); -+ if (err) -+ goto done; -+ err = buf_puts(&len, buf, got_object_tag_get_name(tag)); -+ if (err) -+ goto done; -+ err = buf_putc(buf, '\n'); -+ if (err) -+ goto done; -+ err = buf_puts(&len, buf, GOT_TAG_LABEL_TAGGER); -+ if (err) -+ goto done; -+ err = buf_puts(&len, buf, tagger); -+ if (err) -+ goto done; -+ err = buf_puts(&len, buf, "\n"); -+ if (err) -+ goto done; -+ tagmsg = got_object_tag_get_message(tag); -+ err = buf_append(&len, buf, tagmsg, start_sig-tagmsg); -+ if (err) -+ goto done; -+ -+done: -+ free(id_str); -+ free(tagger); -+ return err; -+} -+ -+const struct got_error * -+got_sigs_verify_tag_ssh(char **msg, struct got_tag_object *tag, -+ const char *start_sig, const char* allowed_signers, const char* revoked, -+ int verbosity) -+{ -+ const struct got_error *error = NULL; -+ const char* argv[17]; -+ int pid, status, in_pfd[2], out_pfd[2]; -+ char* parsed_identity = NULL; -+ const char *identity; -+ char* tmppath = NULL; -+ FILE *tmpsig, *out = NULL; -+ BUF *buf; -+ int i = 0, j; -+ -+ *msg = NULL; -+ -+ error = got_opentemp_named(&tmppath, &tmpsig, -+ GOT_TMPDIR_STR "/got-tagsig"); -+ if (error) -+ goto done; -+ -+ identity = got_object_tag_get_tagger(tag); -+ parsed_identity = signer_identity(identity); -+ if (parsed_identity != NULL) -+ identity = parsed_identity; -+ -+ if (fputs(start_sig, tmpsig) == EOF) { -+ error = got_error_from_errno("fputs"); -+ goto done; -+ } -+ if (fflush(tmpsig) == EOF) { -+ error = got_error_from_errno("fflush"); -+ goto done; -+ } -+ -+ error = buf_alloc(&buf, 0); -+ if (error) -+ goto done; -+ error = got_tag_write_signed_data(buf, tag, start_sig); -+ if (error) -+ goto done; -+ -+ argv[i++] = GOT_TAG_PATH_SSH_KEYGEN; -+ argv[i++] = "-Y"; -+ argv[i++] = "verify"; -+ argv[i++] = "-f"; -+ argv[i++] = allowed_signers; -+ argv[i++] = "-I"; -+ argv[i++] = identity; -+ argv[i++] = "-n"; -+ argv[i++] = "git"; -+ argv[i++] = "-s"; -+ argv[i++] = tmppath; -+ if (revoked) { -+ argv[i++] = "-r"; -+ argv[i++] = revoked; -+ } -+ if (verbosity > 0) { -+ /* ssh(1) allows up to 3 "-v" options. */ -+ for (j = 0; j < MIN(3, verbosity); j++) -+ argv[i++] = "-v"; -+ } -+ argv[i++] = NULL; -+ assert(i <= nitems(argv)); -+ -+ if (pipe2(in_pfd, 0) == -1) { -+ error = got_error_from_errno("pipe2"); -+ goto done; -+ } -+ if (pipe2(out_pfd, 0) == -1) { -+ error = got_error_from_errno("pipe2"); -+ goto done; -+ } -+ -+ pid = fork(); -+ if (pid == -1) { -+ error = got_error_from_errno("fork"); -+ close(in_pfd[0]); -+ close(in_pfd[1]); -+ close(out_pfd[0]); -+ close(out_pfd[1]); -+ return error; -+ } else if (pid == 0) { -+ if (close(in_pfd[1]) == -1) -+ err(1, "close"); -+ if (close(out_pfd[1]) == -1) -+ err(1, "close"); -+ if (dup2(in_pfd[0], 0) == -1) -+ err(1, "dup2"); -+ if (dup2(out_pfd[0], 1) == -1) -+ err(1, "dup2"); -+ if (execv(GOT_TAG_PATH_SSH_KEYGEN, (char **const)argv) == -1) -+ err(1, "execv"); -+ abort(); /* not reached */ -+ } -+ if (close(in_pfd[0]) == -1) { -+ error = got_error_from_errno("close"); -+ goto done; -+ } -+ if (close(out_pfd[0]) == -1) { -+ error = got_error_from_errno("close"); -+ goto done; -+ } -+ if (buf_write_fd(buf, in_pfd[1]) == -1) { -+ error = got_error_from_errno("write"); -+ goto done; -+ } -+ if (close(in_pfd[1]) == -1) { -+ error = got_error_from_errno("close"); -+ goto done; -+ } -+ if (waitpid(pid, &status, 0) == -1) { -+ error = got_error_from_errno("waitpid"); -+ goto done; -+ } -+ if (!WIFEXITED(status)) { -+ error = got_error(GOT_ERR_BAD_TAG_SIGNATURE); -+ goto done; -+ } -+ -+ out = fdopen(out_pfd[1], "r"); -+ if (out == NULL) { -+ error = got_error_from_errno("fdopen"); -+ goto done; -+ } -+ error = buf_load(&buf, out); -+ if (error) -+ goto done; -+ error = buf_putc(buf, '\0'); -+ if (error) -+ goto done; -+ if (close(out_pfd[1]) == -1) { -+ error = got_error_from_errno("close"); -+ goto done; -+ } -+ out = NULL; -+ *msg = buf_get(buf); -+ if (WEXITSTATUS(status) != 0) -+ error = got_error(GOT_ERR_BAD_TAG_SIGNATURE); -+ -+done: -+ free(parsed_identity); -+ free(tmppath); -+ if (tmpsig && fclose(tmpsig) == EOF && error == NULL) -+ error = got_error_from_errno("fclose"); -+ if (out && fclose(out) == EOF && error == NULL) -+ error = got_error_from_errno("fclose"); -+ return error; -+} -blob - aa2c97552358174249a7361aba78c785626d6b7f -blob + be0d93073a8d7779e487b6a2d12bad1e6c9721d4 ---- libexec/got-read-gotconfig/got-read-gotconfig.c -+++ libexec/got-read-gotconfig/got-read-gotconfig.c -@@ -548,6 +548,24 @@ main(int argc, char *argv[]) - err = send_gotconfig_str(&ibuf, - gotconfig->author ? gotconfig->author : ""); - break; -+ case GOT_IMSG_GOTCONFIG_ALLOWEDSIGNERS_REQUEST: -+ if (gotconfig == NULL) { -+ err = got_error(GOT_ERR_PRIVSEP_MSG); -+ break; -+ } -+ err = send_gotconfig_str(&ibuf, -+ gotconfig->allowed_signers_file ? -+ gotconfig->allowed_signers_file : ""); -+ break; -+ case GOT_IMSG_GOTCONFIG_REVOKEDSIGNERS_REQUEST: -+ if (gotconfig == NULL) { -+ err = got_error(GOT_ERR_PRIVSEP_MSG); -+ break; -+ } -+ err = send_gotconfig_str(&ibuf, -+ gotconfig->revoked_signers_file ? -+ gotconfig->revoked_signers_file : ""); -+ break; - case GOT_IMSG_GOTCONFIG_REMOTES_REQUEST: - if (gotconfig == NULL) { - err = got_error(GOT_ERR_PRIVSEP_MSG); -blob - 1ce499222101a45de399bd433825c767df869d91 -blob + 504e691250732f7b2baee47695fc1794127b2adb ---- libexec/got-read-gotconfig/gotconfig.h -+++ libexec/got-read-gotconfig/gotconfig.h -@@ -1,4 +1,5 @@ - /* -+ * Copyright (c) 2022 Josh Rickmar - * Copyright (c) 2020, 2021 Tracey Emery - * Copyright (c) 2020 Stefan Sperling - * -@@ -66,6 +67,8 @@ struct gotconfig { - char *author; - struct gotconfig_remote_repo_list remotes; - int nremotes; -+ char *allowed_signers_file; -+ char *revoked_signers_file; - }; - - /* -blob - b9a0bd38cabe5d893cbbb04c482578a895a094ed -blob + 85fc623c3bd3ebda367919af6ac405ae817a88fc ---- libexec/got-read-gotconfig/parse.y -+++ libexec/got-read-gotconfig/parse.y -@@ -99,7 +99,8 @@ typedef struct { - - %token ERROR - %token REMOTE REPOSITORY SERVER PORT PROTOCOL MIRROR_REFERENCES BRANCH --%token AUTHOR FETCH_ALL_BRANCHES REFERENCE FETCH SEND -+%token AUTHOR ALLOWED_SIGNERS REVOKED_SIGNERS FETCH_ALL_BRANCHES REFERENCE -+%token FETCH SEND - %token STRING - %token NUMBER - %type boolean portplain -@@ -113,6 +114,7 @@ grammar : /* empty */ - | grammar '\n' - | grammar author '\n' - | grammar remote '\n' -+ | grammar allowed_signers '\n' - ; - boolean : STRING { - if (strcasecmp($1, "true") == 0 || -@@ -306,6 +308,14 @@ author : AUTHOR STRING { - gotconfig.author = $2; - } - ; -+allowed_signers : ALLOWED_SIGNERS STRING { -+ gotconfig.allowed_signers_file = $2; -+ } -+ ; -+revoked_signers : REVOKED_SIGNERS STRING { -+ gotconfig.revoked_signers_file = $2; -+ } -+ ; - optnl : '\n' optnl - | /* empty */ - ; -@@ -354,6 +364,7 @@ lookup(char *s) - { - /* This has to be sorted always. */ - static const struct keywords keywords[] = { -+ {"allowed_signers", ALLOWED_SIGNERS}, - {"author", AUTHOR}, - {"branch", BRANCH}, - {"fetch", FETCH}, -@@ -364,6 +375,7 @@ lookup(char *s) - {"reference", REFERENCE}, - {"remote", REMOTE}, - {"repository", REPOSITORY}, -+ {"revoked_signers", REVOKED_SIGNERS}, - {"send", SEND}, - {"server", SERVER}, - }; -@@ -791,6 +803,8 @@ gotconfig_free(struct gotconfig *conf) - struct gotconfig_remote_repo *remote; - - free(conf->author); -+ free(conf->allowed_signers_file); -+ free(conf->revoked_signers_file); - while (!TAILQ_EMPTY(&conf->remotes)) { - remote = TAILQ_FIRST(&conf->remotes); - TAILQ_REMOVE(&conf->remotes, remote, entry); -blob - 53325e40ea937187e8814d7b18dd3a6a2f5c40f5 -blob + b39af2be74c1e13b37e5bb89219e62eed8046e23 ---- regress/cmdline/tag.sh -+++ regress/cmdline/tag.sh -@@ -257,7 +257,168 @@ test_tag_list_lightweight() { - test_done "$testroot" "$ret" - } - -+test_tag_create_ssh_signed() { -+ local testroot=`test_init tag_create` -+ local commit_id=`git_show_head $testroot/repo` -+ local tag=1.0.0 -+ local tag2=2.0.0 -+ -+ ssh-keygen -q -N '' -t ed25519 -f $testroot/id_ed25519 -+ ret=$? -+ if [ $ret -ne 0 ]; then -+ echo "ssh-keygen failed unexpectedly" -+ test_done "$testroot" "$ret" -+ return 1 -+ fi -+ touch $testroot/allowed_signers -+ echo "allowed_signers \"$testroot/allowed_signers\"" > \ -+ $testroot/repo/.git/got.conf -+ -+ # Create a signed tag based on repository's HEAD reference -+ got tag -s $testroot/id_ed25519 -m 'test' -r $testroot/repo -c HEAD \ -+ $tag > $testroot/stdout -+ ret=$? -+ if [ $ret -ne 0 ]; then -+ echo "got tag command failed unexpectedly" -+ test_done "$testroot" "$ret" -+ return 1 -+ fi -+ -+ tag_id=`got ref -r $testroot/repo -l \ -+ | grep "^refs/tags/$tag" | tr -d ' ' | cut -d: -f2` -+ echo "Created tag $tag_id" > $testroot/stdout.expected -+ cmp -s $testroot/stdout $testroot/stdout.expected -+ ret=$? -+ if [ $ret -ne 0 ]; then -+ diff -u $testroot/stdout.expected $testroot/stdout -+ test_done "$testroot" "$ret" -+ return 1 -+ fi -+ -+ # Ensure validation fails when the key is not allowed -+ echo "signature: Could not verify signature." > \ -+ $testroot/stdout.expected -+ VERIFY_STDOUT=$(got tag -r $testroot/repo -V $tag 2> $testroot/stderr) -+ ret=$? -+ echo "$VERIFY_STDOUT" | grep '^signature: ' > $testroot/stdout -+ if [ $ret -eq 0 ]; then -+ diff -u $testroot/stdout.expected $testroot/stdout -+ test_done "$testroot" "1" -+ return 1 -+ fi -+ -+ GOOD_SIG='Good "git" signature for flan_hacker@openbsd.org with ED25519 key SHA256:' -+ -+ # Validate the signature with the key allowed -+ echo -n 'flan_hacker@openbsd.org ' > $testroot/allowed_signers -+ cat $testroot/id_ed25519.pub >> $testroot/allowed_signers -+ GOT_STDOUT=$(got tag -r $testroot/repo -V $tag 2> $testroot/stderr) -+ ret=$? -+ if [ $ret -ne 0 ]; then -+ echo "got tag command failed unexpectedly" -+ diff -u $testroot/stdout.expected $testroot/stdout -+ test_done "$testroot" "$ret" -+ return 1 -+ fi -+ -+ if ! echo "$GOT_STDOUT" | grep -q "^signature: $GOOD_SIG"; then -+ echo "got tag command failed to validate signature" -+ test_done "$testroot" "1" -+ return 1 -+ fi -+ -+ # Ensure that Git recognizes and verifies the tag Got has created -+ (cd $testroot/repo && git checkout -q $tag) -+ ret=$? -+ if [ $ret -ne 0 ]; then -+ echo "git checkout command failed unexpectedly" -+ test_done "$testroot" "$ret" -+ return 1 -+ fi -+ (cd $testroot/repo && git config --local gpg.ssh.allowedSignersFile \ -+ $testroot/allowed_signers) -+ GIT_STDERR=$(cd $testroot/repo && git tag -v $tag 2>&1 1>/dev/null) -+ if ! echo "$GIT_STDERR" | grep -q "^$GOOD_SIG"; then -+ echo "git tag command failed to validate signature" -+ test_done "$testroot" "1" -+ return 1 -+ fi -+ -+ # Ensure Got recognizes the new tag -+ got checkout -c $tag $testroot/repo $testroot/wt >/dev/null -+ ret=$? -+ if [ $ret -ne 0 ]; then -+ echo "got checkout command failed unexpectedly" -+ test_done "$testroot" "$ret" -+ return 1 -+ fi -+ -+ # Create a tag based on implied worktree HEAD ref -+ (cd $testroot/wt && got tag -m 'test' $tag2 > $testroot/stdout) -+ ret=$? -+ if [ $ret -ne 0 ]; then -+ test_done "$testroot" "$ret" -+ return 1 -+ fi -+ -+ tag_id2=`got ref -r $testroot/repo -l \ -+ | grep "^refs/tags/$tag2" | tr -d ' ' | cut -d: -f2` -+ echo "Created tag $tag_id2" > $testroot/stdout.expected -+ cmp -s $testroot/stdout $testroot/stdout.expected -+ ret=$? -+ if [ $ret -ne 0 ]; then -+ diff -u $testroot/stdout.expected $testroot/stdout -+ test_done "$testroot" "$ret" -+ return 1 -+ fi -+ -+ (cd $testroot/repo && git checkout -q $tag2) -+ ret=$? -+ if [ $ret -ne 0 ]; then -+ echo "git checkout command failed unexpectedly" -+ test_done "$testroot" "$ret" -+ return 1 -+ fi -+ -+ # Attempt to create a tag pointing at a non-commit -+ local tree_id=`git_show_tree $testroot/repo` -+ (cd $testroot/wt && got tag -m 'test' -c $tree_id foobar \ -+ 2> $testroot/stderr) -+ ret=$? -+ if [ $ret -eq 0 ]; then -+ echo "git tag command succeeded unexpectedly" -+ test_done "$testroot" "1" -+ return 1 -+ fi -+ -+ echo "got: commit $tree_id: object not found" \ -+ > $testroot/stderr.expected -+ cmp -s $testroot/stderr $testroot/stderr.expected -+ ret=$? -+ if [ $ret -ne 0 ]; then -+ diff -u $testroot/stderr.expected $testroot/stderr -+ test_done "$testroot" "$ret" -+ return 1 -+ fi -+ -+ got ref -r $testroot/repo -l > $testroot/stdout -+ echo "HEAD: $commit_id" > $testroot/stdout.expected -+ echo -n "refs/got/worktree/base-" >> $testroot/stdout.expected -+ cat $testroot/wt/.got/uuid | tr -d '\n' >> $testroot/stdout.expected -+ echo ": $commit_id" >> $testroot/stdout.expected -+ echo "refs/heads/master: $commit_id" >> $testroot/stdout.expected -+ echo "refs/tags/$tag: $tag_id" >> $testroot/stdout.expected -+ echo "refs/tags/$tag2: $tag_id2" >> $testroot/stdout.expected -+ cmp -s $testroot/stdout $testroot/stdout.expected -+ ret=$? -+ if [ $ret -ne 0 ]; then -+ diff -u $testroot/stdout.expected $testroot/stdout -+ fi -+ test_done "$testroot" "$ret" -+} -+ - test_parseargs "$@" - run_test test_tag_create - run_test test_tag_list - run_test test_tag_list_lightweight -+run_test test_tag_create_ssh_signed -blob - 0215869fd1a3678fe92c416a609faf3e875f0a34 -blob + f835a2398bf16bf81771722cceeaea81aaa9423b ---- regress/fetch/Makefile -+++ regress/fetch/Makefile -@@ -4,7 +4,8 @@ PROG = fetch_test - SRCS = error.c privsep.c reference.c sha1.c object.c object_parse.c path.c \ - opentemp.c repository.c lockfile.c object_cache.c pack.c inflate.c \ - deflate.c delta.c delta_cache.c object_idset.c object_create.c \ -- fetch.c gotconfig.c dial.c fetch_test.c bloom.c murmurhash2.c -+ fetch.c gotconfig.c dial.c fetch_test.c bloom.c murmurhash2.c sigs.c \ -+ buf.c date.c - - CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib - LDADD = -lutil -lz -lm -blob - ba79d5e787ada9939dea4f62aae062cea501f845 -blob + 7379d7e77fb9e190eb44211cdf722939696a6cbe ---- tog/Makefile -+++ tog/Makefile -@@ -12,7 +12,7 @@ SRCS= tog.c blame.c commit_graph.c delta.c diff.c \ - gotconfig.c diff_main.c diff_atomize_text.c \ - diff_myers.c diff_output.c diff_output_plain.c \ - diff_output_unidiff.c diff_output_edscript.c \ -- diff_patience.c bloom.c murmurhash2.c -+ diff_patience.c bloom.c murmurhash2.c sigs.c date.c - MAN = ${PROG}.1 - - CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib - diff --git a/pkgs/got.nix b/pkgs/got.nix deleted file mode 100644 index de56c3e..0000000 --- a/pkgs/got.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ lib, stdenv, fetchpatch, fetchgit, bison, pkg-config, libressl, libbsd -, libuuid, libmd, zlib, ncurses, isUnstable, openssh, autoreconfHook -, sshKeyGenPath ? "/run/current-system/sw/bin/ssh-keygen" }: - -stdenv.mkDerivation rec { - pname = "got"; - rev = "a8fa2ba8469e013475c403304989843b7fc17ae8"; - version = "0.74"; - - src = fetchgit { - inherit rev; - - url = "git://git.gameoftrees.org/got-portable.git"; - sha256 = "sha256-oQofGknpCyRFyNuUZYpLcZ57JCl04wuaxM1RpIXp1LE="; - }; - - patches = [ - (fetchpatch { - url = "http://sprunge.us/sEDCV2"; - sha256 = "sha256-oondY/IMU6YMnx5+lIGpN43/tQ/tkCarmveMykQc24c="; - }) - ]; - - nativeBuildInputs = [ pkg-config libressl libbsd libmd zlib autoreconfHook ]; - - buildInputs = [ bison libressl libbsd libuuid libmd zlib ncurses ]; - - CFLAGS = ''-DGOT_TAG_PATH_SSH_KEYGEN=\"${sshKeyGenPath}\"''; - - doInstallCheck = true; - - installCheckPhase = '' - runHook preInstallCheck - test "$($out/bin/got --version)" = '${pname} ${version}' - runHook postInstallCheck - ''; - - meta = with lib; { - description = - "A version control system which prioritizes ease of use and simplicity over flexibility"; - longDescription = '' - Game of Trees (Got) is a version control system which prioritizes - ease of use and simplicity over flexibility. - - Got uses Git repositories to store versioned data. Git can be used - for any functionality which has not yet been implemented in - Got. It will always remain possible to work with both Got and Git - on the same repository. - ''; - homepage = "https://gameoftrees.org"; - license = licenses.isc; - platforms = platforms.linux; - maintainers = with maintainers; [ qbit ]; - }; -} -