Skip to main content

qa-orchestrator

Inject faults, drive walks, and check the audit tool reached the verdict it should have.

bmc-sensor-audit judges firmware: it diffs what an OpenBMC declaration promises against what the machine reports. This drives both sides. It perturbs a machine in ways whose correct verdict is known in advance — a sensor removed, one switched off, a reading frozen — and checks the tool reached it.

Why this is a separate program

The audit tool is the judge of the outcome, so it cannot also be the injector. A referee that shipped its own fault injection would be certifying itself: every scenario would be written against the behaviour the tool happens to have, and a tool that stopped detecting something would quietly stop being asked about it.

So the injector lives outside and consumes only the referee's published surfaces — exit codes, the JSON report, the attestation. referee.py does not import bmc_sensor_audit, and a test asserts that by reading the file. If a scenario needs something the published surface does not carry, that is a feature request against the tool, not a reason to reach past it.

A scenario

format: qa-scenario/1
backend: mock
mode: coverage
config: fixtures/board.json          # resolved beside this file, not from the cwd

machine:
  sensors:
    - {name: Inlet,  reading: 21.0, upper_critical: 80, upper_warning: 70}
    - {name: Outlet, reading: 27.5, upper_critical: 80, upper_warning: 70}

phases:
  - walks: 1
    expect:
      audit: {exit: 0}

  - action: {remove: Outlet}
    walks: 1
    expect:
      audit:
        exit: 1
        finding: "not reported by the machine at all"
        names: [Outlet]
        not_names: [Inlet]
      firmware: {Outlet: absent, Inlet: reading}

Released — 0.1.0, tagged v0.1.0, Apache-2.0, on PyPI as qa-orchestrator.

pip install qa-orchestrator

qa-orchestrator check <scenario.yaml>     # parse only; needs no machine
qa-orchestrator run <scenario.yaml>

The two worked scenarios are named with a placeholder above rather than by filename, because a wheel carries only what lives under the package directory: a pip install gives you the command and not the examples. They ship in this repository and in the sdist, under scenarios/. From a clone, pip install -e . puts the same script on the path and the scenarios beside it.

audit and firmware are different claims and both are worth making. The sensor is gone and the tool noticed it is gone are separate facts. A scenario that could only express the second could never tell a broken injector from a blind referee — the run would be green either way.

not_names is half of every detection claim. Naming the frozen sensor shows the tool found something; showing the sensor beside it was not named is what makes that evidence of detection rather than of a check that flags everything.

The format refuses what it cannot run

A phase with no walks, an expect block that sets nothing, an action verb this build does not implement, a drive with fewer values than walks, exit_code where exit was meant — all rejected at parse time with the phase named. Each of them would otherwise produce a run that executed, reported clean, and tested nothing, which is indistinguishable from a real pass at the exit code.

Three tiers, and one of them says so

Backend What it is State
mock the audit tool's own MockBMC, in process working; needs no hardware
qemu attaches to a running instance, injects over QMP wire format tested, integration not
testbed relay boards and real fans not implemented, and refuses

The tiers exist so one scenario runs at increasing cost and realism without being rewritten. That only holds if a tier which cannot do something refuses instead of approximating it. testbed raises at construction and its refusal lists what a real implementation needs — a specification, not an apology. A stub that accepted injections and did nothing would report that real fans were pulled having touched nothing, and every phase after it would judge an unperturbed machine and pass.

qemu attaches to an already-running instance whose QMP socket the scenario names. It does not boot one. Owning the boot recipe — image build id, machine type, FRU provisioning — is real work that is not done here, and claiming it would be worse than not having it. The QMP conversation is tested against a fake socket, so the greeting, handshake, framing and error path are covered; no real QEMU has run it.

Exit codes

The same three-valued contract the audit tool uses, because this sits in the same pipeline and a fourth vocabulary at this layer is one more thing for a gate to get wrong:

0 every expectation held
1 a verdict disagreed with the scenario
2 the run could not be completed

2 never reads as clean. A scenario that could not reach its backend has judged nothing. Could-not-complete outranks disagreement, because a run that stopped early has not evaluated the phases it never reached.

A run also reports how many phases asserted anything. A scenario of phases that assert nothing is green and worthless, and the exit code cannot tell that from a real pass — so it is said in words instead.

The acceptance scenario

scenarios/stuck-at.yaml reproduces the experiment the audit tool already ships: a sensor driven to a new value before each of twelve walks, then left alone for sixteen. The engine is silent while everything moves and names exactly the frozen sensor once one freezes, with a control sensor still moving beside it.

That experiment is the acceptance test for this harness, because its outcome is already known. If the orchestrator cannot express it, the DSL is wrong — and at first it could not: drive took one sensor and a phase may carry only one action, so there was no way to keep a control moving beside the frozen one. The general drive: {sensors: {...}} form exists because this file needed it.

Two things it does not show. Freezing a reading through a mock is an experiment, not a sensor failing on its own. And the declaration it runs against carries thresholds deliberately: a sensor declaring none is excluded from the liveness model entirely, so a thresholdless board produces an empty model and a clean run that checked nothing.

Not built yet

  • The redundancy scenario against the audit tool's supplemental template.
  • The qemu boot recipe; this build attaches to a running instance.
  • The testbed tier, which needs a lab.

Apache-2.0.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qa_orchestrator-0.1.0.tar.gz (36.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qa_orchestrator-0.1.0-py3-none-any.whl (30.9 kB view details)

Uploaded Python 3

File details

Details for the file qa_orchestrator-0.1.0.tar.gz.

File metadata

  • Download URL: qa_orchestrator-0.1.0.tar.gz
  • Upload date:
  • Size: 36.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.12

File hashes

Hashes for qa_orchestrator-0.1.0.tar.gz
Algorithm Hash digest
SHA256 947a08aadba8f44dd45a01820bc5905d664f1f2fbad674bf2cbb72507cccf7f7
MD5 353d8d3a14068cddba427e8331088804
BLAKE2b-256 2ba82a3e4703c70fa14e73ec9f8abfa5a72578e808e3c06a76ff38bcd4555568

See more details on using hashes here.

File details

Details for the file qa_orchestrator-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for qa_orchestrator-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a0c2fb52c309db8aeda8cd47989d5babca9c3ae7cb0bd518e27795a2ea9c6482
MD5 c0b1bc20ae04e129d96695f2661d754e
BLAKE2b-256 f296a44dfbaa98f8aa901857208baa8a9e00dec3ba4d70b9a5fc1732c34f47b7

See more details on using hashes here.

Release history Release notifications | RSS feed

0.3.0

2 files

0.2.0

2 files

0.1.2

2 files

0.1.1

2 files

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page