Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/machine-health/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "machine-health",
"version": "0.11.18",
"version": "0.12.0",
"description": "Workstation health audit: OS-specific checks (disk, OS updates, security posture, CISA KEV correlation) run from a versioned catalog with trend-aware severity, approval-gated remediations, and dated markdown reports. Windows fully implemented; macOS/Linux scaffolded (report UNKNOWN and stop). Machine state persists in the plugin data directory; the report directory and check catalog are configurable.",
"author": {
"name": "Melodic Software",
Expand Down
16 changes: 16 additions & 0 deletions plugins/machine-health/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@
All notable changes to the `machine-health` plugin are documented here. Format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning.

## [0.12.0]

### Added

- **New check: `drive-root-litter` (catalog #19).** Reports unexpected files and directories at
fixed-volume roots — the class a disk audit found as an empty `C:\tmp` path-translation artifact
and a 0-byte `C:\log.txt` dropped by an elevated process with CWD `C:\` — so root droppings
surface on a routine health run instead of only during a manual audit. The expected-entry set is
data (`references/windows/drive-root-baseline.jsonc`), not script logic: the system drive gets a
full baseline diff, non-system volumes report only known litter-name shapes (user content there is
presumed intentional), and admitting a new legitimate entry is a data edit. Severity caps at WARN
(≥10 residue entries) with INFO below — tidiness, never CRIT — and the check is excluded from the
trend engine's generic upward upgrade. Output is deterministic (sorted residue, day-granularity
`created` dates) so an unchanged dropping feeds `identical_streak` demotion instead of reading as
news every run. Read-only, no elevation, Windows only; removal routes to `disk-hygiene:clean`.

## [0.11.18]

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion plugins/machine-health/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ from a versioned catalog, with trend-aware severity, narrow approval-gated remed
dated markdown report per run. Fail-safe posture throughout: surface issues over silently fixing
them, and every finding carries reproduction commands.

Windows is fully implemented (18 checks, PowerShell 7.x). macOS and Linux are scaffolded as
Windows is fully implemented (19 checks, PowerShell 7.x). macOS and Linux are scaffolded as
honest `NOT_IMPLEMENTED` stubs. On those hosts the skill reports UNKNOWN and stops rather than
pretending coverage.

Expand Down
13 changes: 13 additions & 0 deletions plugins/machine-health/skills/audit/catalog/checks.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,19 @@
"added_on": "2026-08-21",
"crash_count": 0,
"identical_streak": 0
},
{
"id": "drive-root-litter",
Comment thread
kyle-sexton marked this conversation as resolved.
"category": "storage",
"os": ["windows"],
"script": "scripts/windows/checks/Test-DriveRootLitter.ps1",
"severity_rules": "references/windows/check-catalog.md#19-drive-root-litter",
"needs_admin": false,
"enabled": true,
"deprecated": false,
"added_on": "2026-08-30",
"crash_count": 0,
"identical_streak": 0
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- [8. Driver inventory](#8-driver-inventory)
- [17. Claude Code temp root](#17-claude-code-temp-root)
- [18. Environment and PATH health](#18-environment-and-path-health)
- [19. Drive-root litter](#19-drive-root-litter)

Per-check rubrics for Windows. Section numbers follow the order of `catalog/checks.jsonc` and are
load-bearing — each is the anchor a catalog entry's `severity_rules` points at, so renumbering breaks
Expand Down Expand Up @@ -363,3 +364,73 @@ All checks emit the schema in `references/shared/output-schema.md`, use `scripts
A User-scope `=1` silently freezes the installed binary — the defect that motivated
this check. Duplicate and missing PATH entries are INFO because presence is a shape,
not a verdict that the entry should be removed.

---

## 19. Drive-root litter

- **Script:** `scripts/windows/checks/Test-DriveRootLitter.ps1`
- **Category:** `storage`
- **Needs admin:** no. Listing a volume root, reading root-entry owners via `Get-Acl`, and
probing a stray directory for emptiness all work un-elevated; when an owner or emptiness
probe is denied anyway the field ships as `null` and severity is unaffected.
- **Remediation:** none. The check reports; it never deletes, moves, or modifies. Removal
routes to `disk-hygiene:clean` (`detail.remediation_route`), which owns deletion behind
its own snapshot and approval model.
- **Commands:**

```powershell
Get-ChildItem -LiteralPath "$env:SystemDrive\" -Force | Select-Object Name, Mode, Length
Get-Volume | Where-Object { $_.DriveType -eq 'Fixed' -and $_.DriveLetter }
```

- **What it detects:** entries at a fixed-volume root that nothing on the machine accounts
for — the class a disk audit once found as an empty `C:\tmp` path-translation artifact
and a 0-byte `C:\log.txt` dropped by an elevated process whose CWD was `C:\`. Both files
and directories are in scope; the listing is **non-recursive** (the root's own entries,
nothing below them).

- **Baseline is data, not logic:** the expected-entry set lives in
`references/windows/drive-root-baseline.jsonc`. Admitting a newly legitimate entry is an
edit to that file, never a script change. Names are `-like` patterns (case-insensitive,
`*`/`?` wildcards) matched **type-aware** — a directory only matches the `directories`
list, a file only the `files` list, so a stray file named `Recovery` cannot hide behind
the expected directory of the same name.

- **Per-volume posture:**
- **System drive** (`%SystemDrive%`): full baseline diff. Every root entry not matching
`all_volumes` + `system_drive` is residue.
- **Non-system fixed volumes** (data drives, Dev Drives): a user-managed root legitimately
holds arbitrary content, so a baseline diff there would be all noise. Only names matching
the `data_volume_litter` shapes (`tmp`, `temp`, `tmp.*`, `log.txt`, `*.tmp`) are
reported; everything else is presumed intentional. A machine that deliberately keeps a
`D:\tmp` admits it with a baseline data edit.
- Removable and network drives are never scanned.

- **Severity rubric:**
- `WARN` — ≥10 residue entries: something is actively dumping at a root, action this week.
- `INFO` — 1–9 residue entries.
- `OK` — no residue.
- `UNKNOWN` — the baseline file is missing or unparsable (no way to tell residue from a
legitimate entry), **or** any root could not be listed at all (an unlistable root can
hide any amount of litter, so partial results cannot support a threshold verdict —
partial residue still ships in `detail`). `ran_successfully = false` keeps such a run
out of `checks_ran` so an undercounted `residue_count` never becomes a trend baseline.
- No `CRIT`. Root litter is tidiness with no data-loss or security consequence, and
`references/shared/severity-rubric.md` reserves `CRIT` for imminent-failure and security
conditions while directing ambiguity to the lower level. `drive-root-litter` is mapped
to `residue_count` for history but deliberately **excluded** from the trend engine's
generic upward upgrade for the same reason.

- **Trend behavior:** output is deterministic — residue sorted by volume then name, and each
entry carries a `created` **date** (day granularity, stable across runs) rather than an
instant — so a dropping that sits unchanged produces identical findings run over run and
feeds the catalog's `identical_streak` demotion accounting instead of reading as news
every week. `residue_count` is the history metric.

- **Notes:** owner (`Get-Acl`) and directory emptiness (first `EnumerateFileSystemEntries`
hit only — the check never recurses into a stray directory) are best-effort diagnostic
context: the original `C:\log.txt` was attributed by its `BUILTIN\Administrators` owner.
`Get-Volume` failing (Storage module unavailable) degrades to scanning the system drive
alone rather than `UNKNOWN`. The check is Windows-only; a POSIX port would need its own
baseline semantics (`/` has a very different expected set) and is not scaffolded.
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Expected-entry baseline for the drive-root-litter check
// (scripts/windows/checks/Test-DriveRootLitter.ps1).
//
// The check lists each fixed-volume root non-recursively and reports the
// residue: entries this file does not expect. The baseline is data on purpose
// so admitting a new legitimate entry is an edit here, never a script change.
// Names are matched case-insensitively with PowerShell -like semantics, so `*`
// and `?` are wildcards. Matching is type-aware: a directory only matches the
// "directories" list and a file only the "files" list -- a stray FILE named
// "Recovery" must not hide behind the directory of the same name.
//
// Rubric and rationale: references/windows/check-catalog.md#19-drive-root-litter
{
// Expected at the root of ANY fixed volume. NTFS/ReFS housekeeping the OS
// creates on every volume it touches.
"all_volumes": {
"directories": [
"$Recycle.Bin",
"System Volume Information",
"Recovery",
"Config.Msi", // Windows Installer rollback staging; appears wherever an MSI ran
"OneDriveTemp" // OneDrive sync staging on the volume hosting a synced folder
],
"files": []
},
// Expected only at the SYSTEM drive root (%SystemDrive%, normally C:\).
"system_drive": {
"directories": [
"Windows",
"Program Files",
"Program Files (x86)",
"ProgramData",
"Users",
"PerfLogs",
"Documents and Settings", // hidden compatibility junction to Users
"$SysReset", // Reset-this-PC logs
"$WinREAgent", // Windows RE servicing staging
"$GetCurrent", // media-based feature-update staging
"$Windows.~BT", // in-place upgrade staging
"$Windows.~WS", // media-creation staging
"inetpub" // created on ALL machines by the April 2025 security update (CVE-2025-21204 hardening), IIS installed or not
],
"files": [
"pagefile.sys",
"swapfile.sys",
"hiberfil.sys",
"DumpStack.log",
"DumpStack.log.tmp",
"bootmgr",
"BOOTNXT",
"BOOTSECT.BAK",
"bootTel.dat",
"autoexec.bat", // NTVDM-era stubs some upgrade lineages still carry
"config.sys"
]
},
// A NON-system volume root (data drive, Dev Drive) legitimately holds
// arbitrary user content, so a baseline diff there would be all noise.
// On those volumes only names matching these known machine-generated
// dropping shapes are reported; everything else is presumed intentional.
"data_volume_litter": {
"directories": [
"tmp", // POSIX-tool path-translation artifact (an MSYS/Cygwin /tmp landing at the root)
"temp",
"tmp.*" // mktemp-style names written to the wrong CWD
],
"files": [
"log.txt", // default log name of a process whose CWD was the volume root
"tmp.*",
"*.tmp"
]
}
}
Loading