Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ on:
- ".github/workflows/deploy-docs.yml"
- "apps/site/**"
- "packaging/repositories/apt-channel.json"
- "packaging/repositories/fedora-channel.json"
- "apps/docs/**"
- "assets/product-screenshot.png"
- "package.json"
Expand Down
83 changes: 83 additions & 0 deletions .github/workflows/publish-fedora.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: Publish Fedora Repository

on:
workflow_call:
inputs:
tag:
type: string
required: true
operation:
type: string
default: publish
workflow_dispatch:
inputs:
operation:
description: Publish a stable release, refresh expiry, or roll back to a retained revision
type: choice
options: [publish, refresh, rollback]
default: publish
tag:
description: Existing stable release tag for publish
type: string
revision:
description: Retained repository revision SHA-256 for rollback
type: string
schedule:
- cron: "53 5 * * 1"

permissions:
contents: read

concurrency:
group: fedora-repository-production
cancel-in-progress: false

jobs:
publish:
if: >-
${{
vars.FEDORA_REPOSITORY_ENABLED == 'true' &&
(github.ref == format('refs/heads/{0}', github.event.repository.default_branch) ||
(github.workflow == 'Release' && startsWith(github.ref, 'refs/tags/v')))
}}
runs-on: ubuntu-24.04
timeout-minutes: 35
environment: packages-production
container:
image: fedora:44@sha256:be9d65e2344d805cc11114319c685ecaa96b6d9b4350a0a6460cdb931babbd19
steps:
- name: Install repository and workflow tools
run: >-
dnf install -y
createrepo_c dnf git gh gnupg2 nodejs openssh-clients openssl python3 rpm-build rpm-sign

- name: Checkout publisher
uses: actions/checkout@v7.0.0
with:
fetch-depth: 0
persist-credentials: false

- name: Build, publish, and verify repository
env:
GH_TOKEN: ${{ github.token }}
OPERATION: ${{ inputs.operation || 'refresh' }}
RELEASE_TAG: ${{ inputs.tag }}
ROLLBACK_REVISION: ${{ inputs.revision }}
FEDORA_REPOSITORY_URL: ${{ vars.FEDORA_REPOSITORY_URL }}
FEDORA_REPOSITORY_HOST: ${{ vars.FEDORA_REPOSITORY_HOST }}
FEDORA_REPOSITORY_ROOT: ${{ vars.FEDORA_REPOSITORY_ROOT }}
FEDORA_SSH_PORT: ${{ vars.FEDORA_SSH_PORT || '22' }}
FEDORA_SIGNING_FINGERPRINT: ${{ vars.FEDORA_SIGNING_FINGERPRINT }}
FEDORA_SSH_PRIVATE_KEY: ${{ secrets.FEDORA_SSH_PRIVATE_KEY }}
FEDORA_SSH_KNOWN_HOSTS: ${{ secrets.FEDORA_SSH_KNOWN_HOSTS }}
FEDORA_SIGNING_KEY: ${{ secrets.FEDORA_SIGNING_KEY }}
FEDORA_SIGNING_PASSPHRASE: ${{ secrets.FEDORA_SIGNING_PASSPHRASE }}
run: bash scripts/publish-fedora-workflow.sh

- name: Upload public verification and activation record
uses: actions/upload-artifact@v7.0.1
with:
name: loopwire-fedora-publication-${{ github.run_id }}
path: dist/fedora-publication
if-no-files-found: error
retention-days: 90
10 changes: 10 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -513,3 +513,13 @@ jobs:
tag: ${{ needs.publish-release.outputs.tag }}
operation: publish
secrets: inherit

publish-fedora:
name: Publish signed Fedora channel
needs: publish-release
if: ${{ vars.FEDORA_REPOSITORY_ENABLED == 'true' && !contains(needs.publish-release.outputs.tag, '-') }}
uses: ./.github/workflows/publish-fedora.yml
with:
tag: ${{ needs.publish-release.outputs.tag }}
operation: publish
secrets: inherit
2 changes: 2 additions & 0 deletions .github/workflows/web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
- ".github/workflows/web.yml"
- "apps/site/**"
- "packaging/repositories/apt-channel.json"
- "packaging/repositories/fedora-channel.json"
- "apps/docs/**"
- "assets/product-screenshot.png"
- "README.md"
Expand All @@ -32,6 +33,7 @@ on:
- ".github/workflows/web.yml"
- "apps/site/**"
- "packaging/repositories/apt-channel.json"
- "packaging/repositories/fedora-channel.json"
- "apps/docs/**"
- "assets/product-screenshot.png"
- "README.md"
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/workflow-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
- "scripts/test-ci-impact.rb"
- "scripts/test-ci-workflow-paths.rb"
- "scripts/test-apt-workflow.rb"
- "scripts/test-fedora-workflow.rb"
- "scripts/*native-package-proof-snapshot.mjs"
- "scripts/verify-github-workflows.sh"
- "scripts/verify-requirements.sh"
Expand All @@ -23,6 +24,7 @@ on:
- "scripts/test-ci-impact.rb"
- "scripts/test-ci-workflow-paths.rb"
- "scripts/test-apt-workflow.rb"
- "scripts/test-fedora-workflow.rb"
- "scripts/*native-package-proof-snapshot.mjs"
- "scripts/verify-github-workflows.sh"
- "scripts/verify-requirements.sh"
Expand Down
5 changes: 3 additions & 2 deletions .planning/STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ gsd_state_version: 1.0
milestone: v0.5
milestone_name: GitHub Operator Setup
status: Ready for Review
last_updated: "2026-09-05T14:08:23Z"
last_updated: "2026-09-05T15:03:31Z"
last_activity: 2026-09-05
progress:
total_phases: 1
Expand All @@ -27,7 +27,7 @@ See: .planning/PROJECT.md (updated 2026-07-03)
Phase: 19 of 19 complete
Plan: 19.1 — Hardened GitHub Actions Setup
Status: Ready for review in PR #9
Last activity: 2026-09-05 - completed quick task 260905-kyo: signed APT repository development and clean-guest proof
Last activity: 2026-09-05 - completed quick task 260905-mhp: signed Fedora repository development and clean-guest proof


## Blockers / Concerns
Expand Down Expand Up @@ -94,6 +94,7 @@ Last activity: 2026-09-05 - completed quick task 260905-kyo: signed APT reposito
| 260905-hia | Minimal landing identity, GSAP reactions and screenshot proofs in PR #40 | 2026-09-05 | 6e84a9a | [260905-hia-landing-identity](./quick/260905-hia-landing-identity/) |
| 260905-i4l | Scope CI to affected files while retaining release validation | 2026-09-05 | f9bc0d8 | [260905-i4l-scope-ci](./quick/260905-i4l-scope-ci/) |
| 260905-kyo | Signed APT repository development and clean-guest lifecycle proof | 2026-09-05 | 639cbbb | [260905-kyo-signed-apt](./quick/260905-kyo-signed-apt/) |
| 260905-mhp | Signed Fedora repository development and clean-guest lifecycle proof | 2026-09-05 | e73c5bb | [260905-mhp-signed-fedora](./quick/260905-mhp-signed-fedora/) |

## Accumulated Context

Expand Down
57 changes: 57 additions & 0 deletions .planning/quick/260905-mhp-signed-fedora/260905-mhp-PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
status: implementing
issue: 36
depends_on: 45
---

# Signed Fedora repository development

Goal: complete every development task in #36 and open a dedicated PR containing `resolves #36`. This branch is an
intentional stack on #35/PR #45 because the Fedora channel reuses its reviewed SSH/POSIX publication, protected
environment, public activation, and guest-proof foundations. Production provider ownership, credentials, signing
identity and first public activation remain the separately listed human operational tasks.

## Decisions

- Choose a project-owned repository over COPR. It indexes the exact OpenSSL-authenticated release RPM, controls when
the RPM is signed and verified, supports reviewed revision/CAS/retention/recovery semantics, and can be tested
locally and over the same restricted SSH origin. COPR rebuilds from source and owns signing/publication timing, so
its output would need distinct provider build evidence and would not be the existing release artifact.
- Initial scope is Fedora 44 x86_64 only. #37 adds openSUSE independently after this PR is open.
- The repository-distributed copy of the GitHub Release RPM receives a separate OpenPGP RPM signature before its
final repository hash and lifecycle evidence are recorded. The source release hash and distributed hash stay
distinct and traceable.
- Require both `gpgcheck=1` for package signatures and `repo_gpgcheck=1` for the detached OpenPGP signature over
`repodata/repomd.xml`. No local-RPM signature exception applies to the repository path.
- Retain immutable signed RPMs and content-addressed repodata indefinitely in v1. Publication must serialize writers,
require an expected revision, reject immutable collisions, recover interruption, and publish metadata only after
every package/content object exists. The implementation must make clients either verify a complete revision or
fail safely during the promotion boundary; exact commit semantics are recorded after generator/publisher tests.
- Metadata expires after 30 days and gets protected weekly refresh. Rollback selects a retained package set, signs
fresh metadata, and documents the explicit DNF downgrade needed on already-upgraded clients.
- The checked-in Fedora channel remains pending. Existing signed direct-download and automatic-installer paths stay
functional until a human reviews the production public proof record and commits activation data.

## Work lanes

1. `fedora_repo_protocol`: exact release authentication, RPM/repository signing, createrepo metadata, manifest,
retention/rollback and real DNF/tamper tests in a pinned Fedora toolchain.
2. `fedora_publisher`: local/SSH POSIX publication, commit semantics, CAS/locks/recovery, immutable retention, actual
SSH and HTTP/cache tests.
3. `fedora_guest`: isolated clean Fedora 44 KVM lifecycle and strict raw evidence verifier, including package
signatures, installed payload hashes, providers and a real GUI window.
4. `fedora_docs`: provider comparison, pending/verified website gate and complete user/operator documentation.
5. Root integration: scoped setup/public verification, protected release/refresh/rollback workflow, configuration
contracts, CI gates, browser fixtures, final review, issue checklist and PR delivery.

## Required verification

- Real DNF with repository and package signature checks accepts correct content and rejects wrong/unsigned/tampered
RPMs and metadata. Version/architecture/target and downgrade rules are independently verified.
- Publication proves writer exclusion, CAS, ordering/commit behavior, idempotence, interruption recovery, permissions,
immutable retention, rollback, actual SSH transport, and public cache behavior without production credentials.
- A clean checksum-pinned Fedora 44 KVM guest performs repository install, reinstall, fixture upgrade, explicit
rollback/downgrade, removal and repository removal against the final committed development code. Raw proof binds
source/distributed hashes, signer, origin, versions, installed bytes, providers and GUI behavior.
- Pending and verified-fixture browser states, workflow/action syntax, documentation, focused tests and full project
gates pass. Public production remains disabled and no human task is reported complete without its real evidence.
88 changes: 88 additions & 0 deletions .planning/quick/260905-mhp-signed-fedora/260905-mhp-SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
status: complete
issue: 36
depends_on: 45
---

# Signed Fedora repository development

Issue: https://github.com/sandwichfarm/loopwire/issues/36

## Result and stack

The Fedora 44 x86_64 development work is complete. This branch intentionally stacks on #35/PR #45 to reuse its
reviewed SSH/POSIX publication, protected environment, activation gate, and KVM harness. The dedicated Fedora channel
record remains `pending`; the separate Human operational tasks still own production hosting, signing identity,
GitHub configuration, first public publication, and website activation. Until then the existing signed direct RPM and
automatic installer remain visible.

## Development checklist evidence

1. **Provider evaluation:** the maintainer runbook compares COPR and project-owned delivery across output provenance,
signing, Fedora targeting, promotion, proof, retention, and rollback. Project-owned was selected because it consumes
the exact project-authenticated release RPM, signs only a staged copy, controls publication and produces local/CI
proof. COPR output would be a separate provider build needing provider-specific evidence.
2. **Package path:** the generator accepts only Fedora 44 x86_64 `loopwire-VERSION-1.fc44.x86_64.rpm`, while allowing
the known signed openSUSE sibling in the real GitHub Release. It verifies the OpenSSL release signature, signed
checksum, RPM digest, NEVRA and public release manifest before repository processing. Source release and distributed
hashes are recorded separately; the source GitHub RPM is never mutated.
3. **Signing:** `rpmsign` applies an RSA/SHA-256 OpenPGP package signature to the staged repository copy.
`repodata/repomd.xml.asc` separately authenticates SHA-256 metadata objects. Both are verified using isolated RPM
and GnuPG databases pinned to the expected primary fingerprint. Passphrases travel only through protected files.
4. **Publication/rollback:** the Fedora publisher retains RPMs, fingerprint keys, checksum-named repodata, and private
snapshots indefinitely in v1. It validates before writes, locks the origin, requires revision CAS, rejects
immutable collisions, writes the new signature then atomically commits `repomd.xml`, journals every checkpoint,
and recovers interrupted or explicitly reviewed expired transactions. Real DNF fails closed during the brief mixed
signature/XML state and succeeds after recovery. Rollback freshly signs the retained package set.
5. **Protected automation:** Publish Fedora Repository uses a checksum-pinned Fedora 44 container and supports a
release call, manual publish/refresh/rollback, and weekly refresh. `FEDORA_REPOSITORY_ENABLED=true` plus the
`packages-production` environment gates all writes. Stable publication waits for the existing GitHub Release and
evidence gates, re-downloads public assets, publishes over pinned SSH, and verifies every HTTPS-served byte before
producing a reviewable activation record.
6. **Bootstrap:** the repeat-safe helper targets Fedora 44 x86_64, verifies the HTTPS key's full fingerprint, writes
only the managed `.repo` and fingerprint key file, and requires `gpgcheck=1`, `repo_gpgcheck=1`, `sslverify=1`,
`skip_if_unavailable=False`. Dry-run has no network/writes; removal preserves other repositories, installed packages
and RPM-database trust. Docs explain inspecting/removing previously accepted RPM keys during rotation or compromise.
7. **Regression tests:** real DNF accepts only valid package and repodata signatures and rejects wrong signers,
unsigned/tampered RPMs and changed metadata. Tests cover name/version/release/architecture, real release sibling
assets, version order, retention, fresh rollback, deterministic fixed-date candidates, encrypted keys, unsafe paths,
concurrent locks, CAS, every interruption checkpoint, permissions, actual SSH without remote GPG, Nginx cache/404
headers and real DNF recovery from a mismatched signature/XML transition.
8. **Clean Fedora lifecycle:** a checksum-pinned Fedora 44 KVM guest consumes the actual public v0.1.0 Fedora RPM,
authenticated through the project release key, SHA256SUMS, release-assets manifest, public release commit and tar
RELEASE metadata. The repository-signed baseline is installed/reinstalled through DNF, upgraded to the explicitly
synthetic `+dnffixture1`, downgraded to the public baseline, removed, and its repository removed. Proof binds DNF
origin, embedded signatures, source/distributed hashes, installed `/usr` bytes, providers, backend JSON, GUI linkage
and a real X11 window. Fixture keys use an isolated RPM database that is removed on every exit.
9. **Docs/UI:** Fedora homepage, install guide, support matrix, release guide, user guide, operator runbook, packaging
docs, navigation and release notes are updated. Pending preserves the existing authenticated local-RPM path;
verified-fixture browser proof switches only Fedora to `sudo dnf install loopwire` and its separate setup link.
DNF's custom-deadline replay limitation is explicit. Production activation remains human-owned and the repository
is never described as a default Fedora repository.

## Verification

- Final `pnpm check` passed: project verification, types, 295 workspace tests, 22 Rust tests, native/package gates,
production builds, static-site verification, and both APT/Fedora repository suites.
- `pnpm verify:rpm-repository` passed in the pinned Fedora 44 image: 13 generator, 20 publisher, 7 bootstrap,
6 public HTTPS, 3 workflow preflight, 34 raw proof-verifier and 4 channel-gate cases.
- The publisher suite exercised actual SSH and DNF5. DNF rejected the intentionally interrupted signature/XML pair;
recovery restored a valid repository. Nginx syntax and live cache/404 headers passed.
- The Fedora 44 KVM lifecycle produced 122 evidence files at `e73c5bb` and passed the independent verifier. Baseline
source SHA-256 is `5a163db0acd1d2f8c73f8cff1b4cc05f12a3d811bfedaf681ea46f460d4d1fb3`, matching the public release manifest.
- Pending and activated-fixture Chromium runs passed the nine platform panels, commands, keyboard/copy failure and
recovery, no-JavaScript fallback, responsive widths, signal motion/reduced-motion/visibility checks, and Fedora
setup link/guide command. The checked-in channel was restored to pending.
- Workflow contracts, actionlint, ShellCheck, Python/Node/Ruby/Bash syntax, docs/build checks and whitespace passed.
A comprehensive review's public-release provenance finding was fixed and approved on targeted re-review.

## Boundaries

The issue's five Human operational tasks remain unchecked. No production host, TLS/DNS, account, OpenPGP identity,
SSH credential, GitHub environment value, repository publication, or website activation was created or changed.
The project verifier enforces the custom signed metadata deadline; DNF itself verifies signatures but does not enforce
that project-specific expiry tag, so HTTPS/origin control and monitoring remain part of operations.

Power-loss and network filesystems were not exercised; production requires local POSIX flock/fsync/atomic-rename
semantics. The KVM repository signer, TLS CA and upgrade version are disposable fixture material. Only the baseline
source RPM is the actual published v0.1.0 Fedora artifact.
2 changes: 2 additions & 0 deletions apps/docs/docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export default defineConfig({
items: [
{ text: "Install", link: "/guide/install" },
{ text: "APT Repository", link: "/guide/apt-repository" },
{ text: "Fedora Repository", link: "/guide/fedora-repository" },
{ text: "Basic Usage", link: "/guide/basic-usage" },
{ text: "Configurations", link: "/guide/configurations" },
{ text: "Audio Backends", link: "/guide/backends" },
Expand All @@ -62,6 +63,7 @@ export default defineConfig({
{ text: "VM Matrix", link: "/developer/vm-matrix" },
{ text: "Release", link: "/developer/release" },
{ text: "APT Repository Operations", link: "/developer/apt-repository" },
{ text: "Fedora Repository Operations", link: "/developer/fedora-repository" },
{ text: "Release Notes", link: "/developer/release-notes" }
]
},
Expand Down
Loading