From 97411083d67339b8a6e04b19c190632519fb3b82 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 8 Oct 2024 15:56:40 +0200 Subject: [PATCH 1/4] permissions-db: Do not get unused variant value Otherwise this allocates some memory just to release it again. --- document-portal/permission-db.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/document-portal/permission-db.c b/document-portal/permission-db.c index 1fb5ad35f..0c8bd8a42 100644 --- a/document-portal/permission-db.c +++ b/document-portal/permission-db.c @@ -1144,9 +1144,7 @@ add_permissions (GVariant *app_permissions, const char *new_app_id; const char *child_app_id; - g_autoptr(GVariant) new_perms_array = NULL; - - g_variant_get (permissions, "{&s@as}", &new_app_id, &new_perms_array); + g_variant_get (permissions, "{&s@as}", &new_app_id, NULL); g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); @@ -1203,9 +1201,7 @@ remove_permissions (GVariant *app_permissions, g_variant_iter_init (&iter, app_permissions); while ((child = g_variant_iter_next_value (&iter))) { - g_autoptr(GVariant) old_perms_array = NULL; - - g_variant_get (child, "{&s@as}", &child_app_id, &old_perms_array); + g_variant_get (child, "{&s@as}", &child_app_id, NULL); if (strcmp (app, child_app_id) != 0) g_variant_builder_add_value (&builder, child); From 33d2de59a5eeae6592e3cdb98a9fdbd8bade55bc Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 8 Oct 2024 15:53:47 +0200 Subject: [PATCH 2/4] permissions-db: Specify the full GVariant type The builder has no chance to infer the type of the array entries if there are none so trying to construct empty arrays of type G_VARIANT_TYPE_ARRAY is an error. Specify the full type instead. --- document-portal/permission-db.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document-portal/permission-db.c b/document-portal/permission-db.c index 0c8bd8a42..493b35125 100644 --- a/document-portal/permission-db.c +++ b/document-portal/permission-db.c @@ -770,7 +770,7 @@ permission_db_update (PermissionDb *self) /* We should never list an app that has empty id lists */ g_assert (app_ids[0] != NULL); - g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); for (j = 0; app_ids[j] != NULL; j++) g_variant_builder_add (&builder, "s", app_ids[j]); @@ -1196,7 +1196,7 @@ remove_permissions (GVariant *app_permissions, GVariant *child; const char *child_app_id; - g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sas}")); g_variant_iter_init (&iter, app_permissions); while ((child = g_variant_iter_next_value (&iter))) From c462559eb548b6eeb2c53c923c309f3c9dc8c347 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 8 Oct 2024 16:23:07 +0200 Subject: [PATCH 3/4] Suppress asan leaks We fail CI when there are memory leaks but some of the existing leaks are not trivial to track down. This introduces a suppression file for asan which helps keep CI green while also clearly documenting leaks that we're aware of. --- tests/asan.suppression | 8 ++++++++ tests/meson.build | 1 + tests/template.test.in | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 tests/asan.suppression diff --git a/tests/asan.suppression b/tests/asan.suppression new file mode 100644 index 000000000..ac1f115fa --- /dev/null +++ b/tests/asan.suppression @@ -0,0 +1,8 @@ +# external (GIO?) +leak:g_dbus_message_new_from_blob +# Bugs in our code +# Take a look at them and try to figure out what's going on! +leak:permission_db_entry_set_app_permissions +leak:test_color_delay +leak:test_color_basic +leak:test_color_parallel diff --git a/tests/meson.build b/tests/meson.build index 078fcf6d3..797f10322 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -5,6 +5,7 @@ env_tests.set('XDP_VALIDATE_ICON', xdp_validate_icon.full_path()) env_tests.set('G_TEST_SRCDIR', meson.current_source_dir()) env_tests.set('G_TEST_BUILDDIR', meson.current_build_dir()) env_tests.set('G_DEBUG', 'gc-friendly') # from glib-tap.mk +env_tests.set('LSAN_OPTIONS', 'suppressions=' + meson.current_source_dir() / 'asan.suppression') if glib_dep.version().version_compare('>= 2.68') test_protocol = 'tap' diff --git a/tests/template.test.in b/tests/template.test.in index 01c1e1924..49c0aa997 100644 --- a/tests/template.test.in +++ b/tests/template.test.in @@ -1,4 +1,4 @@ [Test] Type=session -Exec=@installed_testdir@/@exec@ --tap +Exec=env LSAN_OPTIONS=exitcode=0 @installed_testdir@/@exec@ --tap Output=TAP From 9f6cd9e0d7bbe44bd39c975b821366466f23a8a8 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 8 Oct 2024 20:34:53 +0200 Subject: [PATCH 4/4] ci: Build image from Containerfile when tag changes This moves all workflows to a unified image which is defined in a Containerfile. The CI will create an image if one with the required tag does not exist and re-uses existing images if they do exist already. Co-authored-by: flexagoon --- .github/workflows/Containerfile | 53 +++++++++ .github/workflows/build-and-test.yml | 98 ++++++++++++++++ .github/workflows/check.yml | 166 --------------------------- .github/workflows/container.yml | 52 +++++++++ .github/workflows/pages.yml | 56 +++------ 5 files changed, 219 insertions(+), 206 deletions(-) create mode 100644 .github/workflows/Containerfile create mode 100644 .github/workflows/build-and-test.yml delete mode 100644 .github/workflows/check.yml create mode 100644 .github/workflows/container.yml diff --git a/.github/workflows/Containerfile b/.github/workflows/Containerfile new file mode 100644 index 000000000..57028297a --- /dev/null +++ b/.github/workflows/Containerfile @@ -0,0 +1,53 @@ +# This Containerfile builds the image that we use in all github workflows. +# When this file is changed, or one needs to rebuild the image for another +# reason, bump the `IMAGE_TAG` in the container.yml workflow. + +FROM ubuntu:latest + +RUN apt update +RUN apt upgrade -y + +# Install dependencies +RUN apt install -y --no-install-recommends \ + gcc clang \ + ca-certificates \ + desktop-file-utils \ + fuse3 \ + gettext \ + git \ + gnome-desktop-testing \ + gtk-doc-tools \ + libcap2-bin \ + libflatpak-dev \ + libfontconfig1-dev \ + libfuse3-dev \ + libgdk-pixbuf-2.0-dev \ + librsvg2-2 \ + librsvg2-common \ + libgeoclue-2-dev \ + libglib2.0-dev \ + libjson-glib-dev \ + libpipewire-0.3-dev \ + libsystemd-dev \ + libtool \ + llvm \ + libclang-rt-18-dev \ + python3-gi \ + shared-mime-info + +# Install meson +RUN apt install -y --no-install-recommends meson + +# Install pytest +RUN apt install -y --no-install-recommends \ + python3-pytest \ + python3-pytest-xdist \ + python3-dbusmock \ + python3-dbus + +# Install doc dependencies +RUN apt install -y --no-install-recommends \ + python3-sphinx-copybutton \ + python3-sphinxext-opengraph \ + furo \ + python3-sphinx \ No newline at end of file diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 000000000..b22753966 --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,98 @@ +name: Build and Test + +on: [push, pull_request] + +env: + TESTS_TIMEOUT: 10 # in minutes + +jobs: + build-container: + uses: ./.github/workflows/container.yml + permissions: + packages: write + + build-and-test: + name: Build and Test + runs-on: ubuntu-latest + needs: build-container + strategy: + matrix: + compiler: ['gcc', 'clang'] + sanitizer: ['address'] + + container: + image: ${{ needs.build-container.outputs.image }} + env: + CFLAGS: -Wp,-D_FORTIFY_SOURCE=2 + CC: ${{ matrix.compiler }} + TEST_IN_CI: 1 + G_MESSAGES_DEBUG: all + options: ${{ needs.build-container.outputs.image_options }} + + steps: + - name: Configure environment + run: | + git config --global --add safe.directory $GITHUB_WORKSPACE + echo XDG_DATA_DIRS=$GITHUB_WORKSPACE/tests/share:/usr/local/share:/usr/share | tee -a $GITHUB_ENV + + - name: Check out xdg-desktop-portal + uses: actions/checkout@v4 + + - name: Check out libportal fork with a similarly named branch + id: libportal-branched + uses: actions/checkout@v4 + continue-on-error: true + with: + repository: ${{ github.actor }}/libportal + ref: ${{ github.head_ref || github.ref_name }} + path: libportal + + - name: Check out libportal default branch + if: steps.libportal-branched.outcome == 'failure' + uses: actions/checkout@v4 + with: + repository: flatpak/libportal + path: libportal + + - name: Build libportal + run: | + meson setup libportal _build_libportal $MESON_OPTIONS + meson compile -C _build_libportal + meson install -C _build_libportal + env: + MESON_OPTIONS: --prefix=/usr -Ddocs=false -Dintrospection=false -Dtests=false + + - name: Build xdg-desktop-portal + run: | + meson setup _build $MESON_OPTIONS + meson compile -C _build + env: + MESON_OPTIONS: -Dinstalled-tests=true -Dpytest=enabled -Db_sanitize=${{ matrix.sanitizer }} + + - name: Run xdg-desktop-portal tests + run: timeout --signal=KILL -v ${TESTS_TIMEOUT}m meson test -C _build + + - name: Install xdg-desktop-portal + run: meson install -C _build + + - name: Run xdg-desktop-portal installed-tests + run: | + test -n "$(gnome-desktop-testing-runner -l xdg-desktop-portal)" + gnome-desktop-testing-runner --report-directory installed-test-logs/ \ + -t $((TESTS_TIMEOUT * 60)) xdg-desktop-portal + + - name: Create dist tarball + run: | + ls -la + timeout --signal=KILL -v ${TESTS_TIMEOUT}m meson dist -C _build + + - name: Upload test logs + uses: actions/upload-artifact@v4 + if: success() || failure() + with: + name: test logs (${{ matrix.compiler }}, ${{ matrix.sanitizer }}) + path: | + tests/*.log + test-*.log + installed-test-logs/ + _build/meson-logs/testlog.txt diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml deleted file mode 100644 index 13946dbfd..000000000 --- a/.github/workflows/check.yml +++ /dev/null @@ -1,166 +0,0 @@ -name: Portal CI - -on: [push, pull_request] - -env: - DEBIAN_FRONTEND: noninteractive - TESTS_TIMEOUT: 10 # in minutes - -jobs: - check: - name: Ubuntu 22.04 build - runs-on: ubuntu-22.04 - strategy: - matrix: - compiler: ['gcc', 'clang'] - sanitizer: ['address'] - - env: - UBUNTU_VERSION: '22.04' - CC: ${{ matrix.compiler }} - BASE_CFLAGS: -Wp,-D_FORTIFY_SOURCE=2 - BUILD_CONTAINER: ${{ matrix.compiler }}-build-container - RUN_CMD: docker exec -t -w /src -e TEST_IN_CI -e ASAN_OPTIONS -e G_MESSAGES_DEBUG -e XDG_DATA_DIRS ${{ matrix.compiler }}-build-container - AS_USER: runuser -u tester -- - BUILDDIR: builddir - - steps: - - name: Prepare environment - id: env-setup - run: | - echo "cflags=$BASE_CFLAGS" >> $GITHUB_OUTPUT; - - - name: Prepare container - run: | - docker run --name $BUILD_CONTAINER \ - --tty --device /dev/fuse --cap-add SYS_ADMIN \ - --security-opt apparmor:unconfined \ - --privileged \ - -v $(pwd):/src \ - -e DEBIAN_FRONTEND \ - -e DEBCONF_NONINTERACTIVE_SEEN=true \ - -e TERM=dumb \ - -e MAKEFLAGS="-j $(getconf _NPROCESSORS_ONLN)" \ - -e CC -e CFLAGS="${{ steps.env-setup.outputs.cflags }}" \ - -e LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib64 \ - -e PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig \ - -d ubuntu:$UBUNTU_VERSION sleep infinity - - - name: Install dependencies - run: | - $RUN_CMD apt-get update --quiet - $RUN_CMD apt-get upgrade --quiet -y - $RUN_CMD apt-get install --quiet -y --no-install-recommends \ - ${{ matrix.compiler }} \ - desktop-file-utils \ - fuse3 \ - gettext \ - git \ - gnome-desktop-testing \ - gtk-doc-tools \ - libcap2-bin \ - libflatpak-dev \ - libfontconfig1-dev \ - libfuse3-dev \ - libgdk-pixbuf-2.0-dev \ - librsvg2-2 \ - librsvg2-common \ - libgeoclue-2-dev \ - libglib2.0-dev \ - libjson-glib-dev \ - libpipewire-0.3-dev \ - libsystemd-dev \ - libtool \ - llvm \ - python3-gi \ - shared-mime-info - - - name: Install dependencies for meson - run: | - $RUN_CMD apt-get install --quiet -y --no-install-recommends \ - meson - - - name: Install dependencies for the pytest test suite - run: | - $RUN_CMD apt-get install --quiet -y --no-install-recommends \ - python3-pytest python3-pytest-xdist python3-dbusmock python3-dbus - - - name: Check out xdg-desktop-portal - uses: actions/checkout@v4 - - - name: Check out libportal fork with a similarly named branch - id: libportal-branched - uses: actions/checkout@v4 - continue-on-error: true - with: - repository: ${{ github.actor }}/libportal - ref: ${{ github.head_ref || github.ref_name }} - path: libportal - - - name: Check out libportal default branch - if: steps.libportal-branched.outcome == 'failure' - uses: actions/checkout@v4 - with: - repository: flatpak/libportal - path: libportal - - - name: Setup test user - run: | - $RUN_CMD adduser --disabled-password --gecos "" tester - $RUN_CMD chown tester:tester . -R - - - name: Build libportal - run: | - $RUN_CMD $AS_USER meson setup libportal ${LIBPORTAL_BUILDDIR} $MESON_OPTIONS - $RUN_CMD $AS_USER meson compile -C ${LIBPORTAL_BUILDDIR} - $RUN_CMD meson install -C ${LIBPORTAL_BUILDDIR} - env: - MESON_OPTIONS: -Ddocs=false -Dintrospection=false -Dtests=false - LIBPORTAL_BUILDDIR: libportal_builddir - - - name: Build xdg-desktop-portal - run: | - $RUN_CMD $AS_USER meson setup ${BUILDDIR} $MESON_OPTIONS - $RUN_CMD $AS_USER meson compile -C ${BUILDDIR} - env: - MESON_OPTIONS: -Dinstalled-tests=true -Dpytest=enabled -Db_sanitize=${{ matrix.sanitizer }} - - - name: Run xdg-desktop-portal tests - run: $RUN_CMD $AS_USER timeout --signal=KILL -v ${TESTS_TIMEOUT}m meson test -C ${BUILDDIR} - env: - TEST_IN_CI: 1 - G_MESSAGES_DEBUG: all - - - name: Install xdg-desktop-portal - run: $RUN_CMD meson install -C ${BUILDDIR} - - - name: Run xdg-desktop-portal installed-tests - run: | - test -n "$($RUN_CMD $AS_USER gnome-desktop-testing-runner -l xdg-desktop-portal)" - $RUN_CMD $AS_USER \ - env TEST_INSTALLED_IN_CI=1 XDG_DATA_DIRS=/src/tests/share/:$XDG_DATA_DIRS \ - gnome-desktop-testing-runner --report-directory installed-test-logs/ \ - -t $((TESTS_TIMEOUT * 60)) xdg-desktop-portal - env: - G_MESSAGES_DEBUG: all - TEST_IN_CI: 1 - XDG_DATA_DIRS: /usr/local/share:/usr/share - - - name: Create dist tarball - run: | - $RUN_CMD $AS_USER ls -la - $RUN_CMD $AS_USER timeout --signal=KILL -v ${TESTS_TIMEOUT}m meson dist -C ${BUILDDIR} - env: - TEST_IN_CI: 1 - G_MESSAGES_DEBUG: all - - - name: Upload test logs - uses: actions/upload-artifact@v3 - if: success() || failure() - with: - name: test logs - path: | - tests/*.log - test-*.log - installed-test-logs/ - builddir/meson-logs/testlog.txt diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml new file mode 100644 index 000000000..d5d04ec53 --- /dev/null +++ b/.github/workflows/container.yml @@ -0,0 +1,52 @@ +name: Create build container + +env: + IMAGE_TAG: 20241008-1 + +on: + workflow_call: + outputs: + image: + description: "The build image" + value: ${{ jobs.build-container.outputs.image }} + image_options: + description: "The options to use with the image" + value: --device /dev/fuse --cap-add SYS_ADMIN --security-opt apparmor:unconfined --privileged + +jobs: + build-container: + name: Create build container + runs-on: ubuntu-latest + + outputs: + image: ${{ steps.check.outputs.image }} + + steps: + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ github.token }} + + - name: Set lower case owner name + env: + OWNER: '${{ github.repository_owner }}' + run: | + echo "OWNER_LOWERCASE=${OWNER,,}" >>${GITHUB_ENV} + + - name: Check if image already exists on GHCR + id: check + run: | + image=ghcr.io/${{ env.OWNER_LOWERCASE }}/xdg-desktop-portal:${{ env.IMAGE_TAG }} + echo "exists=$(docker manifest inspect $image >/dev/null && echo 'true' || echo 'false')" \ + >> "$GITHUB_OUTPUT" + echo "image=$image" >> "$GITHUB_OUTPUT" + + - name: Build and push + if: ${{ steps.check.outputs.exists == 'false' }} + uses: docker/build-push-action@v5 + with: + push: true + file: .github/workflows/Containerfile + tags: ghcr.io/${{ env.OWNER_LOWERCASE }}/xdg-desktop-portal:${{ env.IMAGE_TAG }} diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 31c1c2140..26c561909 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -12,47 +12,22 @@ concurrency: cancel-in-progress: false jobs: + build-container: + uses: ./.github/workflows/container.yml + permissions: + packages: write + build: - runs-on: ubuntu-20.04 - container: - image: fedora:latest - steps: - - name: Install dependencies - run: | - dnf install -y \ - desktop-file-utils \ - flatpak-devel \ - fontconfig-devel \ - fuse3 \ - fuse3-devel \ - gcc \ - gdk-pixbuf2-devel \ - geoclue2-devel \ - gettext \ - glib2-devel \ - gnome-desktop-testing \ - gtk-doc \ - json-glib-devel \ - libcap \ - libcap-devel \ - libportal-devel \ - llvm \ - meson \ - pipewire-devel \ - python3-gobject \ - shared-mime-info \ - systemd-devel + runs-on: ubuntu-latest + needs: build-container + permissions: + contents: write - - name: Install dependencies for doc builds - run: | - dnf install -y \ - ca-certificates \ - git \ - python-sphinx-copybutton \ - python-sphinxext-opengraph \ - python3-furo \ - python3-sphinx + container: + image: ${{ needs.build-container.outputs.image }} + options: ${{ needs.build-container.outputs.image_options }} + steps: - name: Check out xdg-desktop-portal uses: actions/checkout@v4 @@ -77,12 +52,13 @@ jobs: # Deployment job deploy: + runs-on: ubuntu-latest + needs: build environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build if: ${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') }} + steps: - name: Deploy to GitHub Pages id: deployment