From 4ba188c906ff1c7fd8b582b8bfa2c6cde168e422 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Thu, 27 Oct 2022 16:34:21 +1300 Subject: [PATCH 1/8] portal: Rename function to not be flatpak specific It will also read snap information --- gio/gportalsupport.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gio/gportalsupport.c b/gio/gportalsupport.c index 7d0e3226c..a176865b5 100644 --- a/gio/gportalsupport.c +++ b/gio/gportalsupport.c @@ -28,7 +28,7 @@ static gboolean network_available; static gboolean dconf_access; static void -read_flatpak_info (void) +sandbox_info_read (void) { static gsize flatpak_info_read = 0; GSandboxType sandbox_type; @@ -92,20 +92,20 @@ read_flatpak_info (void) gboolean glib_should_use_portal (void) { - read_flatpak_info (); + sandbox_info_read (); return use_portal; } gboolean glib_network_available_in_sandbox (void) { - read_flatpak_info (); + sandbox_info_read (); return network_available; } gboolean glib_has_dconf_access_in_sandbox (void) { - read_flatpak_info (); + sandbox_info_read (); return dconf_access; } From 660242af0723b6f469ba2baceec2c110a702d1bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 24 Nov 2022 04:23:57 +0100 Subject: [PATCH 2/8] tests/sandbox: Use isolated-directories So we don't have to bother to manually remove the created artifacts. --- gio/tests/sandbox.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/gio/tests/sandbox.c b/gio/tests/sandbox.c index 849260ea0..5c11bcb1a 100644 --- a/gio/tests/sandbox.c +++ b/gio/tests/sandbox.c @@ -30,28 +30,24 @@ test_sandbox_none (void) static void test_sandbox_snap (void) { - gchar *temp_dir, *snap_path, *snap_version_path, *meta_path, *yaml_path; + const char *temp_dir; + gchar *snap_path, *meta_path, *yaml_path; GError *error = NULL; - temp_dir = g_dir_make_tmp ("gio-test-sandbox_XXXXXX", &error); - g_assert_no_error (error); - snap_path = g_build_filename (temp_dir, "snap", NULL); - snap_version_path = g_build_filename (snap_path, "current", NULL); - meta_path = g_build_filename (snap_version_path, "meta", NULL); + temp_dir = g_getenv ("G_TEST_TMPDIR"); + g_assert_nonnull (temp_dir); + + snap_path = g_build_filename (temp_dir, "snap", "current", NULL); + meta_path = g_build_filename (snap_path, "meta", NULL); yaml_path = g_build_filename (meta_path, "snap.yaml", NULL); g_mkdir_with_parents (meta_path, 0700); - g_file_set_contents (yaml_path, "", -1, NULL); - g_setenv ("SNAP", snap_version_path, TRUE); + g_file_set_contents (yaml_path, "", -1, &error); + g_assert_no_error (error); + g_setenv ("SNAP", snap_path, TRUE); g_assert_cmpint (glib_get_sandbox_type (), ==, G_SANDBOX_TYPE_SNAP); g_unsetenv ("SNAP"); - g_unlink (yaml_path); - g_rmdir (meta_path); - g_rmdir (snap_version_path); - g_rmdir (snap_path); - g_rmdir (temp_dir); - g_free (temp_dir); g_free (snap_path); g_free (meta_path); g_free (yaml_path); @@ -60,7 +56,7 @@ test_sandbox_snap (void) int main (int argc, char **argv) { - g_test_init (&argc, &argv, NULL); + g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); g_test_add_func ("/sandbox/none", test_sandbox_none); g_test_add_func ("/sandbox/snap", test_sandbox_snap); From 0e4dff445fed5773d730f9c1373453fe420e7d97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 24 Nov 2022 04:26:19 +0100 Subject: [PATCH 3/8] gsandbox: Mark classic snaps as UNKNOWN sandbox type Classic snaps are just a kind of packages with no sandbox at all, so there's no point to mark them as sandboxed. In this way we can just do IO checks once without having to multiply them. Co-Authored-by: Robert Ancell --- gio/gsandbox.c | 53 ++++++++++++++++++++++++++++++++++++++++++++- gio/tests/sandbox.c | 38 +++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/gio/gsandbox.c b/gio/gsandbox.c index ced0df7db..34f680b5a 100644 --- a/gio/gsandbox.c +++ b/gio/gsandbox.c @@ -22,27 +22,78 @@ #include "gsandbox.h" +#include + +#define SNAP_CONFINEMENT_PREFIX "confinement:" + static gboolean is_flatpak (void) { return g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS); } +static gchar * +get_snap_confinement (const char *snap_yaml, + GError **error) +{ + char *confinement = NULL; + char *yaml_contents; + + if (g_file_get_contents (snap_yaml, &yaml_contents, NULL, error)) + { + const char *line = yaml_contents; + + do + { + if (g_str_has_prefix (line, SNAP_CONFINEMENT_PREFIX)) + break; + + line = strchr (line, '\n'); + if (line) + line += 1; + } + while (line != NULL); + + if (line) + { + const char *start = line + strlen (SNAP_CONFINEMENT_PREFIX); + const char *end = strchr (start, '\n'); + + confinement = + g_strstrip (end ? g_strndup (start, end-start) : g_strdup (start)); + } + + g_free (yaml_contents); + } + + return g_steal_pointer (&confinement); +} + static gboolean is_snap (void) { + GError *error = NULL; const gchar *snap_path; gchar *yaml_path; + char *confinement; gboolean result; snap_path = g_getenv ("SNAP"); if (snap_path == NULL) return FALSE; + result = FALSE; yaml_path = g_build_filename (snap_path, "meta", "snap.yaml", NULL); - result = g_file_test (yaml_path, G_FILE_TEST_EXISTS); + confinement = get_snap_confinement (yaml_path, &error); g_free (yaml_path); + /* Classic snaps are de-facto no sandboxed apps, so we can ignore them */ + if (!error && g_strcmp0 (confinement, "classic") != 0) + result = TRUE; + + g_clear_error (&error); + g_free (confinement); + return result; } diff --git a/gio/tests/sandbox.c b/gio/tests/sandbox.c index 5c11bcb1a..1f5c8bd15 100644 --- a/gio/tests/sandbox.c +++ b/gio/tests/sandbox.c @@ -33,6 +33,10 @@ test_sandbox_snap (void) const char *temp_dir; gchar *snap_path, *meta_path, *yaml_path; GError *error = NULL; + const char *contents = "name: glib-test-portal-support\n" + "title: GLib Portal Support Test\n" + "version: 2.76\n" + "summary: Test it works\n"; temp_dir = g_getenv ("G_TEST_TMPDIR"); g_assert_nonnull (temp_dir); @@ -41,7 +45,7 @@ test_sandbox_snap (void) meta_path = g_build_filename (snap_path, "meta", NULL); yaml_path = g_build_filename (meta_path, "snap.yaml", NULL); g_mkdir_with_parents (meta_path, 0700); - g_file_set_contents (yaml_path, "", -1, &error); + g_file_set_contents (yaml_path, contents, -1, &error); g_assert_no_error (error); g_setenv ("SNAP", snap_path, TRUE); @@ -53,6 +57,37 @@ test_sandbox_snap (void) g_free (yaml_path); } +static void +test_sandbox_snap_classic (void) +{ + GError *error = NULL; + const char *temp_dir; + char *snap_path, *meta_path, *yaml_path; + const char *contents = "name: glib-test-portal-support\n" + "title: GLib Portal Support Test\n" + "version: 2.76\n" + "summary: Test it works\n" + "confinement: classic\n"; + + temp_dir = g_getenv ("G_TEST_TMPDIR"); + g_assert_nonnull (temp_dir); + + snap_path = g_build_filename (temp_dir, "snap", "current", NULL); + meta_path = g_build_filename (snap_path, "meta", NULL); + yaml_path = g_build_filename (meta_path, "snap.yaml", NULL); + g_mkdir_with_parents (meta_path, 0700); + g_file_set_contents (yaml_path, contents, -1, &error); + g_assert_no_error (error); + g_setenv ("SNAP", snap_path, TRUE); + + g_assert_cmpint (glib_get_sandbox_type (), ==, G_SANDBOX_TYPE_UNKNOWN); + + g_unsetenv ("SNAP"); + g_free (snap_path); + g_free (meta_path); + g_free (yaml_path); +} + int main (int argc, char **argv) { @@ -60,6 +95,7 @@ main (int argc, char **argv) g_test_add_func ("/sandbox/none", test_sandbox_none); g_test_add_func ("/sandbox/snap", test_sandbox_snap); + g_test_add_func ("/sandbox/classic-snap", test_sandbox_snap_classic); return g_test_run (); } From 216d7ba0428acfc4e8421267d95f53fb99051c68 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Thu, 27 Oct 2022 10:35:30 +1300 Subject: [PATCH 4/8] portal: Check for snap plugs before accessing portals This is of particular use in the gsettings backend, which is currently using dconf for all snaps. Fully confined snaps should use the keyfile backend, as Flatpaks do. Co-Authored-by: Marco Trevisan --- gio/gportalsupport.c | 57 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/gio/gportalsupport.c b/gio/gportalsupport.c index a176865b5..d6aaab4fd 100644 --- a/gio/gportalsupport.c +++ b/gio/gportalsupport.c @@ -20,23 +20,50 @@ #include "config.h" +#include "glib-private.h" #include "gportalsupport.h" #include "gsandbox.h" +static GSandboxType sandbox_type = G_SANDBOX_TYPE_UNKNOWN; static gboolean use_portal; static gboolean network_available; static gboolean dconf_access; +static gboolean +snap_plug_is_connected (const gchar *plug_name) +{ + const gchar *argv[] = { "snapctl", "is-connected", plug_name, NULL }; + gint wait_status; + + /* Bail out if our process is privileged - we don't want to pass those + * privileges to snapctl. It could be overridden using PATH and this would + * allow arbitrary code execution. + */ + if (GLIB_PRIVATE_CALL (g_check_setuid) ()) + return FALSE; + + if (!g_spawn_sync (NULL, (gchar **) argv, NULL, + G_SPAWN_SEARCH_PATH | + G_SPAWN_STDOUT_TO_DEV_NULL | + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, NULL, NULL, &wait_status, + NULL)) + return FALSE; + + return g_spawn_check_wait_status (wait_status, NULL); +} + static void sandbox_info_read (void) { - static gsize flatpak_info_read = 0; - GSandboxType sandbox_type; + static gsize sandbox_info_is_read = 0; - if (!g_once_init_enter (&flatpak_info_read)) + /* Sandbox type and Flatpak info is static, so only read once */ + if (!g_once_init_enter (&sandbox_info_is_read)) return; sandbox_type = glib_get_sandbox_type (); + switch (sandbox_type) { case G_SANDBOX_TYPE_FLATPAK: @@ -72,8 +99,9 @@ sandbox_info_read (void) g_key_file_unref (keyfile); } break; - case G_SANDBOX_TYPE_UNKNOWN: case G_SANDBOX_TYPE_SNAP: + break; + case G_SANDBOX_TYPE_UNKNOWN: { const char *var; @@ -86,13 +114,17 @@ sandbox_info_read (void) break; } - g_once_init_leave (&flatpak_info_read, 1); + g_once_init_leave (&sandbox_info_is_read, 1); } gboolean glib_should_use_portal (void) { sandbox_info_read (); + + if (sandbox_type == G_SANDBOX_TYPE_SNAP) + return snap_plug_is_connected ("desktop"); + return use_portal; } @@ -100,6 +132,17 @@ gboolean glib_network_available_in_sandbox (void) { sandbox_info_read (); + + if (sandbox_type == G_SANDBOX_TYPE_SNAP) + { + /* FIXME: This is inefficient doing multiple calls to check connections. + * See https://github.com/snapcore/snapd/pull/12301 for a proposed + * improvement to snapd for this. + */ + return snap_plug_is_connected ("desktop") || + snap_plug_is_connected ("network-status"); + } + return network_available; } @@ -107,5 +150,9 @@ gboolean glib_has_dconf_access_in_sandbox (void) { sandbox_info_read (); + + if (sandbox_type == G_SANDBOX_TYPE_SNAP) + return snap_plug_is_connected ("gsettings"); + return dconf_access; } From b1a2b64e94b6c38dbd438a6b9c4f24233f507745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 24 Nov 2022 05:27:27 +0100 Subject: [PATCH 5/8] gio/tests: Add tests for portal support functions Test all the snap cases and the unknown sandbox one. We need to use different test processes as we initialize the portal type early enough that it can't be changed later. --- gio/tests/meson.build | 16 ++ gio/tests/portal-support-env-var.c | 45 +++++ gio/tests/portal-support-none.c | 43 +++++ gio/tests/portal-support-snap-classic.c | 119 ++++++++++++++ gio/tests/portal-support-snap.c | 208 ++++++++++++++++++++++++ gio/tests/portal-support-utils.c | 87 ++++++++++ gio/tests/portal-support-utils.h | 30 ++++ 7 files changed, 548 insertions(+) create mode 100644 gio/tests/portal-support-env-var.c create mode 100644 gio/tests/portal-support-none.c create mode 100644 gio/tests/portal-support-snap-classic.c create mode 100644 gio/tests/portal-support-snap.c create mode 100644 gio/tests/portal-support-utils.c create mode 100644 gio/tests/portal-support-utils.h diff --git a/gio/tests/meson.build b/gio/tests/meson.build index 78b7f87b4..baf114c96 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -227,6 +227,22 @@ if host_machine.system() != 'windows' 'gdbus-peer-object-manager' : {}, 'gdbus-sasl' : {}, 'live-g-file' : {}, + 'portal-support-none' : { + 'extra_sources': ['../gportalsupport.c', '../gsandbox.c'], + 'suite': ['portal-support'], + }, + 'portal-support-env-var' : { + 'extra_sources': ['../gportalsupport.c', '../gsandbox.c'], + 'suite': ['portal-support'], + }, + 'portal-support-snap' : { + 'extra_sources': ['../gportalsupport.c', '../gsandbox.c', 'portal-support-utils.c'], + 'suite': ['portal-support'], + }, + 'portal-support-snap-classic' : { + 'extra_sources': ['../gportalsupport.c', '../gsandbox.c', 'portal-support-utils.c'], + 'suite': ['portal-support'], + }, 'resolver-parsing' : {'dependencies' : [network_libs]}, 'socket-address' : {}, 'stream-rw_all' : {}, diff --git a/gio/tests/portal-support-env-var.c b/gio/tests/portal-support-env-var.c new file mode 100644 index 000000000..b1d3fd3c3 --- /dev/null +++ b/gio/tests/portal-support-env-var.c @@ -0,0 +1,45 @@ +/* + * GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2022 Canonical Ltd. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * 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.1 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, see . + * + * Author: Marco Trevisan + */ + +#include "../gportalsupport.h" +#include + +static void +test_portal_support_env_var (void) +{ + g_assert_true (glib_should_use_portal ()); + g_assert_true (glib_network_available_in_sandbox ()); + g_assert_true (glib_has_dconf_access_in_sandbox ()); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + g_setenv ("GTK_USE_PORTAL", "1", TRUE); + + g_test_add_func ("/portal-support/env-var", test_portal_support_env_var); + + return g_test_run (); +} diff --git a/gio/tests/portal-support-none.c b/gio/tests/portal-support-none.c new file mode 100644 index 000000000..1bc0a9391 --- /dev/null +++ b/gio/tests/portal-support-none.c @@ -0,0 +1,43 @@ +/* + * GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2022 Canonical Ltd. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * 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.1 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, see . + * + * Author: Marco Trevisan + */ + +#include "../gportalsupport.h" +#include + +static void +test_portal_support_none (void) +{ + g_assert_false (glib_should_use_portal ()); + g_assert_true (glib_network_available_in_sandbox ()); + g_assert_true (glib_has_dconf_access_in_sandbox ()); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/portal-support/none", test_portal_support_none); + + return g_test_run (); +} diff --git a/gio/tests/portal-support-snap-classic.c b/gio/tests/portal-support-snap-classic.c new file mode 100644 index 000000000..8c0ed90c2 --- /dev/null +++ b/gio/tests/portal-support-snap-classic.c @@ -0,0 +1,119 @@ +/* + * GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2022 Canonical Ltd. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * 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.1 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, see . + * + * Author: Marco Trevisan + */ + +#include "portal-support-utils.h" + +#include "../gportalsupport.h" +#include + +typedef struct +{ + char *old_path; + char *old_snap; + + const char *bin_path; + const char *snap_path; +} SetupData; + +static void +tests_setup (SetupData *setup_data, + gconstpointer data) +{ + setup_data->old_path = g_strdup (g_getenv ("PATH")); + setup_data->old_snap = g_strdup (g_getenv ("SNAP")); + + setup_data->bin_path = g_get_user_runtime_dir (); + setup_data->snap_path = g_getenv ("G_TEST_TMPDIR"); + + g_assert_nonnull (setup_data->bin_path); + g_assert_nonnull (setup_data->snap_path); + + g_setenv ("PATH", setup_data->bin_path, TRUE); + g_setenv ("SNAP", setup_data->snap_path, TRUE); +} + +static void +tests_teardown (SetupData *setup_data, + gconstpointer data) +{ + if (setup_data->old_path) + g_setenv ("PATH", setup_data->old_path, TRUE); + else + g_unsetenv ("PATH"); + + if (setup_data->old_snap) + g_setenv ("SNAP", setup_data->old_snap, TRUE); + else + g_unsetenv ("SNAP"); + + g_clear_pointer (&setup_data->old_path, g_free); + g_clear_pointer (&setup_data->old_snap, g_free); +} + +static void +test_portal_support_snap_no_snapctl (SetupData *setup, + gconstpointer data) +{ + g_assert_false (glib_should_use_portal ()); + g_assert_true (glib_network_available_in_sandbox ()); + g_assert_true (glib_has_dconf_access_in_sandbox ()); +} + +static void +test_portal_support_snap_none (SetupData *setup, + gconstpointer data) +{ + create_fake_snap_yaml (setup->snap_path, TRUE); + create_fake_snapctl (setup->bin_path, NULL); + + g_assert_false (glib_should_use_portal ()); + g_assert_true (glib_network_available_in_sandbox ()); + g_assert_true (glib_has_dconf_access_in_sandbox ()); +} + +static void +test_portal_support_snap_all (SetupData *setup, + gconstpointer data) +{ + create_fake_snap_yaml (setup->snap_path, TRUE); + create_fake_snapctl (setup->bin_path, "desktop|network-status|gsettings"); + + g_assert_false (glib_should_use_portal ()); + g_assert_true (glib_network_available_in_sandbox ()); + g_assert_true (glib_has_dconf_access_in_sandbox ()); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); + + g_test_add ("/portal-support/snap-classic/no-snapctl", SetupData, NULL, + tests_setup, test_portal_support_snap_no_snapctl, tests_teardown); + g_test_add ("/portal-support/snap-classic/none", SetupData, NULL, + tests_setup, test_portal_support_snap_none, tests_teardown); + g_test_add ("/portal-support/snap-classic/all", SetupData, NULL, + tests_setup, test_portal_support_snap_all, tests_teardown); + + return g_test_run (); +} diff --git a/gio/tests/portal-support-snap.c b/gio/tests/portal-support-snap.c new file mode 100644 index 000000000..7dd14d82f --- /dev/null +++ b/gio/tests/portal-support-snap.c @@ -0,0 +1,208 @@ +/* + * GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2022 Canonical Ltd. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * 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.1 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, see . + * + * Author: Marco Trevisan + */ + +#include "portal-support-utils.h" + +#include "../gportalsupport.h" +#include +#include + +typedef struct +{ + char *old_path; + char *old_snap; + + const char *bin_path; + const char *snap_path; +} SetupData; + +static void +tests_setup (SetupData *setup_data, + gconstpointer data) +{ + setup_data->old_path = g_strdup (g_getenv ("PATH")); + setup_data->old_snap = g_strdup (g_getenv ("SNAP")); + + setup_data->bin_path = g_get_user_runtime_dir (); + setup_data->snap_path = g_getenv ("G_TEST_TMPDIR"); + + g_assert_nonnull (setup_data->bin_path); + g_assert_nonnull (setup_data->snap_path); + + g_setenv ("PATH", setup_data->bin_path, TRUE); + g_setenv ("SNAP", setup_data->snap_path, TRUE); +} + +static void +tests_teardown (SetupData *setup_data, + gconstpointer data) +{ + if (setup_data->old_path) + g_setenv ("PATH", setup_data->old_path, TRUE); + else + g_unsetenv ("PATH"); + + if (setup_data->old_snap) + g_setenv ("SNAP", setup_data->old_snap, TRUE); + else + g_unsetenv ("SNAP"); + + g_clear_pointer (&setup_data->old_path, g_free); + g_clear_pointer (&setup_data->old_snap, g_free); +} + +static void +test_portal_support_snap_no_snapctl (SetupData *setup, + gconstpointer data) +{ + create_fake_snap_yaml (setup->snap_path, FALSE); + + g_assert_false (glib_should_use_portal ()); + g_assert_false (glib_network_available_in_sandbox ()); + g_assert_false (glib_has_dconf_access_in_sandbox ()); +} + +static void +test_portal_support_snap_none (SetupData *setup, + gconstpointer data) +{ + create_fake_snap_yaml (setup->snap_path, FALSE); + create_fake_snapctl (setup->bin_path, NULL); + + g_assert_false (glib_should_use_portal ()); + g_assert_false (glib_network_available_in_sandbox ()); + g_assert_false (glib_has_dconf_access_in_sandbox ()); +} + +static void +test_portal_support_snap_all (SetupData *setup, + gconstpointer data) +{ + create_fake_snap_yaml (setup->snap_path, FALSE); + create_fake_snapctl (setup->bin_path, "desktop|network-status|gsettings"); + + g_assert_true (glib_should_use_portal ()); + g_assert_true (glib_network_available_in_sandbox ()); + g_assert_true (glib_has_dconf_access_in_sandbox ()); +} + +static void +test_portal_support_snap_desktop_only (SetupData *setup, + gconstpointer data) +{ + create_fake_snap_yaml (setup->snap_path, FALSE); + create_fake_snapctl (setup->bin_path, "desktop"); + + g_assert_true (glib_should_use_portal ()); + g_assert_true (glib_network_available_in_sandbox ()); + g_assert_false (glib_has_dconf_access_in_sandbox ()); +} + +static void +test_portal_support_snap_network_only (SetupData *setup, + gconstpointer data) +{ + create_fake_snap_yaml (setup->snap_path, FALSE); + create_fake_snapctl (setup->bin_path, "network-status"); + + g_assert_false (glib_should_use_portal ()); + g_assert_true (glib_network_available_in_sandbox ()); + g_assert_false (glib_has_dconf_access_in_sandbox ()); +} + +static void +test_portal_support_snap_gsettings_only (SetupData *setup, + gconstpointer data) +{ + create_fake_snap_yaml (setup->snap_path, FALSE); + create_fake_snapctl (setup->bin_path, "gsettings"); + + g_assert_false (glib_should_use_portal ()); + g_assert_false (glib_network_available_in_sandbox ()); + g_assert_true (glib_has_dconf_access_in_sandbox ()); +} + +static void +test_portal_support_snap_updates_dynamically (SetupData *setup, + gconstpointer data) +{ + create_fake_snap_yaml (setup->snap_path, FALSE); + create_fake_snapctl (setup->bin_path, NULL); + + g_assert_false (glib_should_use_portal ()); + g_assert_false (glib_network_available_in_sandbox ()); + g_assert_false (glib_has_dconf_access_in_sandbox ()); + + create_fake_snapctl (setup->bin_path, "desktop"); + g_assert_true (glib_should_use_portal ()); + g_assert_true (glib_network_available_in_sandbox ()); + g_assert_false (glib_has_dconf_access_in_sandbox ()); + + create_fake_snapctl (setup->bin_path, "network-status|gsettings"); + g_assert_false (glib_should_use_portal ()); + g_assert_true (glib_network_available_in_sandbox ()); + g_assert_true (glib_has_dconf_access_in_sandbox ()); + + create_fake_snapctl (setup->bin_path, "desktop|network-status|gsettings"); + g_assert_true (glib_should_use_portal ()); + g_assert_true (glib_network_available_in_sandbox ()); + g_assert_true (glib_has_dconf_access_in_sandbox ()); + + create_fake_snapctl (setup->bin_path, "desktop|gsettings"); + g_assert_true (glib_should_use_portal ()); + g_assert_true (glib_network_available_in_sandbox ()); + g_assert_true (glib_has_dconf_access_in_sandbox ()); + + create_fake_snapctl (setup->bin_path, "gsettings"); + g_assert_false (glib_should_use_portal ()); + g_assert_false (glib_network_available_in_sandbox ()); + g_assert_true (glib_has_dconf_access_in_sandbox ()); + + create_fake_snapctl (setup->bin_path, NULL); + g_assert_false (glib_should_use_portal ()); + g_assert_false (glib_network_available_in_sandbox ()); + g_assert_false (glib_has_dconf_access_in_sandbox ()); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); + + g_test_add ("/portal-support/snap/no-snapctl", SetupData, NULL, + tests_setup, test_portal_support_snap_no_snapctl, tests_teardown); + g_test_add ("/portal-support/snap/none", SetupData, NULL, + tests_setup, test_portal_support_snap_none, tests_teardown); + g_test_add ("/portal-support/snap/all", SetupData, NULL, + tests_setup, test_portal_support_snap_all, tests_teardown); + g_test_add ("/portal-support/snap/desktop-only", SetupData, NULL, + tests_setup, test_portal_support_snap_desktop_only, tests_teardown); + g_test_add ("/portal-support/snap/network-only", SetupData, NULL, + tests_setup, test_portal_support_snap_network_only, tests_teardown); + g_test_add ("/portal-support/snap/gsettings-only", SetupData, NULL, + tests_setup, test_portal_support_snap_gsettings_only, tests_teardown); + g_test_add ("/portal-support/snap/updates-dynamically", SetupData, NULL, + tests_setup, test_portal_support_snap_updates_dynamically, tests_teardown); + + return g_test_run (); +} diff --git a/gio/tests/portal-support-utils.c b/gio/tests/portal-support-utils.c new file mode 100644 index 000000000..9fb69287a --- /dev/null +++ b/gio/tests/portal-support-utils.c @@ -0,0 +1,87 @@ +/* + * GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2022 Canonical Ltd. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * 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.1 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, see . + * + * Author: Marco Trevisan + */ + +#include "portal-support-utils.h" + +#include +#include + +void +create_fake_snapctl (const char *path, + const char *supported_op) +{ + GError *error = NULL; + char *snapctl_content; + char *snapctl; + + snapctl = g_build_filename (path, "snapctl", NULL); + snapctl_content = g_strdup_printf ("#!/bin/sh\n" \ + "[ \"$1\" != 'is-connected' ] && exit 2\n" + "[ -z \"$2\" ] && exit 3\n" + "[ -n \"$3\" ] && exit 4\n" + "case \"$2\" in\n" + " %s) exit 0;;\n" + " *) exit 1;;\n" + "esac\n", + supported_op ? supported_op : ""); + + g_file_set_contents (snapctl, snapctl_content, -1, &error); + g_assert_no_error (error); + g_assert_cmpint (g_chmod (snapctl, 0500), ==, 0); + + g_test_message ("Created snapctl in %s", snapctl); + + g_clear_error (&error); + g_free (snapctl_content); + g_free (snapctl); +} + +void +create_fake_snap_yaml (const char *snap_path, + gboolean is_classic) +{ + char *meta_path; + char *yaml_path; + char *yaml_contents; + + g_assert_nonnull (snap_path); + + yaml_contents = g_strconcat ("name: glib-test-portal-support\n" + "title: GLib Portal Support Test\n" + "version: 2.76\n" + "summary: Test it works\n", + is_classic ? + "confinement: classic\n" : NULL, NULL); + + meta_path = g_build_filename (snap_path, "meta", NULL); + g_assert_cmpint (g_mkdir_with_parents (meta_path, 0700), ==, 0); + + yaml_path = g_build_filename (meta_path, "snap.yaml", NULL); + g_file_set_contents (yaml_path, yaml_contents, -1, NULL); + + g_test_message ("Created snap.yaml in %s", yaml_path); + + g_free (meta_path); + g_free (yaml_path); + g_free (yaml_contents); +} diff --git a/gio/tests/portal-support-utils.h b/gio/tests/portal-support-utils.h new file mode 100644 index 000000000..bb5a31c6e --- /dev/null +++ b/gio/tests/portal-support-utils.h @@ -0,0 +1,30 @@ +/* + * GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2022 Canonical Ltd. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * 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.1 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, see . + * + * Author: Marco Trevisan + */ + +#include + +void create_fake_snap_yaml (const char *snap_path, + gboolean is_classic); + +void create_fake_snapctl (const char *path, + const char *supported_op); From 94ebd9f041c9c07da2e42f5682f16d08feb9b3c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 24 Nov 2022 05:33:30 +0100 Subject: [PATCH 6/8] gio/tests/sandbox: Use test portal utils to create fake snap.yaml --- gio/tests/meson.build | 2 +- gio/tests/sandbox.c | 33 ++++++--------------------------- 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/gio/tests/meson.build b/gio/tests/meson.build index baf114c96..43c5820cc 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -108,7 +108,7 @@ gio_tests = { 'proxy-test' : {}, 'readwrite' : {}, 'sandbox' : { - 'source': ['sandbox.c', '../gsandbox.c'], + 'extra_sources': ['../gsandbox.c', 'portal-support-utils.c'], }, 'simple-async-result' : {}, 'simple-proxy' : {}, diff --git a/gio/tests/sandbox.c b/gio/tests/sandbox.c index 1f5c8bd15..a432556dd 100644 --- a/gio/tests/sandbox.c +++ b/gio/tests/sandbox.c @@ -17,6 +17,8 @@ * Public License along with this library; if not, see . */ +#include "portal-support-utils.h" + #include "../gsandbox.h" #include #include @@ -31,61 +33,38 @@ static void test_sandbox_snap (void) { const char *temp_dir; - gchar *snap_path, *meta_path, *yaml_path; - GError *error = NULL; - const char *contents = "name: glib-test-portal-support\n" - "title: GLib Portal Support Test\n" - "version: 2.76\n" - "summary: Test it works\n"; + gchar *snap_path; temp_dir = g_getenv ("G_TEST_TMPDIR"); g_assert_nonnull (temp_dir); snap_path = g_build_filename (temp_dir, "snap", "current", NULL); - meta_path = g_build_filename (snap_path, "meta", NULL); - yaml_path = g_build_filename (meta_path, "snap.yaml", NULL); - g_mkdir_with_parents (meta_path, 0700); - g_file_set_contents (yaml_path, contents, -1, &error); - g_assert_no_error (error); + create_fake_snap_yaml (snap_path, FALSE); g_setenv ("SNAP", snap_path, TRUE); g_assert_cmpint (glib_get_sandbox_type (), ==, G_SANDBOX_TYPE_SNAP); g_unsetenv ("SNAP"); g_free (snap_path); - g_free (meta_path); - g_free (yaml_path); } static void test_sandbox_snap_classic (void) { - GError *error = NULL; const char *temp_dir; - char *snap_path, *meta_path, *yaml_path; - const char *contents = "name: glib-test-portal-support\n" - "title: GLib Portal Support Test\n" - "version: 2.76\n" - "summary: Test it works\n" - "confinement: classic\n"; + char *snap_path; temp_dir = g_getenv ("G_TEST_TMPDIR"); g_assert_nonnull (temp_dir); snap_path = g_build_filename (temp_dir, "snap", "current", NULL); - meta_path = g_build_filename (snap_path, "meta", NULL); - yaml_path = g_build_filename (meta_path, "snap.yaml", NULL); - g_mkdir_with_parents (meta_path, 0700); - g_file_set_contents (yaml_path, contents, -1, &error); - g_assert_no_error (error); + create_fake_snap_yaml (snap_path, TRUE); g_setenv ("SNAP", snap_path, TRUE); g_assert_cmpint (glib_get_sandbox_type (), ==, G_SANDBOX_TYPE_UNKNOWN); g_unsetenv ("SNAP"); g_free (snap_path); - g_free (meta_path); - g_free (yaml_path); } int From e6eebfd9c344bd16873728258f7c29bb63b255d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 24 Nov 2022 05:54:07 +0100 Subject: [PATCH 7/8] gportalsupport: Force use /usr/bin/snapctl to get snap connection status Do not search in path for snapctl to avoid it to be potentially overridden by changing the PATH env variable. Still allow testing by using an ifdef to check if we're building for the test files or not. --- gio/gportalsupport.c | 12 ++++++++++-- gio/tests/meson.build | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/gio/gportalsupport.c b/gio/gportalsupport.c index d6aaab4fd..2dd329489 100644 --- a/gio/gportalsupport.c +++ b/gio/gportalsupport.c @@ -29,21 +29,29 @@ static gboolean use_portal; static gboolean network_available; static gboolean dconf_access; +#ifdef G_PORTAL_SUPPORT_TEST +static const char *snapctl = "snapctl"; +#else +static const char *snapctl = "/usr/bin/snapctl"; +#endif + static gboolean snap_plug_is_connected (const gchar *plug_name) { - const gchar *argv[] = { "snapctl", "is-connected", plug_name, NULL }; gint wait_status; + const gchar *argv[] = { snapctl, "is-connected", plug_name, NULL }; /* Bail out if our process is privileged - we don't want to pass those - * privileges to snapctl. It could be overridden using PATH and this would + * privileges to snapctl. It could be overridden and this would * allow arbitrary code execution. */ if (GLIB_PRIVATE_CALL (g_check_setuid) ()) return FALSE; if (!g_spawn_sync (NULL, (gchar **) argv, NULL, +#ifdef G_PORTAL_SUPPORT_TEST G_SPAWN_SEARCH_PATH | +#endif G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, NULL, NULL, &wait_status, diff --git a/gio/tests/meson.build b/gio/tests/meson.build index 43c5820cc..1fc5258aa 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -229,6 +229,7 @@ if host_machine.system() != 'windows' 'live-g-file' : {}, 'portal-support-none' : { 'extra_sources': ['../gportalsupport.c', '../gsandbox.c'], + 'c_args': ['-DG_PORTAL_SUPPORT_TEST'], 'suite': ['portal-support'], }, 'portal-support-env-var' : { @@ -237,10 +238,12 @@ if host_machine.system() != 'windows' }, 'portal-support-snap' : { 'extra_sources': ['../gportalsupport.c', '../gsandbox.c', 'portal-support-utils.c'], + 'c_args': ['-DG_PORTAL_SUPPORT_TEST'], 'suite': ['portal-support'], }, 'portal-support-snap-classic' : { 'extra_sources': ['../gportalsupport.c', '../gsandbox.c', 'portal-support-utils.c'], + 'c_args': ['-DG_PORTAL_SUPPORT_TEST'], 'suite': ['portal-support'], }, 'resolver-parsing' : {'dependencies' : [network_libs]}, From 92fae633a0d9e6f0edaa379595ef999161d3643d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 24 Nov 2022 19:07:27 +0100 Subject: [PATCH 8/8] gio/tests: Add tests for flatpak infos Support testing flatpak infos, we do it by faking /.flatpak-info file in case we're building in test mode. --- gio/gportalsupport.c | 14 ++++- gio/gsandbox.c | 17 +++++- gio/tests/meson.build | 21 ++++++++ gio/tests/portal-support-flatpak-full.c | 49 +++++++++++++++++ .../portal-support-flatpak-gsettings-only.c | 49 +++++++++++++++++ .../portal-support-flatpak-network-only.c | 49 +++++++++++++++++ gio/tests/portal-support-flatpak-none.c | 47 ++++++++++++++++ gio/tests/portal-support-utils.c | 54 +++++++++++++++++++ gio/tests/portal-support-utils.h | 7 +++ gio/tests/sandbox.c | 8 +++ 10 files changed, 313 insertions(+), 2 deletions(-) create mode 100644 gio/tests/portal-support-flatpak-full.c create mode 100644 gio/tests/portal-support-flatpak-gsettings-only.c create mode 100644 gio/tests/portal-support-flatpak-network-only.c create mode 100644 gio/tests/portal-support-flatpak-none.c diff --git a/gio/gportalsupport.c b/gio/gportalsupport.c index 2dd329489..7e1da2273 100644 --- a/gio/gportalsupport.c +++ b/gio/gportalsupport.c @@ -77,13 +77,21 @@ sandbox_info_read (void) case G_SANDBOX_TYPE_FLATPAK: { GKeyFile *keyfile; + const char *keyfile_path = "/.flatpak-info"; use_portal = TRUE; network_available = FALSE; dconf_access = FALSE; keyfile = g_key_file_new (); - if (g_key_file_load_from_file (keyfile, "/.flatpak-info", G_KEY_FILE_NONE, NULL)) + +#ifdef G_PORTAL_SUPPORT_TEST + char *test_key_file = + g_build_filename (g_get_user_runtime_dir (), keyfile_path, NULL); + keyfile_path = test_key_file; +#endif + + if (g_key_file_load_from_file (keyfile, keyfile_path, G_KEY_FILE_NONE, NULL)) { char **shared = NULL; char *dconf_policy = NULL; @@ -104,6 +112,10 @@ sandbox_info_read (void) } } +#ifdef G_PORTAL_SUPPORT_TEST + g_clear_pointer (&test_key_file, g_free); +#endif + g_key_file_unref (keyfile); } break; diff --git a/gio/gsandbox.c b/gio/gsandbox.c index 34f680b5a..fcbefa902 100644 --- a/gio/gsandbox.c +++ b/gio/gsandbox.c @@ -29,7 +29,22 @@ static gboolean is_flatpak (void) { - return g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS); + const char *flatpak_info = "/.flatpak-info"; + gboolean found; + +#ifdef G_PORTAL_SUPPORT_TEST + char *test_key_file = + g_build_filename (g_get_user_runtime_dir (), flatpak_info, NULL); + flatpak_info = test_key_file; +#endif + + found = g_file_test (flatpak_info, G_FILE_TEST_EXISTS); + +#ifdef G_PORTAL_SUPPORT_TEST + g_clear_pointer (&test_key_file, g_free); +#endif + + return found; } static gchar * diff --git a/gio/tests/meson.build b/gio/tests/meson.build index 1fc5258aa..66b650376 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -109,6 +109,7 @@ gio_tests = { 'readwrite' : {}, 'sandbox' : { 'extra_sources': ['../gsandbox.c', 'portal-support-utils.c'], + 'c_args': ['-DG_PORTAL_SUPPORT_TEST'], }, 'simple-async-result' : {}, 'simple-proxy' : {}, @@ -227,6 +228,26 @@ if host_machine.system() != 'windows' 'gdbus-peer-object-manager' : {}, 'gdbus-sasl' : {}, 'live-g-file' : {}, + 'portal-support-flatpak-none' : { + 'extra_sources': ['../gportalsupport.c', '../gsandbox.c', 'portal-support-utils.c'], + 'c_args': ['-DG_PORTAL_SUPPORT_TEST'], + 'suite': ['portal-support'], + }, + 'portal-support-flatpak-full' : { + 'extra_sources': ['../gportalsupport.c', '../gsandbox.c', 'portal-support-utils.c'], + 'c_args': ['-DG_PORTAL_SUPPORT_TEST'], + 'suite': ['portal-support'], + }, + 'portal-support-flatpak-network-only' : { + 'extra_sources': ['../gportalsupport.c', '../gsandbox.c', 'portal-support-utils.c'], + 'c_args': ['-DG_PORTAL_SUPPORT_TEST'], + 'suite': ['portal-support'], + }, + 'portal-support-flatpak-gsettings-only' : { + 'extra_sources': ['../gportalsupport.c', '../gsandbox.c', 'portal-support-utils.c'], + 'c_args': ['-DG_PORTAL_SUPPORT_TEST'], + 'suite': ['portal-support'], + }, 'portal-support-none' : { 'extra_sources': ['../gportalsupport.c', '../gsandbox.c'], 'c_args': ['-DG_PORTAL_SUPPORT_TEST'], diff --git a/gio/tests/portal-support-flatpak-full.c b/gio/tests/portal-support-flatpak-full.c new file mode 100644 index 000000000..539e96ffd --- /dev/null +++ b/gio/tests/portal-support-flatpak-full.c @@ -0,0 +1,49 @@ +/* + * GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2022 Canonical Ltd. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * 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.1 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, see . + * + * Author: Marco Trevisan + */ + +#include "portal-support-utils.h" + +#include "../gportalsupport.h" +#include + +static void +test_portal_support_flatpak_full (void) +{ + create_fake_flatpak_info (g_get_user_runtime_dir (), + (GStrv)(const char* []) {"foo", "bar", "network", "more", NULL}, + "talk"); + + g_assert_true (glib_should_use_portal ()); + g_assert_true (glib_network_available_in_sandbox ()); + g_assert_true (glib_has_dconf_access_in_sandbox ()); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); + + g_test_add_func ("/portal-support/flatpak/full", test_portal_support_flatpak_full); + + return g_test_run (); +} diff --git a/gio/tests/portal-support-flatpak-gsettings-only.c b/gio/tests/portal-support-flatpak-gsettings-only.c new file mode 100644 index 000000000..1b8b93401 --- /dev/null +++ b/gio/tests/portal-support-flatpak-gsettings-only.c @@ -0,0 +1,49 @@ +/* + * GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2022 Canonical Ltd. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * 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.1 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, see . + * + * Author: Marco Trevisan + */ + +#include "portal-support-utils.h" + +#include "../gportalsupport.h" +#include + +static void +test_portal_support_flatpak_gsettings_only (void) +{ + create_fake_flatpak_info (g_get_user_runtime_dir (), + (GStrv)(const char* []) {"unsupported-stuff", NULL}, + "talk"); + + g_assert_true (glib_should_use_portal ()); + g_assert_false (glib_network_available_in_sandbox ()); + g_assert_true (glib_has_dconf_access_in_sandbox ()); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); + + g_test_add_func ("/portal-support/flatpak/gsettings", test_portal_support_flatpak_gsettings_only); + + return g_test_run (); +} diff --git a/gio/tests/portal-support-flatpak-network-only.c b/gio/tests/portal-support-flatpak-network-only.c new file mode 100644 index 000000000..1e4ff6df3 --- /dev/null +++ b/gio/tests/portal-support-flatpak-network-only.c @@ -0,0 +1,49 @@ +/* + * GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2022 Canonical Ltd. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * 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.1 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, see . + * + * Author: Marco Trevisan + */ + +#include "portal-support-utils.h" + +#include "../gportalsupport.h" +#include + +static void +test_portal_support_flatpak_network (void) +{ + create_fake_flatpak_info (g_get_user_runtime_dir (), + (GStrv)(const char* []) {"foo", "bar", "network", "more", NULL}, + "do-not-talk"); + + g_assert_true (glib_should_use_portal ()); + g_assert_true (glib_network_available_in_sandbox ()); + g_assert_false (glib_has_dconf_access_in_sandbox ()); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); + + g_test_add_func ("/portal-support/flatpak/network", test_portal_support_flatpak_network); + + return g_test_run (); +} diff --git a/gio/tests/portal-support-flatpak-none.c b/gio/tests/portal-support-flatpak-none.c new file mode 100644 index 000000000..7c3d8c826 --- /dev/null +++ b/gio/tests/portal-support-flatpak-none.c @@ -0,0 +1,47 @@ +/* + * GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2022 Canonical Ltd. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * 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.1 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, see . + * + * Author: Marco Trevisan + */ + +#include "portal-support-utils.h" + +#include "../gportalsupport.h" +#include + +static void +test_portal_support_flatpak_none (void) +{ + create_fake_flatpak_info (g_get_user_runtime_dir (), NULL, NULL); + + g_assert_true (glib_should_use_portal ()); + g_assert_false (glib_network_available_in_sandbox ()); + g_assert_false (glib_has_dconf_access_in_sandbox ()); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); + + g_test_add_func ("/portal-support/flatpak/none", test_portal_support_flatpak_none); + + return g_test_run (); +} diff --git a/gio/tests/portal-support-utils.c b/gio/tests/portal-support-utils.c index 9fb69287a..ae7073a3a 100644 --- a/gio/tests/portal-support-utils.c +++ b/gio/tests/portal-support-utils.c @@ -85,3 +85,57 @@ create_fake_snap_yaml (const char *snap_path, g_free (yaml_path); g_free (yaml_contents); } + +void +create_fake_flatpak_info_from_key_file (const char *root_path, + GKeyFile *key_file) +{ + GError *error = NULL; + char *key_file_path; + + g_assert_nonnull (root_path); + + key_file_path = g_build_filename (root_path, ".flatpak-info", NULL); + g_test_message ("Creating .flatpak-info in %s", key_file_path); + g_key_file_save_to_file (key_file, key_file_path, &error); + g_assert_no_error (error); + + g_free (key_file_path); +} + +void +create_fake_flatpak_info (const char *root_path, + const GStrv shared_context, + const char *dconf_dbus_policy) +{ + GKeyFile *key_file; + + key_file = g_key_file_new (); + + /* File format is defined at: + * https://docs.flatpak.org/en/latest/flatpak-command-reference.html + */ + g_key_file_set_string (key_file, "Application", "name", + "org.gnome.GLib.Test.Flatpak"); + g_key_file_set_string (key_file, "Application", "runtime", + "org.gnome.Platform/x86_64/44"); + g_key_file_set_string (key_file, "Application", "sdk", + "org.gnome.Sdk/x86_64/44"); + + if (shared_context) + { + g_key_file_set_string_list (key_file, "Context", "shared", + (const char * const *) shared_context, + g_strv_length (shared_context)); + } + + if (dconf_dbus_policy) + { + g_key_file_set_string (key_file, "Session Bus Policy", "ca.desrt.dconf", + dconf_dbus_policy); + } + + create_fake_flatpak_info_from_key_file (root_path, key_file); + + g_key_file_free (key_file); +} diff --git a/gio/tests/portal-support-utils.h b/gio/tests/portal-support-utils.h index bb5a31c6e..40c035b43 100644 --- a/gio/tests/portal-support-utils.h +++ b/gio/tests/portal-support-utils.h @@ -28,3 +28,10 @@ void create_fake_snap_yaml (const char *snap_path, void create_fake_snapctl (const char *path, const char *supported_op); + +void create_fake_flatpak_info (const char *root_path, + const GStrv shared_context, + const char *dconf_dbus_policy); + +void create_fake_flatpak_info_from_key_file (const char *root_path, + GKeyFile *key_file); diff --git a/gio/tests/sandbox.c b/gio/tests/sandbox.c index a432556dd..c0720e2df 100644 --- a/gio/tests/sandbox.c +++ b/gio/tests/sandbox.c @@ -67,6 +67,13 @@ test_sandbox_snap_classic (void) g_free (snap_path); } +static void +test_sandbox_flatpak (void) +{ + create_fake_flatpak_info (g_get_user_runtime_dir (), NULL, NULL); + g_assert_cmpint (glib_get_sandbox_type (), ==, G_SANDBOX_TYPE_FLATPAK); +} + int main (int argc, char **argv) { @@ -75,6 +82,7 @@ main (int argc, char **argv) g_test_add_func ("/sandbox/none", test_sandbox_none); g_test_add_func ("/sandbox/snap", test_sandbox_snap); g_test_add_func ("/sandbox/classic-snap", test_sandbox_snap_classic); + g_test_add_func ("/sandbox/flatpak", test_sandbox_flatpak); return g_test_run (); }