commit - 8fe0cd3a6f849b803a9113fa3a2e06fad9f5315b
commit + ff5e1f096349d36a0ba772c0d78a21b2ab54e060
blob - 527aac5ec1564ad8bda90d4d954008c453b86bbe
blob + 3f0c7462ca5f91c506d50f1069da4df4835c65ec
--- got/got.c
+++ got/got.c
}
static const struct got_error *
+get_signer_id(char **signer_id, struct got_repository *repo,
+ struct got_worktree *worktree)
+{
+ const char *got_signer_id = NULL;
+ const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL;
+
+ *signer_id = 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_signer_id = got_gotconfig_get_signer_id(worktree_conf);
+ if (got_signer_id == NULL)
+ got_signer_id = got_gotconfig_get_signer_id(repo_conf);
+
+ if (got_signer_id) {
+ *signer_id = strdup(got_signer_id);
+ if (*signer_id == 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");
char *cwd = NULL, *repo_path = NULL, *commit_id_str = NULL;
char *gitconfig_path = NULL, *tagger = NULL;
char *allowed_signers = NULL, *revoked_signers = NULL;
+ char *signer_id = NULL;
const char *tag_name = NULL, *commit_id_arg = NULL, *tagmsg = NULL;
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:ls:Vv")) != -1) {
break;
case 'r':
repo_path = realpath(optarg, NULL);
- if (repo_path == NULL)
- return got_error_from_errno2("realpath",
+ if (repo_path == NULL) {
+ error = got_error_from_errno2("realpath",
optarg);
+ goto done;
+ }
got_path_strip_trailing_slashes(repo_path);
break;
case 'l':
do_list = 1;
break;
case 's':
- signer_id = optarg;
+ signer_id = strdup(optarg);
+ if (signer_id == NULL) {
+ error = got_error_from_errno("strdup");
+ goto done;
+ }
break;
case 'V':
verify_tags = 1;
error = get_author(&tagger, repo, worktree);
if (error)
goto done;
+ if (signer_id == NULL) {
+ error = get_signer_id(&signer_id, repo, worktree);
+ if (error)
+ goto done;
+ }
if (worktree) {
/* Release work tree lock. */
got_worktree_close(worktree);
free(tagger);
free(allowed_signers);
free(revoked_signers);
+ free(signer_id);
return error;
}
blob - 7b2e234dbad1c046f7c60882658a72fb41612294
blob + bf287b2c094e6c1f0225bc770acf44401dfd19b2
--- got/got.conf.5
+++ got/got.conf.5
may fail to parse commits without an email address in author data,
.Xr got 1
attempts to reject author information with a missing email address.
+.It Ic signer_id Pa signer-id
+Configure a
+.Ar signer-id
+to sign tag objects.
+This key will be used to sign all tag objects unless overridden by
+.Cm got tag Fl s Ar signer-id .
+.Pp
+For SSH-based signatures,
+.Ar signer-id
+is the path to a file which may refer to either a private SSH key,
+or a public SSH key with the private half available via
+.Xr ssh-agent 1 .
.It Ic allowed_signers Pa path
Configure a
.Ar path
blob - 26e15d93b91bc42ee028fa8ecf60a8d1ac4dfdc9
blob + 856906fff4ebd284a8a00d8f3b215d57faaa4a96
--- include/got_gotconfig.h
+++ include/got_gotconfig.h
*/
const char *
got_gotconfig_get_revoked_signers_file(const struct got_gotconfig *);
+
+/*
+ * Obtain the signer identity used to sign tag objects
+ * Returns NULL if no configuration file is found or no revoked signers file
+ * is configured.
+ */
+const char *
+got_gotconfig_get_signer_id(const struct got_gotconfig *);
blob - 39337ed4d9cbe7dfa5939b3f4dcb38793ccddfbd
blob + 3bc97a1cade1f4c7316b0712a2bb752d0276ebbc
--- lib/got_lib_gotconfig.h
+++ lib/got_lib_gotconfig.h
struct got_remote_repo *remotes;
char *allowed_signers_file;
char *revoked_signers_file;
+ char *signer_id;
};
const struct got_error *got_gotconfig_read(struct got_gotconfig **,
blob - d7a3b44f1263da90512579341f553502dc6d4a4e
blob + 4fe2f0ffd0ca86387452b6b7ff95282358bcd66d
--- lib/got_lib_privsep.h
+++ lib/got_lib_privsep.h
GOT_IMSG_GOTCONFIG_AUTHOR_REQUEST,
GOT_IMSG_GOTCONFIG_ALLOWEDSIGNERS_REQUEST,
GOT_IMSG_GOTCONFIG_REVOKEDSIGNERS_REQUEST,
+ GOT_IMSG_GOTCONFIG_SIGNERID_REQUEST,
GOT_IMSG_GOTCONFIG_REMOTES_REQUEST,
GOT_IMSG_GOTCONFIG_INT_VAL,
GOT_IMSG_GOTCONFIG_STR_VAL,
struct imsgbuf *);
const struct got_error *got_privsep_send_gotconfig_revoked_signers_req(
struct imsgbuf *);
+const struct got_error *got_privsep_send_gotconfig_signer_id_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 - 4263124d516f9667576c82c1dff455733d247f0d
blob + 15c59da31d1d53d2ceac7f3f8184fb211f1f8403
--- lib/gotconfig.c
+++ lib/gotconfig.c
if (err)
goto done;
+ err = got_privsep_send_gotconfig_signer_id_req(ibuf);
+ if (err)
+ goto done;
+
+ err = got_privsep_recv_gotconfig_str(&(*conf)->signer_id, ibuf);
+ if (err)
+ goto done;
+
err = got_privsep_send_gotconfig_remotes_req(ibuf);
if (err)
goto done;
{
return conf->revoked_signers_file;
}
+
+const char *
+got_gotconfig_get_signer_id(const struct got_gotconfig *conf)
+{
+ return conf->signer_id;
+}
blob - e5c1a77dd9cbf5a1fbb32633f6161301ed5e1fc5
blob + c0e2e9215b1e69757313a926d8ca0e0408abd03f
--- lib/privsep.c
+++ lib/privsep.c
}
const struct got_error *
+got_privsep_send_gotconfig_signer_id_req(struct imsgbuf *ibuf)
+{
+ if (imsg_compose(ibuf,
+ GOT_IMSG_GOTCONFIG_SIGNERID_REQUEST, 0, 0, -1, NULL, 0) == -1)
+ return got_error_from_errno("imsg_compose "
+ "GOTCONFIG_SIGNERID_REQUEST");
+
+ return flush_imsg(ibuf);
+}
+
+const struct got_error *
got_privsep_send_gotconfig_remotes_req(struct imsgbuf *ibuf)
{
if (imsg_compose(ibuf,
blob - a3485e939c9e5dbb2d7836e31c2630ff6aeeafe8
blob + b9052f22d3c1f55bf22de427ccf3adbeb24ef97b
--- libexec/got-read-gotconfig/got-read-gotconfig.c
+++ libexec/got-read-gotconfig/got-read-gotconfig.c
err = send_gotconfig_str(&ibuf,
gotconfig->revoked_signers_file ?
gotconfig->revoked_signers_file : "");
+ break;
+ case GOT_IMSG_GOTCONFIG_SIGNERID_REQUEST:
+ if (gotconfig == NULL) {
+ err = got_error(GOT_ERR_PRIVSEP_MSG);
+ break;
+ }
+ err = send_gotconfig_str(&ibuf,
+ gotconfig->signer_id ? gotconfig->signer_id : "");
break;
case GOT_IMSG_GOTCONFIG_REMOTES_REQUEST:
if (gotconfig == NULL) {
blob - 504e691250732f7b2baee47695fc1794127b2adb
blob + f055d6650038380fc13eda6741a0f4631132c03c
--- libexec/got-read-gotconfig/gotconfig.h
+++ libexec/got-read-gotconfig/gotconfig.h
int nremotes;
char *allowed_signers_file;
char *revoked_signers_file;
+ char *signer_id;
};
/*
blob - 394b87aa67d4fb52430e635f9143f621eb0a0d9a
blob + 30138458acdf75220bb9572368ec826118f37f6f
--- libexec/got-read-gotconfig/parse.y
+++ libexec/got-read-gotconfig/parse.y
%token ERROR
%token REMOTE REPOSITORY SERVER PORT PROTOCOL MIRROR_REFERENCES BRANCH
-%token AUTHOR ALLOWED_SIGNERS REVOKED_SIGNERS FETCH_ALL_BRANCHES REFERENCE
-%token FETCH SEND
+%token AUTHOR ALLOWED_SIGNERS REVOKED_SIGNERS SIGNER_ID FETCH_ALL_BRANCHES
+%token REFERENCE FETCH SEND
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.number> boolean portplain
| grammar remote '\n'
| grammar allowed_signers '\n'
| grammar revoked_signers '\n'
+ | grammar signer_id '\n'
;
boolean : STRING {
if (strcasecmp($1, "true") == 0 ||
gotconfig.revoked_signers_file = $2;
}
;
+signer_id : SIGNER_ID STRING {
+ gotconfig.signer_id = $2;
+ }
+ ;
optnl : '\n' optnl
| /* empty */
;
{"revoked_signers", REVOKED_SIGNERS},
{"send", SEND},
{"server", SERVER},
+ {"signer_id", SIGNER_ID},
};
const struct keywords *p;
free(conf->author);
free(conf->allowed_signers_file);
free(conf->revoked_signers_file);
+ free(conf->signer_id);
while (!TAILQ_EMPTY(&conf->remotes)) {
remote = TAILQ_FIRST(&conf->remotes);
TAILQ_REMOVE(&conf->remotes, remote, entry);
blob - d32b03f5eccb5ae355f4b16e488a44068c680b01
blob + d7bf186e4decab4cc4922f2dd6d76908101102bf
--- regress/cmdline/tag.sh
+++ regress/cmdline/tag.sh
local commit_id=`git_show_head $testroot/repo`
local tag=1.0.0
local tag2=2.0.0
+ local tag3=3.0.0
ssh-keygen -q -N '' -t ed25519 -f $testroot/id_ed25519
ret=$?
ret=$?
if [ $ret -ne 0 ]; then
echo "got checkout command failed unexpectedly"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # Create another signed tag with a SHA1 commit ID
+ got tag -s $testroot/id_ed25519 -m 'test' -r $testroot/repo \
+ -c $commit_id $tag2 > $testroot/stdout
+
+ # Create another signed tag with key defined in got.conf(5)
+ echo "signer_id \"$testroot/id_ed25519\"" >> \
+ $testroot/repo/.git/got.conf
+ got tag -m 'test' -r $testroot/repo -c HEAD $tag3 > $testroot/stdout
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "got tag command failed unexpectedly"
+ test_done "$testroot" "$ret"
+ return 1
fi
+
+ # got tag -V behaves like got tag -l, but with verification enabled.
+ got tag -l -r $testroot/repo > $testroot/stdout.list
+ got tag -V -r $testroot/repo > $testroot/stdout.verify
+ diff -U0 $testroot/stdout.list $testroot/stdout.verify |
+ sed -e '/^--- /d' -e '/^+++ /d' > $testroot/stdout
+ echo "@@ -5,0 +6 @@" > $testroot/stdout.expected
+ echo -n "+signature: $GOOD_SIG" >> $testroot/stdout.expected
+ ssh-keygen -l -f $testroot/id_ed25519.pub | cut -d' ' -f 2 \
+ >> $testroot/stdout.expected
+ echo "@@ -19,0 +21 @@" >> $testroot/stdout.expected
+ echo -n "+signature: $GOOD_SIG" >> $testroot/stdout.expected
+ ssh-keygen -l -f $testroot/id_ed25519.pub | cut -d' ' -f 2 \
+ >> $testroot/stdout.expected
+ echo "@@ -33,0 +36 @@" >> $testroot/stdout.expected
+ echo -n "+signature: $GOOD_SIG" >> $testroot/stdout.expected
+ ssh-keygen -l -f $testroot/id_ed25519.pub | cut -d' ' -f 2 \
+ >> $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"
}