Jul 2026 - Present Solo build: tools, tests, documentation
Tools and Scripts
Twenty-seven small tools for monitoring, Windows and Linux administration, and Ansible automation, each with its own README, example config, safeguards, and tests, all held to one repository-wide check.
ls -1 <folder>/
Live OS matrix: pending
Tools and Scripts collects the small utilities I write for DevOps, IT operations, security work, migrations, and self-hosted infrastructure. It holds 27 tested tools in Python, Bash, PowerShell, and Ansible, from a read-only Prometheus target check to an Ansible project that patches a Linux fleet. The point of the repository is the standard every tool is held to: its own folder, the same twelve README sections, local config that never holds secrets, a dry run or check mode before risky changes, an exact confirmation phrase before the ones that can cut off access, and tests. One command verifies all of it, and the README is plain about what that verification does and does not prove.
Five folders, one tool per folder
The tools are grouped by area rather than by language. Each one lives in its own folder with its README, an annotated example config, a guided configurator, and its tests, so a reader can download a single folder and run that tool without the rest of the repository.
- monitoring/
- Prometheus target and Grafana dashboard checks, node_exporter textfile collectors for DNF updates and Cloudflare tunnel health, TeamSpeak and Minecraft probes, a UniFi flow collector and dashboards for Splunk, and a Discord alert relay
- windows/
- An online-logon GPO, a key-only OpenSSH workstation bootstrap, a recovery-environment lockdown, daily session limits, and an installer signature check, plus one small batch file
- linux/
- A NetworkManager cutover with automatic rollback, a Proxmox subscription-notice tool, a Wazuh hash list refresh, and a guarded Compose service update
- automation/
- Four Ansible projects (fleet updates, monitoring exporters, a Linux access baseline, and SSH key rotation), two Semaphore tools, and a TeamSpeak channel migration
- utilities/
- A PowerShell TCP reachability check and a Node.js server that previews only the tracked files of a git working tree
The contract every tool follows
A template in the repository spells out what each tool owes its reader, and repository-level tests enforce the parts a test can check: every tool folder needs a README, a configurator, and a tests folder, and every README needs the same twelve sections, from use case and dry run through safeguard reasoning, rollback, and exit behavior.
Near its first runnable command, each README also states the platform, the privilege it needs, exactly what it changes, how to preview it, where rollback stops, and what every nonzero exit code means.
- Configuration
- A tracked config.example and an ignored config.local, with a CUSTOMIZE: marker beside every value the user owns. The command line beats local config, which beats documented defaults
- Secrets
- Never in config files or arguments. Tools read them from a named environment variable or a hidden prompt
- Configurators
- Refuse to replace an existing local config unless the user passes a separate, documented overwrite option
- Preview
- Dry runs, Ansible check mode, PowerShell WhatIf, or a plan-only default, so a change can be reviewed before it happens
- Gates
- Anything that can remove access, interrupt networking, replace data, or create remote objects needs an explicit gate, and an exact phrase when one stale flag could turn a preview into a live run
A network cutover that rolls itself back
The NetworkManager cutover moves a Linux interface onto a prepared NetworkManager profile, a change that can cut off the SSH session running it. It has three paths: ifupdown on Debian 13, Netplan on Ubuntu 24.04, and direct profile activation on Rocky 10, since RHEL 10 removed support for legacy ifcfg files. The replacement network file is supplied whole and reviewed, because a partial automatic edit can leave two network systems owning one interface.
The dry run checks dependencies, config syntax, which file owns the interface, the candidate file, and the profile binding without changing anything. The live run backs up the source file where there is one, switches over, and then asserts the exact IPv4 address, the full default-route set with its metrics and tables, the exact DNS server set, and the active profile. A failed assertion, a timeout, an interrupt, or a termination signal starts rollback: the timestamped backup is restored and the tool tries to bring the prior connection back up.
A hash list that never installs empty
Wazuh can check file hashes against services like VirusTotal, but free API tiers have quotas, and lookups that hit the quota fail without alerting. This Bash tool builds a local CDB list of known-bad SHA-256 hashes from the abuse.ch MalwareBazaar recent feed instead, so a lookup on the manager needs no API call at all.
It pins the harmless EICAR test hash as the first line so the alert pipeline can be tested on demand, and it refuses any list below a minimum entry count so a failed or empty feed cannot wipe the active one. The new list is written to a staging file in the destination folder and renamed into place, so if anything fails before the rename, the old list stays byte-identical. After restarting the manager it confirms the service is active again, and it ships with a systemd service and timer for scheduled runs.
Fleet patching behind explicit gates
The fleet updates project is an Ansible project that patches Linux hosts through apt or dnf and updates the Docker Compose projects listed in a reviewed inventory. Nothing discovers new hosts or projects on its own, and both plays refuse live changes unless fleet_confirmation is set to exactly UPDATE FLEET.
There is no automatic rollback of packages, reboots, or recreated containers, and the README says so and asks for tested backups and console access before a live window.
- Reboots
- Report-only by default. Opting into reboot=auto forces one host at a time, and an early assertion stops the play if the batch holds more than one host
- Reboot proof
- Records the boot ID, reboots through a transient systemd timer, reconnects, and treats a changed boot ID as the proof, then waits for systemd to report running
- Compose health
- An update only passes when every container is running and every configured health check is healthy
- Inventory validator
- Rejects empty groups, duplicate YAML keys, privileged login accounts, inline credentials, and unguarded local connections without contacting a host
Checked locally, not yet claimed live
One command, python check.py, is the only complete verification. It runs Ruff lint and format checks, pytest, Python compilation, example-config parsing, a help check for every command, Bash, PowerShell, and Node syntax checks, ShellCheck, Ansible Lint and a syntax check of every playbook, and a Gitleaks scan of the full Git history. A missing checker fails the run with the install step instead of being skipped, and on Windows the Linux-side checks run inside WSL.
The Bash tools are tested from pytest. The Wazuh tests, for example, put fake curl, install, and systemctl commands first on PATH to simulate an empty feed, a failed download, and an install that corrupts its target, then assert the old list is untouched. The first recorded run, on July 20, 2026, covered five tools and 59 tests. The latest, on September 25, 2026, passed 49 check groups and 797 tests with one Windows-only test skipped, and Gitleaks found no leaks.