lib/pull: Add OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES
This is an option which is intended mostly for flatpak; see: https://github.com/flatpak/flatpak/issues/845 We're adding an option for pulling into *all* repo modes that has an effect similar to the `bare-user-only` change from https://github.com/ostreedev/ostree/pull/909 This way one can pull content into e.g. a root-owned `bare` repository and ensure that there aren't any setuid or world-writable files. Closes: #926 Approved by: alexlarsson
This commit is contained in:
parent
74e3581ed6
commit
6ed824bf00
|
|
@ -111,6 +111,7 @@ typedef struct {
|
||||||
gboolean is_mirror;
|
gboolean is_mirror;
|
||||||
gboolean is_commit_only;
|
gboolean is_commit_only;
|
||||||
gboolean is_untrusted;
|
gboolean is_untrusted;
|
||||||
|
gboolean is_bareuseronly_files;
|
||||||
|
|
||||||
GPtrArray *dirs;
|
GPtrArray *dirs;
|
||||||
|
|
||||||
|
|
@ -556,6 +557,94 @@ pull_matches_subdir (OtPullData *pull_data,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This bit mirrors similar code in commit_loose_content_object() for the
|
||||||
|
* bare-user-only mode. It's opt-in though for all pulls.
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
validate_bareuseronly_mode (OtPullData *pull_data,
|
||||||
|
const char *checksum,
|
||||||
|
guint32 content_mode,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
if (!pull_data->is_bareuseronly_files)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (S_ISREG (content_mode))
|
||||||
|
{
|
||||||
|
const guint32 invalid_modebits = ((content_mode & ~S_IFMT) & ~0775);
|
||||||
|
if (invalid_modebits > 0)
|
||||||
|
return glnx_throw (error, "object %s.file: invalid mode 0%04o with bits 0%04o",
|
||||||
|
checksum, content_mode, invalid_modebits);
|
||||||
|
}
|
||||||
|
else if (S_ISLNK (content_mode))
|
||||||
|
; /* Nothing */
|
||||||
|
else
|
||||||
|
g_assert_not_reached ();
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Import a single content object in the case where
|
||||||
|
* we have pull_data->remote_repo_local.
|
||||||
|
*
|
||||||
|
* One important special case here is handling the
|
||||||
|
* OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES flag.
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
import_one_local_content_object (OtPullData *pull_data,
|
||||||
|
const char *checksum,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_assert (pull_data->remote_repo_local);
|
||||||
|
|
||||||
|
const gboolean trusted = !pull_data->is_untrusted;
|
||||||
|
if (trusted && !pull_data->is_bareuseronly_files)
|
||||||
|
{
|
||||||
|
if (!ostree_repo_import_object_from_with_trust (pull_data->repo, pull_data->remote_repo_local,
|
||||||
|
OSTREE_OBJECT_TYPE_FILE, checksum,
|
||||||
|
trusted,
|
||||||
|
cancellable, error))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* In this case we either need to validate the checksum
|
||||||
|
* or the file mode.
|
||||||
|
*/
|
||||||
|
g_autoptr(GInputStream) content_input = NULL;
|
||||||
|
g_autoptr(GFileInfo) content_finfo = NULL;
|
||||||
|
g_autoptr(GVariant) content_xattrs = NULL;
|
||||||
|
|
||||||
|
if (!ostree_repo_load_file (pull_data->remote_repo_local, checksum,
|
||||||
|
&content_input, &content_finfo, &content_xattrs,
|
||||||
|
cancellable, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!validate_bareuseronly_mode (pull_data, checksum,
|
||||||
|
g_file_info_get_attribute_uint32 (content_finfo, "unix::mode"),
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Now that we've potentially validated it, convert to object stream */
|
||||||
|
guint64 length;
|
||||||
|
g_autoptr(GInputStream) object_stream = NULL;
|
||||||
|
if (!ostree_raw_file_to_content_stream (content_input, content_finfo,
|
||||||
|
content_xattrs, &object_stream,
|
||||||
|
&length, cancellable, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
g_autofree guchar *real_csum = NULL;
|
||||||
|
if (!ostree_repo_write_content (pull_data->repo, checksum,
|
||||||
|
object_stream, length,
|
||||||
|
&real_csum,
|
||||||
|
cancellable, error))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
scan_dirtree_object (OtPullData *pull_data,
|
scan_dirtree_object (OtPullData *pull_data,
|
||||||
const char *checksum,
|
const char *checksum,
|
||||||
|
|
@ -595,15 +684,19 @@ scan_dirtree_object (OtPullData *pull_data,
|
||||||
&file_is_stored, cancellable, error))
|
&file_is_stored, cancellable, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (!file_is_stored && pull_data->remote_repo_local)
|
/* If we already have this object, move on to the next */
|
||||||
|
if (file_is_stored)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Is this a local repo? */
|
||||||
|
if (pull_data->remote_repo_local)
|
||||||
{
|
{
|
||||||
if (!ostree_repo_import_object_from_with_trust (pull_data->repo, pull_data->remote_repo_local,
|
if (!import_one_local_content_object (pull_data, file_checksum, cancellable, error))
|
||||||
OSTREE_OBJECT_TYPE_FILE, file_checksum, !pull_data->is_untrusted,
|
|
||||||
cancellable, error))
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
else if (!file_is_stored && !g_hash_table_lookup (pull_data->requested_content, file_checksum))
|
else if (!g_hash_table_lookup (pull_data->requested_content, file_checksum))
|
||||||
{
|
{
|
||||||
|
/* In this case we're doing HTTP pulls */
|
||||||
g_hash_table_add (pull_data->requested_content, file_checksum);
|
g_hash_table_add (pull_data->requested_content, file_checksum);
|
||||||
enqueue_one_object_request (pull_data, file_checksum, OSTREE_OBJECT_TYPE_FILE, path, FALSE, FALSE);
|
enqueue_one_object_request (pull_data, file_checksum, OSTREE_OBJECT_TYPE_FILE, path, FALSE, FALSE);
|
||||||
file_checksum = NULL; /* Transfer ownership */
|
file_checksum = NULL; /* Transfer ownership */
|
||||||
|
|
@ -2775,6 +2868,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||||
pull_data->is_mirror = (flags & OSTREE_REPO_PULL_FLAGS_MIRROR) > 0;
|
pull_data->is_mirror = (flags & OSTREE_REPO_PULL_FLAGS_MIRROR) > 0;
|
||||||
pull_data->is_commit_only = (flags & OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY) > 0;
|
pull_data->is_commit_only = (flags & OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY) > 0;
|
||||||
pull_data->is_untrusted = (flags & OSTREE_REPO_PULL_FLAGS_UNTRUSTED) > 0;
|
pull_data->is_untrusted = (flags & OSTREE_REPO_PULL_FLAGS_UNTRUSTED) > 0;
|
||||||
|
pull_data->is_bareuseronly_files = (flags & OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES) > 0;
|
||||||
pull_data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
|
pull_data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
|
|
@ -3042,11 +3136,21 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For local pulls, default to disabling static deltas so that the
|
if (pull_data->remote_repo_local)
|
||||||
* exact object files are copied.
|
{
|
||||||
*/
|
/* For local pulls, default to disabling static deltas so that the
|
||||||
if (pull_data->remote_repo_local && !pull_data->require_static_deltas)
|
* exact object files are copied.
|
||||||
pull_data->disable_static_deltas = TRUE;
|
*/
|
||||||
|
if (!pull_data->require_static_deltas)
|
||||||
|
pull_data->disable_static_deltas = TRUE;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (pull_data->is_bareuseronly_files)
|
||||||
|
{
|
||||||
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Can't use bareuseronly-files with non-local origin repo");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* We can't use static deltas if pulling into an archive-z2 repo. */
|
/* We can't use static deltas if pulling into an archive-z2 repo. */
|
||||||
if (self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2)
|
if (self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2)
|
||||||
|
|
|
||||||
|
|
@ -1015,12 +1015,14 @@ gboolean ostree_repo_prune_from_reachable (OstreeRepo *self,
|
||||||
* @OSTREE_REPO_PULL_FLAGS_MIRROR: Write out refs suitable for mirrors
|
* @OSTREE_REPO_PULL_FLAGS_MIRROR: Write out refs suitable for mirrors
|
||||||
* @OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY: Fetch only the commit metadata
|
* @OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY: Fetch only the commit metadata
|
||||||
* @OSTREE_REPO_PULL_FLAGS_UNTRUSTED: Don't trust local remote
|
* @OSTREE_REPO_PULL_FLAGS_UNTRUSTED: Don't trust local remote
|
||||||
|
* @OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES: Since 2017.7. Reject writes of content objects with modes outside of 0775.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OSTREE_REPO_PULL_FLAGS_NONE,
|
OSTREE_REPO_PULL_FLAGS_NONE,
|
||||||
OSTREE_REPO_PULL_FLAGS_MIRROR = (1 << 0),
|
OSTREE_REPO_PULL_FLAGS_MIRROR = (1 << 0),
|
||||||
OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY = (1 << 1),
|
OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY = (1 << 1),
|
||||||
OSTREE_REPO_PULL_FLAGS_UNTRUSTED = (1 << 2)
|
OSTREE_REPO_PULL_FLAGS_UNTRUSTED = (1 << 2),
|
||||||
|
OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES = (1 << 3)
|
||||||
} OstreeRepoPullFlags;
|
} OstreeRepoPullFlags;
|
||||||
|
|
||||||
_OSTREE_PUBLIC
|
_OSTREE_PUBLIC
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
static char *opt_remote;
|
static char *opt_remote;
|
||||||
static gboolean opt_disable_fsync;
|
static gboolean opt_disable_fsync;
|
||||||
static gboolean opt_untrusted;
|
static gboolean opt_untrusted;
|
||||||
|
static gboolean opt_bareuseronly_files;
|
||||||
static gboolean opt_require_static_deltas;
|
static gboolean opt_require_static_deltas;
|
||||||
static gboolean opt_gpg_verify;
|
static gboolean opt_gpg_verify;
|
||||||
static gboolean opt_gpg_verify_summary;
|
static gboolean opt_gpg_verify_summary;
|
||||||
|
|
@ -42,6 +43,7 @@ static GOptionEntry options[] = {
|
||||||
{ "remote", 0, 0, G_OPTION_ARG_STRING, &opt_remote, "Add REMOTE to refspec", "REMOTE" },
|
{ "remote", 0, 0, G_OPTION_ARG_STRING, &opt_remote, "Add REMOTE to refspec", "REMOTE" },
|
||||||
{ "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL },
|
{ "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL },
|
||||||
{ "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust source", NULL },
|
{ "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust source", NULL },
|
||||||
|
{ "bareuseronly-files", 0, 0, G_OPTION_ARG_NONE, &opt_bareuseronly_files, "Reject regular files with mode outside of 0775 (world writable, suid, etc.)", NULL },
|
||||||
{ "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_require_static_deltas, "Require static deltas", NULL },
|
{ "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_require_static_deltas, "Require static deltas", NULL },
|
||||||
{ "gpg-verify", 0, 0, G_OPTION_ARG_NONE, &opt_gpg_verify, "GPG verify commits (must specify --remote)", NULL },
|
{ "gpg-verify", 0, 0, G_OPTION_ARG_NONE, &opt_gpg_verify, "GPG verify commits (must specify --remote)", NULL },
|
||||||
{ "gpg-verify-summary", 0, 0, G_OPTION_ARG_NONE, &opt_gpg_verify_summary, "GPG verify summary (must specify --remote)", NULL },
|
{ "gpg-verify-summary", 0, 0, G_OPTION_ARG_NONE, &opt_gpg_verify_summary, "GPG verify summary (must specify --remote)", NULL },
|
||||||
|
|
@ -92,6 +94,8 @@ ostree_builtin_pull_local (int argc, char **argv, GCancellable *cancellable, GEr
|
||||||
|
|
||||||
if (opt_untrusted)
|
if (opt_untrusted)
|
||||||
pullflags |= OSTREE_REPO_PULL_FLAGS_UNTRUSTED;
|
pullflags |= OSTREE_REPO_PULL_FLAGS_UNTRUSTED;
|
||||||
|
if (opt_bareuseronly_files)
|
||||||
|
pullflags |= OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES;
|
||||||
|
|
||||||
if (opt_disable_fsync)
|
if (opt_disable_fsync)
|
||||||
ostree_repo_set_disable_fsync (repo, TRUE);
|
ostree_repo_set_disable_fsync (repo, TRUE);
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ static gboolean opt_dry_run;
|
||||||
static gboolean opt_disable_static_deltas;
|
static gboolean opt_disable_static_deltas;
|
||||||
static gboolean opt_require_static_deltas;
|
static gboolean opt_require_static_deltas;
|
||||||
static gboolean opt_untrusted;
|
static gboolean opt_untrusted;
|
||||||
|
static gboolean opt_bareuseronly_files;
|
||||||
static char** opt_subpaths;
|
static char** opt_subpaths;
|
||||||
static char** opt_http_headers;
|
static char** opt_http_headers;
|
||||||
static char* opt_cache_dir;
|
static char* opt_cache_dir;
|
||||||
|
|
@ -50,6 +51,7 @@ static GOptionEntry options[] = {
|
||||||
{ "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Write refs suitable for a mirror", NULL },
|
{ "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Write refs suitable for a mirror", NULL },
|
||||||
{ "subpath", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_subpaths, "Only pull the provided subpath(s)", NULL },
|
{ "subpath", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_subpaths, "Only pull the provided subpath(s)", NULL },
|
||||||
{ "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust (local) sources", NULL },
|
{ "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust (local) sources", NULL },
|
||||||
|
{ "bareuseronly-files", 0, 0, G_OPTION_ARG_NONE, &opt_bareuseronly_files, "Reject regular files with mode outside of 0775 (world writable, suid, etc.)", NULL },
|
||||||
{ "dry-run", 0, 0, G_OPTION_ARG_NONE, &opt_dry_run, "Only print information on what will be downloaded (requires static deltas)", NULL },
|
{ "dry-run", 0, 0, G_OPTION_ARG_NONE, &opt_dry_run, "Only print information on what will be downloaded (requires static deltas)", NULL },
|
||||||
{ "depth", 0, 0, G_OPTION_ARG_INT, &opt_depth, "Traverse DEPTH parents (-1=infinite) (default: 0)", "DEPTH" },
|
{ "depth", 0, 0, G_OPTION_ARG_INT, &opt_depth, "Traverse DEPTH parents (-1=infinite) (default: 0)", "DEPTH" },
|
||||||
{ "url", 0, 0, G_OPTION_ARG_STRING, &opt_url, "Pull objects from this URL instead of the one from the remote config", NULL },
|
{ "url", 0, 0, G_OPTION_ARG_STRING, &opt_url, "Pull objects from this URL instead of the one from the remote config", NULL },
|
||||||
|
|
@ -167,6 +169,8 @@ ostree_builtin_pull (int argc, char **argv, GCancellable *cancellable, GError **
|
||||||
|
|
||||||
if (opt_untrusted)
|
if (opt_untrusted)
|
||||||
pullflags |= OSTREE_REPO_PULL_FLAGS_UNTRUSTED;
|
pullflags |= OSTREE_REPO_PULL_FLAGS_UNTRUSTED;
|
||||||
|
if (opt_bareuseronly_files)
|
||||||
|
pullflags |= OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES;
|
||||||
|
|
||||||
if (opt_dry_run && !opt_require_static_deltas)
|
if (opt_dry_run && !opt_require_static_deltas)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
echo "1..$((66 + ${extra_basic_tests:-0}))"
|
echo "1..$((68 + ${extra_basic_tests:-0}))"
|
||||||
|
|
||||||
$CMD_PREFIX ostree --version > version.yaml
|
$CMD_PREFIX ostree --version > version.yaml
|
||||||
python -c 'import yaml; yaml.safe_load(open("version.yaml"))'
|
python -c 'import yaml; yaml.safe_load(open("version.yaml"))'
|
||||||
|
|
@ -267,6 +267,32 @@ test2_commit_relpath=/objects/${test2_commitid:0:2}/${test2_commitid:2}.commit
|
||||||
assert_files_hardlinked repo/${test2_commit_relpath} repo2/${test2_commit_relpath}
|
assert_files_hardlinked repo/${test2_commit_relpath} repo2/${test2_commit_relpath}
|
||||||
echo "ok pull-local (hardlinking metadata)"
|
echo "ok pull-local (hardlinking metadata)"
|
||||||
|
|
||||||
|
cd ${test_tmpdir}
|
||||||
|
rm repo2 -rf && mkdir repo2
|
||||||
|
ostree_repo_init repo2 --mode=$opposite_mode
|
||||||
|
${CMD_PREFIX} ostree --repo=repo2 pull-local --bareuseronly-files repo test2
|
||||||
|
${CMD_PREFIX} ostree --repo=repo2 fsck -q
|
||||||
|
echo "ok pull-local --bareuseronly-files"
|
||||||
|
|
||||||
|
# This is mostly a copy of the suid test in test-basic-user-only.sh,
|
||||||
|
# but for the `pull --bareuseronly-files` case.
|
||||||
|
cd ${test_tmpdir}
|
||||||
|
rm repo-input -rf
|
||||||
|
ostree_repo_init repo-input init --mode=archive
|
||||||
|
cd ${test_tmpdir}
|
||||||
|
cat > statoverride.txt <<EOF
|
||||||
|
2048 /some-setuid
|
||||||
|
EOF
|
||||||
|
mkdir -p files/
|
||||||
|
echo "a setuid file" > files/some-setuid
|
||||||
|
chmod 0644 files/some-setuid
|
||||||
|
$CMD_PREFIX ostree --repo=repo-input commit -b content-with-suid --statoverride=statoverride.txt --tree=dir=files
|
||||||
|
if $CMD_PREFIX ostree pull-local --repo=repo --bareuseronly-files repo-input content-with-suid 2>err.txt; then
|
||||||
|
assert_not_reached "copying suid file with --bareuseronly-files worked?"
|
||||||
|
fi
|
||||||
|
assert_file_has_content err.txt 'object.*\.file: invalid mode.*with bits 040.*'
|
||||||
|
echo "ok pull-local (bareuseronly files)"
|
||||||
|
|
||||||
cd ${test_tmpdir}
|
cd ${test_tmpdir}
|
||||||
${CMD_PREFIX} ostree --repo=repo2 checkout ${CHECKOUT_U_ARG} test2 test2-checkout-from-local-clone
|
${CMD_PREFIX} ostree --repo=repo2 checkout ${CHECKOUT_U_ARG} test2 test2-checkout-from-local-clone
|
||||||
cd test2-checkout-from-local-clone
|
cd test2-checkout-from-local-clone
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ function verify_initial_contents() {
|
||||||
assert_file_has_content baz/cow '^moo$'
|
assert_file_has_content baz/cow '^moo$'
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "1..20"
|
echo "1..21"
|
||||||
|
|
||||||
# Try both syntaxes
|
# Try both syntaxes
|
||||||
repo_init --no-gpg-verify
|
repo_init --no-gpg-verify
|
||||||
|
|
@ -79,6 +79,13 @@ ${CMD_PREFIX} ostree --repo=mirrorrepo pull origin main
|
||||||
${CMD_PREFIX} ostree --repo=mirrorrepo fsck
|
${CMD_PREFIX} ostree --repo=mirrorrepo fsck
|
||||||
echo "ok pull (refuses deltas)"
|
echo "ok pull (refuses deltas)"
|
||||||
|
|
||||||
|
if ${CMD_PREFIX} ostree --repo=mirrorrepo \
|
||||||
|
pull origin main --bareuseronly-files 2>err.txt; then
|
||||||
|
assert_not_reached "--bareuseronly-files unexpectedly succeeded"
|
||||||
|
fi
|
||||||
|
assert_file_has_content err.txt 'bareuseronly-files with non-local'
|
||||||
|
echo "ok pull (refuses bareuseronly)"
|
||||||
|
|
||||||
cd ${test_tmpdir}
|
cd ${test_tmpdir}
|
||||||
rm mirrorrepo/refs/remotes/* -rf
|
rm mirrorrepo/refs/remotes/* -rf
|
||||||
${CMD_PREFIX} ostree --repo=mirrorrepo prune --refs-only
|
${CMD_PREFIX} ostree --repo=mirrorrepo prune --refs-only
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue