-
Notifications
You must be signed in to change notification settings - Fork 1
Manage Third Party Risk
Concentration risk, fourth-party exposure, and due-diligence (DD) cadence are
the auditor-facing core of a third-party risk management (TPRM) program.
Evidentia keeps a local vendor inventory, computes concentration-risk reports
across configurable dimensions, and generates / ingests DD questionnaires
(CAIQ, SIG via a licensed template, or a packaged generic baseline). This guide
walks the full operator loop with the evidentia tprm command group.
- Nothing beyond a working Evidentia install — the vendor inventory is local file-backed persistence (no third-party credentials, no network calls).
- The store location resolves via, in order: an explicit path, the
EVIDENTIA_VENDOR_STORE_DIRenvironment variable, then a platform default (platformdirs.user_data_dir). For a self-contained demo or a CI run, point it at a scratch directory so you do not touch your real inventory:
export EVIDENTIA_VENDOR_STORE_DIR="$(mktemp -d)/vendor_store"The
xlsxquestionnaire output format requires the optional[xlsx]extra (pip install 'evidentia-core[xlsx]'). Thesig/sig-liteframeworks additionally require a Shared Assessments licensed XLSX template you supply with--from-template. Thejson/csvpaths below run with no extras.
| Field | What it drives |
|---|---|
--type |
Vendor type — one of saas, subservice_org, contractor, data_processor, cloud_provider, open_source. |
--criticality-tier |
FFIEC tier — one of critical, high, medium, low. Drives the auto-computed DD review cadence. |
--regulatory-classification |
Comma-separated flags — custody, clearing, model, data_processor, critical_third_party. |
--residual-risk-score |
Integer 1–25 (0 = unscored). |
next_review_due |
Auto-computed from criticality_tier + last_due_diligence_review unless you override it with --next-review-due. |
The concentration-report dimensions (--by) are 4th-party, cloud-provider,
criticality-tier, region, regulatory-classification, and
service-category, aligned to FFIEC + OCC Bulletin 2013-29 + FRB SR 13-19
expectations.
evidentia tprm vendor add \
--name "Acme Cloud Inc." \
--type saas \
--criticality-tier critical \
--owner "alice@example.com" \
--contract-start-date 2026-01-01 \
--region "us-east-1" \
--regulatory-classification "data_processor,critical_third_party" \
--residual-risk-score 16 \
--last-due-diligence-review 2026-02-15✓ Added vendor Acme Cloud Inc. (id: e5dd135b-e489-4a4a-9fa4-f3da59589f71)
The command prints the new vendor's UUID — capture it; later commands
(show, edit, dd-questionnaire generate) take that ID. Key flags:
-
--contract-start-dateis required (YYYY-MM-DD). It is easy to miss because it sits among the optional date flags, butvendor addwill not create a record without it. -
--name,--type,--criticality-tier, and--ownerround out the minimum atomic add. See the table above for the--typeand--criticality-tierenum values. - Because we passed
--last-due-diligence-review, Evidentia auto-computesnext_review_duefrom the criticality-tier cadence (acriticalvendor reviewed2026-02-15is next due2027-02-15). - For complex records with fourth-parties and evidence pointers, skip the
atomic flags and load a YAML file with
--from-yaml <path>instead.
Add a couple more so later steps have something to aggregate:
evidentia tprm vendor add --name "Globex Hosting LLC" --type cloud_provider \
--criticality-tier high --owner "bob@example.com" \
--contract-start-date 2025-06-01 --region "us-east-1" --residual-risk-score 12
evidentia tprm vendor add --name "Initech Analytics" --type data_processor \
--criticality-tier medium --owner "carol@example.com" \
--contract-start-date 2025-09-15 --region "eu-west-1" \
--regulatory-classification "model" --residual-risk-score 6✓ Added vendor Globex Hosting LLC (id: c03d3d9e-c2d0-451c-8a6a-fc3fbf541716)
✓ Added vendor Initech Analytics (id: 6e4d2c8d-7c63-4701-83fd-38aeab4b4e6a)
evidentia tprm vendor list Vendor inventory (3 total)
┌─────────┬─────────┬─────────┬─────────┬──────────┬─────────┬──────┬────┬────┐
│ ID │ Name │ Type │ Critic… │ Owner │ Next │ Risk │ 4P │ Ev │
│ │ │ │ │ │ review │ │ │ │
├─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼──────┼────┼────┤
│ e5dd13… │ Acme │ saas │ critic… │ alice@e… │ 2027-0… │ 16 │ 0 │ 0 │
│ │ Cloud │ │ │ │ │ │ │ │
│ c03d3d… │ Globex │ cloud_… │ high │ bob@exa… │ — │ 12 │ 0 │ 0 │
│ │ Hosting │ │ │ │ │ │ │ │
│ 6e4d2c… │ Initech │ data_p… │ medium │ carol@e… │ — │ 6 │ 0 │ 0 │
│ │ Analyt… │ │ │ │ │ │ │ │
└─────────┴─────────┴─────────┴─────────┴──────────┴─────────┴──────┴────┴────┘
The table is sorted by criticality then name. The 4P column counts
fourth-parties and Ev counts attached evidence refs. Filter with
--criticality-tier / --type to narrow a large inventory.
For machine consumption, add --json — a bare array of vendor records,
ready for jq:
evidentia tprm vendor list --json | jq '.[].name'"Acme Cloud Inc."
"Globex Hosting LLC"
"Initech Analytics"Each record carries the full vendor shape (id, type, criticality_tier,
relationship_owner, region, the contract / review dates,
regulatory_classification, fourth_parties, residual_risk_score,
evidence_refs, created_at / updated_at, and an evidentia_version
stamp). This same JSON is what you feed to gap analysis as a tamper-evident
vendor inventory — see What's next.
The CLI
--jsonis unpaginated (optimized for shell pipes). The REST equivalentGET /api/tprm/vendorsreturns a{total, skip, limit, vendors}pagination envelope instead; the shape divergence is intentional and documented in the CLI reference.
Show one vendor in full, including the resolved review cadence:
evidentia tprm vendor show e5dd135b-e489-4a4a-9fa4-f3da59589f71Acme Cloud Inc. (e5dd135b-e489-4a4a-9fa4-f3da59589f71)
Type: saas
Criticality tier: critical
Relationship owner: alice@example.com
Contract start: 2026-01-01
Contract end: (indefinite)
Last DD review: 2026-02-15
Next review due: 2027-02-15
Residual risk: 16 / 25
Regulatory flags: data_processor, critical_third_party
Created: 2026-05-30 06:44:33+00:00 Updated: 2026-05-30 06:44:33+00:00
Add --json to show for the raw record instead of the human view.
Atomic --<field> flags update one or more fields in place. Record a completed
DD review and bump the residual-risk score for the cloud-provider:
evidentia tprm vendor edit c03d3d9e-c2d0-451c-8a6a-fc3fbf541716 \
--residual-risk-score 15 \
--last-due-diligence-review 2026-03-01✓ Updated vendor Globex Hosting LLC (id: c03d3d9e-c2d0-451c-8a6a-fc3fbf541716)
Updating --last-due-diligence-review re-runs the cadence calculation, so
next_review_due moves automatically (a high vendor reviewed 2026-03-01 is
next due 2027-03-01). Confirm with show:
evidentia tprm vendor show c03d3d9e-c2d0-451c-8a6a-fc3fbf541716Globex Hosting LLC (c03d3d9e-c2d0-451c-8a6a-fc3fbf541716)
Type: cloud_provider
Criticality tier: high
Relationship owner: bob@example.com
Contract start: 2025-06-01
Contract end: (indefinite)
Last DD review: 2026-03-01
Next review due: 2027-03-01
Residual risk: 15 / 25
Created: 2026-05-30 06:44:51+00:00 Updated: 2026-05-30 06:45:35+00:00
edit has two other mutually-exclusive modes: --from-yaml <path> for a
scripted full-replace (preserves the original id + created_at), and
--editor to open the current record as YAML in $EDITOR. To remove a record
entirely, evidentia tprm vendor delete <id> prompts for confirmation unless
you pass -y — auditors generally prefer keeping the record and letting the
contract dates lapse over deleting history.
Aggregate the inventory across one or more dimensions to surface where you are
over-concentrated. Pass --threshold to flag any value whose vendor share
meets-or-exceeds a percentage; omit it for an unflagged distribution view.
evidentia tprm concentration-report --by criticality-tier --threshold 30 --format json{
"generated_at": "2026-05-30T06:45:49.891330Z",
"total_vendors": 3,
"threshold": 30.0,
"dimensions": [
{
"dimension": "criticality-tier",
"total_unique_values": 3,
"distribution": [
{ "value": "critical", "count": 1, "percentage": 33.3, "exceeds_threshold": true },
{ "value": "high", "count": 1, "percentage": 33.3, "exceeds_threshold": true },
{ "value": "medium", "count": 1, "percentage": 33.3, "exceeds_threshold": true }
],
"vendors_with_value": 3
}
]
}The real JSON also ends with an
"evidentia_version"field (the build that produced the report); it is trimmed here so the doc does not pin a version.
The report dict carries generated_at, total_vendors, the threshold you
passed, and a dimensions array — each with a per-value distribution
(count, percentage, and exceeds_threshold against your threshold). With
three single-vendor tiers each holding 33.3%, all three exceed a 30% threshold.
--by accepts multiple comma-separated dimensions (the default is
region,cloud-provider), and --format offers html / json / csv. CSV is
the most pipe-friendly for a single dimension:
evidentia tprm concentration-report --by region --threshold 50 --format csvdimension,value,count,percentage,exceeds_threshold
region,us-east-1,2,66.7,true
region,eu-west-1,1,33.3,false
Here two of three vendors sit in us-east-1 (66.7%), which trips the 50%
threshold — exactly the regional-concentration signal an examiner looks for.
The default --format html writes a self-contained, sortable HTML report;
redirect it to a file (--output report.html) or let it dump to stdout.
dd-questionnaire generate pre-fills a questionnaire with the vendor's metadata
(name, type, criticality, contract dates, region, regulatory classification,
fourth-party disclosures) so the receiving vendor only fills in the control
answers. The default framework is evidentia-generic (a packaged FFIEC-aligned
baseline) and the default --output-format is json:
evidentia tprm dd-questionnaire generate \
--vendor-id e5dd135b-e489-4a4a-9fa4-f3da59589f71 \
--format evidentia-generic \
--output-format json \
--output acme-dd.json✓ Wrote JSON questionnaire to acme-dd.json (20 question(s);
format=evidentia-generic; vendor=Acme Cloud Inc.)
The written file carries a vendor metadata block (echoing the inventory
record) and a questions array. Each question has a stable id, a domain,
the question_text, optional response_options, and operator notes on
acceptable evidence:
{
"id": "EVG-GOV-03",
"domain": "Governance",
"question_text": "Has your organization undergone an independent third-party security audit (SOC 2 Type II, ISO 27001, FedRAMP, or equivalent) in the last 12 months?",
"response_options": ["Yes", "No", "Not Applicable"],
"notes": "If Yes, provide the report or attestation letter and indicate the audit period covered."
}Key flags:
-
--vendor-idis required — the questionnaire is always tied to a record. -
--formatchoices:caiq-full,caiq-lite,evidentia-generic(packaged).sig/sig-liteare also accepted only with--from-template(see below). -
--output-formatchoices:json,csv,xlsx.xlsxrequires the[xlsx]extra (pip install 'evidentia-core[xlsx]') and a--outputpath (binary output can't go to stdout). Thejson/csvpaths shown here need no extra.
Requires a licensed template. SIG / SIG-Lite generation needs a Shared Assessments licensed XLSX you supply with
--from-template; Evidentia pre-fills vendor metadata into the standard cells and leaves the question content untouched for license compliance. Not shown here (the template is not redistributable):evidentia tprm dd-questionnaire generate \ --vendor-id <id> --format sig \ --from-template path/to/SIG-2026.xlsx \ --output sig-prefilled.xlsx
Once a vendor returns the completed file, dd-questionnaire ingest parses it
and correlates it back to the inventory record. Format is auto-detected from the
extension (.json / .csv / .xlsx). Correlation is required — it
resolves via --vendor-id if you pass it, otherwise via the questionnaire's
embedded vendor_id from the prefill.
evidentia tprm dd-questionnaire ingest --questionnaire acme-completed.jsonThe command parses the file, correlates it back to the vendor inventory record, and prints a summary for operator review:
✓ Ingested questionnaire from completed-q.json
Vendor: Acme Cloud (id=e1ed43f9-…) Questionnaire ID: ed778a88-… Format: evidentia-generic
Responses: 20 (answered: 0)
Vendor responses (first 25)
┌─────────────┬──────────┐
│ Question ID │ Response │
├─────────────┼──────────┤
│ EVG-GOV-01 │ (blank) │
│ EVG-GOV-02 │ (blank) │
│ … │ … │
└─────────────┴──────────┘
Pass --output-format json for a machine-readable summary. The format field
carries the questionnaire framework (evidentia-generic, caiq-lite, …); the
responses map is keyed by question ID:
{
"vendor": { "id": "e1ed43f9-…", "name": "Acme Cloud" },
"questionnaire_id": "ed778a88-…",
"format": "evidentia-generic",
"responses": { "EVG-GOV-01": "", "EVG-GOV-02": "", "…": "…" }
}The flags themselves are straightforward: --questionnaire <path> is required;
--vendor-id overrides correlation when the embedded ID is missing or you want
to file the response against a different record; --output-format is table
(default) or json.
Note on persistence: this release's
ingestis parse + correlate + display only. Writing the response intovendor.evidence_refs[]is queued for a follow-up release (pending the evidence chain-of-custody Sigstore signing — see Sign and verify evidence).
The list-and-add basics also work in the browser. Start the server with
evidentia serve and open the TPRM screen from the sidebar's Govern
group — it reads and writes the same file-backed vendor store the CLI above
manages, so a vendor added in either place shows up in the other. The screen
covers browsing the inventory, filtering it, and the atomic add; the full loop —
concentration-risk reports, due-diligence questionnaires, edits, and deletes —
stays on the CLI.

-
Browse. The inventory renders one card per vendor, each showing the
vendor name, a criticality-tier badge (
critical/high/medium/low), a type badge (SaaS, Subservice org, Contractor, Data processor, Cloud provider, Open source), the relationship owner, and the next review due date (not scheduled until a DD review is recorded). The header shows a liveN of M vendorscount. -
Filter. Two chip rows narrow the list without a page reload — one by
criticality tier and one by vendor type — the same two axes
vendor list --criticality-tier/--typefilter on. The filters combine; click All tiers / All types to clear an axis. -
Add a vendor. The New vendor form takes the same five required fields
as
vendor add— name, relationship owner, contract start date (a date picker; easy to miss on the CLI, but the form will not submit without it), and chip pickers for type and criticality tier. The Add vendor button stays disabled until the three text/date fields are filled; a validation error from the server surfaces inline beneath the form rather than clearing it.
Richer fields — region, regulatory classification, fourth parties, the
residual-risk score, and evidence references — are set through the CLI
(evidentia tprm vendor edit, or a --from-yaml load) on the same store; the
form leaves residual risk at its 0 (unscored) default.
-
Feed the inventory into gap analysis.
evidentia tprm vendor list --json > vendors.jsonproduces the inventory thatevidentia gap analyze --format oscal-ar --vendor-inventory vendors.jsonembeds into an OSCAL Assessment Results document (each vendor added tometadata.parties[]and as a SHA-256-hashed back-matter resource). See Run a gap analysis. - Track remediation of vendor findings. Roll material third-party gaps into a POA&M with milestone timelines.
- Run reviews on a cadence. Wire the DD-review schedule into a recurring assessment loop with CONMON deployment.
-
Full flag reference. Every
tprmflag, default, and enum is in the CLI reference →evidentia tprm. - The data model. The base-model conventions behind the vendor record live in Concepts → Data model.
-
vendor addexits without creating a record: confirm you passed--contract-start-date(YYYY-MM-DD). It is required and sits among the optional date flags, so it is the most commonly missed argument. -
Invalid vendor ID format (expected UUID string):show/edit/deletetake the full UUID, not the truncated ID shown in thelisttable. Runevidentia tprm vendor list --json | jq '.[].id'to copy a full ID. -
xlsx requires the [xlsx] extra(or an import error onopenpyxl): thexlsxoutput format needspip install 'evidentia-core[xlsx]'. Usejsonorcsvif you don't need a workbook. -
concentration-reportshows everything at 0%/100% or an empty distribution: the report is computed over whatever is in the store. ConfirmEVIDENTIA_VENDOR_STORE_DIRpoints at the inventory you populated (a freshmktemp -dstore starts empty), and that the vendors carry the dimension you asked for with--by(e.g.--by regionneeds--regionset on records).
-
- AI Governance
- Air Gapped Install
- Ci Integration
- CONMON Deployment
- Emit Cyclonedx VEX
- Emit OCSF Detection
- Emit SARIF
- Explain Controls
- Generate And Quantify Risk
- Governance Metrics And Workflows
- Ingest OCSF
- Manage Model Risk
- Manage POAM
- Manage Third Party Risk
- MCP Client Setup
- OSPS Self Assessment
- Run Gap Analysis
- Serve The Web Ui
- Sign And Verify Evidence