feat: extract the assessment into a shared, headless surface (4.1.0) - #14
Merged
Merged
Conversation
The verdict rules, the Cisco client and the run orchestration were reachable only through `analyzer.run()`, which resolves credentials from the per-user config file, discovers an inventory in the working folder, prints to a terminal, writes an HTML file and exits the process. A second consumer could not call the assessment without inheriting all of that, so it would have had to reimplement the rules — and a reimplementation of Constitution IV is a second, divergent answer about the same firewall. Add `caia/assessment.py` holding `analyze(inventory, client)`: the whole check with no user interface attached. It takes a list of per-device dicts (whatever produced them) and a `psirt.Client` the caller owns; it prints nothing, writes nothing, never exits the process and never consults the working folder. `_load_catalogues`, `_run_checks` and `_assemble_devices` move there unchanged. Together with `matching`, `psirt` and `inventory`, this is now the package's documented shared surface. `analyzer` keeps the terminal run flow and supplies its output through the new `on_plan` and `on_progress` callbacks, so the printed run is byte-identical to before. Two properties are deliberate and covered by tests: - A catalogue fetch that fails raises, rather than returning an inventory of Needs review. Access failure must not read as a data-quality problem. - A failure once the catalogues are in hand still returns `partial_cause` with every answer already obtained, so a run is never thrown away. `analyze` also accepts pre-built catalogues, so a long-running consumer can hold them rather than spend requests re-fetching what never changes. `inventory` no longer calls `sys.exit` when openpyxl is missing; it raises ImportError. A library must not terminate its host process on import. No behaviour change for `caia` users: same prompts, same output, same report, same exit codes. 246 existing tests pass untouched; 25 added for the library path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The verdict rules, the Cisco client and the run orchestration are currently reachable only through
analyzer.run()— which resolves credentials from the per-user config file, discovers an inventory in the working folder, prints to a terminal, writes an HTML file, and exits the process.That makes the assessment unusable by anything that isn't a terminal. A second consumer would have to reimplement the rules instead, and a reimplementation of Constitution IV is a second, divergent answer about the same firewall — the one outcome this tool exists to prevent.
This is the prerequisite for
caia-web, which will depend on this package at a pinned tag and import the assessment rather than fork it.What changed
New —
caia/assessment.py.analyze(inventory, client)is the whole check with no user interface attached. It takes a list of per-device dicts (whatever produced them) plus apsirt.Clientthe caller owns. It prints nothing, writes nothing, never exits the process, and never consults the working folder._load_catalogues,_run_checksand_assemble_devicesmoved here unchanged.Together with
matching,psirtandinventory, this is now the package's documented shared surface — see the updated table in the README's maintainers section.Changed —
caia/analyzer.py. Keeps the terminal run flow and supplies its output through the newon_planandon_progresscallbacks. The printed run is byte-identical to before.Changed —
caia/inventory.py. No longer callssys.exitwhen openpyxl is missing; raisesImportErrorinstead. A library must not terminate its host process on import.Two properties worth reviewing closely
Both are about not letting an access failure look like a clean or merely-unassessable fleet:
MODEL_UNMAPPED— a report that reads as a data-quality problem when the real cause was a rejected credential.analyzer.run()catches and dies exactly as it did before.partial_causewith every answer already obtained. A run is never thrown away, and devices never asked about are Needs review, never Not impacted.Also
analyze()accepts pre-built catalogues, so a long-running consumer can hold them rather than spend requests re-fetching what never changes. Not used by the CLI.Behaviour
No change for
caiausers: same prompts, same progress output, same report, same exit codes.Tests
test_api_flowalready covers the engine end-to-end throughrun(), so it is the regression gate for this refactor.tests/test_assessment.pyfor the library path: an in-memory inventory, callbacks, supplied catalogues, both failure modes, input not mutated, and nothing printed.Smoke-tested against a real 70-device inventory: loads 70 devices across 3 families, collapsing to 33 distinct questions.
Version
VERSION→4.1.0. Minor, not patch: this adds public API. Tag4.1.0after merge socaia-webhas something to pin.🤖 Generated with Claude Code