Update to 1.18.0

Resolves: RHEL-126038
Resolves: RHEL-92123
Resolves: RHEL-165631
Resolves: RHEL-170158
This commit is contained in:
Jan Grulich 2026-06-11 10:51:42 +00:00
parent b99c73432a
commit 7da9e0d25b
6 changed files with 1464 additions and 18 deletions

1
.gitignore vendored
View File

@ -117,3 +117,4 @@
/flatpak-1.16.0.tar.xz
/flatpak-1.17.2.tar.xz
/flatpak-1.17.3.tar.xz
/flatpak-1.18.0.tar.xz

View File

@ -0,0 +1,970 @@
From 7ccc155aa363f389f52c7676b353ad5c9d6dcfc5 Mon Sep 17 00:00:00 2001
From: Luigi Pavan <lpavan@redhat.com>
Date: Thu, 14 May 2026 12:27:57 +0200
Subject: [PATCH 1/3] oci: Retry on 401 with FlatpakTokenProvider
When a bearer token expires mid-transaction, OCI registry HTTP requests
fail with 401 Unauthorized, causing the entire transaction to fail. This
is particularly problematic for long-running transactions where the
token lifetime is shorter than the total operation time.
Add a token refresh mechanism that allows the OCI registry layer to
transparently retry a failed HTTP request after obtaining a fresh token
via a FlatpakTokenProvider object provided by the transaction layer.
FlatpakTokenProvider is a GObject that encapsulates the ability to
obtain and refresh bearer tokens. It holds references to the transaction
and the current operation, and its refresh_token method re-invokes
request_tokens_for_remote() to get a fresh token from the authenticator.
Its get_token method returns the current token from the operation,
providing a live view that reflects any refresh.
FlatpakTokenProvider replaces the const char *token parameter on the
OCI code path functions, while leaving OSTree-only functions unchanged.
At registry creation points, the provider is set on the registry so it
can be used for retry on 401.
At the FlatpakOciRegistry level, a token_provider field is added. On
401, the three HTTP call sites (remote_load_file, download_blob,
mirror_blob) attempt one token refresh and retry, defensively resetting
any output streams before the retry.
---
common/flatpak-common-types-private.h | 1 +
common/flatpak-dir-private.h | 43 ++++----
common/flatpak-dir.c | 80 +++++++-------
common/flatpak-image-source-private.h | 10 +-
common/flatpak-image-source.c | 20 ++--
common/flatpak-oci-registry-private.h | 2 +
common/flatpak-oci-registry.c | 104 ++++++++++++++++---
common/flatpak-transaction.c | 144 +++++++++++++++++++-------
8 files changed, 288 insertions(+), 116 deletions(-)
diff --git a/common/flatpak-common-types-private.h b/common/flatpak-common-types-private.h
index cb09d78e6d..49bb8bbeeb 100644
--- a/common/flatpak-common-types-private.h
+++ b/common/flatpak-common-types-private.h
@@ -59,5 +59,6 @@ typedef struct _FlatpakImageSource FlatpakImageSource;
typedef struct FlatpakOciRegistry FlatpakOciRegistry;
typedef struct _FlatpakOciManifest FlatpakOciManifest;
typedef struct _FlatpakOciImage FlatpakOciImage;
+typedef struct _FlatpakTokenProvider FlatpakTokenProvider;
#endif /* __FLATPAK_COMMON_TYPES_H__ */
diff --git a/common/flatpak-dir-private.h b/common/flatpak-dir-private.h
index 9a9f8a12a6..431bb96c1a 100644
--- a/common/flatpak-dir-private.h
+++ b/common/flatpak-dir-private.h
@@ -62,6 +62,13 @@ GType flatpak_deploy_get_type (void);
typedef struct _PolkitSubject PolkitSubject;
+#define FLATPAK_TYPE_TOKEN_PROVIDER flatpak_token_provider_get_type ()
+G_DECLARE_FINAL_TYPE (FlatpakTokenProvider, flatpak_token_provider, FLATPAK, TOKEN_PROVIDER, GObject)
+
+const char *flatpak_token_provider_get_token (FlatpakTokenProvider *self);
+gboolean flatpak_token_provider_refresh_token (FlatpakTokenProvider *self,
+ GCancellable *cancellable);
+
typedef struct
{
FlatpakDecomposed *ref;
@@ -160,25 +167,25 @@ gboolean flatpak_remote_state_lookup_sparse_cache (FlatpakRemoteState *self,
const char *ref,
VarMetadataRef *out_metadata,
GError **error);
-GVariant *flatpak_remote_state_load_ref_commit (FlatpakRemoteState *self,
- FlatpakDir *dir,
- const char *ref,
- const char *opt_commit,
- const char *token,
- char **out_commit,
- GCancellable *cancellable,
- GError **error);
+GVariant *flatpak_remote_state_load_ref_commit (FlatpakRemoteState *self,
+ FlatpakDir *dir,
+ const char *ref,
+ const char *opt_commit,
+ FlatpakTokenProvider *token_provider,
+ char **out_commit,
+ GCancellable *cancellable,
+ GError **error);
void flatpak_remote_state_add_sideload_dir (FlatpakRemoteState *self,
GFile *path);
void flatpak_remote_state_add_sideload_image_collection (FlatpakRemoteState *self,
FlatpakImageCollection *image_collection);
-FlatpakImageSource * flatpak_remote_state_fetch_image_source (FlatpakRemoteState *self,
- FlatpakDir *dir,
- const char *ref,
- const char *opt_rev,
- const char *token,
- GCancellable *cancellable,
- GError **error);
+FlatpakImageSource * flatpak_remote_state_fetch_image_source (FlatpakRemoteState *self,
+ FlatpakDir *dir,
+ const char *ref,
+ const char *opt_rev,
+ FlatpakTokenProvider *token_provider,
+ GCancellable *cancellable,
+ GError **error);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakDir, g_object_unref)
@@ -611,7 +618,7 @@ gboolean flatpak_dir_pull (Fla
GFile *sideload_repo,
FlatpakImageSource *opt_image_source,
GBytes *require_metadata,
- const char *token,
+ FlatpakTokenProvider *token_provider,
OstreeRepo *repo,
FlatpakPullFlags flatpak_flags,
OstreeRepoPullFlags flags,
@@ -735,7 +742,7 @@ gboolean flatpak_dir_install (Fla
GFile *sideload_repo,
FlatpakImageSource *opt_image_source,
GBytes *require_metadata,
- const char *token,
+ FlatpakTokenProvider *token_provider,
FlatpakProgress *progress,
GCancellable *cancellable,
GError **error);
@@ -783,7 +790,7 @@ gboolean flatpak_dir_update (Fla
GFile *sideload_repo,
FlatpakImageSource *opt_image_source,
GBytes *require_metadata,
- const char *token,
+ FlatpakTokenProvider *token_provider,
FlatpakProgress *progress,
GCancellable *cancellable,
GError **error);
diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c
index 73118e1127..da96153eb1 100644
--- a/common/flatpak-dir.c
+++ b/common/flatpak-dir.c
@@ -116,7 +116,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (AutoPolkitSubject, g_object_unref)
static FlatpakOciRegistry *flatpak_dir_create_system_child_oci_registry (FlatpakDir *self,
GLnxLockFile *file_lock,
- const char *token,
+ FlatpakTokenProvider *token_provider,
GError **error);
static OstreeRepo * flatpak_dir_create_child_repo (FlatpakDir *self,
@@ -135,7 +135,7 @@ static gboolean flatpak_dir_mirror_oci (FlatpakDir *self,
const char *ref,
const char *opt_rev,
FlatpakImageSource *opt_image_source,
- const char *token,
+ FlatpakTokenProvider *token_provider,
FlatpakProgress *progress,
GCancellable *cancellable,
GError **error);
@@ -1209,7 +1209,7 @@ flatpak_remote_state_new_image_source (FlatpakRemoteState *self,
FlatpakDir *dir,
const char *oci_repository,
const char *digest,
- const char *token,
+ FlatpakTokenProvider *token_provider,
GCancellable *cancellable,
GError **error)
{
@@ -1229,7 +1229,7 @@ flatpak_remote_state_new_image_source (FlatpakRemoteState *self,
image_source = flatpak_image_source_new_remote (registry_uri,
oci_repository,
digest,
- token,
+ token_provider,
signature_lookaside,
NULL, error);
if (image_source == NULL)
@@ -1243,7 +1243,7 @@ flatpak_remote_state_fetch_image_source (FlatpakRemoteState *self,
FlatpakDir *dir,
const char *ref,
const char *opt_rev,
- const char *token,
+ FlatpakTokenProvider *token_provider,
GCancellable *cancellable,
GError **error)
{
@@ -1277,7 +1277,7 @@ flatpak_remote_state_fetch_image_source (FlatpakRemoteState *self,
oci_digest = g_strconcat ("sha256:", opt_rev ? opt_rev : latest_rev, NULL);
- image_source = flatpak_remote_state_new_image_source (self, dir, oci_repository, oci_digest, token, cancellable, error);
+ image_source = flatpak_remote_state_new_image_source (self, dir, oci_repository, oci_digest, token_provider, cancellable, error);
if (image_source == NULL)
return NULL;
@@ -1302,13 +1302,13 @@ flatpak_remote_state_fetch_commit_object_oci (FlatpakRemoteState *self,
FlatpakDir *dir,
const char *ref,
const char *checksum,
- const char *token,
+ FlatpakTokenProvider *token_provider,
GCancellable *cancellable,
GError **error)
{
g_autoptr(FlatpakImageSource) image_source = NULL;
- image_source = flatpak_remote_state_fetch_image_source (self, dir, ref, checksum, token, cancellable, error);
+ image_source = flatpak_remote_state_fetch_image_source (self, dir, ref, checksum, token_provider, cancellable, error);
if (image_source == NULL)
return NULL;
@@ -1430,7 +1430,7 @@ flatpak_remote_state_load_ref_commit (FlatpakRemoteState *self,
FlatpakDir *dir,
const char *ref,
const char *opt_commit,
- const char *token,
+ FlatpakTokenProvider *token_provider,
char **out_commit,
GCancellable *cancellable,
GError **error)
@@ -1481,11 +1481,16 @@ flatpak_remote_state_load_ref_commit (FlatpakRemoteState *self,
}
if (flatpak_dir_get_remote_oci (dir, self->remote_name))
- commit_data = flatpak_remote_state_fetch_commit_object_oci (self, dir, ref, commit, token,
- cancellable, error);
+ {
+ commit_data = flatpak_remote_state_fetch_commit_object_oci (self, dir, ref, commit, token_provider,
+ cancellable, error);
+ }
else
- commit_data = flatpak_remote_state_fetch_commit_object (self, dir, ref, commit, token,
- cancellable, error);
+ {
+ const char *token = token_provider ? flatpak_token_provider_get_token (token_provider) : NULL;
+ commit_data = flatpak_remote_state_fetch_commit_object (self, dir, ref, commit, token,
+ cancellable, error);
+ }
out:
if (out_commit)
@@ -6317,7 +6322,7 @@ flatpak_dir_setup_extra_data (FlatpakDir *self,
OstreeRepo *repo,
const char *ref,
const char *rev,
- const char *token,
+ FlatpakTokenProvider *token_provider,
FlatpakPullFlags flatpak_flags,
FlatpakProgress *progress,
GCancellable *cancellable,
@@ -6362,7 +6367,7 @@ flatpak_dir_setup_extra_data (FlatpakDir *self,
g_autoptr(GVariant) extra_data_sources = NULL;
commitv = flatpak_remote_state_load_ref_commit (state, self, ref, rev,
- token, NULL, cancellable, error);
+ token_provider, NULL, cancellable, error);
if (commitv == NULL)
return FALSE;
@@ -6838,7 +6843,7 @@ flatpak_dir_mirror_oci (FlatpakDir *self,
const char *ref,
const char *opt_rev,
FlatpakImageSource *opt_image_source,
- const char *token,
+ FlatpakTokenProvider *token_provider,
FlatpakProgress *progress,
GCancellable *cancellable,
GError **error)
@@ -6852,7 +6857,7 @@ flatpak_dir_mirror_oci (FlatpakDir *self,
if (!image_source)
{
image_source = flatpak_remote_state_fetch_image_source (state, self,
- ref, opt_rev, token,
+ ref, opt_rev, token_provider,
cancellable, error);
if (image_source == NULL)
return FALSE;
@@ -6887,7 +6892,7 @@ flatpak_dir_pull_oci (FlatpakDir *self,
OstreeRepo *repo,
FlatpakPullFlags flatpak_flags,
OstreeRepoPullFlags flags,
- const char *token,
+ FlatpakTokenProvider *token_provider,
FlatpakProgress *progress,
GCancellable *cancellable,
GError **error)
@@ -6907,7 +6912,7 @@ flatpak_dir_pull_oci (FlatpakDir *self,
if (!image_source)
{
image_source = flatpak_remote_state_fetch_image_source (state, self,
- ref, opt_rev, token,
+ ref, opt_rev, token_provider,
cancellable, error);
if (image_source == NULL)
return FALSE;
@@ -6935,7 +6940,7 @@ flatpak_dir_pull_oci (FlatpakDir *self,
g_info ("Imported OCI image as checksum %s", checksum);
if (!flatpak_dir_setup_extra_data (self, state, repo,
- ref, checksum, token,
+ ref, checksum, token_provider,
flatpak_flags,
progress,
cancellable,
@@ -6976,7 +6981,7 @@ flatpak_dir_pull (FlatpakDir *self,
GFile *sideload_repo,
FlatpakImageSource *opt_image_source,
GBytes *require_metadata,
- const char *token,
+ FlatpakTokenProvider *token_provider,
OstreeRepo *repo,
FlatpakPullFlags flatpak_flags,
OstreeRepoPullFlags flags,
@@ -6992,6 +6997,7 @@ flatpak_dir_pull (FlatpakDir *self,
g_auto(GLnxLockFile) lock = { 0, };
g_autofree char *name = NULL;
g_autofree char *current_checksum = NULL;
+ const char *token = token_provider ? flatpak_token_provider_get_token (token_provider) : NULL;
if (!flatpak_dir_ensure_repo (self, cancellable, error))
return FALSE;
@@ -7007,7 +7013,7 @@ flatpak_dir_pull (FlatpakDir *self,
if (opt_image_source || flatpak_dir_get_remote_oci (self, state->remote_name))
return flatpak_dir_pull_oci (self, state, ref, opt_rev, opt_image_source, repo, flatpak_flags,
- flags, token, progress, cancellable, error);
+ flags, token_provider, progress, cancellable, error);
if (!ostree_repo_remote_get_url (self->repo,
state->remote_name,
@@ -7057,7 +7063,7 @@ flatpak_dir_pull (FlatpakDir *self,
/* Setup extra data information before starting to pull, so we can have precise
* progress reports */
if (!flatpak_dir_setup_extra_data (self, state, repo,
- ref, rev, token,
+ ref, rev, token_provider,
flatpak_flags,
progress,
cancellable,
@@ -10483,7 +10489,7 @@ rewrite_dynamic_launchers (FlatpakDecomposed *ref,
static FlatpakOciRegistry *
flatpak_dir_create_system_child_oci_registry (FlatpakDir *self,
GLnxLockFile *file_lock,
- const char *token,
+ FlatpakTokenProvider *token_provider,
GError **error)
{
g_autoptr(GFile) cache_dir = NULL;
@@ -10518,7 +10524,11 @@ flatpak_dir_create_system_child_oci_registry (FlatpakDir *self,
if (new_registry == NULL)
return NULL;
- flatpak_oci_registry_set_token (new_registry, token);
+ if (token_provider)
+ {
+ flatpak_oci_registry_set_token (new_registry, flatpak_token_provider_get_token (token_provider));
+ flatpak_oci_registry_set_token_provider (new_registry, token_provider);
+ }
return g_steal_pointer (&new_registry);
}
@@ -10800,7 +10810,7 @@ flatpak_dir_install (FlatpakDir *self,
GFile *sideload_repo,
FlatpakImageSource *opt_image_source,
GBytes *require_metadata,
- const char *token,
+ FlatpakTokenProvider *token_provider,
FlatpakProgress *progress,
GCancellable *cancellable,
GError **error)
@@ -10855,7 +10865,7 @@ flatpak_dir_install (FlatpakDir *self,
g_autoptr(FlatpakOciRegistry) registry = NULL;
g_autoptr(GFile) registry_file = NULL;
- registry = flatpak_dir_create_system_child_oci_registry (self, &child_repo_lock, token, error);
+ registry = flatpak_dir_create_system_child_oci_registry (self, &child_repo_lock, token_provider, error);
if (registry == NULL)
return FALSE;
@@ -10864,7 +10874,7 @@ flatpak_dir_install (FlatpakDir *self,
child_repo_path = g_file_get_path (registry_file);
if (!flatpak_dir_mirror_oci (self, registry, state, flatpak_decomposed_get_ref (ref),
- opt_commit, opt_image_source, token, progress, cancellable, error))
+ opt_commit, opt_image_source, token_provider, progress, cancellable, error))
return FALSE;
}
else if (!gpg_verify_summary || !gpg_verify)
@@ -10958,7 +10968,7 @@ flatpak_dir_install (FlatpakDir *self,
flatpak_flags |= FLATPAK_PULL_FLAGS_SIDELOAD_EXTRA_DATA;
- if (!flatpak_dir_pull (self, state, flatpak_decomposed_get_ref (ref), opt_commit, subpaths, sideload_repo, NULL, require_metadata, token,
+ if (!flatpak_dir_pull (self, state, flatpak_decomposed_get_ref (ref), opt_commit, subpaths, sideload_repo, NULL, require_metadata, token_provider,
child_repo,
flatpak_flags,
0,
@@ -11037,7 +11047,7 @@ flatpak_dir_install (FlatpakDir *self,
if (!no_pull)
{
if (!flatpak_dir_pull (self, state, flatpak_decomposed_get_ref (ref), opt_commit, opt_subpaths,
- sideload_repo, opt_image_source, require_metadata, token, NULL,
+ sideload_repo, opt_image_source, require_metadata, token_provider, NULL,
flatpak_flags, OSTREE_REPO_PULL_FLAGS_NONE,
progress, cancellable, error))
return FALSE;
@@ -11512,7 +11522,7 @@ flatpak_dir_update (FlatpakDir *self,
GFile *sideload_repo,
FlatpakImageSource *opt_image_source,
GBytes *require_metadata,
- const char *token,
+ FlatpakTokenProvider *token_provider,
FlatpakProgress *progress,
GCancellable *cancellable,
GError **error)
@@ -11589,7 +11599,7 @@ flatpak_dir_update (FlatpakDir *self,
g_autoptr(FlatpakOciRegistry) registry = NULL;
g_autoptr(GFile) registry_file = NULL;
- registry = flatpak_dir_create_system_child_oci_registry (self, &child_repo_lock, token, error);
+ registry = flatpak_dir_create_system_child_oci_registry (self, &child_repo_lock, token_provider, error);
if (registry == NULL)
return FALSE;
@@ -11598,7 +11608,7 @@ flatpak_dir_update (FlatpakDir *self,
child_repo_path = g_file_get_path (registry_file);
if (!flatpak_dir_mirror_oci (self, registry, state, flatpak_decomposed_get_ref (ref),
- commit, opt_image_source, token, progress, cancellable, error))
+ commit, opt_image_source, token_provider, progress, cancellable, error))
return FALSE;
}
else if (!gpg_verify_summary || !gpg_verify)
@@ -11678,7 +11688,7 @@ flatpak_dir_update (FlatpakDir *self,
flatpak_flags |= FLATPAK_PULL_FLAGS_SIDELOAD_EXTRA_DATA;
if (!flatpak_dir_pull (self, state, flatpak_decomposed_get_ref (ref),
- commit, subpaths, sideload_repo, NULL, require_metadata, token,
+ commit, subpaths, sideload_repo, NULL, require_metadata, token_provider,
child_repo,
flatpak_flags, 0,
progress, cancellable, error))
@@ -11744,7 +11754,7 @@ flatpak_dir_update (FlatpakDir *self,
if (!no_pull)
{
if (!flatpak_dir_pull (self, state, flatpak_decomposed_get_ref (ref),
- commit, subpaths, sideload_repo, opt_image_source, require_metadata, token,
+ commit, subpaths, sideload_repo, opt_image_source, require_metadata, token_provider,
NULL, flatpak_flags, OSTREE_REPO_PULL_FLAGS_NONE,
progress, cancellable, error))
return FALSE;
diff --git a/common/flatpak-image-source-private.h b/common/flatpak-image-source-private.h
index 1259c1348d..92f6ea7df2 100644
--- a/common/flatpak-image-source-private.h
+++ b/common/flatpak-image-source-private.h
@@ -42,11 +42,11 @@ FlatpakImageSource *flatpak_image_source_new_local (GFile *file,
const char *reference,
GCancellable *cancellable,
GError **error);
-FlatpakImageSource *flatpak_image_source_new_remote (const char *uri,
- const char *oci_repository,
- const char *digest,
- const char *token,
- const char *signature_lookaside,
+FlatpakImageSource *flatpak_image_source_new_remote (const char *uri,
+ const char *oci_repository,
+ const char *digest,
+ FlatpakTokenProvider *token_provider,
+ const char *signature_lookaside,
GCancellable *cancellable,
GError **error);
FlatpakImageSource *flatpak_image_source_new_for_location (const char *location,
diff --git a/common/flatpak-image-source.c b/common/flatpak-image-source.c
index eab92a1b8e..adb81947a1 100644
--- a/common/flatpak-image-source.c
+++ b/common/flatpak-image-source.c
@@ -180,13 +180,13 @@ flatpak_image_source_new_local (GFile *file,
}
FlatpakImageSource *
-flatpak_image_source_new_remote (const char *uri,
- const char *oci_repository,
- const char *digest,
- const char *token,
- const char *signature_lookaside,
- GCancellable *cancellable,
- GError **error)
+flatpak_image_source_new_remote (const char *uri,
+ const char *oci_repository,
+ const char *digest,
+ FlatpakTokenProvider *token_provider,
+ const char *signature_lookaside,
+ GCancellable *cancellable,
+ GError **error)
{
g_autoptr(FlatpakOciRegistry) registry = NULL;
@@ -194,7 +194,11 @@ flatpak_image_source_new_remote (const char *uri,
if (!registry)
return NULL;
- flatpak_oci_registry_set_token (registry, token);
+ if (token_provider)
+ {
+ flatpak_oci_registry_set_token (registry, flatpak_token_provider_get_token (token_provider));
+ flatpak_oci_registry_set_token_provider (registry, token_provider);
+ }
flatpak_oci_registry_set_signature_lookaside (registry, signature_lookaside);
return flatpak_image_source_new (registry, oci_repository, digest, cancellable, error);
diff --git a/common/flatpak-oci-registry-private.h b/common/flatpak-oci-registry-private.h
index ca56eab396..2fc75bc2c8 100644
--- a/common/flatpak-oci-registry-private.h
+++ b/common/flatpak-oci-registry-private.h
@@ -61,6 +61,8 @@ FlatpakOciRegistry * flatpak_oci_registry_new_for_archive (GFile *archi
GError **error);
void flatpak_oci_registry_set_token (FlatpakOciRegistry *self,
const char *token);
+void flatpak_oci_registry_set_token_provider (FlatpakOciRegistry *self,
+ FlatpakTokenProvider *provider);
void flatpak_oci_registry_set_signature_lookaside (FlatpakOciRegistry *self,
const char *signature_lookaside);
gboolean flatpak_oci_registry_is_local (FlatpakOciRegistry *self);
diff --git a/common/flatpak-oci-registry.c b/common/flatpak-oci-registry.c
index 3a3fec3d46..429c32d244 100644
--- a/common/flatpak-oci-registry.c
+++ b/common/flatpak-oci-registry.c
@@ -74,6 +74,7 @@ struct FlatpakOciRegistry
GFile *archive;
int tmp_dfd;
char *token;
+ FlatpakTokenProvider *token_provider;
char *signature_lookaside;
/* Local repos */
@@ -138,6 +139,7 @@ flatpak_oci_registry_finalize (GObject *object)
g_clear_pointer (&self->base_uri, g_uri_unref);
g_clear_pointer (&self->uri, g_free);
g_clear_pointer (&self->token, g_free);
+ g_clear_object (&self->token_provider);
g_clear_object (&self->archive);
g_clear_pointer (&self->tmp_dir, glnx_tmpdir_free);
g_clear_pointer (&self->certificates, flatpak_certificates_free);
@@ -291,6 +293,29 @@ flatpak_oci_registry_set_token (FlatpakOciRegistry *self,
0, NULL, NULL);
}
+void
+flatpak_oci_registry_set_token_provider (FlatpakOciRegistry *self,
+ FlatpakTokenProvider *provider)
+{
+ g_set_object (&self->token_provider, provider);
+}
+
+static gboolean
+flatpak_oci_registry_try_refresh_token (FlatpakOciRegistry *self,
+ GCancellable *cancellable)
+{
+ if (self->token_provider == NULL)
+ return FALSE;
+
+ g_info ("Refreshing registry token for %s", self->uri);
+
+ if (!flatpak_token_provider_refresh_token (self->token_provider, cancellable))
+ return FALSE;
+
+ flatpak_oci_registry_set_token (self, flatpak_token_provider_get_token (self->token_provider));
+ return TRUE;
+}
+
void
flatpak_oci_registry_set_signature_lookaside (FlatpakOciRegistry *self,
const char *signature_lookaside)
@@ -384,6 +409,18 @@ remote_load_file (FlatpakOciRegistry *self,
NULL, self->token,
NULL, NULL, NULL, out_content_type, NULL,
cancellable, error);
+ if (bytes == NULL
+ && g_error_matches (*error, FLATPAK_HTTP_ERROR, FLATPAK_HTTP_ERROR_UNAUTHORIZED)
+ && flatpak_oci_registry_try_refresh_token (self, cancellable))
+ {
+ g_clear_error (error);
+ bytes = flatpak_load_uri_full (self->http_session,
+ uri_s, self->certificates, FLATPAK_HTTP_FLAGS_ACCEPT_OCI,
+ NULL, self->token,
+ NULL, NULL, NULL, out_content_type, NULL,
+ cancellable, error);
+ }
+
if (bytes == NULL)
return NULL;
@@ -1016,13 +1053,34 @@ flatpak_oci_registry_download_blob (FlatpakOciRegistry *self,
if (fd == -1)
return -1;
- if (!flatpak_download_http_uri (self->http_session, uri_s,
- self->certificates,
- FLATPAK_HTTP_FLAGS_ACCEPT_OCI,
- out_stream,
- self->token,
- progress_cb, user_data,
- cancellable, error))
+ gboolean download_ok;
+
+ download_ok = flatpak_download_http_uri (self->http_session, uri_s,
+ self->certificates,
+ FLATPAK_HTTP_FLAGS_ACCEPT_OCI,
+ out_stream,
+ self->token,
+ progress_cb, user_data,
+ cancellable, error);
+ if (!download_ok
+ && g_error_matches (*error, FLATPAK_HTTP_ERROR, FLATPAK_HTTP_ERROR_UNAUTHORIZED)
+ && flatpak_oci_registry_try_refresh_token (self, cancellable))
+ {
+ g_clear_error (error);
+ g_clear_object (&out_stream);
+ ftruncate (fd, 0);
+ lseek (fd, 0, SEEK_SET);
+ out_stream = g_unix_output_stream_new (fd, FALSE);
+
+ download_ok = flatpak_download_http_uri (self->http_session, uri_s,
+ self->certificates,
+ FLATPAK_HTTP_FLAGS_ACCEPT_OCI,
+ out_stream,
+ self->token,
+ progress_cb, user_data,
+ cancellable, error);
+ }
+ if (!download_ok)
return -1;
if (!g_output_stream_close (out_stream, cancellable, error))
@@ -1107,14 +1165,34 @@ flatpak_oci_registry_mirror_blob (FlatpakOciRegistry *self,
if (uri_s == NULL)
return FALSE;
+ gboolean download_ok;
+
out_stream = g_unix_output_stream_new (tmpf.fd, FALSE);
- if (!flatpak_download_http_uri (source_registry->http_session,
- uri_s, source_registry->certificates,
- FLATPAK_HTTP_FLAGS_ACCEPT_OCI, out_stream,
- self->token,
- progress_cb, user_data,
- cancellable, error))
+ download_ok = flatpak_download_http_uri (source_registry->http_session,
+ uri_s, source_registry->certificates,
+ FLATPAK_HTTP_FLAGS_ACCEPT_OCI, out_stream,
+ self->token,
+ progress_cb, user_data,
+ cancellable, error);
+ if (!download_ok
+ && g_error_matches (*error, FLATPAK_HTTP_ERROR, FLATPAK_HTTP_ERROR_UNAUTHORIZED)
+ && flatpak_oci_registry_try_refresh_token (self, cancellable))
+ {
+ g_clear_error (error);
+ g_clear_object (&out_stream);
+ ftruncate (tmpf.fd, 0);
+ lseek (tmpf.fd, 0, SEEK_SET);
+ out_stream = g_unix_output_stream_new (tmpf.fd, FALSE);
+
+ download_ok = flatpak_download_http_uri (source_registry->http_session,
+ uri_s, source_registry->certificates,
+ FLATPAK_HTTP_FLAGS_ACCEPT_OCI, out_stream,
+ self->token,
+ progress_cb, user_data,
+ cancellable, error);
+ }
+ if (!download_ok)
return FALSE;
if (!g_output_stream_close (out_stream, cancellable, error))
diff --git a/common/flatpak-transaction.c b/common/flatpak-transaction.c
index 5d1460ce60..cc17d58786 100644
--- a/common/flatpak-transaction.c
+++ b/common/flatpak-transaction.c
@@ -164,6 +164,25 @@ typedef struct {
GVariant *results;
} RequestData;
+/* Pointers are not ref'd; the provider never outlives the transaction or op. */
+struct _FlatpakTokenProvider {
+ GObject parent;
+ FlatpakTransaction *transaction;
+ FlatpakTransactionOperation *op;
+};
+
+G_DEFINE_TYPE (FlatpakTokenProvider, flatpak_token_provider, G_TYPE_OBJECT)
+
+static void
+flatpak_token_provider_class_init (FlatpakTokenProviderClass *klass)
+{
+}
+
+static void
+flatpak_token_provider_init (FlatpakTokenProvider *self)
+{
+}
+
typedef struct _FlatpakTransactionPrivate
{
GObject parent;
@@ -244,6 +263,8 @@ enum {
};
static gboolean op_may_need_token (FlatpakTransactionOperation *op);
+static FlatpakTokenProvider *flatpak_token_provider_new_for_op (FlatpakTransaction *transaction,
+ FlatpakTransactionOperation *op);
static void flatpak_transaction_normalize_ops (FlatpakTransaction *self);
static gboolean request_required_tokens (FlatpakTransaction *self,
@@ -3910,9 +3931,12 @@ resolve_ops (FlatpakTransaction *self,
flatpak_remote_state_lookup_ref (state, flatpak_decomposed_get_ref (op->ref),
NULL, NULL, &op->summary_metadata, NULL, NULL, NULL);
+ g_autoptr(FlatpakTokenProvider) token_provider =
+ flatpak_token_provider_new_for_op (self, op);
+
commit_data = flatpak_remote_state_load_ref_commit (state, priv->dir,
flatpak_decomposed_get_ref (op->ref),
- checksum, /* initially NULL */ op->resolved_token,
+ checksum, token_provider,
NULL, NULL, &local_error);
if (commit_data == NULL)
{
@@ -4351,6 +4375,7 @@ request_tokens_for_remote (FlatpakTransaction *self,
/* Allow sending empty tokens to mean no token needed */
+ g_free (op->resolved_token);
op->resolved_token = *token == 0 ? NULL : g_strdup (token);
op->requested_token = TRUE;
}
@@ -4358,6 +4383,41 @@ request_tokens_for_remote (FlatpakTransaction *self,
return TRUE;
}
+static FlatpakTokenProvider *
+flatpak_token_provider_new_for_op (FlatpakTransaction *transaction,
+ FlatpakTransactionOperation *op)
+{
+ FlatpakTokenProvider *self = g_object_new (FLATPAK_TYPE_TOKEN_PROVIDER, NULL);
+
+ self->transaction = transaction;
+ self->op = op;
+
+ return self;
+}
+
+const char *
+flatpak_token_provider_get_token (FlatpakTokenProvider *self)
+{
+ return self->op->resolved_token;
+}
+
+gboolean
+flatpak_token_provider_refresh_token (FlatpakTokenProvider *self,
+ GCancellable *cancellable)
+{
+ GList op_list = { .data = self->op, .next = NULL, .prev = NULL };
+ g_autoptr(GError) local_error = NULL;
+
+ if (!request_tokens_for_remote (self->transaction, self->op->remote,
+ &op_list, cancellable, &local_error))
+ {
+ g_info ("Token refresh failed: %s", local_error->message);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static gboolean
request_required_tokens (FlatpakTransaction *self,
const char *optional_remote, /* else all remotes */
@@ -5093,24 +5153,29 @@ _run_op_kind (FlatpakTransaction *self,
op->resolved_metakey, &local_error))
res = FALSE;
else
- res = flatpak_dir_install (priv->dir,
- priv->no_pull,
- priv->no_deploy,
- priv->disable_static_deltas,
- priv->reinstall,
- priv->max_op >= APP_UPDATE,
- op->pin_on_deploy,
- op->update_preinstalled_on_deploy,
- remote_state, op->ref,
- op->resolved_commit,
- (const char **) op->subpaths,
- (const char **) op->previous_ids,
- op->resolved_sideload_path,
- op->resolved_image_source,
- op->resolved_metadata,
- op->resolved_token,
- progress->progress_obj,
- cancellable, &local_error);
+ {
+ g_autoptr(FlatpakTokenProvider) token_provider =
+ flatpak_token_provider_new_for_op (self, op);
+
+ res = flatpak_dir_install (priv->dir,
+ priv->no_pull,
+ priv->no_deploy,
+ priv->disable_static_deltas,
+ priv->reinstall,
+ priv->max_op >= APP_UPDATE,
+ op->pin_on_deploy,
+ op->update_preinstalled_on_deploy,
+ remote_state, op->ref,
+ op->resolved_commit,
+ (const char **) op->subpaths,
+ (const char **) op->previous_ids,
+ op->resolved_sideload_path,
+ op->resolved_image_source,
+ op->resolved_metadata,
+ token_provider,
+ progress->progress_obj,
+ cancellable, &local_error);
+ }
flatpak_transaction_progress_done (progress);
@@ -5167,24 +5232,29 @@ _run_op_kind (FlatpakTransaction *self,
(const char **) op->previous_ids,
cancellable, &local_error);
else
- res = flatpak_dir_update (priv->dir,
- priv->no_pull,
- priv->no_deploy,
- priv->disable_static_deltas,
- op->commit != NULL, /* Allow downgrade if we specify commit */
- priv->max_op >= APP_UPDATE,
- priv->max_op == APP_INSTALL || priv->max_op == RUNTIME_INSTALL,
- remote_state,
- op->ref,
- op->resolved_commit,
- (const char **) op->subpaths,
- (const char **) op->previous_ids,
- op->resolved_sideload_path,
- op->resolved_image_source,
- op->resolved_metadata,
- op->resolved_token,
- progress->progress_obj,
- cancellable, &local_error);
+ {
+ g_autoptr(FlatpakTokenProvider) token_provider =
+ flatpak_token_provider_new_for_op (self, op);
+
+ res = flatpak_dir_update (priv->dir,
+ priv->no_pull,
+ priv->no_deploy,
+ priv->disable_static_deltas,
+ op->commit != NULL, /* Allow downgrade if we specify commit */
+ priv->max_op >= APP_UPDATE,
+ priv->max_op == APP_INSTALL || priv->max_op == RUNTIME_INSTALL,
+ remote_state,
+ op->ref,
+ op->resolved_commit,
+ (const char **) op->subpaths,
+ (const char **) op->previous_ids,
+ op->resolved_sideload_path,
+ op->resolved_image_source,
+ op->resolved_metadata,
+ token_provider,
+ progress->progress_obj,
+ cancellable, &local_error);
+ }
flatpak_transaction_progress_done (progress);
/* Handle noop-updates */
From 4ae3855f058d4aeed6f50298268d40dcb0c75375 Mon Sep 17 00:00:00 2001
From: Luigi Pavan <lpavan@redhat.com>
Date: Tue, 19 May 2026 11:55:00 +0200
Subject: [PATCH 2/3] oci: Fix crash when error parameter is NULL in 401 retry
logic
The 401 retry logic added in the previous commit dereferences the
GError **error parameter with *error without first checking that error
is non-NULL. When callers pass NULL for error (e.g. the _deltaindex
lookup), this causes a SIGSEGV.
Add error != NULL guards to all three retry sites in remote_load_file,
flatpak_oci_registry_download_blob, and flatpak_oci_registry_mirror_blob.
---
common/flatpak-oci-registry.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/common/flatpak-oci-registry.c b/common/flatpak-oci-registry.c
index 429c32d244..5ff45995f4 100644
--- a/common/flatpak-oci-registry.c
+++ b/common/flatpak-oci-registry.c
@@ -410,6 +410,7 @@ remote_load_file (FlatpakOciRegistry *self,
NULL, NULL, NULL, out_content_type, NULL,
cancellable, error);
if (bytes == NULL
+ && error != NULL
&& g_error_matches (*error, FLATPAK_HTTP_ERROR, FLATPAK_HTTP_ERROR_UNAUTHORIZED)
&& flatpak_oci_registry_try_refresh_token (self, cancellable))
{
@@ -1063,6 +1064,7 @@ flatpak_oci_registry_download_blob (FlatpakOciRegistry *self,
progress_cb, user_data,
cancellable, error);
if (!download_ok
+ && error != NULL
&& g_error_matches (*error, FLATPAK_HTTP_ERROR, FLATPAK_HTTP_ERROR_UNAUTHORIZED)
&& flatpak_oci_registry_try_refresh_token (self, cancellable))
{
@@ -1176,6 +1178,7 @@ flatpak_oci_registry_mirror_blob (FlatpakOciRegistry *self,
progress_cb, user_data,
cancellable, error);
if (!download_ok
+ && error != NULL
&& g_error_matches (*error, FLATPAK_HTTP_ERROR, FLATPAK_HTTP_ERROR_UNAUTHORIZED)
&& flatpak_oci_registry_try_refresh_token (self, cancellable))
{
From 7fc7350f6d1e24abef3e18cf6da792e28751c746 Mon Sep 17 00:00:00 2001
From: Luigi Pavan <lpavan@redhat.com>
Date: Mon, 8 Jun 2026 18:55:15 +0200
Subject: [PATCH 3/3] oci: Fix download_blob 401 retry writing to O_RDONLY fd
The retry path after a 401 discarded the O_WRONLY out_stream and
wrapped the O_RDONLY fd as a new write stream. ftruncate() silently
failed on the read-only descriptor and subsequent writes returned
EBADF, leaving the temp file empty. checksum_fd() then computed the
SHA-256 of zero bytes, causing a digest mismatch and a failed install.
Fix by using g_unix_output_stream_get_fd() to reach the O_WRONLY fd,
resetting it in place, and reusing the existing stream. Apply the
same truncate-and-seek pattern to mirror_blob, where the stream
destroy-and-recreate roundtrip was unnecessary.
---
common/flatpak-oci-registry.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/common/flatpak-oci-registry.c b/common/flatpak-oci-registry.c
index 5ff45995f4..10d96049b5 100644
--- a/common/flatpak-oci-registry.c
+++ b/common/flatpak-oci-registry.c
@@ -1069,10 +1069,9 @@ flatpak_oci_registry_download_blob (FlatpakOciRegistry *self,
&& flatpak_oci_registry_try_refresh_token (self, cancellable))
{
g_clear_error (error);
- g_clear_object (&out_stream);
- ftruncate (fd, 0);
- lseek (fd, 0, SEEK_SET);
- out_stream = g_unix_output_stream_new (fd, FALSE);
+ int write_fd = g_unix_output_stream_get_fd (G_UNIX_OUTPUT_STREAM (out_stream));
+ ftruncate (write_fd, 0);
+ lseek (write_fd, 0, SEEK_SET);
download_ok = flatpak_download_http_uri (self->http_session, uri_s,
self->certificates,
@@ -1183,10 +1182,8 @@ flatpak_oci_registry_mirror_blob (FlatpakOciRegistry *self,
&& flatpak_oci_registry_try_refresh_token (self, cancellable))
{
g_clear_error (error);
- g_clear_object (&out_stream);
ftruncate (tmpf.fd, 0);
lseek (tmpf.fd, 0, SEEK_SET);
- out_stream = g_unix_output_stream_new (tmpf.fd, FALSE);
download_ok = flatpak_download_http_uri (source_registry->http_session,
uri_s, source_registry->certificates,

View File

@ -0,0 +1,457 @@
From d439efe6dd66f623aca58d58ed981520f300113d Mon Sep 17 00:00:00 2001
From: Sebastian Wick <sebastian.wick@redhat.com>
Date: Thu, 11 Jun 2026 17:24:11 +0200
Subject: [PATCH 1/4] oci-registry: Load the certificates from an ImageSource
---
common/flatpak-oci-registry.c | 30 ++++++++++++++++--------------
1 file changed, 16 insertions(+), 14 deletions(-)
diff --git a/common/flatpak-oci-registry.c b/common/flatpak-oci-registry.c
index 3a3fec3d46..0a442cd407 100644
--- a/common/flatpak-oci-registry.c
+++ b/common/flatpak-oci-registry.c
@@ -2405,23 +2405,28 @@ remote_load_signatures (FlatpakOciRegistry *self,
}
static FlatpakOciSignatures *
-flatpak_oci_registry_load_signatures (FlatpakOciRegistry *self,
- const char *oci_repository,
- const char *digest,
- GCancellable *cancellable,
- GError **error)
+load_signatures (FlatpakImageSource *image_source,
+ GCancellable *cancellable,
+ GError **error)
{
- if (self->dfd != -1)
+ FlatpakOciRegistry *registry = flatpak_image_source_get_registry (image_source);
+
+ if (registry->dfd != -1)
{
g_autoptr(FlatpakOciSignatures) signatures = flatpak_oci_signatures_new ();
- if (!flatpak_oci_signatures_load_from_dfd (signatures, self->dfd, cancellable, error))
+ if (!flatpak_oci_signatures_load_from_dfd (signatures, registry->dfd, cancellable, error))
return NULL;
return g_steal_pointer (&signatures);
}
else
- return remote_load_signatures (self, oci_repository, digest, cancellable, error);
+ {
+ const char *oci_repository = flatpak_image_source_get_oci_repository (image_source);
+ const char *digest = flatpak_image_source_get_digest (image_source);
+
+ return remote_load_signatures (registry, oci_repository, digest, cancellable, error);
+ }
}
static const char *
@@ -3283,8 +3288,7 @@ flatpak_mirror_image_from_oci (FlatpakOciRegistry *dst_registry,
if (!flatpak_oci_registry_save_index (dst_registry, index, cancellable, error))
return FALSE;
- signatures = flatpak_oci_registry_load_signatures (registry, oci_repository, digest,
- cancellable, error);
+ signatures = load_signatures (image_source, cancellable, error);
if (!signatures)
return FALSE;
@@ -3339,10 +3343,8 @@ flatpak_pull_from_oci (OstreeRepo *repo,
g_assert (g_str_has_prefix (digest, "sha256:"));
- signatures = flatpak_oci_registry_load_signatures (dst_registry,
- dest_oci_repository,
- digest,
- cancellable, error);
+ signatures = load_signatures (opt_dst_image_source ? opt_dst_image_source : image_source,
+ cancellable, error);
if (!signatures)
return FALSE;
From 780916961cb935b74c2fcaeed6e88b30e35d04e1 Mon Sep 17 00:00:00 2001
From: Sebastian Wick <sebastian.wick@redhat.com>
Date: Thu, 11 Jun 2026 17:27:47 +0200
Subject: [PATCH 2/4] oci-registry: Check signatures from mirrored repo in the
system helper
In flatpak_pull_from_oci we can be in in the system helper where we pull
the mirrored OCI image into the system repo. However, to fetch the
signatures in GPG signed repos, we used a remote OciImageSource created
through `flatpak_remote_state_fetch_image_source`. This caused fetching
some data from the registry which we don't want in the deploy method,
and also fails if a token is required to access the repo.
This change fetches the signatures from the mirrored OCI repo instead of
pulling them from the remote OciImageSource. The signatures can come from
anywhere because we verify them against the GPG key in the system repo.
The important bit is the change in `flatpak_pull_from_oci` where we now
pass in the local image_source to fetch the signatures from, and in the
system helper, where we get the right metadata to check the signatures
against (eventually ends up in `flatpak_oci_signatures_verify`).
---
app/flatpak-builtins-build-import-bundle.c | 2 +-
common/flatpak-dir.c | 2 +-
common/flatpak-oci-registry-private.h | 3 ++-
common/flatpak-oci-registry.c | 16 ++++++-------
system-helper/flatpak-system-helper.c | 28 ++++++++++++++--------
5 files changed, 29 insertions(+), 22 deletions(-)
diff --git a/app/flatpak-builtins-build-import-bundle.c b/app/flatpak-builtins-build-import-bundle.c
index 6b06073f30..5455bb5348 100644
--- a/app/flatpak-builtins-build-import-bundle.c
+++ b/app/flatpak-builtins-build-import-bundle.c
@@ -68,7 +68,7 @@ import_oci (OstreeRepo *repo, GFile *file,
ref = flatpak_image_source_get_ref (image_source);
- commit_checksum = flatpak_pull_from_oci (repo, image_source, NULL, NULL,
+ commit_checksum = flatpak_pull_from_oci (repo, image_source, NULL, NULL, NULL,
ref, FLATPAK_PULL_FLAGS_NONE,
NULL, NULL, cancellable, error);
if (commit_checksum == NULL)
diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c
index 73118e1127..36d9b4314c 100644
--- a/common/flatpak-dir.c
+++ b/common/flatpak-dir.c
@@ -6926,7 +6926,7 @@ flatpak_dir_pull_oci (FlatpakDir *self,
g_info ("Pulling OCI image %s", oci_digest);
- checksum = flatpak_pull_from_oci (repo, image_source, NULL,
+ checksum = flatpak_pull_from_oci (repo, image_source, NULL, NULL,
state->remote_name, ref, flatpak_flags, oci_pull_progress_cb, progress, cancellable, error);
if (checksum == NULL)
diff --git a/common/flatpak-oci-registry-private.h b/common/flatpak-oci-registry-private.h
index ca56eab396..451f770861 100644
--- a/common/flatpak-oci-registry-private.h
+++ b/common/flatpak-oci-registry-private.h
@@ -194,7 +194,8 @@ typedef void (*FlatpakOciPullProgress) (guint64 total_size,
char * flatpak_pull_from_oci (OstreeRepo *repo,
FlatpakImageSource *image_source,
- FlatpakImageSource *opt_dst_image_source,
+ const char *opt_sigcheck_repository,
+ const char *opt_sigcheck_registry_uri,
const char *remote,
const char *ref,
FlatpakPullFlags flags,
diff --git a/common/flatpak-oci-registry.c b/common/flatpak-oci-registry.c
index 0a442cd407..07b194e0c8 100644
--- a/common/flatpak-oci-registry.c
+++ b/common/flatpak-oci-registry.c
@@ -3301,7 +3301,8 @@ flatpak_mirror_image_from_oci (FlatpakOciRegistry *dst_registry,
char *
flatpak_pull_from_oci (OstreeRepo *repo,
FlatpakImageSource *image_source,
- FlatpakImageSource *opt_dst_image_source,
+ const char *opt_sigcheck_repository,
+ const char *opt_sigcheck_registry_uri,
const char *remote,
const char *ref,
FlatpakPullFlags flags,
@@ -3334,23 +3335,20 @@ flatpak_pull_from_oci (OstreeRepo *repo,
g_autoptr(GVariantBuilder) metadata_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
g_autoptr(GVariant) metadata = NULL;
g_autoptr(FlatpakOciSignatures) signatures = NULL;
- FlatpakOciRegistry *dst_registry = opt_dst_image_source ?
- flatpak_image_source_get_registry (opt_dst_image_source) : registry;
- const char *dest_oci_repository = opt_dst_image_source ?
- flatpak_image_source_get_oci_repository (opt_dst_image_source) : oci_repository;
+ const char *sigcheck_registry_uri = opt_sigcheck_registry_uri ? opt_sigcheck_registry_uri : registry->uri;
+ const char *sigcheck_repository = opt_sigcheck_repository ? opt_sigcheck_repository : oci_repository;
int n_layers;
int i;
g_assert (g_str_has_prefix (digest, "sha256:"));
- signatures = load_signatures (opt_dst_image_source ? opt_dst_image_source : image_source,
- cancellable, error);
+ signatures = load_signatures (image_source, cancellable, error);
if (!signatures)
return FALSE;
if (!flatpak_oci_signatures_verify (signatures, repo, remote,
- dst_registry->uri,
- dest_oci_repository,
+ sigcheck_registry_uri,
+ sigcheck_repository,
digest,
error))
return FALSE;
diff --git a/system-helper/flatpak-system-helper.c b/system-helper/flatpak-system-helper.c
index 81c0801628..f6156b70a2 100644
--- a/system-helper/flatpak-system-helper.c
+++ b/system-helper/flatpak-system-helper.c
@@ -492,6 +492,9 @@ handle_deploy (FlatpakSystemHelper *object,
const char *verified_digest;
g_autofree char *upstream_url = NULL;
g_autoptr(FlatpakImageSource) system_image_source = NULL;
+ g_autoptr(GVariant) metadata = NULL;
+ const char *sigcheck_repository = NULL;
+ g_autofree char *sigcheck_registry_uri = NULL;
if (!ostree_repo_remote_get_url (flatpak_dir_get_repo (system),
arg_origin,
@@ -546,21 +549,26 @@ handle_deploy (FlatpakSystemHelper *object,
return G_DBUS_METHOD_INVOCATION_HANDLED;
}
- system_image_source =
- flatpak_remote_state_fetch_image_source (state,
- system,
- arg_ref,
- verified_digest,
- NULL,
- NULL, &error);
- if (!system_image_source)
+ flatpak_remote_state_lookup_ref (state, arg_ref,
+ NULL, NULL,
+ &metadata,
+ NULL, NULL, NULL);
+
+ if (!g_variant_lookup (metadata, "xa.oci-repository", "s", &sigcheck_repository))
+ {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "Can't get the OCI repository from the summary");
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ if (!ostree_repo_remote_get_url (flatpak_dir_get_repo (system), arg_origin, &sigcheck_registry_uri, NULL))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
- "Can't fetch image source: %s", error->message);
+ "Can't get the OCI registry URI");
return G_DBUS_METHOD_INVOCATION_HANDLED;
}
- checksum = flatpak_pull_from_oci (flatpak_dir_get_repo (system), image_source, system_image_source,
+ checksum = flatpak_pull_from_oci (flatpak_dir_get_repo (system), image_source, sigcheck_repository, sigcheck_registry_uri,
arg_origin, arg_ref, FLATPAK_PULL_FLAGS_NONE, NULL, NULL, NULL, &error);
if (checksum == NULL)
{
From ef6554153e801311cf1e76c2ddb5fc1dbcc22121 Mon Sep 17 00:00:00 2001
From: Luigi Pavan <lpavan@redhat.com>
Date: Thu, 11 Jun 2026 12:50:26 +0200
Subject: [PATCH 3/4] tests/oci-registry: Add bearer token auth support to the
mock OCI registry
Add infrastructure for testing OCI installations from auth-protected
registries. The mock server now supports requiring a bearer token on all
/v2/ requests, configurable via a new POST /testing-auth/configure admin
endpoint. The client gains a corresponding 'configure-auth' subcommand.
Assisted-by: Cursor
---
tests/oci-registry-client.py | 17 +++++++++++++++++
tests/oci-registry-server.py | 25 +++++++++++++++++++++++++
2 files changed, 42 insertions(+)
diff --git a/tests/oci-registry-client.py b/tests/oci-registry-client.py
index 3855af5454..a80fe1973c 100755
--- a/tests/oci-registry-client.py
+++ b/tests/oci-registry-client.py
@@ -82,6 +82,19 @@ def run_delete_sig(args):
sys.exit(1)
+def run_configure_auth(args):
+ params = {"token": args.token}
+ query = urllib.parse.urlencode(params)
+ conn = get_conn(args)
+ path = "/testing-auth/configure?{query}".format(query=query)
+ conn.request("POST", path)
+ response = conn.getresponse()
+ if response.status != 200:
+ print(response.read(), file=sys.stderr)
+ print("Failed: status={}".format(response.status), file=sys.stderr)
+ sys.exit(1)
+
+
parser = argparse.ArgumentParser()
parser.add_argument("--url", required=True)
parser.add_argument("--cacert")
@@ -114,5 +127,9 @@ def run_delete_sig(args):
delete_sig_parser.add_argument("digest")
delete_sig_parser.set_defaults(func=run_delete_sig)
+configure_auth_parser = subparsers.add_parser("configure-auth")
+configure_auth_parser.add_argument("--token", required=True)
+configure_auth_parser.set_defaults(func=run_configure_auth)
+
args = parser.parse_args()
args.func(args)
diff --git a/tests/oci-registry-server.py b/tests/oci-registry-server.py
index 497d7ca011..a890a097b1 100755
--- a/tests/oci-registry-server.py
+++ b/tests/oci-registry-server.py
@@ -15,6 +15,8 @@
icons = {}
signatures = {}
+required_token = None
+
def get_index():
results = []
@@ -81,6 +83,15 @@ def check_route(self, route):
return True
+ def check_auth(self):
+ """Return True if auth is not required or the Authorization: Bearer header matches the required token."""
+ if required_token is None:
+ return True
+ auth_header = self.headers.get("Authorization", "")
+ if not auth_header.startswith("Bearer "):
+ return False
+ return auth_header[len("Bearer "):] == required_token
+
def do_GET(self):
response = 404
response_string = b""
@@ -97,10 +108,18 @@ def get_file_contents(repo_name, type, ref):
return 404, b""
if self.check_route("/v2/@repo_name/blobs/@digest"):
+ if not self.check_auth():
+ self.send_response(401)
+ self.end_headers()
+ return
repo_name = self.matches["repo_name"]
digest = self.matches["digest"]
response, response_string = get_file_contents(repo_name, "blobs", digest)
elif self.check_route("/v2/@repo_name/manifests/@ref"):
+ if not self.check_auth():
+ self.send_response(401)
+ self.end_headers()
+ return
repo_name = self.matches["repo_name"]
ref = self.matches["ref"]
response, response_string = get_file_contents(repo_name, "manifests", ref)
@@ -234,6 +253,12 @@ def do_POST(self):
ref = f"{repo_name}@{digest}"
sigs = signatures.setdefault(ref, [])
sigs.append(signature_bytes)
+ self.send_response(200)
+ self.end_headers()
+ elif self.check_route("/testing-auth/configure"):
+ global required_token
+ required_token = self.query.get("token", [None])[0]
+
self.send_response(200)
self.end_headers()
else:
From 35efa19c2e4f46359ede239057bde3783e50267d Mon Sep 17 00:00:00 2001
From: Luigi Pavan <lpavan@redhat.com>
Date: Thu, 11 Jun 2026 12:50:26 +0200
Subject: [PATCH 4/4] tests: Add test for installing from an auth-protected OCI
registry
Add a regression test that installs from an auth-protected OCI registry.
The registry requires a bearer token for all /v2/ requests; the client
authenticates via the mock test authenticator and the installation
completes successfully. The test runs for both user and system install
paths.
Assisted-by: Cursor
---
tests/meson.build | 1 +
tests/test-oci-auth.sh | 69 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 70 insertions(+)
create mode 100755 tests/test-oci-auth.sh
diff --git a/tests/meson.build b/tests/meson.build
index 43d1493b73..d0b4f29e06 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -396,6 +396,7 @@ tests = {
'system,http',
'system,https',
]},
+ 'oci-auth': {'wrap': ['user', 'system']},
'update-remote-configuration': {'wrap': ['newsummary', 'oldsummary']},
'override': {},
'update-portal': {'wrap': ['user', 'system']},
diff --git a/tests/test-oci-auth.sh b/tests/test-oci-auth.sh
new file mode 100755
index 0000000000..33c2271f09
--- /dev/null
+++ b/tests/test-oci-auth.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+#
+# Copyright (C) 2026 Red Hat, Inc.
+#
+# 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
+
+# shellcheck source=libtest.sh
+. "$(dirname "$0")/libtest.sh"
+
+skip_without_bwrap
+
+echo "1..1"
+
+# Start the fake OCI registry server
+
+httpd oci-registry-server.py --dir=.
+port=$(cat httpd-port)
+
+# shellcheck disable=SC2154
+client="python3 ${test_srcdir}/oci-registry-client.py --url=http://127.0.0.1:${port}"
+
+setup_repo_no_add oci
+
+# Build OCI bundles and upload them to the registry
+
+${FLATPAK} build-bundle --runtime --oci $FL_GPGARGS repos/oci oci/platform-image org.test.Platform >&2
+$client add platform latest "$(pwd)/oci/platform-image"
+
+${FLATPAK} build-bundle --oci $FL_GPGARGS repos/oci oci/app-image org.test.Hello >&2
+$client add hello latest "$(pwd)/oci/app-image"
+
+# Add OCI remote configured to use the mock test authenticator.
+# The default authenticator for OCI remotes is org.flatpak.Authenticator.Oci;
+# we override it to use the mock authenticator that reads its token from
+# $XDG_RUNTIME_DIR/required-token on every call.
+
+${FLATPAK} remote-add ${U} oci-auth-registry "oci+http://127.0.0.1:${port}" \
+ --authenticator-name org.flatpak.Authenticator.test >&2
+
+# Test: install from an auth-protected OCI registry
+#
+# The registry requires a bearer token for all /v2/ requests. The client
+# authenticates via the mock authenticator and completes the installation
+# successfully.
+
+echo -n "token-1" > "${XDG_RUNTIME_DIR}/required-token"
+$client configure-auth --token token-1
+
+${FLATPAK} ${U} install -y oci-auth-registry org.test.Hello >&2
+
+run org.test.Hello > hello_out
+assert_file_has_content hello_out '^Hello world, from a sandbox$'
+
+ok "install from auth-protected OCI registry"

View File

@ -1,4 +1,4 @@
From 5f5aeea8d8be071468fb8e9640554518fb65885e Mon Sep 17 00:00:00 2001
From 33de26dbeeda858042683db5f8d848a319622098 Mon Sep 17 00:00:00 2001
From: Sebastian Wick <sebastian.wick@redhat.com>
Date: Tue, 16 Dec 2025 17:15:32 +0100
Subject: [PATCH] run: Enable FIPS crypto policy if it is enabled on the host
@ -6,17 +6,17 @@ Subject: [PATCH] run: Enable FIPS crypto policy if it is enabled on the host
This is a close copy of what podman/containers does to support FIPS. Any
other crypto policy is ignored for now.
---
common/flatpak-run.c | 87 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 87 insertions(+)
common/flatpak-run.c | 95 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
diff --git ./common/flatpak-run.c ../common/flatpak-run.c
index 6c319231..b51cc637 100644
--- ./common/flatpak-run.c
+++ ../common/flatpak-run.c
@@ -2215,6 +2215,91 @@ flatpak_run_setup_usr_links (FlatpakBwrap *bwrap,
diff --git a/common/flatpak-run.c b/common/flatpak-run.c
index 5ea1250..7a9bf3c 100644
--- a/common/flatpak-run.c
+++ b/common/flatpak-run.c
@@ -2312,6 +2312,91 @@ flatpak_run_setup_usr_links (FlatpakBwrap *bwrap,
}
}
+static void
+flatpak_run_setup_fips (FlatpakBwrap *bwrap,
+ GFile *runtime_files)
@ -105,15 +105,22 @@ index 6c319231..b51cc637 100644
/* Directories in /sys to share with the sandbox if accessible. */
static const char *const sysfs_dirs[] =
{
@@ -2405,6 +2490,8 @@ flatpak_run_setup_base_argv (FlatpakBwrap *bwrap,
@@ -2524,6 +2609,16 @@ flatpak_run_setup_base_argv (FlatpakBwrap *bwrap,
}
}
+ flatpak_run_setup_fips (bwrap, runtime_files);
+ if (runtime_fd >= 0)
+ {
+ g_autofree char *runtime_path = flatpak_get_path_for_fd (runtime_fd, NULL);
+ if (runtime_path != NULL)
+ {
+ g_autoptr(GFile) runtime_files = g_file_new_for_path (runtime_path);
+ flatpak_run_setup_fips (bwrap, runtime_files);
+ }
+ }
+
if (app_id_dir != NULL)
{
g_autoptr(GFile) app_cache_dir = g_file_get_child (app_id_dir, "cache");
--
2.51.0
--
2.53.0

View File

@ -12,7 +12,7 @@
%bcond malcontent %[!0%{?rhel}]
Name: flatpak
Version: 1.17.3
Version: 1.18.0
Release: 1%{?dist}
Summary: Application deployment framework for desktop apps
@ -33,6 +33,10 @@ Source2: flatpak.sysusers.conf
Patch1: flatpak-for-registry.redhat.io-get-certificates-from-etc-pki.patch
# Enable FIPS support
Patch2: flatpak-run-Enable-FIPS-crypto-policy-if-it-is-enabled-on-th.patch
# Retry on 401 with FlatpakTokenProvider (https://github.com/flatpak/flatpak/pull/6662)
Patch3: flatpak-oci-Retry-on-401-with-FlatpakTokenProvider.patch
# Check signatures from mirrored repo in system helper (https://github.com/flatpak/flatpak/pull/6682)
Patch4: flatpak-oci-registry-Check-signatures-from-mirrored-repo-in.patch
# ostree not on i686 for RHEL 10
# https://github.com/containers/composefs/pull/229#issuecomment-1838735764
@ -293,7 +297,7 @@ fi
%files selinux
%{_datadir}/selinux/packages/flatpak.pp.bz2
%{_datadir}/selinux/devel/include/contrib/flatpak.if
%{_datadir}/selinux/devel/include/distributed/flatpak.if
%files session-helper
%license COPYING
@ -308,6 +312,13 @@ fi
%changelog
* Thu Jun 11 2026 Jan Grulich <jgrulich@redhat.com> - 1.18.0-1
- Update to 1.18.0
Resolves: RHEL-126038
Resolves: RHEL-92123
Resolves: RHEL-165631
Resolves: RHEL-170158
* Tue Mar 17 2026 Jan Grulich <jgrulich@redhat.com> - 1.17.3-1
- 1.17.3
Resolves: RHEL-126038

View File

@ -1 +1 @@
SHA512 (flatpak-1.17.3.tar.xz) = 889213e5babafbfc3bc2525d36351d0703a6f5da013c04010f1622236a59c8cea3cdef9430e31599dc0950c2da9621c172d2f6a359b5642273977787b9df1409
SHA512 (flatpak-1.18.0.tar.xz) = 0dbfef463e3d2e7f9fd9db6c301804f1fd37450ef224936f9e68ed2d86bcbe5feaba99ead923bcd5f303bfc6376b858beb951c9f70afbbd65c4a0585ad2abc02