Merge branch 'cc/fast-import-strip-signed-commits'
"git fast-import" learned that "--signed-commits=<how>" option that corresponds to that of "git fast-export". * cc/fast-import-strip-signed-commits: fast-import: add '--signed-commits=<mode>' option gpg-interface: refactor 'enum sign_mode' parsingmain
commit
f2d464b9f5
|
@ -66,6 +66,11 @@ fast-import stream! This option is enabled automatically for
|
||||||
remote-helpers that use the `import` capability, as they are
|
remote-helpers that use the `import` capability, as they are
|
||||||
already trusted to run their own code.
|
already trusted to run their own code.
|
||||||
|
|
||||||
|
--signed-commits=(verbatim|warn-verbatim|warn-strip|strip|abort)::
|
||||||
|
Specify how to handle signed commits. Behaves in the same way
|
||||||
|
as the same option in linkgit:git-fast-export[1], except that
|
||||||
|
default is 'verbatim' (instead of 'abort').
|
||||||
|
|
||||||
Options for Frontends
|
Options for Frontends
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,6 @@ static const char *const fast_export_usage[] = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
enum sign_mode { SIGN_ABORT, SIGN_VERBATIM, SIGN_STRIP, SIGN_WARN_VERBATIM, SIGN_WARN_STRIP };
|
|
||||||
|
|
||||||
static int progress;
|
static int progress;
|
||||||
static enum sign_mode signed_tag_mode = SIGN_ABORT;
|
static enum sign_mode signed_tag_mode = SIGN_ABORT;
|
||||||
static enum sign_mode signed_commit_mode = SIGN_STRIP;
|
static enum sign_mode signed_commit_mode = SIGN_STRIP;
|
||||||
|
@ -62,20 +60,13 @@ static int parse_opt_sign_mode(const struct option *opt,
|
||||||
const char *arg, int unset)
|
const char *arg, int unset)
|
||||||
{
|
{
|
||||||
enum sign_mode *val = opt->value;
|
enum sign_mode *val = opt->value;
|
||||||
|
|
||||||
if (unset)
|
if (unset)
|
||||||
return 0;
|
return 0;
|
||||||
else if (!strcmp(arg, "abort"))
|
|
||||||
*val = SIGN_ABORT;
|
if (parse_sign_mode(arg, val))
|
||||||
else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
|
|
||||||
*val = SIGN_VERBATIM;
|
|
||||||
else if (!strcmp(arg, "warn-verbatim") || !strcmp(arg, "warn"))
|
|
||||||
*val = SIGN_WARN_VERBATIM;
|
|
||||||
else if (!strcmp(arg, "warn-strip"))
|
|
||||||
*val = SIGN_WARN_STRIP;
|
|
||||||
else if (!strcmp(arg, "strip"))
|
|
||||||
*val = SIGN_STRIP;
|
|
||||||
else
|
|
||||||
return error("Unknown %s mode: %s", opt->long_name, arg);
|
return error("Unknown %s mode: %s", opt->long_name, arg);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -188,6 +188,8 @@ static int global_argc;
|
||||||
static const char **global_argv;
|
static const char **global_argv;
|
||||||
static const char *global_prefix;
|
static const char *global_prefix;
|
||||||
|
|
||||||
|
static enum sign_mode signed_commit_mode = SIGN_VERBATIM;
|
||||||
|
|
||||||
/* Memory pools */
|
/* Memory pools */
|
||||||
static struct mem_pool fi_mem_pool = {
|
static struct mem_pool fi_mem_pool = {
|
||||||
.block_alloc = 2*1024*1024 - sizeof(struct mp_block),
|
.block_alloc = 2*1024*1024 - sizeof(struct mp_block),
|
||||||
|
@ -2752,6 +2754,15 @@ static void parse_one_signature(struct signature_data *sig, const char *v)
|
||||||
parse_data(&sig->data, 0, NULL);
|
parse_data(&sig->data, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void discard_one_signature(void)
|
||||||
|
{
|
||||||
|
struct strbuf data = STRBUF_INIT;
|
||||||
|
|
||||||
|
read_next_command();
|
||||||
|
parse_data(&data, 0, NULL);
|
||||||
|
strbuf_release(&data);
|
||||||
|
}
|
||||||
|
|
||||||
static void add_gpgsig_to_commit(struct strbuf *commit_data,
|
static void add_gpgsig_to_commit(struct strbuf *commit_data,
|
||||||
const char *header,
|
const char *header,
|
||||||
struct signature_data *sig)
|
struct signature_data *sig)
|
||||||
|
@ -2785,6 +2796,22 @@ static void store_signature(struct signature_data *stored_sig,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void import_one_signature(struct signature_data *sig_sha1,
|
||||||
|
struct signature_data *sig_sha256,
|
||||||
|
const char *v)
|
||||||
|
{
|
||||||
|
struct signature_data sig = { NULL, NULL, STRBUF_INIT };
|
||||||
|
|
||||||
|
parse_one_signature(&sig, v);
|
||||||
|
|
||||||
|
if (!strcmp(sig.hash_algo, "sha1"))
|
||||||
|
store_signature(sig_sha1, &sig, "SHA-1");
|
||||||
|
else if (!strcmp(sig.hash_algo, "sha256"))
|
||||||
|
store_signature(sig_sha256, &sig, "SHA-256");
|
||||||
|
else
|
||||||
|
die(_("parse_one_signature() returned unknown hash algo"));
|
||||||
|
}
|
||||||
|
|
||||||
static void parse_new_commit(const char *arg)
|
static void parse_new_commit(const char *arg)
|
||||||
{
|
{
|
||||||
static struct strbuf msg = STRBUF_INIT;
|
static struct strbuf msg = STRBUF_INIT;
|
||||||
|
@ -2817,19 +2844,32 @@ static void parse_new_commit(const char *arg)
|
||||||
if (!committer)
|
if (!committer)
|
||||||
die("Expected committer but didn't get one");
|
die("Expected committer but didn't get one");
|
||||||
|
|
||||||
/* Process signatures (up to 2: one "sha1" and one "sha256") */
|
|
||||||
while (skip_prefix(command_buf.buf, "gpgsig ", &v)) {
|
while (skip_prefix(command_buf.buf, "gpgsig ", &v)) {
|
||||||
struct signature_data sig = { NULL, NULL, STRBUF_INIT };
|
switch (signed_commit_mode) {
|
||||||
|
|
||||||
parse_one_signature(&sig, v);
|
/* First, modes that don't need the signature to be parsed */
|
||||||
|
case SIGN_ABORT:
|
||||||
|
die("encountered signed commit; use "
|
||||||
|
"--signed-commits=<mode> to handle it");
|
||||||
|
case SIGN_WARN_STRIP:
|
||||||
|
warning(_("stripping a commit signature"));
|
||||||
|
/* fallthru */
|
||||||
|
case SIGN_STRIP:
|
||||||
|
discard_one_signature();
|
||||||
|
break;
|
||||||
|
|
||||||
if (!strcmp(sig.hash_algo, "sha1"))
|
/* Second, modes that parse the signature */
|
||||||
store_signature(&sig_sha1, &sig, "SHA-1");
|
case SIGN_WARN_VERBATIM:
|
||||||
else if (!strcmp(sig.hash_algo, "sha256"))
|
warning(_("importing a commit signature verbatim"));
|
||||||
store_signature(&sig_sha256, &sig, "SHA-256");
|
/* fallthru */
|
||||||
else
|
case SIGN_VERBATIM:
|
||||||
BUG("parse_one_signature() returned unknown hash algo");
|
import_one_signature(&sig_sha1, &sig_sha256, v);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Third, BUG */
|
||||||
|
default:
|
||||||
|
BUG("invalid signed_commit_mode value %d", signed_commit_mode);
|
||||||
|
}
|
||||||
read_next_command();
|
read_next_command();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3501,6 +3541,9 @@ static int parse_one_option(const char *option)
|
||||||
option_active_branches(option);
|
option_active_branches(option);
|
||||||
} else if (skip_prefix(option, "export-pack-edges=", &option)) {
|
} else if (skip_prefix(option, "export-pack-edges=", &option)) {
|
||||||
option_export_pack_edges(option);
|
option_export_pack_edges(option);
|
||||||
|
} else if (skip_prefix(option, "signed-commits=", &option)) {
|
||||||
|
if (parse_sign_mode(option, &signed_commit_mode))
|
||||||
|
usagef(_("unknown --signed-commits mode '%s'"), option);
|
||||||
} else if (!strcmp(option, "quiet")) {
|
} else if (!strcmp(option, "quiet")) {
|
||||||
show_stats = 0;
|
show_stats = 0;
|
||||||
quiet = 1;
|
quiet = 1;
|
||||||
|
|
|
@ -1125,3 +1125,20 @@ out:
|
||||||
FREE_AND_NULL(ssh_signing_key_file);
|
FREE_AND_NULL(ssh_signing_key_file);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int parse_sign_mode(const char *arg, enum sign_mode *mode)
|
||||||
|
{
|
||||||
|
if (!strcmp(arg, "abort"))
|
||||||
|
*mode = SIGN_ABORT;
|
||||||
|
else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
|
||||||
|
*mode = SIGN_VERBATIM;
|
||||||
|
else if (!strcmp(arg, "warn-verbatim") || !strcmp(arg, "warn"))
|
||||||
|
*mode = SIGN_WARN_VERBATIM;
|
||||||
|
else if (!strcmp(arg, "warn-strip"))
|
||||||
|
*mode = SIGN_WARN_STRIP;
|
||||||
|
else if (!strcmp(arg, "strip"))
|
||||||
|
*mode = SIGN_STRIP;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -104,4 +104,19 @@ int check_signature(struct signature_check *sigc,
|
||||||
void print_signature_buffer(const struct signature_check *sigc,
|
void print_signature_buffer(const struct signature_check *sigc,
|
||||||
unsigned flags);
|
unsigned flags);
|
||||||
|
|
||||||
|
/* Modes for --signed-tags=<mode> and --signed-commits=<mode> options. */
|
||||||
|
enum sign_mode {
|
||||||
|
SIGN_ABORT,
|
||||||
|
SIGN_WARN_VERBATIM,
|
||||||
|
SIGN_VERBATIM,
|
||||||
|
SIGN_WARN_STRIP,
|
||||||
|
SIGN_STRIP,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return 0 if `arg` can be parsed into an `enum sign_mode`. Return -1
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
int parse_sign_mode(const char *arg, enum sign_mode *mode);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1035,6 +1035,7 @@ integration_tests = [
|
||||||
't9302-fast-import-unpack-limit.sh',
|
't9302-fast-import-unpack-limit.sh',
|
||||||
't9303-fast-import-compression.sh',
|
't9303-fast-import-compression.sh',
|
||||||
't9304-fast-import-marks.sh',
|
't9304-fast-import-marks.sh',
|
||||||
|
't9305-fast-import-signatures.sh',
|
||||||
't9350-fast-export.sh',
|
't9350-fast-export.sh',
|
||||||
't9351-fast-export-anonymize.sh',
|
't9351-fast-export-anonymize.sh',
|
||||||
't9400-git-cvsserver-server.sh',
|
't9400-git-cvsserver-server.sh',
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='git fast-import --signed-commits=<mode>'
|
||||||
|
|
||||||
|
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
. "$TEST_DIRECTORY/lib-gpg.sh"
|
||||||
|
|
||||||
|
test_expect_success 'set up unsigned initial commit and import repo' '
|
||||||
|
test_commit first &&
|
||||||
|
git init new
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPG 'set up OpenPGP signed commit' '
|
||||||
|
git checkout -b openpgp-signing main &&
|
||||||
|
echo "Content for OpenPGP signing." >file-sign &&
|
||||||
|
git add file-sign &&
|
||||||
|
git commit -S -m "OpenPGP signed commit" &&
|
||||||
|
OPENPGP_SIGNING=$(git rev-parse --verify openpgp-signing)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPG 'import OpenPGP signature with --signed-commits=verbatim' '
|
||||||
|
git fast-export --signed-commits=verbatim openpgp-signing >output &&
|
||||||
|
git -C new fast-import --quiet --signed-commits=verbatim <output >log 2>&1 &&
|
||||||
|
IMPORTED=$(git -C new rev-parse --verify refs/heads/openpgp-signing) &&
|
||||||
|
test $OPENPGP_SIGNING = $IMPORTED &&
|
||||||
|
test_must_be_empty log
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSM 'set up X.509 signed commit' '
|
||||||
|
git checkout -b x509-signing main &&
|
||||||
|
test_config gpg.format x509 &&
|
||||||
|
test_config user.signingkey $GIT_COMMITTER_EMAIL &&
|
||||||
|
echo "Content for X.509 signing." >file-sign &&
|
||||||
|
git add file-sign &&
|
||||||
|
git commit -S -m "X.509 signed commit" &&
|
||||||
|
X509_SIGNING=$(git rev-parse HEAD)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSM 'import X.509 signature fails with --signed-commits=abort' '
|
||||||
|
git fast-export --signed-commits=verbatim x509-signing >output &&
|
||||||
|
test_must_fail git -C new fast-import --quiet --signed-commits=abort <output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSM 'import X.509 signature with --signed-commits=warn-verbatim' '
|
||||||
|
git -C new fast-import --quiet --signed-commits=warn-verbatim <output >log 2>&1 &&
|
||||||
|
IMPORTED=$(git -C new rev-parse --verify refs/heads/x509-signing) &&
|
||||||
|
test $X509_SIGNING = $IMPORTED &&
|
||||||
|
test_grep "importing a commit signature" log
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH 'set up SSH signed commit' '
|
||||||
|
git checkout -b ssh-signing main &&
|
||||||
|
test_config gpg.format ssh &&
|
||||||
|
test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" &&
|
||||||
|
echo "Content for SSH signing." >file-sign &&
|
||||||
|
git add file-sign &&
|
||||||
|
git commit -S -m "SSH signed commit" &&
|
||||||
|
SSH_SIGNING=$(git rev-parse HEAD)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH 'strip SSH signature with --signed-commits=strip' '
|
||||||
|
git fast-export --signed-commits=verbatim ssh-signing >output &&
|
||||||
|
git -C new fast-import --quiet --signed-commits=strip <output >log 2>&1 &&
|
||||||
|
IMPORTED=$(git -C new rev-parse --verify refs/heads/ssh-signing) &&
|
||||||
|
test $SSH_SIGNING != $IMPORTED &&
|
||||||
|
git -C new cat-file commit "$IMPORTED" >actual &&
|
||||||
|
test_grep ! -E "^gpgsig" actual &&
|
||||||
|
test_must_be_empty log
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPG 'setup a commit with dual OpenPGP signatures on its SHA-1 and SHA-256 formats' '
|
||||||
|
# Create a signed SHA-256 commit
|
||||||
|
git init --object-format=sha256 explicit-sha256 &&
|
||||||
|
git -C explicit-sha256 config extensions.compatObjectFormat sha1 &&
|
||||||
|
git -C explicit-sha256 checkout -b dual-signed &&
|
||||||
|
test_commit -C explicit-sha256 A &&
|
||||||
|
echo B >explicit-sha256/B &&
|
||||||
|
git -C explicit-sha256 add B &&
|
||||||
|
test_tick &&
|
||||||
|
git -C explicit-sha256 commit -S -m "signed" B &&
|
||||||
|
SHA256_B=$(git -C explicit-sha256 rev-parse dual-signed) &&
|
||||||
|
|
||||||
|
# Create the corresponding SHA-1 commit
|
||||||
|
SHA1_B=$(git -C explicit-sha256 rev-parse --output-object-format=sha1 dual-signed) &&
|
||||||
|
|
||||||
|
# Check that the resulting SHA-1 commit has both signatures
|
||||||
|
git -C explicit-sha256 cat-file -p $SHA1_B >out &&
|
||||||
|
test_grep -E "^gpgsig " out &&
|
||||||
|
test_grep -E "^gpgsig-sha256 " out
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPG 'strip both OpenPGP signatures with --signed-commits=warn-strip' '
|
||||||
|
git -C explicit-sha256 fast-export --signed-commits=verbatim dual-signed >output &&
|
||||||
|
test_grep -E "^gpgsig sha1 openpgp" output &&
|
||||||
|
test_grep -E "^gpgsig sha256 openpgp" output &&
|
||||||
|
git -C new fast-import --quiet --signed-commits=warn-strip <output >log 2>&1 &&
|
||||||
|
git -C new cat-file commit refs/heads/dual-signed >actual &&
|
||||||
|
test_grep ! -E "^gpgsig " actual &&
|
||||||
|
test_grep ! -E "^gpgsig-sha256 " actual &&
|
||||||
|
test_grep "stripping a commit signature" log >out &&
|
||||||
|
test_line_count = 2 out
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
Loading…
Reference in New Issue