Lab 05 — Building CLI Tools¶
Hands-on lab · ← Back to the module concept
Lab environment: real-feed rewire — validation deferred. The sidecar threat-intel API now serves real abuse.ch data (Feodo Tracker + URLhaus) from
feeds/db.json, shared with module 04.make up && make demo && make downhas not yet been re-run on a clean Linux runner against this change; validate before marking the lab done.
Setup¶
git clone https://github.com/plaintext-security/plaintext-labs
cd plaintext-labs/python-for-security/05-building-cli-tools
make up # Python 3.12 container with typer + httpx installed; real-feed API running
make demo # shows ioc-check --help and a sample enrich run
make refresh # (optional, needs network) re-fetch the LIVE abuse.ch feeds into feeds/db.json
make shell
make down
The real-feed threat-intel API from module 04 runs as a sidecar (abuse.ch Feodo Tracker +
URLhaus, served locally from feeds/db.json with source/fetched_at provenance). The student
container has typer, httpx, and rich installed. data/iocs.txt is the same real-IOC list
from module 04 (real malicious C2 IPs, URLhaus sample ids, and known-clean public resolvers).
Scenario¶
The enrichment script from module 04 works, but the rest of the team can't use it without reading
the source. Your task: wrap it into a proper CLI tool called ioc-check with --help output,
typed arguments, two subcommands (enrich and report), and clean error messages. The tool
should be runnable by anyone who can type python ioc-check.py --help.
Do¶
- [ ] From the scenario, sketch the CLI contract before writing code: which subcommands, which
arguments and types, and what a good error message looks like for an invalid IOC type. (You'll
diff your
--helpagainst the reference at the end withmake demo— design it yourself first.) - [ ] Create
ioc-check.pywith twotypersubcommands: enrich: accepts--ioc(a single IOC string) or--file(a path to a list), and--output(optional path for JSON output; default stdout). Calls the mock API.report: reads the JSON output fromenrichand prints arichtable summary.- [ ] Add input validation to
enrich: reject clearly invalid IOC formats (non-IP strings that aren't valid SHA-256 hashes) with a clear error message and exit code 1. - [ ] Confirm that
python ioc-check.py enrich --ioc 8.8.8.8produces valid JSON output. - [ ] Confirm that
python ioc-check.py enrich --file data/iocs.txt | python ioc-check.py reportworks end to end via stdin pipe. - [ ] Run
make demoagain — confirm your tool's--helpoutput matches the reference shape.
Success criteria — you're done when¶
- [ ]
python ioc-check.py --helpshows both subcommands with descriptions. - [ ]
python ioc-check.py enrich --ioc 8.8.8.8exits 0 and produces JSON. - [ ]
python ioc-check.py enrich --ioc not-validexits 1 with a helpful error message. - [ ] The
enrich | reportpipeline works end to end.
Deliverables¶
ioc-check.py. Commit it. Do not commit generated output files.
Automate & own it¶
Required. Add a version subcommand that prints the tool version from a __version__
variable. Then write a test_cli.py that uses typer.testing.CliRunner to test at least three
invocations: a valid single-IOC enrich, an invalid IOC (expects exit code 1), and --help
(expects exit code 0 and "enrich" in the output). Have a model draft the tests; run them with
python -m pytest test_cli.py; commit the test file.
AI acceleration¶
Describe the tool's desired interface to a model and ask it to generate ioc-check.py with
typer. Then try to break it: call it with --ioc "" (empty string), --file /nonexistent,
and --ioc 192.168.1.999. Does it handle each case correctly? Fix what breaks and commit the
fix with a comment explaining what the model missed.
Connects forward¶
ioc-check becomes the foundation for the MCP server in module 09 — the server exposes the
same enrich function as an LLM tool. The typer pattern reappears in every automation script
in Track 10.
Marketable proof¶
"I build security CLI tools with typer — typed arguments, --help output, composable subcommands, and clean exit codes so they work in shell pipelines and CI gates."
Stretch¶
- Package
ioc-checkas a proper Python package withpyproject.tomlso it installs viapip install .and runs asioc-check(notpython ioc-check.py). - Add shell completion using
typer's built-in completion support.
Comments
Sign in with GitHub to comment. Choose the type: Feedback (errors or suggestions on this page) · Hints (help for fellow learners — no spoilers) · General (anything else).