diff --git a/Makefile-tests.am b/Makefile-tests.am index 85995aa6..9837e5cd 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -134,6 +134,7 @@ _installed_or_uninstalled_test_scripts = \ tests/test-repo-finder-mount-integration.sh \ tests/test-summary-collections.sh \ tests/test-pull-collections.sh \ + tests/test-config.sh \ $(NULL) experimental_test_scripts = \ @@ -360,7 +361,8 @@ EXTRA_DIST += \ $(NULL) tests/libreaddir-rand.so: Makefile - $(AM_V_GEN) ln -fns ../.libs/libreaddir-rand.so tests + mkdir -p tests/ + $(AM_V_GEN) ln -fns ../.libs/libreaddir-rand.so tests/ ALL_LOCAL_RULES += tests/libreaddir-rand.so CLEANFILES += tests/libreaddir-rand.so tests/ostree-symlink-stamp \ tests/ostree-prepare-root-symlink-stamp tests/ostree-remount-symlink-stamp \ diff --git a/Makefile.in b/Makefile.in index 36f71f7c..de1f8906 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1737,9 +1737,9 @@ am__EXEEXT_23 = tests/test-basic.sh tests/test-basic-user.sh \ tests/test-remote-add-collections.sh \ tests/test-repo-finder-mount-integration.sh \ tests/test-summary-collections.sh \ - tests/test-pull-collections.sh $(am__EXEEXT_2) \ - $(am__EXEEXT_20) $(am__append_67) $(am__append_70) \ - $(am__EXEEXT_22) + tests/test-pull-collections.sh tests/test-config.sh \ + $(am__EXEEXT_2) $(am__EXEEXT_20) $(am__append_67) \ + $(am__append_70) $(am__EXEEXT_22) @ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__EXEEXT_24 = \ @ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@ $(am__EXEEXT_23) am__EXEEXT_25 = $(am__EXEEXT_2) $(am__EXEEXT_24) @@ -2597,8 +2597,9 @@ _installed_or_uninstalled_test_scripts = tests/test-basic.sh \ tests/test-remote-add-collections.sh \ tests/test-repo-finder-mount-integration.sh \ tests/test-summary-collections.sh \ - tests/test-pull-collections.sh $(NULL) $(am__append_65) \ - $(am__append_67) $(am__append_70) $(am__append_71) + tests/test-pull-collections.sh tests/test-config.sh $(NULL) \ + $(am__append_65) $(am__append_67) $(am__append_70) \ + $(am__append_71) experimental_test_scripts = \ $(NULL) @@ -7944,6 +7945,13 @@ tests/test-pull-collections.sh.log: tests/test-pull-collections.sh --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-config.sh.log: tests/test-config.sh + @p='tests/test-config.sh'; \ + b='tests/test-config.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) tests/test-rofiles-fuse.sh.log: tests/test-rofiles-fuse.sh @p='tests/test-rofiles-fuse.sh'; \ b='tests/test-rofiles-fuse.sh'; \ @@ -8575,7 +8583,8 @@ src/ostree/parse-datetime.c: src/ostree/parse-datetime.y Makefile @BUILDOPT_USE_STATIC_COMPILER_TRUE@ $(STATIC_COMPILER) -o $@ -static $(top_srcdir)/src/switchroot/ostree-prepare-root.c $(ostree_prepare_root_CPPFLAGS) $(AM_CFLAGS) $(DEFAULT_INCLUDES) tests/libreaddir-rand.so: Makefile - $(AM_V_GEN) ln -fns ../.libs/libreaddir-rand.so tests + mkdir -p tests/ + $(AM_V_GEN) ln -fns ../.libs/libreaddir-rand.so tests/ tests/%-symlink-stamp: % Makefile $(AM_V_GEN) set -e; \ diff --git a/apidoc/html/ostree-OstreeRepo.html b/apidoc/html/ostree-OstreeRepo.html index abe18803..eddc4e59 100644 --- a/apidoc/html/ostree-OstreeRepo.html +++ b/apidoc/html/ostree-OstreeRepo.html @@ -2644,10 +2644,7 @@ ostree_repo_write_config (GKeyFile *new_config, GError **error);

Save new_config - in place of this repository's config file. Note -that new_config - should not be modified after - this function -simply adds a reference.

+ in place of this repository's config file.

Parameters

@@ -2664,7 +2661,7 @@ simply adds a reference.

- + @@ -7693,14 +7690,15 @@ describes the available branches and other metadata.

regular, setting the ostree.summary.expires key in additional_metadata will aid clients in working out when to check for updates.

-

It is regenerated automatically after a commit if -core/commit-update-summary is set.

+

It is regenerated automatically after any ref is +added, removed, or updated if core/auto-update-summary is set.

If the core/collection-id key is set in the configuration, it will be included as OSTREE_SUMMARY_COLLECTION_ID in the summary file. Refs that have associated collection IDs will be included in the generated summary file, listed under the OSTREE_SUMMARY_COLLECTION_MAP key. Collection IDs and refs in OSTREE_SUMMARY_COLLECTION_MAP are guaranteed to be in lexicographic order.

+

Locking: exclusive

Parameters

new_config

Overwrite the config file with this data. Do not change later!

Overwrite the config file with this data

 
diff --git a/bash/ostree b/bash/ostree index d7b54373..677aee7c 100644 --- a/bash/ostree +++ b/bash/ostree @@ -398,6 +398,7 @@ _ostree_config() { " local options_with_args=" + --group --repo " diff --git a/configure b/configure index b8a9326c..e551d6b1 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for libostree 2018.7. +# Generated by GNU Autoconf 2.69 for libostree 2018.8. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='libostree' PACKAGE_TARNAME='libostree' -PACKAGE_VERSION='2018.7' -PACKAGE_STRING='libostree 2018.7' +PACKAGE_VERSION='2018.8' +PACKAGE_STRING='libostree 2018.8' PACKAGE_BUGREPORT='walters@verbum.org' PACKAGE_URL='' @@ -1547,7 +1547,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures libostree 2018.7 to adapt to many kinds of systems. +\`configure' configures libostree 2018.8 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1617,7 +1617,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of libostree 2018.7:";; + short | recursive ) echo "Configuration of libostree 2018.8:";; esac cat <<\_ACEOF @@ -1864,7 +1864,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -libostree configure 2018.7 +libostree configure 2018.8 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2336,7 +2336,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by libostree $as_me 2018.7, which was +It was created by libostree $as_me 2018.8, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3204,7 +3204,7 @@ fi # Define the identity of the package. PACKAGE='libostree' - VERSION='2018.7' + VERSION='2018.8' # Some tools Automake needs. @@ -5938,9 +5938,9 @@ test -n "$YACC" || YACC="yacc" YEAR_VERSION=2018 -RELEASE_VERSION=7 +RELEASE_VERSION=8 -PACKAGE_VERSION=2018.7 +PACKAGE_VERSION=2018.8 if echo "$CFLAGS" | grep -q -E -e '-Werror($| )'; then : @@ -18623,7 +18623,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by libostree $as_me 2018.7, which was +This file was extended by libostree $as_me 2018.8, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -18689,7 +18689,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -libostree config.status 2018.7 +libostree config.status 2018.8 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 4484e06a..4ccd79c6 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ dnl update libostree-released.sym from libostree-devel.sym, and update the check dnl in test-symbols.sh, and also set is_release_build=yes below. Then make dnl another post-release commit to bump the version, and set is_release_build=no. m4_define([year_version], [2018]) -m4_define([release_version], [7]) +m4_define([release_version], [8]) m4_define([package_version], [year_version.release_version]) AC_INIT([libostree], [package_version], [walters@verbum.org]) is_release_build=yes diff --git a/man/ostree-config.xml b/man/ostree-config.xml index f1232602..dc180b83 100644 --- a/man/ostree-config.xml +++ b/man/ostree-config.xml @@ -53,9 +53,15 @@ Boston, MA 02111-1307, USA. ostree config get SECTIONNAME.KEYNAME + + ostree config get --group=GROUPNAME KEYNAME + ostree config set SECTIONNAME.KEYNAME VALUE + + ostree config set --group=GROUPNAME KEYNAME VALUE + @@ -70,5 +76,6 @@ Boston, MA 02111-1307, USA. Example $ ostree config get core.mode bare + $ ostree config set --group='remote "myremote"' url http://example.com/repo diff --git a/man/ostree.repo-config.xml b/man/ostree.repo-config.xml index 4aedc138..dc126d65 100644 --- a/man/ostree.repo-config.xml +++ b/man/ostree.repo-config.xml @@ -87,10 +87,20 @@ Boston, MA 02111-1307, USA. - commit-update-summary + auto-update-summary Boolean value controlling whether or not to - automatically update the summary file after a commit. Defaults - to false. + automatically update the summary file after any ref is added, + removed, or updated. Other modifications which may render a + summary file stale (like static deltas, or collection IDs) do + not currently trigger an auto-update. + + + + + commit-update-summary + This option is deprecated. Use + auto-update-summary instead, for which this + option is now an alias. @@ -119,21 +129,36 @@ Boston, MA 02111-1307, USA. min-free-space-percent - Integer percentage value (0-99) that specifies a minimum - percentage of total space (in blocks) in the underlying filesystem to - keep free. The default value is 3. - In case this option is co-existing with min-free-space-size (see below), - it would be ignored and min-free-space-size check would be enforced instead. - + + + Integer percentage value (0-99) that specifies a minimum percentage + of total space (in blocks) in the underlying filesystem to keep + free. The default value is 3, which is enforced when neither this + option nor min-free-space-size are set. + + + If min-free-space-size is set to a non-zero + value, min-free-space-percent is ignored. + + min-free-space-size - Value (in MB, GB or TB) that specifies a minimum space in the - underlying filesystem to keep free. Also, note that min-free-space-percent - and min-free-space-size are mutually exclusive. Examples of acceptable values: - 500MB, 1GB etc. The default value is 0MB, which disables this check. - + + + Value (in power-of-2 MB, GB or TB) that specifies a minimum space + in the underlying filesystem to keep free. Examples of acceptable + values: 500MB (524 288 000 bytes), + 1GB (1 073 741 824 bytes), + 1TB (1 099 511 627 776 bytes). + + + If this option is set to a non-zero value, and + min-free-space-percent is also set, this option + takes priority. + + diff --git a/src/boot/ostree-remount.service b/src/boot/ostree-remount.service index 68209f96..47e1387a 100644 --- a/src/boot/ostree-remount.service +++ b/src/boot/ostree-remount.service @@ -31,6 +31,7 @@ Before=systemd-tmpfiles-setup.service [Service] Type=oneshot +RemainAfterExit=yes ExecStart=/usr/lib/ostree/ostree-remount StandardInput=null StandardOutput=syslog diff --git a/src/libostree/libostree-devel.sym b/src/libostree/libostree-devel.sym index a4040ba6..24db9df2 100644 --- a/src/libostree/libostree-devel.sym +++ b/src/libostree/libostree-devel.sym @@ -18,6 +18,8 @@ ***/ /* Add new symbols here. Release commits should copy this section into -released.sym. */ +LIBOSTREE_2018.9 { +} LIBOSTREE_2018.7; /* Stub section for the stable release *after* this development one; don't * edit this other than to update the last number. This is just a copy/paste diff --git a/src/libostree/libostree-released.sym b/src/libostree/libostree-released.sym index 1e17e581..ae3bb5ed 100644 --- a/src/libostree/libostree-released.sym +++ b/src/libostree/libostree-released.sym @@ -534,6 +534,8 @@ global: ostree_mutable_tree_check_error; } LIBOSTREE_2018.6; +/* No new symbols in 2018.8 */ + /* NOTE: Only add more content here in release commits! See the * comments at the top of this file. */ diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index bbbe1961..d464cd0a 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -445,10 +445,10 @@ throw_min_free_space_error (OstreeRepo *self, else err_msg = "would be exceeded"; - if (self->min_free_space_percent > 0) - return glnx_throw (error, "min-free-space-percent '%u%%' %s", self->min_free_space_percent, err_msg); - else + if (self->min_free_space_mb > 0) return glnx_throw (error, "min-free-space-size %" G_GUINT64_FORMAT "MB %s", self->min_free_space_mb, err_msg); + else + return glnx_throw (error, "min-free-space-percent '%u%%' %s", self->min_free_space_percent, err_msg); } typedef struct { @@ -1295,6 +1295,7 @@ write_metadata_object (OstreeRepo *self, char actual_checksum[OSTREE_SHA256_STRING_LEN+1]; if (is_tombstone) { + g_assert (expected_checksum != NULL); memcpy (actual_checksum, expected_checksum, sizeof (actual_checksum)); } else @@ -2194,11 +2195,19 @@ ostree_repo_commit_transaction (OstreeRepo *self, if (self->txn.refs) if (!_ostree_repo_update_refs (self, self->txn.refs, cancellable, error)) return FALSE; - g_clear_pointer (&self->txn.refs, g_hash_table_destroy); if (self->txn.collection_refs) if (!_ostree_repo_update_collection_refs (self, self->txn.collection_refs, cancellable, error)) return FALSE; + + /* Update the summary if auto-update-summary is set, because doing so was + * delayed for each ref change during the transaction. + */ + if ((self->txn.refs || self->txn.collection_refs) && + !_ostree_repo_maybe_regenerate_summary (self, cancellable, error)) + return FALSE; + + g_clear_pointer (&self->txn.refs, g_hash_table_destroy); g_clear_pointer (&self->txn.collection_refs, g_hash_table_destroy); self->in_transaction = FALSE; @@ -3309,6 +3318,7 @@ write_dir_entry_to_mtree_internal (OstreeRepo *self, } else { + g_assert (dfd_iter != NULL); g_auto(GLnxDirFdIterator) child_dfd_iter = { 0, }; if (!glnx_dirfd_iterator_init_at (dfd_iter->fd, name, FALSE, &child_dfd_iter, error)) diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h index 0a447634..99eaf494 100644 --- a/src/libostree/ostree-repo-private.h +++ b/src/libostree/ostree-repo-private.h @@ -61,7 +61,8 @@ G_BEGIN_DECLS #define OSTREE_COMMIT_TIMESTAMP "ostree.commit.timestamp" typedef enum { - OSTREE_REPO_TEST_ERROR_PRE_COMMIT = (1 << 0) + OSTREE_REPO_TEST_ERROR_PRE_COMMIT = (1 << 0), + OSTREE_REPO_TEST_ERROR_INVALID_CACHE = (1 << 1), } OstreeRepoTestErrorFlags; struct OstreeRepoCommitModifier { @@ -437,6 +438,11 @@ _ostree_repo_get_remote_inherited (OstreeRepo *self, const char *name, GError **error); +gboolean +_ostree_repo_maybe_regenerate_summary (OstreeRepo *self, + GCancellable *cancellable, + GError **error); + /* Locking APIs are currently private. * See https://github.com/ostreedev/ostree/pull/1555 */ diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c index 9553272e..c6b70ffb 100644 --- a/src/libostree/ostree-repo-pull.c +++ b/src/libostree/ostree-repo-pull.c @@ -2486,7 +2486,10 @@ process_one_static_delta (OtPullData *pull_data, OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM, NULL, &inline_delta_part, cancellable, error)) - return FALSE; + { + fetch_static_delta_data_free (fetch_data); + return FALSE; + } _ostree_static_delta_part_execute_async (pull_data->repo, fetch_data->objects, @@ -3345,6 +3348,19 @@ initiate_request (OtPullData *pull_data, return TRUE; } + /* If doing a delta from a ref, look up the from-revision, since we need it + * on most paths below. */ + if (ref != NULL) + { + g_autofree char *refspec = NULL; + if (pull_data->remote_name != NULL) + refspec = g_strdup_printf ("%s:%s", pull_data->remote_name, ref->ref_name); + if (!ostree_repo_resolve_rev (pull_data->repo, + refspec ?: ref->ref_name, TRUE, + &delta_from_revision, error)) + return FALSE; + } + /* If we have a summary, we can use the newer logic */ if (pull_data->summary) { @@ -3372,7 +3388,16 @@ initiate_request (OtPullData *pull_data, enqueue_one_static_delta_superblock_request (pull_data, deltares.from_revision, to_revision, ref); break; case DELTA_SEARCH_RESULT_SCRATCH: - enqueue_one_static_delta_superblock_request (pull_data, NULL, to_revision, ref); + { + /* If a from-scratch delta is available, we don’t want to use it if + * the ref already exists locally, since we are likely only a few + * commits out of date; so doing an object pull is likely more + * bandwidth efficient. */ + if (delta_from_revision != NULL) + queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0, ref); + else + enqueue_one_static_delta_superblock_request (pull_data, NULL, to_revision, ref); + } break; case DELTA_SEARCH_RESULT_UNCHANGED: { @@ -3392,13 +3417,6 @@ initiate_request (OtPullData *pull_data, { /* Are we doing a delta via a ref? In that case we can fall back to the older * logic of just using the current tip of the ref as a delta FROM source. */ - g_autofree char *refspec = NULL; - if (pull_data->remote_name != NULL) - refspec = g_strdup_printf ("%s:%s", pull_data->remote_name, ref->ref_name); - if (!ostree_repo_resolve_rev (pull_data->repo, - refspec ?: ref->ref_name, TRUE, - &delta_from_revision, error)) - return FALSE; /* Determine whether the from revision we have is partial; this * can happen if e.g. one uses `ostree pull --commit-metadata-only`. @@ -3983,7 +4001,10 @@ ostree_repo_pull_with_options (OstreeRepo *self, goto out; if (bytes_summary) - summary_from_cache = TRUE; + { + g_debug ("Loaded %s summary from cache", remote_name_or_baseurl); + summary_from_cache = TRUE; + } if (!pull_data->summary && !bytes_summary) { @@ -4021,12 +4042,53 @@ ostree_repo_pull_with_options (OstreeRepo *self, if (pull_data->gpg_verify_summary && bytes_summary && bytes_sig) { g_autoptr(OstreeGpgVerifyResult) result = NULL; + g_autoptr(GError) temp_error = NULL; result = ostree_repo_verify_summary (self, pull_data->remote_name, bytes_summary, bytes_sig, - cancellable, error); - if (!ostree_gpg_verify_result_require_valid_signature (result, error)) - goto out; + cancellable, &temp_error); + if (!ostree_gpg_verify_result_require_valid_signature (result, &temp_error)) + { + if (summary_from_cache) + { + /* The cached summary doesn't match, fetch a new one and verify again */ + if ((self->test_error_flags & OSTREE_REPO_TEST_ERROR_INVALID_CACHE) > 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Remote %s cached summary invalid and " + "OSTREE_REPO_TEST_ERROR_INVALID_CACHE specified", + pull_data->remote_name); + goto out; + } + else + g_debug ("Remote %s cached summary invalid, pulling new version", + pull_data->remote_name); + + summary_from_cache = FALSE; + g_clear_pointer (&bytes_summary, (GDestroyNotify)g_bytes_unref); + if (!_ostree_fetcher_mirrored_request_to_membuf (pull_data->fetcher, + pull_data->meta_mirrorlist, + "summary", + OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT, + pull_data->n_network_retries, + &bytes_summary, + OSTREE_MAX_METADATA_SIZE, + cancellable, error)) + goto out; + + g_autoptr(OstreeGpgVerifyResult) retry = + ostree_repo_verify_summary (self, pull_data->remote_name, + bytes_summary, bytes_sig, + cancellable, error); + if (!ostree_gpg_verify_result_require_valid_signature (retry, error)) + goto out; + } + else + { + g_propagate_error (error, g_steal_pointer (&temp_error)); + goto out; + } + } } if (bytes_summary) @@ -4131,7 +4193,6 @@ ostree_repo_pull_with_options (OstreeRepo *self, { const char *delta; g_autoptr(GVariant) csum_v = NULL; - guchar *csum_data = g_malloc (OSTREE_SHA256_DIGEST_LEN); g_autoptr(GVariant) ref = g_variant_get_child_value (deltas, i); g_variant_get_child (ref, 0, "&s", &delta); @@ -4140,6 +4201,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, if (!validate_variant_is_csum (csum_v, error)) goto out; + guchar *csum_data = g_malloc (OSTREE_SHA256_DIGEST_LEN); memcpy (csum_data, ostree_checksum_bytes_peek (csum_v), 32); g_hash_table_insert (pull_data->summary_deltas_checksums, g_strdup (delta), @@ -5255,8 +5317,9 @@ find_remotes_cb (GObject *obj, summary_bytes, FALSE); /* Check the summary’s additional metadata and set up @commit_metadata - * and @refs_and_remotes_table with all the refs listed in the summary - * file which intersect with @refs. */ + * and @refs_and_remotes_table with the refs listed in the summary file, + * filtered by the keyring associated with this result and the + * intersection with @refs. */ additional_metadata_v = g_variant_get_child_value (summary_v, 1); if (g_variant_lookup (additional_metadata_v, OSTREE_SUMMARY_COLLECTION_ID, "s", &summary_collection_id)) @@ -5277,6 +5340,13 @@ find_remotes_cb (GObject *obj, while (summary_collection_map != NULL && g_variant_iter_loop (summary_collection_map, "{s@a(s(taya{sv}))}", &summary_collection_id, &summary_refs)) { + /* Exclude refs that don't use the associated keyring if this is a + * dynamic remote, by comparing against the collection ID of the + * remote this one inherits from */ + if (result->remote->refspec_name != NULL && + !check_remote_matches_collection_id (self, result->remote->refspec_name, summary_collection_id)) + continue; + if (!find_remotes_process_refs (self, refs, result, i, summary_collection_id, summary_refs, commit_metadatas, refs_and_remotes_table)) { @@ -5656,7 +5726,7 @@ copy_option (GVariantDict *master_options, { g_autoptr(GVariant) option_v = g_variant_dict_lookup_value (master_options, key, expected_type); if (option_v != NULL) - g_variant_dict_insert_value (slave_options, key, g_steal_pointer (&option_v)); + g_variant_dict_insert_value (slave_options, key, option_v); } /** diff --git a/src/libostree/ostree-repo-refs.c b/src/libostree/ostree-repo-refs.c index 2600cb7c..1bbe3901 100644 --- a/src/libostree/ostree-repo-refs.c +++ b/src/libostree/ostree-repo-refs.c @@ -1144,6 +1144,11 @@ _ostree_repo_write_ref (OstreeRepo *self, if (!_ostree_repo_update_mtime (self, error)) return FALSE; + /* Update the summary after updating the mtime so the summary doesn't look + * out of date */ + if (!self->in_transaction && !_ostree_repo_maybe_regenerate_summary (self, cancellable, error)) + return FALSE; + return TRUE; } @@ -1153,17 +1158,10 @@ _ostree_repo_update_refs (OstreeRepo *self, GCancellable *cancellable, GError **error) { - GHashTableIter hash_iter; - gpointer key, value; - - g_hash_table_iter_init (&hash_iter, refs); - while (g_hash_table_iter_next (&hash_iter, &key, &value)) + GLNX_HASH_TABLE_FOREACH_KV (refs, const char*, refspec, const char*, rev) { - const char *refspec = key; - const char *rev = value; g_autofree char *remote = NULL; g_autofree char *ref_name = NULL; - if (!ostree_parse_refspec (refspec, &remote, &ref_name, error)) return FALSE; @@ -1253,7 +1251,6 @@ ostree_repo_list_collection_refs (OstreeRepo *self, (GDestroyNotify) ostree_collection_ref_free, g_free); - g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; g_autoptr(GString) base_path = g_string_new (""); const gchar *main_collection_id = ostree_repo_get_collection_id (self); @@ -1279,6 +1276,8 @@ ostree_repo_list_collection_refs (OstreeRepo *self, { const char *refs_dir = *iter; gboolean refs_dir_exists = FALSE; + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + if (!ot_dfd_iter_init_allow_noent (self->repo_dir_fd, refs_dir, &dfd_iter, &refs_dir_exists, error)) return FALSE; diff --git a/src/libostree/ostree-repo-static-delta-compilation.c b/src/libostree/ostree-repo-static-delta-compilation.c index 9084a72f..054ac06f 100644 --- a/src/libostree/ostree-repo-static-delta-compilation.c +++ b/src/libostree/ostree-repo-static-delta-compilation.c @@ -313,14 +313,13 @@ finish_part (OstreeStaticDeltaBuilder *builder, GError **error) static OstreeStaticDeltaPartBuilder * allocate_part (OstreeStaticDeltaBuilder *builder, GError **error) { - OstreeStaticDeltaPartBuilder *part = g_new0 (OstreeStaticDeltaPartBuilder, 1); - if (builder->parts->len > 0) { if (!finish_part (builder, error)) return NULL; } + OstreeStaticDeltaPartBuilder *part = g_new0 (OstreeStaticDeltaPartBuilder, 1); part->objects = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref); part->payload = g_string_new (NULL); part->operations = g_string_new (NULL); @@ -1522,7 +1521,7 @@ ostree_repo_static_delta_generate (OstreeRepo *self, goto out; } - g_variant_builder_add_value (part_headers, g_variant_ref (part_builder->header)); + g_variant_builder_add_value (part_headers, part_builder->header); total_compressed_size += part_builder->compressed_size; total_uncompressed_size += part_builder->uncompressed_size; diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index f4dcb703..18736c24 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -1187,6 +1187,7 @@ ostree_repo_init (OstreeRepo *self) static gsize gpgme_initialized; const GDebugKey test_error_keys[] = { { "pre-commit", OSTREE_REPO_TEST_ERROR_PRE_COMMIT }, + { "invalid-cache", OSTREE_REPO_TEST_ERROR_INVALID_CACHE }, }; if (g_once_init_enter (&gpgme_initialized)) @@ -1440,12 +1441,10 @@ ostree_repo_copy_config (OstreeRepo *self) /** * ostree_repo_write_config: * @self: Repo - * @new_config: Overwrite the config file with this data. Do not change later! + * @new_config: Overwrite the config file with this data * @error: a #GError * - * Save @new_config in place of this repository's config file. Note - * that @new_config should not be modified after - this function - * simply adds a reference. + * Save @new_config in place of this repository's config file. */ gboolean ostree_repo_write_config (OstreeRepo *self, @@ -4611,8 +4610,9 @@ ostree_repo_pull_default_console_progress_changed (OstreeAsyncProgress *progress if (bytes_sec > 0) { - /* MAX(0, value) here just to be defensive */ - guint64 est_time_remaining = MAX(0, (total_delta_part_size - fetched_delta_part_size)) / bytes_sec; + guint64 est_time_remaining = 0; + if (total_delta_part_size > fetched_delta_part_size) + est_time_remaining = (total_delta_part_size - fetched_delta_part_size) / bytes_sec; g_autofree char *formatted_est_time_remaining = _formatted_time_remaining_from_seconds (est_time_remaining); /* No space between %s and remaining, since formatted_est_time_remaining has a trailing space */ g_string_append_printf (buf, "Receiving delta parts: %u/%u %s/%s %s/s %sremaining", @@ -4891,7 +4891,7 @@ ostree_repo_add_gpg_signature_summary (OstreeRepo *self, g_autoptr(GVariant) metadata = NULL; if (!ot_openat_ignore_enoent (self->repo_dir_fd, "summary.sig", &fd, error)) return FALSE; - if (fd != -1) + if (fd >= 0) { if (!ot_variant_read_fd (fd, 0, G_VARIANT_TYPE (OSTREE_SUMMARY_SIG_GVARIANT_STRING), FALSE, &metadata, error)) @@ -5384,8 +5384,8 @@ summary_add_ref_entry (OstreeRepo *self, * regular, setting the `ostree.summary.expires` key in @additional_metadata * will aid clients in working out when to check for updates. * - * It is regenerated automatically after a commit if - * `core/commit-update-summary` is set. + * It is regenerated automatically after any ref is + * added, removed, or updated if `core/auto-update-summary` is set. * * If the `core/collection-id` key is set in the configuration, it will be * included as %OSTREE_SUMMARY_COLLECTION_ID in the summary file. Refs that @@ -5393,6 +5393,8 @@ summary_add_ref_entry (OstreeRepo *self, * file, listed under the %OSTREE_SUMMARY_COLLECTION_MAP key. Collection IDs * and refs in %OSTREE_SUMMARY_COLLECTION_MAP are guaranteed to be in * lexicographic order. + * + * Locking: exclusive */ gboolean ostree_repo_regenerate_summary (OstreeRepo *self, @@ -5400,6 +5402,18 @@ ostree_repo_regenerate_summary (OstreeRepo *self, GCancellable *cancellable, GError **error) { + /* Take an exclusive lock. This makes sure the commits and deltas don't get + * deleted while generating the summary. It also means we can be sure refs + * won't be created/updated/deleted during the operation, without having to + * add exclusive locks to those operations which would prevent concurrent + * commits from working. + */ + g_autoptr(OstreeRepoAutoLock) lock = NULL; + lock = _ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, + cancellable, error); + if (!lock) + return FALSE; + g_auto(GVariantDict) additional_metadata_builder = OT_VARIANT_BUILDER_INITIALIZER; g_variant_dict_init (&additional_metadata_builder, additional_metadata); g_autoptr(GVariantBuilder) refs_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(s(taya{sv}))")); @@ -5577,6 +5591,37 @@ ostree_repo_regenerate_summary (OstreeRepo *self, return TRUE; } +/* Regenerate the summary if `core/auto-update-summary` is set. We default to FALSE for + * this setting because OSTree supports multiple processes committing to the same repo (but + * different refs) concurrently, and in fact gnome-continuous actually does this. In that + * context it's best to update the summary explicitly once at the end of multiple + * transactions instead of automatically here. `auto-update-summary` only updates + * atomically within a transaction. */ +gboolean +_ostree_repo_maybe_regenerate_summary (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + gboolean auto_update_summary; + if (!ot_keyfile_get_boolean_with_default (self->config, "core", + "auto-update-summary", FALSE, + &auto_update_summary, error)) + return FALSE; + + /* Deprecated alias for `auto-update-summary`. */ + gboolean commit_update_summary; + if (!ot_keyfile_get_boolean_with_default (self->config, "core", + "commit-update-summary", FALSE, + &commit_update_summary, error)) + return FALSE; + + if ((auto_update_summary || commit_update_summary) && + !ostree_repo_regenerate_summary (self, NULL, cancellable, error)) + return FALSE; + + return TRUE; +} + gboolean _ostree_repo_is_locked_tmpdir (const char *filename) { diff --git a/src/libostree/ostree-version.h b/src/libostree/ostree-version.h index b3d558ac..4a754ead 100644 --- a/src/libostree/ostree-version.h +++ b/src/libostree/ostree-version.h @@ -43,7 +43,7 @@ * * Since: 2017.4 */ -#define OSTREE_RELEASE_VERSION (7) +#define OSTREE_RELEASE_VERSION (8) /** * OSTREE_VERSION @@ -52,7 +52,7 @@ * * Since: 2017.4 */ -#define OSTREE_VERSION (2018.7) +#define OSTREE_VERSION (2018.8) /** * OSTREE_VERSION_S: @@ -62,7 +62,7 @@ * * Since: 2017.4 */ -#define OSTREE_VERSION_S "2018.7" +#define OSTREE_VERSION_S "2018.8" #define OSTREE_ENCODE_VERSION(year,release) \ ((year) << 16 | (release)) diff --git a/src/libotutil/ot-gpg-utils.c b/src/libotutil/ot-gpg-utils.c index 9d5c8d3a..cc5b0ae4 100644 --- a/src/libotutil/ot-gpg-utils.c +++ b/src/libotutil/ot-gpg-utils.c @@ -262,10 +262,8 @@ data_read_cb (void *handle, void *buffer, size_t size) g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), -1); - g_input_stream_read_all (input_stream, buffer, size, - &bytes_read, NULL, &local_error); - - if (local_error != NULL) + if (!g_input_stream_read_all (input_stream, buffer, size, + &bytes_read, NULL, &local_error)) { set_errno_from_gio_error (local_error); g_clear_error (&local_error); @@ -287,7 +285,7 @@ data_write_cb (void *handle, const void *buffer, size_t size) if (g_output_stream_write_all (output_stream, buffer, size, &bytes_written, NULL, &local_error)) { - g_output_stream_flush (output_stream, NULL, &local_error); + (void)g_output_stream_flush (output_stream, NULL, &local_error); } if (local_error != NULL) diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c index c2f78700..535239be 100644 --- a/src/ostree/ot-builtin-commit.c +++ b/src/ostree/ot-builtin-commit.c @@ -752,7 +752,6 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio if (!skip_commit) { - gboolean update_summary; guint64 timestamp; if (!opt_no_bindings) @@ -823,22 +822,6 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio if (!ostree_repo_commit_transaction (repo, &stats, cancellable, error)) goto out; - - /* The default for this option is FALSE, even for archive repos, - * because ostree supports multiple processes committing to the same - * repo (but different refs) concurrently, and in fact gnome-continuous - * actually does this. In that context it's best to update the summary - * explicitly instead of automatically here. */ - if (!ot_keyfile_get_boolean_with_default (ostree_repo_get_config (repo), "core", - "commit-update-summary", FALSE, - &update_summary, error)) - goto out; - - if (update_summary && !ostree_repo_regenerate_summary (repo, - NULL, - cancellable, - error)) - goto out; } else { diff --git a/src/ostree/ot-builtin-config.c b/src/ostree/ot-builtin-config.c index 89bf3df9..4368f50c 100644 --- a/src/ostree/ot-builtin-config.c +++ b/src/ostree/ot-builtin-config.c @@ -28,12 +28,15 @@ #include "ostree.h" #include "otutil.h" +static char* opt_group; + /* ATTENTION: * Please remember to update the bash-completion script (bash/ostree) and * man page (man/ostree-config.xml) when changing the option list. */ static GOptionEntry options[] = { + { "group", 0, 0, G_OPTION_ARG_STRING, &opt_group , "Group name", NULL }, { NULL } }; @@ -44,7 +47,7 @@ split_key_string (const char *k, GError **error) { const char *dot = strchr (k, '.'); - + if (!dot) { return glnx_throw (error, @@ -85,18 +88,31 @@ ostree_builtin_config (int argc, char **argv, OstreeCommandInvocation *invocatio if (!strcmp (op, "set")) { - if (argc < 4) + if (opt_group) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "KEY and VALUE must be specified"); - goto out; + if (argc < 4) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "GROUP name, KEY and VALUE must be specified"); + goto out; + } + section = g_strdup(opt_group); + key = g_strdup(argv[2]); + value = argv[3]; + } + else + { + if (argc < 4) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "KEY and VALUE must be specified"); + goto out; + } + section_key = argv[2]; + value = argv[3]; + if(!split_key_string (section_key, §ion, &key, error)) + goto out; } - - section_key = argv[2]; - value = argv[3]; - - if (!split_key_string (section_key, §ion, &key, error)) - goto out; config = ostree_repo_copy_config (repo); g_key_file_set_string (config, section, key, value); @@ -108,17 +124,29 @@ ostree_builtin_config (int argc, char **argv, OstreeCommandInvocation *invocatio { GKeyFile *readonly_config = NULL; g_autofree char *value = NULL; - if (argc < 3) + if (opt_group) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "KEY must be specified"); - goto out; + if (argc < 3) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Group name and key must be specified"); + goto out; + } + section = g_strdup(opt_group); + key = g_strdup(argv[2]); + } + else + { + if(argc < 3) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "KEY must be specified"); + goto out; + } + section_key = argv[2]; + if (!split_key_string (section_key, §ion, &key, error)) + goto out; } - - section_key = argv[2]; - - if (!split_key_string (section_key, §ion, &key, error)) - goto out; readonly_config = ostree_repo_get_config (repo); value = g_key_file_get_string (readonly_config, section, key, error); @@ -133,7 +161,7 @@ ostree_builtin_config (int argc, char **argv, OstreeCommandInvocation *invocatio "Unknown operation %s", op); goto out; } - + ret = TRUE; out: if (config) diff --git a/src/ostree/ot-builtin-refs.c b/src/ostree/ot-builtin-refs.c index a7f77ac8..5c2214cc 100644 --- a/src/ostree/ot-builtin-refs.c +++ b/src/ostree/ot-builtin-refs.c @@ -293,7 +293,7 @@ ostree_builtin_refs (int argc, char **argv, OstreeCommandInvocation *invocation, else if (opt_create) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "You must specify an existing ref when creating a new ref"); + "You must specify a revision when creating a new ref"); goto out; } diff --git a/tests/test-auto-summary.sh b/tests/test-auto-summary.sh index b12f1593..3a04f184 100755 --- a/tests/test-auto-summary.sh +++ b/tests/test-auto-summary.sh @@ -29,6 +29,7 @@ echo "1..4" setup_test_repository "bare" echo "ok setup" +# Check that without commit-update-summary set, creating a commit doesn't update the summary mkdir test echo hello > test/a @@ -47,6 +48,7 @@ echo "ok commit 2" assert_streq "$OLD_MD5" "$(md5sum repo/summary)" +# Check that with commit-update-summary set, creating a commit updates the summary $OSTREE --repo=repo config set core.commit-update-summary true echo hello3 > test/a @@ -56,7 +58,46 @@ echo "ok commit 3" assert_not_streq "$OLD_MD5" "$(md5sum repo/summary)" +$OSTREE --repo=repo config set core.commit-update-summary false + # Check that summary --update deletes the .sig file touch repo/summary.sig $OSTREE summary --update assert_not_has_file repo/summary.sig + +# Check that without auto-update-summary set, adding, changing, or deleting a ref doesn't update the summary +$OSTREE summary --update +OLD_MD5=$(md5sum repo/summary) +$OSTREE commit -b test2 -s "A commit" test + +assert_streq "$OLD_MD5" "$(md5sum repo/summary)" + +$OSTREE reset test test^ + +assert_streq "$OLD_MD5" "$(md5sum repo/summary)" + +$OSTREE refs --delete test + +assert_streq "$OLD_MD5" "$(md5sum repo/summary)" + +# Check that with auto-update-summary set, adding, changing, or deleting a ref updates the summary +$OSTREE --repo=repo config set core.auto-update-summary true + +$OSTREE summary --update +OLD_MD5=$(md5sum repo/summary) +echo hello > test/a +$OSTREE commit -b test -s "A commit" test +echo hello2 > test/a +$OSTREE commit -b test -s "Another commit" test + +assert_not_streq "$OLD_MD5" "$(md5sum repo/summary)" + +OLD_MD5=$(md5sum repo/summary) +$OSTREE reset test test^ + +assert_not_streq "$OLD_MD5" "$(md5sum repo/summary)" + +OLD_MD5=$(md5sum repo/summary) +$OSTREE refs --delete test + +assert_not_streq "$OLD_MD5" "$(md5sum repo/summary)" diff --git a/tests/test-config.sh b/tests/test-config.sh new file mode 100755 index 00000000..b1ea3e5e --- /dev/null +++ b/tests/test-config.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# +# Copyright (C) 2018 Sinny Kumari +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo '1..2' + +ostree_repo_init repo +${CMD_PREFIX} ostree remote add --repo=repo --set=xa.title=Flathub --set=xa.title-is-set=true flathub https://dl.flathub.org/repo/ +${CMD_PREFIX} ostree remote add --repo=repo org.mozilla.FirefoxRepo http://example.com/ostree/repo/ + +${CMD_PREFIX} ostree config --repo=repo get core.mode > list.txt +${CMD_PREFIX} ostree config --repo=repo get --group=core repo_version >> list.txt +${CMD_PREFIX} ostree config --repo=repo get --group='remote "flathub"' 'xa.title' >> list.txt +${CMD_PREFIX} ostree config --repo=repo get --group='remote "flathub"' 'xa.title-is-set' >> list.txt +${CMD_PREFIX} ostree config --repo=repo get --group='remote "org.mozilla.FirefoxRepo"' url >> list.txt +${CMD_PREFIX} cat list.txt + +assert_file_has_content list.txt "bare" +assert_file_has_content list.txt "1" +assert_file_has_content list.txt "Flathub" +assert_file_has_content list.txt "true" +assert_file_has_content list.txt "http://example.com/ostree/repo/" +echo "ok config get" + +${CMD_PREFIX} ostree config --repo=repo set core.mode bare-user-only +${CMD_PREFIX} ostree config --repo=repo set --group='remote "flathub"' 'xa.title' 'Nightly Flathub' +${CMD_PREFIX} ostree config --repo=repo set --group='remote "flathub"' 'xa.title-is-set' 'false' +${CMD_PREFIX} ostree config --repo=repo set --group='remote "org.mozilla.FirefoxRepo"' url http://example.com/ostree/ + +assert_file_has_content repo/config "bare-user-only" +assert_file_has_content repo/config "Nightly Flathub" +assert_file_has_content repo/config "false" +assert_file_has_content repo/config "http://example.com/ostree/" +echo "ok config set" diff --git a/tests/test-pull-summary-sigs.sh b/tests/test-pull-summary-sigs.sh index c6d04f41..dee186b5 100755 --- a/tests/test-pull-summary-sigs.sh +++ b/tests/test-pull-summary-sigs.sh @@ -23,7 +23,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -echo "1..7" +echo "1..10" COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" @@ -151,4 +151,128 @@ grep static-deltas summary.txt > static-deltas.txt assert_file_has_content static-deltas.txt \ $(${OSTREE} --repo=repo rev-parse origin:main) +## Tests for handling of cached summaries while racing with remote summary updates + +# Make 2 different but valid summary/signature pairs to test races with +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{,.1} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{,.1} +mkdir ${test_tmpdir}/ostree-srv/even-another-files +cd ${test_tmpdir}/ostree-srv/even-another-files +echo 'hello world even another object' > even-another-hello-world +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_SIGN} -b even-another -s "A commit" -m "Another Commit body" +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{,.2} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{,.2} +cd ${test_tmpdir} + +# Reset to the old valid summary and pull to cache it +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.1,} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.1,} +repo_reinit +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Simulate a pull race where the client gets the old summary and the new +# summary signature since it was generated on the server between the +# requests +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.2,} +if ${OSTREE} --repo=repo pull origin main 2>err.txt; then + assert_not_reached "Successful pull with old summary" +fi +assert_file_has_content err.txt "none are in trusted keyring" +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Publish correct summary and check that subsequent pull succeeds +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.2,} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.2 >&2 + +echo "ok pull with signed summary remote old summary" + +# Reset to the old valid summary and pull to cache it +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.1,} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.1,} +repo_reinit +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Simulate a pull race where the client gets the new summary and the old +# summary signature. This is unlikely to happen except if the web server +# is caching the old signature. This should succeed because the cached +# old summary is used. +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.2,} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Publish correct signature and check that subsequent pull succeeds +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.2,} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.2 >&2 + +echo "ok pull with signed summary remote old summary signature" + +# Reset to the old valid summary and pull to cache it +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.1,} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.1,} +repo_reinit +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Simulate a broken summary cache to see if it can be recovered from. +# Prior to commit c4c2b5eb the client would save the summary to the +# cache before validating the signature. That would mean the cache would +# have mismatched summary and signature and ostree would remain +# deadlocked there until the remote published a new signature. +# +# First pull with OSTREE_REPO_TEST_ERROR=invalid-cache to see the +# invalid cache is detected. Then pull again to check if it can be +# recovered from. +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 repo/tmp/cache/summaries/origin +if OSTREE_REPO_TEST_ERROR=invalid-cache ${OSTREE} --repo=repo pull origin main 2>err.txt; then + assert_not_reached "Should have hit OSTREE_REPO_TEST_ERROR_INVALID_CACHE" +fi +assert_file_has_content err.txt "OSTREE_REPO_TEST_ERROR_INVALID_CACHE" +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Publish new signature and check that subsequent pull succeeds +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.2,} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.2,} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.2 >&2 + +echo "ok pull with signed summary broken cache" + libtest_cleanup_gpg diff --git a/tests/test-symbols.sh b/tests/test-symbols.sh index faf58dcf..df7f8648 100755 --- a/tests/test-symbols.sh +++ b/tests/test-symbols.sh @@ -54,7 +54,7 @@ echo 'ok documented symbols' # ONLY update this checksum in release commits! cat > released-sha256.txt <