Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a7fce54
Support native CVS cameras and refresh XPS hardware packages
CybexHQ Sep 26, 2026
f93054f
Merge remote-tracking branch 'origin/main'
CybexHQ Sep 26, 2026
86f185f
Implement ISO desktop upgrades, installer qualification and signed re…
DigitalPals Sep 26, 2026
8c619ea
Include agent skill sources in isolated ISO builds and verify subkey …
DigitalPals Sep 26, 2026
8c02842
Add a bounded ephemeral release runner and stabilize CI fixtures
DigitalPals Sep 26, 2026
36de2ed
Exercise real installer controls and constrain legacy qualification
DigitalPals Sep 26, 2026
1128d32
Verify installed locale and robustly bootstrap console test access
DigitalPals Sep 26, 2026
121f0b7
Offer every supported Anaconda installer locale
DigitalPals Sep 26, 2026
73a8ebe
Capture bounded installer state when browser qualification fails
DigitalPals Sep 26, 2026
2526d4e
Bound iVentoy refresh polling and tolerate transient status timeouts
DigitalPals Sep 26, 2026
a1713ff
Create linger state directory during offline ISO provisioning
DigitalPals Sep 26, 2026
cd53e64
Handle bounded installer initialization contention through the UI
DigitalPals Sep 26, 2026
586f3dd
Check browser test dependencies before starting qualification VMs
DigitalPals Sep 26, 2026
6369f26
Handle sequential shell IPC and observed Dutch console OCR in qualifi…
DigitalPals Sep 26, 2026
835603e
Report bounded redacted installed audit failures
DigitalPals Sep 26, 2026
eaa42b4
Enforce installed absence checks and tolerate vanished IPC clients
DigitalPals Sep 26, 2026
37dbdad
Change the effective shell default in upgrade preference fixtures
DigitalPals Sep 26, 2026
b52003d
Record current ISO lifecycle candidate and qualification evidence
DigitalPals Sep 26, 2026
cd24f0f
Preserve precise Python failures in bounded installed audit diagnostics
DigitalPals Sep 26, 2026
482ec43
Verify the requested recovery point using snapshot index semantics
DigitalPals Sep 26, 2026
79b16cc
Accept Fedora hardlink timezone aliases during installed audits
DigitalPals Sep 26, 2026
6283fec
Log in through SDDM after unlocking a recovery overlay boot
DigitalPals Sep 26, 2026
16e2200
Wait for the expected login session before discovering its terminal
DigitalPals Sep 26, 2026
b31611e
Record passing Dutch encrypted and US plain ISO qualification
DigitalPals Sep 26, 2026
09f28c4
Capture bounded redacted SSH and screen diagnostics on VM readiness f…
DigitalPals Sep 26, 2026
bfd756b
Verify clean guest shutdown after an acknowledged SSH disconnect
DigitalPals Sep 26, 2026
a991a97
Prevent desktop bus descendants from hanging GTK provisioning
DigitalPals Sep 26, 2026
bd04954
Keep VM control sockets independent of artifact path length
DigitalPals Sep 26, 2026
bdb7c59
Record complete ISO lifecycle qualification and artifact cleanup
DigitalPals Sep 26, 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
189 changes: 189 additions & 0 deletions .github/workflows/desktop-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
name: ISO lifecycle qualification

on:
workflow_dispatch:
inputs:
tag:
description: Reviewed release tag matching VERSION
required: true
type: string
baseline_iso:
description: Older supported ISO on the PXE host under /data/pxe/iso
required: true
type: string
workflow_call:
inputs:
tag:
required: true
type: string
baseline_iso:
required: true
type: string
secrets:
CYBEXOS_RPM_SIGNING_KEY:
required: false

permissions:
contents: read

concurrency:
group: cybexos-iso-release
cancel-in-progress: false

jobs:
qualify:
# Debian 13 PXE host: only reviewed main/tag code, with no signing secret
# or desktop-release environment attached to this machine.
if: github.repository == 'DigitalPals/CybexOS' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
runs-on: cybexos-iso-${{ github.run_id }}
timeout-minutes: 360
env:
RELEASE_TAG: ${{ inputs.tag }}
BASELINE_ISO: ${{ inputs.baseline_iso }}
PYTHONDONTWRITEBYTECODE: '1'
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
persist-credentials: false
- name: Prepare isolated release workspace
run: |
set -euo pipefail
work=$(mktemp -d "$RUNNER_TEMP/cybexos-release.XXXXXXXX")
printf 'RELEASE_WORK=%s\n' "$work" >> "$GITHUB_ENV"
test -r /data/pxe/README.md
test -n "$BASELINE_ISO"
systemctl is-active --quiet iventoy.service
image/build --preflight
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: '24'
- name: Install isolated browser test driver
run: |
npm install --prefix "$RELEASE_WORK/browser" --no-audit --no-fund --ignore-scripts playwright-core@1.63.0
printf 'NODE_PATH=%s\n' "$RELEASE_WORK/browser/node_modules" >> "$GITHUB_ENV"
- name: Build and qualify graphical installs, upgrade and recovery
run: |
image/release-gate --execute --output "$RELEASE_WORK/qualification" \
--tag "$RELEASE_TAG" --baseline-iso "$BASELINE_ISO"
- name: Transfer qualified artifacts and reports to the hosted signing job
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: cybexos-qualified-desktop
# The common root is qualification/. Do not upload VM disks, console
# logs, browser state, the builder cache, or the source checkout.
path: |
${{ env.RELEASE_WORK }}/qualification/build/artifacts/
${{ env.RELEASE_WORK }}/qualification/*/qualification.json
${{ env.RELEASE_WORK }}/qualification/release-gate.json
if-no-files-found: error
compression-level: 0
retention-days: 2
- name: Retain bounded qualification evidence
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: cybexos-qualification-reports
path: |
${{ env.RELEASE_WORK }}/qualification/release-gate.json
${{ env.RELEASE_WORK }}/qualification/*/qualification.json
retention-days: 14
if-no-files-found: ignore
- name: Remove task staging
if: always()
run: |
if [[ -n ${RELEASE_WORK:-} && $RELEASE_WORK == "$RUNNER_TEMP"/cybexos-release.* ]]; then
rm -rf -- "$RELEASE_WORK"
fi

sign:
name: Sign qualified desktop artifacts on a hosted Fedora container
needs: qualify
runs-on: ubuntu-latest
environment: desktop-release
timeout-minutes: 120
env:
RELEASE_TAG: ${{ inputs.tag }}
PYTHONDONTWRITEBYTECODE: '1'
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
persist-credentials: false
- name: Reserve space for raw and prepared desktop artifacts
run: |
set -euo pipefail
# This job owns its disposable GitHub-hosted VM. Remove only unused
# preinstalled SDKs; runner tools, Docker and our checkout stay intact.
sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc /usr/local/.ghcup
available=$(df --output=avail -B1 "$RUNNER_TEMP" | tail -n 1)
if (( available < 24 * 1024 * 1024 * 1024 )); then
echo 'Signing requires at least 24 GiB free for raw and prepared artifacts.' >&2
exit 1
fi
work=$(mktemp -d "$RUNNER_TEMP/cybexos-signing.XXXXXXXX")
printf 'RELEASE_WORK=%s\n' "$work" >> "$GITHUB_ENV"
- name: Prepare Fedora 44 RPM signing tools without private key access
run: |
docker build --tag cybexos-release-signing:local - <<'DOCKERFILE'
FROM fedora:44
RUN dnf -y --setopt=install_weak_deps=False install python3 rpm rpm-sign createrepo_c gnupg2 tar gzip && dnf clean all
DOCKERFILE
- name: Download the exact qualified build and reports
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: cybexos-qualified-desktop
path: ${{ env.RELEASE_WORK }}/qualified
- name: Sign RPM and prepare verified release assets
env:
RELEASE_SIGNING_KEY: ${{ secrets.CYBEXOS_RPM_SIGNING_KEY }}
run: |
set -euo pipefail
test -n "$RELEASE_SIGNING_KEY"
# The key enters only this ephemeral hosted container. Its value is
# passed through the environment, never arguments or shell tracing.
docker run --rm --init --interactive \
--name "cybexos-signing-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" \
--env RELEASE_SIGNING_KEY --env RELEASE_TAG --env GITHUB_REPOSITORY \
--env PYTHONDONTWRITEBYTECODE=1 \
--volume "$GITHUB_WORKSPACE:/source:ro" \
--volume "$RELEASE_WORK:/release-work" \
--workdir /source cybexos-release-signing:local bash -s <<'SIGN'
set -euo pipefail
keyhome=/release-work/signing
install -d -m 0700 "$keyhome"
trap 'gpgconf --homedir "$keyhome" --kill all; rm -rf -- "$keyhome"' EXIT
printf '%s' "$RELEASE_SIGNING_KEY" | gpg --homedir "$keyhome" --batch --import
unset RELEASE_SIGNING_KEY
fingerprint=$(python3 -c 'import json; print(json.load(open("image/channels/stable.json"))["fingerprint"])')
baseurl=$(python3 -c 'import json; print(json.load(open("image/channels/stable.json"))["baseurl"])')
image/release-repository /release-work/qualified/build/artifacts/cybexos-desktop-*.rpm \
--output /release-work/signed --public-key image/channels/CYBEXOS-desktop.asc \
--key "$fingerprint" --gnupghome "$keyhome" --baseurl "$baseurl" \
--packages-baseurl "https://github.com/$GITHUB_REPOSITORY/releases/download/$RELEASE_TAG"
reports=()
for scenario in encrypted-us plain-us encrypted-nl plain-nl upgrade; do
reports+=(--qualification "/release-work/qualified/$scenario/qualification.json")
done
image/prepare-github-release --signed-repository /release-work/signed \
--artifacts /release-work/qualified/build/artifacts \
--output /release-work/publication --repository "$GITHUB_REPOSITORY" \
--tag "$RELEASE_TAG" --fingerprint "$fingerprint" "${reports[@]}"
# The container is root; artifacts must be readable by the hosted
# runner's upload action. Secret material is outside this directory.
chmod -R a+rX /release-work/publication
SIGN
- name: Retain qualified assets for the publishing job
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: cybexos-desktop-release
path: ${{ env.RELEASE_WORK }}/publication/
if-no-files-found: error
compression-level: 0
retention-days: 2
- name: Remove signing material and task artifacts
if: always()
run: |
docker rm --force "cybexos-signing-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >/dev/null 2>&1 || true
docker image rm cybexos-release-signing:local >/dev/null 2>&1 || true
if [[ -n ${RELEASE_WORK:-} && $RELEASE_WORK == "$RUNNER_TEMP"/cybexos-signing.* ]]; then
sudo rm -rf -- "$RELEASE_WORK"
fi
24 changes: 2 additions & 22 deletions .github/workflows/live-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,10 @@ name: Live image integration

on:
pull_request:
paths:
- image/**
- roles/apps/**
- roles/base/**
- roles/desktop/**
- roles/boot/**
- roles/dotfiles/**
- assets/**
- VERSION
- inventory/group_vars/all.yml
- .github/workflows/live-image.yml
push:
paths:
- image/**
- roles/apps/**
- roles/base/**
- roles/desktop/**
- roles/boot/**
- roles/dotfiles/**
- assets/**
- VERSION
- inventory/group_vars/all.yml
- .github/workflows/live-image.yml
branches: [main]
workflow_dispatch:
workflow_call:

permissions:
contents: read
Expand Down
72 changes: 68 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,32 @@ concurrency:
cancel-in-progress: false

jobs:
prerequisites:
name: Release prerequisites
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- name: Require reviewed license, version and older ISO
env:
RELEASE_TAG: ${{ github.ref_name }}
BASELINE_ISO: ${{ vars.CYBEXOS_BASELINE_ISO }}
run: |
set -euo pipefail
test -s LICENSE || test -s LICENSE.md
test -n "$BASELINE_ISO"
version=${RELEASE_TAG#v}
scripts/semver validate "$version"
test "$(cat VERSION)" = "$version"

source:
name: Source contract
# The exact job that gates main: same packages, same verified COPR key.
uses: ./.github/workflows/tests.yml

image-source:
name: Image source contract
uses: ./.github/workflows/live-image.yml

vm:
name: Generic Fedora VM install
runs-on: ubuntu-latest
Expand All @@ -32,17 +53,33 @@ jobs:
if test -e /dev/kvm; then sudo chmod a+rw /dev/kvm; fi
- run: ./tests/fedora-vm-convergence

iso:
name: ISO install, upgrade and recovery
needs: [prerequisites, source, image-source, vm]
uses: ./.github/workflows/desktop-release.yml
with:
tag: ${{ github.ref_name }}
baseline_iso: ${{ vars.CYBEXOS_BASELINE_ISO }}
secrets: inherit

publish:
name: Build, attest, and publish release asset
needs: [source, vm]
needs: [source, vm, iso]
runs-on: ubuntu-latest
timeout-minutes: 20
timeout-minutes: 60
permissions:
contents: write
id-token: write
attestations: write
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- name: Download qualified desktop assets
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: cybexos-desktop-release
path: dist/desktop-release
- name: Require a repository distribution license
run: test -s LICENSE || test -s LICENSE.md
- name: Install release build dependencies
run: |
sudo apt-get update
Expand Down Expand Up @@ -117,13 +154,40 @@ jobs:
--generate-notes --title "CybexOS $version" "${prerelease[@]}"
gh release upload "$RELEASE_TAG" \
"dist/cybexos-$version.tar.zst" \
"dist/cybexos-$version.tar.zst.sigstore.jsonl" dist/SHA256SUMS
"dist/cybexos-$version.tar.zst.sigstore.jsonl" dist/SHA256SUMS \
dist/desktop-release/assets/*
gh release edit "$RELEASE_TAG" --draft=false
for attempt in $(seq 1 12); do
for _attempt in $(seq 1 12); do
if test "$(gh api "repos/$GITHUB_REPOSITORY/releases/tags/$RELEASE_TAG" --jq .immutable)" = true; then
exit 0
fi
sleep 5
done
echo "GitHub did not make $RELEASE_TAG immutable after publication" >&2
exit 1

pages:
name: Publish signed desktop repository metadata
needs: publish
# Prerelease assets are downloadable but must never advance stable clients.
if: ${{ !contains(github.ref_name, '-') }}
runs-on: ubuntu-latest
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deploy.outputs.page_url }}
steps:
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: cybexos-desktop-release
path: desktop-release
- uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b
- uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa
with:
path: desktop-release/pages
- name: Deploy verified metadata after RPM assets exist
id: deploy
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e
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 DigitalPals and CybexOS contributors

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.
Loading
Loading