Skip to content

chore: update docs from development branch - #588

Merged
sadsfae merged 46 commits into
masterfrom
development
Sep 16, 2026
Merged

sadsfae merged 46 commits into
masterfrom
development

Conversation

@sadsfae

@sadsfae sadsfae commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

chore: docs only update and ci hardening for quay container builds

mmahut and others added 30 commits May 25, 2026 11:27
feat: add --rack, --uloc, --blade CLI arguments for explicit host location
feat: add AUR package and CI publishing
chore: bump CI Python to a support version.
The --set-bios-attribute path now accepts a repeatable --attribute-value
option taking attribute=value pairs, so multiple BIOS attributes are
staged and applied in a single operation and one reboot. Existing
--attribute/--value usage is unchanged.

The accepted-value check is reset per attribute so an invalid value is
not masked by an earlier accepted one, and accepted values are sent
using the registry's canonical casing.

fixes: #393
Follow-up from independent and adversarial review of the PR:
- reject duplicate --attribute-value names instead of silently last-wins
- error when --attribute-value is mixed with legacy --attribute/--value
- require --set-bios-attribute when --attribute-value is used (no silent no-op)
- validate pairs before any session/network work so bad syntax fails fast
- resolve attributes to the registry canonical AttributeName before the
  current-value lookup and PATCH (odd casing no longer misreported)
- skip the PATCH and reboot entirely when every value is already in the
  desired state
- pin single-PATCH / no-PATCH counts and add edge-case tests
…stry

The multi-attribute path silently dropped a value when two attributes differed
only by case (e.g. ProcC1E and procc1e both mapped to the same canonical name).
Make the duplicate check case-insensitive, narrow canonical-name resolution to
the registry AttributeName field only, and raise a catchable BadfishException
when the BMC does not expose a BIOS registry instead of crashing with a
TypeError.
Grafuls (review): the nested loop was O(entries x attributes). Build a
lowercase->canonical AttributeName map once, then resolve each supplied
attribute with one lookup. Behavior unchanged (38 BIOS tests pass).
Adds an rpmlint make target under rpm/ that builds the SRPM and binary
noarch RPM and lints the spec plus both artifacts, and a GHA workflow
that runs it in a fedora:latest container on PRs and pushes. Pivots
the #312 investigation away from rpminspect, which targets binary
packages and deviation analysis that do not apply to a noarch pure
Python package.

fixes: #312
Follow-up from independent review of the PR:
- run the rpmlint gate on synchronize and reopened, not just opened/edited,
  so new commits pushed to the PR are actually linted
- install rpm-build explicitly (previously only transitive)
- add rpmbuild/ to rpm cleanup and .gitignore
- mark the rpmlint target .PHONY
- jobs get permissions: contents: read
- main.py lost its shebang earlier; clear the stale executable bit (module
  is not a script; entry point is the badfish console script)
paths filter keeps the RPM hygiene gate to packaging-related changes;
concurrency group cancels superseded runs instead of queueing them.
The rpm build derives VERSION from setup.py, but the paths filter omitted it,
so a setup.py-only change would not re-trigger the gate. Also, if setuptools is
unimportable the Makefile silently built badfish-.tar.gz with empty @Version@
substitutions; the version is now asserted non-empty before building.
Adds a mock iDRAC server so badfish can be developed and tested without
bare metal. Run with "badfish --redfish-emulator --port 8443"; it always
runs as a persistent server until interrupted.

Design: static resource shapes live as JSON templates under
src/badfish/emulator/templates, served over HTTPS by a small aiohttp app
with an in-memory fake driver holding mutable system state. Architecture
is inspired by the sushy-tools emulator (OpenStack, Apache-2.0), written
independently for badfish under GPL-3.0-or-later.

Covers the surface badfish actually talks to: session/token auth, power
and reset, one-shot boot and boot order, BIOS registry and attributes,
jobs queue, virtual media, firmware inventory, processor/memory/network
inventory, the Dell OS deployment service and SCP targets, and the Dell
network attribute registry. Screenshot and network ISO actions report
"not supported" so badfish degrades gracefully.

Default credentials are quads/quads (override with BADFISH_EMULATOR_USER
and BADFISH_EMULATOR_PASSWORD). TLS uses a bundled self-signed test
certificate, so clients should pass --insecure.

Tests: unit coverage of the API surface plus an end-to-end test that
runs the real badfish client against a live emulator over TLS.
Adds the Redfish AccountService surface to the mock iDRAC: a JSON-backed
user store (created at runtime, /tmp by default, BADFISH_EMULATOR_USERS to
relocate), roles ReadOnly/Operator/Administrator, per-role authorization on
mutating requests, and the last-enabled-Administrator guard. Users can be
created, edited, removed and have passwords changed over the API, so future
badfish user/RBAC client work has a stable target.

The store stays a flat JSON file rather than sqlite on purpose: the emulator
is a temporal testing fixture, not a persistent service, and JSON keeps the
state human-inspectable and aligned with the DMTF/sushy mockup convention.
sqlite would be stdlib-safe too, but its durability/concurrency advantages
are precisely what this throwaway scope does not need.

Also ships the account_service and account templates (previously missing),
warts the e2e test off the shared /tmp default store, and declares template
and cert package_data so the emulator actually runs from an installed wheel
or RPM (templates were previously omitted from the build entirely).
Codecov patch coverage on the new emulator surface was 74.45% against a
93.43% target, pulling the PR check red. Adds targeted tests for the
member collections (NIC/CPU/DIMM), session and registry resources,
malformed-JSON 400s on every JSON reader, ChangePassword and account
PATCH/DELETE error paths, reset variants and BIOS/Manager actions, the
Dell OEM endpoints (job queue, OS deployment, SCP import/export,
screenshot), PATCH/DELETE fallthroughs, garbage Basic auth, corrupt-store
recovery, and a live run_daemon smoke test plus the main() routing branch.

Two small correctness fixes surfaced while chasing coverage: the chassis
Power consumption was dead code (shadowed by the static URI map), so it
never varied with power state, and run_daemon now returns web.run_app()
so callers can drive it. Patch coverage is now ~99%.
… private key

The emulator bundled a self-signed private key in SCM and in the wheel/RPM
(emulator/certs/emulator.key). This removes it from the repo and from
package data, and generates a fresh per-install localhost keypair on first
run under $XDG_CACHE_HOME/badfish/emulator (overridable via
BADFISH_EMULATOR_CERTS), so no private key ever sits in public artifacts.
Existing certs are reused; the key is written 0600. Tests cover generation,
reuse, missing-openssl, default-dir resolution, and the live daemon now
exercises runtime generation.
…ose RBAC gaps

Findings from independent + contrarian review of this PR, all verified live:

- NetworkPorts / NetworkDeviceFunctions collections now served (were 500:
  _STATIC_URI referenced templates that don't exist). badfish walks these
  in get_network_adapters / get_nic_fqdds.
- DellNetworkAttributes also registered on the Chassis tree (client uses
  /Chassis/... not /Systems/... for get/set_nic_attribute).
- SCP export job now carries SystemConfiguration so export_scp completes
  instead of timing out; task template gains Oem.Dell.Message so
  import_scp's progress poll reads cleanly.
- DetachISOImage returns 200 like real iDRAC (badfish only accepts 200).
- Last enabled Administrator cannot be demoted via RoleId (previously only
  disable/delete were guarded); roles re-resolved live so demotions take
  effect on existing sessions instead of a login-time snapshot.
- Pending restart power-on task is cancelled by any later reset.
- NetworkPorts member resources served; firmware member ids singularized;
  reused certs re-applied 0600.
- Tests: network collections + Chassis NIC attribute set, export/import
  payload asserts, live-RBAC demotion, restart override, end-to-end drives
  get_network_adapters/get_nic_fqdds/get_nic_attribute/detach/export_scp.
Per maintainer direction on review follow-ups:
- Jobs report Running/0% on the first read, then Completed/100% on the
  next, so badfish's poll-and-retry job loops exercise a real lifecycle
  instead of instant success. The job-creation POST body renders without
  consuming a read so the first client poll sees the running state.
- Import tasks are now tracked; TaskService/Tasks/<unknown> 404s like
  real iDRAC (badfish only polls tasks it created via SCP import).
- RBAC intentionally left permissive: Operator may run SCP/job actions.
…user store

The ServiceRoot advertised Chassis, TaskService and Registries, but all three
404'd, which would break any Redfish client that walks the link tree. Serve a
Chassis collection, a TaskService resource with its Tasks collection, and a
Registries collection. The user store is now written 0600 (not world-readable
under a default umask), uses a unique temp filename so concurrent instances
don't race, and the throwaway default /tmp path is no longer trusted: a
pre-existing file there (e.g. a locally planted Administrator) is ignored.
…id helper

Make _collection_uri data-driven (open/closed: a new collection is a row in
_COLLECTIONS, not a new branch), centralize the malformed-JSON 400 handling in
_read_body (was 8 duplicated blocks), and factor the JID_ generation into
_next_job_id (was 3 duplicated blocks). The extended flag for splitting the 919-line
god-module into multiple files was deliberately deferred: the independent review
judged a single file defensible for a dev-only mock, the module's helpers are
referenced directly by the tests, and a physical split would churn tests and
package_data for little gain.
Forks don't have the QUAY_USERNAME/QUAY_API_TOKEN secrets, so the
Development Build workflow dies at podman login on every fork push
(empty password -> 'inappropriate ioctl for device'). Gate the quay_dev
job to this repo so forks skip it and the dev image is still published
from quadsproject/badfish exactly as before.
Run black to fix the two lint errors that fail the repo-wide Black check on development: expand the state.jobs[job_id] dict literal (over 120 chars) and collapse the parenthesized uloc expression to one line.

fixes: #556
The emulator subcommand shells out to openssl to generate its self-signed
TLS cert on first run. Without openssl in BuildRequires/Requires the rpmbuild
%check step (pytest) fails the 3 emulator tests with 'openssl not found'.

Add openssl to BuildRequires (for %check) and Requires (runtime), and to the
dnf install list in the rpmlint workflow.
fix: black-format emulator.py and main.py
Add a Common Operations section and TOC entry for the --ls-gpu flag.
Correct the interface-key format spec and all examples to match the
shipped idrac_interfaces.yml keys, which use no _interfaces suffix.
The EthernetInterface template renders an empty Id, so badfish's
boot_to_mac sees device=None and raises 'MAC Address does not match any
of the existing'. Populate the member Id from its resource id so
collection members (EthernetInterface, Processor, Memory) carry a real
identity and boot-to-mac resolves the device.

Fixes #564
docs: document --ls-gpu and correct interface-key naming
fix(emulator): set member Id so boot-to-mac resolves devices
ttlogan and others added 16 commits September 8, 2026 22:36
Dell 17G hosts (R670, iDRAC10) fail virtual media cleanup and OS
deployment with "Could not unmount virtual media" and "iDRAC version
installed doesn't support DellOSDeploymentService". iDRAC10 dropped the
legacy /redfish/v1/Dell OEM namespace and no longer serves the
VirtualMedia collection under the manager resource.

Port of quadsproject/quads#723 (commit 0dd27bb4):
- find_virtual_media_resource() resolves VirtualMedia from the manager
  then system resource, caching the result. Supermicro keeps VM1.
- is_optical_media() and get_virtual_media_device() replace the
  [x for x in vm_config if "CD" in x][0] filter; a miss raises
  BadfishException instead of IndexError.
- find_os_deployment_resource() tries {system}/Oem/Dell/... then the
  legacy /redfish/v1/Dell path, caching the result. The OS deployment
  action URIs now use the resolved resource.

fixes: quadsproject/quads#723
…-deployment

fix: iDRAC10 virtual media and OS deployment paths
The default Dockerfile ran 'git clone https://github.com/quadsproject/badfish' with no -b
flag, so it pulled the repository default branch (master) regardless of what the CI
checkout had. The development-build workflow therefore published a master/v1.6.0 image
as quay.io/quads/badfish:development, which lacked development features like the
built-in Redfish emulator.

Build from the already-checked-out context instead (COPY . /badfish + WORKDIR /badfish).
Both development-build and production-release workflows already actions/checkout the
target ref, so this removes the default-branch dependence and the clone race. Added a
minimal .dockerignore to keep .git and python caches out of the build context.
The image now builds from the checked-out context instead of cloning
the repo, so git is unused at build and runtime. Dockerfile_dev and
Dockerfile_local are not referenced by any workflow or documentation,
so remove them.
…rses

boot_to_type returns its boot_to result and execute_badfish folds a
False result into the exit status. export_scp joins the export filename
to the target directory instead of concatenating. find_systems_resource
wraps both response JSON parses in the standard BadfishException guard.
- F3: timestamp-string YAML loader at all four parse() load sites so
  zero-date ReleaseDate (0000-00-00T00:00:00Z) stays a string instead of
  raising ValueError in yaml.safe_load; ValueError added to outer except.
- F4: defensive diff() tolerates 0/1 hosts, missing SoftwareId/Version,
  compares Version via str() and avoids zip truncation.
- F9: BadfishLogger creates the parent dir of --log before FileHandler.
- F11/F13: emit structured check-boot data (BootOrder/HostType) and guard
  parse() against missing messages so -o json --check-boot is sensible.

Fixes #559 #560 #565 #567 #570
Full documentation sweep against the development branch codebase: fix TOC
structure and anchors, document missing CLI options (--timeout, --insecure,
--rack, --uloc, --blade), refresh the features and requirements lists, fix
broken examples and typos, and update Redfish emulator documentation.
docs: sync README with current badfish feature set
Add --retry=5 --retry-delay=15s to the podman build and push commands
in the production release workflow so transient Quay CDN connection
failures no longer fail releases.

fixes: #582
Fix spelling and grammar errors in README, CONTRIBUTING and the
issue/PR templates, modernize stale GitHub documentation links,
and correct inaccurate claims (Redfish IPMI 2.0 requirement
wording, --get-power-consumed vendor scope, nonexistent
'Ready for review' template, Docs team reviewer).

No functional changes; documentation only.
Address reviewer feedback (sadsfae):
- README: narrow python3-devel requirement to only pip source
  builds (packager-side BuildRequires otherwise)
- README: restore lowercase fc640 in the machine table for
  consistency with the other rows and config key style
- README: replace 'minimal IPMI 2.0 specification' with 'Redfish
  boot source override' (badfish is Redfish-only)
- CONTRIBUTING: modernize the last old-scheme docs link
- CONTRIBUTING: drop redundant 'for' in 'request for additional'
docs: fix typos and inaccuracies in README and CONTRIBUTING
@sadsfae
sadsfae merged commit 3f9889a into master Sep 16, 2026
21 checks passed
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.

5 participants