diff --git a/.env.example b/.env.example index 477ad75..25cdc88 100644 --- a/.env.example +++ b/.env.example @@ -1,18 +1,13 @@ -# The normal way to set your key is: caia --config -# (it stores these values per-user, so every run in any folder finds them). +# The normal way to set your credentials is: caia --config +# (it stores them per-user, so every run in any folder finds them). # # This file is only for automation or a local per-folder override: copy it to ".env" in the # folder you run the tool from, and these values are loaded into the environment for that run. # Environment variables take precedence over the stored per-user config. # -# Get your key from the Fuel iX Dev Portal: https://dev.fuelix.ai -# -> Default project -> "..." -> View -> API keys -> copy the key. +# Get your own client ID and secret from the Cisco PSIRT developer portal: +# https://developer.cisco.com/psirt/ -> register an application -> copy both values. +# One per person; the client ID is an identifier, the client secret is a secret. -FUELIX_API_KEY= - -# Optional. The model the analyzer sends advisories to. -# Change only if your org has a different model id enabled (see https://dev.fuelix.ai). -FUELIX_MODEL=claude-sonnet-5 - -# Optional. OpenAI-compatible base URL (only change if instructed). -FUELIX_BASE_URL=https://api.fuelix.ai/v1 +CISCO_CLIENT_ID= +CISCO_CLIENT_SECRET= diff --git a/.gitignore b/.gitignore index f4d1956..db55caa 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ venv/ # Inputs / outputs inventory.xlsx -analysis_output_*.xlsx impact_report_*.html ~$*.xlsx @@ -22,9 +21,6 @@ impact_report_*.html /inventory/ /output/ -# Temp CSAF downloads (created via tempfile) -csaf_*/ - # macOS .DS_Store diff --git a/.specify/feature.json b/.specify/feature.json index f7e88b1..ff19045 100644 --- a/.specify/feature.json +++ b/.specify/feature.json @@ -1,3 +1,3 @@ { - "feature_directory": "specs/006-api-inventory-check" + "feature_directory": "specs/007-decommission-ai-analyzer" } diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md index e3232f6..8b89c22 100644 --- a/.specify/memory/constitution.md +++ b/.specify/memory/constitution.md @@ -1,30 +1,60 @@ -# Cisco Advisory Impact Agent Constitution +# Cisco Advisory Impact Analyzer Constitution ## Core Principles ### I. Standard-Library-First & Minimal Dependencies -All network access (HTTP to Cisco and to FueliX) and core logic MUST use the Python -standard library. A third-party package MAY be added ONLY when the standard library -cannot reasonably provide the capability, and each such dependency MUST be justified in -the pull request that introduces it. The runtime dependency set is deliberately small -(currently `openpyxl` for Excel and `python-dotenv` for `.env` loading); growing it is a -reviewed decision, not a default. +All network access (HTTP to Cisco) and core logic MUST use the Python standard library. A +third-party package MAY be added ONLY when the standard library cannot reasonably provide the +capability, and each such dependency MUST be justified in the pull request that introduces it. +The runtime dependency set is deliberately small (currently `openpyxl` to read the user's +inventory spreadsheet and `python-dotenv` for `.env` loading); growing it is a reviewed +decision, not a default, and a dependency that outlives its purpose MUST be removed. Rationale: A small, standard-library-based footprint keeps the tool portable, trivially installable behind corporate proxies, and low in supply-chain attack surface — essential @@ -80,51 +110,53 @@ gives every platform the same install/run/update experience with no manual envir ### III. CLI-First, Scriptable Interface Every capability MUST be reachable through the command line. The tool MUST support both -an interactive mode and a fully flag-driven mode (e.g. `--url`, `--inventory`, -`--output-dir`, `--dry-run`) so it can be automated and tested without human input. -Human-readable output goes to the user via the `ui` module; errors MUST be actionable -(state what failed and how to fix it). Exit codes MUST be meaningful (non-zero on -failure; `130` on interrupt). +an interactive mode and a fully flag-driven mode (e.g. `--inventory`, `--sheet`, +`--output-dir`) so it can be automated without human input. Human-readable output goes to the +user via the `ui` module; errors MUST be actionable (state what failed and how to fix it). +Exit codes MUST be meaningful (non-zero on failure; `130` on interrupt). An option that is +withdrawn MUST be refused with a message naming it as removed and stating what to run instead, +rather than falling through to a generic argument error. Rationale: Scriptability enables automation and repeatable tests; clear text I/O keeps -the tool debuggable and honest about what it did. +the tool debuggable and honest about what it did. A withdrawn option is a promise the tool +once made, so breaking it deserves an explanation rather than a shrug. ### IV. Conservative & Traceable Analysis (NON-NEGOTIABLE) Impact determinations MUST NOT overstate risk. When the available data is insufficient -to decide — for example when impact depends on runtime configuration the inventory does -not track, or when the authoritative source does not recognize a device's software -release or hardware platform — the result MUST be labelled as undecided, never guessed. -The label MUST be unambiguous within the report it appears in; `Indeterminate` in the -advisory-driven analysis and `Needs review` in the inventory-driven check are both -conforming. A determination that a device is *not* affected MUST rest on positive -confirmation from official Cisco source data, never on the mere absence of a result; an -undecided device MUST NOT be presented as unaffected. Every determination MUST be -traceable to official Cisco source data (an ERP page, an advisory's CSAF JSON, or Cisco's -PSIRT advisory API); the tool MUST NOT invent advisory facts. Where a mode uses AI to -reach a determination, that output MUST be normalized and validated before it reaches the -report. +to decide — for example when Cisco does not recognize a device's software release, does not +list that release for the device's hardware platform, or cannot be reached — the result MUST be +labelled `Needs review`, never guessed. A determination that a device is *not* affected MUST +rest on positive confirmation from official Cisco source data, never on the mere absence of a +result; a device labelled `Needs review` MUST NOT be presented as unaffected, and every such +device MUST carry a human-readable reason. Every determination MUST be traceable to official +Cisco source data — the PSIRT advisory API and the platform and release catalogues it publishes; +the tool MUST NOT invent advisory facts, infer a verdict Cisco has not given, or derive one from +any source other than Cisco's published data. Rationale: People act on these reports to protect firewalls. A false "Not Affected" is dangerous and a fabricated "Affected" erodes trust; conservative, source-anchored -results are the only acceptable posture. Each mode may choose the clearest label for its -own report, but the substance is fixed: an undecidable device is never presented as safe, -and safety is asserted only when the source data affirms it. The positive-confirmation -rule exists because an authoritative source can return "nothing found" both for a device -that is genuinely clean and for one it cannot recognize at all — treating those alike -would silently convert a data-quality problem into a clean bill of health. +results are the only acceptable posture. The positive-confirmation rule exists because an +authoritative source can return "nothing found" both for a device that is genuinely clean and +for one it cannot recognize at all — treating those alike would silently convert a data-quality +problem into a clean bill of health. Requiring the verdict to come from Cisco rather than from +inference is what makes each finding reproducible and defensible to the person who has to act +on it. ### V. Secrets Hygiene & Data Locality API keys and other secrets MUST live only in the per-user configuration file (or in environment variables) and MUST NEVER be committed, logged, or printed. The per-user configuration file MUST be stored outside any working folder and, where the OS supports it, restricted to owner-only permissions. The tool MUST refuse to run when a required -secret is missing rather than proceeding insecurely. Inventory data MUST stay local; only -the minimum advisory and inventory context required for a determination may be sent to the -FueliX AI endpoint. `.gitignore` MUST continue to exclude secrets, inventory, and -generated reports. +secret is missing rather than proceeding insecurely, and MUST make no external request in that +case. Inventory data MUST stay local: the only inventory-derived facts that may leave the +machine are the product family, hardware platform, and software release being checked — never a +firewall name, a priority, or any other identifying detail. `.gitignore` MUST continue to +exclude secrets, inventory, and generated reports. Rationale: The inventory describes an organization's security posture and the API key is -a personal credential; leaking either is a direct harm. +a personal credential; leaking either is a direct harm. Bounding the disclosure to three derived +values means an observer of the tool's traffic learns what software is being asked about, but +nothing about who runs it or where. ## Technology & Data Constraints @@ -135,28 +167,20 @@ a personal credential; leaking either is a direct harm. source checkout (into a virtual environment) is a supported fallback where `uv` is unavailable; `--update` is uv-specific and does not apply on that path. The product version is single-sourced from the committed `VERSION` file into the package metadata at build time. -- Source of truth: Cisco Event Response (ERP) pages and official advisory CSAF JSON - fetched from `sec.cloudapps.cisco.com`, and Cisco's PSIRT openVuln advisory API — the - same published data that backs Cisco's public Software Checker — for release- and - platform-scoped advisory lookups and for the platform/release catalogues those lookups - are validated against. Catalogues MUST be retrieved from Cisco rather than hardcoded, so - newly published releases and platforms are picked up without a tool release. No scraped - or cached-as-authoritative alternatives. -- AI provider: FueliX (OpenAI-compatible Chat Completions endpoint) accessed over the - standard library, using the current default model configured in `fuelix.py`. +- Source of truth: Cisco's PSIRT openVuln advisory API — the same published data that backs + Cisco's public Software Checker — for release- and platform-scoped advisory lookups and for the + platform/release catalogues those lookups are validated against. Catalogues MUST be retrieved + from Cisco rather than hardcoded, so newly published releases and platforms are picked up + without a tool release. No scraped or cached-as-authoritative alternatives. - Inputs/outputs: the inventory is a user-provided `.xlsx` (sheet `FW_List`) located in the - current working folder; reports are written into an `output/` folder inside that same - working folder as timestamped files — `analysis_output_*.xlsx` for the advisory-driven - analysis and `impact_report_*.html` for the inventory-driven check. An HTML report MUST be - a single self-contained file that renders with no network access, so it survives being - emailed or archived. Reports MUST never be overwritten. Header matching MUST stay tolerant - of minor naming variation. -- Networking: the analyzer itself contacts only `sec.cloudapps.cisco.com` (Cisco - ERP/CSAF), `api.fuelix.ai` (AI), `apix.cisco.com` (Cisco PSIRT advisory data and + current working folder; the report is written into an `output/` folder inside that same + working folder as a timestamped `impact_report_*.html` file. The report MUST be a single + self-contained file that renders with no network access, so it survives being emailed or + archived. Reports MUST never be overwritten. Header matching MUST stay tolerant of minor + naming variation. Advisory content received from Cisco MUST be treated as untrusted text that + cannot alter the report's structure, styling, or behaviour. +- Networking: the analyzer itself contacts only `apix.cisco.com` (Cisco PSIRT advisory data and platform/release catalogues) and `id.cisco.com` (short-lived access token for that API). - To the Cisco advisory API the tool MUST send only the derived product family, hardware - platform and software release being checked — never a firewall name or any other inventory - identifier — keeping that disclosure strictly smaller than what the AI endpoint receives. Version and update checks additionally contact GitHub — `api.github.com` and `github.com` — solely to discover the latest published release; they send no inventory or secrets and MUST be best-effort and time-bounded so @@ -181,12 +205,13 @@ constitutional compliance is enforced. ## Development Workflow & Quality Gates -- Tests: extraction and parsing logic (CSAF product sections, affected releases, - inventory matching) MUST have tests, and the existing test suite MUST pass before a - change is merged. Changes to CSAF/ERP parsing or inventory matching MUST add or update - tests covering the new behavior. -- Dry-run: user-facing changes that affect analysis flow SHOULD be exercisable via - `--dry-run` (no AI call, no network write) to keep verification cheap. +- Tests: the logic behind every verdict — inventory loading and column matching, release + normalization, platform and release catalogue handling, verdict assignment, and report + generation — MUST have tests, and the existing test suite MUST pass before a change is merged. + Changes to any of that logic MUST add or update tests covering the new behavior. Because the + tool offers no offline preview and every run contacts Cisco, the test suite is the primary + means of verifying an analysis-flow change without credentials: such changes MUST be covered + by tests that run with no credentials and no network access. - Review: pull requests MUST confirm compliance with the Core Principles, especially Principle IV (conservative, traceable analysis) and Principle V (secrets/data handling). Any new runtime dependency MUST be explicitly justified (Principle I). @@ -195,7 +220,7 @@ constitutional compliance is enforced. those flows change. Their instructions MUST remain consistent with each other and with the code — including the working-folder inventory and `output/` conventions and where files are read and written. A change to the instructions in one MUST be mirrored in the - other within the same pull request. + other within the same pull request. Neither may describe a capability the tool does not have. - Versioning & releases: the committed `VERSION` file is the single source of truth for the product version and MUST follow semantic versioning. A release is cut by pushing a git tag equal to the current `VERSION` and publishing a matching GitHub Release; the Release workflow @@ -208,7 +233,7 @@ constitutional compliance is enforced. ## Governance -This constitution supersedes ad-hoc practice for the Cisco Advisory Impact Agent. All +This constitution supersedes ad-hoc practice for the Cisco Advisory Impact Analyzer. All changes MUST comply with the Core Principles; when a change cannot, the reviewer MUST require either a compliant alternative or an explicit, documented justification recorded in the pull request. @@ -223,4 +248,4 @@ Compliance is verified at review time. Dependent Spec Kit artifacts (plan, spec, tasks templates and their generated documents) MUST remain consistent with the principles above; the Constitution Check in the planning workflow enforces this on each feature. -**Version**: 2.2.1 | **Ratified**: 2026-07-14 | **Last Amended**: 2026-07-25 +**Version**: 3.0.0 | **Ratified**: 2026-07-14 | **Last Amended**: 2026-07-26 diff --git a/README.md b/README.md index 24c5082..3f2a20c 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,18 @@ TELUS Digital

-

Cisco Advisory Impact Agent

+

Cisco Advisory Impact Analyzer

-

Agentic firewall impact analysis for Cisco security advisories

+

Fleet-wide firewall impact analysis, straight from Cisco

--- -Paste a Cisco **Event Response (ERP)** link and get back a spreadsheet telling you -**which of your firewalls are affected**. +Run one command in the folder holding your firewall inventory and get back an HTML report +telling you **which of your firewalls Cisco lists as vulnerable, and to what**. -Behind the scenes it finds every security advisory referenced by the ERP, downloads each -advisory's official data (CSAF), and uses AI (via **FueliX**) to compare the affected -products and software releases against **your firewall inventory**. The result is a -timestamped Excel file listing, per advisory, the impacted firewalls. +It asks Cisco's **PSIRT advisory API** — the same published data behind Cisco's public +Software Checker — which advisories apply to each firewall's software release on its exact +hardware model, and reports the answer. Every verdict comes from Cisco; nothing is inferred. Installed as a **[uv](https://docs.astral.sh/uv/) tool**: one install command, then a single `caia` command you can run from any folder. Works on **macOS, @@ -28,14 +27,12 @@ Windows, and Linux**. | - | ----------- | ------------- | | 1 | **uv** (recommended) — or just **Python 3.9+** | It manages Python for you. Not sure if you have it? See [Get uv](#get-uv) below — check first, install only if needed. Can't install uv? See [Install without uv](#install-without-uv-python-only) — you only need Python. | | 2 | **Git** | The uv install command below pulls the tool straight from GitHub, so Git must be installed first. Not sure if you have it? See [Get Git](#get-git) below. | -| 3 | **A FueliX API key** — for advisory mode | Get yours from — each person needs their own (steps below). | -| 4 | **Cisco PSIRT API credentials** — for inventory mode (`--api`) | A client ID and client secret from — each person needs their own. | -| 5 | **Your firewall inventory** as an Excel `.xlsx` file in the folder you run from | You build this yourself (format below). | -| 6 | **Internet access** to `sec.cloudapps.cisco.com` and `api.fuelix.ai`, plus `apix.cisco.com` and `id.cisco.com` for `--api` | Usually already available; corporate proxies can block these. | +| 3 | **Cisco PSIRT API credentials** | A client ID and client secret from — each person needs their own (steps below). | +| 4 | **Your firewall inventory** as an Excel `.xlsx` file in the folder you run from | You build this yourself (format below). | +| 5 | **Internet access** to `apix.cisco.com` and `id.cisco.com` | Usually already available; corporate proxies can block these. | -> Every credential is stored once, per user, via `caia --config`. You only need the ones -> for the mode you use: **advisory mode** needs the FueliX key, **inventory mode** needs the -> Cisco credentials. Each mode refuses to run without its own, and points you at `--config`. +> Your credentials are stored once, per user, via `caia --config`. The tool refuses to run +> without them and points you at `--config`. ### Get uv @@ -140,15 +137,14 @@ repository to clone and no virtual environment to create or activate. > no need to re-run `--config`. Note that `caia --update` cannot make this jump for you: the > distribution name changed, so an old install has to be replaced with the command above. -Then set your FueliX API key once (stored per-user, used from any folder): +Then set your Cisco credentials once (stored per-user, used from any folder): ```bash caia --config ``` -`--config` asks for your API key (typing is hidden) and lets you pick the AI model from a short -list (default `claude-sonnet-5`). The values are saved to a per-user config file — see -[Configuration](#configuration-your-api-key) below. +`--config` asks for your Cisco client ID and client secret, checks them against Cisco, and +saves them to a per-user config file — see [Configuration](#configuration) below. --- @@ -181,7 +177,7 @@ py -m pip install . This installs the `caia` command **inside that environment**. From then on it behaves exactly like the uv install — use it as described in [Run it](#run-it) and -[Configuration](#configuration-your-api-key) (`caia --config`, then +[Configuration](#configuration) (`caia --config`, then `caia` from your inventory folder). **Notes for this path:** @@ -193,41 +189,29 @@ on it behaves exactly like the uv install — use it as described in [Run it](#r - **Updating is manual here.** `--update` is uv-specific and will report that uv wasn't found. To update, download the newer ZIP and re-run `python -m pip install .` in your environment. Pass `--no-update-check` to skip the start-of-run version check. -- Everything else — `--config`, inventory discovery, the `output/` folder, `--dry-run`, and the - analysis itself — works identically to the uv install. +- Everything else — `--config`, inventory discovery, the `output/` folder, and the check + itself — works identically to the uv install. --- ## Run it -There are **two modes**, and they answer opposite questions. Pick the one that matches what -you're asking: - -| | Advisory mode (default) | Inventory mode (`--api`) | -| --- | --- | --- | -| **Question** | "Given this advisory, which of my firewalls are affected?" | "Given my inventory, which firewalls are vulnerable right now, and to what?" | -| **You supply** | An ERP or advisory link | Nothing but the inventory | -| **Answer comes from** | AI reading the advisory's text | Cisco's own published data — no AI | -| **Output** | `analysis_output_.xlsx` | `impact_report_.html` | -| **Needs** | FueliX API key | Cisco PSIRT client ID + secret | - -The output formats differ because the reports are read differently. The spreadsheet is one -row per advisory, which suits a per-advisory review. The HTML report is one row per firewall -with clickable advisory links, collapsible detail and filtering — which is what a -fleet-wide worklist needs, and what a spreadsheet handles badly once a single device has -dozens of advisories against it. - -### Inventory mode — check everything at once - -`cd` into the folder holding your inventory, then: +`cd` into the folder holding your inventory `.xlsx`, then: ```bash -caia --api +caia ``` -No link needed. The tool asks Cisco which published advisories apply to each firewall's -software release on its exact hardware model, then writes -**`impact_report__