feat: Flatpak packaging for the HeiniRemote agent
Build and Publish HeiniRemote Agent Flatpak / build (push) Failing after 4m52s
Build and Publish HeiniRemote Agent Flatpak / build (push) Failing after 4m52s
Bundles the agent as de.pc_heini.HeiniRemoteAgent on the freedesktop 24.08 runtime, mirroring the o3de-flatpak CI approach (bwrap-free build, OSTree repo force-pushed to pages, single-file bundle attached to a Gitea release). Compiles the agent from upstream source (newest v* tag, else main). Sandbox notes: screen capture/input via portals need no special permission; the PTY console uses flatpak-spawn --host for a real host shell, and a native install's agent.toml is adopted read-only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
commit
801db2871b
11 files changed
+486
No files matched your search
@@ -0,0 +1,192 @@
|
|||||||
|
name: Build and Publish HeiniRemote Agent Flatpak
|
||||||
|
|
||||||
|
on:
|
||||||
|
# New upstream release: the daily check rebuilds when HeiniRemote has a
|
||||||
|
# version (tag or main commit) with no matching tag here yet.
|
||||||
|
schedule:
|
||||||
|
- cron: '0 3 * * *' # daily at 03:00
|
||||||
|
# Code change: rebuild whenever the packaging itself changes. Scoped to
|
||||||
|
# `main` on purpose — the job force-pushes the `pages` branch and creates
|
||||||
|
# tags, and those must NOT re-trigger it (that would loop).
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths-ignore:
|
||||||
|
- 'README.md'
|
||||||
|
- 'docs/**'
|
||||||
|
- 'LICENSE*'
|
||||||
|
- '.gitignore'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
force:
|
||||||
|
description: 'Rebuild even if this version was already published'
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
# ubuntu:24.04 matches the freedesktop 24.08 runtime closely enough
|
||||||
|
# (glibc 2.39, GStreamer 1.24) that the cargo-built binary runs
|
||||||
|
# unmodified inside the runtime. Privileged so Flatpak's bwrap works
|
||||||
|
# where needed (runtime install triggers).
|
||||||
|
image: ubuntu:24.04
|
||||||
|
options: --privileged
|
||||||
|
steps:
|
||||||
|
- name: Install build dependencies
|
||||||
|
run: |
|
||||||
|
apt-get update
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
|
ca-certificates curl git jq flatpak wl-clipboard \
|
||||||
|
build-essential pkg-config \
|
||||||
|
libglib2.0-dev libdbus-1-dev libxkbcommon-dev \
|
||||||
|
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
|
||||||
|
libgstreamer-plugins-bad1.0-dev \
|
||||||
|
libpipewire-0.3-dev
|
||||||
|
|
||||||
|
# Plain git clone instead of actions/checkout@v4: the bare ubuntu image
|
||||||
|
# has no Node.js, so JavaScript actions fail with exit 127.
|
||||||
|
- name: Checkout
|
||||||
|
env:
|
||||||
|
TOKEN: ${{ secrets.PUBLISH_TOKEN != '' && secrets.PUBLISH_TOKEN || secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
AUTH_URL="$(echo "${GITHUB_SERVER_URL}" | sed "s#://#://${GITHUB_ACTOR}:${TOKEN}@#")/${GITHUB_REPOSITORY}.git"
|
||||||
|
git init -q
|
||||||
|
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||||
|
git remote add origin "$AUTH_URL"
|
||||||
|
git fetch -q --depth 1 origin "${GITHUB_SHA:-$GITHUB_REF_NAME}"
|
||||||
|
git checkout -q FETCH_HEAD
|
||||||
|
|
||||||
|
- name: Resolve upstream HeiniRemote version
|
||||||
|
id: ver
|
||||||
|
env:
|
||||||
|
TOKEN: ${{ secrets.PUBLISH_TOKEN != '' && secrets.PUBLISH_TOKEN || secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
chmod +x scripts/*.sh
|
||||||
|
export UPSTREAM_URL="$(echo "${GITHUB_SERVER_URL}" | sed "s#://#://${GITHUB_ACTOR}:${TOKEN}@#")/pc-heini/HeiniRemote.git"
|
||||||
|
eval "$(scripts/get-latest-version.sh)"
|
||||||
|
{
|
||||||
|
echo "version=$version"
|
||||||
|
echo "ref=$ref"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Packaging HeiniRemote $version (ref $ref)"
|
||||||
|
|
||||||
|
- name: Decide whether to build
|
||||||
|
id: check
|
||||||
|
run: |
|
||||||
|
# A code push (or a manual force) rebuilds even if this version is
|
||||||
|
# already published — the point is to test the changed packaging.
|
||||||
|
if [ "${{ inputs.force }}" = "true" ] || [ "${{ github.event_name }}" = "push" ]; then
|
||||||
|
echo "build=true" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Rebuild requested (${{ github.event_name }})."
|
||||||
|
elif git ls-remote --tags origin "refs/tags/v${{ steps.ver.outputs.version }}" | grep -q .; then
|
||||||
|
echo "build=false" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "v${{ steps.ver.outputs.version }} already published — nothing to do."
|
||||||
|
else
|
||||||
|
echo "build=true" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "New version v${{ steps.ver.outputs.version }} — building."
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Install Rust
|
||||||
|
if: steps.check.outputs.build == 'true'
|
||||||
|
run: |
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal
|
||||||
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
||||||
|
|
||||||
|
- name: Build agent from upstream source
|
||||||
|
if: steps.check.outputs.build == 'true'
|
||||||
|
env:
|
||||||
|
TOKEN: ${{ secrets.PUBLISH_TOKEN != '' && secrets.PUBLISH_TOKEN || secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
UPSTREAM_URL="$(echo "${GITHUB_SERVER_URL}" | sed "s#://#://${GITHUB_ACTOR}:${TOKEN}@#")/pc-heini/HeiniRemote.git"
|
||||||
|
# init+fetch instead of clone: works for tags and bare commit shas alike.
|
||||||
|
rm -rf upstream && git init -q upstream
|
||||||
|
git -C upstream remote add origin "$UPSTREAM_URL"
|
||||||
|
git -C upstream fetch -q --depth 1 origin "${{ steps.ver.outputs.ref }}"
|
||||||
|
git -C upstream checkout -q FETCH_HEAD
|
||||||
|
cargo build --release -p heiniremote-agent --manifest-path upstream/Cargo.toml
|
||||||
|
|
||||||
|
- name: Install Flatpak runtime and SDK
|
||||||
|
if: steps.check.outputs.build == 'true'
|
||||||
|
run: |
|
||||||
|
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||||
|
flatpak install -y flathub org.freedesktop.Platform//24.08 org.freedesktop.Sdk//24.08
|
||||||
|
|
||||||
|
- name: Stamp version into AppStream metadata
|
||||||
|
if: steps.check.outputs.build == 'true'
|
||||||
|
run: |
|
||||||
|
sed -i -E \
|
||||||
|
"s#<release version=\"[^\"]*\" date=\"[^\"]*\"/>#<release version=\"${{ steps.ver.outputs.version }}\" date=\"$(date +%F)\"/>#" \
|
||||||
|
de.pc_heini.HeiniRemoteAgent.metainfo.xml
|
||||||
|
|
||||||
|
- name: Build Flatpak into OSTree repo
|
||||||
|
if: steps.check.outputs.build == 'true'
|
||||||
|
run: |
|
||||||
|
AGENT_BIN=upstream/target/release/heiniremote-agent scripts/make-flatpak.sh
|
||||||
|
# Single-file bundle for direct installs without adding the remote.
|
||||||
|
mkdir -p dist
|
||||||
|
flatpak build-bundle repo \
|
||||||
|
"dist/heiniremote-agent-${{ steps.ver.outputs.version }}.flatpak" \
|
||||||
|
de.pc_heini.HeiniRemoteAgent stable
|
||||||
|
# Free disk before publishing (repo/ + dist/ are all we still need).
|
||||||
|
rm -rf build-dir upstream
|
||||||
|
|
||||||
|
- name: Generate .flatpakrepo
|
||||||
|
if: steps.check.outputs.build == 'true'
|
||||||
|
run: |
|
||||||
|
BASE="${{ github.server_url }}/${{ github.repository }}/raw/branch/pages"
|
||||||
|
cat > repo/heiniremote.flatpakrepo <<EOF
|
||||||
|
[Flatpak Repo]
|
||||||
|
Title=HeiniRemote Agent
|
||||||
|
Url=$BASE
|
||||||
|
Homepage=https://pc-heini.de/
|
||||||
|
Comment=HeiniRemote remote maintenance agent as a Flatpak
|
||||||
|
Description=Install the HeiniRemote agent on any Linux distribution via Flatpak.
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Publish OSTree repo to the 'pages' branch
|
||||||
|
if: steps.check.outputs.build == 'true'
|
||||||
|
env:
|
||||||
|
TOKEN: ${{ secrets.PUBLISH_TOKEN != '' && secrets.PUBLISH_TOKEN || secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
AUTH_URL="$(echo "${{ github.server_url }}" | sed "s#://#://${{ github.actor }}:${TOKEN}@#")/${{ github.repository }}.git"
|
||||||
|
rm -rf publish && mkdir publish && cd publish
|
||||||
|
git init -q -b pages
|
||||||
|
git config user.name "Gitea Actions"
|
||||||
|
git config user.email "actions@pc-heini.de"
|
||||||
|
cp -a ../repo/. .
|
||||||
|
touch .nojekyll
|
||||||
|
git add -A
|
||||||
|
git commit -q -m "HeiniRemote Agent Flatpak v${{ steps.ver.outputs.version }}"
|
||||||
|
# Force-push a single snapshot so the pages branch never accumulates history.
|
||||||
|
git push -f "$AUTH_URL" pages
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
- name: Tag and release the published version
|
||||||
|
if: steps.check.outputs.build == 'true'
|
||||||
|
env:
|
||||||
|
TOKEN: ${{ secrets.PUBLISH_TOKEN != '' && secrets.PUBLISH_TOKEN || secrets.GITHUB_TOKEN }}
|
||||||
|
GITEA_API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
|
||||||
|
run: |
|
||||||
|
AUTH_URL="$(echo "${{ github.server_url }}" | sed "s#://#://${{ github.actor }}:${TOKEN}@#")/${{ github.repository }}.git"
|
||||||
|
TAG="v${{ steps.ver.outputs.version }}"
|
||||||
|
if git ls-remote --tags "$AUTH_URL" "refs/tags/$TAG" | grep -q .; then
|
||||||
|
echo "Tag $TAG already exists (force rebuild) — leaving it in place."
|
||||||
|
else
|
||||||
|
git tag "$TAG"
|
||||||
|
git push "$AUTH_URL" "$TAG"
|
||||||
|
fi
|
||||||
|
# Attach the single-file bundle to a Gitea release for direct download.
|
||||||
|
curl -fsS -X POST "$GITEA_API/releases" \
|
||||||
|
-H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
|
||||||
|
-d "{\"tag_name\":\"$TAG\",\"name\":\"$TAG\"}" || true
|
||||||
|
RELEASE_ID=$(curl -fsS "$GITEA_API/releases/tags/$TAG" \
|
||||||
|
-H "Authorization: token $TOKEN" | jq -r '.id')
|
||||||
|
f="dist/heiniremote-agent-${{ steps.ver.outputs.version }}.flatpak"
|
||||||
|
curl -fsS -X POST "$GITEA_API/releases/$RELEASE_ID/assets?name=$(basename "$f")" \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
-F "attachment=@$f" >/dev/null || echo "Asset already attached."
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
build-dir/
|
||||||
|
repo/
|
||||||
|
publish/
|
||||||
|
upstream/
|
||||||
|
dist/
|
||||||
|
*.flatpak
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
# heiniremote-flatpak
|
||||||
|
|
||||||
|
Flatpak packaging for the [HeiniRemote](https://git.pc-heini.de/pc-heini/HeiniRemote)
|
||||||
|
customer agent (`de.pc_heini.HeiniRemoteAgent`) — an additional distribution
|
||||||
|
channel next to the plain release binary, with all dependencies (GStreamer,
|
||||||
|
libnice, wl-clipboard, …) pinned inside the freedesktop 24.08 runtime.
|
||||||
|
|
||||||
|
Same setup as [o3de-flatpak](https://git.pc-heini.de/pc-heini/o3de-flatpak):
|
||||||
|
a Gitea Action builds the Flatpak **without** `flatpak-builder` (no bubblewrap
|
||||||
|
needed in CI), exports it into an OSTree repo and force-pushes that to the
|
||||||
|
`pages` branch. The difference: the agent is compiled from upstream source
|
||||||
|
(newest `v*` tag, falling back to `main` while no release exists) instead of
|
||||||
|
repackaging a prebuilt archive.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
From the Flatpak remote (gets updates via `flatpak update`):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
flatpak remote-add --if-not-exists heiniremote \
|
||||||
|
https://git.pc-heini.de/pc-heini/heiniremote-flatpak/raw/branch/pages/heiniremote.flatpakrepo
|
||||||
|
flatpak install heiniremote de.pc_heini.HeiniRemoteAgent
|
||||||
|
```
|
||||||
|
|
||||||
|
Or as a single-file bundle (attached to each release of this repo, no remote
|
||||||
|
needed, but no auto-updates either):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
flatpak install ./heiniremote-agent-<version>.flatpak
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configure
|
||||||
|
|
||||||
|
The agent needs a server URL and device token. Inside the sandbox the config
|
||||||
|
path is:
|
||||||
|
|
||||||
|
```
|
||||||
|
~/.var/app/de.pc_heini.HeiniRemoteAgent/config/heiniremote/agent.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
If a native install already left a config at `~/.config/heiniremote/agent.toml`,
|
||||||
|
the wrapper picks it up automatically (read-only). `HEINIREMOTE_SERVER_URL` /
|
||||||
|
`HEINIREMOTE_TOKEN` env overrides work as usual:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
flatpak run --env=HEINIREMOTE_SERVER_URL=wss://… de.pc_heini.HeiniRemoteAgent
|
||||||
|
```
|
||||||
|
|
||||||
|
## Autostart
|
||||||
|
|
||||||
|
The native install runs as a systemd user service; the Flatpak equivalent is a
|
||||||
|
user unit wrapping `flatpak run`:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
# ~/.config/systemd/user/heiniremote-agent.service
|
||||||
|
[Unit]
|
||||||
|
Description=HeiniRemote agent (Flatpak)
|
||||||
|
After=graphical-session.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=flatpak run de.pc_heini.HeiniRemoteAgent
|
||||||
|
Restart=on-failure
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=graphical-session.target
|
||||||
|
```
|
||||||
|
|
||||||
|
## How the sandbox is punched
|
||||||
|
|
||||||
|
Screen capture and input injection go through xdg-desktop-portal
|
||||||
|
(ScreenCast + RemoteDesktop) — that is the normal, fully sandboxed path and
|
||||||
|
needs no special permission. Two things do:
|
||||||
|
|
||||||
|
- **`--talk-name=org.freedesktop.Flatpak`** — the PTY rescue console must show
|
||||||
|
the *host*, not the sandbox. The wrapper sets `SHELL=/app/bin/host-shell`,
|
||||||
|
which execs the user's real login shell via `flatpak-spawn --host`. This is
|
||||||
|
a deliberate sandbox escape; for a remote maintenance tool the sandbox is
|
||||||
|
packaging, not a security boundary.
|
||||||
|
- **`--filesystem=xdg-config/heiniremote:ro`** — adopt a native install's
|
||||||
|
`agent.toml` (see above).
|
||||||
|
|
||||||
|
Everything else is standard: `network` (signaling + WebRTC/TURN), `wayland`
|
||||||
|
(bundled wl-copy/wl-paste), `dri` (dmabuf screencast buffers), and the
|
||||||
|
StatusNotifier names for the tray icon.
|
||||||
|
|
||||||
|
## Repo layout
|
||||||
|
|
||||||
|
| File | Role |
|
||||||
|
|---|---|
|
||||||
|
| `.gitea/workflows/build-flatpak.yml` | CI: resolve upstream version → cargo build → assemble → publish `pages` + release bundle. Daily schedule picks up new upstream versions. |
|
||||||
|
| `scripts/get-latest-version.sh` | Newest upstream `v*` tag, else `main` HEAD (`0.0.0-git.<date>.<sha>`). |
|
||||||
|
| `scripts/make-flatpak.sh` | bwrap-free assembly: `build-init` → copy files → `build-finish` → `build-export`. |
|
||||||
|
| `heiniremote-wrapper.sh` | Entry point: host-shell `$SHELL` override + config adoption. |
|
||||||
|
| `host-shell.sh` | `flatpak-spawn --host` bridge for the PTY console. |
|
||||||
|
| `de.pc_heini.HeiniRemoteAgent.*` | Desktop file, AppStream metainfo (version stamped by CI), icon. |
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=HeiniRemote Agent
|
||||||
|
Comment=Remote maintenance agent — connects this machine to a HeiniRemote server
|
||||||
|
Exec=heiniremote-wrapper.sh
|
||||||
|
Icon=de.pc_heini.HeiniRemoteAgent
|
||||||
|
Terminal=false
|
||||||
|
Categories=Network;RemoteAccess;
|
||||||
|
Keywords=remote;support;fernwartung;
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component type="desktop-application">
|
||||||
|
<id>de.pc_heini.HeiniRemoteAgent</id>
|
||||||
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
|
<project_license>proprietary</project_license>
|
||||||
|
<name>HeiniRemote Agent</name>
|
||||||
|
<summary>Remote maintenance agent for HeiniRemote</summary>
|
||||||
|
<description>
|
||||||
|
<p>
|
||||||
|
Customer-side agent for HeiniRemote: Wayland screen capture and input
|
||||||
|
injection via xdg-desktop-portal, plus a PTY rescue console, streamed
|
||||||
|
over WebRTC to the HeiniRemote management console. Requires a HeiniRemote
|
||||||
|
server URL and device token (agent.toml).
|
||||||
|
</p>
|
||||||
|
</description>
|
||||||
|
<launchable type="desktop-id">de.pc_heini.HeiniRemoteAgent.desktop</launchable>
|
||||||
|
<url type="homepage">https://pc-heini.de/</url>
|
||||||
|
<developer_name>PC-Heini</developer_name>
|
||||||
|
<releases>
|
||||||
|
<!-- Version/date are stamped by CI (build-flatpak.yml) before export. -->
|
||||||
|
<release version="0.0.0" date="1970-01-01"/>
|
||||||
|
</releases>
|
||||||
|
<content_rating type="oars-1.1"/>
|
||||||
|
</component>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||||
|
<!-- HeiniRemote "Fernblick": remote screen inside a screen, PC-Heini logo
|
||||||
|
yellow (#f6db3e) on an anthracite tile (variant B2 of the logo drafts). -->
|
||||||
|
<rect width="32" height="32" rx="7" fill="#1d1e20"/>
|
||||||
|
<rect x="0.5" y="0.5" width="31" height="31" rx="6.5" fill="none" stroke="#f6db3e" stroke-opacity="0.25"/>
|
||||||
|
<rect x="7" y="8.5" width="18" height="13" rx="2.5" fill="none" stroke="#f6db3e" stroke-width="2.6"/>
|
||||||
|
<rect x="14.5" y="13.5" width="7.5" height="5.5" rx="1.2" fill="#f6db3e"/>
|
||||||
|
<rect x="12" y="23.5" width="8" height="2" rx="1" fill="#f6db3e" opacity="0.85"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 657 B |
Executable
+24
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Flatpak entry point for the HeiniRemote agent.
|
||||||
|
#
|
||||||
|
# Two sandbox adaptations, no agent code changes:
|
||||||
|
#
|
||||||
|
# 1. The PTY console (agent's console.rs) spawns $SHELL. Inside the sandbox
|
||||||
|
# that would be a sandboxed shell showing the Flatpak filesystem — useless
|
||||||
|
# as a rescue console. Point it at the host-shell bridge instead, which
|
||||||
|
# escapes to the real host login shell via flatpak-spawn.
|
||||||
|
#
|
||||||
|
# 2. Config migration: the agent reads $XDG_CONFIG_HOME/heiniremote/agent.toml,
|
||||||
|
# which Flatpak redirects to ~/.var/app/<id>/config/. If no config exists
|
||||||
|
# there yet but a native install left one at ~/.config/heiniremote/
|
||||||
|
# (visible read-only via --filesystem=xdg-config/heiniremote:ro), use that
|
||||||
|
# via the agent's HEINIREMOTE_CONFIG override.
|
||||||
|
export SHELL=/app/bin/host-shell
|
||||||
|
|
||||||
|
if [ -z "${HEINIREMOTE_CONFIG:-}" ] \
|
||||||
|
&& [ ! -f "${XDG_CONFIG_HOME:-$HOME/.config}/heiniremote/agent.toml" ] \
|
||||||
|
&& [ -f "$HOME/.config/heiniremote/agent.toml" ]; then
|
||||||
|
export HEINIREMOTE_CONFIG="$HOME/.config/heiniremote/agent.toml"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec /app/bin/heiniremote-agent "$@"
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[Flatpak Repo]
|
||||||
|
Title=HeiniRemote Agent
|
||||||
|
# The CI job regenerates this file on the 'pages' branch with the correct URL,
|
||||||
|
# so the canonical copy to use is:
|
||||||
|
# https://git.pc-heini.de/pc-heini/heiniremote-flatpak/raw/branch/pages/heiniremote.flatpakrepo
|
||||||
|
Url=https://git.pc-heini.de/pc-heini/heiniremote-flatpak/raw/branch/pages
|
||||||
|
Homepage=https://pc-heini.de/
|
||||||
|
Comment=HeiniRemote remote maintenance agent as a Flatpak
|
||||||
|
Description=Install the HeiniRemote agent on any Linux distribution via Flatpak.
|
||||||
Executable
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Host-shell bridge for the agent's PTY console.
|
||||||
|
#
|
||||||
|
# The wrapper sets SHELL=/app/bin/host-shell, so the agent's PTY console
|
||||||
|
# spawns this instead of a sandboxed shell. flatpak-spawn --host (requires
|
||||||
|
# --talk-name=org.freedesktop.Flatpak) runs the command on the host with the
|
||||||
|
# PTY fds forwarded, giving the remote console a real host login shell.
|
||||||
|
#
|
||||||
|
# The inner resolution runs ON THE HOST: flatpak-spawn forwards the sandbox
|
||||||
|
# environment, so $SHELL would still point at this script — resolve the user's
|
||||||
|
# real login shell from passwd instead and fix up $SHELL before exec'ing it.
|
||||||
|
exec flatpak-spawn --host /bin/sh -c '
|
||||||
|
shell="$(getent passwd "$(id -un)" | cut -d: -f7)"
|
||||||
|
[ -x "$shell" ] || shell=/bin/sh
|
||||||
|
export SHELL="$shell"
|
||||||
|
exec "$shell" -l
|
||||||
|
'
|
||||||
Executable
+27
@@ -0,0 +1,27 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Resolve which HeiniRemote revision to package. Prints eval-able output:
|
||||||
|
# version=<x.y.z or 0.0.0-git.<date>.<sha>>
|
||||||
|
# ref=<tag name or commit sha>
|
||||||
|
#
|
||||||
|
# Prefers the newest v* release tag on the upstream repo; while no release tag
|
||||||
|
# exists yet, falls back to the tip of main (version derived from the commit).
|
||||||
|
# UPSTREAM_URL may carry credentials (CI injects the actions token for private
|
||||||
|
# repos); only derived values are printed.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
UPSTREAM_URL="${UPSTREAM_URL:-https://git.pc-heini.de/pc-heini/HeiniRemote.git}"
|
||||||
|
|
||||||
|
tag=$(git ls-remote --tags "$UPSTREAM_URL" 'refs/tags/v*' \
|
||||||
|
| awk -F'refs/tags/' '{print $2}' \
|
||||||
|
| grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
|
||||||
|
| sort -V | tail -n1 || true)
|
||||||
|
|
||||||
|
if [ -n "$tag" ]; then
|
||||||
|
echo "version=${tag#v}"
|
||||||
|
echo "ref=$tag"
|
||||||
|
else
|
||||||
|
sha=$(git ls-remote "$UPSTREAM_URL" refs/heads/main | cut -c1-12)
|
||||||
|
[ -n "$sha" ] || { echo "ERROR: cannot resolve upstream main" >&2; exit 1; }
|
||||||
|
echo "version=0.0.0-git.$(date +%Y%m%d).$sha"
|
||||||
|
echo "ref=$sha"
|
||||||
|
fi
|
||||||
Executable
+74
@@ -0,0 +1,74 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Assemble the HeiniRemote agent Flatpak WITHOUT flatpak-builder.
|
||||||
|
#
|
||||||
|
# Same approach as o3de-flatpak: flatpak-builder would run build commands
|
||||||
|
# inside a bubblewrap sandbox (needs user namespaces / privileged CI). We
|
||||||
|
# don't need that — the real build (cargo) happens outside this script, and
|
||||||
|
# flatpak build-init/build-finish/build-export only touch files and the
|
||||||
|
# OSTree repo.
|
||||||
|
#
|
||||||
|
# Inputs (env):
|
||||||
|
# AGENT_BIN path to the compiled heiniremote-agent binary (required)
|
||||||
|
# WL_CLIPBOARD_DIR dir containing wl-copy/wl-paste to bundle (default /usr/bin)
|
||||||
|
#
|
||||||
|
# Produces ./repo (an OSTree repo with branch "stable").
|
||||||
|
set -euo pipefail
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
APP_ID=de.pc_heini.HeiniRemoteAgent
|
||||||
|
RUNTIME_VER=24.08
|
||||||
|
BRANCH=stable
|
||||||
|
AGENT_BIN="${AGENT_BIN:?set AGENT_BIN to the compiled heiniremote-agent}"
|
||||||
|
WL_DIR="${WL_CLIPBOARD_DIR:-/usr/bin}"
|
||||||
|
|
||||||
|
rm -rf build-dir repo
|
||||||
|
|
||||||
|
echo ">> build-init"
|
||||||
|
flatpak build-init build-dir "$APP_ID" org.freedesktop.Sdk org.freedesktop.Platform "$RUNTIME_VER"
|
||||||
|
DEST=build-dir/files
|
||||||
|
|
||||||
|
echo ">> installing agent + bundled tools"
|
||||||
|
install -Dm755 "$AGENT_BIN" "$DEST/bin/heiniremote-agent"
|
||||||
|
# wl-clipboard is bundled because the agent's clipboard sync shells out to it
|
||||||
|
# (clipboard.rs); the freedesktop runtime does not ship it.
|
||||||
|
install -Dm755 "$WL_DIR/wl-copy" "$DEST/bin/wl-copy"
|
||||||
|
install -Dm755 "$WL_DIR/wl-paste" "$DEST/bin/wl-paste"
|
||||||
|
install -Dm755 heiniremote-wrapper.sh "$DEST/bin/heiniremote-wrapper.sh"
|
||||||
|
install -Dm755 host-shell.sh "$DEST/bin/host-shell"
|
||||||
|
|
||||||
|
echo ">> installing desktop metadata"
|
||||||
|
install -Dm644 "$APP_ID.desktop" "$DEST/share/applications/$APP_ID.desktop"
|
||||||
|
install -Dm644 "$APP_ID.metainfo.xml" "$DEST/share/metainfo/$APP_ID.metainfo.xml"
|
||||||
|
install -Dm644 "$APP_ID.svg" "$DEST/share/icons/hicolor/scalable/apps/$APP_ID.svg"
|
||||||
|
|
||||||
|
echo ">> build-finish (sandbox permissions)"
|
||||||
|
# ScreenCast/RemoteDesktop run through xdg-desktop-portal, which sandboxed
|
||||||
|
# apps may always talk to — no extra permission needed. What IS needed:
|
||||||
|
# network signaling wss + WebRTC/TURN
|
||||||
|
# wayland wl-copy/wl-paste talk to the compositor
|
||||||
|
# dri PipeWire screencast buffers may be dmabuf
|
||||||
|
# xdg-config/heiniremote:ro adopt an existing native install's agent.toml
|
||||||
|
# StatusNotifier* tray icon (ksni); non-fatal if absent. ksni
|
||||||
|
# owns org.kde.StatusNotifierItem-{pid}-1 and
|
||||||
|
# the wrapper exec's the agent, so inside the
|
||||||
|
# sandbox the pid is deterministically 2
|
||||||
|
# org.freedesktop.Flatpak flatpak-spawn --host for the rescue console's
|
||||||
|
# real host shell — deliberate sandbox escape,
|
||||||
|
# without it the console would show the sandbox
|
||||||
|
flatpak build-finish build-dir \
|
||||||
|
--command=heiniremote-wrapper.sh \
|
||||||
|
--share=network \
|
||||||
|
--socket=wayland \
|
||||||
|
--device=dri \
|
||||||
|
--filesystem=xdg-config/heiniremote:ro \
|
||||||
|
--talk-name=org.kde.StatusNotifierWatcher \
|
||||||
|
--own-name=org.kde.StatusNotifierItem-2-1 \
|
||||||
|
--talk-name=org.freedesktop.Flatpak
|
||||||
|
|
||||||
|
echo ">> export to OSTree repo"
|
||||||
|
# --disable-sandbox: build-export validates icons in bwrap by default, which
|
||||||
|
# fails in unprivileged CI containers; this runs the same validation in-process.
|
||||||
|
flatpak build-export --disable-sandbox repo build-dir "$BRANCH"
|
||||||
|
flatpak build-update-repo repo --title="HeiniRemote Agent" --prune --prune-depth=1
|
||||||
|
|
||||||
|
echo ">> done: ./repo"
|
||||||
Reference in new issue
Block a user