diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml
index 6ea1c7b..7ac7c7d 100644
--- a/.gitea/workflows/ci.yml
+++ b/.gitea/workflows/ci.yml
@@ -25,7 +25,7 @@ jobs:
$SUDO apt-get update
$SUDO apt-get install -y --no-install-recommends python3 python3-yaml dpkg-dev zstd
- name: Full regression suite
- run: ./tests/full-verify.sh
+ run: bash ./tests/full-verify.sh
rpm-package:
runs-on: ubuntu-latest
@@ -37,8 +37,8 @@ jobs:
- name: Build backend and RPM
run: |
set -euo pipefail
- ./build.sh
- ./packaging/build-rpm.sh
+ bash ./build.sh
+ bash ./packaging/build-rpm.sh
VERSION="$(tr -d '[:space:]' < VERSION)"
rpm -qpi "dist/citizen-launcher-${VERSION}-1.linux.x86_64.rpm"
@@ -52,7 +52,7 @@ jobs:
run: pacman -Syu --noconfirm --needed git go zstd curl python
- uses: actions/checkout@v4
- name: Build backend
- run: ./build.sh
+ run: bash ./build.sh
- name: Build pacman package as unprivileged user
shell: bash
run: |
@@ -60,5 +60,5 @@ jobs:
VERSION="$(tr -d '[:space:]' < VERSION)"
useradd -m builder
chown -R builder:builder "$WORKSPACE"
- su builder -s /bin/bash -c "cd '$WORKSPACE' && ./packaging/build-arch.sh"
+ su builder -s /bin/bash -c "cd '$WORKSPACE' && bash ./packaging/build-arch.sh"
test -s "dist/citizen-launcher-${VERSION}-1-x86_64.pkg.tar.zst"
diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml
index 2448404..2f9336a 100644
--- a/.gitea/workflows/release.yml
+++ b/.gitea/workflows/release.yml
@@ -32,7 +32,7 @@ jobs:
run: |
set -euo pipefail
VERSION="$(tr -d '[:space:]' < VERSION)"
- ./scripts/gitea-release.sh ensure \
+ bash ./scripts/gitea-release.sh ensure \
"$TAG_NAME" \
"Citizen Launcher ${VERSION}" \
RELEASE_NOTES.md \
@@ -58,14 +58,14 @@ jobs:
$SUDO apt-get update
$SUDO apt-get install -y --no-install-recommends python3 python3-yaml dpkg-dev zstd curl
- name: Full regression and package suite
- run: ./tests/full-verify.sh
+ run: bash ./tests/full-verify.sh
- name: Upload Debian and generic assets to Gitea
shell: bash
run: |
set -euo pipefail
VERSION="$(tr -d '[:space:]' < VERSION)"
- ./scripts/gitea-release.sh upload "$TAG_NAME" "dist/citizen-launcher_${VERSION}_amd64.deb"
- ./scripts/gitea-release.sh upload "$TAG_NAME" "dist/citizen-launcher-${VERSION}-linux-amd64.tar.gz"
+ bash ./scripts/gitea-release.sh upload "$TAG_NAME" "dist/citizen-launcher_${VERSION}_amd64.deb"
+ bash ./scripts/gitea-release.sh upload "$TAG_NAME" "dist/citizen-launcher-${VERSION}-linux-amd64.tar.gz"
rpm:
needs: prepare-release
@@ -83,15 +83,15 @@ jobs:
set -euo pipefail
VERSION="$(tr -d '[:space:]' < VERSION)"
test "$TAG_NAME" = "v${VERSION}"
- ./build.sh
- ./packaging/build-rpm.sh
+ bash ./build.sh
+ bash ./packaging/build-rpm.sh
rpm -qpi "dist/citizen-launcher-${VERSION}-1.linux.x86_64.rpm"
- name: Upload RPM to Gitea
shell: bash
run: |
set -euo pipefail
VERSION="$(tr -d '[:space:]' < VERSION)"
- ./scripts/gitea-release.sh upload "$TAG_NAME" "dist/citizen-launcher-${VERSION}-1.linux.x86_64.rpm"
+ bash ./scripts/gitea-release.sh upload "$TAG_NAME" "dist/citizen-launcher-${VERSION}-1.linux.x86_64.rpm"
arch:
needs: prepare-release
@@ -110,17 +110,17 @@ jobs:
set -euo pipefail
VERSION="$(tr -d '[:space:]' < VERSION)"
test "$TAG_NAME" = "v${VERSION}"
- ./build.sh
+ bash ./build.sh
useradd -m builder
chown -R builder:builder "$WORKSPACE"
- su builder -s /bin/bash -c "cd '$WORKSPACE' && CITIZEN_LAUNCHER_RELEASE_REPO='$CITIZEN_LAUNCHER_RELEASE_REPO' ./packaging/build-arch.sh"
+ su builder -s /bin/bash -c "cd '$WORKSPACE' && CITIZEN_LAUNCHER_RELEASE_REPO='$CITIZEN_LAUNCHER_RELEASE_REPO' bash ./packaging/build-arch.sh"
test -s "dist/citizen-launcher-${VERSION}-1-x86_64.pkg.tar.zst"
- name: Upload Arch package to Gitea
shell: bash
run: |
set -euo pipefail
VERSION="$(tr -d '[:space:]' < VERSION)"
- ./scripts/gitea-release.sh upload "$TAG_NAME" "dist/citizen-launcher-${VERSION}-1-x86_64.pkg.tar.zst"
+ bash ./scripts/gitea-release.sh upload "$TAG_NAME" "dist/citizen-launcher-${VERSION}-1-x86_64.pkg.tar.zst"
finalize-release:
needs: [deb-and-generic, rpm, arch]
@@ -132,7 +132,7 @@ jobs:
run: |
set -euo pipefail
rm -rf release-assets
- ./scripts/gitea-release.sh download-assets "$TAG_NAME" release-assets
+ bash ./scripts/gitea-release.sh download-assets "$TAG_NAME" release-assets
VERSION="$(tr -d '[:space:]' < VERSION)"
test -s "release-assets/citizen-launcher_${VERSION}_amd64.deb"
test -s "release-assets/citizen-launcher-${VERSION}-1.linux.x86_64.rpm"
@@ -140,4 +140,4 @@ jobs:
test -s "release-assets/citizen-launcher-${VERSION}-linux-amd64.tar.gz"
(cd release-assets && sha256sum * | LC_ALL=C sort -k2 > SHA256SUMS.txt)
- name: Publish SHA256SUMS on Gitea release
- run: ./scripts/gitea-release.sh upload "$TAG_NAME" release-assets/SHA256SUMS.txt
+ run: bash ./scripts/gitea-release.sh upload "$TAG_NAME" release-assets/SHA256SUMS.txt
diff --git a/GITEA.md b/GITEA.md
index d826175..4d4c4cc 100644
--- a/GITEA.md
+++ b/GITEA.md
@@ -1,6 +1,6 @@
# Gitea Actions setup
-Citizen Launcher 1.1.1 uses Gitea Actions natively. Workflows are in `.gitea/workflows/`; the old `.github/workflows/` directory is intentionally absent.
+Citizen Launcher 1.1.2 uses Gitea Actions natively. Workflows are in `.gitea/workflows/`; the old `.github/workflows/` directory is intentionally absent.
## Requirements
@@ -26,8 +26,8 @@ If your runner uses a different label, replace `runs-on: ubuntu-latest` in both
Push a version tag matching `VERSION`, for example:
```bash
-git tag v1.1.1
-git push origin v1.1.1
+git tag v1.1.2
+git push origin v1.1.2
```
`.gitea/workflows/release.yml` then:
diff --git a/INSTALLIEREN.sh b/INSTALLIEREN.sh
index 60902cc..004368b 100644
--- a/INSTALLIEREN.sh
+++ b/INSTALLIEREN.sh
@@ -38,7 +38,7 @@ esac
if $immutable; then
echo "Immutable Linux-Variante erkannt ($id${variant:+/$variant})."
echo "Citizen Launcher wird sicher im Benutzerkonto installiert; das Basis-Image bleibt unangetastet."
- exec "$ROOT/install.sh"
+ exec bash "$ROOT/install.sh"
fi
case "$family" in
@@ -80,4 +80,4 @@ esac
echo "Kein passendes natives Paket im Projektordner gefunden."
echo "Installiere die portable, vollständig updatefähige Benutzer-Version …"
-exec "$ROOT/install.sh"
+exec bash "$ROOT/install.sh"
diff --git a/README.md b/README.md
index fdf4898..8a1a145 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Citizen Launcher 1.1.1
+# Citizen Launcher 1.1.2
Citizen Launcher is a cross-distribution Star Citizen setup, launch, repair and maintenance application for Linux. The same static Go core runs on Debian/Ubuntu, Fedora/RHEL derivatives, Arch derivatives, openSUSE and generic glibc-based desktop Linux. Omarchy support is an optional integration, not a runtime requirement.
@@ -8,7 +8,7 @@ Citizen Launcher is a cross-distribution Star Citizen setup, launch, repair and
The launcher owns the fragile user-space gaming stack so users do not have to pick Wine builds, copy DXVK DLLs or rebuild prefixes by hand. Kernel, GPU driver, firmware and base-distribution upgrades remain owned by the Linux distribution.
-The 1.0.1 gaming path was confirmed end-to-end on real hardware: launcher, RSI installation and Star Citizen playability. 1.1.1 keeps that gaming core and adds native multi-distribution packaging/update integration.
+The 1.0.1 gaming path was confirmed end-to-end on real hardware: launcher, RSI installation and Star Citizen playability. 1.1.2 keeps that gaming core and adds native multi-distribution packaging/update integration.
## Supported Linux families
@@ -32,25 +32,25 @@ The installer detects the distro family, prefers a native package found in `dist
### Debian / Ubuntu / Mint
```bash
-sudo apt install ./dist/citizen-launcher_1.1.1_amd64.deb
+sudo apt install ./dist/citizen-launcher_1.1.2_amd64.deb
```
### Fedora / Nobara / RHEL family
```bash
-sudo dnf install ./dist/citizen-launcher-1.1.1-1.linux.x86_64.rpm
+sudo dnf install ./dist/citizen-launcher-1.1.2-1.linux.x86_64.rpm
```
### openSUSE Tumbleweed / Slowroll
```bash
-sudo zypper install ./dist/citizen-launcher-1.1.1-1.linux.x86_64.rpm
+sudo zypper install ./dist/citizen-launcher-1.1.2-1.linux.x86_64.rpm
```
### Arch / Manjaro / EndeavourOS / CachyOS / Omarchy
```bash
-sudo pacman -U ./dist/citizen-launcher-1.1.1-1-x86_64.pkg.tar.zst
+sudo pacman -U ./dist/citizen-launcher-1.1.2-1-x86_64.pkg.tar.zst
```
### Generic / immutable desktop Linux
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 5746ac0..d5ab8d6 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,8 +1,8 @@
-# Citizen Launcher 1.1.1
+# Citizen Launcher 1.1.2
## Gitea-native CI/CD release
-1.1.1 keeps the confirmed playable multi-distribution 1.1.x runtime and migrates the project automation from GitHub Actions to Gitea Actions.
+1.1.2 keeps the confirmed playable multi-distribution 1.1.x runtime and hardens the Gitea Actions pipeline introduced in 1.1.1.
### Gitea workflows
@@ -26,3 +26,10 @@ The release flow does not depend on cross-job `upload-artifact` compatibility. E
### Runtime
Wine, DXVK, RSI Launcher setup, hardware checks, single-instance protection, repair, support bundles and the already confirmed playable Star Citizen path are unchanged.
+## Gitea CI hardening
+
+- Gitea Actions invokes repository shell scripts explicitly through `bash`.
+- Nested test, build and release scripts use the same mode-independent convention.
+- Added a regression guard against direct `.sh` execution in the critical CI graph.
+- Fixes Gitea/act exit code 126 (`Permission denied`) when checkout files are mode `0644`.
+
diff --git a/TEST_REPORT.md b/TEST_REPORT.md
index 26855c2..246b3de 100644
--- a/TEST_REPORT.md
+++ b/TEST_REPORT.md
@@ -1,14 +1,14 @@
-# Citizen Launcher 1.1.1 – Verification Report
+# Citizen Launcher 1.1.2 – Verification Report
Date: 2026-09-01
## Release scope
-Citizen Launcher 1.1.1 keeps the confirmed playable 1.1.x multi-distribution gaming core and migrates CI/CD and release publishing to Gitea Actions.
+Citizen Launcher 1.1.2 keeps the confirmed playable 1.1.x multi-distribution gaming core and hardens the Gitea-native CI/CD introduced in 1.1.1 against checkout permission differences.
## Automated release gate
-The 1.1.1 tree passes the local release gate with:
+The 1.1.2 tree passes the local release gate with:
- shell syntax checks for installers, packaging, Gitea release helper and tests
- `gofmt` cleanliness
@@ -27,6 +27,8 @@ The 1.1.1 tree passes the local release gate with:
- static validation of RPM spec and Arch PKGBUILD/package hooks
- multi-distro platform-family and immutable-host regression tests
- native package self-update parser/asset-selection tests for DEB, RPM and pacman formats
+- full regression suite repeated successfully after forcing every repository `*.sh` file to mode `0644`; CI does not depend on executable bits
+- regression guard rejects direct repository `.sh` execution in Gitea workflow entry points
## Gitea CI/CD design verified
@@ -57,14 +59,18 @@ A separate build check confirmed that a `gitea:https://.../api/v1/repos/owner/re
The current local build environment contains Debian packaging tools, therefore these artifacts can be built and inspected locally:
-- `dist/citizen-launcher_1.1.1_amd64.deb`
-- `dist/citizen-launcher-1.1.1-linux-amd64.tar.gz`
+- `dist/citizen-launcher_1.1.2_amd64.deb`
+- `dist/citizen-launcher-1.1.2-linux-amd64.tar.gz`
The local environment does not provide native `rpmbuild` / Arch `makepkg`; the Gitea workflows build those in Fedora and Arch job containers:
-- `citizen-launcher-1.1.1-1.linux.x86_64.rpm`
-- `citizen-launcher-1.1.1-1-x86_64.pkg.tar.zst`
+- `citizen-launcher-1.1.2-1.linux.x86_64.rpm`
+- `citizen-launcher-1.1.2-1-x86_64.pkg.tar.zst`
## Gaming-core acceptance
The Star Citizen install/play path is unchanged from the already accepted 1.0.1/1.1.0 line. The CI migration changes release and update plumbing, not Wine/DXVK/RSI launch behavior.
+
+## Checkout permission regression
+
+The complete `tests/full-verify.sh` suite was repeated after forcing every repository `*.sh` file to Unix mode `0644`. It still completed successfully. This reproduces the Gitea/act checkout condition that caused exit code 126 and verifies that CI/CD no longer depends on executable bits for repository shell scripts. Distributed archives still mark shell scripts executable for convenience.
diff --git a/VERSION b/VERSION
index 524cb55..45a1b3f 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.1.1
+1.1.2
diff --git a/backend/bin/citizen-launcher b/backend/bin/citizen-launcher
index 7bf37bf..61c091e 100644
Binary files a/backend/bin/citizen-launcher and b/backend/bin/citizen-launcher differ
diff --git a/backend/cmd/citizen-launcher/main.go b/backend/cmd/citizen-launcher/main.go
index e844bd5..1e29114 100644
--- a/backend/cmd/citizen-launcher/main.go
+++ b/backend/cmd/citizen-launcher/main.go
@@ -16,7 +16,7 @@ import (
)
var (
- appVersion = "1.1.1"
+ appVersion = "1.1.2"
releaseRepo = "github:sendnwv/omarchy-sc"
)
diff --git a/build.sh b/build.sh
index 0190e9d..37c28dd 100644
--- a/build.sh
+++ b/build.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
-(cd "$ROOT/backend" && ./build.sh)
+(cd "$ROOT/backend" && bash ./build.sh)
echo "Build fertig: backend/bin/citizen-launcher"
diff --git a/dist/citizen-launcher-1.1.2-linux-amd64.tar.gz b/dist/citizen-launcher-1.1.2-linux-amd64.tar.gz
new file mode 100644
index 0000000..4112794
Binary files /dev/null and b/dist/citizen-launcher-1.1.2-linux-amd64.tar.gz differ
diff --git a/dist/citizen-launcher_1.1.2_amd64.deb b/dist/citizen-launcher_1.1.2_amd64.deb
new file mode 100644
index 0000000..e49f02e
Binary files /dev/null and b/dist/citizen-launcher_1.1.2_amd64.deb differ
diff --git a/install-omarchy.sh b/install-omarchy.sh
index 2fc502b..87ec634 100644
--- a/install-omarchy.sh
+++ b/install-omarchy.sh
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
-"$ROOT/install.sh"
+bash "$ROOT/install.sh"
command -v omarchy >/dev/null 2>&1 || { echo "Omarchy nicht gefunden; Standalone-Launcher ist trotzdem installiert."; exit 0; }
DEST="$HOME/.config/omarchy/plugins/local.omarchy-citizen"
mkdir -p "$DEST/backend/bin"
diff --git a/integrations/omarchy/Panel.qml b/integrations/omarchy/Panel.qml
index 38b4fc2..ca40c62 100644
--- a/integrations/omarchy/Panel.qml
+++ b/integrations/omarchy/Panel.qml
@@ -12,7 +12,7 @@ Panel {
property var anchorItem: null
property var hostWidget: null
- property string pluginVersion: "1.1.1"
+ property string pluginVersion: "1.1.2"
property string health: "checking"
property string depsState: "checking"
property string depsMissing: ""
@@ -106,7 +106,7 @@ Panel {
values[lines[i].slice(0, p)] = lines[i].slice(p + 1)
}
- pluginVersion = values.plugin_version || "1.1.1"
+ pluginVersion = values.plugin_version || "1.1.2"
health = values.health || "setup"
depsState = values.deps || "missing"
depsMissing = values.deps_missing || ""
diff --git a/integrations/omarchy/citizenctl b/integrations/omarchy/citizenctl
index 3dc8529..d8805ef 100644
--- a/integrations/omarchy/citizenctl
+++ b/integrations/omarchy/citizenctl
@@ -2,7 +2,7 @@
set -u
PLUGIN_ID="local.omarchy-citizen"
-PLUGIN_VERSION="1.1.1"
+PLUGIN_VERSION="1.1.2"
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
diff --git a/integrations/omarchy/manifest.json b/integrations/omarchy/manifest.json
index 17e8353..f1a1c8d 100644
--- a/integrations/omarchy/manifest.json
+++ b/integrations/omarchy/manifest.json
@@ -2,7 +2,7 @@
"schemaVersion": 1,
"id": "local.omarchy-citizen",
"name": "Citizen Launcher · Omarchy",
- "version": "1.1.1",
+ "version": "1.1.2",
"author": "Community prototype",
"license": "MIT",
"description": "Optional Omarchy bar integration for the distro-neutral Citizen Launcher.",
diff --git a/packaging/build-all.sh b/packaging/build-all.sh
index b7585e4..82d9f5c 100644
--- a/packaging/build-all.sh
+++ b/packaging/build-all.sh
@@ -1,16 +1,16 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
-"$ROOT/build.sh"
-"$ROOT/packaging/build-deb.sh"
-"$ROOT/packaging/build-tarball.sh"
+bash "$ROOT/build.sh"
+bash "$ROOT/packaging/build-deb.sh"
+bash "$ROOT/packaging/build-tarball.sh"
if command -v rpmbuild >/dev/null 2>&1; then
- "$ROOT/packaging/build-rpm.sh"
+ bash "$ROOT/packaging/build-rpm.sh"
else
echo "Hinweis: rpmbuild fehlt – RPM wird in Fedora/openSUSE CI gebaut." >&2
fi
if command -v makepkg >/dev/null 2>&1 && [[ $EUID -ne 0 ]]; then
- "$ROOT/packaging/build-arch.sh"
+ bash "$ROOT/packaging/build-arch.sh"
else
echo "Hinweis: makepkg fehlt/Root – Arch-Paket wird in Arch CI gebaut." >&2
fi
diff --git a/packaging/citizen-launcher.spec b/packaging/citizen-launcher.spec
index 2551d74..ded0f8b 100644
--- a/packaging/citizen-launcher.spec
+++ b/packaging/citizen-launcher.spec
@@ -104,5 +104,7 @@ fi
%config(noreplace) %{_sysconfdir}/citizen-launcher/release-repo
%changelog
+* Tue Sep 01 2026 Citizen Launcher Project - 1.1.2-1
+- Gitea Actions checkout permission hardening
* Tue Sep 01 2026 Citizen Launcher Project - 1.1.1-1
- Multi-distribution native package support
diff --git a/packaging/metainfo/io.github.citizenlauncher.CitizenLauncher.metainfo.xml b/packaging/metainfo/io.github.citizenlauncher.CitizenLauncher.metainfo.xml
index c394248..b9417ae 100644
--- a/packaging/metainfo/io.github.citizenlauncher.CitizenLauncher.metainfo.xml
+++ b/packaging/metainfo/io.github.citizenlauncher.CitizenLauncher.metainfo.xml
@@ -13,6 +13,6 @@
https://github.com/sendnwv/omarchy-sc
Game
citizen-launcher
-
+
diff --git a/packaging/rpm/citizen-launcher.spec b/packaging/rpm/citizen-launcher.spec
index 2551d74..ded0f8b 100644
--- a/packaging/rpm/citizen-launcher.spec
+++ b/packaging/rpm/citizen-launcher.spec
@@ -104,5 +104,7 @@ fi
%config(noreplace) %{_sysconfdir}/citizen-launcher/release-repo
%changelog
+* Tue Sep 01 2026 Citizen Launcher Project - 1.1.2-1
+- Gitea Actions checkout permission hardening
* Tue Sep 01 2026 Citizen Launcher Project - 1.1.1-1
- Multi-distribution native package support
diff --git a/tests/full-verify.sh b/tests/full-verify.sh
index 6c27f8a..3fb7406 100644
--- a/tests/full-verify.sh
+++ b/tests/full-verify.sh
@@ -1,9 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
-"$ROOT/tests/verify.sh"
+bash "$ROOT/tests/verify.sh"
+bash "$ROOT/tests/mode-independence.sh"
(cd "$ROOT/backend" && go test -race ./...)
-"$ROOT/backend/integration-test.sh"
-"$ROOT/tests/gitea-release-helper.sh"
-"$ROOT/tests/package-verify.sh"
+bash "$ROOT/backend/integration-test.sh"
+bash "$ROOT/tests/gitea-release-helper.sh"
+bash "$ROOT/tests/package-verify.sh"
echo 'Citizen Launcher full verification: OK'
diff --git a/tests/gitea-release-helper.sh b/tests/gitea-release-helper.sh
index 4cd6438..4edf9c2 100644
--- a/tests/gitea-release-helper.sh
+++ b/tests/gitea-release-helper.sh
@@ -25,7 +25,7 @@ class H(http.server.BaseHTTPRequestHandler):
return r
def do_GET(self):
path=urllib.parse.urlparse(self.path).path
- if path.endswith('/releases/tags/v1.1.1'):
+ if path.endswith('/releases/tags/v1.1.2'):
if release is None: self.send_error(404); return
self.sendj(200,self.rel()); return
if path.startswith('/download/'):
@@ -78,12 +78,12 @@ export GITEA_API_URL="http://127.0.0.1:${PORT}/api/v1"
export GITEA_REPOSITORY="owner/repo"
export GITEA_TOKEN="test-token"
-echo first > "$TMP/citizen-launcher_1.1.1_amd64.deb"
-"$ROOT/scripts/gitea-release.sh" ensure v1.1.1 'Citizen Launcher 1.1.1' "$ROOT/RELEASE_NOTES.md" deadbeef
-"$ROOT/scripts/gitea-release.sh" ensure v1.1.1 'Citizen Launcher 1.1.1' "$ROOT/RELEASE_NOTES.md" deadbeef
-"$ROOT/scripts/gitea-release.sh" upload v1.1.1 "$TMP/citizen-launcher_1.1.1_amd64.deb"
-echo replacement > "$TMP/citizen-launcher_1.1.1_amd64.deb"
-"$ROOT/scripts/gitea-release.sh" upload v1.1.1 "$TMP/citizen-launcher_1.1.1_amd64.deb"
-"$ROOT/scripts/gitea-release.sh" download-assets v1.1.1 "$TMP/download"
-cmp "$TMP/citizen-launcher_1.1.1_amd64.deb" "$TMP/download/citizen-launcher_1.1.1_amd64.deb"
+echo first > "$TMP/citizen-launcher_1.1.2_amd64.deb"
+bash "$ROOT/scripts/gitea-release.sh" ensure v1.1.2 'Citizen Launcher 1.1.2' "$ROOT/RELEASE_NOTES.md" deadbeef
+bash "$ROOT/scripts/gitea-release.sh" ensure v1.1.2 'Citizen Launcher 1.1.2' "$ROOT/RELEASE_NOTES.md" deadbeef
+bash "$ROOT/scripts/gitea-release.sh" upload v1.1.2 "$TMP/citizen-launcher_1.1.2_amd64.deb"
+echo replacement > "$TMP/citizen-launcher_1.1.2_amd64.deb"
+bash "$ROOT/scripts/gitea-release.sh" upload v1.1.2 "$TMP/citizen-launcher_1.1.2_amd64.deb"
+bash "$ROOT/scripts/gitea-release.sh" download-assets v1.1.2 "$TMP/download"
+cmp "$TMP/citizen-launcher_1.1.2_amd64.deb" "$TMP/download/citizen-launcher_1.1.2_amd64.deb"
echo 'Gitea release helper verification: OK'
diff --git a/tests/mode-independence.sh b/tests/mode-independence.sh
new file mode 100644
index 0000000..eb9d290
--- /dev/null
+++ b/tests/mode-independence.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+set -euo pipefail
+ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
+
+python3 - "$ROOT" <<'PY'
+from pathlib import Path
+import re, sys
+root = Path(sys.argv[1])
+check = [
+ root/'build.sh', root/'install-omarchy.sh', root/'INSTALLIEREN.sh',
+ root/'tests/full-verify.sh', root/'tests/verify.sh', root/'tests/package-verify.sh',
+ root/'tests/gitea-release-helper.sh', root/'packaging/build-all.sh',
+ root/'.gitea/workflows/ci.yml', root/'.gitea/workflows/release.yml',
+]
+for p in check:
+ text = p.read_text()
+ bad = []
+ for lineno, line in enumerate(text.splitlines(), 1):
+ stripped = line.strip()
+ if stripped.startswith('#') or stripped.endswith('\\') or stripped.endswith('; do'):
+ continue
+ # Direct ./script.sh command (workflow or shell command) without an interpreter.
+ if re.search(r'(^|[;&|]\s*|run:\s*)\./[^\s"\x27]+\.sh(?:\s|$)', stripped):
+ bad.append((lineno, stripped))
+ # Direct "$ROOT/path/script.sh" command at start of a shell line.
+ if re.search(r'^"?\$ROOT/[^"\s]+\.sh"?(?:\s|$)', stripped):
+ bad.append((lineno, stripped))
+ if bad:
+ raise SystemExit(f'direct shell execution remains in {p}: {bad}')
+print('Mode-independent shell invocation: OK')
+PY
diff --git a/tests/package-verify.sh b/tests/package-verify.sh
index 2e63991..2f130f9 100644
--- a/tests/package-verify.sh
+++ b/tests/package-verify.sh
@@ -4,8 +4,8 @@ ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
VERSION="$(tr -d '[:space:]' < "$ROOT/VERSION")"
rm -rf "$ROOT/dist"
mkdir -p "$ROOT/dist"
-"$ROOT/packaging/build-deb.sh"
-"$ROOT/packaging/build-tarball.sh"
+bash "$ROOT/packaging/build-deb.sh"
+bash "$ROOT/packaging/build-tarball.sh"
DEB="$ROOT/dist/citizen-launcher_${VERSION}_amd64.deb"
TAR="$ROOT/dist/citizen-launcher-${VERSION}-linux-amd64.tar.gz"
[[ -s "$DEB" && -s "$TAR" ]]
@@ -45,14 +45,14 @@ grep -q "'x86_64'" "$ROOT/packaging/arch/PKGBUILD.in"
grep -q 'citizen-launcher-self-update.timer' "$ROOT/packaging/arch/PKGBUILD.in"
if command -v rpmbuild >/dev/null 2>&1; then
- "$ROOT/packaging/build-rpm.sh"
+ bash "$ROOT/packaging/build-rpm.sh"
RPM="$ROOT/dist/citizen-launcher-${VERSION}-1.linux.x86_64.rpm"
[[ -s "$RPM" ]]
rpm -qp --qf '%{NAME}\n%{VERSION}\n%{ARCH}\n' "$RPM" | grep -qx 'citizen-launcher' -m1
fi
if command -v makepkg >/dev/null 2>&1 && [[ $EUID -ne 0 ]]; then
- "$ROOT/packaging/build-arch.sh"
+ bash "$ROOT/packaging/build-arch.sh"
[[ -s "$ROOT/dist/citizen-launcher-${VERSION}-1-x86_64.pkg.tar.zst" ]]
fi
diff --git a/tests/verify.sh b/tests/verify.sh
index 5a6129b..f7f76de 100644
--- a/tests/verify.sh
+++ b/tests/verify.sh
@@ -5,11 +5,11 @@ for f in \
"$ROOT/install.sh" "$ROOT/uninstall.sh" "$ROOT/install-omarchy.sh" "$ROOT/INSTALLIEREN.sh" \
"$ROOT/build.sh" "$ROOT/packaging/build-deb.sh" "$ROOT/packaging/build-rpm.sh" \
"$ROOT/packaging/build-arch.sh" "$ROOT/packaging/build-tarball.sh" "$ROOT/packaging/build-all.sh" \
- "$ROOT/scripts/gitea-release.sh" "$ROOT/tests/gitea-release-helper.sh"; do
+ "$ROOT/scripts/gitea-release.sh" "$ROOT/tests/gitea-release-helper.sh" "$ROOT/tests/mode-independence.sh"; do
bash -n "$f"
done
(cd "$ROOT/backend" && gofmt -w cmd/citizen-launcher && go test ./... && go vet ./...)
-"$ROOT/build.sh"
+bash "$ROOT/build.sh"
[[ "$("$ROOT/backend/bin/citizen-launcher" --version)" == "$(tr -d '[:space:]' < "$ROOT/VERSION")" ]]
[[ ! -n "$(gofmt -l "$ROOT/backend/cmd/citizen-launcher")" ]]
python3 - <<'PY' "$ROOT"
@@ -22,6 +22,12 @@ release=(root/'.gitea/workflows/release.yml').read_text()
assert 'gh release' not in release
assert 'gitea.api_url' in release and 'gitea.token' in release
assert 'actions/upload-artifact' not in release and 'actions/download-artifact' not in release
+
+import re
+for wf in [root/'.gitea/workflows/ci.yml', root/'.gitea/workflows/release.yml']:
+ text=wf.read_text()
+ bad=re.findall(r'(?m)^\s*(?:run:\s*)?(\./[^\s]+\.sh)(?:\s|$)', text)
+ assert not bad, f'workflow executes shell script directly: {wf}: {bad}'
print('Gitea workflow yaml: OK')
PY
echo 'Citizen Launcher verification: OK'