feat(integrations): add Vanta integration with compliance, evidence file, people, vendor, vulnerability, and risk tools (#4993)

* feat(integrations): add Vanta integration with compliance, evidence file, people, vendor, vulnerability, and risk tools

* fix(integrations): use write-only scope for vanta document submit and stream-cap document downloads

* fix(integrations): vanta review feedback - unique svg ids, mime type for base64 uploads, auth check consistency

* fix(integrations): bound vanta base64 fileContent size at the contract level

* improvement(integrations): cache vanta tokens and retry once on revocation to avoid concurrent token races

* improvement(integrations): deduplicate in-flight vanta token exchanges

* fix(integrations): hash vanta client secret in token cache keys

* improvement(integrations): expose vanta upload mime type in block and align fileContent bound with the 100MB cap

* chore: resolve api-validation baseline after rebase onto staging (816 + 3 vanta routes)
This commit is contained in:
Waleed
2026-06-12 10:56:27 -07:00
committed by GitHub
parent e2523e0fb5
commit 3db7161b1c
49 changed files with 8799 additions and 2 deletions
+51
View File
@@ -7555,6 +7555,57 @@ export function OnePasswordIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function VantaIcon(props: SVGProps<SVGSVGElement>) {
const id = useId()
const clipId = `vanta_clip_${id}`
const maskId = `vanta_mask_${id}`
return (
<svg {...props} viewBox='0 0 512 512' fill='none' xmlns='http://www.w3.org/2000/svg'>
<g clipPath={`url(#${clipId})`}>
<circle cx='256' cy='256' r='256' fill='#AC55FF' />
<mask
id={maskId}
style={{ maskType: 'alpha' }}
maskUnits='userSpaceOnUse'
x='0'
y='0'
width='512'
height='512'
>
<circle cx='256' cy='256' r='256' fill='#AC55FF' />
</mask>
<g mask={`url(#${maskId})`}>
<path
d='M269.699 530.451C360.294 530.451 407.136 502.376 421.276 474.223C422.09 472.599 420.53 470.761 418.81 471.332C402.863 476.607 390.96 466.808 389.625 455.498C389.625 455.498 385.167 407.538 369.22 402.858C370.165 400.913 374.01 385.586 362.126 371.424C365.376 361.406 362.691 354.81 360.26 349.823C363.222 346.191 365.498 341.506 366.482 336.943C366.726 335.861 366.721 334.905 367.598 333.887C373.201 329.231 379.384 325.389 383.145 318.574C389.923 306.26 385.382 292.196 377.167 281.817C376.334 280.671 375.681 280.12 375.622 277.176C375.642 272.145 374.731 266.968 372.027 262.717C370.648 260.557 368.84 258.69 366.945 256.959C359.052 249.598 349.609 244.163 340.542 238.293C339.295 237.494 337.843 236.431 337.302 234.978C334.447 224.351 327.065 216.131 317.886 213.894C317.691 206.776 310.187 195.983 298.835 195.983C295.371 195.983 292.506 197.865 290.718 194.623C286.566 186.75 278.293 185.287 273.976 185.088C273.25 185.053 273.046 184.078 273.704 183.766C275.087 183.103 277.182 182.187 280.291 180.988C295.882 173.524 289.431 131.009 283.049 108.575C280.062 100.199 272.49 76.3803 253.942 74.8057C252.665 74.6985 251.359 74.7277 250.126 75.0836C246.555 76.1122 243.909 78.9738 242.048 82.9372C235.914 95.2709 234.379 128.562 232.123 142.797C228.922 163.096 226.023 184.873 215.913 193.799C211.606 182.436 205.374 177.171 201.969 177.37C199.001 178.068 203.016 183.835 201.306 192.341C200.117 197.236 197.408 201.804 192.794 201.804C179.273 201.804 167.098 134.173 163.463 93.5451C163.365 92.4824 163.263 91.4245 163.068 90.3715C161.285 80.5533 156.12 74.757 150.663 74.757C147.896 74.757 137.961 73.7478 126.584 91.639C118.764 105.591 113.795 120.177 113.312 147.341C113.322 174.714 125.532 193.019 130.477 202.023C150.688 235.266 153.387 246.741 149.562 267.007C145.674 286.653 157.533 297.7 157.533 297.7C155.857 300.298 153.645 307.259 153.134 314.899C152.807 319.764 153.801 328.49 156.125 333.891C151.024 344.885 151.146 353.621 151.146 359.129C151.146 371.892 145.577 377.089 138.336 379.36C140.29 386.322 153.275 390.051 160.788 382.612C158.571 404.476 154.473 424.171 148.753 448.546C145.197 465.233 145.796 474.583 148.49 482.5C149.703 486.069 151.604 489.355 153.928 492.319C181.637 527.667 233.629 530.451 269.699 530.451ZM269.655 482.739C259.671 481.116 250.331 476.139 243.515 468.602C225.351 474.618 206.466 459.33 212.205 439.147C213.121 436.505 217.058 437.475 216.668 440.229C216.103 443.783 216.756 447.42 218.281 450.55C222.34 459.827 234.438 462.323 241.853 455.859C244.596 453.441 248.562 454.362 250.424 457.36C266.663 479.4 300.355 475.266 311.654 450.525C313.311 447.069 314.392 443.408 315.021 439.615C315.464 436.924 319.498 437.178 319.61 439.898C320.522 466.525 295.6 486.902 269.65 482.744L269.655 482.739Z'
fill='#240642'
/>
<path
d='M371.525 292.61C369.79 292.61 367.924 295.033 367.446 298.806C366.414 304.125 366.769 313.958 362.028 313.958C358.749 313.958 358.452 307.367 352.942 301.293C347.226 295.399 339.031 294.799 333.774 290.558C330.851 288.53 329.111 286.034 329.301 281.749C329.301 281.749 329.925 274.924 339.134 276.172C343.514 276.63 350.613 277.698 355.007 278.2C362.857 279.087 364.772 273.247 365.005 271.263C365.507 266.612 360.572 262.761 357.448 260.05C353.502 256.613 349.2 253.527 344.742 250.758C343.933 250.256 343.109 249.735 342.286 249.208C331.104 242.076 311.225 230.137 300.077 243.768C296.082 249.12 294.347 255.287 293.095 260.396C290.781 269.747 285.923 273.354 282.474 279.058C276.992 288.111 273.226 298.392 272.938 308.971C272.89 324.244 282.332 339.205 297.397 348.555C309.9 355.117 316.317 355.117 321.325 353.777C322.241 353.465 324.249 352.065 322.87 349.75C322.621 349.257 321.925 348.175 321.501 347.473C320.073 344.846 322.027 342.442 324.921 344.69C326.826 346.181 328.77 347.673 331.011 348.585C332.897 349.35 335.046 349.652 336.995 349.136C336.995 349.136 336.995 349.136 336.999 349.136C339.28 348.39 340.434 346.893 340.566 344.982C340.698 342.701 339.665 340.936 337.954 339.995C335.353 338.728 329.594 335.559 327.162 333.765C324.419 331.844 321.486 328.973 320.468 327.89C317.15 324.361 316.2 320.914 314.134 320.914C313.788 320.934 313.452 321.129 313.218 321.392C311.922 322.777 311.912 325.058 311.849 326.36C311.805 327.32 311.956 328.783 310.611 328.783C307.278 328.783 307.288 321.831 307.293 319.944C307.293 317.36 308.238 310.657 312.229 310.657C313.461 310.657 315.137 312.31 315.795 312.958C324.59 322.723 334.812 330.318 347.762 330.318C357.677 330.318 365.96 324.717 371.169 319.466C375.247 315.371 377.932 310.243 378.112 304.944C378.224 301.585 376.611 292.615 371.525 292.615V292.61ZM314.714 301.697C313.51 302.365 312.073 301.536 310.762 301.107C308.126 300.24 305.135 301.117 302.962 302.843C301.471 304.032 300.331 305.587 299.405 307.264C298.396 309.097 298.206 311.515 296.038 311.515C294.255 311.515 293.358 309.044 293.163 308.025C292.116 302.492 294.786 296.335 299.751 293.683C304.716 291.031 311.6 292.435 314.811 297.056C315.308 297.773 315.732 298.582 315.79 299.455C315.849 300.327 315.483 301.273 314.718 301.697H314.714Z'
fill='white'
/>
<path
d='M249.386 238.371C244.645 238.44 240.046 240.477 236.694 243.919C234.808 245.854 230.608 252.114 231.017 261.761C230.949 263.18 229.083 263.687 228.333 262.478C225.307 257.057 225.132 251.402 226.306 247.229C228.912 238.795 236.274 231.785 246.224 231.785C259.277 231.785 262.551 240.326 263.204 242.973C263.516 244.07 262.161 244.879 261.328 244.099C259.165 242.086 255.827 238.371 249.376 238.371H249.386Z'
fill='white'
/>
<path
d='M250.453 257.471C247.334 257.749 244.874 255.736 244.596 252.621C244.323 249.559 246.384 247.034 249.503 246.756C252.621 246.478 255.15 248.599 255.422 251.66C255.7 254.78 253.571 257.193 250.458 257.471H250.453Z'
fill='white'
/>
<path
d='M148.261 199.172C143.662 199.172 128.582 174.699 128.582 140.145C128.582 124.638 132.563 108.087 139.798 108.087C144.251 108.087 145.26 117.574 145.465 120.387C147.808 150.066 143.983 170.224 149.567 197.109C149.937 198.684 148.987 199.176 148.261 199.176V199.172Z'
fill='white'
/>
</g>
</g>
<defs>
<clipPath id={clipId}>
<rect width='512' height='512' fill='white' />
</clipPath>
</defs>
</svg>
)
}
export function VercelIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
+2
View File
@@ -207,6 +207,7 @@ import {
TwilioIcon,
TypeformIcon,
UpstashIcon,
VantaIcon,
VercelIcon,
VideoIcon,
WealthboxIcon,
@@ -456,6 +457,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
twilio_voice: TwilioIcon,
typeform: TypeformIcon,
upstash: UpstashIcon,
vanta: VantaIcon,
vercel: VercelIcon,
video_generator: VideoIcon,
video_generator_v2: VideoIcon,
@@ -208,6 +208,7 @@
"twilio_voice",
"typeform",
"upstash",
"vanta",
"vercel",
"wealthbox",
"webflow",
@@ -0,0 +1,691 @@
---
title: Vanta
description: Query compliance status and manage evidence in Vanta
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="vanta"
color="#F8F4F3"
/>
{/* MANUAL-CONTENT-START:intro */}
[Vanta](https://www.vanta.com/) is a trust management platform that automates security and compliance for frameworks like SOC 2, ISO 27001, HIPAA, and GDPR. It continuously monitors your infrastructure, people, and vendors through automated tests, and centralizes the evidence auditors need.
With the Vanta integration in Sim, you can:
- **Monitor compliance posture**: List frameworks with control, document, and test completion counts, and drill into individual controls and their mapped tests and evidence documents.
- **Triage failing tests**: List automated compliance tests by status, framework, integration, or category, and pull the exact failing resource entities that need remediation.
- **Manage evidence documents**: List and inspect evidence documents, upload evidence files with descriptions and effective dates, download previously uploaded files, and submit document collections for auditor review.
- **Track people and security tasks**: List people with employment status, group membership, and outstanding security tasks (trainings, policy acceptance, background checks, device monitoring).
- **Review policies and vendors**: Check policy approval status and versions, and track vendors with risk levels, contract dates, and security review schedules.
- **Stay on top of vulnerabilities**: List vulnerabilities with severity and SLA deadline filters, review remediation history, and inspect the vulnerable assets behind each finding.
- **Watch device compliance**: List monitored computers with screenlock, disk encryption, password manager, and antivirus check outcomes.
- **Manage risk scenarios**: Query risk register scenarios with likelihood/impact scores, treatment decisions, and review status.
The integration authenticates with Vanta OAuth client credentials (created under Settings → Developer Console in Vanta) and supports both the commercial (api.vanta.com) and FedRAMP (api.vanta-gov.com) environments. Evidence uploads require credentials granted the `vanta-api.documents:upload` scope.
{/* MANUAL-CONTENT-END */}
## Usage Instructions
Integrate Vanta into the workflow. Monitor compliance frameworks, controls, and automated tests; find failing test entities; manage evidence documents including file upload, download, and submission; and track people, policies, vendors, monitored computers, vulnerabilities, and risk scenarios. Requires Vanta OAuth client credentials.
## Actions
### `vanta_list_frameworks`
List the compliance frameworks (e.g., SOC 2, ISO 27001) available in a Vanta account with completion counts
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `frameworks` | array | Frameworks in the Vanta account |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_get_framework`
Get a Vanta compliance framework by ID, including its requirement categories and mapped controls
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `frameworkId` | string | Yes | Unique ID of the framework \(e.g., soc2\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `framework` | json | The requested framework with requirement categories |
### `vanta_list_framework_controls`
List the controls that belong to a specific Vanta compliance framework
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `frameworkId` | string | Yes | Unique ID of the framework \(e.g., soc2\) |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `controls` | array | Controls belonging to the framework |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_list_controls`
List the security controls in a Vanta account, optionally filtered by framework
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `frameworkMatchesAny` | string | No | Comma-separated framework IDs to filter controls by \(e.g., soc2,iso27001\) |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `controls` | array | Controls matching the filters |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_get_control`
Get a Vanta security control by ID, including its status and evidence pass/fail counts
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `controlId` | string | Yes | Unique ID of the control |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `control` | json | The requested control with status and evidence counts |
### `vanta_list_control_tests`
List the automated tests mapped to a specific Vanta control
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `controlId` | string | Yes | Unique ID of the control |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `tests` | array | Tests mapped to the control |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_list_control_documents`
List the evidence documents mapped to a specific Vanta control
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `controlId` | string | Yes | Unique ID of the control |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `documents` | array | Documents mapped to the control |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_list_tests`
List the automated compliance tests in a Vanta account, with filters for status, framework, integration, control, owner, and category
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `statusFilter` | string | No | Filter by test status: OK, DEACTIVATED, NEEDS_ATTENTION, IN_PROGRESS, INVALID, or NOT_APPLICABLE |
| `frameworkFilter` | string | No | Filter by framework ID \(e.g., soc2\) |
| `integrationFilter` | string | No | Filter by integration ID \(e.g., aws\) |
| `controlFilter` | string | No | Filter by control ID |
| `ownerFilter` | string | No | Filter by owner user ID |
| `categoryFilter` | string | No | Filter by test category \(e.g., ACCOUNTS_ACCESS, COMPUTERS, INFRASTRUCTURE, POLICIES, VULNERABILITY_MANAGEMENT\) |
| `isInRollout` | boolean | No | Filter by whether the test is in rollout |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `tests` | array | Tests matching the filters |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_get_test`
Get a Vanta automated compliance test by ID, including its status and remediation info
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `testId` | string | Yes | Unique ID of the test \(e.g., test-aws-cloudtrail-enabled\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `test` | json | The requested test |
### `vanta_list_test_entities`
List the failing or deactivated resource entities for a specific Vanta test, useful for finding exactly which resources need remediation
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `testId` | string | Yes | Unique ID of the test \(e.g., test-aws-cloudtrail-enabled\) |
| `entityStatus` | string | No | Filter entities by status: FAILING or DEACTIVATED |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `entities` | array | Resource entities for the test |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_list_documents`
List the evidence documents in a Vanta account, optionally filtered by framework or document status
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `frameworkMatchesAny` | string | No | Comma-separated framework IDs to filter documents by \(e.g., soc2,iso27001\) |
| `statusMatchesAny` | string | No | Comma-separated document statuses to filter by: "Needs document", "Needs update", "Not relevant", "OK" |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `documents` | array | Documents matching the filters |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_get_document`
Get a Vanta evidence document by ID, including its renewal schedule and deactivation status
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `documentId` | string | Yes | Unique ID of the document |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `document` | json | The requested document |
### `vanta_list_document_uploads`
List the files uploaded to a specific Vanta evidence document
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `documentId` | string | Yes | Unique ID of the document |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `uploads` | array | Files uploaded to the document |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_upload_document_file`
Upload an evidence file to a Vanta document. Requires credentials with the vanta-api.documents:upload scope.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `documentId` | string | Yes | Unique ID of the document to attach the file to |
| `file` | file | No | The evidence file to upload |
| `fileContent` | string | No | Base64-encoded file content \(alternative to file\) |
| `fileName` | string | No | Optional file name override |
| `mimeType` | string | No | MIME type of the file \(e.g., application/pdf\); used when uploading base64 content, since uploaded files already carry their own type |
| `description` | string | No | Description of the uploaded evidence \(e.g., "Q3 access review evidence"\) |
| `effectiveAtDate` | string | No | ISO 8601 date indicating when the document is effective from |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `upload` | json | Metadata of the uploaded file |
### `vanta_download_document_file`
Download a file previously uploaded to a Vanta evidence document and store it in execution files
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `documentId` | string | Yes | Unique ID of the document |
| `uploadedFileId` | string | Yes | Unique ID of the uploaded file \(from List Document Uploads\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `file` | file | Downloaded file stored in execution files |
| `name` | string | Name of the downloaded file |
| `mimeType` | string | MIME type of the downloaded file |
| `size` | number | Size of the downloaded file in bytes |
### `vanta_submit_document`
Submit a Vanta document collection for review so uploaded evidence becomes visible to auditors. Requires credentials with write access.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `documentId` | string | Yes | Unique ID of the document to submit |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `documentId` | string | ID of the submitted document |
| `submitted` | boolean | Whether the document collection was submitted |
### `vanta_list_people`
List the people tracked in a Vanta account with employment status, group membership, and security task completion
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `emailAndNameFilter` | string | No | Filter people by email address or name |
| `employmentStatus` | string | No | Filter by employment status: UPCOMING, CURRENT, ON_LEAVE, INACTIVE, or FORMER |
| `groupIdsMatchesAny` | string | No | Comma-separated group IDs to filter people by |
| `tasksSummaryStatusMatchesAny` | string | No | Comma-separated task summary statuses to filter by: NONE, DUE_SOON, OVERDUE, COMPLETE, PAUSED, OFFBOARDING_DUE_SOON, OFFBOARDING_OVERDUE, OFFBOARDING_COMPLETE |
| `taskTypeMatchesAny` | string | No | Comma-separated task types to filter by: COMPLETE_TRAININGS, ACCEPT_POLICIES, COMPLETE_CUSTOM_TASKS, COMPLETE_CUSTOM_OFFBOARDING_TASKS, INSTALL_DEVICE_MONITORING, COMPLETE_BACKGROUND_CHECKS |
| `taskStatusMatchesAny` | string | No | Comma-separated task statuses to filter by: COMPLETE, DUE_SOON, OVERDUE, NONE |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `people` | array | People matching the filters |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_get_person`
Get a person tracked in Vanta by ID, including employment, leave, and security task status
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `personId` | string | Yes | Unique ID of the person |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `person` | json | The requested person |
### `vanta_list_policies`
List the security policies in a Vanta account with approval status and version info
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `policies` | array | Policies in the Vanta account |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_get_policy`
Get a Vanta security policy by ID, including its approval status and latest approved version documents
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `policyId` | string | Yes | Unique ID of the policy |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `policy` | json | The requested policy |
### `vanta_list_vendors`
List the vendors tracked in a Vanta account with risk levels, contract dates, and security review schedules
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `name` | string | No | Filter vendors by name |
| `statusMatchesAny` | string | No | Comma-separated vendor statuses to filter by: MANAGED, ARCHIVED, IN_PROCUREMENT |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `vendors` | array | Vendors matching the filters |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_get_vendor`
Get a Vanta vendor by ID, including risk levels, contract details, and authentication info
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `vendorId` | string | Yes | Unique ID of the vendor |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `vendor` | json | The requested vendor |
### `vanta_list_monitored_computers`
List the monitored computers in a Vanta account with screenlock, disk encryption, password manager, and antivirus check outcomes
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `complianceStatusFilterMatchesAny` | string | No | Comma-separated compliance issues to filter by: PWM_NOT_INSTALLED, HD_NOT_ENCRYPTED, AV_NOT_INSTALLED, SCREENLOCK_NOT_CONFIGURED, LAST_CHECK_OVER_14_DAYS |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `computers` | array | Monitored computers matching the filters |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_list_vulnerabilities`
List the vulnerabilities detected across a Vanta account with filters for severity, fixability, SLA deadlines, package, and integration
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `q` | string | No | Search query for vulnerabilities |
| `severity` | string | No | Filter by severity: LOW, MEDIUM, HIGH, or CRITICAL |
| `isFixAvailable` | boolean | No | Filter by whether a fix is available |
| `isDeactivated` | boolean | No | Filter by whether vulnerability monitoring is deactivated |
| `includeVulnerabilitiesWithoutSlas` | boolean | No | Include vulnerabilities that have no SLA deadline |
| `packageIdentifier` | string | No | Filter by the affected package identifier |
| `externalVulnerabilityId` | string | No | Filter by external vulnerability ID \(e.g., a CVE identifier\) |
| `integrationId` | string | No | Filter by the integration that detected the vulnerability |
| `vulnerableAssetId` | string | No | Filter by the vulnerable asset ID |
| `slaDeadlineAfterDate` | string | No | Only include vulnerabilities with an SLA deadline after this ISO 8601 date |
| `slaDeadlineBeforeDate` | string | No | Only include vulnerabilities with an SLA deadline before this ISO 8601 date |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `vulnerabilities` | array | Vulnerabilities matching the filters |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_list_vulnerability_remediations`
List remediated vulnerabilities in a Vanta account with detection, SLA deadline, and remediation dates
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `integrationId` | string | No | Filter by the integration that detected the vulnerability |
| `severity` | string | No | Filter by severity: LOW, MEDIUM, HIGH, or CRITICAL |
| `isRemediatedOnTime` | boolean | No | Filter by whether the vulnerability was remediated before its SLA deadline |
| `remediatedAfterDate` | string | No | Only include remediations completed after this ISO 8601 date |
| `remediatedBeforeDate` | string | No | Only include remediations completed before this ISO 8601 date |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `remediations` | array | Vulnerability remediations matching the filters |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_list_vulnerable_assets`
List the assets associated with vulnerabilities in a Vanta account (servers, repositories, workstations, and more)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `q` | string | No | Search query for vulnerable assets |
| `integrationId` | string | No | Filter by the integration scanning the asset |
| `assetType` | string | No | Filter by asset type: SERVER, SERVERLESS_FUNCTION, CONTAINER, CONTAINER_REPOSITORY, CONTAINER_REPOSITORY_IMAGE, CODE_REPOSITORY, MANIFEST_FILE, WORKSTATION, or OTHER |
| `assetExternalAccountId` | string | No | Filter by the external account ID the asset belongs to |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `assets` | array | Vulnerable assets matching the filters |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_get_vulnerable_asset`
Get a vulnerable asset in Vanta by ID, including the scanners reporting it and per-scanner asset details
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `vulnerableAssetId` | string | Yes | Unique ID of the vulnerable asset |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `asset` | json | The requested vulnerable asset |
### `vanta_list_risk_scenarios`
List the risk scenarios in a Vanta risk register with likelihood/impact scores, treatment decisions, and review status
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `searchString` | string | No | Search string to filter risk scenarios |
| `includeIgnored` | boolean | No | Include ignored risk scenarios |
| `type` | string | No | Filter by scenario type: "Risk Scenario" or "Enterprise Risk" |
| `ownerMatchesAny` | string | No | Comma-separated owner emails to filter by |
| `categoryMatchesAny` | string | No | Comma-separated risk categories to filter by |
| `ciaCategoryMatchesAny` | string | No | Comma-separated CIA categories to filter by: Confidentiality, Integrity, Availability |
| `treatmentTypeMatchesAny` | string | No | Comma-separated treatments to filter by: Mitigate, Transfer, Avoid, Accept |
| `inherentScoreGroupMatchesAny` | string | No | Comma-separated inherent score groups to filter by: "Very low", Low, Med, High, Critical |
| `residualScoreGroupMatchesAny` | string | No | Comma-separated residual score groups to filter by: "Very low", Low, Med, High, Critical |
| `reviewStatusMatchesAny` | string | No | Comma-separated review statuses to filter by: APPROVED, DRAFT, NOT_REVIEWED, AWAITING_SUBMISSION, PENDING_APPROVAL, REQUESTED_CHANGES |
| `orderBy` | string | No | Field to order results by: description or createdAt |
| `pageSize` | number | No | Maximum number of items per page \(1-100, default 10\) |
| `pageCursor` | string | No | Pagination cursor: pass the endCursor from the previous response to fetch the next page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `riskScenarios` | array | Risk scenarios matching the filters |
| `pageInfo` | json | Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page |
### `vanta_get_risk_scenario`
Get a Vanta risk scenario by ID, including its scores, treatment decision, and review status
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `clientId` | string | Yes | Vanta OAuth application client ID |
| `clientSecret` | string | Yes | Vanta OAuth application client secret |
| `region` | string | No | Vanta API region: "us" \(api.vanta.com, default\) or "gov" \(api.vanta-gov.com\) |
| `riskScenarioId` | string | Yes | Unique ID of the risk scenario |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `riskScenario` | json | The requested risk scenario |
@@ -0,0 +1,160 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { vantaDownloadContract } from '@/lib/api/contracts/tools/vanta'
import { parseRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { generateRequestId } from '@/lib/core/utils/request'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import {
buildVantaUrl,
extractVantaError,
fetchVantaWithAuth,
getVantaBaseUrl,
VANTA_READ_SCOPE,
} from '@/tools/vanta/utils'
export const dynamic = 'force-dynamic'
const logger = createLogger('VantaDownloadAPI')
const MAX_DOWNLOAD_SIZE_BYTES = 100 * 1024 * 1024
function downloadSizeError(bytes: number): NextResponse {
const sizeMB = (bytes / (1024 * 1024)).toFixed(2)
return NextResponse.json(
{ success: false, error: `File size (${sizeMB}MB) exceeds download limit of 100MB` },
{ status: 400 }
)
}
/**
* Reads a response body incrementally, aborting as soon as the accumulated
* size exceeds the limit so oversized files are never fully buffered.
* Returns null when the limit is exceeded.
*/
async function readBodyWithLimit(response: Response, maxBytes: number): Promise<Buffer | null> {
const reader = response.body?.getReader()
if (!reader) {
const buffer = Buffer.from(await response.arrayBuffer())
return buffer.length > maxBytes ? null : buffer
}
const chunks: Uint8Array[] = []
let total = 0
while (true) {
const { done, value } = await reader.read()
if (done) break
total += value.byteLength
if (total > maxBytes) {
await reader.cancel()
return null
}
chunks.push(value)
}
return Buffer.concat(chunks)
}
/**
* Extracts the filename from a Content-Disposition header, if present.
*/
function getFileNameFromContentDisposition(header: string | null): string | null {
if (!header) return null
const utf8Match = header.match(/filename\*=UTF-8''([^;]+)/i)
if (utf8Match) {
try {
return decodeURIComponent(utf8Match[1])
} catch {
return null
}
}
const plainMatch = header.match(/filename="?([^";]+)"?/i)
return plainMatch ? plainMatch[1] : null
}
export const POST = withRouteHandler(async (request: NextRequest) => {
const requestId = generateRequestId()
try {
const authResult = await checkInternalAuth(request, { requireWorkflowId: false })
if (!authResult.success) {
logger.warn(`[${requestId}] Unauthorized Vanta download attempt`, {
error: authResult.error || 'Unauthorized',
})
return NextResponse.json(
{ success: false, error: authResult.error || 'Unauthorized' },
{ status: 401 }
)
}
const parsed = await parseRequest(vantaDownloadContract, request, {})
if (!parsed.success) return parsed.response
const params = parsed.data.body
const mediaUrl = buildVantaUrl(
getVantaBaseUrl(params.region),
`/documents/${encodeURIComponent(params.documentId)}/uploads/${encodeURIComponent(params.uploadedFileId)}/media`
)
logger.info(`[${requestId}] Downloading Vanta document file`, {
documentId: params.documentId,
uploadedFileId: params.uploadedFileId,
})
const response = await fetchVantaWithAuth(
{
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
scope: VANTA_READ_SCOPE,
},
(accessToken) =>
fetch(mediaUrl, {
method: 'GET',
headers: { Authorization: `Bearer ${accessToken}` },
cache: 'no-store',
})
)
if (!response.ok) {
const errorData: unknown = await response.json().catch(() => null)
const message = extractVantaError(errorData, 'Failed to download Vanta document file')
logger.error(`[${requestId}] Vanta download failed`, { status: response.status, message })
return NextResponse.json({ success: false, error: message }, { status: response.status })
}
const contentLength = Number(response.headers.get('content-length'))
if (Number.isFinite(contentLength) && contentLength > MAX_DOWNLOAD_SIZE_BYTES) {
return downloadSizeError(contentLength)
}
const buffer = await readBodyWithLimit(response, MAX_DOWNLOAD_SIZE_BYTES)
if (buffer === null) {
return NextResponse.json(
{ success: false, error: 'File exceeds download limit of 100MB' },
{ status: 400 }
)
}
const mimeType = response.headers.get('content-type') || 'application/octet-stream'
const name =
getFileNameFromContentDisposition(response.headers.get('content-disposition')) ||
`vanta-document-file-${params.uploadedFileId}`
logger.info(`[${requestId}] Vanta download successful`, { name, size: buffer.length })
return NextResponse.json({
success: true,
output: {
file: { name, mimeType, data: buffer.toString('base64'), size: buffer.length },
name,
mimeType,
size: buffer.length,
},
})
} catch (error) {
const message = toError(error).message
logger.error(`[${requestId}] Vanta download failed`, { error: message })
return NextResponse.json({ success: false, error: message }, { status: 500 })
}
})
+423
View File
@@ -0,0 +1,423 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import type { VantaQueryBody } from '@/lib/api/contracts/tools/vanta'
import { vantaQueryContract } from '@/lib/api/contracts/tools/vanta'
import { parseRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { generateRequestId } from '@/lib/core/utils/request'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import {
asVantaRecord,
buildVantaUrl,
extractVantaError,
fetchVantaWithAuth,
getVantaBaseUrl,
getVantaListResults,
normalizeVantaControl,
normalizeVantaControlDetail,
normalizeVantaDocument,
normalizeVantaDocumentDetail,
normalizeVantaFramework,
normalizeVantaFrameworkDetail,
normalizeVantaMonitoredComputer,
normalizeVantaPerson,
normalizeVantaPolicy,
normalizeVantaRiskScenario,
normalizeVantaTest,
normalizeVantaTestEntity,
normalizeVantaUploadedFile,
normalizeVantaVendor,
normalizeVantaVulnerability,
normalizeVantaVulnerabilityRemediation,
normalizeVantaVulnerableAsset,
splitVantaCommaList,
VANTA_READ_SCOPE,
VANTA_WRITE_SCOPE,
} from '@/tools/vanta/utils'
export const dynamic = 'force-dynamic'
const logger = createLogger('VantaQueryAPI')
interface VantaApiRequest {
method: 'GET' | 'POST'
url: string
}
/**
* Maps a validated query operation to the Vanta API request it performs.
*/
function buildVantaApiRequest(baseUrl: string, params: VantaQueryBody): VantaApiRequest {
const id = encodeURIComponent
switch (params.operation) {
case 'vanta_list_frameworks':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, '/frameworks', {
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_get_framework':
return { method: 'GET', url: buildVantaUrl(baseUrl, `/frameworks/${id(params.frameworkId)}`) }
case 'vanta_list_framework_controls':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, `/frameworks/${id(params.frameworkId)}/controls`, {
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_list_controls':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, '/controls', {
frameworkMatchesAny: splitVantaCommaList(params.frameworkMatchesAny),
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_get_control':
return { method: 'GET', url: buildVantaUrl(baseUrl, `/controls/${id(params.controlId)}`) }
case 'vanta_list_control_tests':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, `/controls/${id(params.controlId)}/tests`, {
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_list_control_documents':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, `/controls/${id(params.controlId)}/documents`, {
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_list_tests':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, '/tests', {
statusFilter: params.statusFilter,
frameworkFilter: params.frameworkFilter,
integrationFilter: params.integrationFilter,
controlFilter: params.controlFilter,
ownerFilter: params.ownerFilter,
categoryFilter: params.categoryFilter,
isInRollout: params.isInRollout,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_get_test':
return { method: 'GET', url: buildVantaUrl(baseUrl, `/tests/${id(params.testId)}`) }
case 'vanta_list_test_entities':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, `/tests/${id(params.testId)}/entities`, {
entityStatus: params.entityStatus,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_list_documents':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, '/documents', {
frameworkMatchesAny: splitVantaCommaList(params.frameworkMatchesAny),
statusMatchesAny: splitVantaCommaList(params.statusMatchesAny),
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_get_document':
return { method: 'GET', url: buildVantaUrl(baseUrl, `/documents/${id(params.documentId)}`) }
case 'vanta_list_document_uploads':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, `/documents/${id(params.documentId)}/uploads`, {
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_submit_document':
return {
method: 'POST',
url: buildVantaUrl(baseUrl, `/documents/${id(params.documentId)}/submit`),
}
case 'vanta_list_people':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, '/people', {
emailAndNameFilter: params.emailAndNameFilter,
employmentStatus: params.employmentStatus,
groupIdsMatchesAny: splitVantaCommaList(params.groupIdsMatchesAny),
tasksSummaryStatusMatchesAny: splitVantaCommaList(params.tasksSummaryStatusMatchesAny),
taskTypeMatchesAny: splitVantaCommaList(params.taskTypeMatchesAny),
taskStatusMatchesAny: splitVantaCommaList(params.taskStatusMatchesAny),
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_get_person':
return { method: 'GET', url: buildVantaUrl(baseUrl, `/people/${id(params.personId)}`) }
case 'vanta_list_policies':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, '/policies', {
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_get_policy':
return { method: 'GET', url: buildVantaUrl(baseUrl, `/policies/${id(params.policyId)}`) }
case 'vanta_list_vendors':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, '/vendors', {
name: params.name,
statusMatchesAny: splitVantaCommaList(params.statusMatchesAny),
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_get_vendor':
return { method: 'GET', url: buildVantaUrl(baseUrl, `/vendors/${id(params.vendorId)}`) }
case 'vanta_list_monitored_computers':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, '/monitored-computers', {
complianceStatusFilterMatchesAny: splitVantaCommaList(
params.complianceStatusFilterMatchesAny
),
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_list_vulnerabilities':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, '/vulnerabilities', {
q: params.q,
severity: params.severity,
isFixAvailable: params.isFixAvailable,
isDeactivated: params.isDeactivated,
includeVulnerabilitiesWithoutSlas: params.includeVulnerabilitiesWithoutSlas,
packageIdentifier: params.packageIdentifier,
externalVulnerabilityId: params.externalVulnerabilityId,
integrationId: params.integrationId,
vulnerableAssetId: params.vulnerableAssetId,
slaDeadlineAfterDate: params.slaDeadlineAfterDate,
slaDeadlineBeforeDate: params.slaDeadlineBeforeDate,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_list_vulnerability_remediations':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, '/vulnerability-remediations', {
integrationId: params.integrationId,
severity: params.severity,
isRemediatedOnTime: params.isRemediatedOnTime,
remediatedAfterDate: params.remediatedAfterDate,
remediatedBeforeDate: params.remediatedBeforeDate,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_list_vulnerable_assets':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, '/vulnerable-assets', {
q: params.q,
integrationId: params.integrationId,
assetType: params.assetType,
assetExternalAccountId: params.assetExternalAccountId,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_get_vulnerable_asset':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, `/vulnerable-assets/${id(params.vulnerableAssetId)}`),
}
case 'vanta_list_risk_scenarios':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, '/risk-scenarios', {
searchString: params.searchString,
includeIgnored: params.includeIgnored,
type: params.type,
ownerMatchesAny: splitVantaCommaList(params.ownerMatchesAny),
categoryMatchesAny: splitVantaCommaList(params.categoryMatchesAny),
ciaCategoryMatchesAny: splitVantaCommaList(params.ciaCategoryMatchesAny),
treatmentTypeMatchesAny: splitVantaCommaList(params.treatmentTypeMatchesAny),
inherentScoreGroupMatchesAny: splitVantaCommaList(params.inherentScoreGroupMatchesAny),
residualScoreGroupMatchesAny: splitVantaCommaList(params.residualScoreGroupMatchesAny),
reviewStatusMatchesAny: splitVantaCommaList(params.reviewStatusMatchesAny),
orderBy: params.orderBy,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
}
case 'vanta_get_risk_scenario':
return {
method: 'GET',
url: buildVantaUrl(baseUrl, `/risk-scenarios/${id(params.riskScenarioId)}`),
}
}
}
/**
* Normalizes a successful Vanta API response body into the operation's
* documented output shape.
*/
function buildVantaOutput(params: VantaQueryBody, data: unknown): Record<string, unknown> {
switch (params.operation) {
case 'vanta_list_frameworks': {
const { data: items, pageInfo } = getVantaListResults(data)
return { frameworks: items.map(normalizeVantaFramework), pageInfo }
}
case 'vanta_get_framework':
return { framework: normalizeVantaFrameworkDetail(asVantaRecord(data)) }
case 'vanta_list_framework_controls':
case 'vanta_list_controls': {
const { data: items, pageInfo } = getVantaListResults(data)
return { controls: items.map(normalizeVantaControl), pageInfo }
}
case 'vanta_get_control':
return { control: normalizeVantaControlDetail(asVantaRecord(data)) }
case 'vanta_list_control_tests':
case 'vanta_list_tests': {
const { data: items, pageInfo } = getVantaListResults(data)
return { tests: items.map(normalizeVantaTest), pageInfo }
}
case 'vanta_get_test':
return { test: normalizeVantaTest(asVantaRecord(data)) }
case 'vanta_list_test_entities': {
const { data: items, pageInfo } = getVantaListResults(data)
return { entities: items.map(normalizeVantaTestEntity), pageInfo }
}
case 'vanta_list_control_documents':
case 'vanta_list_documents': {
const { data: items, pageInfo } = getVantaListResults(data)
return { documents: items.map(normalizeVantaDocument), pageInfo }
}
case 'vanta_get_document':
return { document: normalizeVantaDocumentDetail(asVantaRecord(data)) }
case 'vanta_list_document_uploads': {
const { data: items, pageInfo } = getVantaListResults(data)
return { uploads: items.map(normalizeVantaUploadedFile), pageInfo }
}
case 'vanta_submit_document':
return { documentId: params.documentId, submitted: true }
case 'vanta_list_people': {
const { data: items, pageInfo } = getVantaListResults(data)
return { people: items.map(normalizeVantaPerson), pageInfo }
}
case 'vanta_get_person':
return { person: normalizeVantaPerson(asVantaRecord(data)) }
case 'vanta_list_policies': {
const { data: items, pageInfo } = getVantaListResults(data)
return { policies: items.map(normalizeVantaPolicy), pageInfo }
}
case 'vanta_get_policy':
return { policy: normalizeVantaPolicy(asVantaRecord(data)) }
case 'vanta_list_vendors': {
const { data: items, pageInfo } = getVantaListResults(data)
return { vendors: items.map(normalizeVantaVendor), pageInfo }
}
case 'vanta_get_vendor':
return { vendor: normalizeVantaVendor(asVantaRecord(data)) }
case 'vanta_list_monitored_computers': {
const { data: items, pageInfo } = getVantaListResults(data)
return { computers: items.map(normalizeVantaMonitoredComputer), pageInfo }
}
case 'vanta_list_vulnerabilities': {
const { data: items, pageInfo } = getVantaListResults(data)
return { vulnerabilities: items.map(normalizeVantaVulnerability), pageInfo }
}
case 'vanta_list_vulnerability_remediations': {
const { data: items, pageInfo } = getVantaListResults(data)
return { remediations: items.map(normalizeVantaVulnerabilityRemediation), pageInfo }
}
case 'vanta_list_vulnerable_assets': {
const { data: items, pageInfo } = getVantaListResults(data)
return { assets: items.map(normalizeVantaVulnerableAsset), pageInfo }
}
case 'vanta_get_vulnerable_asset':
return { asset: normalizeVantaVulnerableAsset(asVantaRecord(data)) }
case 'vanta_list_risk_scenarios': {
const { data: items, pageInfo } = getVantaListResults(data)
return { riskScenarios: items.map(normalizeVantaRiskScenario), pageInfo }
}
case 'vanta_get_risk_scenario':
return { riskScenario: normalizeVantaRiskScenario(asVantaRecord(data)) }
}
}
export const POST = withRouteHandler(async (request: NextRequest) => {
const requestId = generateRequestId()
try {
const authResult = await checkInternalAuth(request, { requireWorkflowId: false })
if (!authResult.success) {
logger.warn(`[${requestId}] Unauthorized Vanta query attempt`, {
error: authResult.error || 'Unauthorized',
})
return NextResponse.json(
{ success: false, error: authResult.error || 'Unauthorized' },
{ status: 401 }
)
}
const parsed = await parseRequest(vantaQueryContract, request, {})
if (!parsed.success) return parsed.response
const params = parsed.data.body
const baseUrl = getVantaBaseUrl(params.region)
const scope =
params.operation === 'vanta_submit_document' ? VANTA_WRITE_SCOPE : VANTA_READ_SCOPE
logger.info(`[${requestId}] Vanta query request`, { operation: params.operation })
const apiRequest = buildVantaApiRequest(baseUrl, params)
const response = await fetchVantaWithAuth(
{
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
scope,
},
(accessToken) =>
fetch(apiRequest.url, {
method: apiRequest.method,
headers: {
Accept: 'application/json',
Authorization: `Bearer ${accessToken}`,
},
cache: 'no-store',
})
)
if (!response.ok) {
const errorData: unknown = await response.json().catch(() => null)
return NextResponse.json(
{ success: false, error: extractVantaError(errorData, 'Vanta request failed') },
{ status: response.status }
)
}
const data: unknown = response.status === 204 ? null : await response.json().catch(() => null)
return NextResponse.json({ success: true, output: buildVantaOutput(params, data) })
} catch (error) {
const message = toError(error).message
logger.error(`[${requestId}] Vanta query failed`, { error: message })
return NextResponse.json({ success: false, error: message }, { status: 500 })
}
})
@@ -0,0 +1,145 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { vantaUploadContract } from '@/lib/api/contracts/tools/vanta'
import { parseRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { generateRequestId } from '@/lib/core/utils/request'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { processFilesToUserFiles, type RawFileInput } from '@/lib/uploads/utils/file-utils'
import { downloadFileFromStorage } from '@/lib/uploads/utils/file-utils.server'
import { assertToolFileAccess } from '@/app/api/files/authorization'
import {
asVantaRecord,
buildVantaUrl,
extractVantaError,
fetchVantaWithAuth,
getVantaBaseUrl,
normalizeVantaUploadedFile,
VANTA_DOCUMENT_UPLOAD_SCOPE,
} from '@/tools/vanta/utils'
export const dynamic = 'force-dynamic'
const logger = createLogger('VantaUploadAPI')
const MAX_UPLOAD_SIZE_BYTES = 100 * 1024 * 1024
function uploadSizeError(bytes: number): NextResponse {
const sizeMB = (bytes / (1024 * 1024)).toFixed(2)
return NextResponse.json(
{ success: false, error: `File size (${sizeMB}MB) exceeds upload limit of 100MB` },
{ status: 400 }
)
}
export const POST = withRouteHandler(async (request: NextRequest) => {
const requestId = generateRequestId()
try {
const authResult = await checkInternalAuth(request, { requireWorkflowId: false })
if (!authResult.success || !authResult.userId) {
logger.warn(`[${requestId}] Unauthorized Vanta upload attempt`, {
error: authResult.error || 'Missing userId',
})
return NextResponse.json(
{ success: false, error: authResult.error || 'Unauthorized' },
{ status: 401 }
)
}
const parsed = await parseRequest(vantaUploadContract, request, {})
if (!parsed.success) return parsed.response
const params = parsed.data.body
let fileBuffer: Buffer
let fileName: string
let mimeType: string
if (params.file) {
const userFiles = processFilesToUserFiles([params.file as RawFileInput], requestId, logger)
if (userFiles.length === 0) {
return NextResponse.json({ success: false, error: 'Invalid file input' }, { status: 400 })
}
const userFile = userFiles[0]
const denied = await assertToolFileAccess(userFile.key, authResult.userId, requestId, logger)
if (denied) return denied
if (userFile.size > MAX_UPLOAD_SIZE_BYTES) {
return uploadSizeError(userFile.size)
}
fileBuffer = await downloadFileFromStorage(userFile, requestId, logger)
fileName = params.fileName || userFile.name
mimeType = userFile.type || params.mimeType || 'application/octet-stream'
} else if (params.fileContent) {
fileBuffer = Buffer.from(params.fileContent, 'base64')
fileName = params.fileName || 'file'
mimeType = params.mimeType || 'application/octet-stream'
} else {
return NextResponse.json({ success: false, error: 'File is required' }, { status: 400 })
}
if (fileBuffer.length > MAX_UPLOAD_SIZE_BYTES) {
return uploadSizeError(fileBuffer.length)
}
logger.info(`[${requestId}] Uploading file to Vanta document`, {
documentId: params.documentId,
fileName,
size: fileBuffer.length,
})
const uploadUrl = buildVantaUrl(
getVantaBaseUrl(params.region),
`/documents/${encodeURIComponent(params.documentId)}/uploads`
)
const response = await fetchVantaWithAuth(
{
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
scope: VANTA_DOCUMENT_UPLOAD_SCOPE,
},
(accessToken) => {
const formData = new FormData()
formData.append(
'file',
new Blob([new Uint8Array(fileBuffer)], { type: mimeType }),
fileName
)
if (params.description) {
formData.append('description', params.description)
}
if (params.effectiveAtDate) {
formData.append('effectiveAtDate', params.effectiveAtDate)
}
return fetch(uploadUrl, {
method: 'POST',
headers: { Authorization: `Bearer ${accessToken}` },
body: formData,
cache: 'no-store',
})
}
)
const data: unknown = await response.json().catch(() => null)
if (!response.ok) {
const message = extractVantaError(data, 'Failed to upload file to Vanta document')
logger.error(`[${requestId}] Vanta upload failed`, { status: response.status, message })
return NextResponse.json({ success: false, error: message }, { status: response.status })
}
logger.info(`[${requestId}] Vanta upload successful`, { documentId: params.documentId })
return NextResponse.json({
success: true,
output: { upload: normalizeVantaUploadedFile(asVantaRecord(data)) },
})
} catch (error) {
const message = toError(error).message
logger.error(`[${requestId}] Vanta upload failed`, { error: message })
return NextResponse.json({ success: false, error: message }, { status: 500 })
}
})
File diff suppressed because it is too large Load Diff
+3
View File
@@ -290,6 +290,7 @@ import { TwilioSMSBlock, TwilioSMSBlockMeta } from '@/blocks/blocks/twilio'
import { TwilioVoiceBlock, TwilioVoiceBlockMeta } from '@/blocks/blocks/twilio_voice'
import { TypeformBlock, TypeformBlockMeta } from '@/blocks/blocks/typeform'
import { UpstashBlock, UpstashBlockMeta } from '@/blocks/blocks/upstash'
import { VantaBlock, VantaBlockMeta } from '@/blocks/blocks/vanta'
import { VariablesBlock } from '@/blocks/blocks/variables'
import { VercelBlock, VercelBlockMeta } from '@/blocks/blocks/vercel'
import {
@@ -590,6 +591,7 @@ const BLOCK_REGISTRY: Record<string, BlockConfig> = {
twilio_voice: TwilioVoiceBlock,
typeform: TypeformBlock,
upstash: UpstashBlock,
vanta: VantaBlock,
variables: VariablesBlock,
vercel: VercelBlock,
video_generator: VideoGeneratorBlock,
@@ -836,6 +838,7 @@ const BLOCK_META_REGISTRY: Record<string, BlockMeta> = {
twilio_voice: TwilioVoiceBlockMeta,
typeform: TypeformBlockMeta,
upstash: UpstashBlockMeta,
vanta: VantaBlockMeta,
vercel: VercelBlockMeta,
wealthbox: WealthboxBlockMeta,
webflow: WebflowBlockMeta,
+51
View File
@@ -7555,6 +7555,57 @@ export function OnePasswordIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function VantaIcon(props: SVGProps<SVGSVGElement>) {
const id = useId()
const clipId = `vanta_clip_${id}`
const maskId = `vanta_mask_${id}`
return (
<svg {...props} viewBox='0 0 512 512' fill='none' xmlns='http://www.w3.org/2000/svg'>
<g clipPath={`url(#${clipId})`}>
<circle cx='256' cy='256' r='256' fill='#AC55FF' />
<mask
id={maskId}
style={{ maskType: 'alpha' }}
maskUnits='userSpaceOnUse'
x='0'
y='0'
width='512'
height='512'
>
<circle cx='256' cy='256' r='256' fill='#AC55FF' />
</mask>
<g mask={`url(#${maskId})`}>
<path
d='M269.699 530.451C360.294 530.451 407.136 502.376 421.276 474.223C422.09 472.599 420.53 470.761 418.81 471.332C402.863 476.607 390.96 466.808 389.625 455.498C389.625 455.498 385.167 407.538 369.22 402.858C370.165 400.913 374.01 385.586 362.126 371.424C365.376 361.406 362.691 354.81 360.26 349.823C363.222 346.191 365.498 341.506 366.482 336.943C366.726 335.861 366.721 334.905 367.598 333.887C373.201 329.231 379.384 325.389 383.145 318.574C389.923 306.26 385.382 292.196 377.167 281.817C376.334 280.671 375.681 280.12 375.622 277.176C375.642 272.145 374.731 266.968 372.027 262.717C370.648 260.557 368.84 258.69 366.945 256.959C359.052 249.598 349.609 244.163 340.542 238.293C339.295 237.494 337.843 236.431 337.302 234.978C334.447 224.351 327.065 216.131 317.886 213.894C317.691 206.776 310.187 195.983 298.835 195.983C295.371 195.983 292.506 197.865 290.718 194.623C286.566 186.75 278.293 185.287 273.976 185.088C273.25 185.053 273.046 184.078 273.704 183.766C275.087 183.103 277.182 182.187 280.291 180.988C295.882 173.524 289.431 131.009 283.049 108.575C280.062 100.199 272.49 76.3803 253.942 74.8057C252.665 74.6985 251.359 74.7277 250.126 75.0836C246.555 76.1122 243.909 78.9738 242.048 82.9372C235.914 95.2709 234.379 128.562 232.123 142.797C228.922 163.096 226.023 184.873 215.913 193.799C211.606 182.436 205.374 177.171 201.969 177.37C199.001 178.068 203.016 183.835 201.306 192.341C200.117 197.236 197.408 201.804 192.794 201.804C179.273 201.804 167.098 134.173 163.463 93.5451C163.365 92.4824 163.263 91.4245 163.068 90.3715C161.285 80.5533 156.12 74.757 150.663 74.757C147.896 74.757 137.961 73.7478 126.584 91.639C118.764 105.591 113.795 120.177 113.312 147.341C113.322 174.714 125.532 193.019 130.477 202.023C150.688 235.266 153.387 246.741 149.562 267.007C145.674 286.653 157.533 297.7 157.533 297.7C155.857 300.298 153.645 307.259 153.134 314.899C152.807 319.764 153.801 328.49 156.125 333.891C151.024 344.885 151.146 353.621 151.146 359.129C151.146 371.892 145.577 377.089 138.336 379.36C140.29 386.322 153.275 390.051 160.788 382.612C158.571 404.476 154.473 424.171 148.753 448.546C145.197 465.233 145.796 474.583 148.49 482.5C149.703 486.069 151.604 489.355 153.928 492.319C181.637 527.667 233.629 530.451 269.699 530.451ZM269.655 482.739C259.671 481.116 250.331 476.139 243.515 468.602C225.351 474.618 206.466 459.33 212.205 439.147C213.121 436.505 217.058 437.475 216.668 440.229C216.103 443.783 216.756 447.42 218.281 450.55C222.34 459.827 234.438 462.323 241.853 455.859C244.596 453.441 248.562 454.362 250.424 457.36C266.663 479.4 300.355 475.266 311.654 450.525C313.311 447.069 314.392 443.408 315.021 439.615C315.464 436.924 319.498 437.178 319.61 439.898C320.522 466.525 295.6 486.902 269.65 482.744L269.655 482.739Z'
fill='#240642'
/>
<path
d='M371.525 292.61C369.79 292.61 367.924 295.033 367.446 298.806C366.414 304.125 366.769 313.958 362.028 313.958C358.749 313.958 358.452 307.367 352.942 301.293C347.226 295.399 339.031 294.799 333.774 290.558C330.851 288.53 329.111 286.034 329.301 281.749C329.301 281.749 329.925 274.924 339.134 276.172C343.514 276.63 350.613 277.698 355.007 278.2C362.857 279.087 364.772 273.247 365.005 271.263C365.507 266.612 360.572 262.761 357.448 260.05C353.502 256.613 349.2 253.527 344.742 250.758C343.933 250.256 343.109 249.735 342.286 249.208C331.104 242.076 311.225 230.137 300.077 243.768C296.082 249.12 294.347 255.287 293.095 260.396C290.781 269.747 285.923 273.354 282.474 279.058C276.992 288.111 273.226 298.392 272.938 308.971C272.89 324.244 282.332 339.205 297.397 348.555C309.9 355.117 316.317 355.117 321.325 353.777C322.241 353.465 324.249 352.065 322.87 349.75C322.621 349.257 321.925 348.175 321.501 347.473C320.073 344.846 322.027 342.442 324.921 344.69C326.826 346.181 328.77 347.673 331.011 348.585C332.897 349.35 335.046 349.652 336.995 349.136C336.995 349.136 336.995 349.136 336.999 349.136C339.28 348.39 340.434 346.893 340.566 344.982C340.698 342.701 339.665 340.936 337.954 339.995C335.353 338.728 329.594 335.559 327.162 333.765C324.419 331.844 321.486 328.973 320.468 327.89C317.15 324.361 316.2 320.914 314.134 320.914C313.788 320.934 313.452 321.129 313.218 321.392C311.922 322.777 311.912 325.058 311.849 326.36C311.805 327.32 311.956 328.783 310.611 328.783C307.278 328.783 307.288 321.831 307.293 319.944C307.293 317.36 308.238 310.657 312.229 310.657C313.461 310.657 315.137 312.31 315.795 312.958C324.59 322.723 334.812 330.318 347.762 330.318C357.677 330.318 365.96 324.717 371.169 319.466C375.247 315.371 377.932 310.243 378.112 304.944C378.224 301.585 376.611 292.615 371.525 292.615V292.61ZM314.714 301.697C313.51 302.365 312.073 301.536 310.762 301.107C308.126 300.24 305.135 301.117 302.962 302.843C301.471 304.032 300.331 305.587 299.405 307.264C298.396 309.097 298.206 311.515 296.038 311.515C294.255 311.515 293.358 309.044 293.163 308.025C292.116 302.492 294.786 296.335 299.751 293.683C304.716 291.031 311.6 292.435 314.811 297.056C315.308 297.773 315.732 298.582 315.79 299.455C315.849 300.327 315.483 301.273 314.718 301.697H314.714Z'
fill='white'
/>
<path
d='M249.386 238.371C244.645 238.44 240.046 240.477 236.694 243.919C234.808 245.854 230.608 252.114 231.017 261.761C230.949 263.18 229.083 263.687 228.333 262.478C225.307 257.057 225.132 251.402 226.306 247.229C228.912 238.795 236.274 231.785 246.224 231.785C259.277 231.785 262.551 240.326 263.204 242.973C263.516 244.07 262.161 244.879 261.328 244.099C259.165 242.086 255.827 238.371 249.376 238.371H249.386Z'
fill='white'
/>
<path
d='M250.453 257.471C247.334 257.749 244.874 255.736 244.596 252.621C244.323 249.559 246.384 247.034 249.503 246.756C252.621 246.478 255.15 248.599 255.422 251.66C255.7 254.78 253.571 257.193 250.458 257.471H250.453Z'
fill='white'
/>
<path
d='M148.261 199.172C143.662 199.172 128.582 174.699 128.582 140.145C128.582 124.638 132.563 108.087 139.798 108.087C144.251 108.087 145.26 117.574 145.465 120.387C147.808 150.066 143.983 170.224 149.567 197.109C149.937 198.684 148.987 199.176 148.261 199.176V199.172Z'
fill='white'
/>
</g>
</g>
<defs>
<clipPath id={clipId}>
<rect width='512' height='512' fill='white' />
</clipPath>
</defs>
</svg>
)
}
export function VercelIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
@@ -30,5 +30,6 @@ export * from './shared'
export * from './stagehand'
export * from './thinking'
export * from './typeform'
export * from './vanta'
export * from './workday'
export * from './zoom'
+740
View File
@@ -0,0 +1,740 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { FileInputSchema } from '@/lib/uploads/utils/file-schemas'
const nullableString = z.string().nullable()
const nullableNumber = z.number().nullable()
const nullableBoolean = z.boolean().nullable()
const vantaPageInfoSchema = z
.object({
startCursor: nullableString,
endCursor: nullableString,
hasNextPage: z.boolean(),
hasPreviousPage: z.boolean(),
})
.nullable()
const vantaOwnerSchema = z
.object({
id: nullableString,
displayName: nullableString,
emailAddress: nullableString,
})
.nullable()
const vantaCustomFieldsSchema = z.array(
z.object({
label: nullableString,
value: z.union([z.string(), z.array(z.string())]).nullable(),
})
)
const vantaFrameworkSchema = z.object({
id: nullableString,
displayName: nullableString,
shorthandName: nullableString,
description: nullableString,
numControlsCompleted: nullableNumber,
numControlsTotal: nullableNumber,
numDocumentsPassing: nullableNumber,
numDocumentsTotal: nullableNumber,
numTestsPassing: nullableNumber,
numTestsTotal: nullableNumber,
})
const vantaFrameworkDetailSchema = vantaFrameworkSchema.extend({
requirementCategories: z.array(
z.object({
id: nullableString,
name: nullableString,
shorthand: nullableString,
requirements: z.array(
z.object({
id: nullableString,
name: nullableString,
shorthand: nullableString,
description: nullableString,
controls: z.array(
z.object({
id: nullableString,
externalId: nullableString,
name: nullableString,
description: nullableString,
})
),
})
),
})
),
})
const vantaControlSchema = z.object({
id: nullableString,
externalId: nullableString,
name: nullableString,
description: nullableString,
source: nullableString,
domains: z.array(z.string()),
owner: vantaOwnerSchema,
role: nullableString,
customFields: vantaCustomFieldsSchema,
creationDate: nullableString,
modificationDate: nullableString,
})
const vantaControlDetailSchema = vantaControlSchema.extend({
note: nullableString,
status: nullableString,
numDocumentsPassing: nullableNumber,
numDocumentsTotal: nullableNumber,
numTestsPassing: nullableNumber,
numTestsTotal: nullableNumber,
})
const vantaTestSchema = z.object({
id: nullableString,
name: nullableString,
description: nullableString,
failureDescription: nullableString,
remediationDescription: nullableString,
category: nullableString,
status: nullableString,
integrations: z.array(z.string()),
lastTestRunDate: nullableString,
latestFlipDate: nullableString,
version: z.object({ major: nullableNumber, minor: nullableNumber }).nullable(),
deactivatedStatusInfo: z
.object({
isDeactivated: nullableBoolean,
deactivatedReason: nullableString,
lastUpdatedDate: nullableString,
})
.nullable(),
remediationStatusInfo: z
.object({
status: nullableString,
soonestRemediateByDate: nullableString,
itemCount: nullableNumber,
})
.nullable(),
owner: vantaOwnerSchema,
})
const vantaTestEntitySchema = z.object({
id: nullableString,
entityStatus: nullableString,
displayName: nullableString,
responseType: nullableString,
deactivatedReason: nullableString,
createdDate: nullableString,
lastUpdatedDate: nullableString,
})
const vantaDocumentSchema = z.object({
id: nullableString,
title: nullableString,
description: nullableString,
category: nullableString,
ownerId: nullableString,
isSensitive: nullableBoolean,
uploadStatus: nullableString,
uploadStatusDate: nullableString,
url: nullableString,
})
const vantaDocumentDetailSchema = vantaDocumentSchema.extend({
note: nullableString,
nextRenewalDate: nullableString,
renewalCadence: nullableString,
reminderWindow: nullableString,
subscribers: z.array(z.string()),
deactivatedStatus: z
.object({
isDeactivated: nullableBoolean,
reason: nullableString,
creationDate: nullableString,
expiration: nullableString,
})
.nullable(),
})
const vantaUploadedFileSchema = z.object({
id: nullableString,
fileName: nullableString,
title: nullableString,
description: nullableString,
mimeType: nullableString,
uploadedBy: z.object({ id: nullableString, type: nullableString }).nullable(),
creationDate: nullableString,
updatedDate: nullableString,
deletionDate: nullableString,
effectiveDate: nullableString,
url: nullableString,
})
const vantaPersonSchema = z.object({
id: nullableString,
userId: nullableString,
emailAddress: nullableString,
name: z
.object({ first: nullableString, last: nullableString, display: nullableString })
.nullable(),
employment: z
.object({
status: nullableString,
startDate: nullableString,
endDate: nullableString,
jobTitle: nullableString,
})
.nullable(),
leaveInfo: z
.object({ status: nullableString, startDate: nullableString, endDate: nullableString })
.nullable(),
groupIds: z.array(z.string()),
tasksSummary: z
.object({
status: nullableString,
dueDate: nullableString,
completionDate: nullableString,
})
.nullable(),
})
const vantaPolicySchema = z.object({
id: nullableString,
name: nullableString,
description: nullableString,
status: nullableString,
approvedAtDate: nullableString,
latestVersionStatus: nullableString,
latestApprovedVersion: z
.object({
versionId: nullableString,
documents: z.array(
z.object({ language: nullableString, slugId: nullableString, url: nullableString })
),
})
.nullable(),
})
const vantaVendorSchema = z.object({
id: nullableString,
name: nullableString,
status: nullableString,
websiteUrl: nullableString,
category: nullableString,
servicesProvided: nullableString,
additionalNotes: nullableString,
accountManagerName: nullableString,
accountManagerEmail: nullableString,
securityOwnerUserId: nullableString,
businessOwnerUserId: nullableString,
inherentRiskLevel: nullableString,
residualRiskLevel: nullableString,
isRiskAutoScored: nullableBoolean,
isVisibleToAuditors: nullableBoolean,
riskAttributeIds: z.array(z.string()),
vendorHeadquarters: nullableString,
contractStartDate: nullableString,
contractRenewalDate: nullableString,
contractTerminationDate: nullableString,
contractAmount: z.object({ amount: nullableNumber, currency: nullableString }).nullable(),
nextSecurityReviewDueDate: nullableString,
lastSecurityReviewCompletionDate: nullableString,
authDetails: z
.object({
method: nullableString,
passwordMFA: nullableBoolean,
passwordMinimumLength: nullableNumber,
passwordRequiresNumber: nullableBoolean,
passwordRequiresSymbol: nullableBoolean,
})
.nullable(),
customFields: vantaCustomFieldsSchema,
latestDecision: z.object({ status: nullableString, lastUpdatedAt: nullableString }).nullable(),
linkedTaskTrackerTaskProcurementRequest: z
.object({ url: nullableString, service: nullableString })
.nullable(),
})
const vantaMonitoredComputerSchema = z.object({
id: nullableString,
integrationId: nullableString,
lastCheckDate: nullableString,
screenlock: nullableString,
diskEncryption: nullableString,
passwordManager: nullableString,
antivirusInstallation: nullableString,
operatingSystem: z.object({ type: nullableString, version: nullableString }).nullable(),
owner: vantaOwnerSchema,
serialNumber: nullableString,
udid: nullableString,
})
const vantaVulnerabilitySchema = z.object({
id: nullableString,
name: nullableString,
description: nullableString,
severity: nullableString,
vulnerabilityType: nullableString,
integrationId: nullableString,
targetId: nullableString,
packageIdentifier: nullableString,
cvssSeverityScore: nullableNumber,
scannerScore: nullableNumber,
isFixable: nullableBoolean,
fixedVersion: nullableString,
remediateByDate: nullableString,
firstDetectedDate: nullableString,
sourceDetectedDate: nullableString,
lastDetectedDate: nullableString,
scanSource: nullableString,
externalURL: nullableString,
relatedVulns: z.array(z.string()),
relatedUrls: z.array(z.string()),
deactivateMetadata: z
.object({
isVulnDeactivatedIndefinitely: nullableBoolean,
deactivatedUntilDate: nullableString,
deactivationReason: nullableString,
deactivatedOnDate: nullableString,
deactivatedBy: nullableString,
})
.nullable(),
})
const vantaVulnerabilityRemediationSchema = z.object({
id: nullableString,
vulnerabilityId: nullableString,
vulnerableAssetId: nullableString,
severity: nullableString,
detectedDate: nullableString,
slaDeadlineDate: nullableString,
remediationDate: nullableString,
})
const vantaVulnerableAssetSchema = z.object({
id: nullableString,
name: nullableString,
assetType: nullableString,
hasBeenScanned: nullableBoolean,
imageScanTag: nullableString,
scanners: z.array(
z.object({
resourceId: nullableString,
integrationId: nullableString,
targetId: nullableString,
imageDigest: nullableString,
imagePushedAtDate: nullableString,
imageTags: z.array(z.string()),
assetTags: z.array(z.object({ key: nullableString, value: nullableString })),
parentAccountOrOrganization: nullableString,
biosUuid: nullableString,
ipv4s: z.array(z.string()),
ipv6s: z.array(z.string()),
macAddresses: z.array(z.string()),
hostnames: z.array(z.string()),
fqdns: z.array(z.string()),
operatingSystems: z.array(z.string()),
})
),
})
const vantaRiskScenarioSchema = z.object({
riskId: nullableString,
description: nullableString,
likelihood: nullableNumber,
impact: nullableNumber,
residualLikelihood: nullableNumber,
residualImpact: nullableNumber,
categories: z.array(z.string()),
ciaCategories: z.array(z.string()),
treatment: nullableString,
owner: nullableString,
note: nullableString,
riskRegister: nullableString,
customFields: vantaCustomFieldsSchema,
isArchived: nullableBoolean,
reviewStatus: nullableString,
requiredApprovers: z.array(z.string()),
type: nullableString,
identificationDate: nullableString,
})
const VANTA_REGIONS = ['us', 'gov'] as const
const vantaBaseBodySchema = z.object({
clientId: z.string().min(1, 'Client ID is required'),
clientSecret: z.string().min(1, 'Client secret is required'),
region: z.enum(VANTA_REGIONS).optional(),
})
const vantaPaginationBodySchema = z.object({
pageSize: z
.number()
.int()
.min(1, 'pageSize must be at least 1')
.max(100, 'pageSize must be at most 100')
.optional(),
pageCursor: z.string().min(1, 'pageCursor cannot be empty').optional(),
})
const vantaListBaseBodySchema = vantaBaseBodySchema.extend(vantaPaginationBodySchema.shape)
const requiredId = (label: string) => z.string().trim().min(1, `${label} is required`)
const listFrameworksSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_frameworks'),
})
const getFrameworkSchema = vantaBaseBodySchema.extend({
operation: z.literal('vanta_get_framework'),
frameworkId: requiredId('Framework ID'),
})
const listFrameworkControlsSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_framework_controls'),
frameworkId: requiredId('Framework ID'),
})
const listControlsSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_controls'),
frameworkMatchesAny: z.string().optional(),
})
const getControlSchema = vantaBaseBodySchema.extend({
operation: z.literal('vanta_get_control'),
controlId: requiredId('Control ID'),
})
const listControlTestsSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_control_tests'),
controlId: requiredId('Control ID'),
})
const listControlDocumentsSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_control_documents'),
controlId: requiredId('Control ID'),
})
const listTestsSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_tests'),
statusFilter: z
.enum(['OK', 'DEACTIVATED', 'NEEDS_ATTENTION', 'IN_PROGRESS', 'INVALID', 'NOT_APPLICABLE'])
.optional(),
frameworkFilter: z.string().optional(),
integrationFilter: z.string().optional(),
controlFilter: z.string().optional(),
ownerFilter: z.string().optional(),
categoryFilter: z
.enum([
'ACCOUNTS_ACCESS',
'ACCOUNT_SECURITY',
'ACCOUNT_SETUP',
'COMPUTERS',
'CUSTOM',
'DATA_STORAGE',
'EMPLOYEES',
'INFRASTRUCTURE',
'IT',
'LOGGING',
'MONITORING_ALERTS',
'PEOPLE',
'POLICIES',
'RISK_ANALYSIS',
'SECURITY_ALERT_MANAGEMENT',
'SOFTWARE_DEVELOPMENT',
'VENDORS',
'VULNERABILITY_MANAGEMENT',
])
.optional(),
isInRollout: z.boolean().optional(),
})
const getTestSchema = vantaBaseBodySchema.extend({
operation: z.literal('vanta_get_test'),
testId: requiredId('Test ID'),
})
const listTestEntitiesSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_test_entities'),
testId: requiredId('Test ID'),
entityStatus: z.enum(['FAILING', 'DEACTIVATED']).optional(),
})
const listDocumentsSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_documents'),
frameworkMatchesAny: z.string().optional(),
statusMatchesAny: z.string().optional(),
})
const getDocumentSchema = vantaBaseBodySchema.extend({
operation: z.literal('vanta_get_document'),
documentId: requiredId('Document ID'),
})
const listDocumentUploadsSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_document_uploads'),
documentId: requiredId('Document ID'),
})
const submitDocumentSchema = vantaBaseBodySchema.extend({
operation: z.literal('vanta_submit_document'),
documentId: requiredId('Document ID'),
})
const listPeopleSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_people'),
emailAndNameFilter: z.string().optional(),
employmentStatus: z.enum(['UPCOMING', 'CURRENT', 'ON_LEAVE', 'INACTIVE', 'FORMER']).optional(),
groupIdsMatchesAny: z.string().optional(),
tasksSummaryStatusMatchesAny: z.string().optional(),
taskTypeMatchesAny: z.string().optional(),
taskStatusMatchesAny: z.string().optional(),
})
const getPersonSchema = vantaBaseBodySchema.extend({
operation: z.literal('vanta_get_person'),
personId: requiredId('Person ID'),
})
const listPoliciesSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_policies'),
})
const getPolicySchema = vantaBaseBodySchema.extend({
operation: z.literal('vanta_get_policy'),
policyId: requiredId('Policy ID'),
})
const listVendorsSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_vendors'),
name: z.string().optional(),
statusMatchesAny: z.string().optional(),
})
const getVendorSchema = vantaBaseBodySchema.extend({
operation: z.literal('vanta_get_vendor'),
vendorId: requiredId('Vendor ID'),
})
const listMonitoredComputersSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_monitored_computers'),
complianceStatusFilterMatchesAny: z.string().optional(),
})
const listVulnerabilitiesSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_vulnerabilities'),
q: z.string().optional(),
severity: z.enum(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']).optional(),
isFixAvailable: z.boolean().optional(),
isDeactivated: z.boolean().optional(),
includeVulnerabilitiesWithoutSlas: z.boolean().optional(),
packageIdentifier: z.string().optional(),
externalVulnerabilityId: z.string().optional(),
integrationId: z.string().optional(),
vulnerableAssetId: z.string().optional(),
slaDeadlineAfterDate: z.string().optional(),
slaDeadlineBeforeDate: z.string().optional(),
})
const listVulnerabilityRemediationsSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_vulnerability_remediations'),
integrationId: z.string().optional(),
severity: z.enum(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']).optional(),
isRemediatedOnTime: z.boolean().optional(),
remediatedAfterDate: z.string().optional(),
remediatedBeforeDate: z.string().optional(),
})
const listVulnerableAssetsSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_vulnerable_assets'),
q: z.string().optional(),
integrationId: z.string().optional(),
assetType: z
.enum([
'SERVER',
'SERVERLESS_FUNCTION',
'CONTAINER',
'CONTAINER_REPOSITORY',
'CONTAINER_REPOSITORY_IMAGE',
'CODE_REPOSITORY',
'MANIFEST_FILE',
'WORKSTATION',
'OTHER',
])
.optional(),
assetExternalAccountId: z.string().optional(),
})
const getVulnerableAssetSchema = vantaBaseBodySchema.extend({
operation: z.literal('vanta_get_vulnerable_asset'),
vulnerableAssetId: requiredId('Vulnerable asset ID'),
})
const listRiskScenariosSchema = vantaListBaseBodySchema.extend({
operation: z.literal('vanta_list_risk_scenarios'),
searchString: z.string().optional(),
includeIgnored: z.boolean().optional(),
type: z.enum(['Risk Scenario', 'Enterprise Risk']).optional(),
ownerMatchesAny: z.string().optional(),
categoryMatchesAny: z.string().optional(),
ciaCategoryMatchesAny: z.string().optional(),
treatmentTypeMatchesAny: z.string().optional(),
inherentScoreGroupMatchesAny: z.string().optional(),
residualScoreGroupMatchesAny: z.string().optional(),
reviewStatusMatchesAny: z.string().optional(),
orderBy: z.enum(['description', 'createdAt']).optional(),
})
const getRiskScenarioSchema = vantaBaseBodySchema.extend({
operation: z.literal('vanta_get_risk_scenario'),
riskScenarioId: requiredId('Risk scenario ID'),
})
export const vantaQueryBodySchema = z.discriminatedUnion('operation', [
listFrameworksSchema,
getFrameworkSchema,
listFrameworkControlsSchema,
listControlsSchema,
getControlSchema,
listControlTestsSchema,
listControlDocumentsSchema,
listTestsSchema,
getTestSchema,
listTestEntitiesSchema,
listDocumentsSchema,
getDocumentSchema,
listDocumentUploadsSchema,
submitDocumentSchema,
listPeopleSchema,
getPersonSchema,
listPoliciesSchema,
getPolicySchema,
listVendorsSchema,
getVendorSchema,
listMonitoredComputersSchema,
listVulnerabilitiesSchema,
listVulnerabilityRemediationsSchema,
listVulnerableAssetsSchema,
getVulnerableAssetSchema,
listRiskScenariosSchema,
getRiskScenarioSchema,
])
const vantaQueryOutputSchema = z.union([
z.object({ frameworks: z.array(vantaFrameworkSchema), pageInfo: vantaPageInfoSchema }),
z.object({ framework: vantaFrameworkDetailSchema }),
z.object({ controls: z.array(vantaControlSchema), pageInfo: vantaPageInfoSchema }),
z.object({ control: vantaControlDetailSchema }),
z.object({ tests: z.array(vantaTestSchema), pageInfo: vantaPageInfoSchema }),
z.object({ test: vantaTestSchema }),
z.object({ entities: z.array(vantaTestEntitySchema), pageInfo: vantaPageInfoSchema }),
z.object({ documents: z.array(vantaDocumentSchema), pageInfo: vantaPageInfoSchema }),
z.object({ document: vantaDocumentDetailSchema }),
z.object({ uploads: z.array(vantaUploadedFileSchema), pageInfo: vantaPageInfoSchema }),
z.object({ documentId: z.string(), submitted: z.boolean() }),
z.object({ people: z.array(vantaPersonSchema), pageInfo: vantaPageInfoSchema }),
z.object({ person: vantaPersonSchema }),
z.object({ policies: z.array(vantaPolicySchema), pageInfo: vantaPageInfoSchema }),
z.object({ policy: vantaPolicySchema }),
z.object({ vendors: z.array(vantaVendorSchema), pageInfo: vantaPageInfoSchema }),
z.object({ vendor: vantaVendorSchema }),
z.object({ computers: z.array(vantaMonitoredComputerSchema), pageInfo: vantaPageInfoSchema }),
z.object({
vulnerabilities: z.array(vantaVulnerabilitySchema),
pageInfo: vantaPageInfoSchema,
}),
z.object({
remediations: z.array(vantaVulnerabilityRemediationSchema),
pageInfo: vantaPageInfoSchema,
}),
z.object({ assets: z.array(vantaVulnerableAssetSchema), pageInfo: vantaPageInfoSchema }),
z.object({ asset: vantaVulnerableAssetSchema }),
z.object({ riskScenarios: z.array(vantaRiskScenarioSchema), pageInfo: vantaPageInfoSchema }),
z.object({ riskScenario: vantaRiskScenarioSchema }),
])
const vantaQueryResponseSchema = z.object({
success: z.literal(true),
output: vantaQueryOutputSchema,
})
export const vantaQueryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/vanta/query',
body: vantaQueryBodySchema,
response: { mode: 'json', schema: vantaQueryResponseSchema },
})
const VANTA_MAX_UPLOAD_BYTES = 100 * 1024 * 1024
/** Base64 length of the largest allowed upload (4 chars per 3 bytes). */
const VANTA_MAX_UPLOAD_BASE64_LENGTH = Math.ceil(VANTA_MAX_UPLOAD_BYTES / 3) * 4
export const vantaUploadBodySchema = vantaBaseBodySchema.extend({
documentId: requiredId('Document ID'),
file: FileInputSchema.optional().nullable(),
fileContent: z
.string()
.max(VANTA_MAX_UPLOAD_BASE64_LENGTH, 'fileContent exceeds the 100MB upload limit')
.nullish(),
fileName: z.string().nullish(),
mimeType: z.string().nullish(),
description: z.string().nullish(),
effectiveAtDate: z.string().nullish(),
})
const vantaUploadResponseSchema = z.object({
success: z.literal(true),
output: z.object({ upload: vantaUploadedFileSchema }),
})
export const vantaUploadContract = defineRouteContract({
method: 'POST',
path: '/api/tools/vanta/upload',
body: vantaUploadBodySchema,
response: { mode: 'json', schema: vantaUploadResponseSchema },
})
export const vantaDownloadBodySchema = vantaBaseBodySchema.extend({
documentId: requiredId('Document ID'),
uploadedFileId: requiredId('Uploaded file ID'),
})
const vantaDownloadResponseSchema = z.object({
success: z.literal(true),
output: z.object({
file: z.object({
name: z.string(),
mimeType: z.string(),
data: z.string(),
size: z.number(),
}),
name: z.string(),
mimeType: z.string(),
size: z.number(),
}),
})
export const vantaDownloadContract = defineRouteContract({
method: 'POST',
path: '/api/tools/vanta/download',
body: vantaDownloadBodySchema,
response: { mode: 'json', schema: vantaDownloadResponseSchema },
})
export type VantaQueryBody = ContractBody<typeof vantaQueryContract>
export type VantaQueryBodyInput = ContractBodyInput<typeof vantaQueryContract>
export type VantaQueryResponse = ContractJsonResponse<typeof vantaQueryContract>
export type VantaUploadBody = ContractBody<typeof vantaUploadContract>
export type VantaUploadBodyInput = ContractBodyInput<typeof vantaUploadContract>
export type VantaUploadResponse = ContractJsonResponse<typeof vantaUploadContract>
export type VantaDownloadBody = ContractBody<typeof vantaDownloadContract>
export type VantaDownloadBodyInput = ContractBodyInput<typeof vantaDownloadContract>
export type VantaDownloadResponse = ContractJsonResponse<typeof vantaDownloadContract>
@@ -206,6 +206,7 @@ import {
TwilioIcon,
TypeformIcon,
UpstashIcon,
VantaIcon,
VercelIcon,
WealthboxIcon,
WebflowIcon,
@@ -430,6 +431,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
twilio_voice: TwilioIcon,
typeform: TypeformIcon,
upstash: UpstashIcon,
vanta: VantaIcon,
vercel: VercelIcon,
wealthbox: WealthboxIcon,
webflow: WebflowIcon,
+135
View File
@@ -15666,6 +15666,141 @@
"integrationType": "databases",
"tags": ["cloud"]
},
{
"type": "vanta",
"slug": "vanta",
"name": "Vanta",
"description": "Query compliance status and manage evidence in Vanta",
"longDescription": "Integrate Vanta into the workflow. Monitor compliance frameworks, controls, and automated tests; find failing test entities; manage evidence documents including file upload, download, and submission; and track people, policies, vendors, monitored computers, vulnerabilities, and risk scenarios. Requires Vanta OAuth client credentials.",
"bgColor": "#F8F4F3",
"iconName": "VantaIcon",
"docsUrl": "https://docs.sim.ai/integrations/vanta",
"operations": [
{
"name": "List Frameworks",
"description": "List the compliance frameworks (e.g., SOC 2, ISO 27001) available in a Vanta account with completion counts"
},
{
"name": "Get Framework",
"description": "Get a Vanta compliance framework by ID, including its requirement categories and mapped controls"
},
{
"name": "List Framework Controls",
"description": "List the controls that belong to a specific Vanta compliance framework"
},
{
"name": "List Controls",
"description": "List the security controls in a Vanta account, optionally filtered by framework"
},
{
"name": "Get Control",
"description": "Get a Vanta security control by ID, including its status and evidence pass/fail counts"
},
{
"name": "List Control Tests",
"description": "List the automated tests mapped to a specific Vanta control"
},
{
"name": "List Control Documents",
"description": "List the evidence documents mapped to a specific Vanta control"
},
{
"name": "List Tests",
"description": "List the automated compliance tests in a Vanta account, with filters for status, framework, integration, control, owner, and category"
},
{
"name": "Get Test",
"description": "Get a Vanta automated compliance test by ID, including its status and remediation info"
},
{
"name": "List Test Entities",
"description": "List the failing or deactivated resource entities for a specific Vanta test, useful for finding exactly which resources need remediation"
},
{
"name": "List Documents",
"description": "List the evidence documents in a Vanta account, optionally filtered by framework or document status"
},
{
"name": "Get Document",
"description": "Get a Vanta evidence document by ID, including its renewal schedule and deactivation status"
},
{
"name": "List Document Uploads",
"description": "List the files uploaded to a specific Vanta evidence document"
},
{
"name": "Upload Document File",
"description": "Upload an evidence file to a Vanta document. Requires credentials with the vanta-api.documents:upload scope."
},
{
"name": "Download Document File",
"description": "Download a file previously uploaded to a Vanta evidence document and store it in execution files"
},
{
"name": "Submit Document",
"description": "Submit a Vanta document collection for review so uploaded evidence becomes visible to auditors. Requires credentials with write access."
},
{
"name": "List People",
"description": "List the people tracked in a Vanta account with employment status, group membership, and security task completion"
},
{
"name": "Get Person",
"description": "Get a person tracked in Vanta by ID, including employment, leave, and security task status"
},
{
"name": "List Policies",
"description": "List the security policies in a Vanta account with approval status and version info"
},
{
"name": "Get Policy",
"description": "Get a Vanta security policy by ID, including its approval status and latest approved version documents"
},
{
"name": "List Vendors",
"description": "List the vendors tracked in a Vanta account with risk levels, contract dates, and security review schedules"
},
{
"name": "Get Vendor",
"description": "Get a Vanta vendor by ID, including risk levels, contract details, and authentication info"
},
{
"name": "List Monitored Computers",
"description": "List the monitored computers in a Vanta account with screenlock, disk encryption, password manager, and antivirus check outcomes"
},
{
"name": "List Vulnerabilities",
"description": "List the vulnerabilities detected across a Vanta account with filters for severity, fixability, SLA deadlines, package, and integration"
},
{
"name": "List Vulnerability Remediations",
"description": "List remediated vulnerabilities in a Vanta account with detection, SLA deadline, and remediation dates"
},
{
"name": "List Vulnerable Assets",
"description": "List the assets associated with vulnerabilities in a Vanta account (servers, repositories, workstations, and more)"
},
{
"name": "Get Vulnerable Asset",
"description": "Get a vulnerable asset in Vanta by ID, including the scanners reporting it and per-scanner asset details"
},
{
"name": "List Risk Scenarios",
"description": "List the risk scenarios in a Vanta risk register with likelihood/impact scores, treatment decisions, and review status"
},
{
"name": "Get Risk Scenario",
"description": "Get a Vanta risk scenario by ID, including its scores, treatment decision, and review status"
}
],
"operationCount": 29,
"triggers": [],
"triggerCount": 0,
"authType": "api-key",
"category": "tools",
"integrationType": "security",
"tags": ["monitoring", "automation", "document-processing"]
},
{
"type": "vercel",
"slug": "vercel",
+60
View File
@@ -3375,6 +3375,37 @@ import {
upstashRedisSetTool,
upstashRedisTtlTool,
} from '@/tools/upstash'
import {
vantaDownloadDocumentFileTool,
vantaGetControlTool,
vantaGetDocumentTool,
vantaGetFrameworkTool,
vantaGetPersonTool,
vantaGetPolicyTool,
vantaGetRiskScenarioTool,
vantaGetTestTool,
vantaGetVendorTool,
vantaGetVulnerableAssetTool,
vantaListControlDocumentsTool,
vantaListControlsTool,
vantaListControlTestsTool,
vantaListDocumentsTool,
vantaListDocumentUploadsTool,
vantaListFrameworkControlsTool,
vantaListFrameworksTool,
vantaListMonitoredComputersTool,
vantaListPeopleTool,
vantaListPoliciesTool,
vantaListRiskScenariosTool,
vantaListTestEntitiesTool,
vantaListTestsTool,
vantaListVendorsTool,
vantaListVulnerabilitiesTool,
vantaListVulnerabilityRemediationsTool,
vantaListVulnerableAssetsTool,
vantaSubmitDocumentTool,
vantaUploadDocumentFileTool,
} from '@/tools/vanta'
import {
vercelAddDomainTool,
vercelAddProjectDomainTool,
@@ -5511,6 +5542,35 @@ export const tools: Record<string, ToolConfig> = {
trigger_dev_get_waitpoint_token: triggerDevGetWaitpointTokenTool,
trigger_dev_list_waitpoint_tokens: triggerDevListWaitpointTokensTool,
trigger_dev_list_timezones: triggerDevListTimezonesTool,
vanta_list_frameworks: vantaListFrameworksTool,
vanta_get_framework: vantaGetFrameworkTool,
vanta_list_framework_controls: vantaListFrameworkControlsTool,
vanta_list_controls: vantaListControlsTool,
vanta_get_control: vantaGetControlTool,
vanta_list_control_tests: vantaListControlTestsTool,
vanta_list_control_documents: vantaListControlDocumentsTool,
vanta_list_tests: vantaListTestsTool,
vanta_get_test: vantaGetTestTool,
vanta_list_test_entities: vantaListTestEntitiesTool,
vanta_list_documents: vantaListDocumentsTool,
vanta_get_document: vantaGetDocumentTool,
vanta_list_document_uploads: vantaListDocumentUploadsTool,
vanta_upload_document_file: vantaUploadDocumentFileTool,
vanta_download_document_file: vantaDownloadDocumentFileTool,
vanta_submit_document: vantaSubmitDocumentTool,
vanta_list_people: vantaListPeopleTool,
vanta_get_person: vantaGetPersonTool,
vanta_list_policies: vantaListPoliciesTool,
vanta_get_policy: vantaGetPolicyTool,
vanta_list_vendors: vantaListVendorsTool,
vanta_get_vendor: vantaGetVendorTool,
vanta_list_monitored_computers: vantaListMonitoredComputersTool,
vanta_list_vulnerabilities: vantaListVulnerabilitiesTool,
vanta_list_vulnerability_remediations: vantaListVulnerabilityRemediationsTool,
vanta_list_vulnerable_assets: vantaListVulnerableAssetsTool,
vanta_get_vulnerable_asset: vantaGetVulnerableAssetTool,
vanta_list_risk_scenarios: vantaListRiskScenariosTool,
vanta_get_risk_scenario: vantaGetRiskScenarioTool,
vercel_list_deployments: vercelListDeploymentsTool,
vercel_get_deployment: vercelGetDeploymentTool,
vercel_create_deployment: vercelCreateDeploymentTool,
@@ -0,0 +1,74 @@
import type { ToolConfig } from '@/tools/types'
import type {
VantaDownloadDocumentFileParams,
VantaDownloadDocumentFileResponse,
} from '@/tools/vanta/types'
import { createVantaTransformResponse } from '@/tools/vanta/utils'
export const vantaDownloadDocumentFileTool: ToolConfig<
VantaDownloadDocumentFileParams,
VantaDownloadDocumentFileResponse
> = {
id: 'vanta_download_document_file',
name: 'Vanta Download Document File',
description:
'Download a file previously uploaded to a Vanta evidence document and store it in execution files',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
documentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the document',
},
uploadedFileId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the uploaded file (from List Document Uploads)',
},
},
request: {
url: '/api/tools/vanta/download',
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
documentId: params.documentId,
uploadedFileId: params.uploadedFileId,
}),
},
transformResponse: createVantaTransformResponse<VantaDownloadDocumentFileResponse>(
'Failed to download Vanta document file'
),
outputs: {
file: { type: 'file', description: 'Downloaded file stored in execution files' },
name: { type: 'string', description: 'Name of the downloaded file' },
mimeType: { type: 'string', description: 'MIME type of the downloaded file' },
size: { type: 'number', description: 'Size of the downloaded file in bytes' },
},
}
+64
View File
@@ -0,0 +1,64 @@
import type { ToolConfig } from '@/tools/types'
import { VANTA_CONTROL_DETAIL_OUTPUT_PROPERTIES } from '@/tools/vanta/outputs'
import type { VantaGetControlParams, VantaGetControlResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaGetControlTool: ToolConfig<VantaGetControlParams, VantaGetControlResponse> = {
id: 'vanta_get_control',
name: 'Vanta Get Control',
description:
'Get a Vanta security control by ID, including its status and evidence pass/fail counts',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
controlId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the control',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_get_control',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
controlId: params.controlId,
}),
},
transformResponse: createVantaTransformResponse<VantaGetControlResponse>(
'Failed to get Vanta control'
),
outputs: {
control: {
type: 'json',
description: 'The requested control with status and evidence counts',
properties: VANTA_CONTROL_DETAIL_OUTPUT_PROPERTIES,
},
},
}
+64
View File
@@ -0,0 +1,64 @@
import type { ToolConfig } from '@/tools/types'
import { VANTA_DOCUMENT_DETAIL_OUTPUT_PROPERTIES } from '@/tools/vanta/outputs'
import type { VantaGetDocumentParams, VantaGetDocumentResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaGetDocumentTool: ToolConfig<VantaGetDocumentParams, VantaGetDocumentResponse> = {
id: 'vanta_get_document',
name: 'Vanta Get Document',
description:
'Get a Vanta evidence document by ID, including its renewal schedule and deactivation status',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
documentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the document',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_get_document',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
documentId: params.documentId,
}),
},
transformResponse: createVantaTransformResponse<VantaGetDocumentResponse>(
'Failed to get Vanta document'
),
outputs: {
document: {
type: 'json',
description: 'The requested document',
properties: VANTA_DOCUMENT_DETAIL_OUTPUT_PROPERTIES,
},
},
}
+65
View File
@@ -0,0 +1,65 @@
import type { ToolConfig } from '@/tools/types'
import { VANTA_FRAMEWORK_DETAIL_OUTPUT_PROPERTIES } from '@/tools/vanta/outputs'
import type { VantaGetFrameworkParams, VantaGetFrameworkResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaGetFrameworkTool: ToolConfig<VantaGetFrameworkParams, VantaGetFrameworkResponse> =
{
id: 'vanta_get_framework',
name: 'Vanta Get Framework',
description:
'Get a Vanta compliance framework by ID, including its requirement categories and mapped controls',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
frameworkId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the framework (e.g., soc2)',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_get_framework',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
frameworkId: params.frameworkId,
}),
},
transformResponse: createVantaTransformResponse<VantaGetFrameworkResponse>(
'Failed to get Vanta framework'
),
outputs: {
framework: {
type: 'json',
description: 'The requested framework with requirement categories',
properties: VANTA_FRAMEWORK_DETAIL_OUTPUT_PROPERTIES,
},
},
}
+64
View File
@@ -0,0 +1,64 @@
import type { ToolConfig } from '@/tools/types'
import { VANTA_PERSON_OUTPUT_PROPERTIES } from '@/tools/vanta/outputs'
import type { VantaGetPersonParams, VantaGetPersonResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaGetPersonTool: ToolConfig<VantaGetPersonParams, VantaGetPersonResponse> = {
id: 'vanta_get_person',
name: 'Vanta Get Person',
description:
'Get a person tracked in Vanta by ID, including employment, leave, and security task status',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
personId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the person',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_get_person',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
personId: params.personId,
}),
},
transformResponse: createVantaTransformResponse<VantaGetPersonResponse>(
'Failed to get Vanta person'
),
outputs: {
person: {
type: 'json',
description: 'The requested person',
properties: VANTA_PERSON_OUTPUT_PROPERTIES,
},
},
}
+64
View File
@@ -0,0 +1,64 @@
import type { ToolConfig } from '@/tools/types'
import { VANTA_POLICY_OUTPUT_PROPERTIES } from '@/tools/vanta/outputs'
import type { VantaGetPolicyParams, VantaGetPolicyResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaGetPolicyTool: ToolConfig<VantaGetPolicyParams, VantaGetPolicyResponse> = {
id: 'vanta_get_policy',
name: 'Vanta Get Policy',
description:
'Get a Vanta security policy by ID, including its approval status and latest approved version documents',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
policyId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the policy',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_get_policy',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
policyId: params.policyId,
}),
},
transformResponse: createVantaTransformResponse<VantaGetPolicyResponse>(
'Failed to get Vanta policy'
),
outputs: {
policy: {
type: 'json',
description: 'The requested policy',
properties: VANTA_POLICY_OUTPUT_PROPERTIES,
},
},
}
+67
View File
@@ -0,0 +1,67 @@
import type { ToolConfig } from '@/tools/types'
import { VANTA_RISK_SCENARIO_OUTPUT_PROPERTIES } from '@/tools/vanta/outputs'
import type { VantaGetRiskScenarioParams, VantaGetRiskScenarioResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaGetRiskScenarioTool: ToolConfig<
VantaGetRiskScenarioParams,
VantaGetRiskScenarioResponse
> = {
id: 'vanta_get_risk_scenario',
name: 'Vanta Get Risk Scenario',
description:
'Get a Vanta risk scenario by ID, including its scores, treatment decision, and review status',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
riskScenarioId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the risk scenario',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_get_risk_scenario',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
riskScenarioId: params.riskScenarioId,
}),
},
transformResponse: createVantaTransformResponse<VantaGetRiskScenarioResponse>(
'Failed to get Vanta risk scenario'
),
outputs: {
riskScenario: {
type: 'json',
description: 'The requested risk scenario',
properties: VANTA_RISK_SCENARIO_OUTPUT_PROPERTIES,
},
},
}
+62
View File
@@ -0,0 +1,62 @@
import type { ToolConfig } from '@/tools/types'
import { VANTA_TEST_OUTPUT_PROPERTIES } from '@/tools/vanta/outputs'
import type { VantaGetTestParams, VantaGetTestResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaGetTestTool: ToolConfig<VantaGetTestParams, VantaGetTestResponse> = {
id: 'vanta_get_test',
name: 'Vanta Get Test',
description:
'Get a Vanta automated compliance test by ID, including its status and remediation info',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
testId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the test (e.g., test-aws-cloudtrail-enabled)',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_get_test',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
testId: params.testId,
}),
},
transformResponse: createVantaTransformResponse<VantaGetTestResponse>('Failed to get Vanta test'),
outputs: {
test: {
type: 'json',
description: 'The requested test',
properties: VANTA_TEST_OUTPUT_PROPERTIES,
},
},
}
+64
View File
@@ -0,0 +1,64 @@
import type { ToolConfig } from '@/tools/types'
import { VANTA_VENDOR_OUTPUT_PROPERTIES } from '@/tools/vanta/outputs'
import type { VantaGetVendorParams, VantaGetVendorResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaGetVendorTool: ToolConfig<VantaGetVendorParams, VantaGetVendorResponse> = {
id: 'vanta_get_vendor',
name: 'Vanta Get Vendor',
description:
'Get a Vanta vendor by ID, including risk levels, contract details, and authentication info',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
vendorId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the vendor',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_get_vendor',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
vendorId: params.vendorId,
}),
},
transformResponse: createVantaTransformResponse<VantaGetVendorResponse>(
'Failed to get Vanta vendor'
),
outputs: {
vendor: {
type: 'json',
description: 'The requested vendor',
properties: VANTA_VENDOR_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,70 @@
import type { ToolConfig } from '@/tools/types'
import { VANTA_VULNERABLE_ASSET_OUTPUT_PROPERTIES } from '@/tools/vanta/outputs'
import type {
VantaGetVulnerableAssetParams,
VantaGetVulnerableAssetResponse,
} from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaGetVulnerableAssetTool: ToolConfig<
VantaGetVulnerableAssetParams,
VantaGetVulnerableAssetResponse
> = {
id: 'vanta_get_vulnerable_asset',
name: 'Vanta Get Vulnerable Asset',
description:
'Get a vulnerable asset in Vanta by ID, including the scanners reporting it and per-scanner asset details',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
vulnerableAssetId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the vulnerable asset',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_get_vulnerable_asset',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
vulnerableAssetId: params.vulnerableAssetId,
}),
},
transformResponse: createVantaTransformResponse<VantaGetVulnerableAssetResponse>(
'Failed to get Vanta vulnerable asset'
),
outputs: {
asset: {
type: 'json',
description: 'The requested vulnerable asset',
properties: VANTA_VULNERABLE_ASSET_OUTPUT_PROPERTIES,
},
},
}
+30
View File
@@ -0,0 +1,30 @@
export { vantaDownloadDocumentFileTool } from './download_document_file'
export { vantaGetControlTool } from './get_control'
export { vantaGetDocumentTool } from './get_document'
export { vantaGetFrameworkTool } from './get_framework'
export { vantaGetPersonTool } from './get_person'
export { vantaGetPolicyTool } from './get_policy'
export { vantaGetRiskScenarioTool } from './get_risk_scenario'
export { vantaGetTestTool } from './get_test'
export { vantaGetVendorTool } from './get_vendor'
export { vantaGetVulnerableAssetTool } from './get_vulnerable_asset'
export { vantaListControlDocumentsTool } from './list_control_documents'
export { vantaListControlTestsTool } from './list_control_tests'
export { vantaListControlsTool } from './list_controls'
export { vantaListDocumentUploadsTool } from './list_document_uploads'
export { vantaListDocumentsTool } from './list_documents'
export { vantaListFrameworkControlsTool } from './list_framework_controls'
export { vantaListFrameworksTool } from './list_frameworks'
export { vantaListMonitoredComputersTool } from './list_monitored_computers'
export { vantaListPeopleTool } from './list_people'
export { vantaListPoliciesTool } from './list_policies'
export { vantaListRiskScenariosTool } from './list_risk_scenarios'
export { vantaListTestEntitiesTool } from './list_test_entities'
export { vantaListTestsTool } from './list_tests'
export { vantaListVendorsTool } from './list_vendors'
export { vantaListVulnerabilitiesTool } from './list_vulnerabilities'
export { vantaListVulnerabilityRemediationsTool } from './list_vulnerability_remediations'
export { vantaListVulnerableAssetsTool } from './list_vulnerable_assets'
export { vantaSubmitDocumentTool } from './submit_document'
export * from './types'
export { vantaUploadDocumentFileTool } from './upload_document_file'
@@ -0,0 +1,94 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_DOCUMENT_OUTPUT_PROPERTIES,
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type {
VantaListControlDocumentsParams,
VantaListDocumentsResponse,
} from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListControlDocumentsTool: ToolConfig<
VantaListControlDocumentsParams,
VantaListDocumentsResponse
> = {
id: 'vanta_list_control_documents',
name: 'Vanta List Control Documents',
description: 'List the evidence documents mapped to a specific Vanta control',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
controlId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the control',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_control_documents',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
controlId: params.controlId,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListDocumentsResponse>(
'Failed to list Vanta control documents'
),
outputs: {
documents: {
type: 'array',
description: 'Documents mapped to the control',
items: { type: 'object', properties: VANTA_DOCUMENT_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,91 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
VANTA_TEST_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type { VantaListControlTestsParams, VantaListTestsResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListControlTestsTool: ToolConfig<
VantaListControlTestsParams,
VantaListTestsResponse
> = {
id: 'vanta_list_control_tests',
name: 'Vanta List Control Tests',
description: 'List the automated tests mapped to a specific Vanta control',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
controlId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the control',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_control_tests',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
controlId: params.controlId,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListTestsResponse>(
'Failed to list Vanta control tests'
),
outputs: {
tests: {
type: 'array',
description: 'Tests mapped to the control',
items: { type: 'object', properties: VANTA_TEST_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
+89
View File
@@ -0,0 +1,89 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_CONTROL_OUTPUT_PROPERTIES,
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type { VantaListControlsParams, VantaListControlsResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListControlsTool: ToolConfig<VantaListControlsParams, VantaListControlsResponse> =
{
id: 'vanta_list_controls',
name: 'Vanta List Controls',
description: 'List the security controls in a Vanta account, optionally filtered by framework',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
frameworkMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated framework IDs to filter controls by (e.g., soc2,iso27001)',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_controls',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
frameworkMatchesAny: params.frameworkMatchesAny,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListControlsResponse>(
'Failed to list Vanta controls'
),
outputs: {
controls: {
type: 'array',
description: 'Controls matching the filters',
items: { type: 'object', properties: VANTA_CONTROL_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,94 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
VANTA_UPLOADED_FILE_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type {
VantaListDocumentUploadsParams,
VantaListDocumentUploadsResponse,
} from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListDocumentUploadsTool: ToolConfig<
VantaListDocumentUploadsParams,
VantaListDocumentUploadsResponse
> = {
id: 'vanta_list_document_uploads',
name: 'Vanta List Document Uploads',
description: 'List the files uploaded to a specific Vanta evidence document',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
documentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the document',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_document_uploads',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
documentId: params.documentId,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListDocumentUploadsResponse>(
'Failed to list Vanta document uploads'
),
outputs: {
uploads: {
type: 'array',
description: 'Files uploaded to the document',
items: { type: 'object', properties: VANTA_UPLOADED_FILE_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
+100
View File
@@ -0,0 +1,100 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_DOCUMENT_OUTPUT_PROPERTIES,
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type { VantaListDocumentsParams, VantaListDocumentsResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListDocumentsTool: ToolConfig<
VantaListDocumentsParams,
VantaListDocumentsResponse
> = {
id: 'vanta_list_documents',
name: 'Vanta List Documents',
description:
'List the evidence documents in a Vanta account, optionally filtered by framework or document status',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
frameworkMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated framework IDs to filter documents by (e.g., soc2,iso27001)',
},
statusMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated document statuses to filter by: "Needs document", "Needs update", "Not relevant", "OK"',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_documents',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
frameworkMatchesAny: params.frameworkMatchesAny,
statusMatchesAny: params.statusMatchesAny,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListDocumentsResponse>(
'Failed to list Vanta documents'
),
outputs: {
documents: {
type: 'array',
description: 'Documents matching the filters',
items: { type: 'object', properties: VANTA_DOCUMENT_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,94 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_CONTROL_OUTPUT_PROPERTIES,
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type {
VantaListControlsResponse,
VantaListFrameworkControlsParams,
} from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListFrameworkControlsTool: ToolConfig<
VantaListFrameworkControlsParams,
VantaListControlsResponse
> = {
id: 'vanta_list_framework_controls',
name: 'Vanta List Framework Controls',
description: 'List the controls that belong to a specific Vanta compliance framework',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
frameworkId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the framework (e.g., soc2)',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_framework_controls',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
frameworkId: params.frameworkId,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListControlsResponse>(
'Failed to list Vanta framework controls'
),
outputs: {
controls: {
type: 'array',
description: 'Controls belonging to the framework',
items: { type: 'object', properties: VANTA_CONTROL_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
+85
View File
@@ -0,0 +1,85 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_FRAMEWORK_OUTPUT_PROPERTIES,
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type { VantaListFrameworksParams, VantaListFrameworksResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListFrameworksTool: ToolConfig<
VantaListFrameworksParams,
VantaListFrameworksResponse
> = {
id: 'vanta_list_frameworks',
name: 'Vanta List Frameworks',
description:
'List the compliance frameworks (e.g., SOC 2, ISO 27001) available in a Vanta account with completion counts',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_frameworks',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListFrameworksResponse>(
'Failed to list Vanta frameworks'
),
outputs: {
frameworks: {
type: 'array',
description: 'Frameworks in the Vanta account',
items: { type: 'object', properties: VANTA_FRAMEWORK_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,96 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_MONITORED_COMPUTER_OUTPUT_PROPERTIES,
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type {
VantaListMonitoredComputersParams,
VantaListMonitoredComputersResponse,
} from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListMonitoredComputersTool: ToolConfig<
VantaListMonitoredComputersParams,
VantaListMonitoredComputersResponse
> = {
id: 'vanta_list_monitored_computers',
name: 'Vanta List Monitored Computers',
description:
'List the monitored computers in a Vanta account with screenlock, disk encryption, password manager, and antivirus check outcomes',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
complianceStatusFilterMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated compliance issues to filter by: PWM_NOT_INSTALLED, HD_NOT_ENCRYPTED, AV_NOT_INSTALLED, SCREENLOCK_NOT_CONFIGURED, LAST_CHECK_OVER_14_DAYS',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_monitored_computers',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
complianceStatusFilterMatchesAny: params.complianceStatusFilterMatchesAny,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListMonitoredComputersResponse>(
'Failed to list Vanta monitored computers'
),
outputs: {
computers: {
type: 'array',
description: 'Monitored computers matching the filters',
items: { type: 'object', properties: VANTA_MONITORED_COMPUTER_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
+126
View File
@@ -0,0 +1,126 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
VANTA_PERSON_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type { VantaListPeopleParams, VantaListPeopleResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListPeopleTool: ToolConfig<VantaListPeopleParams, VantaListPeopleResponse> = {
id: 'vanta_list_people',
name: 'Vanta List People',
description:
'List the people tracked in a Vanta account with employment status, group membership, and security task completion',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
emailAndNameFilter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter people by email address or name',
},
employmentStatus: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by employment status: UPCOMING, CURRENT, ON_LEAVE, INACTIVE, or FORMER',
},
groupIdsMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated group IDs to filter people by',
},
tasksSummaryStatusMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated task summary statuses to filter by: NONE, DUE_SOON, OVERDUE, COMPLETE, PAUSED, OFFBOARDING_DUE_SOON, OFFBOARDING_OVERDUE, OFFBOARDING_COMPLETE',
},
taskTypeMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated task types to filter by: COMPLETE_TRAININGS, ACCEPT_POLICIES, COMPLETE_CUSTOM_TASKS, COMPLETE_CUSTOM_OFFBOARDING_TASKS, INSTALL_DEVICE_MONITORING, COMPLETE_BACKGROUND_CHECKS',
},
taskStatusMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated task statuses to filter by: COMPLETE, DUE_SOON, OVERDUE, NONE',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_people',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
emailAndNameFilter: params.emailAndNameFilter,
employmentStatus: params.employmentStatus,
groupIdsMatchesAny: params.groupIdsMatchesAny,
tasksSummaryStatusMatchesAny: params.tasksSummaryStatusMatchesAny,
taskTypeMatchesAny: params.taskTypeMatchesAny,
taskStatusMatchesAny: params.taskStatusMatchesAny,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListPeopleResponse>(
'Failed to list Vanta people'
),
outputs: {
people: {
type: 'array',
description: 'People matching the filters',
items: { type: 'object', properties: VANTA_PERSON_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
+83
View File
@@ -0,0 +1,83 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
VANTA_POLICY_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type { VantaListPoliciesParams, VantaListPoliciesResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListPoliciesTool: ToolConfig<VantaListPoliciesParams, VantaListPoliciesResponse> =
{
id: 'vanta_list_policies',
name: 'Vanta List Policies',
description:
'List the security policies in a Vanta account with approval status and version info',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_policies',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListPoliciesResponse>(
'Failed to list Vanta policies'
),
outputs: {
policies: {
type: 'array',
description: 'Policies in the Vanta account',
items: { type: 'object', properties: VANTA_POLICY_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
+169
View File
@@ -0,0 +1,169 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
VANTA_RISK_SCENARIO_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type {
VantaListRiskScenariosParams,
VantaListRiskScenariosResponse,
} from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListRiskScenariosTool: ToolConfig<
VantaListRiskScenariosParams,
VantaListRiskScenariosResponse
> = {
id: 'vanta_list_risk_scenarios',
name: 'Vanta List Risk Scenarios',
description:
'List the risk scenarios in a Vanta risk register with likelihood/impact scores, treatment decisions, and review status',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
searchString: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search string to filter risk scenarios',
},
includeIgnored: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Include ignored risk scenarios',
},
type: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by scenario type: "Risk Scenario" or "Enterprise Risk"',
},
ownerMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated owner emails to filter by',
},
categoryMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated risk categories to filter by',
},
ciaCategoryMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated CIA categories to filter by: Confidentiality, Integrity, Availability',
},
treatmentTypeMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated treatments to filter by: Mitigate, Transfer, Avoid, Accept',
},
inherentScoreGroupMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated inherent score groups to filter by: "Very low", Low, Med, High, Critical',
},
residualScoreGroupMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated residual score groups to filter by: "Very low", Low, Med, High, Critical',
},
reviewStatusMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated review statuses to filter by: APPROVED, DRAFT, NOT_REVIEWED, AWAITING_SUBMISSION, PENDING_APPROVAL, REQUESTED_CHANGES',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Field to order results by: description or createdAt',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_risk_scenarios',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
searchString: params.searchString,
includeIgnored: params.includeIgnored,
type: params.type,
ownerMatchesAny: params.ownerMatchesAny,
categoryMatchesAny: params.categoryMatchesAny,
ciaCategoryMatchesAny: params.ciaCategoryMatchesAny,
treatmentTypeMatchesAny: params.treatmentTypeMatchesAny,
inherentScoreGroupMatchesAny: params.inherentScoreGroupMatchesAny,
residualScoreGroupMatchesAny: params.residualScoreGroupMatchesAny,
reviewStatusMatchesAny: params.reviewStatusMatchesAny,
orderBy: params.orderBy,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListRiskScenariosResponse>(
'Failed to list Vanta risk scenarios'
),
outputs: {
riskScenarios: {
type: 'array',
description: 'Risk scenarios matching the filters',
items: { type: 'object', properties: VANTA_RISK_SCENARIO_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
+102
View File
@@ -0,0 +1,102 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
VANTA_TEST_ENTITY_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type {
VantaListTestEntitiesParams,
VantaListTestEntitiesResponse,
} from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListTestEntitiesTool: ToolConfig<
VantaListTestEntitiesParams,
VantaListTestEntitiesResponse
> = {
id: 'vanta_list_test_entities',
name: 'Vanta List Test Entities',
description:
'List the failing or deactivated resource entities for a specific Vanta test, useful for finding exactly which resources need remediation',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
testId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the test (e.g., test-aws-cloudtrail-enabled)',
},
entityStatus: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter entities by status: FAILING or DEACTIVATED',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_test_entities',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
testId: params.testId,
entityStatus: params.entityStatus,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListTestEntitiesResponse>(
'Failed to list Vanta test entities'
),
outputs: {
entities: {
type: 'array',
description: 'Resource entities for the test',
items: { type: 'object', properties: VANTA_TEST_ENTITY_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
+133
View File
@@ -0,0 +1,133 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
VANTA_TEST_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type { VantaListTestsParams, VantaListTestsResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListTestsTool: ToolConfig<VantaListTestsParams, VantaListTestsResponse> = {
id: 'vanta_list_tests',
name: 'Vanta List Tests',
description:
'List the automated compliance tests in a Vanta account, with filters for status, framework, integration, control, owner, and category',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
statusFilter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Filter by test status: OK, DEACTIVATED, NEEDS_ATTENTION, IN_PROGRESS, INVALID, or NOT_APPLICABLE',
},
frameworkFilter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by framework ID (e.g., soc2)',
},
integrationFilter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by integration ID (e.g., aws)',
},
controlFilter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by control ID',
},
ownerFilter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by owner user ID',
},
categoryFilter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Filter by test category (e.g., ACCOUNTS_ACCESS, COMPUTERS, INFRASTRUCTURE, POLICIES, VULNERABILITY_MANAGEMENT)',
},
isInRollout: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Filter by whether the test is in rollout',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_tests',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
statusFilter: params.statusFilter,
frameworkFilter: params.frameworkFilter,
integrationFilter: params.integrationFilter,
controlFilter: params.controlFilter,
ownerFilter: params.ownerFilter,
categoryFilter: params.categoryFilter,
isInRollout: params.isInRollout,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListTestsResponse>(
'Failed to list Vanta tests'
),
outputs: {
tests: {
type: 'array',
description: 'Tests matching the filters',
items: { type: 'object', properties: VANTA_TEST_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
+97
View File
@@ -0,0 +1,97 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
VANTA_VENDOR_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type { VantaListVendorsParams, VantaListVendorsResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListVendorsTool: ToolConfig<VantaListVendorsParams, VantaListVendorsResponse> = {
id: 'vanta_list_vendors',
name: 'Vanta List Vendors',
description:
'List the vendors tracked in a Vanta account with risk levels, contract dates, and security review schedules',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter vendors by name',
},
statusMatchesAny: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated vendor statuses to filter by: MANAGED, ARCHIVED, IN_PROCUREMENT',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_vendors',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
name: params.name,
statusMatchesAny: params.statusMatchesAny,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListVendorsResponse>(
'Failed to list Vanta vendors'
),
outputs: {
vendors: {
type: 'array',
description: 'Vendors matching the filters',
items: { type: 'object', properties: VANTA_VENDOR_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,165 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
VANTA_VULNERABILITY_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type {
VantaListVulnerabilitiesParams,
VantaListVulnerabilitiesResponse,
} from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListVulnerabilitiesTool: ToolConfig<
VantaListVulnerabilitiesParams,
VantaListVulnerabilitiesResponse
> = {
id: 'vanta_list_vulnerabilities',
name: 'Vanta List Vulnerabilities',
description:
'List the vulnerabilities detected across a Vanta account with filters for severity, fixability, SLA deadlines, package, and integration',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
q: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search query for vulnerabilities',
},
severity: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by severity: LOW, MEDIUM, HIGH, or CRITICAL',
},
isFixAvailable: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Filter by whether a fix is available',
},
isDeactivated: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Filter by whether vulnerability monitoring is deactivated',
},
includeVulnerabilitiesWithoutSlas: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Include vulnerabilities that have no SLA deadline',
},
packageIdentifier: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by the affected package identifier',
},
externalVulnerabilityId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by external vulnerability ID (e.g., a CVE identifier)',
},
integrationId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by the integration that detected the vulnerability',
},
vulnerableAssetId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by the vulnerable asset ID',
},
slaDeadlineAfterDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Only include vulnerabilities with an SLA deadline after this ISO 8601 date',
},
slaDeadlineBeforeDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Only include vulnerabilities with an SLA deadline before this ISO 8601 date',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_vulnerabilities',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
q: params.q,
severity: params.severity,
isFixAvailable: params.isFixAvailable,
isDeactivated: params.isDeactivated,
includeVulnerabilitiesWithoutSlas: params.includeVulnerabilitiesWithoutSlas,
packageIdentifier: params.packageIdentifier,
externalVulnerabilityId: params.externalVulnerabilityId,
integrationId: params.integrationId,
vulnerableAssetId: params.vulnerableAssetId,
slaDeadlineAfterDate: params.slaDeadlineAfterDate,
slaDeadlineBeforeDate: params.slaDeadlineBeforeDate,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListVulnerabilitiesResponse>(
'Failed to list Vanta vulnerabilities'
),
outputs: {
vulnerabilities: {
type: 'array',
description: 'Vulnerabilities matching the filters',
items: { type: 'object', properties: VANTA_VULNERABILITY_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,123 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
VANTA_VULNERABILITY_REMEDIATION_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type {
VantaListVulnerabilityRemediationsParams,
VantaListVulnerabilityRemediationsResponse,
} from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListVulnerabilityRemediationsTool: ToolConfig<
VantaListVulnerabilityRemediationsParams,
VantaListVulnerabilityRemediationsResponse
> = {
id: 'vanta_list_vulnerability_remediations',
name: 'Vanta List Vulnerability Remediations',
description:
'List remediated vulnerabilities in a Vanta account with detection, SLA deadline, and remediation dates',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
integrationId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by the integration that detected the vulnerability',
},
severity: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by severity: LOW, MEDIUM, HIGH, or CRITICAL',
},
isRemediatedOnTime: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Filter by whether the vulnerability was remediated before its SLA deadline',
},
remediatedAfterDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Only include remediations completed after this ISO 8601 date',
},
remediatedBeforeDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Only include remediations completed before this ISO 8601 date',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_vulnerability_remediations',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
integrationId: params.integrationId,
severity: params.severity,
isRemediatedOnTime: params.isRemediatedOnTime,
remediatedAfterDate: params.remediatedAfterDate,
remediatedBeforeDate: params.remediatedBeforeDate,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListVulnerabilityRemediationsResponse>(
'Failed to list Vanta vulnerability remediations'
),
outputs: {
remediations: {
type: 'array',
description: 'Vulnerability remediations matching the filters',
items: { type: 'object', properties: VANTA_VULNERABILITY_REMEDIATION_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,117 @@
import type { ToolConfig } from '@/tools/types'
import {
VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
VANTA_VULNERABLE_ASSET_OUTPUT_PROPERTIES,
} from '@/tools/vanta/outputs'
import type {
VantaListVulnerableAssetsParams,
VantaListVulnerableAssetsResponse,
} from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaListVulnerableAssetsTool: ToolConfig<
VantaListVulnerableAssetsParams,
VantaListVulnerableAssetsResponse
> = {
id: 'vanta_list_vulnerable_assets',
name: 'Vanta List Vulnerable Assets',
description:
'List the assets associated with vulnerabilities in a Vanta account (servers, repositories, workstations, and more)',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
q: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search query for vulnerable assets',
},
integrationId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by the integration scanning the asset',
},
assetType: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Filter by asset type: SERVER, SERVERLESS_FUNCTION, CONTAINER, CONTAINER_REPOSITORY, CONTAINER_REPOSITORY_IMAGE, CODE_REPOSITORY, MANIFEST_FILE, WORKSTATION, or OTHER',
},
assetExternalAccountId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by the external account ID the asset belongs to',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items per page (1-100, default 10)',
},
pageCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor: pass the endCursor from the previous response to fetch the next page',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_list_vulnerable_assets',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
q: params.q,
integrationId: params.integrationId,
assetType: params.assetType,
assetExternalAccountId: params.assetExternalAccountId,
pageSize: params.pageSize,
pageCursor: params.pageCursor,
}),
},
transformResponse: createVantaTransformResponse<VantaListVulnerableAssetsResponse>(
'Failed to list Vanta vulnerable assets'
),
outputs: {
assets: {
type: 'array',
description: 'Vulnerable assets matching the filters',
items: { type: 'object', properties: VANTA_VULNERABLE_ASSET_OUTPUT_PROPERTIES },
},
pageInfo: {
type: 'json',
description:
'Cursor pagination info for the returned page; pass endCursor as pageCursor to fetch the next page',
optional: true,
properties: VANTA_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
+794
View File
@@ -0,0 +1,794 @@
import type { OutputProperty } from '@/tools/types'
export const VANTA_PAGE_INFO_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
startCursor: {
type: 'string',
description: 'Cursor pointing to the start of the current page',
optional: true,
},
endCursor: {
type: 'string',
description:
'Cursor pointing to the end of the current page; pass as pageCursor to fetch the next page',
optional: true,
},
hasNextPage: { type: 'boolean', description: 'Whether another page exists after this one' },
hasPreviousPage: { type: 'boolean', description: 'Whether a page exists before this one' },
}
const VANTA_OWNER_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: 'Unique ID of the owner', optional: true },
displayName: { type: 'string', description: 'Display name of the owner', optional: true },
emailAddress: { type: 'string', description: 'Email address of the owner', optional: true },
}
const VANTA_CUSTOM_FIELDS_OUTPUT: OutputProperty = {
type: 'array',
description: 'Custom field values configured in the Vanta instance',
items: {
type: 'object',
properties: {
label: { type: 'string', description: 'Custom field label', optional: true },
value: {
type: 'json',
description: 'Custom field value (string or list of strings)',
optional: true,
},
},
},
}
export const VANTA_FRAMEWORK_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: "The framework's unique ID" },
displayName: { type: 'string', description: "The framework's display name" },
shorthandName: { type: 'string', description: "The short version of the framework's name" },
description: { type: 'string', description: "The framework's description" },
numControlsCompleted: {
type: 'number',
description: 'Number of completed controls in the framework',
},
numControlsTotal: { type: 'number', description: 'Total number of controls in the framework' },
numDocumentsPassing: {
type: 'number',
description: 'Number of passing documents in the framework',
},
numDocumentsTotal: { type: 'number', description: 'Total number of documents in the framework' },
numTestsPassing: { type: 'number', description: 'Number of passing tests in the framework' },
numTestsTotal: { type: 'number', description: 'Total number of tests in the framework' },
}
export const VANTA_FRAMEWORK_DETAIL_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
...VANTA_FRAMEWORK_OUTPUT_PROPERTIES,
requirementCategories: {
type: 'array',
description:
"The framework's requirement categories, each with requirements and mapped controls",
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Requirement category ID' },
name: { type: 'string', description: 'Requirement category name' },
shorthand: {
type: 'string',
description: 'Requirement category short name',
optional: true,
},
requirements: {
type: 'array',
description: 'Requirements in this category, each listing its mapped controls',
},
},
},
},
}
export const VANTA_CONTROL_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: "The control's unique ID" },
externalId: { type: 'string', description: "The control's external ID", optional: true },
name: { type: 'string', description: "The control's name" },
description: { type: 'string', description: "The control's description" },
source: { type: 'string', description: 'The control source, either "Vanta" or "Custom"' },
domains: {
type: 'array',
description: 'Security domains the control belongs to',
items: { type: 'string' },
},
owner: {
type: 'json',
description: "The control's owner",
optional: true,
properties: VANTA_OWNER_OUTPUT_PROPERTIES,
},
role: { type: 'string', description: "The control's GDPR role, if applicable", optional: true },
customFields: VANTA_CUSTOM_FIELDS_OUTPUT,
creationDate: {
type: 'string',
description: 'When the control was created (null for Vanta library controls)',
optional: true,
},
modificationDate: {
type: 'string',
description: 'When the control was last modified (null for Vanta library controls)',
optional: true,
},
}
export const VANTA_CONTROL_DETAIL_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
...VANTA_CONTROL_OUTPUT_PROPERTIES,
note: { type: 'string', description: 'A user-created note for the control', optional: true },
status: {
type: 'string',
description: 'Control status (NO_EVIDENCE_MAPPED, NOT_STARTED, IN_PROGRESS, or COMPLETED)',
optional: true,
},
numDocumentsPassing: {
type: 'number',
description: 'Number of passing documents linked to the control',
optional: true,
},
numDocumentsTotal: {
type: 'number',
description: 'Total number of documents linked to the control',
optional: true,
},
numTestsPassing: {
type: 'number',
description: 'Number of passing tests linked to the control',
optional: true,
},
numTestsTotal: {
type: 'number',
description: 'Total number of tests linked to the control',
optional: true,
},
}
export const VANTA_TEST_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: "The test's unique ID" },
name: { type: 'string', description: "The test's name" },
description: { type: 'string', description: "The test's description" },
failureDescription: { type: 'string', description: "The test's failure description" },
remediationDescription: { type: 'string', description: "The test's remediation description" },
category: { type: 'string', description: "The test's category" },
status: {
type: 'string',
description:
'Test run status (OK, DEACTIVATED, NEEDS_ATTENTION, IN_PROGRESS, INVALID, or NOT_APPLICABLE)',
},
integrations: {
type: 'array',
description: "The test's third-party integration dependencies",
items: { type: 'string' },
},
lastTestRunDate: { type: 'string', description: 'Timestamp of the last test run' },
latestFlipDate: {
type: 'string',
description: 'Most recent date the test flipped status',
optional: true,
},
version: {
type: 'json',
description: "The test's version",
optional: true,
properties: {
major: { type: 'number', description: 'Major version number' },
minor: { type: 'number', description: 'Minor version number' },
},
},
deactivatedStatusInfo: {
type: 'json',
description: "The test's deactivation status",
optional: true,
properties: {
isDeactivated: { type: 'boolean', description: 'Whether the test is deactivated' },
deactivatedReason: { type: 'string', description: 'Reason for deactivation', optional: true },
lastUpdatedDate: {
type: 'string',
description: 'Date of the last deactivation status update',
optional: true,
},
},
},
remediationStatusInfo: {
type: 'json',
description: "The test's remediation status",
optional: true,
properties: {
status: { type: 'string', description: 'Remediation status' },
soonestRemediateByDate: {
type: 'string',
description: 'Soonest remediate-by date',
optional: true,
},
itemCount: { type: 'number', description: 'Number of items needing remediation' },
},
},
owner: {
type: 'json',
description: "The test's owner",
optional: true,
properties: VANTA_OWNER_OUTPUT_PROPERTIES,
},
}
export const VANTA_TEST_ENTITY_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: 'Identifier of the entity' },
entityStatus: { type: 'string', description: 'Entity status (FAILING or DEACTIVATED)' },
displayName: { type: 'string', description: 'Display name of the entity' },
responseType: { type: 'string', description: 'Response type of the entity' },
deactivatedReason: { type: 'string', description: 'Reason for deactivation', optional: true },
createdDate: { type: 'string', description: 'Date the entity was first detected' },
lastUpdatedDate: { type: 'string', description: 'Date of the last update to the entity' },
}
export const VANTA_DOCUMENT_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: "The document's unique ID" },
title: { type: 'string', description: "The document's title" },
description: { type: 'string', description: "The document's description" },
category: { type: 'string', description: "The document's category" },
ownerId: { type: 'string', description: "User ID of the document's owner", optional: true },
isSensitive: { type: 'boolean', description: 'Whether the document is sensitive' },
uploadStatus: {
type: 'string',
description: 'Document status ("Needs document", "Needs update", "Not relevant", or "OK")',
},
uploadStatusDate: {
type: 'string',
description: 'Date the upload status last changed',
optional: true,
},
url: { type: 'string', description: 'URL to view the document within Vanta', optional: true },
}
export const VANTA_DOCUMENT_DETAIL_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
...VANTA_DOCUMENT_OUTPUT_PROPERTIES,
note: { type: 'string', description: 'A user note for the document', optional: true },
nextRenewalDate: {
type: 'string',
description: 'When the document needs to be renewed',
optional: true,
},
renewalCadence: {
type: 'string',
description: 'How often the document must be renewed',
optional: true,
},
reminderWindow: {
type: 'string',
description: 'Reminder window ahead of the renewal date (P0D, P1D, P1W, P1M, or P3M)',
optional: true,
},
subscribers: {
type: 'array',
description: 'Emails subscribed to the document',
items: { type: 'string' },
},
deactivatedStatus: {
type: 'json',
description: "The document's deactivation status",
optional: true,
properties: {
isDeactivated: { type: 'boolean', description: 'Whether the document is deactivated' },
reason: {
type: 'string',
description: 'Reason the document was deactivated',
optional: true,
},
creationDate: { type: 'string', description: 'Date the document was deactivated' },
expiration: { type: 'string', description: 'Date the deactivation expires', optional: true },
},
},
}
export const VANTA_UPLOADED_FILE_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: 'Unique ID of the uploaded file' },
fileName: { type: 'string', description: 'File name of the upload', optional: true },
title: { type: 'string', description: 'Title of the upload' },
description: { type: 'string', description: 'Description of the upload', optional: true },
mimeType: { type: 'string', description: 'MIME type of the uploaded file' },
uploadedBy: {
type: 'json',
description: 'Actor who uploaded the file (a user or an application)',
optional: true,
properties: {
id: { type: 'string', description: 'Actor ID' },
type: { type: 'string', description: 'Actor type (USER or APPLICATION)' },
},
},
creationDate: { type: 'string', description: 'Date the file was uploaded' },
updatedDate: { type: 'string', description: 'Date the file was last updated' },
deletionDate: {
type: 'string',
description: 'Date the file was deleted (null if not deleted)',
optional: true,
},
effectiveDate: { type: 'string', description: "The file's effective date", optional: true },
url: { type: 'string', description: "The file's URL" },
}
export const VANTA_PERSON_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: "The person's unique ID" },
userId: {
type: 'string',
description: 'ID of the associated Vanta user account, if one exists',
optional: true,
},
emailAddress: { type: 'string', description: "The person's email address" },
name: {
type: 'json',
description: "The person's name",
optional: true,
properties: {
first: { type: 'string', description: 'First (given) name', optional: true },
last: { type: 'string', description: 'Last (family) name', optional: true },
display: { type: 'string', description: 'Display name used in Vanta' },
},
},
employment: {
type: 'json',
description: "The person's employment information",
optional: true,
properties: {
status: {
type: 'string',
description: 'Employment status (UPCOMING, CURRENT, ON_LEAVE, INACTIVE, or FORMER)',
},
startDate: { type: 'string', description: 'Employment start date' },
endDate: { type: 'string', description: 'Employment end date, if present', optional: true },
jobTitle: { type: 'string', description: 'Job title', optional: true },
},
},
leaveInfo: {
type: 'json',
description: "The person's active or upcoming leave, if any",
optional: true,
properties: {
status: { type: 'string', description: 'Leave status (ACTIVE or UPCOMING)' },
startDate: { type: 'string', description: 'Start of the leave' },
endDate: {
type: 'string',
description: 'End of the leave (null implies indefinite leave)',
optional: true,
},
},
},
groupIds: {
type: 'array',
description: 'IDs of the groups the person belongs to',
items: { type: 'string' },
},
tasksSummary: {
type: 'json',
description: "Aggregated status of the person's tasks",
optional: true,
properties: {
status: {
type: 'string',
description:
'Overall task status (e.g., NONE, DUE_SOON, OVERDUE, COMPLETE, PAUSED, or an OFFBOARDING_* variant)',
},
dueDate: {
type: 'string',
description: "Due date of the person's earliest-due task",
optional: true,
},
completionDate: {
type: 'string',
description: "Date the person's tasks were completed",
optional: true,
},
},
},
}
export const VANTA_POLICY_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: "The policy's unique ID" },
name: { type: 'string', description: "The policy's name" },
description: { type: 'string', description: "The policy's description" },
status: { type: 'string', description: 'Policy status (OK or NEEDS_REMEDIATION)' },
approvedAtDate: {
type: 'string',
description: "The policy's most recent approval date, if applicable",
optional: true,
},
latestVersionStatus: {
type: 'string',
description:
"Status of the policy's latest version (NOT_STARTED, DRAFT, PENDING_APPROVAL, APPROVED, RENEW_SOON, or EXPIRED)",
},
latestApprovedVersion: {
type: 'json',
description: 'The latest approved version of the policy, if available',
optional: true,
properties: {
versionId: { type: 'string', description: 'ID of the latest approved version' },
documents: {
type: 'array',
description: 'Available policy document versions, organized by language',
},
},
},
}
export const VANTA_VENDOR_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: "The vendor's unique ID" },
name: { type: 'string', description: "The vendor's display name" },
status: { type: 'string', description: 'Vendor status (MANAGED, ARCHIVED, or IN_PROCUREMENT)' },
websiteUrl: { type: 'string', description: "The vendor's website URL", optional: true },
category: {
type: 'string',
description: "Display name of the vendor's category",
optional: true,
},
servicesProvided: {
type: 'string',
description: 'Services provided by the vendor',
optional: true,
},
additionalNotes: {
type: 'string',
description: 'Additional notes about the vendor',
optional: true,
},
accountManagerName: {
type: 'string',
description: "The vendor's external account manager name",
optional: true,
},
accountManagerEmail: {
type: 'string',
description: "The vendor's external account manager email",
optional: true,
},
securityOwnerUserId: {
type: 'string',
description: "Vanta user ID of the vendor's security owner",
optional: true,
},
businessOwnerUserId: {
type: 'string',
description: "Vanta user ID of the vendor's business owner",
optional: true,
},
inherentRiskLevel: {
type: 'string',
description: 'Inherent risk level (CRITICAL, HIGH, MEDIUM, LOW, or UNSCORED)',
},
residualRiskLevel: {
type: 'string',
description: 'Residual risk level (CRITICAL, HIGH, MEDIUM, LOW, or UNSCORED)',
},
isRiskAutoScored: {
type: 'boolean',
description: "Whether the vendor's risk is automatically scored",
optional: true,
},
isVisibleToAuditors: {
type: 'boolean',
description: 'Whether auditors can view this vendor',
optional: true,
},
riskAttributeIds: {
type: 'array',
description: 'Risk attribute IDs assigned to the vendor',
items: { type: 'string' },
},
vendorHeadquarters: {
type: 'string',
description: "Country code of the vendor's headquarters",
optional: true,
},
contractStartDate: {
type: 'string',
description: 'Date the vendor contract began',
optional: true,
},
contractRenewalDate: {
type: 'string',
description: 'Date the vendor contract is up for renewal',
optional: true,
},
contractTerminationDate: {
type: 'string',
description: 'Date the vendor contract was terminated',
optional: true,
},
contractAmount: {
type: 'json',
description: 'Contract amount for the vendor',
optional: true,
properties: {
amount: { type: 'number', description: 'Amount of the contract' },
currency: { type: 'string', description: 'Currency of the contract' },
},
},
nextSecurityReviewDueDate: {
type: 'string',
description: 'Next due date for a security review',
optional: true,
},
lastSecurityReviewCompletionDate: {
type: 'string',
description: 'Most recent date a security review was completed',
optional: true,
},
authDetails: {
type: 'json',
description: "The vendor's authentication details",
optional: true,
properties: {
method: {
type: 'string',
description: 'Authentication method (e.g., SSO, OKTA, USERNAME_PASSWORD)',
optional: true,
},
passwordMFA: {
type: 'boolean',
description: 'Whether passwords require multi-factor authentication',
optional: true,
},
passwordMinimumLength: {
type: 'number',
description: 'Minimum password length',
optional: true,
},
passwordRequiresNumber: {
type: 'boolean',
description: 'Whether passwords require a number',
optional: true,
},
passwordRequiresSymbol: {
type: 'boolean',
description: 'Whether passwords require a symbol',
optional: true,
},
},
},
customFields: VANTA_CUSTOM_FIELDS_OUTPUT,
latestDecision: {
type: 'json',
description: "The vendor's latest decision (null when no decision has been made)",
optional: true,
properties: {
status: {
type: 'string',
description: 'Decision status (APPROVED, CONDITIONALLY_APPROVED, or NOT_APPROVED)',
},
lastUpdatedAt: { type: 'string', description: 'When the decision was last updated' },
},
},
linkedTaskTrackerTaskProcurementRequest: {
type: 'json',
description: 'Linked task tracker procurement request, if any',
optional: true,
properties: {
url: { type: 'string', description: 'URL of the procurement request' },
service: { type: 'string', description: 'Task tracker service' },
},
},
}
export const VANTA_MONITORED_COMPUTER_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: 'Unique identifier of the monitored computer' },
integrationId: { type: 'string', description: 'Integration that reports this computer' },
lastCheckDate: {
type: 'string',
description: "Date of the computer's most recent report",
optional: true,
},
screenlock: {
type: 'string',
description: 'Screenlock check outcome (PASS, FAIL, IN_PROGRESS, or NA)',
},
diskEncryption: {
type: 'string',
description: 'Disk encryption check outcome (PASS, FAIL, IN_PROGRESS, or NA)',
},
passwordManager: {
type: 'string',
description: 'Password manager check outcome (PASS, FAIL, IN_PROGRESS, or NA)',
},
antivirusInstallation: {
type: 'string',
description: 'Antivirus check outcome (PASS, FAIL, IN_PROGRESS, or NA)',
},
operatingSystem: {
type: 'json',
description: "The computer's operating system",
optional: true,
properties: {
type: { type: 'string', description: 'Operating system type (macOS, linux, or windows)' },
version: { type: 'string', description: 'Operating system version', optional: true },
},
},
owner: {
type: 'json',
description: "The computer's owner",
optional: true,
properties: VANTA_OWNER_OUTPUT_PROPERTIES,
},
serialNumber: { type: 'string', description: 'Serial number of the computer', optional: true },
udid: { type: 'string', description: 'Universal device ID of the computer', optional: true },
}
export const VANTA_RISK_SCENARIO_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
riskId: { type: 'string', description: 'Unique user-specified ID of the risk scenario' },
description: { type: 'string', description: 'Description of the risk scenario' },
likelihood: {
type: 'number',
description: 'Likelihood score (defaults to a 1-5 range; null when unscored)',
optional: true,
},
impact: {
type: 'number',
description: 'Impact score (defaults to a 1-5 range; null when unscored)',
optional: true,
},
residualLikelihood: {
type: 'number',
description: 'Residual likelihood score after treatments',
optional: true,
},
residualImpact: {
type: 'number',
description: 'Residual impact score after treatments',
optional: true,
},
categories: {
type: 'array',
description: 'Categories this risk scenario belongs to',
items: { type: 'string' },
},
ciaCategories: {
type: 'array',
description: 'CIA categories (Confidentiality, Integrity, Availability)',
items: { type: 'string' },
},
treatment: {
type: 'string',
description: 'Risk treatment decision (Mitigate, Transfer, Avoid, or Accept)',
optional: true,
},
owner: {
type: 'string',
description: 'Email of the person responsible for this risk',
optional: true,
},
note: {
type: 'string',
description: 'Additional context about the risk scenario',
optional: true,
},
riskRegister: {
type: 'string',
description: 'Name of the associated risk register',
optional: true,
},
customFields: VANTA_CUSTOM_FIELDS_OUTPUT,
isArchived: { type: 'boolean', description: 'Whether the scenario is archived' },
reviewStatus: {
type: 'string',
description:
'Review status (APPROVED, DRAFT, NOT_REVIEWED, AWAITING_SUBMISSION, PENDING_APPROVAL, or REQUESTED_CHANGES)',
},
requiredApprovers: {
type: 'array',
description: 'Required approvers for this risk scenario',
items: { type: 'string' },
},
type: { type: 'string', description: 'Scenario type ("Risk Scenario" or "Enterprise Risk")' },
identificationDate: { type: 'string', description: 'Date this risk was identified' },
}
export const VANTA_VULNERABILITY_REMEDIATION_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: 'Unique identifier of the remediation' },
vulnerabilityId: { type: 'string', description: 'ID of the remediated vulnerability' },
vulnerableAssetId: { type: 'string', description: 'ID of the vulnerable asset' },
severity: { type: 'string', description: 'Severity of the vulnerability' },
detectedDate: {
type: 'string',
description: 'Date the vulnerability was first detected',
optional: true,
},
slaDeadlineDate: { type: 'string', description: 'SLA deadline for remediation', optional: true },
remediationDate: {
type: 'string',
description: 'Date the vulnerability was remediated',
optional: true,
},
}
export const VANTA_VULNERABLE_ASSET_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: 'Unique identifier of the vulnerable asset' },
name: { type: 'string', description: 'Display name of the vulnerable asset' },
assetType: {
type: 'string',
description:
'Asset type (e.g., SERVER, SERVERLESS_FUNCTION, CONTAINER_REPOSITORY, CODE_REPOSITORY, WORKSTATION)',
},
hasBeenScanned: { type: 'boolean', description: 'Whether the asset has been scanned' },
imageScanTag: {
type: 'string',
description:
'Container image tag that vulnerabilities are retrieved for (container repositories only)',
optional: true,
},
scanners: {
type: 'array',
description:
'Integrations scanning this asset, with per-scanner asset details (resource ID, hostnames, IPs, image metadata)',
},
}
export const VANTA_VULNERABILITY_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: 'Unique identifier of the vulnerability' },
name: { type: 'string', description: 'Display name of the vulnerability' },
description: { type: 'string', description: 'Description of the vulnerability' },
severity: { type: 'string', description: 'Severity (LOW, MEDIUM, HIGH, or CRITICAL)' },
vulnerabilityType: {
type: 'string',
description: 'Vulnerability type (CONFIGURATION, COMMON, or GROUPED)',
},
integrationId: { type: 'string', description: 'Integration that scans this vulnerability' },
targetId: { type: 'string', description: 'ID of the resource the vulnerability was found on' },
packageIdentifier: {
type: 'string',
description: 'Identifier of the affected package (COMMON and GROUPED vulnerabilities only)',
optional: true,
},
cvssSeverityScore: { type: 'number', description: 'CVSS severity score', optional: true },
scannerScore: { type: 'number', description: 'Scanner score', optional: true },
isFixable: { type: 'boolean', description: 'Whether the vulnerability is fixable' },
fixedVersion: {
type: 'string',
description: 'Package version that remediates the vulnerability',
optional: true,
},
remediateByDate: {
type: 'string',
description: 'SLA date by which the vulnerability should be remediated',
optional: true,
},
firstDetectedDate: { type: 'string', description: 'Date first detected by Vanta' },
sourceDetectedDate: {
type: 'string',
description: 'Date first detected by the source',
optional: true,
},
lastDetectedDate: { type: 'string', description: 'Date last detected', optional: true },
scanSource: {
type: 'string',
description: 'Scanning tool that detected the vulnerability',
optional: true,
},
externalURL: { type: 'string', description: 'External URL for the vulnerability' },
relatedVulns: {
type: 'array',
description: 'Related vulnerabilities (GROUPED vulnerabilities only)',
items: { type: 'string' },
},
relatedUrls: {
type: 'array',
description: 'Related URLs',
items: { type: 'string' },
},
deactivateMetadata: {
type: 'json',
description: 'Deactivation metadata, if the vulnerability was deactivated',
optional: true,
properties: {
isVulnDeactivatedIndefinitely: {
type: 'boolean',
description: 'Whether deactivated indefinitely',
},
deactivatedUntilDate: {
type: 'string',
description: 'Date the vulnerability will be reactivated',
optional: true,
},
deactivationReason: { type: 'string', description: 'Reason for deactivation' },
deactivatedOnDate: { type: 'string', description: 'Date the vulnerability was deactivated' },
deactivatedBy: { type: 'string', description: 'User who deactivated the vulnerability' },
},
},
}
+63
View File
@@ -0,0 +1,63 @@
import type { ToolConfig } from '@/tools/types'
import type { VantaSubmitDocumentParams, VantaSubmitDocumentResponse } from '@/tools/vanta/types'
import { createVantaTransformResponse, VANTA_QUERY_ROUTE } from '@/tools/vanta/utils'
export const vantaSubmitDocumentTool: ToolConfig<
VantaSubmitDocumentParams,
VantaSubmitDocumentResponse
> = {
id: 'vanta_submit_document',
name: 'Vanta Submit Document',
description:
'Submit a Vanta document collection for review so uploaded evidence becomes visible to auditors. Requires credentials with write access.',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
documentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the document to submit',
},
},
request: {
url: VANTA_QUERY_ROUTE,
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
operation: 'vanta_submit_document',
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
documentId: params.documentId,
}),
},
transformResponse: createVantaTransformResponse<VantaSubmitDocumentResponse>(
'Failed to submit Vanta document'
),
outputs: {
documentId: { type: 'string', description: 'ID of the submitted document' },
submitted: { type: 'boolean', description: 'Whether the document collection was submitted' },
},
}
+780
View File
@@ -0,0 +1,780 @@
import type { ToolResponse } from '@/tools/types'
export type VantaRegion = 'us' | 'gov'
export interface VantaBaseParams {
clientId: string
clientSecret: string
region?: VantaRegion
}
export interface VantaPaginationParams {
pageSize?: number
pageCursor?: string
}
export interface VantaListFrameworksParams extends VantaBaseParams, VantaPaginationParams {}
export interface VantaGetFrameworkParams extends VantaBaseParams {
frameworkId: string
}
export interface VantaListFrameworkControlsParams extends VantaBaseParams, VantaPaginationParams {
frameworkId: string
}
export interface VantaListControlsParams extends VantaBaseParams, VantaPaginationParams {
frameworkMatchesAny?: string
}
export interface VantaGetControlParams extends VantaBaseParams {
controlId: string
}
export interface VantaListControlTestsParams extends VantaBaseParams, VantaPaginationParams {
controlId: string
}
export interface VantaListControlDocumentsParams extends VantaBaseParams, VantaPaginationParams {
controlId: string
}
export interface VantaListTestsParams extends VantaBaseParams, VantaPaginationParams {
statusFilter?: string
categoryFilter?: string
frameworkFilter?: string
integrationFilter?: string
controlFilter?: string
ownerFilter?: string
isInRollout?: boolean
}
export interface VantaGetTestParams extends VantaBaseParams {
testId: string
}
export interface VantaListTestEntitiesParams extends VantaBaseParams, VantaPaginationParams {
testId: string
entityStatus?: string
}
export interface VantaListDocumentsParams extends VantaBaseParams, VantaPaginationParams {
frameworkMatchesAny?: string
statusMatchesAny?: string
}
export interface VantaGetDocumentParams extends VantaBaseParams {
documentId: string
}
export interface VantaListDocumentUploadsParams extends VantaBaseParams, VantaPaginationParams {
documentId: string
}
export interface VantaUploadDocumentFileParams extends VantaBaseParams {
documentId: string
file?: unknown
fileContent?: string
fileName?: string
mimeType?: string
description?: string
effectiveAtDate?: string
}
export interface VantaDownloadDocumentFileParams extends VantaBaseParams {
documentId: string
uploadedFileId: string
}
export interface VantaSubmitDocumentParams extends VantaBaseParams {
documentId: string
}
export interface VantaListPeopleParams extends VantaBaseParams, VantaPaginationParams {
emailAndNameFilter?: string
employmentStatus?: string
groupIdsMatchesAny?: string
tasksSummaryStatusMatchesAny?: string
taskTypeMatchesAny?: string
taskStatusMatchesAny?: string
}
export interface VantaGetPersonParams extends VantaBaseParams {
personId: string
}
export interface VantaListPoliciesParams extends VantaBaseParams, VantaPaginationParams {}
export interface VantaGetPolicyParams extends VantaBaseParams {
policyId: string
}
export interface VantaListMonitoredComputersParams extends VantaBaseParams, VantaPaginationParams {
complianceStatusFilterMatchesAny?: string
}
export interface VantaListRiskScenariosParams extends VantaBaseParams, VantaPaginationParams {
searchString?: string
includeIgnored?: boolean
type?: string
ownerMatchesAny?: string
categoryMatchesAny?: string
ciaCategoryMatchesAny?: string
treatmentTypeMatchesAny?: string
inherentScoreGroupMatchesAny?: string
residualScoreGroupMatchesAny?: string
reviewStatusMatchesAny?: string
orderBy?: string
}
export interface VantaGetRiskScenarioParams extends VantaBaseParams {
riskScenarioId: string
}
export interface VantaListVulnerabilityRemediationsParams
extends VantaBaseParams,
VantaPaginationParams {
integrationId?: string
severity?: string
isRemediatedOnTime?: boolean
remediatedAfterDate?: string
remediatedBeforeDate?: string
}
export interface VantaListVulnerableAssetsParams extends VantaBaseParams, VantaPaginationParams {
q?: string
integrationId?: string
assetType?: string
assetExternalAccountId?: string
}
export interface VantaGetVulnerableAssetParams extends VantaBaseParams {
vulnerableAssetId: string
}
export interface VantaListVendorsParams extends VantaBaseParams, VantaPaginationParams {
name?: string
statusMatchesAny?: string
}
export interface VantaGetVendorParams extends VantaBaseParams {
vendorId: string
}
export interface VantaListVulnerabilitiesParams extends VantaBaseParams, VantaPaginationParams {
q?: string
severity?: string
isFixAvailable?: boolean
isDeactivated?: boolean
includeVulnerabilitiesWithoutSlas?: boolean
packageIdentifier?: string
externalVulnerabilityId?: string
integrationId?: string
vulnerableAssetId?: string
slaDeadlineAfterDate?: string
slaDeadlineBeforeDate?: string
}
export interface VantaPageInfo {
startCursor: string | null
endCursor: string | null
hasNextPage: boolean
hasPreviousPage: boolean
}
export interface VantaOwner {
id: string | null
displayName: string | null
emailAddress: string | null
}
export interface VantaCustomField {
label: string | null
value: string | string[] | null
}
export interface VantaFramework {
id: string | null
displayName: string | null
shorthandName: string | null
description: string | null
numControlsCompleted: number | null
numControlsTotal: number | null
numDocumentsPassing: number | null
numDocumentsTotal: number | null
numTestsPassing: number | null
numTestsTotal: number | null
}
export interface VantaFrameworkRequirementControl {
id: string | null
externalId: string | null
name: string | null
description: string | null
}
export interface VantaFrameworkRequirement {
id: string | null
name: string | null
shorthand: string | null
description: string | null
controls: VantaFrameworkRequirementControl[]
}
export interface VantaFrameworkRequirementCategory {
id: string | null
name: string | null
shorthand: string | null
requirements: VantaFrameworkRequirement[]
}
export interface VantaFrameworkDetail extends VantaFramework {
requirementCategories: VantaFrameworkRequirementCategory[]
}
export interface VantaControl {
id: string | null
externalId: string | null
name: string | null
description: string | null
source: string | null
domains: string[]
owner: VantaOwner | null
role: string | null
customFields: VantaCustomField[]
creationDate: string | null
modificationDate: string | null
}
export interface VantaControlDetail extends VantaControl {
note: string | null
status: string | null
numDocumentsPassing: number | null
numDocumentsTotal: number | null
numTestsPassing: number | null
numTestsTotal: number | null
}
export interface VantaTestVersion {
major: number | null
minor: number | null
}
export interface VantaTestDeactivatedStatusInfo {
isDeactivated: boolean | null
deactivatedReason: string | null
lastUpdatedDate: string | null
}
export interface VantaTestRemediationStatusInfo {
status: string | null
soonestRemediateByDate: string | null
itemCount: number | null
}
export interface VantaTest {
id: string | null
name: string | null
description: string | null
failureDescription: string | null
remediationDescription: string | null
category: string | null
status: string | null
integrations: string[]
lastTestRunDate: string | null
latestFlipDate: string | null
version: VantaTestVersion | null
deactivatedStatusInfo: VantaTestDeactivatedStatusInfo | null
remediationStatusInfo: VantaTestRemediationStatusInfo | null
owner: VantaOwner | null
}
export interface VantaTestEntity {
id: string | null
entityStatus: string | null
displayName: string | null
responseType: string | null
deactivatedReason: string | null
createdDate: string | null
lastUpdatedDate: string | null
}
export interface VantaDocument {
id: string | null
title: string | null
description: string | null
category: string | null
ownerId: string | null
isSensitive: boolean | null
uploadStatus: string | null
uploadStatusDate: string | null
url: string | null
}
export interface VantaDocumentDeactivatedStatus {
isDeactivated: boolean | null
reason: string | null
creationDate: string | null
expiration: string | null
}
export interface VantaDocumentDetail extends VantaDocument {
note: string | null
nextRenewalDate: string | null
renewalCadence: string | null
reminderWindow: string | null
subscribers: string[]
deactivatedStatus: VantaDocumentDeactivatedStatus | null
}
export interface VantaUploadedByActor {
id: string | null
type: string | null
}
export interface VantaUploadedFile {
id: string | null
fileName: string | null
title: string | null
description: string | null
mimeType: string | null
uploadedBy: VantaUploadedByActor | null
creationDate: string | null
updatedDate: string | null
deletionDate: string | null
effectiveDate: string | null
url: string | null
}
export interface VantaPersonName {
first: string | null
last: string | null
display: string | null
}
export interface VantaPersonEmployment {
status: string | null
startDate: string | null
endDate: string | null
jobTitle: string | null
}
export interface VantaPersonLeaveInfo {
status: string | null
startDate: string | null
endDate: string | null
}
export interface VantaPersonTasksSummary {
status: string | null
dueDate: string | null
completionDate: string | null
}
export interface VantaPerson {
id: string | null
userId: string | null
emailAddress: string | null
name: VantaPersonName | null
employment: VantaPersonEmployment | null
leaveInfo: VantaPersonLeaveInfo | null
groupIds: string[]
tasksSummary: VantaPersonTasksSummary | null
}
export interface VantaPolicyDocument {
language: string | null
slugId: string | null
url: string | null
}
export interface VantaPolicyLatestApprovedVersion {
versionId: string | null
documents: VantaPolicyDocument[]
}
export interface VantaPolicy {
id: string | null
name: string | null
description: string | null
status: string | null
approvedAtDate: string | null
latestVersionStatus: string | null
latestApprovedVersion: VantaPolicyLatestApprovedVersion | null
}
export interface VantaVendorAuthDetails {
method: string | null
passwordMFA: boolean | null
passwordMinimumLength: number | null
passwordRequiresNumber: boolean | null
passwordRequiresSymbol: boolean | null
}
export interface VantaVendorContractAmount {
amount: number | null
currency: string | null
}
export interface VantaVendorDecision {
status: string | null
lastUpdatedAt: string | null
}
export interface VantaVendorProcurementRequest {
url: string | null
service: string | null
}
export interface VantaVendor {
id: string | null
name: string | null
status: string | null
websiteUrl: string | null
category: string | null
servicesProvided: string | null
additionalNotes: string | null
accountManagerName: string | null
accountManagerEmail: string | null
securityOwnerUserId: string | null
businessOwnerUserId: string | null
inherentRiskLevel: string | null
residualRiskLevel: string | null
isRiskAutoScored: boolean | null
isVisibleToAuditors: boolean | null
riskAttributeIds: string[]
vendorHeadquarters: string | null
contractStartDate: string | null
contractRenewalDate: string | null
contractTerminationDate: string | null
contractAmount: VantaVendorContractAmount | null
nextSecurityReviewDueDate: string | null
lastSecurityReviewCompletionDate: string | null
authDetails: VantaVendorAuthDetails | null
customFields: VantaCustomField[]
latestDecision: VantaVendorDecision | null
linkedTaskTrackerTaskProcurementRequest: VantaVendorProcurementRequest | null
}
export interface VantaVulnerabilityDeactivateMetadata {
isVulnDeactivatedIndefinitely: boolean | null
deactivatedUntilDate: string | null
deactivationReason: string | null
deactivatedOnDate: string | null
deactivatedBy: string | null
}
export interface VantaVulnerability {
id: string | null
name: string | null
description: string | null
severity: string | null
vulnerabilityType: string | null
integrationId: string | null
targetId: string | null
packageIdentifier: string | null
cvssSeverityScore: number | null
scannerScore: number | null
isFixable: boolean | null
fixedVersion: string | null
remediateByDate: string | null
firstDetectedDate: string | null
sourceDetectedDate: string | null
lastDetectedDate: string | null
scanSource: string | null
externalURL: string | null
relatedVulns: string[]
relatedUrls: string[]
deactivateMetadata: VantaVulnerabilityDeactivateMetadata | null
}
export interface VantaOperatingSystem {
type: string | null
version: string | null
}
export interface VantaMonitoredComputer {
id: string | null
integrationId: string | null
lastCheckDate: string | null
screenlock: string | null
diskEncryption: string | null
passwordManager: string | null
antivirusInstallation: string | null
operatingSystem: VantaOperatingSystem | null
owner: VantaOwner | null
serialNumber: string | null
udid: string | null
}
export interface VantaRiskScenario {
riskId: string | null
description: string | null
likelihood: number | null
impact: number | null
residualLikelihood: number | null
residualImpact: number | null
categories: string[]
ciaCategories: string[]
treatment: string | null
owner: string | null
note: string | null
riskRegister: string | null
customFields: VantaCustomField[]
isArchived: boolean | null
reviewStatus: string | null
requiredApprovers: string[]
type: string | null
identificationDate: string | null
}
export interface VantaVulnerabilityRemediation {
id: string | null
vulnerabilityId: string | null
vulnerableAssetId: string | null
severity: string | null
detectedDate: string | null
slaDeadlineDate: string | null
remediationDate: string | null
}
export interface VantaAssetTag {
key: string | null
value: string | null
}
export interface VantaVulnerableAssetScanner {
resourceId: string | null
integrationId: string | null
targetId: string | null
imageDigest: string | null
imagePushedAtDate: string | null
imageTags: string[]
assetTags: VantaAssetTag[]
parentAccountOrOrganization: string | null
biosUuid: string | null
ipv4s: string[]
ipv6s: string[]
macAddresses: string[]
hostnames: string[]
fqdns: string[]
operatingSystems: string[]
}
export interface VantaVulnerableAsset {
id: string | null
name: string | null
assetType: string | null
hasBeenScanned: boolean | null
imageScanTag: string | null
scanners: VantaVulnerableAssetScanner[]
}
export interface VantaDownloadedFile {
name: string
mimeType: string
data: string
size: number
}
export interface VantaListFrameworksResponse extends ToolResponse {
output: {
frameworks: VantaFramework[]
pageInfo: VantaPageInfo | null
}
}
export interface VantaGetFrameworkResponse extends ToolResponse {
output: {
framework: VantaFrameworkDetail
}
}
export interface VantaListControlsResponse extends ToolResponse {
output: {
controls: VantaControl[]
pageInfo: VantaPageInfo | null
}
}
export interface VantaGetControlResponse extends ToolResponse {
output: {
control: VantaControlDetail
}
}
export interface VantaListTestsResponse extends ToolResponse {
output: {
tests: VantaTest[]
pageInfo: VantaPageInfo | null
}
}
export interface VantaGetTestResponse extends ToolResponse {
output: {
test: VantaTest
}
}
export interface VantaListTestEntitiesResponse extends ToolResponse {
output: {
entities: VantaTestEntity[]
pageInfo: VantaPageInfo | null
}
}
export interface VantaListDocumentsResponse extends ToolResponse {
output: {
documents: VantaDocument[]
pageInfo: VantaPageInfo | null
}
}
export interface VantaGetDocumentResponse extends ToolResponse {
output: {
document: VantaDocumentDetail
}
}
export interface VantaListDocumentUploadsResponse extends ToolResponse {
output: {
uploads: VantaUploadedFile[]
pageInfo: VantaPageInfo | null
}
}
export interface VantaUploadDocumentFileResponse extends ToolResponse {
output: {
upload: VantaUploadedFile
}
}
export interface VantaDownloadDocumentFileResponse extends ToolResponse {
output: {
file: VantaDownloadedFile
name: string
mimeType: string
size: number
}
}
export interface VantaSubmitDocumentResponse extends ToolResponse {
output: {
documentId: string
submitted: boolean
}
}
export interface VantaGetPersonResponse extends ToolResponse {
output: {
person: VantaPerson
}
}
export interface VantaGetPolicyResponse extends ToolResponse {
output: {
policy: VantaPolicy
}
}
export interface VantaListMonitoredComputersResponse extends ToolResponse {
output: {
computers: VantaMonitoredComputer[]
pageInfo: VantaPageInfo | null
}
}
export interface VantaListRiskScenariosResponse extends ToolResponse {
output: {
riskScenarios: VantaRiskScenario[]
pageInfo: VantaPageInfo | null
}
}
export interface VantaGetRiskScenarioResponse extends ToolResponse {
output: {
riskScenario: VantaRiskScenario
}
}
export interface VantaListVulnerabilityRemediationsResponse extends ToolResponse {
output: {
remediations: VantaVulnerabilityRemediation[]
pageInfo: VantaPageInfo | null
}
}
export interface VantaListVulnerableAssetsResponse extends ToolResponse {
output: {
assets: VantaVulnerableAsset[]
pageInfo: VantaPageInfo | null
}
}
export interface VantaGetVulnerableAssetResponse extends ToolResponse {
output: {
asset: VantaVulnerableAsset
}
}
export interface VantaListPeopleResponse extends ToolResponse {
output: {
people: VantaPerson[]
pageInfo: VantaPageInfo | null
}
}
export interface VantaListPoliciesResponse extends ToolResponse {
output: {
policies: VantaPolicy[]
pageInfo: VantaPageInfo | null
}
}
export interface VantaListVendorsResponse extends ToolResponse {
output: {
vendors: VantaVendor[]
pageInfo: VantaPageInfo | null
}
}
export interface VantaGetVendorResponse extends ToolResponse {
output: {
vendor: VantaVendor
}
}
export interface VantaListVulnerabilitiesResponse extends ToolResponse {
output: {
vulnerabilities: VantaVulnerability[]
pageInfo: VantaPageInfo | null
}
}
export type VantaResponse =
| VantaListFrameworksResponse
| VantaGetFrameworkResponse
| VantaListControlsResponse
| VantaGetControlResponse
| VantaListTestsResponse
| VantaGetTestResponse
| VantaListTestEntitiesResponse
| VantaListDocumentsResponse
| VantaGetDocumentResponse
| VantaListDocumentUploadsResponse
| VantaUploadDocumentFileResponse
| VantaDownloadDocumentFileResponse
| VantaSubmitDocumentResponse
| VantaListPeopleResponse
| VantaGetPersonResponse
| VantaListPoliciesResponse
| VantaGetPolicyResponse
| VantaListVendorsResponse
| VantaGetVendorResponse
| VantaListMonitoredComputersResponse
| VantaListVulnerabilitiesResponse
| VantaListVulnerabilityRemediationsResponse
| VantaListVulnerableAssetsResponse
| VantaGetVulnerableAssetResponse
| VantaListRiskScenariosResponse
| VantaGetRiskScenarioResponse
@@ -0,0 +1,112 @@
import type { ToolConfig } from '@/tools/types'
import { VANTA_UPLOADED_FILE_OUTPUT_PROPERTIES } from '@/tools/vanta/outputs'
import type {
VantaUploadDocumentFileParams,
VantaUploadDocumentFileResponse,
} from '@/tools/vanta/types'
import { createVantaTransformResponse } from '@/tools/vanta/utils'
export const vantaUploadDocumentFileTool: ToolConfig<
VantaUploadDocumentFileParams,
VantaUploadDocumentFileResponse
> = {
id: 'vanta_upload_document_file',
name: 'Vanta Upload Document File',
description:
'Upload an evidence file to a Vanta document. Requires credentials with the vanta-api.documents:upload scope.',
version: '1.0.0',
params: {
clientId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client ID',
},
clientSecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Vanta OAuth application client secret',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Vanta API region: "us" (api.vanta.com, default) or "gov" (api.vanta-gov.com)',
},
documentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique ID of the document to attach the file to',
},
file: {
type: 'file',
required: false,
visibility: 'user-or-llm',
description: 'The evidence file to upload',
},
fileContent: {
type: 'string',
required: false,
visibility: 'hidden',
description: 'Base64-encoded file content (alternative to file)',
},
fileName: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional file name override',
},
mimeType: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'MIME type of the file (e.g., application/pdf); used when uploading base64 content, since uploaded files already carry their own type',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Description of the uploaded evidence (e.g., "Q3 access review evidence")',
},
effectiveAtDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'ISO 8601 date indicating when the document is effective from',
},
},
request: {
url: '/api/tools/vanta/upload',
method: 'POST',
headers: () => ({ 'Content-Type': 'application/json' }),
body: (params) => ({
clientId: params.clientId,
clientSecret: params.clientSecret,
region: params.region,
documentId: params.documentId,
file: params.file,
fileContent: params.fileContent,
fileName: params.fileName,
mimeType: params.mimeType,
description: params.description,
effectiveAtDate: params.effectiveAtDate,
}),
},
transformResponse: createVantaTransformResponse<VantaUploadDocumentFileResponse>(
'Failed to upload file to Vanta document'
),
outputs: {
upload: {
type: 'json',
description: 'Metadata of the uploaded file',
properties: VANTA_UPLOADED_FILE_OUTPUT_PROPERTIES,
},
},
}
+799
View File
@@ -0,0 +1,799 @@
import type {
VantaControl,
VantaControlDetail,
VantaCustomField,
VantaDocument,
VantaDocumentDetail,
VantaFramework,
VantaFrameworkDetail,
VantaFrameworkRequirement,
VantaFrameworkRequirementCategory,
VantaFrameworkRequirementControl,
VantaMonitoredComputer,
VantaOwner,
VantaPageInfo,
VantaPerson,
VantaPolicy,
VantaPolicyDocument,
VantaRegion,
VantaRiskScenario,
VantaTest,
VantaTestEntity,
VantaUploadedFile,
VantaVendor,
VantaVulnerability,
VantaVulnerabilityRemediation,
VantaVulnerableAsset,
VantaVulnerableAssetScanner,
} from '@/tools/vanta/types'
export const VANTA_API_BASE_URLS: Record<VantaRegion, string> = {
us: 'https://api.vanta.com',
gov: 'https://api.vanta-gov.com',
}
/** Read-only scope used by every query and download operation. */
export const VANTA_READ_SCOPE = 'vanta-api.all:read'
/** Read-write scope used by write operations that do not upload files. */
export const VANTA_WRITE_SCOPE = 'vanta-api.all:read vanta-api.all:write'
/**
* Scope string for document evidence uploads, taken verbatim from Vanta's
* "Upload a document" guide (the upload scope cannot be requested alone).
*/
export const VANTA_DOCUMENT_UPLOAD_SCOPE =
'vanta-api.all:read vanta-api.all:write vanta-api.documents:upload'
export function getVantaBaseUrl(region: VantaRegion | undefined): string {
return VANTA_API_BASE_URLS[region ?? 'us']
}
export const VANTA_QUERY_ROUTE = '/api/tools/vanta/query'
/**
* Builds the standard transformResponse for Vanta tools, which call internal
* API routes that return `{ success, output }` JSON or `{ success: false,
* error }` on failure.
*/
export function createVantaTransformResponse<R extends { success: boolean; output: unknown }>(
fallbackError: string
) {
return async (response: Response): Promise<R> => {
const data = await response.json()
if (!response.ok || data.success === false) {
throw new Error(data.error || fallbackError)
}
return { success: true, output: data.output } as R
}
}
type JsonRecord = Record<string, unknown>
function isJsonRecord(value: unknown): value is JsonRecord {
return typeof value === 'object' && value !== null && !Array.isArray(value)
}
/**
* Coerces an unknown single-resource response body to a record so the
* normalizers can run on it; non-object bodies normalize to all-null fields.
*/
export function asVantaRecord(value: unknown): JsonRecord {
return isJsonRecord(value) ? value : {}
}
function getString(value: unknown): string | null {
return typeof value === 'string' ? value : null
}
function getNumber(value: unknown): number | null {
return typeof value === 'number' && Number.isFinite(value) ? value : null
}
function getBoolean(value: unknown): boolean | null {
return typeof value === 'boolean' ? value : null
}
function getStringArray(value: unknown): string[] {
if (!Array.isArray(value)) return []
return value.filter((entry): entry is string => typeof entry === 'string')
}
function getRecordArray(value: unknown): JsonRecord[] {
if (!Array.isArray(value)) return []
return value.filter(isJsonRecord)
}
/**
* Extracts a human-readable error message from a Vanta API error body.
*/
export function extractVantaError(data: unknown, fallback: string): string {
if (!isJsonRecord(data)) return fallback
if (isJsonRecord(data.error)) {
const nested = getString(data.error.message) ?? getString(data.error.code)
if (nested) return nested
}
return (
getString(data.message) ??
getString(data.error_description) ??
getString(data.error) ??
fallback
)
}
export interface VantaTokenParams {
clientId: string
clientSecret: string
region?: VantaRegion
scope: string
}
interface VantaCachedToken {
token: string
expiresAt: number
}
/**
* In-memory token cache. Vanta only keeps one access token active per
* application — requesting a new token revokes the previous one — so reusing
* a cached token keeps concurrent tool executions with the same credentials
* from revoking each other's tokens mid-flight.
*/
const vantaTokenCache = new Map<string, VantaCachedToken>()
/**
* In-flight token exchanges, keyed like the cache. Concurrent callers that
* miss the cache join the same exchange instead of issuing competing ones
* that would revoke each other's tokens.
*/
const vantaTokenExchanges = new Map<string, Promise<string>>()
/** Evict cached tokens well before their one-hour expiry. */
const VANTA_TOKEN_EXPIRY_BUFFER_MS = 10 * 60 * 1000
/**
* Derives the cache key for a credential set. The client secret is included
* only as a SHA-256 digest so plaintext secrets never persist in the
* long-lived cache maps.
*/
async function vantaTokenCacheKey(params: VantaTokenParams): Promise<string> {
const digest = await crypto.subtle.digest(
'SHA-256',
new TextEncoder().encode(`${params.clientId}:${params.clientSecret}`)
)
const secretHash = Array.from(new Uint8Array(digest))
.map((byte) => byte.toString(16).padStart(2, '0'))
.join('')
return [params.region ?? 'us', params.scope, params.clientId, secretHash].join('|')
}
async function exchangeVantaToken(params: VantaTokenParams, cacheKey: string): Promise<string> {
const response = await fetch(`${getVantaBaseUrl(params.region)}/oauth/token`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
client_id: params.clientId,
client_secret: params.clientSecret,
scope: params.scope,
grant_type: 'client_credentials',
}),
cache: 'no-store',
})
const data: unknown = await response.json().catch(() => null)
if (!response.ok) {
throw new Error(extractVantaError(data, 'Failed to authenticate with Vanta'))
}
if (!isJsonRecord(data) || typeof data.access_token !== 'string') {
throw new Error('Vanta authentication did not return an access token')
}
const expiresInMs = (getNumber(data.expires_in) ?? 0) * 1000
if (expiresInMs > VANTA_TOKEN_EXPIRY_BUFFER_MS) {
vantaTokenCache.set(cacheKey, {
token: data.access_token,
expiresAt: Date.now() + expiresInMs - VANTA_TOKEN_EXPIRY_BUFFER_MS,
})
}
return data.access_token
}
/**
* Returns a bearer token for the Vanta API, exchanging OAuth client
* credentials and caching the result until shortly before expiry. Concurrent
* callers share a single in-flight exchange. Pass `forceRefresh` when a
* cached token has been revoked (e.g., by another process exchanging the
* same credentials); a force refresh still joins any exchange already in
* flight, since that exchange yields an equally fresh token.
*/
export async function getVantaAccessToken(
params: VantaTokenParams,
options?: { forceRefresh?: boolean }
): Promise<string> {
const cacheKey = await vantaTokenCacheKey(params)
if (!options?.forceRefresh) {
const cached = vantaTokenCache.get(cacheKey)
if (cached && cached.expiresAt > Date.now()) {
return cached.token
}
}
const inFlight = vantaTokenExchanges.get(cacheKey)
if (inFlight) {
return inFlight
}
vantaTokenCache.delete(cacheKey)
const exchange = exchangeVantaToken(params, cacheKey)
vantaTokenExchanges.set(cacheKey, exchange)
try {
return await exchange
} finally {
vantaTokenExchanges.delete(cacheKey)
}
}
/**
* Performs an authenticated Vanta API request. When the request comes back
* 401 — typically because another process exchanged the same credentials and
* revoked the cached token — it retries once with a freshly exchanged token.
*/
export async function fetchVantaWithAuth(
tokenParams: VantaTokenParams,
doFetch: (accessToken: string) => Promise<Response>
): Promise<Response> {
const accessToken = await getVantaAccessToken(tokenParams)
const response = await doFetch(accessToken)
if (response.status !== 401) {
return response
}
const freshToken = await getVantaAccessToken(tokenParams, { forceRefresh: true })
return doFetch(freshToken)
}
/**
* Builds a Vanta v1 API URL, appending only query parameters that have a
* value. Array values are appended as repeated parameters.
*/
export function buildVantaUrl(
baseUrl: string,
path: string,
query?: Record<string, string | number | boolean | string[] | null | undefined>
): string {
const url = new URL(`${baseUrl}/v1${path}`)
if (query) {
for (const [key, value] of Object.entries(query)) {
if (value == null || value === '') continue
if (Array.isArray(value)) {
for (const entry of value) {
url.searchParams.append(key, entry)
}
} else {
url.searchParams.set(key, String(value))
}
}
}
return url.toString()
}
/**
* Splits a comma-separated filter value into trimmed entries, returning
* undefined when no usable entries remain.
*/
export function splitVantaCommaList(value: string | null | undefined): string[] | undefined {
if (!value) return undefined
const entries = value
.split(',')
.map((entry) => entry.trim())
.filter(Boolean)
return entries.length > 0 ? entries : undefined
}
/**
* Unwraps the `{ results: { data, pageInfo } }` envelope that every Vanta
* list endpoint returns.
*/
export function getVantaListResults(data: unknown): {
data: JsonRecord[]
pageInfo: VantaPageInfo | null
} {
if (!isJsonRecord(data) || !isJsonRecord(data.results)) {
return { data: [], pageInfo: null }
}
return {
data: getRecordArray(data.results.data),
pageInfo: normalizeVantaPageInfo(data.results.pageInfo),
}
}
export function normalizeVantaPageInfo(value: unknown): VantaPageInfo | null {
if (!isJsonRecord(value)) return null
return {
startCursor: getString(value.startCursor),
endCursor: getString(value.endCursor),
hasNextPage: getBoolean(value.hasNextPage) ?? false,
hasPreviousPage: getBoolean(value.hasPreviousPage) ?? false,
}
}
function normalizeVantaOwner(value: unknown): VantaOwner | null {
if (!isJsonRecord(value)) return null
return {
id: getString(value.id),
displayName: getString(value.displayName),
emailAddress: getString(value.emailAddress),
}
}
function normalizeVantaCustomFields(value: unknown): VantaCustomField[] {
return getRecordArray(value).map((field) => ({
label: getString(field.label),
value: Array.isArray(field.value) ? getStringArray(field.value) : getString(field.value),
}))
}
export function normalizeVantaFramework(resource: JsonRecord): VantaFramework {
return {
id: getString(resource.id),
displayName: getString(resource.displayName),
shorthandName: getString(resource.shorthandName),
description: getString(resource.description),
numControlsCompleted: getNumber(resource.numControlsCompleted),
numControlsTotal: getNumber(resource.numControlsTotal),
numDocumentsPassing: getNumber(resource.numDocumentsPassing),
numDocumentsTotal: getNumber(resource.numDocumentsTotal),
numTestsPassing: getNumber(resource.numTestsPassing),
numTestsTotal: getNumber(resource.numTestsTotal),
}
}
function normalizeVantaFrameworkRequirementControl(
resource: JsonRecord
): VantaFrameworkRequirementControl {
return {
id: getString(resource.id),
externalId: getString(resource.externalId),
name: getString(resource.name),
description: getString(resource.description),
}
}
function normalizeVantaFrameworkRequirement(resource: JsonRecord): VantaFrameworkRequirement {
return {
id: getString(resource.id),
name: getString(resource.name),
shorthand: getString(resource.shorthand),
description: getString(resource.description),
controls: getRecordArray(resource.controls).map(normalizeVantaFrameworkRequirementControl),
}
}
function normalizeVantaFrameworkRequirementCategory(
resource: JsonRecord
): VantaFrameworkRequirementCategory {
return {
id: getString(resource.id),
name: getString(resource.name),
shorthand: getString(resource.shorthand),
requirements: getRecordArray(resource.requirements).map(normalizeVantaFrameworkRequirement),
}
}
export function normalizeVantaFrameworkDetail(resource: JsonRecord): VantaFrameworkDetail {
return {
...normalizeVantaFramework(resource),
requirementCategories: getRecordArray(resource.requirementCategories).map(
normalizeVantaFrameworkRequirementCategory
),
}
}
export function normalizeVantaControl(resource: JsonRecord): VantaControl {
return {
id: getString(resource.id),
externalId: getString(resource.externalId),
name: getString(resource.name),
description: getString(resource.description),
source: getString(resource.source),
domains: getStringArray(resource.domains),
owner: normalizeVantaOwner(resource.owner),
role: getString(resource.role),
customFields: normalizeVantaCustomFields(resource.customFields),
creationDate: getString(resource.creationDate),
modificationDate: getString(resource.modificationDate),
}
}
export function normalizeVantaControlDetail(resource: JsonRecord): VantaControlDetail {
return {
...normalizeVantaControl(resource),
note: getString(resource.note),
status: getString(resource.status),
numDocumentsPassing: getNumber(resource.numDocumentsPassing),
numDocumentsTotal: getNumber(resource.numDocumentsTotal),
numTestsPassing: getNumber(resource.numTestsPassing),
numTestsTotal: getNumber(resource.numTestsTotal),
}
}
export function normalizeVantaTest(resource: JsonRecord): VantaTest {
const version = isJsonRecord(resource.version)
? { major: getNumber(resource.version.major), minor: getNumber(resource.version.minor) }
: null
const deactivatedStatusInfo = isJsonRecord(resource.deactivatedStatusInfo)
? {
isDeactivated: getBoolean(resource.deactivatedStatusInfo.isDeactivated),
deactivatedReason: getString(resource.deactivatedStatusInfo.deactivatedReason),
lastUpdatedDate: getString(resource.deactivatedStatusInfo.lastUpdatedDate),
}
: null
const remediationStatusInfo = isJsonRecord(resource.remediationStatusInfo)
? {
status: getString(resource.remediationStatusInfo.status),
soonestRemediateByDate: getString(resource.remediationStatusInfo.soonestRemediateByDate),
itemCount: getNumber(resource.remediationStatusInfo.itemCount),
}
: null
return {
id: getString(resource.id),
name: getString(resource.name),
description: getString(resource.description),
failureDescription: getString(resource.failureDescription),
remediationDescription: getString(resource.remediationDescription),
category: getString(resource.category),
status: getString(resource.status),
integrations: getStringArray(resource.integrations),
lastTestRunDate: getString(resource.lastTestRunDate),
latestFlipDate: getString(resource.latestFlipDate),
version,
deactivatedStatusInfo,
remediationStatusInfo,
owner: normalizeVantaOwner(resource.owner),
}
}
export function normalizeVantaTestEntity(resource: JsonRecord): VantaTestEntity {
return {
id: getString(resource.id),
entityStatus: getString(resource.entityStatus),
displayName: getString(resource.displayName),
responseType: getString(resource.responseType),
deactivatedReason: getString(resource.deactivatedReason),
createdDate: getString(resource.createdDate),
lastUpdatedDate: getString(resource.lastUpdatedDate),
}
}
export function normalizeVantaDocument(resource: JsonRecord): VantaDocument {
return {
id: getString(resource.id),
title: getString(resource.title),
description: getString(resource.description),
category: getString(resource.category),
ownerId: getString(resource.ownerId),
isSensitive: getBoolean(resource.isSensitive),
uploadStatus: getString(resource.uploadStatus),
uploadStatusDate: getString(resource.uploadStatusDate),
url: getString(resource.url),
}
}
export function normalizeVantaDocumentDetail(resource: JsonRecord): VantaDocumentDetail {
const deactivatedStatus = isJsonRecord(resource.deactivatedStatus)
? {
isDeactivated: getBoolean(resource.deactivatedStatus.isDeactivated),
reason: getString(resource.deactivatedStatus.reason),
creationDate: getString(resource.deactivatedStatus.creationDate),
expiration: getString(resource.deactivatedStatus.expiration),
}
: null
return {
...normalizeVantaDocument(resource),
note: getString(resource.note),
nextRenewalDate: getString(resource.nextRenewalDate),
renewalCadence: getString(resource.renewalCadence),
reminderWindow: getString(resource.reminderWindow),
subscribers: getStringArray(resource.subscribers),
deactivatedStatus,
}
}
export function normalizeVantaUploadedFile(resource: JsonRecord): VantaUploadedFile {
const uploadedBy = isJsonRecord(resource.uploadedBy)
? { id: getString(resource.uploadedBy.id), type: getString(resource.uploadedBy.type) }
: null
return {
id: getString(resource.id),
fileName: getString(resource.fileName),
title: getString(resource.title),
description: getString(resource.description),
mimeType: getString(resource.mimeType),
uploadedBy,
creationDate: getString(resource.creationDate),
updatedDate: getString(resource.updatedDate),
deletionDate: getString(resource.deletionDate),
effectiveDate: getString(resource.effectiveDate),
url: getString(resource.url),
}
}
export function normalizeVantaPerson(resource: JsonRecord): VantaPerson {
const name = isJsonRecord(resource.name)
? {
first: getString(resource.name.first),
last: getString(resource.name.last),
display: getString(resource.name.display),
}
: null
const employment = isJsonRecord(resource.employment)
? {
status: getString(resource.employment.status),
startDate: getString(resource.employment.startDate),
endDate: getString(resource.employment.endDate),
jobTitle: getString(resource.employment.jobTitle),
}
: null
const leaveInfo = isJsonRecord(resource.leaveInfo)
? {
status: getString(resource.leaveInfo.status),
startDate: getString(resource.leaveInfo.startDate),
endDate: getString(resource.leaveInfo.endDate),
}
: null
const tasksSummary = isJsonRecord(resource.tasksSummary)
? {
status: getString(resource.tasksSummary.status),
dueDate: getString(resource.tasksSummary.dueDate),
completionDate: getString(resource.tasksSummary.completionDate),
}
: null
return {
id: getString(resource.id),
userId: getString(resource.userId),
emailAddress: getString(resource.emailAddress),
name,
employment,
leaveInfo,
groupIds: getStringArray(resource.groupIds),
tasksSummary,
}
}
function normalizeVantaPolicyDocument(resource: JsonRecord): VantaPolicyDocument {
return {
language: getString(resource.language),
slugId: getString(resource.slugId),
url: getString(resource.url),
}
}
export function normalizeVantaPolicy(resource: JsonRecord): VantaPolicy {
const latestApprovedVersion = isJsonRecord(resource.latestApprovedVersion)
? {
versionId: getString(resource.latestApprovedVersion.versionId),
documents: getRecordArray(resource.latestApprovedVersion.documents).map(
normalizeVantaPolicyDocument
),
}
: null
return {
id: getString(resource.id),
name: getString(resource.name),
description: getString(resource.description),
status: getString(resource.status),
approvedAtDate: getString(resource.approvedAtDate),
latestVersionStatus: isJsonRecord(resource.latestVersion)
? getString(resource.latestVersion.status)
: null,
latestApprovedVersion,
}
}
export function normalizeVantaVendor(resource: JsonRecord): VantaVendor {
const authDetails = isJsonRecord(resource.authDetails)
? {
method: getString(resource.authDetails.method),
passwordMFA: getBoolean(resource.authDetails.passwordMFA),
passwordMinimumLength: getNumber(resource.authDetails.passwordMinimumLength),
passwordRequiresNumber: getBoolean(resource.authDetails.passwordRequiresNumber),
passwordRequiresSymbol: getBoolean(resource.authDetails.passwordRequiresSymbol),
}
: null
const contractAmount = isJsonRecord(resource.contractAmount)
? {
amount: getNumber(resource.contractAmount.amount),
currency: getString(resource.contractAmount.currency),
}
: null
const latestDecision = isJsonRecord(resource.latestDecision)
? {
status: getString(resource.latestDecision.status),
lastUpdatedAt: getString(resource.latestDecision.lastUpdatedAt),
}
: null
const procurementRequest = isJsonRecord(resource.linkedTaskTrackerTaskProcurementRequest)
? {
url: getString(resource.linkedTaskTrackerTaskProcurementRequest.url),
service: getString(resource.linkedTaskTrackerTaskProcurementRequest.service),
}
: null
return {
id: getString(resource.id),
name: getString(resource.name),
status: getString(resource.status),
websiteUrl: getString(resource.websiteUrl),
category: isJsonRecord(resource.category) ? getString(resource.category.displayName) : null,
servicesProvided: getString(resource.servicesProvided),
additionalNotes: getString(resource.additionalNotes),
accountManagerName: getString(resource.accountManagerName),
accountManagerEmail: getString(resource.accountManagerEmail),
securityOwnerUserId: getString(resource.securityOwnerUserId),
businessOwnerUserId: getString(resource.businessOwnerUserId),
inherentRiskLevel: getString(resource.inherentRiskLevel),
residualRiskLevel: getString(resource.residualRiskLevel),
isRiskAutoScored: getBoolean(resource.isRiskAutoScored),
isVisibleToAuditors: getBoolean(resource.isVisibleToAuditors),
riskAttributeIds: getStringArray(resource.riskAttributeIds),
vendorHeadquarters: getString(resource.vendorHeadquarters),
contractStartDate: getString(resource.contractStartDate),
contractRenewalDate: getString(resource.contractRenewalDate),
contractTerminationDate: getString(resource.contractTerminationDate),
contractAmount,
nextSecurityReviewDueDate: getString(resource.nextSecurityReviewDueDate),
lastSecurityReviewCompletionDate: getString(resource.lastSecurityReviewCompletionDate),
authDetails,
customFields: normalizeVantaCustomFields(resource.customFields),
latestDecision,
linkedTaskTrackerTaskProcurementRequest: procurementRequest,
}
}
function getComputerStatusOutcome(value: unknown): string | null {
return isJsonRecord(value) ? getString(value.outcome) : null
}
export function normalizeVantaMonitoredComputer(resource: JsonRecord): VantaMonitoredComputer {
const operatingSystem = isJsonRecord(resource.operatingSystem)
? {
type: getString(resource.operatingSystem.type),
version: getString(resource.operatingSystem.version),
}
: null
return {
id: getString(resource.id),
integrationId: getString(resource.integrationId),
lastCheckDate: getString(resource.lastCheckDate),
screenlock: getComputerStatusOutcome(resource.screenlock),
diskEncryption: getComputerStatusOutcome(resource.diskEncryption),
passwordManager: getComputerStatusOutcome(resource.passwordManager),
antivirusInstallation: getComputerStatusOutcome(resource.antivirusInstallation),
operatingSystem,
owner: normalizeVantaOwner(resource.owner),
serialNumber: getString(resource.serialNumber),
udid: getString(resource.udid),
}
}
export function normalizeVantaRiskScenario(resource: JsonRecord): VantaRiskScenario {
return {
riskId: getString(resource.riskId),
description: getString(resource.description),
likelihood: getNumber(resource.likelihood),
impact: getNumber(resource.impact),
residualLikelihood: getNumber(resource.residualLikelihood),
residualImpact: getNumber(resource.residualImpact),
categories: getStringArray(resource.categories),
ciaCategories: getStringArray(resource.ciaCategories),
treatment: getString(resource.treatment),
owner: getString(resource.owner),
note: getString(resource.note),
riskRegister: getString(resource.riskRegister),
customFields: normalizeVantaCustomFields(resource.customFields),
isArchived: getBoolean(resource.isArchived),
reviewStatus: getString(resource.reviewStatus),
requiredApprovers: getStringArray(resource.requiredApprovers),
type: getString(resource.type),
identificationDate: getString(resource.identificationDate),
}
}
export function normalizeVantaVulnerabilityRemediation(
resource: JsonRecord
): VantaVulnerabilityRemediation {
return {
id: getString(resource.id),
vulnerabilityId: getString(resource.vulnerabilityId),
vulnerableAssetId: getString(resource.vulnerableAssetId),
severity: getString(resource.severity),
detectedDate: getString(resource.detectedDate),
slaDeadlineDate: getString(resource.slaDeadlineDate),
remediationDate: getString(resource.remediationDate),
}
}
function normalizeVantaVulnerableAssetScanner(resource: JsonRecord): VantaVulnerableAssetScanner {
return {
resourceId: getString(resource.resourceId),
integrationId: getString(resource.integrationId),
targetId: getString(resource.targetId),
imageDigest: getString(resource.imageDigest),
imagePushedAtDate: getString(resource.imagePushedAtDate),
imageTags: getStringArray(resource.imageTags),
assetTags: getRecordArray(resource.assetTags).map((tag) => ({
key: getString(tag.key),
value: getString(tag.value),
})),
parentAccountOrOrganization: getString(resource.parentAccountOrOrganization),
biosUuid: getString(resource.biosUuid),
ipv4s: getStringArray(resource.ipv4s),
ipv6s: getStringArray(resource.ipv6s),
macAddresses: getStringArray(resource.macAddresses),
hostnames: getStringArray(resource.hostnames),
fqdns: getStringArray(resource.fqdns),
operatingSystems: getStringArray(resource.operatingSystems),
}
}
export function normalizeVantaVulnerableAsset(resource: JsonRecord): VantaVulnerableAsset {
return {
id: getString(resource.id),
name: getString(resource.name),
assetType: getString(resource.assetType),
hasBeenScanned: getBoolean(resource.hasBeenScanned),
imageScanTag: getString(resource.imageScanTag),
scanners: getRecordArray(resource.scanners).map(normalizeVantaVulnerableAssetScanner),
}
}
export function normalizeVantaVulnerability(resource: JsonRecord): VantaVulnerability {
const deactivateMetadata = isJsonRecord(resource.deactivateMetadata)
? {
isVulnDeactivatedIndefinitely: getBoolean(
resource.deactivateMetadata.isVulnDeactivatedIndefinitely
),
deactivatedUntilDate: getString(resource.deactivateMetadata.deactivatedUntilDate),
deactivationReason: getString(resource.deactivateMetadata.deactivationReason),
deactivatedOnDate: getString(resource.deactivateMetadata.deactivatedOnDate),
deactivatedBy: getString(resource.deactivateMetadata.deactivatedBy),
}
: null
return {
id: getString(resource.id),
name: getString(resource.name),
description: getString(resource.description),
severity: getString(resource.severity),
vulnerabilityType: getString(resource.vulnerabilityType),
integrationId: getString(resource.integrationId),
targetId: getString(resource.targetId),
packageIdentifier: getString(resource.packageIdentifier),
cvssSeverityScore: getNumber(resource.cvssSeverityScore),
scannerScore: getNumber(resource.scannerScore),
isFixable: getBoolean(resource.isFixable),
fixedVersion: getString(resource.fixedVersion),
remediateByDate: getString(resource.remediateByDate),
firstDetectedDate: getString(resource.firstDetectedDate),
sourceDetectedDate: getString(resource.sourceDetectedDate),
lastDetectedDate: getString(resource.lastDetectedDate),
scanSource: getString(resource.scanSource),
externalURL: getString(resource.externalURL),
relatedVulns: getStringArray(resource.relatedVulns),
relatedUrls: getStringArray(resource.relatedUrls),
deactivateMetadata,
}
}
+2 -2
View File
@@ -9,8 +9,8 @@ const QUERY_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/queries')
const SELECTOR_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/selectors')
const BASELINE = {
totalRoutes: 816,
zodRoutes: 816,
totalRoutes: 819,
zodRoutes: 819,
nonZodRoutes: 0,
} as const