Skip to content

ci: enable matrix-driven multi-variant kernel delivery - #63

Open
Bjordis Collaku (bjordiscollaku) wants to merge 15 commits into
mainfrom
feat/matrix-expansion-ci
Open

ci: enable matrix-driven multi-variant kernel delivery#63
Bjordis Collaku (bjordiscollaku) wants to merge 15 commits into
mainfrom
feat/matrix-expansion-ci

Conversation

@bjordiscollaku

@bjordiscollaku Bjordis Collaku (bjordiscollaku) commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Overview

The CI model is matrix-driven. This repository can deliver multiple kernel variants, each with independent source and package identity, kernel source and ref strategy, configuration fragments, Debian revision, target suites, packaging ref, and Release destination.

Every kernel variant owns exactly two complete matrix rows: one Daily row and one Release row. The matrix resolver expands every suite in those rows into an isolated kernel_variant + suite build leg.

Adding a new kernel variant is a two-row matrix change, not a workflow redesign.

Matrix Model

The current staging-validation rows illustrate the full delivery contract:

Field Daily definition Release definition
Kernel variant qcom-next qcom-next
Suites trixie, forky, resolute trixie, forky
Kernel source qualcomm-linux/kernel qualcomm-linux/kernel
Ref strategy Resolve the latest matching qcom-next-* tag Use the selected release tag
Current kernel ref qcom-next tag family qcom-next-7.2-rc7-20260821
Source package linux-qcom-next linux-qcom-next
Image metapackage linux-image-qcom-next linux-image-qcom-next
Kernel configuration Selected config-fragment set Selected config-fragment set
Debian revision debian_version_stub + suite suffix + ~ debian_version_stub + suite suffix
Packaging ref feat/matrix-expansion-packaging feat/matrix-expansion-packaging
Release destination Not applicable qli-staging

Debian revision is derived, not stored per row. Every variant's Daily and Release rows share one debian_version_stub; a matrix-wide suite_suffix_mapping supplies the suite-specific part so two suites in the same delivery never receive an identical Debian revision. For the current staging stub (0qli+staging1) and mapping (trixie: ~bpo13+1, forky: empty, resolute: ~26.04.1):

Suite Daily Release
Trixie 0qli+staging1~bpo13+1~ 0qli+staging1~bpo13+1
Forky 0qli+staging1~ 0qli+staging1
Resolute 0qli+staging1~26.04.1~ (not a configured Release suite)

This directly fixes a real defect found during target APT validation: Debusine accepted the identical binary package version into both trixie and forky, making the two suites' pool objects ambiguous and returning an HTTP 500 on pool-object download. ci/scripts/derive-debian-revision.sh is the single implementation of the formula; both resolve-matrix.sh and build-kernel-deb.yml's direct-dispatch path call it, so revision derivation cannot drift between the matrix-driven and manual paths.

Each flattened suite leg carries its own values and uses a distinct prepared-source artifact, Debusine child workspace, and publication identity. Parallel suites and future variants therefore cannot share inputs or outputs.

Daily and Release

Daily

Daily is the recurring build and artifact-publication path.

  • Scheduled Daily resolves the full Daily matrix.
  • Manual Daily supports full matrix, selected variant across all suites, and selected variant plus suite.
  • latest_tag resolves the newest matching dated tag. branch_tip resolves the configured branch directly.
  • Debian suites build in Debusine, then their .deb outputs are downloaded from the isolated CI workspace and published to S3.
  • Ubuntu-family suites use the existing Docker build path and publish their outputs to S3.

Release

Release is the controlled package-promotion path.

  • Release is manual only and supports selected variant across all configured Release suites, or selected variant plus suite.
  • It uses the matrix-selected Release tag. It does not resolve a newest tag.
  • Debian source and binary artifacts are built in per-variant, per-suite Debusine CI workspaces.
  • Successful builds are promoted through Debusine package-publish to the selected target workspace.
  • Direct build-kernel-deb.yml dispatches are build-only. Release promotion is initiated exclusively by release.yml.

Architecture

flowchart LR
    IN["Matrix variant + suite input"] --> R{"Resolve suite family"}

    R -->|"trixie · forky"| DEB["Debian path\nbuild-kernel-debusine.yml\nGenerate source package\nSubmit with lib/build\nDebusine builds binaries"]
    R -->|"resolute"| UBU["Ubuntu path\nbuild-kernel-ubuntu.yml\nbuild-kernel.sh in Docker\nBuild binary packages"]

    DEB --> DOUT{"Build type"}
    DOUT -->|Daily| S3["Download .deb files\nPublish to S3"]
    DOUT -->|Release| QLI["Promote source and binaries\nto qli"]
    UBU --> US3["Publish .deb files to S3"]
Loading

Pipeline Overview

flowchart TD
    subgraph triggers[Triggers]
        A1["daily.yml\nScheduled full matrix"]
        A2["daily.yml\nManual full matrix or selected variant and suite"]
        A3["release.yml\nManual selected variant, with optional suite"]
        A4["build-kernel-deb.yml\nManual build-only validation"]
    end

    subgraph matrix[Matrix entry points]
        B1["Daily configure-matrix\nFlatten Daily rows"]
        B2["Daily variant + suite legs\nqcom-next / trixie · forky · resolute"]
        B3["Release configure-matrix\nFlatten Release rows"]
        B4["Release variant + suite legs\nqcom-next / trixie · forky"]
    end

    subgraph orchestrator[Reusable build workflow]
        C1["Resolve suite family"]
        C2["Prepare selected kernel and packaging source\nUpload an isolated prepared-source artifact"]
        C3["Debian build path"]
        C4["Ubuntu build path"]
    end

    subgraph outputs[Outputs]
        D1["Daily S3 artifacts"]
        D2["Release Debusine APT repository"]
    end

    A1 --> B1
    A2 --> B1
    A3 --> B3
    B1 --> B2 --> C1
    B3 --> B4 --> C1
    A4 --> C1
    C1 --> C2
    C2 --> C3 & C4
    C3 --> D1 & D2
    C4 --> D1
Loading

Implementation

  • Replace suite-only orchestration with the structured delivery matrix.
  • Add reusable scripts for matrix validation and flattening, kernel-ref resolution, and LOCALVERSION derivation.
  • Derive each suite's Debian revision from a shared debian_version_stub and matrix-wide suite_suffix_mapping via a new ci/scripts/derive-debian-revision.sh, so Daily and Release rows store one stub instead of a duplicated, suite-blind debian_revision.
  • Pass selected matrix values through the reusable build workflow into the packaging branch.
  • Isolate source artifacts, Debusine workspaces, and publication names by both variant and suite.
  • Route Debian-family suites through source-package generation in the GitHub Debusine builder container, Debusine binary-package builds, and Release promotion.
  • Retain the Ubuntu Docker packaging path and Daily S3 publication path.
  • Add forky to Daily and Release coverage and resolute to Daily coverage.
  • Pin Debian Docker builds to the intended suite.
  • Close template-injection and secrets-over-grant findings in build-kernel.yml and build-kernel-debusine.yml flagged by the repository's required workflow-security scan, moving every ${{ }} reference out of run: script bodies into step-level env:.
  • Document the matrix contract, dispatch choices, delivery flow, ref/version behavior, rollout states, and new-variant onboarding procedure.

Validation

Validation Result
Daily scopes Full matrix, selected variant, and each configured suite completed successfully.
Direct builds Debian and Ubuntu paths, latest-tag, branch-tip, pinned-ref, and advanced overrides completed successfully.
Negative cases Unknown variant, invalid Release suite, unknown config fragment, and nonexistent kernel ref failed at their intended boundaries.
Target validation Generated Qualcomm ARM64 packages installed and booted successfully on target hardware. See Target validation below for the actual commands and output.
Release promotion qcom-next-7.2-rc7-20260821 built and promoted successfully for both trixie and forky in the same run, each receiving its own distinct Debian revision (0qli+staging1~bpo13+1 for trixie, 0qli+staging1 for forky).
Version-collision fix Confirmed at every layer the original defect touched, from S3 artifact naming through Debusine release publication to an actual on-target boot. See Version-collision fix below for the actual commands, filenames, and output.
Staging repository qli-staging carries the full versioned image, image metapackage, versioned and metapackage headers, and debug packages for both trixie and forky, each under its own suite-specific version string.

Target validation

Pulling the trixie package directly onto a live target, before upgrade the three prior kernels (including the previous 20260817 collision-fix validation build) are installed:

debian@debian:~$ dpkg -l | grep linux-image-7
ii  linux-image-7.1.0-rc2-g4e0b0df1c84f         7.1.0~rc2-g4e0b0df1c84f-1                arm64        Linux kernel, version 7.1.0-rc2-g4e0b0df1c84f
ii  linux-image-7.2.0-rc3-qcom-next-20260729    7.2.0~rc3+20260729-0qcom1                arm64        Qualcomm ARM64 Linux kernel image 7.2.0-rc3-qcom-next-20260729
ii  linux-image-7.2.0-rc7-qcom-next-20260817    7.2.0~rc7+20260817-0qli+staging1~bpo13+1 arm64        Qualcomm ARM64 Linux kernel image 7.2.0-rc7-qcom-next-20260817
debian@debian:~$ sudo apt upgrade linux-image-qcom-next
...
Get:2 https://deb.debusine.qualcomm.com/qualcomm/qli-staging trixie/main arm64 linux-image-7.2.0-rc7-qcom-next-20260821 arm64 7.2.0~rc7+20260821-0qli+staging1~bpo13+1 [26.2 MB]
Get:3 https://deb.debusine.qualcomm.com/qualcomm/qli-staging trixie/main arm64 linux-image-qcom-next arm64 7.2.0~rc7+20260821-0qli+staging1~bpo13+1 [1,392 B]
...
Fetched 162 MB in 18s (9,191 kB/s)
...
Unpacking linux-image-7.2.0-rc7-qcom-next-20260821 (7.2.0~rc7+20260821-0qli+staging1~bpo13+1) ...
Unpacking linux-image-qcom-next (7.2.0~rc7+20260821-0qli+staging1~bpo13+1) over (7.2.0~rc7+20260817-0qli+staging1~bpo13+1) ...
...
Setting up linux-image-7.2.0-rc7-qcom-next-20260821 (7.2.0~rc7+20260821-0qli+staging1~bpo13+1) ...
...
update-initramfs: Generating /boot/initrd.img-7.2.0-rc7-qcom-next-20260821
Updating kernel version 7.2.0-rc7-qcom-next-20260821 in systemd-boot...

No Err: lines and no HTTP 500 anywhere in the transfer or install, the exact failure mode this PR fixes. Post-reboot, the target booted the new kernel cleanly and it coexists with all three prior kernels:

debian@debian:~$ dpkg -l | grep linux-image-7
ii  linux-image-7.1.0-rc2-g4e0b0df1c84f         7.1.0~rc2-g4e0b0df1c84f-1                arm64        Linux kernel, version 7.1.0-rc2-g4e0b0df1c84f
ii  linux-image-7.2.0-rc3-qcom-next-20260729    7.2.0~rc3+20260729-0qcom1                arm64        Qualcomm ARM64 Linux kernel image 7.2.0-rc3-qcom-next-20260729
ii  linux-image-7.2.0-rc7-qcom-next-20260817    7.2.0~rc7+20260817-0qli+staging1~bpo13+1 arm64        Qualcomm ARM64 Linux kernel image 7.2.0-rc7-qcom-next-20260817
ii  linux-image-7.2.0-rc7-qcom-next-20260821    7.2.0~rc7+20260821-0qli+staging1~bpo13+1 arm64        Qualcomm ARM64 Linux kernel image 7.2.0-rc7-qcom-next-20260821

debian@debian:~$ uname -r
7.2.0-rc7-qcom-next-20260821

debian@debian:~$ ls /boot/efi/loader/entries/
bc9ca9a5da354d55a221910da4b57135-7.1.0-rc2-g4e0b0df1c84f.conf  bc9ca9a5da354d55a221910da4b57135-7.2.0-rc3-qcom-next-20260729.conf  bc9ca9a5da354d55a221910da4b57135-7.2.0-rc7-qcom-next-20260817.conf  bc9ca9a5da354d55a221910da4b57135-7.2.0-rc7-qcom-next-20260821.conf

debian@debian:~$ dmesg | grep "Linux version"
[    0.000000] Linux version 7.2.0-rc7-qcom-next-20260821 (sbuild@sbuild) (gcc (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44) #1 SMP PREEMPT Fri Aug 21 18:28:01 UTC 2026

All four kernels remain installed side by side with no dpkg conflict, and systemd-boot carries a loader entry for each, confirming the version-collision fix holds: distinct suite-specific revisions produce distinct pool objects, so nothing here collides.

Version-collision fix

suite_suffix_mapping (introduced in this PR) is what makes the target validation above possible: each suite gets its own Debian revision instead of the single shared debian_revision this branch started with, which is what let trixie and forky collide on an identical version in the first place. Daily S3 artifacts for this ref, distinctly versioned per suite:

trixie:
linux-image-7.2.0-rc7-qcom-next-20260821_7.2.0~rc7+20260821-0qli+staging1~bpo13+1~_arm64.deb   25.0 MB
linux-image-7.2.0-rc7-qcom-next-20260821-dbg_7.2.0~rc7+20260821-0qli+staging1~bpo13+1~_arm64.deb   219.1 MB
linux-image-qcom-next_7.2.0~rc7+20260821-0qli+staging1~bpo13+1~_arm64.deb   1.4 KB
linux-headers-7.2.0-rc7-qcom-next-20260821_7.2.0~rc7+20260821-0qli+staging1~bpo13+1~_arm64.deb   9.3 MB
linux-headers-7.2.0-rc7-qcom-next-20260821-dbgsym_7.2.0~rc7+20260821-0qli+staging1~bpo13+1~_arm64.deb   23.1 KB
linux-headers-qcom-next_7.2.0~rc7+20260821-0qli+staging1~bpo13+1~_arm64.deb   1.3 KB

forky:
linux-image-7.2.0-rc7-qcom-next-20260821_7.2.0~rc7+20260821-0qli+staging1~_arm64.deb   25.6 MB
linux-image-7.2.0-rc7-qcom-next-20260821-dbg_7.2.0~rc7+20260821-0qli+staging1~_arm64.deb   218.7 MB
linux-image-qcom-next_7.2.0~rc7+20260821-0qli+staging1~_arm64.deb   1.4 KB
linux-headers-7.2.0-rc7-qcom-next-20260821_7.2.0~rc7+20260821-0qli+staging1~_arm64.deb   9.3 MB
linux-headers-7.2.0-rc7-qcom-next-20260821-dbgsym_7.2.0~rc7+20260821-0qli+staging1~_arm64.deb   23.3 KB
linux-headers-qcom-next_7.2.0~rc7+20260821-0qli+staging1~_arm64.deb   1.3 KB

The Release run's Release to Debusine step reported result=success for both suites, publishing distinct binary-package entries into qli-staging:

trixie:
debian:binary-package    linux-image-7.2.0-rc7-qcom-next-20260821_7.2.0~rc7+20260821-0qli+staging1~bpo13+1_arm64
debian:binary-package    linux-image-7.2.0-rc7-qcom-next-20260821-dbg_7.2.0~rc7+20260821-0qli+staging1~bpo13+1_arm64
debian:binary-package    linux-image-qcom-next_7.2.0~rc7+20260821-0qli+staging1~bpo13+1_arm64
debian:binary-package    linux-headers-7.2.0-rc7-qcom-next-20260821_7.2.0~rc7+20260821-0qli+staging1~bpo13+1_arm64
debian:binary-package    linux-headers-7.2.0-rc7-qcom-next-20260821-dbgsym_7.2.0~rc7+20260821-0qli+staging1~bpo13+1_arm64
debian:binary-package    linux-headers-qcom-next_7.2.0~rc7+20260821-0qli+staging1~bpo13+1_arm64

forky:
debian:binary-package    linux-image-7.2.0-rc7-qcom-next-20260821_7.2.0~rc7+20260821-0qli+staging1_arm64
debian:binary-package    linux-image-7.2.0-rc7-qcom-next-20260821-dbg_7.2.0~rc7+20260821-0qli+staging1_arm64
debian:binary-package    linux-image-qcom-next_7.2.0~rc7+20260821-0qli+staging1_arm64
debian:binary-package    linux-headers-7.2.0-rc7-qcom-next-20260821_7.2.0~rc7+20260821-0qli+staging1_arm64
debian:binary-package    linux-headers-7.2.0-rc7-qcom-next-20260821-dbgsym_7.2.0~rc7+20260821-0qli+staging1_arm64
debian:binary-package    linux-headers-qcom-next_7.2.0~rc7+20260821-0qli+staging1_arm64

Dependencies

Before Merge

  • Merge packaging: enable parameterized multi-variant kernel packages #62 first.
  • Replace the temporary staging overlay with the production configuration in one deliberate follow-up:
    • GitHub environment: Production
    • Release target workspace: qli
    • debian_version_stub (shared by Daily and Release): 0qli
    • Packaging ref: qcom/debian/latest
    • suite_suffix_mapping is suite-identity policy, not a staging artifact; it carries over to production unchanged.
  • Update the matching direct-build default and README rollout text with the same production change.
  • Run and approve final production Daily and Release validation before merging this PR.

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

zizmor found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

Comment thread .github/workflows/release.yml Fixed
Comment thread .github/workflows/release.yml Fixed
Comment thread .github/workflows/build-kernel-debusine.yml Fixed
Comment thread .github/workflows/release.yml Fixed

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a quick look at this (just overall diff), it appears to be in the right kind of shape.

Comment thread .github/workflows/build-kernel-deb.yml Fixed
…ipeline

Introduce a fully parameterized CI matrix that supports multiple build
targets, per-target package naming, per-target config fragment selection,
and a dedicated release workflow that promotes packages to a stable
Debusine workspace.

ci/build-matrix.json:
- New schema replaces the flat {distro} list. Each row carries: type
  (Daily|Release), target_workspace, suites (array -- flattened by
  resolve-matrix.sh), git_clone, branch_or_tag, srcpkg, binpkg,
  kernel_config, debian_revision.
- M1 rows: Daily (latest qcom-next tag, trixie+forky) and Release
  (pinned qcom-next-7.2-rc3-20260722, trixie+forky).

ci/scripts/ (new directory, CI orchestration only):
- resolve-matrix.sh: reads build-matrix.json, filters by --type, expands
  suites arrays into one flat entry per suite, emits compact JSON to stdout.
  Accepts --single-suite for manual dispatch single-target overrides.
  Called by both daily.yml and release.yml.
- resolve-kernel-ref.sh: resolves the kernel ref to build. --latest mode
  queries the remote for the newest qcom-next-*-YYYYMMDD tag using date-
  based sort (not version sort). --ref mode is a validated passthrough for
  pinned release builds. Extracted from the inline pipeline in build-kernel-
  deb.yml where it was fragile and untestable.
- derive-localversion.sh: derives the LOCALVERSION suffix from a kernel ref.
  Tag pattern (qcom-next-<kver>-<YYYYMMDD>) produces -<prefix>-<date>.
  Branch-tip (no date) produces -<ref>-g<short_sha> and requires --sha.
  Extracted from the inline sed pipeline in build-kernel-deb.yml.

daily.yml:
- configure-matrix job delegates to ci/scripts/resolve-matrix.sh --type Daily
  instead of the previous jq pass-through. Handles full matrix (schedule or
  run-full-matrix) and single-suite manual dispatch.
- build job threads all new matrix fields (suite, srcpkg, binpkg,
  kernel-config, debian-revision, git-clone) to build-kernel-deb.yml.
- suite choices updated to include forky.
- Does NOT pass target-workspace (daily builds use the S3 publish path).

release.yml (new):
- workflow_dispatch only, no schedule trigger.
- configure-matrix delegates to resolve-matrix.sh --type Release.
- build job passes latest-tag=false and kernel-branch from the pinned
  branch_or_tag field, plus target-workspace to trigger the Debusine
  release path in build-kernel-debusine.yml.

build-kernel-deb.yml:
- New inputs: suite (replaces distro), git-clone, srcpkg, binpkg,
  kernel-config, debian-revision, target-workspace.
- Resolve kernel ref and derive LOCALVERSION are now thin wrappers around
  ci/scripts/resolve-kernel-ref.sh and ci/scripts/derive-localversion.sh.
- prepare-source.sh invocation passes --srcpkg, --binpkg, --debian-revision,
  --kernel-config through to the packaging branch.
- debusine-build job passes srcpkg and target-workspace to
  build-kernel-debusine.yml.
- forky added to workflow_dispatch suite choices.

build-kernel-debusine.yml:
- New inputs: srcpkg, target-workspace.
- build job exposes srcpkg_version as a job output (from generate-source-
  package step) for use by the release job.
- publish job (S3): runs only when target-workspace is empty (daily path).
- release job (new): runs only when target-workspace is non-empty. Calls
  debusine-action/lib/release to promote packages from the ephemeral CI
  workspace to the stable target workspace. Uses DEBUSINE_RELEASE_TOKEN
  (separate secret with release permissions).

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
The prepare job checks out the packaging branch (qcom/debian/latest) as
its working directory, which does not contain ci/scripts/. The Resolve
kernel ref and Derive LOCALVERSION steps call ci/scripts/resolve-kernel-
ref.sh and ci/scripts/derive-localversion.sh respectively, causing a
'No such file or directory' failure.

Fix: add two steps after the packaging branch checkout that sparse-check
out the CI branch (github.sha, always the main/feature branch that owns
the workflows) into a temporary .ci-branch/ path, copy the scripts into
ci/scripts/, and remove the temporary checkout. The packaging branch has
no ci/ directory so there is no conflict.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
…h invocation

Two fixes:

1. pkg-linux-qcom-ref was not passed from daily.yml/release.yml to
   build-kernel-deb.yml, so the prepare job always checked out
   qcom/debian/latest regardless of which packaging branch was intended.
   This caused prepare-source.sh to be the old version (without --srcpkg,
   --binpkg, --kernel-config flags), which errored on the new flags passed
   by the workflow, leaving debian/changelog ungenerated. The Debusine
   build job then failed with 'cannot open file debian/changelog'.

   Fix: add pkg_linux_qcom_ref as a matrix field and thread it through
   daily.yml and release.yml into build-kernel-deb.yml as pkg-linux-qcom-ref.
   Defaults to qcom/debian/latest when not set in the matrix row.

2. ci/build-matrix.json: set pkg_linux_qcom_ref to
   feat/matrix-expansion-packaging for validation builds so the prepare
   job uses the new prepare-source.sh. Will be updated to qcom/debian/latest
   once feat/matrix-expansion-packaging is merged.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
docker-pkg-build and pkg-builder only support trixie for Debian-family
suites. Forky and sid builds were failing at the 'Build docker image'
step because docker_deb_build.py does not accept forky as a distro.

The docker container is used only for source preparation (prepare-source.sh
runs inside pkg-builder:trixie). The actual suite-specific kernel build
happens inside Debusine, which handles forky and sid natively. Pinning
the docker image to trixie for all Debian-family suites is therefore
correct and sufficient.

Changes:
- build-kernel-deb.yml: add DOCKER_DISTRO env var to the prepare job.
  Resolves to trixie for forky/sid/unstable, passes through the real
  suite for Ubuntu-family (noble, questing, resolute). Both
  docker_deb_build.py and pkg-builder container now use DOCKER_DISTRO.
- build-kernel-debusine.yml: pin debusine-pkg-builder container to
  trixie in both the build and release jobs. The container is used only
  for dpkg-buildpackage -S (source package generation) and lib/release
  (Debusine promotion), neither of which is suite-specific.
- ci/build-matrix.json: add resolute to the Daily suites array. Resolute
  is classified as ubuntu-family by the resolve job and routed through
  build-kernel-ubuntu.yml unchanged. When Debusine gains resolute support,
  only the resolve job classification needs updating -- no matrix change.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
Three silent correctness bugs introduced when the matrix expanded from
one suite per family to N:

1. Artifact name collision (kernel-srcpkg shared across all legs)
   actions/download-artifact resolves a duplicated name to the newest
   artifact, so every consumer received whichever prepare job finished
   last rather than its own tree. Confirmed in run 30053624870: all
   three consumer jobs downloaded artifact 8582070626 (trixie's tree)
   regardless of suite. Suffix the name with the suite at all three
   sites: upload in build-kernel-deb.yml and downloads in
   build-kernel-debusine.yml and build-kernel-ubuntu.yml.

2. JOB_INDEX hardcoded to "0" (Debusine child workspace collision)
   Both Debian-family legs of a run computed the identical child
   workspace name qli-ci-gh-<run_id>-1-0, so only the first
   create_child_workspace succeeded. This was the real cause of every
   forky Debusine failure, not a missing suite configuration on the
   server. Confirmed in run 30053624870: trixie (WR 30423, success at
   23:43:56) and forky (WR 30425, failure at 23:44:04) printed the
   same workspace string. Pass JOB_INDEX: ${{ inputs.suite }} so each
   leg gets a distinct suffix.

3. pkg_linux_qcom_ref pinned to the unmerged feature branch
   Both matrix rows carried "pkg_linux_qcom_ref":
   "feat/matrix-expansion-packaging", making the
   || 'qcom/debian/latest' fallbacks in daily.yml and release.yml
   unreachable dead code. After merge, every build would check out the
   feature branch; after branch deletion, every build would fail at
   actions/checkout. Delete the key from both rows so the fallback
   takes effect.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
…tions

Four independent issues addressed:

1. kernel-config default bypassed on empty explicit input
   build-kernel-deb.yml:325 used || '' where the sibling lines use
   || 'default-value'. A workflow_call default: never applies to an
   explicitly empty input, so a matrix row omitting kernel_config
   passed an empty string, the [[ -n ]] guard skipped --kernel-config,
   and the kernel shipped with zero config fragments while exiting 0.
   Change || '' to || 'squashfs,...' matching the workflow_dispatch
   default and the current matrix rows.

2. target_workspace: "qli" on the Daily row is a landmine
   The Daily row carried target_workspace: "qli" as dead data.
   daily.yml intentionally omits target-workspace from its with: block,
   so the field has no effect today. But it is one line away from
   turning every scheduled nightly into a production promotion into qli
   using DEBUSINE_RELEASE_TOKEN, because build-kernel-debusine.yml
   gates purely on the field being empty or not. Remove it from the
   Daily row; it belongs only on Release rows.

3. target-workspace on workflow_dispatch with no approval gate
   Any write-access user could set target-workspace on a direct
   build-kernel-deb.yml dispatch and promote arbitrary builds to
   production without going through release.yml. Update the description
   to make clear this input is only for release.yml; a follow-up can
   add environment: production once the release path is validated.

4. Single-suite manual dispatch hard-failed for most dropdown options
   resolve-matrix.sh raises jq error() when --single-suite names a
   suite absent from the matrix. daily.yml offered 6 suites against a
   Daily row carrying 2 (trixie, resolute); 4 of 6 options aborted
   configure-matrix. release.yml offered 4 options against a Release
   row carrying 1 (trixie); 3 of 4 aborted. The empty-string default
   in release.yml also triggered an actionlint warning.
   Trim both dropdowns to the suites their matrix rows actually carry.
   Replace release.yml's empty-string option with an 'all' sentinel
   and wire the configure-matrix step to treat both empty and 'all' as
   the full-matrix path.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
The Debusine workspace collision bug (JOB_INDEX hardcoded to "0") caused
both Debian-family legs to compute the identical child workspace name,
making forky's create_child_workspace fail seconds after trixie's succeeded.

That root cause was fixed in d751b30 by keying JOB_INDEX on the suite name,
giving each leg a distinct workspace suffix. Forky can now run in parallel
with trixie without collision.

Add forky to both the Daily and Release suites arrays, and add it to the
workflow_dispatch dropdown options in daily.yml and release.yml so
single-suite manual dispatches work correctly.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
Extend ci/build-matrix.json from a qcom-next-specific configuration into a
kernel-variant delivery contract. Each variant must define exactly one Daily
row and one Release row, keep one srcpkg and binpkg across that pair, and use
package identities that are not shared by another variant. Validate required
matrix fields, suite lists, delivery type, ref strategy, tag-pattern usage, and
Release target-workspace requirements before generating any workflow legs.

Flatten each row's suites into independent variant-and-suite entries and allow
resolution by delivery type, variant, and suite. Thread the resulting metadata
through Daily, Release, and build-kernel-deb: kernel repository, branch or tag,
ref strategy, package identities, config fragments, Debian revision,
LOCALVERSION/KVER_EXTRA overrides, packaging ref, and Debusine workspace data.

Make the execution paths variant-safe. Prepared-source artifacts use the
variant and suite, Debusine JOB_INDEX uses the same pair, and Debian and Ubuntu
S3 destinations include the variant and suite. Generalize ref resolution and
LOCALVERSION derivation so dated tags produce -<variant>-<date>, while branch
tips use a short commit SHA. Retain Debian-versus-Ubuntu suite routing while
propagating the variant identity through both reusable build paths.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
Replace the ambiguous manual-dispatch controls with explicit matrix scopes.
Daily supports Full matrix, Selected variant (all suites), and Selected variant
and suite; scheduled Daily runs always select the full matrix. Each scope maps
directly to resolve-matrix.sh arguments, so a manual run expands exactly the
intended set of flattened matrix legs without empty values or an `all` sentinel.

Constrain Release promotion to one kernel variant. The default Release scope
promotes all configured Release suites for the selected variant; the targeted
scope promotes one selected suite. Remove full-matrix Release promotion so a
new matrix variant cannot be promoted accidentally by an unrelated release.
Release continues to take its pinned ref, package metadata, Debian revision,
packaging ref, and target workspace exclusively from the selected matrix row.

Restructure build-kernel-deb dispatch inputs around kernel variant, suite, and
ref strategy. Use latest_tag, branch_tip, and pinned_ref as explicit strategies
and mark package, configuration, version, repository, and PR inputs as
advanced overrides. Keep direct dispatch build-only; Release promotion remains
owned by release.yml.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
Rewrite the README around the matrix-driven delivery model. Define the
per-variant Daily/Release pair, flattened suite legs, required row fields,
ref-strategy constraints, package-identity rules, and the onboarding procedure
for an additional kernel variant.

Document the end-to-end data flow with diagrams for prepared-source artifacts,
Debian source package generation and Debusine binary builds, Daily S3
publication, Release package-publish promotion, and the Ubuntu Docker path.
Describe variant-and-suite isolation at the GitHub artifact, Debusine workspace,
and S3 boundaries.

Document generated source, versioned image, metapackage, headers, and debug
packages; Debian rc version ordering; direct-build inputs; repository variables
and secrets; and the production baseline: Production GitHub environment, qli
Release workspace, 0qli~/0qli revisions, and qcom/debian/latest packaging ref.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
@bjordiscollaku
Bjordis Collaku (bjordiscollaku) force-pushed the feat/matrix-expansion-ci branch 2 times, most recently from 4acf777 to 7c1ccef Compare August 19, 2026 19:37
Bjordis Collaku (bjordiscollaku) added a commit that referenced this pull request Aug 19, 2026
The Copyright and License Check on PR #63 flagged derive-debian-revision.sh,
derive-localversion.sh, resolve-kernel-ref.sh, and resolve-matrix.sh as
missing a license header. Add the standard two-line header (Qualcomm
copyright notice plus SPDX-License-Identifier: BSD-3-Clause-Clear, matching
LICENSE.txt) to each.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
Bjordis Collaku (bjordiscollaku) added a commit that referenced this pull request Aug 19, 2026
The security scan (zizmor) and Semgrep OSS checks on PR #63 both flagged
genuine issues:

- build-kernel-deb.yml, daily.yml, and release.yml interpolated
  workflow_dispatch/workflow_call inputs and github.event.inputs.* directly
  into run: shell blocks via ${{ }}. That expansion happens as literal text
  substitution before the shell parses anything, so a value containing shell
  metacharacters could inject commands into the runner. Move every such
  input into a step-level env: mapping and reference it as a quoted shell
  variable instead, which passes the value at process-invocation time rather
  than templating it into the script text. daily.yml was not flagged by
  either scanner but carried the identical pattern as release.yml, so it
  gets the same fix for consistency.

- daily.yml and release.yml called build-kernel-deb.yml with
  secrets: inherit, granting it every secret available to the caller even
  though it only ever forwards three Debusine secrets to build-kernel-debusine.yml.
  Declare those three secrets explicitly on build-kernel-deb.yml's
  workflow_call trigger and pass only them by name from daily.yml and
  release.yml, per least privilege.

No behavioral change: every relocated value resolves to the same string at
run time, and the explicit secrets map forwards exactly the secrets already
in use.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
Comment thread .github/workflows/build-kernel-deb.yml Fixed
Comment thread .github/workflows/build-kernel-debusine.yml Fixed
Comment thread .github/workflows/release.yml Fixed
Comment thread .github/workflows/release.yml Fixed
Bjordis Collaku (bjordiscollaku) added a commit that referenced this pull request Aug 19, 2026
The Copyright and License Check on PR #63 flagged derive-debian-revision.sh,
derive-localversion.sh, resolve-kernel-ref.sh, and resolve-matrix.sh as
missing a license header. Add the standard two-line header (Qualcomm
copyright notice plus SPDX-License-Identifier: BSD-3-Clause-Clear, matching
LICENSE.txt) to each.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
Bjordis Collaku (bjordiscollaku) added a commit that referenced this pull request Aug 19, 2026
The security scan (zizmor) and Semgrep OSS checks on PR #63 flagged genuine
issues across every reusable and top-level workflow:

- build-kernel-deb.yml, build-kernel.yml, build-kernel-debusine.yml,
  daily.yml, and release.yml interpolated workflow_dispatch/workflow_call
  inputs, github.event.inputs.*, secrets.*, and steps.*.outputs.* directly
  into run: shell blocks via ${{ }}. That expansion happens as literal text
  substitution before the shell parses anything, so a value containing shell
  metacharacters could inject commands into the runner - including, for the
  docker run --privileged invocations in build-kernel.yml, directly on the
  self-hosted host rather than merely inside the container. Move every such
  value into a step-level env: mapping (forwarded into containers via
  docker run -e) and reference it as a quoted shell variable instead, which
  passes the value at process-invocation time rather than templating it into
  the script text. daily.yml was not flagged by either scanner but carried
  the identical pattern as release.yml, so it gets the same fix for
  consistency.

- daily.yml and release.yml called build-kernel-deb.yml with
  secrets: inherit, granting it every secret available to the caller even
  though it only ever forwards three Debusine secrets to
  build-kernel-debusine.yml. Declare those three secrets explicitly on
  build-kernel-deb.yml's workflow_call trigger and pass only them by name
  from daily.yml and release.yml, per least privilege.

No behavioral change: every relocated value resolves to the same string at
run time, and the explicit secrets map forwards exactly the secrets already
in use.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
Debusine accepted the identical binary package version into both trixie
and forky, making repository object identity ambiguous and later causing
pool-object downloads to fail. Storing one complete debian_revision per
matrix row cannot prevent this: nothing stops two suites from resolving
to the same string.

Restructure ci/build-matrix.json so each row carries a debian_version_stub
and a matrix-wide suite_suffix_mapping supplies the per-suite Debian
suffix. Each row also carries a debian_version_suffix: "~" for Daily,
empty for Release. This is the delivery-type half of the same formula,
computed via an explicit case statement rather than a ternary so the
Daily/Release branching stays self-documenting; storing it on the row
makes it visible next to debian_version_stub instead of only inside the
derivation script.

debian_revision = debian_version_stub + suite_suffix_mapping[suite] +
debian_version_suffix

ci/scripts/derive-debian-revision.sh is the single implementation of this
formula, used both by resolve-matrix.sh for matrix-driven Daily/Release
legs and by build-kernel-deb.yml's direct dispatch path, which has no
full-matrix context.

resolve-matrix.sh rejects a debian_version_stub that ends in ~, a matrix
where any configured suite has no suite_suffix_mapping entry, where two
suites share a suffix, where a suffix is malformed, where a variant's
Daily and Release rows disagree on debian_version_stub, or where a row's
debian_version_suffix disagrees with its own type, before any build job
starts. Derivation still computes the suffix from type internally; the
row field is consumed and stripped before a leg is emitted, so it never
reaches build-kernel-deb.yml. derive-debian-revision.sh independently
re-validates suite_suffix_mapping before deriving anything, since
build-kernel-deb.yml's direct-dispatch path calls it standalone, without
resolve-matrix.sh's validation pass having run first.

build-kernel-deb.yml's advanced manual-dispatch input is renamed from
debian-revision to debian-version-stub; direct dispatch always resolves
using Daily semantics since it is build-only and non-promoting. The
workflow_call interface used by daily.yml and release.yml is unchanged,
since resolve-matrix.sh already supplies the fully-derived revision.

Update README.md to match: replace the debian_revision matrix examples
with debian_version_stub, debian_version_suffix, and the shared
suite_suffix_mapping, add derived Daily/Release examples per suite,
explain the resulting ordering model including the case where Daily
revisions across two suites do not sort relative to each other, note the
new Daily/Release consistency check resolve-matrix.sh performs on
debian_version_suffix, and add suite-onboarding steps alongside the
existing variant-onboarding steps.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
The Copyright and License Check on PR #63 flagged derive-localversion.sh,
resolve-kernel-ref.sh, and resolve-matrix.sh as missing a license header.
Add the standard two-line header (Qualcomm copyright notice plus
SPDX-License-Identifier: BSD-3-Clause-Clear, matching LICENSE.txt) to
each. derive-debian-revision.sh already carries the header from the
commit that introduced it.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
Bjordis Collaku (bjordiscollaku) added a commit that referenced this pull request Aug 19, 2026
The security scan (zizmor) and Semgrep OSS checks on PR #63 flagged genuine
issues across every reusable and top-level workflow:

- build-kernel-deb.yml, build-kernel.yml, build-kernel-debusine.yml,
  daily.yml, and release.yml interpolated workflow_dispatch/workflow_call
  inputs, github.event.inputs.*, secrets.*, and steps.*.outputs.* directly
  into run: shell blocks via ${{ }}. That expansion happens as literal text
  substitution before the shell parses anything, so a value containing shell
  metacharacters could inject commands into the runner - including, for the
  docker run --privileged invocations in build-kernel.yml, directly on the
  self-hosted host rather than merely inside the container. Move every such
  value into a step-level env: mapping (forwarded into containers via
  docker run -e) and reference it as a quoted shell variable instead, which
  passes the value at process-invocation time rather than templating it into
  the script text. daily.yml was not flagged by either scanner but carried
  the identical pattern as release.yml, so it gets the same fix for
  consistency.

- daily.yml and release.yml called build-kernel-deb.yml with
  secrets: inherit, granting it every secret available to the caller even
  though it only ever forwards three Debusine secrets to
  build-kernel-debusine.yml. Declare those three secrets explicitly on
  build-kernel-deb.yml's workflow_call trigger and pass only them by name
  from daily.yml and release.yml, per least privilege.

No behavioral change: every relocated value resolves to the same string at
run time, and the explicit secrets map forwards exactly the secrets already
in use.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
@bjordiscollaku
Bjordis Collaku (bjordiscollaku) force-pushed the feat/matrix-expansion-ci branch 2 times, most recently from 1f881fa to 1f57893 Compare August 21, 2026 18:04
The security scan (zizmor) and Semgrep OSS checks on PR #63 flagged genuine
issues across every reusable and top-level workflow:

- build-kernel-deb.yml, build-kernel.yml, build-kernel-debusine.yml,
  daily.yml, and release.yml interpolated workflow_dispatch/workflow_call
  inputs, github.event.inputs.*, secrets.*, and steps.*.outputs.* directly
  into run: shell blocks via ${{ }}. That expansion happens as literal text
  substitution before the shell parses anything, so a value containing shell
  metacharacters could inject commands into the runner - including, for the
  docker run --privileged invocations in build-kernel.yml, directly on the
  self-hosted host rather than merely inside the container. Move every such
  value into a step-level env: mapping (forwarded into containers via
  docker run -e) and reference it as a quoted shell variable instead, which
  passes the value at process-invocation time rather than templating it into
  the script text. daily.yml was not flagged by either scanner but carried
  the identical pattern as release.yml, so it gets the same fix for
  consistency.

- daily.yml and release.yml called build-kernel-deb.yml with
  secrets: inherit, granting it every secret available to the caller even
  though it only ever forwards three Debusine secrets to
  build-kernel-debusine.yml. Declare those three secrets explicitly on
  build-kernel-deb.yml's workflow_call trigger and pass only them by name
  from daily.yml and release.yml, per least privilege.

No behavioral change: every relocated value resolves to the same string at
run time, and the explicit secrets map forwards exactly the secrets already
in use.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
Use qcom-next-7.2-rc7-20260821 for the staging Release validation.

The upstream version changes with this tag, giving the generated orig
tarball a new pool filename while retaining the existing staging Debian
revision.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
Overlay staging validation settings on the production-ready delivery model.
Run Debusine build and promotion jobs in the Staging GitHub environment,
direct Release promotion to qli-staging, and use 0qli+staging1 as the
Debian version stub for both Daily and Release builds (the Daily/Release
delivery suffix is derived automatically). Point matrix preparation at
feat/matrix-expansion-packaging and align the direct-build stub default
and README input table with the staging stub.

Keep this as the branch-tip commit. Reverting it restores Production,
qli, 0qli, and qcom/debian/latest without changing matrix behavior,
dispatch semantics, package generation, or workflow topology.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants