{"id":51183213,"url":"https://github.com/pmuller/hw-validation","last_synced_at":"2026-06-27T08:03:41.283Z","repository":{"id":363592195,"uuid":"1264037952","full_name":"pmuller/hw-validation","owner":"pmuller","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-09T13:56:51.000Z","size":124,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-09T15:26:48.136Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pmuller.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-09T13:55:58.000Z","updated_at":"2026-06-09T14:06:37.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/pmuller/hw-validation","commit_stats":null,"previous_names":["pmuller/hw-validation"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/pmuller/hw-validation","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmuller%2Fhw-validation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmuller%2Fhw-validation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmuller%2Fhw-validation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmuller%2Fhw-validation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pmuller","download_url":"https://codeload.github.com/pmuller/hw-validation/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmuller%2Fhw-validation/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34845750,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-27T02:00:06.362Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-27T08:03:40.454Z","updated_at":"2026-06-27T08:03:41.278Z","avatar_url":"https://github.com/pmuller.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hardware Validation Toolkit\n\nOne Python CLI for generic Linux hardware validation: host audit, stress, scratch filesystem I/O, network burn-in, disk validation, log triage, and readiness reporting.\n\nThe `hw-validation` command can run from any directory. Become root first for commands that require privileged hardware access.\n\nRepository-root context is only required for development commands such as `uv run ...`, `make ...`, tests, and builds.\n\n## Development\n\nRun these commands from the repository root:\n\n```bash\nmake sync\nmake check\n```\n\nCommon tasks:\n\n| Command | Purpose |\n|---|---|\n| `make help` | Show Make targets. |\n| `make format` | Format and auto-fix Python code. |\n| `make check` | Run lint, format check, typecheck, and tests. |\n| `make smoke` | Run CLI help smoke checks. |\n| `make build` | Build `dist/hw-validation.pyz` with shiv. |\n\n## Setup\n\nFrom a development checkout, run this from the repository root because `uv run` reads `pyproject.toml` and `uv.lock`:\n\n```bash\nuv run hw-validation setup\n```\n\nDry-run without changing the host:\n\n```bash\nuv run hw-validation setup --dry-run\n```\n\nThe setup command uses one Debian package set. Package installation failure is a setup failure.\n\n`setup` always passes `-y` to `apt-get install` to avoid interactive package prompts.\n\n## Commands\n\n| Command | Purpose | Destructive |\n|---|---|---:|\n| `hw-validation setup` | Install and verify host tooling. | No |\n| `hw-validation system audit` | Capture host, firmware, CPU, memory, PCIe, network, sensor, and storage inventory. | No |\n| `hw-validation system stress` | Run CPU, memory, EDAC/RAS/AER, and thermal stress validation. | No |\n| `hw-validation filesystem scratch` | Run fio write and verify jobs inside one created scratch directory. | Yes, inside scratch only |\n| `hw-validation network burnin` | Run iperf3 network burn-in and compare NIC health counters. | No |\n| `hw-validation disk audit` | Capture disk inventory and SMART/NVMe state. | No |\n| `hw-validation disk burnin` | Run destructive per-device disk validation. | Yes |\n| `hw-validation disk monitor` | Capture disk validation telemetry. | No |\n| `hw-validation logs triage` | Scan logs for hardware, kernel, storage, thermal, and network findings. | No |\n| `hw-validation readiness report` | Aggregate final PASS, WARN, or FAIL readiness status. | No |\n| `hw-validation performance report` | Extract fio and badblocks performance summaries from run artifacts. | No |\n\nEvery command has `--help`.\n\nCommands that write artifacts require `--out-root /absolute/path`. `logs triage`, `readiness report`, and `performance report` also require `--log-root /absolute/path` as input.\n\n## Duration And Timing\n\nDuration values are positive integers with an optional suffix: `s`, `m`, `h`, or `d`. A bare integer means seconds. Examples: `30s`, `5m`, `2h`, `1d`.\n\nCommands that run workloads write `plan.json`, per-command `*.meta.json` files, `timing_summary.json`, and `result.json` with `duration_seconds` and `completed_reason`.\n\n| Mode | Commands | Runtime behavior |\n|---|---|---|\n| Fast | `system audit`, `disk audit`, `logs triage`, `readiness report`, `performance report` | Runs collectors, scanners, or artifact summarizers once. |\n| Bounded | `network burnin`, `disk monitor --duration` | Runs for the requested duration plus setup and teardown. |\n| Phase-bounded | `system stress --phase-duration` | Applies the duration to each stress phase, so total runtime is longer than one phase. |\n| Size-bound | `filesystem scratch --size` | Full-file phases depend on size and device speed; random phases use `--runtime`. |\n| Pass-bound | `disk burnin` | Full-device passes depend on disk size and speed; random read phases use `--ssd-randread-duration` or `--hdd-randread-duration` unless `--skip-randread` is set. |\n| Until interrupted | `disk monitor --until-interrupted` | Runs until interrupted and records `completed_reason` as `interrupted`. |\n\n## Profiles\n\nUse `run` when you want the toolkit to compose the sequence, write a manifest, run reports, and enforce expected coverage:\n\n```bash\nuv run hw-validation run smoke \\\n  --out-root /var/log/hw-validation/2026-06-05-run01\n```\n\nProfiles:\n\n| Profile | Purpose |\n|---|---|\n| `smoke` | Short non-destructive validation: system audits, disk audit, disk monitor, triage, readiness. |\n| `standard` | Normal non-destructive validation: audits, stress, filesystem scratch, network burn-in, disk audit, disk monitor, reports. |\n| `acceptance` | Longer bounded validation using `long` durations. It still does not wipe disks by default. |\n| `disk-burnin` | Explicit destructive disk burn-in workflow. Requires exactly one `--device` or `--all-devices`, plus `--i-know-this-erases-data`. |\n\nSpeeds apply only to bounded workloads such as stress, filesystem, network, and monitor:\n\n| Speed | Stress phase | Filesystem runtime | Network | Monitor |\n|---|---:|---:|---:|---:|\n| `smoke` | `5m` | `2m` | `2m` | `2m` |\n| `standard` | `1h` | `30m` | `1h` | `1h` |\n| `long` | `8h` | `2h` | `8h` | `8h` |\n\nDisk burn-in is not a speed. It is pass-bound and device-bound. A true burn-in for a large HDD can take a week or more.\n\n`--all-devices` is intentionally explicit. It discovers non-removable writable whole disks, always removes disks backing the root filesystem before writing the plan, writes each selected device into `profile_manifest.json`, runs the pre burn-in disk audit for those devices, preflights every selected disk for whole-disk, mounted descendant, active swap, and holder safety, then runs the destructive burn-in steps for the selected disks in parallel. Each disk is validated again by the normal per-device burn-in safety checks and per-device locking.\n\nReview `profile_manifest.json` before running destructive work. Rootfs-backed disks are recorded in `excluded_devices` and logged during all-device discovery.\n\n`--all-devices` cannot be combined with `--resume`. Kernel device names are not stable enough to safely resume destructive all-device selection. If you need to resume after a partial all-device run, rerun the remaining disks explicitly with `--device /dev/disk/by-id/...`.\n\nCommon profile examples:\n\n```bash\nuv run hw-validation run standard \\\n  --out-root /var/log/hw-validation/2026-06-05-run01 \\\n  --scratch-path /var/tmp/hw-validation-scratch \\\n  --server 192.0.2.10\n\nuv run hw-validation run acceptance \\\n  --out-root /var/log/hw-validation/2026-06-05-run01 \\\n  --scratch-path /var/tmp/hw-validation-scratch \\\n  --server 192.0.2.10 \\\n  --speed long\n\nuv run hw-validation run disk-burnin \\\n  --out-root /var/log/hw-validation/2026-06-05-run01 \\\n  --device /dev/disk/by-id/ata-EXAMPLE_DISK_SERIAL \\\n  --i-know-this-erases-data\n\nuv run hw-validation run disk-burnin \\\n  --out-root /var/log/hw-validation/2026-06-05-run01 \\\n  --all-devices \\\n  --i-know-this-erases-data\n```\n\nUse `--parts` for targeted runs:\n\n```bash\nuv run hw-validation run standard \\\n  --out-root /var/log/hw-validation/2026-06-05-run01 \\\n  --parts system,disk-audit\n```\n\nProfile artifacts at the run root:\n\n| Artifact | Purpose |\n|---|---|\n| `profile_manifest.json` | Expected steps, labels, commands, selected profile, and speed. Written before execution. |\n| `profile_plan.md` | Human-readable plan. |\n| `report.json` | Profile-level execution summary. |\n| `report.md` | Profile-level human-readable report. |\n| `summary.txt` | One-screen status summary. |\n| `result.json` | Profile aggregate status. |\n\nUseful profile controls:\n\n| Option | Purpose |\n|---|---|\n| `--plan-only` | Write and print the plan without root or workloads. |\n| `--resume` | Skip profile steps that already have a matching `PASS` result for the expected step fingerprint. Not allowed with `--all-devices`. |\n| `--parts` | Select only some parts. |\n| `--speed` | Override bounded workload durations. |\n| `--all-devices` | For `disk-burnin`, discover all eligible disks except rootfs-backed disks and burn them in concurrently. |\n\nReadiness automatically checks `profile_manifest.json` when it exists. Missing required profile steps are reported as missing coverage instead of being silently ignored.\n\n## Run Order\n\n1. Setup tooling.\n2. Boot-level RAM test.\n3. Pre-system audit.\n4. System stress.\n5. Filesystem scratch test.\n6. Network burn-in.\n7. Disk validation, when storage validation is in scope.\n8. Post-system audit.\n9. Log triage.\n10. Readiness report.\n\n## Example Run\n\n```bash\nmkdir -p /var/log/hw-validation/2026-06-05-run01\n\nuv run hw-validation system audit \\\n  --out-root /var/log/hw-validation/2026-06-05-run01 \\\n  --label system-pre\n\nuv run hw-validation system stress \\\n  --out-root /var/log/hw-validation/2026-06-05-run01 \\\n  --label system-24h \\\n  --phase-duration 24h\n\nmkdir -p /var/tmp/hw-validation-scratch\n\nuv run hw-validation filesystem scratch \\\n  --path /var/tmp/hw-validation-scratch \\\n  --out-root /var/log/hw-validation/2026-06-05-run01 \\\n  --label filesystem-scratch \\\n  --size 20G \\\n  --runtime 1h \\\n  --cleanup\n```\n\nOn the peer machine:\n\n```bash\niperf3 -s\n```\n\nBack on this machine:\n\n```bash\nuv run hw-validation network burnin \\\n  --server 192.0.2.10 \\\n  --out-root /var/log/hw-validation/2026-06-05-run01 \\\n  --label primary-network \\\n  --duration 2h \\\n  --parallel 8 \\\n  --bidir\n```\n\nDisk validation, when in scope:\n\n```bash\nuv run hw-validation disk audit \\\n  --out-root /var/log/hw-validation/2026-06-05-run01 \\\n  --label disk-pre \\\n  --all\n\nuv run hw-validation disk monitor \\\n  --out-root /var/log/hw-validation/2026-06-05-run01 \\\n  --label disk-monitor \\\n  --duration 24h \\\n  --interval 30s \\\n  --smart-interval 5m\n\nuv run hw-validation disk burnin \\\n  --device /dev/disk/by-id/ata-EXAMPLE_DISK_SERIAL \\\n  --out-root /var/log/hw-validation/2026-06-05-run01 \\\n  --ssd-randread-duration 60m \\\n  --hdd-randread-duration 30m \\\n  --i-know-this-erases-data\n```\n\nUse `--smartctl-type TYPE` on disk audit, burn-in, or monitor commands when a device requires `smartctl -d TYPE`, for example USB SAT bridges or RAID-backed devices.\n\nFinish:\n\n```bash\nuv run hw-validation system audit \\\n  --out-root /var/log/hw-validation/2026-06-05-run01 \\\n  --label system-post\n\nuv run hw-validation logs triage \\\n  --log-root /var/log/hw-validation/2026-06-05-run01 \\\n  --out-root /var/log/hw-validation/2026-06-05-run01/logs-triage\n\nuv run hw-validation readiness report \\\n  --log-root /var/log/hw-validation/2026-06-05-run01 \\\n  --out-root /var/log/hw-validation/2026-06-05-run01/readiness-report\n\nuv run hw-validation performance report \\\n  --log-root /var/log/hw-validation/2026-06-05-run01 \\\n  --out-root /var/log/hw-validation/2026-06-05-run01/performance-report\n```\n\n## Deployment\n\nBuild from the repository root:\n\n```bash\nmake build\npython3 dist/hw-validation.pyz --help\n```\n\nCopy `dist/hw-validation.pyz` to the validation host after building.\n\n## Results\n\nEvery major command writes `result.json` under the explicit output root.\n\n`performance report` writes `performance_report.json`, `performance_report.md`, and `result.json`. It extracts fio stdout, fio JSON, and badblocks metadata from an existing log root. Fio metrics include bandwidth, IOPS, runtime, and percent of the comparable group median. Badblocks metrics are marked as wall-clock approximations because they are destructive multi-pattern sweeps, not isolated read/write benchmarks.\n\n| Code | Meaning |\n|---:|---|\n| 0 | Pass |\n| 1 | Hard failure |\n| 2 | Warnings or manual review required |\n| 64 | Usage or configuration error |\n| 70 | Internal or tooling error |\n\n| Status | Meaning |\n|---|---|\n| PASS | No failures and no unresolved serious warnings. |\n| WARN | No hard failures, but warnings require human review. |\n| FAIL | One or more hard failures. |\n\n## Blind Spots\n\nOS memory stress does not replace boot-level memory testing.\n\nECC must be verified as enabled.\n\nCorrected ECC errors during validation matter.\n\nPCIe AER errors are not normal during a clean validation run.\n\nStorage resets are not normal during a clean validation run.\n\nPassing one subsystem test does not validate all other subsystems.\n\nKeep the full run directory.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpmuller%2Fhw-validation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpmuller%2Fhw-validation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpmuller%2Fhw-validation/lists"}