Engineering Notes

Building Asset Governance: Audit Before Effects

How I used HHY to detect risky assets, emit a reviewable action plan, and apply allow-listed remediation through runtime-native dry-run semantics.

HOUHUIYANG.COM

Scan to continue reading

Generating…

Building Asset Governance: Audit Before Effects

houhuiyang.com/en/notes/building-asset-governance-with-hhy

The dangerous property of a cleanup script is often not that it cannot delete files, but that deletion is too easy.

I therefore split Asset Governance into two programs. audit.hhy observes and writes a report. cleanup.hhy executes only explicit copy, move, and remove actions from that report. Between judgment and effects sits a boundary that can be read, reviewed, and dry-run.

The closer automation gets to destructive effects, the more its plan should become a first-class artifact.

The actual Asset Governance layout and risky fixtures

Inventory before remediation

inventory uses files("**/*"), totals real Bytes, and checks three metadata rules: size beyond a configured threshold, uppercase letters or spaces in names, and modification time older than 365 days.

Content inspection reads only supported text extensions. A possible credential becomes a critical finding, but matching text never enters the report. Duplicate content is grouped by its text while the result retains only filenames.

Images and videos are deliberately not decoded. This project governs file metadata and placement. Detecting an oversized MP4 does not justify adding a media stack.

The report is evidence and input

The report contains inventory statistics, findings, and configured actions. A critical finding makes audit.hhy return 1, but the full report is still written atomically.

That differs from moving files inside the scanning loop. A failed audit is not uncontrolled execution; it is a successful discovery that requires attention, with evidence preserved for the operator.

The cleaner recognizes only three actions:

if action.kind == "copy" {
    copy(source, path_join(root, action.target), { overwrite: true })
} else if action.kind == "move" {
    move(source, path_join(root, action.target), { overwrite: true })
} else if action.kind == "remove" {
    remove(source)
} else {
    exit(3)
}

Actions are constrained by the report and never routed through a shell. Arbitrary commands and their injection surface are outside the model.

Dry-run belongs to the runtime

cleanup.hhy contains no hand-written if dry_run branch. The same program runs as:

hhy run --dry-run practical-projects/asset-governance/cleanup.hhy PROJECT report.json

The runtime EffectDispatcher intercepts copy, move, and remove operations and prints the plan. Business code follows the same control path without changing files. This is more dependable than duplicating preview logic at every effect call site.

Asset Governance audit, dry-run, and applied-remediation verification

The self-test creates an isolated mktemp workspace, verifies large, naming, stale, sensitive, and duplicate findings, proves that dry-run changes nothing, then applies and asserts copy, move, and remove.

The engineering principle I kept

Safe automation does not mean refusing every dangerous operation. It means separating observation, decision, and execution so every stage has reviewable inputs and outputs.

The most important result is the audit chain: file facts become findings; findings and configuration become actions; actions pass through dry-run before real effects. HHY's Path, Bytes, Duration, Regex, and Effect models keep that chain out of stringly typed shell assembly.

References

Back to Engineering Notes