ci(flatpak): spike how far Flathub actually is - #347
Conversation
Flathub forbids the route every other channel here takes: "All source available submissions must be built entirely from source code. This requirement applies to the main application component defined in the manifest, as well as any runtime dependencies included in the manifest." OpenScreen is MIT, so repackaging the .deb is out, and extra-data is out too — it exists for non-redistributable sources, and upstream authorship implies the redistribution right. That turns the remaining #335 item from "write a manifest" into a port, and the expensive unknown is ffmpeg. scripts/fetch-ffmpeg.mjs pins a BtbN *prebuilt* shared tree, which Flathub rejects on the same rule, and the tree is not merely convenient: build-linux-compositor-addon.mjs renames every ffmpeg dynamic symbol in the libraries it ships, because Electron links Chromium's own stripped libffmpeg.so into the same process and the addon would otherwise bind to that. It needs headers and libraries it owns, so the runtime's ffmpeg-full extension — libraries, no headers — cannot stand in either. So this is a spike, not a submission. The manifest is built by a dispatch-only workflow whose stages all continue on error, because a spike that stops at the first failure reports one fact and this one reports six: whether the guessed runtime, base and node extension versions exist at all, whether flatpak-node-generator can digest this lockfile, whether both Cargo.locks vendor, and where the build actually dies. The verdict lands in the run summary rather than the log. The ffmpeg sha256 in the manifest is deliberately all zeroes. The pinned build is a BtbN snapshot (n8.1.2-34-g9b6c8969e0), not an upstream release, so there is no honest digest to write yet — stage E resolves what upstream actually publishes and the mismatch is itself a finding.
📝 WalkthroughWalkthroughThis change adds an OpenScreen Flatpak manifest and a manually dispatched GitHub Actions workflow. The workflow checks Flathub components, prepares offline dependencies, resolves FFmpeg, runs ChangesFlatpak packaging
Estimated code review effort: 3 (Moderate) | ~30 minutes Sequence Diagram(s)sequenceDiagram
participant Developer
participant GitHubActions as GitHub Actions
participant Flathub
participant DependencyTools as flatpak-builder-tools
participant FlatpakBuilder as flatpak-builder
participant Artifacts as Artifact storage
Developer->>GitHubActions: Manually dispatch Flatpak spike
GitHubActions->>Flathub: Check runtime, SDK, BaseApp, Node, and Rust branches
GitHubActions->>Flathub: Install required Flatpak components
GitHubActions->>DependencyTools: Generate offline npm sources
GitHubActions->>GitHubActions: Vendor Rust dependencies and resolve FFmpeg digest
GitHubActions->>FlatpakBuilder: Build OpenScreen from manifest
GitHubActions->>Artifacts: Upload build log and generated npm sources
GitHubActions->>Developer: Write stage verdict and metadata
Possibly related issues
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/flatpak-spike.yml:
- Around line 66-72: Update the remote query handling around FOUND in the Stage
A workflow: capture the exit status of flatpak remote-ls without allowing ||
true to hide failures, report “QUERY FAILED” to GITHUB_STEP_SUMMARY when the
query fails, and make Stage A fail. Preserve the existing branches and “NOT
PUBLISHED” reporting only for successful queries.
- Around line 97-99: Update the Stage C source-generation step to clone the
maintained flatpak-builder-tools repository from
https://github.com/flatpak/flatpak-builder-tools.git at a pinned commit, install
its node project, and invoke the documented flatpak-node-generator entry point
instead of the nonexistent /tmp/fbt/node script.
In `@build/flatpak/com.getopenscreen.OpenScreen.yml`:
- Around line 112-114: Update the Flatpak manifest sources and build setup to
include both vendored Cargo trees and their generated Cargo configuration files,
then install the matching source-replacement configuration into Cargo’s expected
location before the native build commands. Ensure npm run build:native:linux and
npm run build:native:compositor:linux use these vendored sources without network
access.
- Around line 112-120: Update the Flatpak build commands after electron-builder
runs: copy the bundle from release/1.9.2/linux-unpacked into /app/main, install
/app/bin/openscreen to invoke the bundled executable through zypak-wrapper.sh,
and provide Electron’s binary in electron_config_cache so npm ci --offline can
complete without downloading it.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 71763018-f95e-4ff6-b5db-9e0200489c23
📒 Files selected for processing (2)
.github/workflows/flatpak-spike.ymlbuild/flatpak/com.getopenscreen.OpenScreen.yml
Stage C cloned `flathub-infra/flatpak-builder-tools`, which is a 404, and then invoked `node/flatpak-node-generator.py`, which is not how that tool ships — `node/` is a poetry project exposing a `flatpak-node-generator` console script. Two mistakes stacked on the one stage the spike exists for: whether this lockfile can be turned into offline sources at all. It would have failed for reasons that say nothing about the port. Cloned from `flatpak/`, pinned to 737c008, installed into a venv, so the answer is about the lockfile and stays comparable between runs. Stage A queried the remote once per id behind `|| true`, so a broken remote reported six lines of "NOT PUBLISHED" — the single wrong answer that stage can give, since it reads as "Flathub does not ship the runtime" when it means the question never got asked. One query, status kept, and an explicit QUERY FAILED that draws no conclusion. Both found by CodeRabbit on #347.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/flatpak-spike.yml (1)
157-157: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winReport download failures separately from a missing release.
At
.github/workflows/flatpak-spike.yml:152-157,curl -fsSLuses the same branch for HTTP errors and transport or TLS failures. Capture the HTTP status and curl exit status separately. Emit the snapshot warning only for HTTP 404 or 410. Report other failures as download failures.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/flatpak-spike.yml at line 157, Update the URL validation logic around the curl invocation in the workflow to capture HTTP status and curl exit status independently. Emit the existing snapshot warning only when the HTTP status is 404 or 410; report transport, TLS, and other curl failures as download failures, while preserving successful-download handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/flatpak-spike.yml:
- Line 62: Update the Stage A catalog query and filtering around CATALOG to
include application, branch, and architecture columns, and only mark entries
available when the branch is 24.08 and architecture is x86_64. Preserve the
existing application availability handling for matching entries.
---
Outside diff comments:
In @.github/workflows/flatpak-spike.yml:
- Line 157: Update the URL validation logic around the curl invocation in the
workflow to capture HTTP status and curl exit status independently. Emit the
existing snapshot warning only when the HTTP status is 404 or 410; report
transport, TLS, and other curl failures as download failures, while preserving
successful-download handling.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 7d44743c-49e4-49cb-b504-8e6b90d82b38
📒 Files selected for processing (1)
.github/workflows/flatpak-spike.yml
| # turn a broken remote into six "NOT PUBLISHED" lines, which is the one | ||
| # wrong answer this stage must never give: it would read as "Flathub does | ||
| # not ship the runtime" when it means "the question never got asked". | ||
| if ! CATALOG=$(flatpak remote-ls flathub --user --columns=application,branch 2>&1); then |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
catalog="$(flatpak remote-ls flathub --user \
--columns=application,branch,arch)"
for id in \
org.freedesktop.Platform \
org.freedesktop.Sdk \
org.electronjs.Electron2.BaseApp \
org.freedesktop.Sdk.Extension.node22 \
org.freedesktop.Sdk.Extension.node20 \
org.freedesktop.Sdk.Extension.rust-stable
do
awk -v id="$id" \
'$1 == id && $2 == "24.08" && $3 == "x86_64" { found = 1 }
END { exit !found }' <<<"$catalog"
doneRepository: getopenscreen/openscreen
Length of output: 207
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
file=".github/workflows/flatpak-spike.yml"
printf '%s\n' '--- relevant workflow lines ---'
sed -n '1,120p' "$file"
printf '%s\n' '--- related references ---'
rg -n -C 3 'remote-ls|flatpak install|24\.08|x86_64|branch|arch|FOUND|CATALOG' "$file"Repository: getopenscreen/openscreen
Length of output: 8156
🌐 Web query:
Flatpak command reference remote-ls --columns application branch arch output
💡 Result:
The --columns option for the flatpak remote-ls command allows you to specify which information fields are displayed for each reference found in a remote repository [1][2]. Usage: --columns=FIELD,... You can provide a comma-separated list of fields or use the --columns option multiple times to add specific fields to the output [2]. Available fields include: name: Shows the application or runtime name [2]. description: Shows the description of the application [2]. application: Shows the application or runtime ID [2]. arch: Shows the architecture [2]. branch: Shows the branch [2]. version: Shows the version [2]. ref: Shows the full reference string [2]. origin: Shows the origin remote [2]. commit: Shows the active commit [2]. runtime: Shows the runtime used by the application [2]. installed-size: Shows the installed size [2]. download-size: Shows the download size [2]. options: Shows options associated with the ref [2]. all: Displays all available columns [1][2]. help: Lists all valid field names [2]. Additional notes: - You can abbreviate field names to their unique prefix (e.g., --columns=app for application) [1][2]. - You can change the ellipsization behavior for a column by appending:s (start),:m (middle),:e (end), or:f (full) to the field name (e.g., --columns=application:f) [2]. - For example, running flatpak remote-ls --columns=application,branch,arch will output only the application ID, branch, and architecture for the refs found [2].
Citations:
- 1: https://manpages.debian.org/bookworm/flatpak/flatpak-remote-ls.1.en.html
- 2: https://man7.org/linux/man-pages/man1/flatpak-remote-ls.1.html
Restrict Stage A to the Stage B ref.
Stage B installs x86_64/24.08, but Stage A accepts any branch and architecture. Query application,branch,arch and require $2 == "24.08" and $3 == "x86_64" before marking the application as available.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/flatpak-spike.yml at line 62, Update the Stage A catalog
query and filtering around CATALOG to include application, branch, and
architecture columns, and only mark entries available when the branch is 24.08
and architecture is x86_64. Preserve the existing application availability
handling for matching entries.
Stage C cloned `flathub-infra/flatpak-builder-tools`, which is a 404, and then invoked `node/flatpak-node-generator.py`, which is not how that tool ships — `node/` is a poetry project exposing a `flatpak-node-generator` console script. Two mistakes stacked on the one stage the spike exists for: whether this lockfile can be turned into offline sources at all. It would have failed for reasons that say nothing about the port. Cloned from `flatpak/`, pinned to 737c008, installed into a venv, so the answer is about the lockfile and stays comparable between runs. Stage A queried the remote once per id behind `|| true`, so a broken remote reported six lines of "NOT PUBLISHED" — the single wrong answer that stage can give, since it reads as "Flathub does not ship the runtime" when it means the question never got asked. One query, status kept, and an explicit QUERY FAILED that draws no conclusion. Both found by CodeRabbit on #347.
Run 31575509206 got ffmpeg compiled and then died in `npm ci --offline` with ENOTCACHED on zustand. Not an npm problem: the cache paths were invented. The upstream Electron manifest documents them, and they are positional — flatpak-node-generator lays its output out under `flatpak-node/` in the module build dir, so both variables have to name that exact path: XDG_CACHE_HOME: /run/build/openscreen/flatpak-node/cache npm_config_cache: /run/build/openscreen/flatpak-node/npm-cache XDG_CACHE_HOME looked like a nicety and is not: it is where the Electron binary download is cached, so without it electron's postinstall reaches for the network that the sandbox does not have. Cargo gets the same treatment — CARGO_HOME must be the path flatpak-cargo-generator hardcodes, since it writes its replace-with config there and vendors into $CARGO_HOME/vendor. Stage D now emits real source lists for both lockfiles instead of only proving they resolve, and it counts the destinations the two share, because the generator has no way to separate their vendor directories and crates common to both trees land on the same path twice. Better reported than discovered inside flatpak-builder. Electron needs a zypak wrapper or it fails on the SUID sandbox helper, so there is a launcher script and `command:` finally resolves to something. Also here: a desktop file named after the app id, icons renamed on the way in because Flatpak only exports app-id-named ones, and the metainfo launchable rewritten at install time — that file's own comment already said a Flatpak build would have to, and now something does. Rewritten rather than edited, so it stays correct for the deb, and the rewrite fails loudly if it ever stops matching. The git source is a `type: dir` for now. It cannot be the tag Flathub wants: v1.9.2 predates both the metainfo and the desktop file, so a tagged build would fail on files that do not exist in it. Stage E is deleted. It resolved a digest that is now pinned in the manifest, and its only other act was to report "does not exist" for a connection reset — the same conflation of a broken query with a negative answer that the review of #347 corrected in Stage A.
Refs #335.
Why a spike and not a manifest
Flathub forbids the route every other channel in this repository takes:
OpenScreen is MIT, so it is source-available, so repackaging the
.debis out.extra-datais out on the same reading — it exists for non-redistributable sources, and a submission from the upstream author carries the redistribution right implicitly, so there are no grounds to use it.That turns the last open item on #335 from "write a manifest" into a port, and the expensive unknown is ffmpeg:
scripts/fetch-ffmpeg.mjspins a BtbN prebuilt shared tree, rejected by the same rule.scripts/build-linux-compositor-addon.mjsrenames every ffmpeg dynamic symbol in the libraries it ships, because Electron links Chromium's own strippedlibffmpeg.sointo the same address space and the addon would otherwise bind to it. It needs headers and libraries it owns.org.freedesktop.Platform.ffmpeg-fullas a substitute: libraries, no dev headers.So ffmpeg has to be built from source inside the manifest, and whether that reproduces the tree the addon was tested against is exactly what nobody knows yet.
What this PR is
A dispatch-only workflow that builds a deliberately provisional manifest and reports where it dies. Every stage is
continue-on-error, because a spike that stops at the first failure reports one fact and this one reports six:node22even exist at these versions?flatpak-node-generatordigest thispackage-lock.json?Cargo.lockfiles vendor?n8.1.2-34-g9b6c8969e0) and not a release?flatpak-builderstop?The verdict lands in the run summary, not the log. Stage F failing is the expected result, not the finding — A–E are what decide whether this port is a week or a quarter.
The manifest's ffmpeg
sha256is deliberately all zeroes: the pin is a snapshot, so there is no honest digest to write, and stage E resolves what upstream really ships. A guessed digest must never reach a submission.Notes
workflow_dispatchonly, no event trigger.mainto be dispatchable at all — that is the only reason this is a PR rather than a branch.bash -n.Summary by CodeRabbit
New Features
Chores