2026.04.27.1: same-day post-release PII scrub
The original 2026.04.27 was published-then-deleted from PyPI within
hours after a stricter audit (against the unpacked sdist, not just
curated source paths) found cluster-fingerprint content that the
pre-publish grep had missed. This release supersedes the deleted one;
no functional differences.
Issues found in 2026.04.27 that this fixes:
1. docs/query-patterns/sip-trunk-report.md — "Live result snapshot"
section (38 lines) contained the live cluster's actual SIP trunk
inventory: real hostnames (exp-c-p.binghammemorial.org), real
internal IPs (172.20.6.99, .104, .105, .114, .120, .222, plus
172.20.2.22, 172.20.14.105, 172.24.10.10), real trunk-name +
description rows. Section removed entirely. The query-pattern doc
itself still ships — schema/SQL guidance is generic and useful.
One inline FQDN example (`exp-c-p.binghammemorial.org`) replaced
with `exp-c-p.example.com`. Status line that named the specific
maintenance release (`Validated against CUCM 15.0.1.12900-234 on
2026-04-25.`) genericized to `Validated against CUCM 15.`
2. .mcp.json shipping in sdist with `/home/rpm/bingham/axl` as the
`--directory` argument. Local filesystem path = hostname leak.
Added to `[tool.hatch.build.targets.sdist] exclude`. File stays
in the source repo for development; no longer ships.
3. pyproject.toml comment about the audit workflow ironically
contained the literal word "bingham" as the example grep token.
Rewritten to use "site-specific tokens" generically.
Audit verification (against the unpacked sdist this time):
tar -xzf dist/mcaxl-2026.4.27.1.tar.gz -C /tmp/sdist-inspect
grep -rnEi 'bingham|binghammemorial|10\.[0-9]+\.[0-9]+\.[0-9]+|
172\.(1[6-9]|2[0-9]|3[01])\.[0-9]+\.[0-9]+|
192\.168\.[0-9]+\.[0-9]+|SupportedSystems|CCX-AXL|
CER-AXL|CUC-AXL|TabSync|variphy|15\.0\.1\.12900|
production cluster|/home/rpm|cucm-pub\.bingham'
/tmp/sdist-inspect/
→ returns empty (verified)
Tests still 155/155.
Lesson encoded for next time: the pre-publish audit MUST run against
the unpacked sdist, not just the four explicitly-named paths in the
python.md rule (src/, tests/, README.md, pyproject.toml, .env.example).
The sdist also pulls in docs/, top-level dotfiles, and uv.lock.
CHANGELOG.md spells this out in the post-release note for next time.
This commit is contained in:
parent
87d697f461
commit
0691ba8c46
32
CHANGELOG.md
32
CHANGELOG.md
@ -5,7 +5,37 @@ encode the date the package was tested against the upstream Cisco APIs
|
||||
and published. Format: `YYYY.MM.DD` with optional `.N` post-release
|
||||
suffix for same-day fixes.
|
||||
|
||||
## 2026.04.27 — initial public release
|
||||
## 2026.04.27.1 — same-day PII scrub
|
||||
|
||||
Post-release fix per the python.md immutability rule. The original
|
||||
`2026.04.27` was published-then-deleted from PyPI after a stricter
|
||||
audit found cluster-fingerprint content in the shipped sdist that the
|
||||
pre-publish audit had missed:
|
||||
|
||||
- `docs/query-patterns/sip-trunk-report.md` contained a "Live result
|
||||
snapshot" section with the test cluster's actual SIP trunk inventory
|
||||
(real hostnames, real internal IPs). The query-pattern doc itself
|
||||
still ships; the snapshot section has been removed and one inline
|
||||
FQDN example replaced with `.example.com`.
|
||||
- `.mcp.json` was shipping in the sdist with a local filesystem path.
|
||||
Added to `[tool.hatch.build.targets.sdist] exclude`. The file
|
||||
remains in the source repo for development; it no longer ships.
|
||||
|
||||
Lesson encoded for next time: **the pre-publish PII audit must run
|
||||
against the unpacked sdist, not just curated source paths.** The
|
||||
sdist also pulls in `docs/`, top-level dotfiles like `.mcp.json`, and
|
||||
`uv.lock`. The python.md rule's example grep covers fewer paths than
|
||||
the actual sdist blast surface; the durable fix is `tar -xzf
|
||||
dist/*.tar.gz -C /tmp/inspect && grep -rnE 'site-token' /tmp/inspect`
|
||||
before every publish.
|
||||
|
||||
No functional changes between 2026.04.27 and 2026.04.27.1 — just
|
||||
metadata and shipped-doc content.
|
||||
|
||||
## 2026.04.27 — initial public release (deleted)
|
||||
|
||||
> Yanked-and-deleted from PyPI on the publish date due to a sdist
|
||||
> PII leak. Superseded by `2026.04.27.1`. Retained here as a marker.
|
||||
|
||||
First public release on PyPI as `mcaxl`. Renamed from the internal
|
||||
working name `mcp-cucm-axl` to fit the operator's `mc<interface>`
|
||||
|
||||
@ -6,7 +6,7 @@ route-group/route-list membership. Useful for handoff documentation,
|
||||
post-migration cleanup, and identifying single-points-of-failure on
|
||||
specific trunks.
|
||||
|
||||
**Status:** Validated against CUCM 15.0.1.12900-234 on 2026-04-25.
|
||||
**Status:** Validated against CUCM 15.
|
||||
Empty `prompts/` directory at `src/mcaxl/prompts/` is the
|
||||
intended home for extracting this into a `@mcp.prompt` function. For
|
||||
now, prompts live inline in `server.py` (see `route_plan_overview`,
|
||||
@ -111,7 +111,7 @@ ORDER BY d.name, std.sortorder;
|
||||
**Notes:**
|
||||
|
||||
- `address` is `VARCHAR(255)` — IP literal *or* DNS name. Expressway-C
|
||||
trunks often use FQDNs (e.g., `exp-c-p.binghammemorial.org`) so SRV
|
||||
trunks often use FQDNs (e.g., `exp-c-p.example.com`) so SRV
|
||||
resolution can shift the actual destination.
|
||||
- `addressipv6` exists on the same table but is empty on most clusters.
|
||||
- `port` is `INTEGER` — defaults to 5060 (SIP over UDP/TCP) or 5061 (TLS),
|
||||
@ -203,43 +203,6 @@ LLM to surface:
|
||||
|
||||
---
|
||||
|
||||
## Live result snapshot (Bingham, 2026-04-25)
|
||||
|
||||
11 SIP trunks. All on `Main-Campus-Sub1-Pub-DP` except `exp-c-p-SIP-Trk`
|
||||
(on `Pub-Sub1-DP`). All preferred codec is `711ulaw`. All destinations
|
||||
on port 5060 (no TLS).
|
||||
|
||||
| Trunk | Destination | SIP Profile | CSS | Location |
|
||||
|---|---|---|---|---|
|
||||
| `Forward-Advantage-SIP-Trk` | 172.24.10.10 | FWD Advantage SIP Profile | National-CSS | Main-Campus-LOC |
|
||||
| `PSTN-Router-SIP-Trk` | 172.20.6.222 | PSTN Sparklite SIP Profile | PSTN-Inbound-CSS | Hub_None |
|
||||
| `RightFax-SIP-TRK` | 172.20.2.22 | RightFax SIP Profile | FAX-CSS | Hub_None |
|
||||
| `Unity-Pub-SIP-TRK` | 172.20.6.104 | Unity SIP Profile | Internal-CSS | Main-Campus-LOC |
|
||||
| `Unity-Sub-SIP-TRK` | 172.20.6.105 | Unity SIP Profile | Internal-CSS | Main-Campus-LOC |
|
||||
| `VG450-SIP-TRK` | 172.20.6.99 | RightFax SIP Profile | National-CSS | Hub_None |
|
||||
| `Verba-SIP-TRK` | 172.20.6.120 | Verba Profile | Internal-CSS | Hub_None |
|
||||
| `ZetaFax-SIP-TRK` | 172.20.14.105 | ZetaFax SIP Profile | FAX-CSS | Hub_None |
|
||||
| `exp-c-p-SIP-Trk` | exp-c-p.binghammemorial.org | Expressway SIP Profile | (none) | Main-Campus-LOC |
|
||||
| `exp-c-s-SIP-Trk` | exp-c-s.binghammemorial.org | Expressway SIP Profile | (none) | Main-Campus-LOC |
|
||||
| `singlewireFusion-SIP-TRK` | 172.20.6.114 | singlewire SIP Profile | (none) | Hub_None |
|
||||
|
||||
**Observations from this snapshot** (templates for what the prompt should
|
||||
flag):
|
||||
|
||||
- `VG450-SIP-TRK` (analog voice gateway) shares the `RightFax SIP Profile`
|
||||
with `RightFax-SIP-TRK` — *probably intentional* (both terminate at fax
|
||||
endpoints) but worth confirming with the operator.
|
||||
- The 3 trunks with `calling_search_space = NULL` (Expressway-C primary,
|
||||
Expressway-C secondary, singlewireFusion) all serve specific
|
||||
device-only paths — they don't originate generic outbound routing. Not
|
||||
a finding, but a useful invariant to call out.
|
||||
- `PSTN-Router-SIP-Trk` is the only trunk with `Hub_None` location *and*
|
||||
`PSTN-Inbound-CSS` *and* a stripped-down CSS — consistent with its role
|
||||
as the carrier-facing trunk (and as the H1 SPOF in the
|
||||
[route-plan audit](../../../docs/src/content/docs/audits/2026-04-25-cucm-route-plan.mdx)).
|
||||
|
||||
---
|
||||
|
||||
## Proposed prompt name and signature
|
||||
|
||||
```python
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "mcaxl"
|
||||
version = "2026.04.27"
|
||||
version = "2026.04.27.1"
|
||||
description = "Read-only MCP server for Cisco Unified Communications Manager (CUCM) — AXL SOAP API + RisPort70 registration state — purpose-built for LLM-driven dial-plan and configuration auditing."
|
||||
authors = [{name = "Ryan Malloy", email = "ryan@supported.systems"}]
|
||||
readme = "README.md"
|
||||
@ -58,13 +58,21 @@ packages = ["src/mcaxl"]
|
||||
[tool.hatch.build.targets.sdist]
|
||||
# Keep the published source distribution focused on what's needed to
|
||||
# build / install / run. Excluded files exist for local development only.
|
||||
#
|
||||
# IMPORTANT: this list is the last line of defense for PII leakage.
|
||||
# `tests/` contains real cluster fixtures; `.mcp.json` contains a
|
||||
# local filesystem path; `audits/` contains cluster-specific findings.
|
||||
# Pre-publish workflow: extract the sdist to /tmp and grep for any
|
||||
# site-specific tokens (your org name, internal IP ranges, hostnames)
|
||||
# across the full unpacked tree — MUST return empty before publish.
|
||||
exclude = [
|
||||
"CLAUDE.md", # operator-private project context for Claude Code
|
||||
".env", # never ship credentials
|
||||
"CLAUDE.md", # operator-private project context for Claude Code
|
||||
".env", # never ship credentials
|
||||
".env.local",
|
||||
".mcp.json", # contains local filesystem path; dev-only artifact
|
||||
"axlsqltoolkit.zip", # Cisco-licensed; do not redistribute
|
||||
"audits/", # cluster-specific audit reports
|
||||
"tests/", # tests live in source repo, not the sdist
|
||||
"audits/", # cluster-specific audit reports
|
||||
"tests/", # tests live in source repo, not the sdist
|
||||
".pytest_cache/",
|
||||
".ruff_cache/",
|
||||
"dist/",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user