Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 51 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@

<h1 align="center">Cisco Advisory Impact Analyzer</h1>

<p align="center"><strong>Fleet-wide firewall impact analysis, straight from Cisco</strong></p>
<p align="center"><strong>Check a Cisco advisory bundle against your firewall inventory</strong></p>

---

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**.
Cisco publishes firewall vulnerabilities in **bundles** — an Event Response page listing every
advisory released that day. Give this tool the link to one and it tells you **which of your
firewalls and software releases that publication impacts**, and the release that fixes each.

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.
Software Checker — which of the bundle's advisories apply to each firewall's software release
on its exact hardware model. Every verdict comes from Cisco; nothing is inferred, and a
firewall it could not check is never reported as safe.

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,
Expand All @@ -29,7 +31,7 @@ Windows, and Linux**.
| 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 | **Cisco PSIRT API credentials** | A client ID and client secret from <https://developer.cisco.com/psirt/> — 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. |
| 5 | **Internet access** to `apix.cisco.com`, `id.cisco.com` and `sec.cloudapps.cisco.com` | The first two are Cisco's advisory API and its token endpoint; the third serves the bundle page. Usually already available; corporate proxies can block these. |

> Your credentials are stored once, per user, via `caia --config`. The tool refuses to run
> without them and points you at `--config`.
Expand Down Expand Up @@ -202,47 +204,49 @@ on it behaves exactly like the uv install — use it as described in [Run it](#r
caia
```

The tool finds your inventory in that folder (if there's more than one candidate, it lists them
and lets you pick), asks whether you want to scope the report to one Cisco advisory bundle
(press **Enter** to skip), asks Cisco which published advisories apply to each firewall's
software release on its exact hardware model, and writes
**`impact_report_<date>_<time>.html`** into an **`output`** folder inside your current folder
(created automatically). Open it in any browser.
It finds your inventory in that folder (if there's more than one candidate, it lists them and
lets you pick), then asks for the **advisory bundle** to check it against:

Each run adds a new timestamped file, so previous reports are kept. Press **Ctrl+C** at any
time to cancel cleanly.
```
Cisco advisory bundle URL (press Enter for a whole-fleet report) ›
```

### Checking one advisory bundle
Paste the Event Response link Cisco published — for example
`https://sec.cloudapps.cisco.com/security/center/viewErp.x?alertId=ERP-75736`. A bare
identifier works too: just `ERP-75736`.

Cisco publishes firewall vulnerabilities in **bundled publications** — one Event Response page
listing every advisory released that day. When your team's review is triggered by one of those,
paste its link at the prompt, or skip the prompt entirely:
Supply it up front to skip the prompt entirely, which is what makes a scheduled review
possible:

```bash
caia --erp https://sec.cloudapps.cisco.com/security/center/viewErp.x?alertId=ERP-75736
caia --erp ERP-75736
```

A bare identifier works too: `caia --erp ERP-75736`.

The tool tells you which bundle it found and how many advisories it lists **before** it starts
asking Cisco about your inventory, so a wrong link costs you nothing. The report then flips
round: **one row per advisory in that bundle** rather than one row per firewall, each row
showing the advisory, its publication date, and which of your products it impacts along with
the release that fixes them. Advisories in the bundle that hit nothing still get a row — a
clean result you can point at is worth more than a gap.
asking Cisco about your inventory, so a wrong link costs you nothing. It then writes
**`impact_report_<bundle>_<date>_<time>.html`** into an **`output`** folder inside your current
folder (created automatically). Open it in any browser.

The report is **one row per advisory in the bundle** — each showing the advisory, its
publication date, and which of your devices and releases it impacts along with the release that
fixes them. Advisories in the bundle that hit nothing still get a row; a clean result you can
point at is worth more than a gap.

Two things worth knowing:

- **It is scoped on purpose.** Advisories affecting your fleet from *other* publications are
deliberately absent, and the report says how many it left out. It is not a whole-fleet
assessment; run `caia` with no bundle for that.
- **It is scoped on purpose.** Advisories affecting your inventory from *other* publications are
deliberately absent, and the report says how many it left out. It is not a whole-inventory
assessment.
- **Firewalls that couldn't be checked appear in every row they might belong to**, marked in
yellow and labelled *undetermined*. They are never counted as unaffected. If a row says
"0 impacted" it also tells you how many devices nobody could answer for.

Because `--erp` needs no prompt, a bundle review can be scheduled or scripted. Exit status is
`2` if the value isn't a bundle address, `1` if Cisco can't be reached or the page yields no
advisories — and no report is written in either case.
Each run adds a new timestamped file, so previous reports are kept. Press **Ctrl+C** at any
time to cancel cleanly.

> Pressing **Enter** at the prompt instead produces the older whole-inventory report — one row
> per firewall, listing every advisory Cisco holds against it, from any publication. It remains
> available for a broad sweep, but the bundle check above is what the tool is for.

### Understanding the output

Expand Down Expand Up @@ -391,7 +395,9 @@ Each person uses **their own** credentials — don't share them.
- **`Cisco rejected the configured credentials`** — re-check them with `caia --config`; it
verifies them against Cisco and shows Cisco's own reason for a rejection.
- **`Could not reach Cisco`** — check your connection or proxy. The tool needs
`apix.cisco.com` and `id.cisco.com`.
`apix.cisco.com` and `id.cisco.com` for advisory data, and `sec.cloudapps.cisco.com` to read
the bundle page. A bundle failure says whether it was connectivity or a bad link, and writes
no report either way.
- **`--api has been removed`** (or `--url`, `--dry-run`, `--keep-temp`, `--no-keep-temp`) —
these options were withdrawn in 4.0.0. Just run `caia`.

Expand All @@ -404,15 +410,24 @@ non-interactive run has no prompts at all (no update offer, no confirmation):

| Flag | Purpose |
| ---- | ------- |
| `--erp <URL\|ERP-#####>` | the advisory bundle to check against — supplying it skips the prompt entirely, which is what makes a scheduled review possible |
| `--inventory <PATH>` | use a specific inventory file, bypassing folder discovery |
| `--sheet <NAME>` | inventory sheet name (default `FW_List`) |
| `--output-dir <DIR>` | where to write the report (default: `./output`) |
| `--no-update-check` | skip the start-of-run version check |
| `--yes` | skip the uninstall confirmation |

Exit codes are script-friendly: `0` success, `1` a declined confirmation, `2` an argument
error (including a removed option), `3` a failed version lookup, `4` a failed update or
uninstall, `130` interrupted.
So a nightly or post-publication review is just:

```bash
caia --erp ERP-75736 --inventory /path/to/inventory.xlsx --no-update-check
```

Exit codes are script-friendly: `0` success, `1` a declined confirmation **or a bundle that
could not be resolved** (Cisco unreachable, or a page yielding no advisories), `2` an argument
error (including a removed option, **or a value that is not a Cisco Event Response address**),
`3` a failed version lookup, `4` a failed update or uninstall, `130` interrupted. No report is
written on any non-zero bundle outcome.

On startup the tool prints a splash banner. It is shown only on an interactive terminal, so
piped or redirected output (e.g. `caia --version > file`) stays clean; set `CAIA_NO_BANNER=1`
Expand Down
2 changes: 1 addition & 1 deletion caia/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Cisco Advisory Impact Analyzer — fleet-wide firewall impact analysis, straight from Cisco.
"""Cisco Advisory Impact Analyzer — check a Cisco advisory bundle against your inventory.

Distributed as a uv tool; the on-PATH command is `caia`
(entry point: :func:`caia.cli.main`).
Expand Down
5 changes: 3 additions & 2 deletions caia/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,9 @@ def error(self, message):
def build_parser():
ap = _Parser(
prog="caia",
description="Checks every firewall in your inventory against Cisco's published "
"advisory data, and writes an HTML impact report.",
description="Checks a Cisco advisory bundle (ERP) against your firewall "
"inventory and writes an HTML impact report naming the devices "
"and software releases it impacts.",
)
# Mode flags (handled in precedence order; not combined).
ap.add_argument("--version", action="store_true",
Expand Down
2 changes: 1 addition & 1 deletion caia/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def plain(msg=""):
_GRADIENT = [46, 44, 39, 129]
_WORDMARK = "CAIA"
_NAME = "Cisco Advisory Impact Analyzer"
_SLOGAN = "Fleet-wide firewall impact analysis, straight from Cisco · TELUS Digital"
_SLOGAN = "Check a Cisco advisory bundle against your firewall inventory · TELUS Digital"


def _c256(code, text):
Expand Down
20 changes: 11 additions & 9 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Cisco Advisory Impact Analyzer</title>
<meta name="description" content="Know which of your Cisco firewalls Cisco lists as vulnerable. One command against your inventory, one HTML impact report." />
<meta name="description" content="Give it a Cisco advisory bundle and it tells you which of your firewalls and software releases Cisco lists as impacted, with the release that fixes each." />
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%2322d3ee' d='M12 1 3 5v6c0 5 3.8 9.7 9 11 5.2-1.3 9-6 9-11V5l-9-4Z'/%3E%3Cpath fill='%23071018' d='m11 15-2.5-2.5 1.4-1.4L11 12.2l3.1-3.1 1.4 1.4L11 15Z'/%3E%3C/svg%3E" />
<style>
:root {
Expand Down Expand Up @@ -241,12 +241,14 @@
<section class="hero">
<span class="eyebrow"><span class="dot"></span> TELUS Digital · Security Tooling</span>
<h1>Cisco Advisory Impact Analyzer</h1>
<p class="tagline">Fleet-wide firewall impact analysis, straight from Cisco.</p>
<p class="tagline">Check a Cisco advisory bundle against your firewall inventory.</p>
<p class="lede">
Run one command in the folder holding your inventory. It checks your <b>whole fleet</b>
against Cisco's published advisory data — device by device, on each firewall's exact
hardware model and software release — and writes a self-contained HTML report that names
the release fixing each finding. Every verdict comes from Cisco; nothing is inferred.
Cisco publishes firewall vulnerabilities in <b>bundles</b> — an Event Response page listing
every advisory released that day. Paste the link to one and this tool checks every advisory
in it against your inventory, device by device, on each firewall's exact hardware model and
software release. You get a self-contained HTML report naming which of your devices and
releases that publication impacts, and the release that fixes each. Every verdict comes
from Cisco; nothing is inferred, and a firewall it could not check is never reported as safe.
</p>
<div class="cta">
<a class="btn btn-primary" href="#prereqs">
Expand All @@ -262,8 +264,8 @@ <h1>Cisco Advisory Impact Analyzer</h1>
<div class="grid3">
<div class="card">
<svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
<h3>Checks your whole fleet</h3>
<p>One command. Every firewall in your inventory is checked, not just the ones someone thought to look at &mdash; or scope it to one Cisco advisory bundle and get a row per advisory.</p>
<h3>One bundle, every firewall</h3>
<p>Paste the Event Response link and every firewall in your inventory is checked against every advisory in that publication &mdash; not just the devices someone thought to look at.</p>
</div>
<div class="card">
<svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M12 3 4 6v6c0 4.4 3.4 8.5 8 9 4.6-.5 8-4.6 8-9V6l-8-3Z"/><path d="m9 12 2 2 4-4"/></svg>
Expand All @@ -286,7 +288,7 @@ <h2><span class="num">01</span>Before you start</h2>
<li><b>Git</b> — <span>uv uses it to fetch the tool from GitHub. Not sure if you have it? <a href="#get-uv">Check &amp; install it below</a>.</span></li>
<li><b>Cisco PSIRT API credentials</b> — <span>a client ID and secret from <a href="https://developer.cisco.com/psirt/">developer.cisco.com/psirt</a>, one per person (see “Get your credentials” below).</span></li>
<li><b>Your firewall inventory</b> — <span>an Excel <code>.xlsx</code> (sheet <code>FW_List</code>) in the folder you run from.</span></li>
<li><b>Internet access</b> — <span>to <code>apix.cisco.com</code> and <code>id.cisco.com</code>.</span></li>
<li><b>Internet access</b> — <span>to <code>apix.cisco.com</code>, <code>id.cisco.com</code> and <code>sec.cloudapps.cisco.com</code>.</span></li>
</ul>

<p class="osnote" id="get-uv"><b>Get uv &amp; Git</b> — both are needed before you install the tool. First check whether each is already installed, and install only what's missing. Pick your operating system:</p>
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "caia-cli"
description = "Fleet-wide firewall impact analysis, straight from Cisco"
description = "Check a Cisco advisory bundle against your firewall inventory"
readme = "README.md"
requires-python = ">=3.9"
license = "MIT"
Expand Down
Loading