Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
7287d56
feat(release): Enable overwriting of existing files when attaching re…
rafaself Feb 27, 2026
c4b0897
feat(editor): Add zoom controls with presets and best fit option
rafaself Feb 27, 2026
6b0e629
feat: Add installation script for Flatpak bundle and GNOME shortcut c…
rafaself Feb 27, 2026
9ea3d0e
feat: Enhance installation script with Print Screen integration and r…
rafaself Feb 27, 2026
d5b3f23
feat: Add Makefile and installation scripts for improved setup and GN…
rafaself Feb 27, 2026
0e2d743
feat(ci): Add script security and integrity checks to CI workflow
rafaself Feb 27, 2026
3cc289d
feat: Enhance installation process with Flatpak bundle support and im…
rafaself Feb 27, 2026
71c9ecb
feat: Update Makefile and README for improved installation process an…
rafaself Feb 27, 2026
b11b12a
feat: Add Flatpak dependency checks and installation to Makefile; inc…
rafaself Feb 27, 2026
ce8fa51
feat: Implement uninstall functionality with user data preservation o…
rafaself Feb 27, 2026
7c9a340
feat: Add auto-capture feature and enhance screenshot functionality; …
rafaself Feb 27, 2026
23eb60f
feat: Add optional global CLI command for easier access to Screenux
rafaself Feb 27, 2026
efa5c00
feat: Add app icon for desktop launcher integration and update instal…
rafaself Feb 27, 2026
6c22d84
feat: Add support for light and dark theme icons; update installer an…
rafaself Feb 27, 2026
a5fc8ee
feat: Add CONTRIBUTING.md and LICENSE files; update README for projec…
rafaself Feb 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,75 @@ permissions:
contents: read

jobs:
script-security-integrity:
name: Script Security & Integrity
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install shell tooling
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends shellcheck shfmt

- name: ShellCheck (static analysis)
run: |
mapfile -t script_files < <(git ls-files '*.sh')
[[ ${#script_files[@]} -gt 0 ]] || { echo "No shell scripts found."; exit 0; }
shellcheck -x "${script_files[@]}"

- name: shfmt (format enforcement)
run: |
mapfile -t script_files < <(git ls-files '*.sh')
[[ ${#script_files[@]} -gt 0 ]] || { echo "No shell scripts found."; exit 0; }
shfmt -d -i 2 -ci -sr "${script_files[@]}"

- name: Policy checks (high-risk patterns)
run: |
set -euo pipefail

mapfile -t script_files < <(git ls-files '*.sh')
[[ ${#script_files[@]} -gt 0 ]] || { echo "No shell scripts found."; exit 0; }

fail=0

check_forbidden_pattern() {
local label="$1"
local regex="$2"
if grep -RInE -- "${regex}" "${script_files[@]}"; then
echo "::error::Forbidden pattern detected (${label})"
fail=1
fi
}

check_forbidden_pattern "curl pipe to shell" '(^|[;&|[:space:]])curl([^\n]|\\\n)*\|[[:space:]]*(ba)?sh([[:space:]]|$)'
check_forbidden_pattern "wget pipe to shell" '(^|[;&|[:space:]])wget([^\n]|\\\n)*\|[[:space:]]*(ba)?sh([[:space:]]|$)'
check_forbidden_pattern "sudo usage in scripts" '^[[:space:]]*sudo[[:space:]]+'

if grep -RInE -- '(^|[;&|[:space:]])(curl|wget)[[:space:]][^#\n]*(http|https)://' "${script_files[@]}"; then
echo "::error::Potential unpinned remote download detected (curl/wget URL usage)."
fail=1
fi

if [[ "${fail}" -ne 0 ]]; then
echo "Policy checks failed. Remove forbidden patterns or harden download verification."
exit 1
fi

- name: Generate installer SHA256 checksum
run: |
mkdir -p artifacts
sha256sum scripts/install/install-screenux.sh > artifacts/install-screenux.sh.sha256

- name: Upload checksum artifact
uses: actions/upload-artifact@v4
with:
name: install-screenux-sha256
path: artifacts/install-screenux.sh.sha256

quality-and-security:
name: Quality & Security
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/release-artifacts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,4 @@ jobs:
files: |
screenux-screenshot.flatpak
screenux-screenshot.flatpak.sha256
overwrite_files: true
53 changes: 53 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Contributing to Screenux Screenshot

Thanks for contributing. Keep changes focused, secure, and aligned with the
project's offline-first behavior.

## Ground rules

- Keep PRs small and scoped to one concern.
- Preserve existing style and structure.
- Do not add network-dependent behavior.
- Prefer secure defaults and minimal privileges.

## Development workflow (TDD first)

1. Add or update a failing test for the behavior change.
2. Implement the smallest code change to make it pass.
3. Refactor while keeping tests green.

## Local setup

```bash
python3 -m pip install -r requirements-dev.txt
```

Run app locally:

```bash
./screenux-screenshot
```

## Validation before opening a PR

Run the project checks relevant to your change:

```bash
python3 -m py_compile src/screenux_screenshot.py
pytest -q
```

If your change touches shell scripts, also run shell checks used in CI.

## Commit and PR guidance

- Use clear commit messages in imperative mood.
- Include test updates with behavior changes.
- Describe user-visible impact in the PR description.
- Keep documentation in sync when behavior or workflow changes.

## Security and privacy expectations

- Keep runtime behavior offline-only.
- Do not broaden Flatpak/runtime permissions unless strictly required.
- Maintain safe file handling and local URI validation behavior.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 rafa

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
81 changes: 81 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
SHELL := /usr/bin/env bash

INSTALLER := ./install-screenux.sh
UNINSTALLER := ./uninstall-screenux.sh
APP_ID := io.github.rafa.ScreenuxScreenshot
FLATPAK_MANIFEST := flatpak/io.github.rafa.ScreenuxScreenshot.json
FLATPAK_BUILD_DIR ?= build-dir
FLATPAK_REPO_DIR ?= repo
FLATPAK_BUNDLE ?= ./screenux-screenshot.flatpak
BUNDLE ?= $(FLATPAK_BUNDLE)
FLATPAK_REMOTE ?= flathub
FLATPAK_REMOTE_URL ?= https://flathub.org/repo/flathub.flatpakrepo
FLATPAK_RUNTIME_VERSION ?= 47
FLATPAK_PLATFORM_REF ?= org.gnome.Platform//$(FLATPAK_RUNTIME_VERSION)
FLATPAK_SDK_REF ?= org.gnome.Sdk//$(FLATPAK_RUNTIME_VERSION)

.PHONY: help build-flatpak-bundle ensure-flatpak-build-deps install install-flatpak install-print-screen uninstall uninstall-preserve-data check-install-scripts

help:
@echo "Screenux helper targets"
@echo ""
@echo " make build-flatpak-bundle [FLATPAK_BUNDLE=./screenux-screenshot.flatpak]"
@echo " make install [BUNDLE=./screenux-screenshot.flatpak]"
@echo " make install-print-screen [BUNDLE=./screenux-screenshot.flatpak]"
@echo " make uninstall"
@echo " make uninstall-preserve-data"
@echo " make check-install-scripts"

build-flatpak-bundle: ensure-flatpak-build-deps
@command -v flatpak-builder >/dev/null 2>&1 || ( \
echo "flatpak-builder not found."; \
echo "Install it, then retry:"; \
echo " Debian/Ubuntu: sudo apt-get install -y flatpak-builder flatpak"; \
echo " Fedora: sudo dnf install -y flatpak-builder flatpak"; \
echo " Arch: sudo pacman -S --needed flatpak-builder flatpak"; \
exit 1)
@flatpak-builder --force-clean --repo="$(FLATPAK_REPO_DIR)" "$(FLATPAK_BUILD_DIR)" "$(FLATPAK_MANIFEST)"
@flatpak build-bundle "$(FLATPAK_REPO_DIR)" "$(FLATPAK_BUNDLE)" io.github.rafa.ScreenuxScreenshot
@echo "Bundle created: $(FLATPAK_BUNDLE)"

ensure-flatpak-build-deps:
@command -v flatpak >/dev/null 2>&1 || ( \
echo "flatpak not found."; \
echo "Install it, then retry:"; \
echo " Debian/Ubuntu: sudo apt-get install -y flatpak"; \
echo " Fedora: sudo dnf install -y flatpak"; \
echo " Arch: sudo pacman -S --needed flatpak"; \
exit 1)
@if flatpak info "$(FLATPAK_PLATFORM_REF)" >/dev/null 2>&1 && flatpak info "$(FLATPAK_SDK_REF)" >/dev/null 2>&1; then \
echo "Flatpak runtime deps already installed ($(FLATPAK_RUNTIME_VERSION))."; \
else \
echo "Installing missing Flatpak runtime deps: $(FLATPAK_PLATFORM_REF), $(FLATPAK_SDK_REF)"; \
flatpak remote-add --user --if-not-exists "$(FLATPAK_REMOTE)" "$(FLATPAK_REMOTE_URL)"; \
flatpak install -y --user "$(FLATPAK_REMOTE)" "$(FLATPAK_PLATFORM_REF)" "$(FLATPAK_SDK_REF)"; \
fi

install:
@if [[ -f "$(BUNDLE)" ]]; then \
$(INSTALLER) --bundle "$(BUNDLE)"; \
else \
$(INSTALLER); \
fi

install-print-screen:
@if [[ -f "$(BUNDLE)" ]]; then \
$(INSTALLER) --bundle "$(BUNDLE)" --print-screen; \
else \
$(INSTALLER) --print-screen; \
fi

install-flatpak: install

uninstall:
@$(UNINSTALLER)

uninstall-preserve-data:
@$(UNINSTALLER) --preserve-user-data

check-install-scripts:
@bash -n install-screenux.sh uninstall-screenux.sh scripts/install/install-screenux.sh scripts/install/uninstall-screenux.sh scripts/install/lib/common.sh scripts/install/lib/gnome_shortcuts.sh
@echo "Installer scripts syntax: OK"
83 changes: 72 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,53 @@ Screenux focuses on a clean capture flow: take a screenshot, optionally annotate
- Capture with `Take Screenshot`
- Status updates: `Ready`, `Capturing...`, `Saved: <path>`, `Cancelled`, `Failed: <reason>`
- Built-in editor for quick annotations (shapes/text)
- Editor zoom controls with `Best fit` and quick presets (`33%` to `2000%`)
- Timestamped output names with safe, non-overwriting writes
- Packaged app icon for desktop launcher integration

## 🚀 Quick start
## Install

### 1) Install system dependencies
```bash
./install-screenux.sh --bundle /path/to/screenux-screenshot.flatpak
```

- `python3`
- `python3-gi`
- GTK4 introspection (`gir1.2-gtk-4.0` on Debian/Ubuntu)
- `xdg-desktop-portal` plus a desktop backend (GNOME/KDE/etc.)
The installer creates a desktop entry and installs app icons at `~/.local/share/icons/hicolor/scalable/apps/` so launcher/taskbar icon lookup works reliably. It includes theme variants (`io.github.rafa.ScreenuxScreenshot-light.svg` and `io.github.rafa.ScreenuxScreenshot-dark.svg`) and refreshes the local icon cache when GTK cache tools are available.

### 2) Clone the project
Optional GNOME Print Screen shortcut:

```bash
git clone https://github.com/rafaself/Screenux.git
cd Screenux
./install-screenux.sh --bundle /path/to/screenux-screenshot.flatpak --print-screen
```

### 3) Run Screenux
This maps `Print` to `screenux-screenshot --capture`, which opens Screenux and immediately starts the capture flow.

If Screenux is already installed for your user, you can rerun:

```bash
./screenux-screenshot
./install-screenux.sh
```

Optional global CLI command (`screenux`):

```bash
sudo tee /usr/local/bin/screenux >/dev/null <<'EOF'
#!/usr/bin/env bash

/home/${USER}/dev/Screenux/screenux-screenshot
EOF
sudo chmod +x /usr/local/bin/screenux
```

## Uninstall

```bash
./uninstall-screenux.sh
```

Preserve app data in `~/.var/app/io.github.rafa.ScreenuxScreenshot`:

```bash
./uninstall-screenux.sh --preserve-user-data
```

## 🖱️ Usage
Expand Down Expand Up @@ -112,6 +137,7 @@ Quality gates include:
- Compile validation (`python -m compileall -q src`)
- Automated tests (`pytest -q`)
- Security checks (`bandit`, `pip-audit`)
- Shell script hardening (`ShellCheck`, `shfmt`, policy checks, installer SHA256 artifact)
- Dependency checks (`pip check`, dependency review action)
- Build/package validation (launcher, Flatpak manifest, desktop entry, Docker Compose, Docker build)

Expand Down Expand Up @@ -150,6 +176,33 @@ Notes:

### Flatpak

Requirements:

- `flatpak`
- `flatpak-builder`

Install tools (examples):

```bash
# Debian/Ubuntu
sudo apt-get install -y flatpak flatpak-builder

# Fedora
sudo dnf install -y flatpak flatpak-builder

# Arch
sudo pacman -S --needed flatpak flatpak-builder
```

Build a local bundle and install with Print Screen mapping:

```bash
make build-flatpak-bundle FLATPAK_BUNDLE=./screenux-screenshot.flatpak
make install-print-screen BUNDLE=./screenux-screenshot.flatpak
```

`make build-flatpak-bundle` now auto-checks Flatpak build deps and, when missing, installs `org.gnome.Platform//47` and `org.gnome.Sdk//47` from Flathub in user scope.

```bash
flatpak-builder --force-clean build-dir flatpak/io.github.rafa.ScreenuxScreenshot.json
flatpak-builder --run build-dir flatpak/io.github.rafa.ScreenuxScreenshot.json screenux-screenshot
Expand All @@ -163,3 +216,11 @@ Flatpak permissions stay intentionally narrow (portal access + Desktop filesyste
- Screenshot sources are validated as local, readable `file://` URIs.
- Config parsing is defensive (invalid/non-object/oversized files are ignored).
- Save operations use exclusive file creation to avoid accidental overwrite.

## 🤝 Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for development workflow and PR guidance.

## 📄 License

This project is licensed under the MIT License. See [LICENSE](LICENSE).
5 changes: 5 additions & 0 deletions assets/icons/io.github.rafa.ScreenuxScreenshot-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions assets/icons/io.github.rafa.ScreenuxScreenshot-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions assets/icons/io.github.rafa.ScreenuxScreenshot.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion flatpak/io.github.rafa.ScreenuxScreenshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
"install -Dm755 src/screenux_screenshot.py /app/share/screenux/screenux_screenshot.py",
"install -Dm755 src/screenux_editor.py /app/share/screenux/screenux_editor.py",
"install -Dm755 src/screenux_window.py /app/share/screenux/screenux_window.py",
"install -Dm644 io.github.rafa.ScreenuxScreenshot.desktop /app/share/applications/io.github.rafa.ScreenuxScreenshot.desktop"
"install -Dm644 io.github.rafa.ScreenuxScreenshot.desktop /app/share/applications/io.github.rafa.ScreenuxScreenshot.desktop",
"install -Dm644 assets/icons/io.github.rafa.ScreenuxScreenshot.svg /app/share/icons/hicolor/scalable/apps/io.github.rafa.ScreenuxScreenshot.svg",
"install -Dm644 assets/icons/io.github.rafa.ScreenuxScreenshot-light.svg /app/share/icons/hicolor/scalable/apps/io.github.rafa.ScreenuxScreenshot-light.svg",
"install -Dm644 assets/icons/io.github.rafa.ScreenuxScreenshot-dark.svg /app/share/icons/hicolor/scalable/apps/io.github.rafa.ScreenuxScreenshot-dark.svg"
],
"sources": [
{
Expand Down
5 changes: 5 additions & 0 deletions install-screenux.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
exec bash "${SCRIPT_DIR}/scripts/install/install-screenux.sh" "$@"
Loading
Loading