commit - bd957eacd0877b6f82a7dea14c185f3eb1e5b41c
commit + d68f2c0e20f502d7bea2f0136527683f830b3d6c
blob - 423824ab575879d09fe670bf4a98d4735d474f45
blob + 77ee3290c2b299ba86499c5b196115d3f54e96b6
--- 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 - dac4ab973b68243e262fd1ae6482fffb6dc2bc57
blob + 8b976a88e8422f5bba1012e0cdd2e3d205ed1a6a
--- 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 - 7fae8306f7aa444e25b71f0a95f8f151ec324a7f
blob + 8abcb57e5150fe88df32e79806a1dca197c5948f
--- 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 - 9a16d647b870eb31f58c9d131d1174c60e7d5eb1
blob + ee575dbf080d9b5e9f2a1019a20d281907f06c91
--- 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 - be0d93073a8d7779e487b6a2d12bad1e6c9721d4
blob + 45aaadb8bcd9513fe5075ceaa0fc416d03874885
--- 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 - 6275b70b1ffab7e1c17bf5cc0aab761e56b04c66
blob + cf5be7e73168496c2b26cde6b459a1167864c846
--- 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 - 217af530810b91c6f6861398bf49b4c6f5403578
blob + 9fb2abf1b9d1f9a39caaece132ad5ba7e9fd8178
--- 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=$?
# 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
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