Add reproducible build system, native Unraid plugin, and WebUI
Build Packages / Build .txz packages (push) Failing after 9s
Lint / ShellCheck (push) Failing after 43s
Lint / Validate .plg XML (push) Successful in 10s
Lint / EditorConfig (push) Failing after 6s

- versions.env pins podman, conmon, crun, netavark, aardvark-dns, passt,
  and fuse-overlayfs to verified upstream source checksums; SlackBuild
  recipes, scripts/build-packages.sh, checksums.sh, release.sh, and
  update-versions.sh implement the reproducible pipeline; GitHub Actions
  workflows build in a Slackware container and publish releases without
  committing any binaries.

- plugin/podman.plg installs/updates/removes all eight packages (the
  seven components plus the plugin's own unraid-podman scaffolding
  package) via upgradepkg, using the official Unraid array-event hook
  mechanism (event/disks_mounted, event/stopping) instead of editing
  /boot/config/go. rc.podman and the sbin/ helper scripts implement
  storage creation, config seeding/sync, preflight checks, autostart
  with per-container Safe-Mode, and package verify/update/rollback.

- webui/plugins/podman implements the Dashboard, Containers, Pods,
  Images, Volumes, Networks, Logs, Terminal, Compose, and Settings
  panels against the approved mockup (webui/mockups/prototype.html),
  talking to podman system service exclusively via PodmanClient.php
  (libpod REST API over the Unix socket), with two documented
  exceptions: Terminal's one-shot exec model and Compose's use of the
  podman compose CLI, since libpod has no REST equivalent for either.

- docs/ARCHITECTURE.md and docs/ROADMAP.md record the design decisions
  and honest current status (syntax-checked, unit- and
  integration-tested against fake sockets/servers; not yet run against
  a real Unraid/Podman/Slackware system).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-11 10:51:14 +00:00
co-authored by Claude Sonnet 5
parent 58ffc0c226
commit e2fefcdf9c
124 changed files with 9611 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
# Default owners for everything in the repo, until per-area owners are named.
# See https://docs.github.com/articles/about-codeowners for syntax.
* @OWNER
# Example of future area-based ownership once the team grows:
# /packages/ @OWNER @packaging-maintainer
# /webui/ @OWNER @webui-maintainer
# /plugin/ @OWNER
+51
View File
@@ -0,0 +1,51 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to a positive environment:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Focusing on what is best for the community
Examples of unacceptable behavior:
- The use of sexualized language or imagery, and unwelcome sexual attention
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information without explicit permission
## Enforcement Responsibilities
Project maintainers are responsible for clarifying and enforcing standards of
acceptable behavior and will take appropriate corrective action in response to
any behavior deemed inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces (issues, pull requests,
discussions) and when an individual is officially representing the project in
public spaces.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the maintainers via the contact listed in
[SECURITY.md](SECURITY.md). All complaints will be reviewed and investigated
promptly and fairly.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org),
version 2.1, available at
https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
+39
View File
@@ -0,0 +1,39 @@
---
name: Bug report
about: Report a problem with the plugin
title: "[Bug] "
labels: bug
assignees: ""
---
## Description
A clear description of what went wrong.
## Environment
- Unraid version:
- unraid-podman plugin version:
- Podman version (`podman version`, if available):
- Storage backend (Cache pool / Array disk), pool filesystem (XFS/BTRFS/ZFS):
- Docker also installed/running? (yes/no):
## Steps to reproduce
1. ...
2. ...
## Expected behavior
## Actual behavior
## Relevant logs
Attach or paste relevant excerpts from:
- `/mnt/*/system/podman/logs/podman-service.log`
- Unraid System Log (`Tools -> System Log`)
- `rc.podman status` output
Please redact any secrets (registry credentials, tokens) before posting.
## Additional context
+8
View File
@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Security vulnerability
url: https://github.com/OWNER/unraid-podman/security/advisories/new
about: Please report security issues privately — see SECURITY.md, not a public issue.
- name: General discussion / questions
url: https://github.com/OWNER/unraid-podman/discussions
about: Usage questions and design discussions that aren't a concrete bug or feature request.
+23
View File
@@ -0,0 +1,23 @@
---
name: Feature request
about: Suggest an enhancement or new capability
title: "[Feature] "
labels: enhancement
assignees: ""
---
## Problem
What are you trying to do that isn't currently possible or is unnecessarily hard?
## Proposed solution
## Alternatives considered
## Which architecture phase does this fit?
See [docs/ROADMAP.md](../../docs/ROADMAP.md) — e.g. MVP / WebUI / Rootless /
Docker-optional / Pods. If unsure, leave blank; this helps triage against the
existing phased plan rather than scope-creeping the current phase.
## Additional context
+32
View File
@@ -0,0 +1,32 @@
## Summary
<!-- What does this PR change and why? -->
## Related issue(s)
<!-- Closes #... -->
## Type of change
- [ ] Documentation
- [ ] Packaging (`packages/`)
- [ ] Plugin core (`.plg`, `rc.podman`, `sbin/*`)
- [ ] WebUI (`webui/`)
- [ ] CI / tooling (`.github/`, `scripts/`)
- [ ] Other
## Checklist
- [ ] Changes follow the design in [docs/ARCHITECTURE.md](../docs/ARCHITECTURE.md);
any deliberate deviation is explained below
- [ ] Persistence discipline respected (state written under `/etc`, `/usr`, `/var`
at runtime is also mirrored to `/boot/config/plugins/podman/` or array/cache)
- [ ] No systemd usage introduced
- [ ] Docker coexistence preserved (no shared storage/network/iptables-chain names)
- [ ] `CHANGELOG.md` updated under `[Unreleased]` (if user-facing)
- [ ] Relevant docs under `docs/` updated
- [ ] Tested on a real or virtualized Unraid instance (describe below), where applicable
## How was this tested?
## Notes for reviewers
+37
View File
@@ -0,0 +1,37 @@
# Security Policy
## Threat model context
This plugin runs **rootful Podman**. Its API socket (`/var/run/podman/podman.sock`)
is root-equivalent on the host, in the same way Docker's `docker.sock` is. See
[docs/ARCHITECTURE.md](../docs/ARCHITECTURE.md#19-sicherheitsbetrachtungen-phase-1-rootful)
for the full rationale. Treat any bug that affects socket permissions, WebUI
authentication, or container-to-host isolation as security-sensitive by default.
## Reporting a vulnerability
Please **do not** open a public GitHub issue for security vulnerabilities.
Instead, use one of:
- GitHub [private security advisories](https://github.com/OWNER/unraid-podman/security/advisories/new)
for this repository, or
- Email the maintainers at `security@OWNER-DOMAIN` (placeholder — update once a
contact address exists).
Please include:
- A description of the issue and its potential impact.
- Steps to reproduce (Unraid version, plugin version, storage backend).
- Whether the issue requires local access, network access, or a malicious
container image to trigger.
## Supported versions
This project has not yet cut a stable release. Until a `1.0.0` release, only the
latest `main` branch / most recent tag is supported with security fixes.
## Disclosure process
We aim to acknowledge reports within 5 business days and to agree on a
coordinated disclosure timeline before any public write-up.
+92
View File
@@ -0,0 +1,92 @@
name: Build Packages
# Builds the seven Slackware .txz packages defined under packages/
# (podman, conmon, crun, netavark, aardvark-dns, passt, fuse-overlayfs)
# inside a Slackware container, verifies + consolidates their checksums, and
# uploads the result as a workflow artifact.
#
# Intentionally does NOT commit any built binary back to the repository —
# packages/**, *.txz, dist/ are all git-ignored (see .gitignore). Artifacts
# only ever leave this workflow via the "Upload build artifacts" step below
# (retained by GitHub Actions, not the repo) or, for tagged releases, via
# release.yml attaching them to a GitHub Release.
#
# See docs/ARCHITECTURE.md section 5 (Paketmanagement).
on:
push:
branches: [main]
paths:
- "packages/**"
- "versions.env"
- "scripts/**"
- ".github/workflows/build-packages.yml"
pull_request:
paths:
- "packages/**"
- "versions.env"
- "scripts/**"
- ".github/workflows/build-packages.yml"
workflow_dispatch:
inputs:
packages:
description: >
Space-separated package names to build (default: all seven).
Example: "podman conmon"
required: false
default: ""
workflow_call:
outputs:
artifact-name:
description: "Name of the uploaded dist/ artifact"
value: ${{ jobs.build.outputs.artifact-name }}
# Pin the Slackware build image by tag here. vbatts/slackware is a
# long-standing, widely used Slackware Docker image; swap this (and ideally
# pin by digest) if the project standardizes on a different/self-hosted
# base image. See scripts/ci/setup-slackware-buildenv.sh for how missing
# build dependencies are bootstrapped on top of whatever this image ships.
env:
SLACKWARE_IMAGE: "vbatts/slackware:15.0"
jobs:
build:
name: Build .txz packages
runs-on: ubuntu-latest
container:
image: ${{ env.SLACKWARE_IMAGE }}
outputs:
artifact-name: ${{ steps.artifact-name.outputs.value }}
steps:
- name: Install git and tar (needed before actions/checkout can run)
run: |
(command -v git && command -v tar) || \
(echo "!! base image is missing git/tar — see SLACKWARE_IMAGE in this workflow" && exit 1)
- uses: actions/checkout@v4
- name: Set up Slackware build environment
run: scripts/ci/setup-slackware-buildenv.sh
- name: Build packages
run: scripts/build-packages.sh ${{ github.event.inputs.packages }}
- name: Verify and consolidate checksums
run: scripts/checksums.sh
- name: Compute artifact name
id: artifact-name
run: echo "value=podman-packages-${{ github.sha }}" >> "$GITHUB_OUTPUT"
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ steps.artifact-name.outputs.value }}
path: |
dist/*.txz
dist/*.sha256
dist/*.md5
dist/CHECKSUMS.sha256
dist/CHECKSUMS.md5
if-no-files-found: error
retention-days: 14
+53
View File
@@ -0,0 +1,53 @@
name: Lint
# Static analysis over shell scripts (ShellCheck) and the .plg/XML manifest
# (xmllint) on every push and pull request. Mirrors scripts/dev/lint.sh for
# local use.
on:
push:
branches: [main]
pull_request:
jobs:
shellcheck:
name: ShellCheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install ShellCheck
run: |
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends shellcheck
- name: Run ShellCheck
run: |
set -eu
# shellcheck disable=SC2038 (find | xargs is fine here, filenames
# in this repo never contain spaces/newlines)
find plugin/rc.d plugin/sbin scripts -type f \
\( -name '*.sh' -o -name 'rc.*' -o -name '*.SlackBuild' \) \
-print0 \
| xargs -0 shellcheck --severity=warning --external-sources
xmllint:
name: Validate .plg XML
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install libxml2-utils
run: |
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends libxml2-utils
- name: Validate podman.plg is well-formed XML
run: xmllint --noout plugin/podman.plg
editorconfig:
name: EditorConfig
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: editorconfig-checker/action-editorconfig-checker@main
+96
View File
@@ -0,0 +1,96 @@
name: Release
# Publishes a GitHub Release for a version tag (vX.Y.Z).
#
# By design, this workflow does NOT bump versions or modify podman.plg
# itself — that happens locally via `scripts/release.sh <version>`, which a
# maintainer reviews, commits, and tags *before* pushing the tag (see that
# script's own printed instructions). This workflow's only job is to:
# 1. Rebuild all packages from the tagged commit in a clean Slackware
# container (reproducibility check + provenance — we don't trust
# whatever a maintainer happened to have in their local dist/).
# 2. Verify checksums match what's already committed in plugin/podman.plg
# at this tag (catches a release.sh run that wasn't followed by a
# matching commit — see the "Verify plg matches build" step).
# 3. Create the GitHub Release and attach the .txz packages, checksum
# manifests, and podman.plg.
#
# See docs/ARCHITECTURE.md section 13 (Updates).
on:
push:
tags:
- "v*.*.*"
permissions:
contents: write
jobs:
build:
name: Build release packages
uses: ./.github/workflows/build-packages.yml
publish:
name: Publish GitHub Release
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Download built packages
uses: actions/download-artifact@v4
with:
name: ${{ needs.build.outputs.artifact-name }}
path: dist
- name: Re-verify checksums
run: scripts/checksums.sh dist
- name: Verify plugin/podman.plg matches these artifacts
# scripts/release.sh should already have been run locally, and its
# resulting podman.plg changes committed as part of this tag, before
# the tag was pushed. This step fails the release loudly if that
# didn't happen, instead of publishing a release whose plg points at
# MD5s that don't match the .txz files actually attached below.
run: |
set -eu
for f in dist/*.txz.md5; do
expected_md5=$(awk '{print $1}' "$f")
txz_name=$(basename "${f%.md5}")
if ! grep -qF "$expected_md5" plugin/podman.plg; then
echo "!! $txz_name's checksum ($expected_md5) is not referenced in plugin/podman.plg." >&2
echo "!! Did you forget to run scripts/release.sh and commit its changes before tagging?" >&2
exit 1
fi
done
echo "All package checksums are referenced in plugin/podman.plg — OK."
- name: Extract version from tag
id: version
run: echo "value=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
- name: Extract changelog section for this version
id: changelog
run: |
awk -v ver="${{ steps.version.outputs.value }}" '
$0 ~ "^## \\[" ver "\\]" { found=1; print; next }
found && /^## \[/ { exit }
found { print }
' CHANGELOG.md > /tmp/release-notes.md
echo "path=/tmp/release-notes.md" >> "$GITHUB_OUTPUT"
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
name: "unraid-podman v${{ steps.version.outputs.value }}"
body_path: ${{ steps.changelog.outputs.path }}
# v0.x tags are treated as pre-releases until the plugin reaches a
# first stable 1.0.0 — see docs/ROADMAP.md.
prerelease: ${{ startsWith(steps.version.outputs.value, '0.') }}
files: |
dist/*.txz
dist/*.sha256
dist/*.md5
dist/CHECKSUMS.sha256
dist/CHECKSUMS.md5
plugin/podman.plg