CI/CD Contracts
- Snapshot
- v0.2.0
- Source path
ci/README.md- Tree
c41b976e0362
The scripts under ci/ and workflows under .github/workflows/ check source changes, build images, test the runtime, enforce security policy, and prepare releases. This page explains how to run those checks and where to look when one fails. Verification and Testing explains what the results do and do not prove.
On this page
- Overview
- Pipeline
- Repository checks
- QEMU runtime checks
- Hosted workflows
- Artifacts and supply chain
- Running CI locally
- Interpreting failures
- Changing CI checks
- Sources of truth
- Related documentation
Overview
Product-specific checks live under ci/ so they can be used both locally and from GitHub Actions. Workflow files handle hosted orchestration, permissions, caches, artifact transfer, and publication.
| Path | Purpose |
|---|---|
ci/check_profile.fsh |
Product profiles, release settings, branding, pinning, and workflow invariants |
ci/check_developer_interface.fsh |
Host command help, aliases, completion, and shell syntax |
ci/check_public_automation.py |
Independent Flash-runtime oracle, setup, automation and documentation inventory, package wiring, examples, links, and parity |
ci/check_flashos_platform.fsh |
FlashOS target/toolchain baseline and built target artifacts |
ci/check_flashos_capabilities.fsh |
Capability evidence inventory |
ci/check_flashos_operation_map.fsh |
Flash operation mapping to Rust, relibc, and Redox interfaces |
ci/check_flashos_capability_classification.fsh |
Native/shimmed/unsupported capability classification |
ci/check_flash_conformance.fsh |
Flash v1 executable host-conformance inventory and refusal-boundary audit |
ci/check_flash_release.fsh |
Flash 1.0.0 version, evidence, claim, and candidate-workflow contract |
ci/check_coverage.fsh |
LCOV report completeness |
ci/classify_changes.fsh |
Fail-closed PR product and dependency-policy routing |
ci/aggregate_ci.fsh |
Stable aggregate result and classifier/job agreement |
ci/check_candidate_qualification.fsh |
Exact source-to-PR required/security evidence |
ci/release_candidate.fsh |
Candidate manifest, inventory, checksum, tree, and QEMU-byte validation |
ci/qemu_smoke.py |
x86_64 serial runtime smoke tests |
ci/container/Dockerfile |
Hosted image-build environment |
.github/workflows/ci.yml |
Main CI |
.github/workflows/coverage.yml |
Flash host coverage |
.github/workflows/_image.yml |
Reusable image build and QEMU qualification |
.github/workflows/security.yml |
Dependency and Cargo policy checks |
.github/workflows/candidate.yml |
Non-publishing release-candidate production |
.github/workflows/release.yml |
Exact candidate validation and publication |
flashos.sh |
Local helper commands |
If this document and an executable check disagree, the executable implementation wins.
Pipeline
The candidate and protected-main path is:
- 01CI / required
- 02Exact-tree merge
- 03Main verified / verified
Draft pull requests stop after the source jobs. Ready pull requests take the
product lane unless every changed path belongs to the explicit documentation,
policy, reporting, or isolated host-tool allowlist. Unknown and mixed paths
fail closed into image and QEMU qualification. The required aggregate checks
that the jobs agree with the classifier. Protected-main verification
independently classifies the merged PR, proves exact tree identity, and checks
the successful required and security-required evidence instead of rerunning
the suite. Coverage is manual. Dependency policy runs when classified, weekly,
and on manual request.
Host tests, image construction, QEMU checks, and physical hardware testing are separate verification layers. See Verification and Testing for their exact scope.
Repository checks
Flash v1 host conformance
Run the inventory and source-boundary check from the repository root:
make flash-bootstrap
make flash-automation-tools
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_flash_conformance.fsh
components/flash/conformance/v1.toml
maps each frozen host-v1 semantic family to enabled executable tests in the
locked Flash workspace. The checker requires the complete family and layer
inventory, verifies every test owner and platform contract path, confirms the
standard CI wiring and exact six-setting interactive config surface, and
rejects unclassified runtime refusal boundaries or source markers that imply
unfinished v1 behavior.
The checker validates ownership; cargo test --workspace --locked executes
every listed owner as part of the same flash-quality job. Passing both is the
host-v1 conformance signal. It does not establish Redox target compilation,
image integration, FlashOS runtime support, release readiness, or hardware
behavior.
Flash 1.0.0 release contract
Run the release-boundary check from the repository root:
make flash-bootstrap
make flash-automation-tools
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_flash_release.fsh
components/flash/release/v1.toml
binds the component version to the frozen conformance and exhaustive exercise
contracts, retained host evidence, FlashOS capability report and target matrix,
public release claims, and the exact candidate-workflow commands. The checker
requires zero recorded release findings and zero unexamined inventory items.
The ready pull-request workflow then executes those owners and builds and boots
the exact in-tree package candidate; the record does not release a FlashOS
image or establish physical-hardware support.
Product profile
Run:
make flash-bootstrap
make flash-automation-tools
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_profile.fsh
check_profile.fsh catches repository-level product errors before an image build starts. Among other things it checks:
- development and release profile composition;
- package and account configuration;
- runtime/build package separation and excluded compatibility payloads;
/usr/bin/fshas the configured shell;- release root-account locking;
- FlashOS identity and version surfaces;
- release/image artifact naming and workflow wiring;
- immutable Git revisions for shipped Git-based packages;
- full commit pins for third-party GitHub Actions;
- branding patches and package-web source links;
- QEMU NVMe/USB smoke-test wiring.
After target packages have been built, pass --artifacts to verify the exact
runtime stage metadata, required boot/runtime files, preserved development and
debug outputs, and excluded image payload. The separately staged
flash.lsp package remains selected because the exact-image Flash v1 matrix
exercises it; it is not a login-shell payload or service. Release SBOM
collection uses the same reported package closure and refuses runtime
dependencies it cannot account for; it does not scan unrelated build-package
stages.
FLASHOS_RELEASE_VERSION in versions.env is the central
FlashOS release version. Flash has an independent component version bound to
its release record. The exact package lists, denied values, and source
assertions are kept in the checker instead of being duplicated here.
Failures start with:
profile contract:
Public automation
Run the fail-closed public script and embedded-command inventory from the repository root:
python3 ci/check_public_automation.py
The static contract classifies native Flash roots, bootstrap/recovery and
external-tool exceptions, generated/test data, package copies and runtime
dependencies, installed non-Flash launchers, and .gitattributes. New
standalone or embedded surfaces change the sealed inventory and fail until the
disposition is reviewed.
The checker and its focused Python unit test are intentional independent-
validation exceptions. They reject broken and falsely successful candidate
runtimes, so moving the oracle into the fsh under test would make its trust
boundary circular. The same checker validates setup.sh as the only canonical
operator bootstrap: clean-host package plans, both pinned Rust toolchains, the
narrow Flash installer, pinned automation tools, read-only checks, idempotent
reruns, and forbidden Git, shell-startup, emulator, and device effects.
Shared host modules under ci/lib/ are non-executable frozen-v1 Flash imports,
not additional migration roots. Their external parsing/search boundary is
sealed by ci/automation-tools.json: Taplo 0.10.0, jq 1.7.1, and ripgrep
15.2.0. Explicit binaries may be selected with FLASH_AUTOMATION_TAPLO,
FLASH_AUTOMATION_JQ, and FLASH_AUTOMATION_RG; version drift fails before
project data is consumed. github_qualification.fsh owns the shared bounded,
read-only GitHub evidence and qualification policy used by the main and
candidate roots. make flash-automation-tools downloads the declared
macOS arm64 or Linux x86_64 assets into build/flash-automation-tools/ and
verifies every SHA-256 before extraction.
After the Flash workspace has built the candidate fsh, first acquire the
independent Flash 1.0 bootstrap from the immutable baseline, then exercise the
migrations through both runtimes:
make flash-bootstrap
python3 ci/check_public_automation.py \
--bootstrap-runtime \
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh \
--runtime components/flash/target/debug/fsh
The acquisition target checks out the fixed source commit and tree into an
isolated temporary clone, uses the pinned Rust toolchain, verifies fsh 1.0.0,
and binds the resulting binary digest in a local manifest. The parity gate
rejects missing, non-executable, wrong-version, crashing, always-success,
corrupt-output, or capture-overflow runtimes. It then checks canonical format,
static analysis, ordered execution, cwd, argv, environment, stdout/stderr,
filesystem effects, and exact unsuccessful-status propagation under the
bootstrap before the candidate. Hosted CI runs the static inventory in
repository-quality and the runtime parity in flash-quality. Package/image
and QEMU evidence remain separate downstream gates.
Documentation contract
Run the public documentation check with:
source flashos.sh
flashos check docs
ci/documentation.json lists every public Markdown page and curated .fsh
example. The check catches missing or unlisted pages, broken local links and
anchors, orphaned pages, missing index links, incomplete guide footers, invalid
heading structure, private process terms, and unlisted examples. It also
formats, checks, and runs each example with the fixed Flash 1.0 documentation
runtime.
The check cannot judge the rendered page or the quality of its prose, and it does not test whether external websites are available. Those still need human review.
An optional local drift checker may run afterward when available, but it does not replace this public check.
Platform baseline
Run:
make flash-bootstrap
make flash-automation-tools
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_flashos_platform.fsh
This compares the tracked FlashOS target record with the x86_64 profile, build toolchain, Rust compiler recipe, relibc recipe, and CI wiring.
After a clean image build has produced target package stages, artifact mode also checks the staged target compiler/configuration and ELF identity:
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_flashos_platform.fsh --artifacts
Capability model
The current FlashOS capability data is checked with:
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_flashos_capabilities.fsh
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_flashos_operation_map.fsh
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_flashos_capability_classification.fsh
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_flashos_capability_report.fsh
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_flashos_target_matrix.fsh
These scripts keep the live Capability enum, evidence inventory, operation map, and architectural classification in sync.
The corresponding data files are:
flashos-x86_64-capability-evidence.tomlflashos-x86_64-operation-map.tomlflashos-x86_64-capability-classification.tomlflashos-x86_64-capability-report-v1.tomlflashos-x86_64-runtime-fixtures-v1.tomlflashos-x86_64-target-matrix-v1.toml
The current classification records 41 operations as native and the three standard-directory operations as a FlashOS policy shim. Runtime qualification remains separate from that classification.
The versioned report records the adapter's current advertised set and keeps
each group connected to the bounded runtime fixtures that reach it. Signals
remains withheld. The checker also binds report versions to the Flash workspace
and FlashOS release, proves exact ordered capability coverage, verifies the
adapter bitset, and requires the QEMU runner to consume the same fixtures.
The linked target matrix assigns every advertised operation to one owning case,
covers the required startup, language, session, editor, job, and clean-exit
surfaces, and keeps the withheld Signals group outside the qualified set. Its
checker also requires both the automated and operator-observed consumers to
use the same ordered contract.
QEMU runtime checks
ci/qemu_smoke.py boots an existing x86_64 image and tests the current serial interface. It does not build or modify the source image.
The interaction rows and expected markers live in
flashos-x86_64-runtime-fixtures-v1.toml.
The exhaustive advertised-capability cases live in
flashos-x86_64-target-matrix-v1.toml.
The QEMU harness consumes both versioned suites directly. To render either
ordered contract for an operator-observed target without claiming that it was
run, use:
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/flashos_runtime_fixtures.fsh
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/flashos_target_matrix.fsh
The host needs Python 3, QEMU, compatible x86_64 OVMF/edk2 firmware, and an existing image.
The harness uses one TCG virtual CPU so scheduler timing does not make the product-behavior assertions nondeterministic. This runtime gate does not qualify SMP or multicore behavior.
Example:
python3 ci/qemu_smoke.py \
--image /path/to/harddrive.img \
--ovmf /path/to/OVMF_CODE.fd
Without --ovmf, the script searches its configured Linux and Homebrew locations.
Options
| Option | Purpose |
|---|---|
--image PATH |
Image to boot |
--qemu PATH |
QEMU executable |
--ovmf PATH |
Explicit firmware file |
--log PATH |
Full serial log |
--timeout SECONDS |
Initial boot-marker timeout |
--fixtures PATH |
Versioned target-runtime fixture suite |
--target-matrix PATH |
Versioned target capability matrix |
--disk-interface nvme |
Attach through emulated NVMe |
--disk-interface usb |
Attach as USB mass storage |
--expect-root-locked |
Also test the release root-login policy |
The VM runs headless using OVMF, TCG, snapshot-backed image attachment, an emulated USB keyboard, and HDA audio with a null host backend.
What is tested
| Area | Check |
|---|---|
| Boot | FlashOS boot/startup markers appear |
| Services | Expected framebuffer-debug and audio-driver markers appear |
| Login | The unprivileged user can log in |
| Bounded smoke | Prompt, editing, directories, scripts, pipelines, and waits work |
| Advertised capabilities | Every required target-matrix surface completes in its declared order |
| Withheld capability | Signals remains outside the qualified set |
| Release root policy | Root login is rejected when requested |
The Flash editor redraws the input row while reading keystrokes, so the harness uses scoped output markers rather than treating a bare prompt as command completion. Prompt changes can therefore require a matching harness update.
Every live-editor submission fits within the emulated UART's 16-byte receive
boundary. Matrix scripts are streamed as exact bytes, in chunks no larger than
that boundary, to a foreground head -cN reader and then executed from the
resulting target-side file. This keeps transport mechanics separate from the
script behavior being qualified and avoids relying on a second readiness event
within one editor row.
The full serial stream is written to the requested log on success and failure.
qemu smoke: FAILED:
qemu smoke: ok
The exact matrix covers target prompt recovery, history recall, completion, multiline and Unicode editing, cancellation, configuration, typed capture, structured errors, dynamic execution, globbing, supported jobs, and clean exit. It does not cover inputs outside those cases, signal delivery, stopped/continued/signaled child transitions, general hardware compatibility, full networking, real audio I/O, framebuffer quality, suspend/resume, performance, or complete Flash language behavior.
Hosted workflows
Standard CI
The candidate workflow is .github/workflows/ci.yml. It runs for pull requests and manual dispatch.
The classifier and two source-quality jobs are:
| Job | Checks |
|---|---|
change-classification |
Changed paths, selected lane, image requirement, and dependency-policy scope |
repository-quality |
Root formatting/tests, Ruff, Python tests, product checks, whitespace |
flash-quality |
Flash formatting, Clippy, v1 conformance inventory, and locked host tests |
The source jobs remain required on every PR. Their Cargo downloads and build
outputs use separate toolchain/lockfile/profile keys. A manual cold-cache run
disables these caches so cached and clean results can be compared.
image-and-runtime calls _image.yml only when the classifier selects the
product lane and the PR is ready. Documentation, policy, reporting, and
isolated host-tool paths may select the fast lane. Product source, recipes,
profiles, image/QEMU tooling, CI orchestration, mixed changes, and unknown paths
select the product lane. Drafts defer the image even when it will be required
at ready-for-review.
The final required job combines these results into the stable status used by
repository rules. .github/workflows/main-qualification.yml
then reports verified on the protected-main commit only after
check_main_qualification.fsh verifies the
associated pull request, exact Git-tree identity, independently recomputed path
classification, the appropriate successful or skipped image jobs, and
security-required evidence. This preserves a meaningful visible check on
main without executing the suite twice.
The path classifier, required aggregate, protected-main transfer, and candidate evidence resolver are native Flash contracts with materialized Python-oracle success, failure, GitHub-output, and summary parity, rather than untested branches that exist only in workflow YAML.
Coverage
.github/workflows/coverage.yml is a
manually requested diagnostic that generates host-executable Flash coverage
using the pinned Flash toolchain and pinned cargo-llvm-cov.
Before upload, ci/check_coverage.fsh runs through the immutable Flash runtime and rejects a missing/empty report, reports without executed first-party lines, and reports that omit any of the workspace crates. There is no minimum percentage threshold.
Codecov upload uses GitHub OIDC rather than a persistent token. codecov.yml currently disables Codecov project/patch statuses, comments, and GitHub checks.
The percentage is Flash host coverage; it does not include target-only Redox code, image integration, QEMU behavior, the kernel, or physical hardware.
Image build and runtime qualification
.github/workflows/_image.yml is shared by normal CI and releases.
Inputs:
| Input | Purpose |
|---|---|
artifact-name |
Promoted image artifact name |
runtime-evidence-name |
QEMU logs/results artifact name |
retention-days |
Artifact retention |
config-name |
x86_64 profile; defaults to flashos |
release-evidence |
Also build/boot live media and generate the image SBOM |
source-ref |
Exact source commit |
cold-cache |
Disable BuildKit cache restore/save for a diagnostic run |
The producer uses ci/container/Dockerfile to build the
hard-drive image, validates target artifacts, creates and verifies
SHA256SUMS, and uploads the result. BuildKit layers are keyed by the pinned
container/toolchain inputs and Docker's actual layer input graph; cache export
failure is ignored. A cold-cache run adds --no-cache. Product outputs, final
images, candidate bundles, manifests, SBOMs, attestations, and QEMU results are
never restored as authoritative cache entries.
The candidate artifact contains:
FlashOS-x86_64-harddrive.img
SHA256SUMS
Release-candidate qualification sets release-evidence: true. It additionally builds
and boots the live image over USB mass storage, collects staged target payloads,
generates the image CycloneDX SBOM, and carries the generated cookbook.lock
that resolved the exact build. The release profile also enables the root-lock
assertion.
Runtime jobs preserve available evidence on both success and failure:
qemu-harddrive-smoke.log
qemu-harddrive-performance.json
qemu-live-usb-smoke.log
qemu-results.json
SHA256SUMS
The “clean-room” job name refers to the fresh hosted-runner/container boundary. It is not a bit-for-bit reproducibility claim.
Candidate and release images cook selected packages from tracked recipes. The optional transitional binary feed remains available for local iteration but is not an input to promoted-image qualification.
Security
.github/workflows/security.yml handles dependency review and Cargo policy.
For in-scope pull requests, dependency review rejects newly introduced dependencies at or above the configured high-severity threshold.
The root and Flash workspaces are also checked against their respective deny.toml files for:
advisories
bans
licenses
sources
security-required is the stable aggregate used by repository rules. The
underlying gates run for classified dependency inputs, every Monday, and manual
dispatch; other PRs receive a controlled skip. Security reports should follow
the Security Policy.
Release candidates and publication
.github/workflows/candidate.yml is a
manual, non-publishing producer. It accepts a full source commit, the exact
versions.env version, reviewed release notes, and an optional cold-cache
diagnostic. Before building it verifies that the source is a reviewable PR head
or an exact-tree merged PR result with successful required and
security-required evidence.
The candidate reuses _image.yml with:
config-name: flashos-release
release-evidence: true
It builds the raw release-profile disk and live images once. Separate QEMU
consumers boot those exact raw bytes on the NVMe and USB paths on their first
attempt. Packaging verifies the handoff, compresses those same bytes, creates
the source SBOM, promotes the image SBOM, carries the reviewed notes and QEMU
evidence, writes SHA256SUMS, and creates candidate-manifest.json.
Candidate creation and both publication-validation jobs acquire the immutable
Flash 1.0 runtime and pinned jq before invoking
release_candidate.fsh; Flash owns selection,
identity, inventory, checksum, tree, QEMU-attempt, and decompressed-byte policy.
FlashOS-<version>-x86_64-harddrive.img.zst
FlashOS-<version>-x86_64-live.iso.zst
FlashOS-<version>-source.cdx.json
FlashOS-<version>-image.cdx.json
FlashOS-<version>-release-notes.md
cookbook.lock
candidate-manifest.json
qemu-results.json and logs
SHA256SUMS
The manifest binds the repository, producer run and attempt, source commit and tree, version, release profile, required/security run IDs, tracked input graph, generated cookbook resolution, allowlisted inventory, every candidate digest, raw image digests, and both QEMU results. Re-running the producer creates a distinct artifact identity.
.github/workflows/release.yml is a manual
consumer of an exact existing tag and candidate run ID. Its default dry run
validates the repository/workflow/run/attempt, artifact expiry, tag/version,
tag-tree/candidate-tree equality, inventory, checksums, decompressed image
digests, and release absence. Publication repeats validation in the protected
production environment and uploads the candidate files without building,
compressing, generating, attesting, or substituting anything.
Artifacts and supply chain
The normal image handoff is:
repository revision
↓
source/product checks
↓
containerized image producer
↓
hard-drive image + SHA256SUMS
↓
workflow artifact
↓
separate runtime consumer
↓
checksum verification
↓
NVMe QEMU test
Release packaging and publication preserve one candidate byte chain:
exact source + successful required/security evidence
↓
once-built raw release images
↓
separate NVMe/USB QEMU consumers
↓
compressed bytes + SBOMs + notes + QEMU evidence
↓
checksums + manifest + provenance attestations
↓
exact candidate run ID + exact tag/tree validation
↓
publication without rebuild
| Artifact | Contents |
|---|---|
| PR image | Raw hard-drive image and checksums |
| Release image evidence | Raw disk, raw live image, image SBOM, and checksums |
| QEMU evidence | Both serial logs, target performance JSON, result record, raw digests |
| Release candidate | Compressed images, SBOMs, notes, QEMU evidence, checksums, manifest |
The pipeline also uses pinned Rust toolchains, Cargo lockfiles/policies, immutable Git recipe revisions, full commit pins for third-party Actions, a digest-pinned CI base image, checksum verification of the Rust installer, and SHA-256 verification across artifact handoffs.
Every release-candidate file receives GitHub provenance attestation in the producer run. Publication creates no replacement attestation.
The pipeline does not currently perform two independent builds and compare their output bytes, so it should not be described as a reproducible-build verifier.
Running CI locally
Host checks
From the repository root:
source ./flashos.sh
flashos check ci
This runs the local source-quality collection: helper interface checks, product/profile checks, whitespace validation, root formatting/tests, Flash formatting/Clippy/tests, Ruff, and the offline Python unit tests.
Direct checks
make flash-bootstrap
make flash-automation-tools
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_developer_interface.fsh
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_profile.fsh
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/classify_changes.fsh --json </dev/null
python3 ci/check_public_automation.py
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_flashos_platform.fsh
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_flashos_capabilities.fsh
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_flashos_operation_map.fsh
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_flashos_capability_classification.fsh
ruff check ci/
python3 -m unittest discover -s ci/tests -p 'test_*.py'
The public-automation gate below runs each migrated ci/tests/*.fsh root with
both the immutable bootstrap and the workspace candidate runtime. The current
native CI roots are test_classify_changes.fsh, test_aggregate_ci.fsh,
test_check_coverage.fsh, test_flash_benchmarks.fsh,
test_check_flash_conformance.fsh, test_check_flash_release.fsh,
test_check_flash_v1_exercises.fsh, test_check_flashos_capabilities.fsh,
test_check_flashos_capability_classification.fsh,
test_check_flashos_capability_report.fsh,
test_check_flashos_operation_map.fsh, test_check_flashos_platform.fsh,
test_check_flashos_target_matrix.fsh, test_check_main_qualification.fsh,
test_flashos_runtime_fixtures.fsh, test_flashos_target_matrix.fsh, and
test_release_candidate.fsh.
Validate an existing LCOV report with:
build/flash-bootstrap/134635a5e1282b5d8455a4b2aeb754be5a3a77c1/fsh ci/check_coverage.fsh coverage/flash.lcov
QEMU smoke tests
Development profile:
python3 ci/qemu_smoke.py \
--image build/x86_64/flashos/harddrive.img \
--disk-interface nvme \
--log build/x86_64/flashos/qemu-harddrive-smoke.log
python3 ci/qemu_smoke.py \
--image build/x86_64/flashos/redox-live.iso \
--disk-interface usb \
--log build/x86_64/flashos/qemu-live-usb-smoke.log
Release profile:
python3 ci/qemu_smoke.py \
--image build/x86_64/flashos-release/harddrive.img \
--disk-interface nvme \
--log build/x86_64/flashos-release/qemu-harddrive-smoke.log \
--expect-root-locked \
--expect-passwordless-user \
--expect-release-services
python3 ci/qemu_smoke.py \
--image build/x86_64/flashos-release/redox-live.iso \
--disk-interface usb \
--log build/x86_64/flashos-release/qemu-live-usb-smoke.log \
--expect-root-locked \
--expect-passwordless-user \
--expect-release-services
The release-only service assertion compares the assembled /usr/lib/init.d inventory with the exact reviewed local/system set. It rejects added remote-login or other unexpected init entries; it is not a vulnerability scan of the inherited service implementations.
Add --ovmf if the firmware is not found automatically.
Full local qualification
flashos profile dev # or: flashos profile release
flashos qualify all
This runs the local checks, builds both selected-profile images, and smoke-tests them.
Local qualification does not reproduce every hosted step such as artifact upload/download, hosted SBOM generation, dependency review, provenance attestation, or GitHub Release publication.
Flash target compilation
Target compilation is separate from flashos check ci:
flashos check target
or:
cd components/flash
redoxer build -p flash-cli --bin fsh
Run it when a change affects Flash code selected for the Redox target.
Interpreting failures
Start with the first failing layer.
| Failure point | First place to look |
|---|---|
| Root formatting/tests | Reported file/test, root toolchain, lockfile |
| Flash formatting/Clippy/tests | Reported crate, warning, test, fixture |
| Ruff/Python tests | Reported ci/ file and diagnostic |
| Coverage | Test output, LCOV contents, workspace members, OIDC upload |
| Product profile | Exact profile contract: message and owning file |
| Platform/capability checks | Target record or referenced evidence/map/classification entry |
| Container build | Base image, packages, installer download/checksum |
| Image build | Recipe source, target toolchain, build log, storage |
| Image SBOM | Staged payload, recipe metadata, scanner output |
| Checksum verification | Staging/transfer mismatch or incomplete artifact |
| Boot timeout | Serial log before the missing marker, firmware, QEMU configuration |
| Interactive QEMU check | Serial bytes around the failed interaction |
| Root-lock check | Release profile, account database, login behavior |
| Dependency review/Cargo policy | Dependency diff, advisory, relevant deny.toml |
| Release version | Tag and versions.env |
| Packaging/attestation | Downloaded candidate, job permissions, OIDC context |
| Publication | Tag, environment, permissions, checksums, existing release |
For QEMU failures, keep the complete serial log before rebuilding or rerunning.
Changing CI checks
When an intentional product or pipeline change breaks a check:
- update the implementation and the check that owns the rule;
- update workflow wiring if orchestration, permissions, or artifact flow changed;
- run the relevant local checks;
- rebuild and smoke-test the affected image/profile paths;
- update this page if the developer-facing procedure changed.
Update Verification and Testing only when the broader evidence model or public qualification claim changes.
Artifact-name or SBOM-scope changes usually need matching changes in the producer, consumer, checksums, release packaging, and check_profile.fsh.
Keep third-party Actions pinned to full commit SHAs and external Git package sources pinned to immutable revisions.
Sources of truth
| Concern | Primary source |
|---|---|
| Verification model | Verification and Testing |
| Development workflow | Development |
| Local helpers | flashos.sh |
| Developer interface check | check_developer_interface.fsh |
| Product/profile checks | check_profile.fsh |
| Platform baseline | check_flashos_platform.fsh |
| Capability evidence | check_flashos_capabilities.fsh |
| Operation map | check_flashos_operation_map.fsh |
| Capability classification | check_flashos_capability_classification.fsh |
| Capability report | check_flashos_capability_report.fsh |
| Target capability matrix | check_flashos_target_matrix.fsh |
| Change classification | classify_changes.fsh |
| Required aggregate | aggregate_ci.fsh |
| QEMU runtime checks | qemu_smoke.py |
| Main qualification | check_main_qualification.fsh |
| Candidate evidence | check_candidate_qualification.fsh |
| Candidate manifest | release_candidate.fsh |
| Coverage validation | check_coverage.fsh |
| Hosted build environment | container/Dockerfile |
| Standard CI | .github/workflows/ci.yml |
| Protected-main status | .github/workflows/main-qualification.yml |
| Coverage | .github/workflows/coverage.yml |
| Image build/runtime | .github/workflows/_image.yml |
| Security | .github/workflows/security.yml |
| Candidate production | .github/workflows/candidate.yml |
| Release publication | .github/workflows/release.yml |
| Root Cargo policy | deny.toml |
| Flash Cargo policy | components/flash/deny.toml |
| Product version | versions.env |
| Development profile | config/x86_64/flashos.toml |
| Release profile | config/x86_64/flashos-release.toml |
| Security reporting | Security Policy |
| Release history | Changelog |
Related documentation
- Verification and Testing — Evidence layers and qualification boundaries.
- Development — Repository setup, image builds, profiles, and local helper usage.
- Flash Development — Flash workspace checks, tests, performance budgets, scheduling stress, fuzzing, target compilation, and package integration.
- Flash Performance Benchmarks — Versioned measurements, retained evidence, environment-specific budget derivation, and regression evaluation.
- Flash Scheduling Stress — Seeded host pipeline-cancellation and job-control campaigns, retained results, and exact replay.
- Architecture — System layers, profile composition, package boundaries, and image construction.
- Security Policy — Private vulnerability-reporting instructions and supported security scope.
- Changelog — Published project and release changes.