This page is a plain-language map of the enterprise-hardening work built on top of the ipIII
MVP core. It groups 14 modules into three waves (P0 — blocks enterprise readiness,
P1 — required for a bank/regulated partner, P2 — advanced/optional). Every module below is
LIVE-in-code: the logic exists, is unit-tested, and can be inspected in routes/ip3-*.js.
Every module is also gated by its own environment flag, defaulting to off — nothing here is wired
into a production authentication or authorization path. Read this page together with
/known-limitations for the full honesty register.
off for every single module listed below. A live read-only status endpoint,
/api/ip3/v1/waves/status, reports the loaded/enabled state of all
14 modules at once — it changes nothing, it only reports.
The ipIII MVP core (import → incident → evidence-package → retest → close, on a live PostgreSQL with JWT/RBAC/audit) already works. These 14 modules extend that core toward the requirements a bank, a regulated partner, or an internal audit team expects from an enterprise-grade platform: stricter account lifecycle, CI-gated releases, tenant isolation enforcement, formal evidence timestamps, deterministic hashing, richer CVE context, safer SIEM ingestion, ticket state sync, threat-intel import, code-scanning ingest, board reporting, multi-step approval, an AI red-team register, and Prometheus-style observability. None of this replaces the MVP core — it hardens it, one flag at a time.
Rule: never mix LIVE with DEMO. None
of the 14 modules is LIVE_PROD
today — all have code + tests, but run behind a flag defaulting to off on demo/in-memory data,
so the correct status is LIVE_CONTROLLED
or LIVE_DEMO, never plain "LIVE".
Note on counts: the P0 wave contains two code modules (access-model, rls status groundwork ships in P1) plus the CI-gate shell script, so the live status endpoint reports it as a 2-item wave; grouping above follows the wave-task IDs (IP3-P0-04, IP3-P0-05) used in the codebase. See the table below for the authoritative per-module list.
Without these two, no enterprise conversation can start: uncontrolled account creation and unverified releases are the two gaps auditors flag first.
| Module | Task | What it does | Flag (default) | Source |
|---|---|---|---|---|
| access-model LIVE_CONTROLLED |
IP3-P0-04 | Invite-only account lifecycle: accounts are created exclusively via invite() → accept(token)
— no self-registration, no login without an account. Five-level RBAC hierarchy
(viewer < analyst < ciso < owner < admin), account expiry, disable, role-change,
and a per-change audit trail. This is a lifecycle layer, not a full login system — real authentication
(OIDC/JWT, see ip3-oidc.js) plugs into it via canLogin()/getAccount(). |
IP3_ACCESS_MODEL = off (default) · shadow · on. Off:
logic runs and is testable, but not mounted as production auth middleware. |
routes/ip3-access-model.js |
| ci-gate LIVE_CONTROLLED |
IP3-P0-05 | A CI shell script that runs the overclaim lint plus the relevant test suites before a merge is allowed, so a doctrine violation (claim > proof) or a broken test fails the pipeline instead of reaching a page. This is a repository script, not a running server module — there is no on/off flag because it either runs in CI or it does not. | n/a (CI script) | scripts/ip3-ci-gate.sh |
These six close the gaps a bank, insurer, or NIS2-scoped operator will ask about during procurement: tenant isolation proof, formal timestamps, deterministic hashing, vulnerability context, safe alert ingestion, and ticket state truth.
| Module | Task | What it does | Flag (default) | Source |
|---|---|---|---|---|
| rls-enforce LIVE_CONTROLLED |
IP3-P1-01 | A third, evidentiary layer above the existing app-scoping (ip3-tenancy.js) and
PostgreSQL Row-Level Security (ip3-rls.js): assertion functions
(assertNoCrossTenant) plus a per-tenant audit log and a transactional wrapper
(withTenant) that works both against a real PostgreSQL pool and as a dependency-free
in-memory simulation with the same fail-closed semantics (no tenant_id → deny). |
IP3_RLS = off (default) · shadow · on. Off: the
in-memory simulation still runs (always safe offline); the DB path (SET LOCAL) is not
used even if a pool is supplied. |
routes/ip3-rls-enforce.js |
| tsa LIVE_DEMO |
IP3-P1-02 | RFC 3161 Timestamp-Authority helper for evidence packages: builds a TSQ request, parses a TSR
response, with a local fallback. Default output is explicitly tagged
kind:'UNVERIFIED_LOCAL' — a server clock reading, never presented as a real TSA token. |
IP3_TSA = off (default) · on · live. Live mode talks
to a public TSA (e.g. freetsa.org) — not a contracted qualified TSA/QTSP under eIDAS. Qualified
TSA/QTSP integration is ROADMAP (external resource gap). |
routes/ip3-tsa.js |
| canonical LIVE_DEMO |
IP3-P1-03 | Evidence canonicalization v2: JSON Canonicalization Scheme (JCS / RFC 8785) for a stable,
deterministic SHA-256 of a single evidence object, independent of key order or whitespace. This is
not a cryptographic signature and not the full tamper-evident audit chain (see
ip3-audit-chain.js for that) — only canonicalization + hash of one object. |
IP3_CANONICAL_V2 = off (default) · on. Gates only
the mounted verification endpoint (501 when off); the pure functions
(canonicalize/canonicalHash/verifyCanonical) run offline always. |
routes/ip3-canonical.js |
| cve-enrich LIVE_DEMO |
IP3-P1-04 | CVE enrichment (CVSS + EPSS + CISA KEV signal) for a finding by CVE-ID. Default path is fully
offline: results come from a small built-in reference set of publicly known KEV entries, or are
explicitly marked no_data:true — never fabricated. |
IP3_CVE_ENRICH = off (default) · on. On unlocks a
live-lookup path, but requires the caller to inject its own fetchImpl — the module itself
makes no network calls. Full NVD/EPSS/KEV feeds (auth, pagination, full catalog) are ROADMAP (external
resource gap: API keys). |
routes/ip3-cve-enrich.js |
| siem-guard LIVE_CONTROLLED |
IP3-P1-05 | Transport-layer guard in front of the existing SIEM webhook parser
(ip3-siem-webhook.js, unmodified): constant-time HMAC-SHA256 signature check, in-memory
idempotency-key dedup with TTL, and replay protection (nonce + time window). |
IP3_SIEM_GUARD = off (default) · on. Off: pass-through
(identical to legacy behavior, no enforcement). Shared dedup/replay storage across instances (Redis)
is ROADMAP. |
routes/ip3-siem-guard.js |
| ticket-sync LIVE_CONTROLLED |
IP3-P1-06 | A stateful layer over the existing stateless ticket builders (ip3-ticketing.js): ticket
workflow (open → in_progress → resolved → closed), owner assignment, SLA timers keyed by severity, and
a per-change audit trail. ipIII becomes the local source of truth for ticket state associated with an
incident — this is not a live two-way Jira/GitHub integration (no outbound HTTP, no inbound
webhook back-sync). |
IP3_TICKET_SYNC = off (default) · shadow · on. State
logic always runs (pure, offline, testable); the flag gates only production wiring. Persistence beyond
in-memory and real bidirectional transport are ROADMAP. |
routes/ip3-ticket-sync.js |
These six extend reach (threat-intel import, code-scanning ingest) and depth (board reporting, closure discipline, an AI red-team register, operational metrics) once P0/P1 are in place.
| Module | Task | What it does | Flag (default) | Source |
|---|---|---|---|---|
| stix LIVE_DEMO |
IP3-P2-01 | Import parser for CTI/threat-intel in STIX 2.1 (bundle) and TAXII 2.1 (offline fixture) format, normalized into ipIII findings. ipIII is an evidence-first layer above a CTI feed, not a producer of indicators — import is a media signal, not proof of exploitation. | IP3_STIX = off (default) · on. Gates only the live
TAXII fetch (network, ROADMAP); offline bundle parsing always runs, flag-independent. |
routes/ip3-stix.js |
| scm-ingest LIVE_DEMO |
IP3-P2-02 | SARIF 2.1.0 (GitHub/GitLab code-scanning) parser plus a basic CycloneDX SBOM ingest, producing normalized findings/assets. Zero network I/O in the file-based path. A SARIF result is a static-scanner observation for a given commit/branch — may be a false positive, requires human triage. | IP3_SCM_INGEST = off (default) · shadow · on. Off:
the live GitHub/GitLab context stub returns live_ingest_disabled with zero network
connection; file-based parsing is always available. Real GitHub/GitLab REST calls are ROADMAP (external
resource gap: tokens + egress). |
routes/ip3-scm-ingest.js |
| board-report LIVE_DEMO |
IP3-P2-03 | Board/regulator report generator from normalized incidents/findings: a heuristic summary (residual risk / control effectiveness / trend / RAG) — not a certified GRC score. Regulatory-article references are decision-support, a starting point for the board's conversation with compliance/legal, not legal advice. | IP3_BOARD_REPORT = off (default) · on. Pure functions
always run and are testable; off means enabled=false and any mounted route returns 501. |
routes/ip3-board-report.js |
| approval LIVE_DEMO |
IP3-P2-04 | Multi-step approval workflow for incident closure (analyst → owner → ciso/compliance → closure), a state machine that refuses to close an incident until every required role has approved and a retest-evidence reference is attached. The module checks that a reference exists — it does not verify the referenced evidence's content (that integration is a separate, later step). | IP3_APPROVAL = off (default) · shadow · on. Off: all
mutating operations fail-safe (feature_disabled, zero side effects); read operations
(canClose/getIncident/getAudit) always work. |
routes/ip3-approval.js |
| redteam LIVE_DEMO |
IP3-P2-05 | AI red-team register: a corpus of test cases for AI incidents (prompt-injection, agent-hijack, tool-misuse, hallucination-impact). Registering a test case is a media signal describing a planned or executed test — not proof that a system is secure or that a vulnerability was fixed. A pass/fail result without an attached evidence reference is treated as "unrecognized," never as a silent pass. AI Act art. 73 mapping is decision-support only; it never auto-files a report to a regulator. Defensive-only, synthetic data, no attack payloads or instructions are stored or described here. | IP3_REDTEAM = off (default) · on. Pure register/record
logic always runs offline; the flag gates only an eventual mounted API (501 when off). |
routes/ip3-redteam.js |
| observability LIVE_CONTROLLED |
IP3-P2-06 | Prometheus text-exposition metrics (/metrics): request-duration histogram, counters,
a queue-depth gauge, and a health check. "up=1" means only that the process answered the
metrics request — not that every dependency is healthy. db_health stays
null (explicitly marked as an open gap) unless the caller supplies a real
dbPing() function. |
IP3_OBSERVABILITY = off (default) · on. Off: the
/metrics route returns 404 (fail-safe, zero change to current behavior); measurement
functions run always, offline. |
routes/ip3-observability.js |
All 14 modules are reported by one read-only router that loads each module and, when
available, calls its *Status() function. This endpoint cannot switch anything on — it only
reads the current loaded/flag state and returns JSON.
Returns { total, loaded, enabled, waves: { P0, P1, P2 } } with one entry per module:
id, wave, task, loaded, flag,
enabled.
GET /api/ip3/v1/waves/:id/status
Example: /api/ip3/v1/waves/access-model/status. Unknown id → 404.
routes/ip3-waves-mount.js
Read the router itself — it is deliberately short and does nothing except require() each
module and report what it finds.
Some limitations above cannot be closed by writing more code — they require an external resource, contract, or credential that ipIII does not control. These are marked ROADMAP because no amount of code changes the fact that the resource does not exist yet in this deployment:
| Resource | Needed for | Status |
|---|---|---|
| Production IdP (OIDC/SSO) | federated identity behind access-model, replacing local JWT issuance | ROADMAP |
| mTLS PKI (client certificates) | mutual TLS between clients/services in front of rls-enforce/ticket-sync transport | ROADMAP |
| Qualified TSA/QTSP (eIDAS) | a real qualified timestamp behind tsa, replacing UNVERIFIED_LOCAL | ROADMAP |
| API keys (NVD, GitHub, GitLab) | live-lookup paths in cve-enrich and scm-ingest | ROADMAP |
| Durable storage (Postgres tables / Redis) | all 14 modules currently keep state in-memory, per-process; restart = state loss | ROADMAP |
on in production is a deliberate, ACK-gated decision per module, not a default state.
redteam register works
exclusively with synthetic test-case metadata, describing what was tested and what evidence
counts as a pass — it stores no attack payloads or exploitation instructions. Any security-testing activity
happens strictly within the written Rules of Engagement.
Related: full 7-sprint dev roadmap with evidence → /roadmap-dev · honest register of everything not yet done → /known-limitations · status of every product element → /status-matrix · machine-readable page registry → /pages.json.