veilor-os/docs/research/2026-05-05-agent-wave/08-ci-hardening.md
veilor-org 4e9782a18a docs: 9-agent research wave findings — v0.5.32 blocker map
Logs the full output of the 9-agent deep-dive run on 2026-05-05 to
docs/research/2026-05-05-agent-wave/. Pulls every actionable finding
into one indexed location so v0.5.32 planning has a paper trail.

Files:
  docs/research/2026-05-05-agent-wave/README.md             — index
  docs/research/2026-05-05-agent-wave/01-...real-hardware.md — Plymouth + LUKS edge cases
  docs/research/2026-05-05-agent-wave/02-...firstboot-ux.md  — SDDM + first-boot UX
  docs/research/2026-05-05-agent-wave/03-...spike-plan.md    — bootc-image-builder 1-week spike
  docs/research/2026-05-05-agent-wave/04-...tier-2.md         — AppArmor + nftables + audit + homed
  docs/research/2026-05-05-agent-wave/05-...launch.md         — threat model + v0.7 launch checklist
  docs/research/2026-05-05-agent-wave/06-...log-capture.md    — virtio-9p host-share for anaconda logs
  docs/research/2026-05-05-agent-wave/07-...skel-branding.md  — /etc/skel gap audit
  docs/research/2026-05-05-agent-wave/08-...ci-hardening.md   — SHA-pin actions + SBOM + SLSA L3
  docs/research/2026-05-05-agent-wave/09-...failure-modes.md  — real-hardware pessimistic audit

Plus the prior linter-applied:
  docs/ROADMAP.md      — Lessons learned section, v0.5.32 active block,
                          v0.6 promotion of veilor-postinstall + veilor-doctor,
                          v0.7 bootc spike scheduled
  docs/THREAT-MODEL.md  — drafted by Agent 5; in/out scope, comparison
                          matrix, v0.7 launch checklist

Top blockers identified for v0.5.32 (cross-cited in README):
  1. Suspend/resume wifi death (kernel.modules_disabled=1)
  2. veilor-firstboot.service WantedBy=graphical.target
  3. kernel-upgrade grub drift
  4. USBGuard hash-rules problem (already learned on onyx)
  5. firewalld blocks tailscale0
  6. /etc/skel/ empty
  7. virtio-9p log capture replaces broken virtio-serial path

Wave + verifier pattern (per ROADMAP lessons learned #4) validated:
9 parallel agents on distinct topics produced converging blocker
list. The same pattern landed v0.5.31 four-bug fix from the prior
4-agent verification wave on v0.5.30 outcome.
2026-05-05 14:52:53 +01:00

4.7 KiB

Build-iso CI hardening

Agent 8 of 9-agent wave, 2026-05-05.

State of play

  • Workflows: build-iso.yml, lint.yml, Release Checksums (auto)
  • Secrets/variables: none configured — only ambient GITHUB_TOKEN
  • Repo: private, MIT, no Pages, no Dependabot, no branch protection (Pro-gated until public flip)
  • Container: registry.fedoraproject.org/fedora:43 (tag, not digest)
  • Actions: actions/checkout@v4, addnab/docker-run-action@v3, softprops/action-gh-release@v2, ludeeus/action-shellcheck@masterall unpinned to SHA
  • gum download: pinned by SHA256 ✓
  • Kickstart repos: releases/43/Everything + updates/43/Everythingboth rolling, byte-different daily

Top 5 immediate (S effort, ship in v0.5.32)

# Item Why
1 Pin all actions to commit SHA + add .github/dependabot.yml for github-actions Supply-chain — @master on shellcheck is live-takeover vector; v3/v4 tags are mutable
2 Pin Fedora container to digest (registry.fedoraproject.org/fedora:43@sha256:...) One-line change; eliminates "container drift" repro class
3 Add permissions: block at workflow level (contents: read default), override per-job contents: write is workflow-wide; least-privilege the lint job
4 Generate SBOM via anchore/sbom-action, attach to release Free, ~30 lines, journalist-readable
5 Add actions/attest-build-provenance@v2 for SLSA L3 attestation on ISO + parts Free, GH-native, id-token: write only

v0.4 release-eng roadmap (confirmed/added)

  • Confirmed: Sigstore/cosign signing of ISOs (already in roadmap)
  • Add: Fedora compose-ID pinning per release tag — switch --baseurl to kojipkgs.fedoraproject.org/compose/branched/Fedora-43-...n.X/compose/Everything/x86_64/os/ for stable releases (rolling for ci-latest)
  • Add: Reproducible-Builds.org diffoscope job comparing 2 sequential builds of same SHA — gate on byte-equality
  • Add: harden-runner (StepSecurity) audit-mode pass to enumerate egress; promote to block-mode in v0.5
  • Add: When repo flips public (v0.7), enable secret scanning + push protection + private vuln reporting + branch protection (require ≥1 review, status checks: lint + ksvalidate + build, no force-push)
  • Add: OIDC id-token: write only in tag-release job (not on main push) — keysless cosign signing scoped to release events

YAML diffs

1. Workflow-level permissions + per-job override

permissions:
  contents: read

jobs:
  build:
    permissions:
      contents: write       # gh-release
      id-token: write       # cosign keyless + attestation
      attestations: write

2. SHA-pin actions

- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332     # v4.1.7
- uses: addnab/docker-run-action@4f65375b03d588f307b7a3b0a8bb50f8b58a85b9 # v3
- uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 # v2.1.0

(SHAs to be re-checked at apply-time; dependabot keeps them current)

3. Pin Fedora digest

image: registry.fedoraproject.org/fedora:43@sha256:<DIGEST>

Capture once via skopeo inspect --raw docker://registry.fedoraproject.org/fedora:43 | jq -r .config.digest and bump on each releasever bump.

4. SBOM + attestation + cosign

- name: Install cosign
  uses: sigstore/cosign-installer@d7d6e07a3ddf0f9a4f8b3b9e3f1d1a5ce8e9b5b3 # v3.7.0

- name: Sign ISO parts (keyless)
  if: github.event_name == 'release'
  run: |
    cd build/out
    for f in *.part-*; do cosign sign-blob --yes "$f" \
      --output-signature "$f.sig" --output-certificate "$f.pem"; done    

- name: Generate SBOM (SPDX)
  uses: anchore/sbom-action@e8d2a6937ecead383dfe75190d104edd1f9c5751 # v0.17.4
  with:
    path: build/out
    format: spdx-json
    output-file: build/out/veilor-os.spdx.json

- name: Build provenance attestation
  uses: actions/attest-build-provenance@7668571508540a607bdfd90a87a560489fe372eb # v2.1.0
  with:
    subject-path: 'build/out/*.part-*'

5. New .github/dependabot.yml

version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule: { interval: "weekly" }
    groups:
      actions: { patterns: ["*"] }

6. Timeout

Keep at 90min. Largest observed runs ~70min; trimming would false-fail Fedora-mirror-slow days. No change.

Q&A

  • Secrets in use: none. Only ambient GITHUB_TOKEN. Once public, enable secret scanning + push protection (free for public repos).
  • Pages: not deployed from this repo. Docs site out-of-scope here.
  • Dependency review: only gum fetched out-of-band — already SHA256-pinned. Add actions/dependency-review-action on PRs once public.