Skip to content

Commit 003819b

Browse files
committed
Add secure GitHub Actions for CI and release publishing
- CI workflow builds and validates the .deb on push/PR (no upload) - Release workflow attaches .deb only when a GitHub Release is published - Pin third-party actions to commit SHAs; minimal permissions - Dependabot for weekly github-actions updates - Document release process and hardening in README
1 parent 6c48016 commit 003819b

5 files changed

Lines changed: 154 additions & 3 deletions

File tree

.github/dependabot.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Keep pinned GitHub Actions updated via reviewed Dependabot PRs.
2+
version: 2
3+
updates:
4+
- package-ecosystem: github-actions
5+
directory: /
6+
schedule:
7+
interval: weekly
8+
groups:
9+
github-actions:
10+
patterns:
11+
- "*"

.github/workflows/ci.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Validate .deb builds on push/PR. Does not publish artifacts.
2+
name: CI
3+
4+
on:
5+
push:
6+
branches: [main]
7+
pull_request:
8+
branches: [main]
9+
10+
# Supply-chain hardening: default least privilege for all jobs.
11+
permissions:
12+
contents: read
13+
14+
concurrency:
15+
group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
build-deb:
20+
runs-on: ubuntu-24.04
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
24+
25+
- name: Install packaging tools
26+
run: sudo apt-get update && sudo apt-get install -y rsync dpkg-dev
27+
28+
- name: Build .deb
29+
run: ./build-deb.sh
30+
31+
- name: Verify package metadata
32+
run: |
33+
deb="$(ls -1 build/debian/streamdeck-openpnp_*_all.deb | head -1)"
34+
test -n "$deb"
35+
dpkg-deb -I "$deb" | grep -q 'Package: streamdeck-openpnp'
36+
dpkg-deb -I "$deb" | grep -q 'libnotify-bin'
37+
dpkg-deb -c "$deb" | grep -q './usr/bin/streamdeck-run'
38+
echo "Built: $deb ($(du -h "$deb" | cut -f1))"

.github/workflows/release.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Build and attach the .deb only when a GitHub Release is published.
2+
# Creating a tag alone does not publish; draft/pre-release releases are ignored.
3+
name: Release
4+
5+
on:
6+
release:
7+
types: [published]
8+
9+
permissions:
10+
contents: write
11+
12+
concurrency:
13+
group: release-${{ github.event.release.id }}
14+
cancel-in-progress: false
15+
16+
jobs:
17+
build-and-upload:
18+
# Never run for forked copies of the workflow.
19+
if: github.repository == 'tlf30/lumenpnp-streamdeck'
20+
runs-on: ubuntu-24.04
21+
steps:
22+
- name: Checkout release tag
23+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
24+
with:
25+
ref: ${{ github.event.release.tag_name }}
26+
27+
- name: Resolve package version
28+
id: version
29+
run: |
30+
tag="${{ github.event.release.tag_name }}"
31+
version="${tag#v}"
32+
if ! printf '%s' "$version" | grep -Eq '^[0-9]+(\.[0-9]+)*(-[0-9A-Za-z.-]+)?$'; then
33+
echo "Release tag must look like v0.1.0 (got: $tag)" >&2
34+
exit 1
35+
fi
36+
echo "version=$version" >> "$GITHUB_OUTPUT"
37+
echo "Building streamdeck-openpnp_$version_all.deb"
38+
39+
- name: Install packaging tools
40+
run: sudo apt-get update && sudo apt-get install -y rsync dpkg-dev
41+
42+
- name: Build .deb
43+
env:
44+
VERSION: ${{ steps.version.outputs.version }}
45+
run: ./build-deb.sh
46+
47+
- name: Verify artifact name
48+
run: |
49+
expected="build/debian/streamdeck-openpnp_${{ steps.version.outputs.version }}_all.deb"
50+
test -f "$expected"
51+
ls -la "$expected"
52+
53+
- name: Upload to GitHub Release
54+
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2.2.1
55+
with:
56+
files: build/debian/streamdeck-openpnp_${{ steps.version.outputs.version }}_all.deb
57+
fail_on_unmatched_files: true

README.md

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ Optional `notify-send` popups for lock/unlock, idle lock, bridge offline, blocke
138138
- `libhidapi-libusb0`
139139
- `python3-venv`, `python3-pip`
140140
- OpenPnP with a configured machine (actuator names `VAC1` / `VAC2` expected for vacuum keys)
141-
- Desktop: `libnotify-bin` (`notify-send`) for notifications — optional
141+
- Desktop: `libnotify-bin` (`notify-send`) for notifications (installed as a package dependency)
142142

143143
---
144144

@@ -366,7 +366,7 @@ See [HID-NOTES.md](HID-NOTES.md) for protocol details.
366366
| `OpenPnP bridge not running` | Restart OpenPnP; confirm `Startup.py` symlink |
367367
| First button press missed | Ensure only one HID client is running; use current controller (HID read/write decoupling fix) |
368368
| Permission denied on `/dev/hidraw*` | Run `sudo udevadm control --reload-rules && sudo udevadm trigger`; replug |
369-
| Notifications silent | Install `libnotify-bin`; check `notifications_enabled` |
369+
| Notifications silent | Check `notifications_enabled`; verify `notify-send` is available |
370370
| Bridge changes ignored | **Restart OpenPnP** (not just the controller) |
371371
| Controller changes ignored | `systemctl --user restart streamdeck` or `./run` |
372372

@@ -404,6 +404,51 @@ streamdeck/
404404

405405
---
406406

407+
## Releases
408+
409+
The `.deb` is built and uploaded **only when a GitHub Release is published** — not on every push.
410+
411+
### Publish a new version
412+
413+
1. Update `VERSION` default in `build-deb.sh` if needed (the release workflow passes the tag).
414+
2. Commit and push to `main`.
415+
3. Create a tag matching the version, e.g. `v0.1.0`.
416+
4. On GitHub: **Releases → Draft a new release** → choose the tag → **Publish release**.
417+
5. The [Release workflow](.github/workflows/release.yml) builds `streamdeck-openpnp_<version>_all.deb` and attaches it to that release.
418+
419+
Install from a release asset:
420+
421+
```bash
422+
curl -LO https://github.com/tlf30/lumenpnp-streamdeck/releases/download/v0.1.0/streamdeck-openpnp_0.1.0_all.deb
423+
sudo apt install ./streamdeck-openpnp_0.1.0_all.deb
424+
streamdeck-setup-user
425+
systemctl --user enable --now streamdeck
426+
```
427+
428+
### CI vs release workflows
429+
430+
| Workflow | Trigger | Publishes `.deb`? |
431+
|----------|---------|-------------------|
432+
| [CI](.github/workflows/ci.yml) | Push / PR to `main` | No — build verification only |
433+
| [Release](.github/workflows/release.yml) | Release **published** | Yes — attached to the release |
434+
435+
### GitHub Actions hardening
436+
437+
These workflows follow supply-chain best practices:
438+
439+
- **Pinned actions** to full commit SHAs (not floating `@v4` tags).
440+
- **Least-privilege `permissions`**`contents: read` for CI; `contents: write` only on release upload.
441+
- **No release on PRs or tags alone** — only `release: published`.
442+
- **Repository guard** — release job runs only on `tlf30/lumenpnp-streamdeck`.
443+
- **Dependabot** weekly PRs for action updates (`.github/dependabot.yml`).
444+
445+
Recommended repository settings (GitHub → Settings → Actions):
446+
447+
- **Fork pull request workflows:** Do not run (prevents untrusted workflow code from accessing secrets).
448+
- **Workflow permissions:** Read repository contents and packages permissions (workflows elevate only where needed).
449+
450+
---
451+
407452
## License
408453

409454
[MIT License](LICENSE) — Copyright (c) 2026 LumenPNP.

build-deb.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ Version: ${VERSION}
7070
Section: misc
7171
Priority: optional
7272
Architecture: ${ARCH}
73-
Depends: python3 (>= 3.10), python3-venv, python3-pip, libhidapi-libusb0, systemd | systemd-standalone
73+
Depends: python3 (>= 3.10), python3-venv, python3-pip, libhidapi-libusb0, libnotify-bin, systemd | systemd-standalone
7474
Maintainer: LumenPNP <support@lumenpnp.com>
7575
Description: Stream Deck + XL controller for OpenPnP / LumenPNP
7676
Installs the Stream Deck controller service, OpenPnP bridge startup script,

0 commit comments

Comments
 (0)