diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index dc1290d..c408fe2 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,18 +1,18 @@ { - "name": "Ona", - "image": "mcr.microsoft.com/devcontainers/base:2.0.4-noble", - "containerEnv": { - "DO_NOT_TRACK": "1", - "NO_UPDATE_NOTIFIER": "1", - "COREPACK_ENABLE_DOWNLOAD_PROMPT": "0" + "name": "Ona", + "image": "mcr.microsoft.com/devcontainers/base:2.0.4-noble", + "containerEnv": { + "DO_NOT_TRACK": "1", + "NO_UPDATE_NOTIFIER": "1", + "COREPACK_ENABLE_DOWNLOAD_PROMPT": "0" + }, + "postCreateCommand": ".devcontainer/lifecycle/post-create.sh", + "remoteUser": "vscode", + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "22", + "pnpmVersion": "none" }, - "postCreateCommand": ".devcontainer/lifecycle/post-create.sh", - "remoteUser": "vscode", - "features": { - "ghcr.io/devcontainers/features/node:1": { - "version": "22", - "pnpmVersion": "none" - }, - "ghcr.io/devcontainers/features/github-cli:1": {} - } + "ghcr.io/devcontainers/features/github-cli:1": {} + } } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7762ac8..bcbdfad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,9 @@ jobs: - name: Generate API client run: pnpm generate + - name: Check formatting + run: pnpm format:check + - name: Typecheck run: pnpm typecheck diff --git a/.oxfmtrc.json b/.oxfmtrc.json new file mode 100644 index 0000000..ee00633 --- /dev/null +++ b/.oxfmtrc.json @@ -0,0 +1,5 @@ +{ + "$schema": "./node_modules/oxfmt/configuration_schema.json", + "printWidth": 80, + "ignorePatterns": ["*.md", "api-spec.json", "pnpm-lock.yaml"] +} diff --git a/AGENTS.md b/AGENTS.md index 59dbab6..089ce40 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,6 +14,10 @@ We map from the REST api path to a command structure for CLI with the following - Use the same placeholder for common inputs: `` for IDs, `` for date-times, `` for date-only values, `` for true/false, `` for search terms, `` for inline JSON, `` for local files, and `` for other free text. - Mark repeatable flags `(repeatable)`. Describe timestamps as “ISO 8601 timestamp”; avoid repeated format examples. +# Formatting + +- Run `pnpm format` (oxfmt) before committing; CI runs `pnpm format:check`. Markdown is not formatted. + # Testing - Test changes end to end when modifying the CLI. Build the binary and test the commands. diff --git a/package.json b/package.json index b2a1e66..008da44 100644 --- a/package.json +++ b/package.json @@ -2,26 +2,24 @@ "name": "@vanta/cli", "version": "0.2.0", "description": "Vanta CLI — manage compliance resources from the terminal", - "type": "module", + "license": "SEE LICENSE IN LICENSE", "bin": { "vanta": "./dist/cli.js" }, "files": [ "dist" ], + "type": "module", "scripts": { "generate": "openapi-ts", "dev": "tsx src/cli.ts", "build": "pnpm run generate && tsup", "typecheck": "tsc --noEmit", "test": "node --import tsx --test 'src/**/*.test.ts'", - "build:binaries": "tsx scripts/build-binaries.ts" - }, - "packageManager": "pnpm@12.6.0", - "engines": { - "node": ">=22" + "build:binaries": "tsx scripts/build-binaries.ts", + "format": "oxfmt", + "format:check": "oxfmt --check" }, - "license": "SEE LICENSE IN LICENSE", "dependencies": { "@napi-rs/keyring": "^1.3.0", "@toon-format/toon": "^0.8.0", @@ -31,8 +29,13 @@ "@hey-api/openapi-ts": "^0.85.0", "@types/node": "^22.15.0", "bun": "^1.3.14", + "oxfmt": "0.72.0", "tsup": "^8.5.0", "tsx": "^4.20.0", "typescript": "^5.8.0" - } + }, + "engines": { + "node": ">=22" + }, + "packageManager": "pnpm@12.6.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 28d8b45..d3ded7e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -185,6 +185,9 @@ importers: bun: specifier: ^1.3.14 version: 1.3.14 + oxfmt: + specifier: 0.72.0 + version: 0.72.0 tsup: specifier: ^8.5.0 version: 8.5.1(jiti@2.7.0)(tsx@4.23.12)(typescript@5.9.3) @@ -710,6 +713,128 @@ packages: cpu: [x64] os: [win32] + '@oxfmt/binding-android-arm-eabi@0.72.0': + resolution: {integrity: sha512-u4U1uaDOVBuorGNC/07NLm48nECHOiJJka002YGML16Md2DRvf38RGBt01lH60EOGvNlFVmbLoksQedNBoZHKw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxfmt/binding-android-arm64@0.72.0': + resolution: {integrity: sha512-GCnM+Ae2mWOKC+92y3FOb6eZJeVnBAVz82e3lITUUg+kxukYKzBNAvJ/hhHIfa2A0md55SYYhdWPddSSy3KPVA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxfmt/binding-darwin-arm64@0.72.0': + resolution: {integrity: sha512-LjQ8tlevdtwraFlWC6AnQ1Forzde0clRmnsP3QmK+ydSElDt/J+5Jc+m+//Ly1G97aP7WCNUw110QMIUw2K7xA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxfmt/binding-darwin-x64@0.72.0': + resolution: {integrity: sha512-+ZbcxhB1C34RQR5IldSyY6Z/yalJIxHXhP36PGE4sEq0f/lgL5jCLmOKoDeVm8dqd9gFGDsd1bNWHSGCAwdSkw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxfmt/binding-freebsd-x64@0.72.0': + resolution: {integrity: sha512-yGPhA8sePEBFV9iGcprhyOk3Bz3fZshswMH3DpYIPZFLT1DG5LjiZ0j6AJQpSueaL6bUK0av1K+5+fe+ldy5EQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxfmt/binding-linux-arm-gnueabihf@0.72.0': + resolution: {integrity: sha512-/g5axuqFMcAtoQrFLR5EJEMDjR5Ea4GuzpdDmMpPWAgrF1DmL4kD1NPNVlpXEOxpFJnD6lPvLKYj1lzdlrfifA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxfmt/binding-linux-arm-musleabihf@0.72.0': + resolution: {integrity: sha512-InVitdHbS09PM+w+WinIiyX37rC9R3L7lUP9mKy9uKTEDSUFaLjWsLoreRIxKivnv7Ndqc6Trvi+K+b6ZzhiJg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxfmt/binding-linux-arm64-gnu@0.72.0': + resolution: {integrity: sha512-WKjlyRAxpPjXoqeuwFBim5LscgvY+RNEiZ971C9JlRQZONhJTsXDki/oHFYQE+fzzRpzXh3owZvOdT3kNL2g+g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-arm64-musl@0.72.0': + resolution: {integrity: sha512-poafnbsPpJhR+5Mbwpf8CscugTyiRAzjTOxRVn8ra3X2jnURs2xL5Du2xl5g2iW85lICMglpmLf8jDjZEbNgzQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxfmt/binding-linux-ppc64-gnu@0.72.0': + resolution: {integrity: sha512-zNUi0gKRsO7S3IfPzsTbnm88OedPuX32hmZFWZRWHvWJlAoZRwVbeO6Nb3hng4vDgL7qUKp4TGqzPz1mhsycYg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-riscv64-gnu@0.72.0': + resolution: {integrity: sha512-qTY7z/iyF/rWI2HWwWMevXqZW5PZUOofUy2afK7v6rseXnpld3yjgyIk6pCux3DqWQ0lB+f5atvLJNBwzLvFsw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-riscv64-musl@0.72.0': + resolution: {integrity: sha512-w18qfo8vEMD6EKEHtzTvjc6jH8yCyXIT1Bn7PFWJd0PpZyzH/VQDx4xvjCh0LGz6GRzqiezbisTdG9AoXtpkZQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxfmt/binding-linux-s390x-gnu@0.72.0': + resolution: {integrity: sha512-grW8HwEir+vK7fCcq1ZgL3NHQCfZ1PidiERE9Hbf+24xGys+DoDaoqTht4ccfn0PcBwbViLkwkda/KNpJu2KRQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-x64-gnu@0.72.0': + resolution: {integrity: sha512-wQJRQfWBRIn88Pkr449EUViwRayrYUScg7ty+Ihiem21mQ9BUA6S9e/4RAgyNk9lMag0KBouyKskjq61rOC0WQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-x64-musl@0.72.0': + resolution: {integrity: sha512-T1B0uQzafxuGPjjaPrZJ497nxoi1BiI65JfsYc56nNpmev3msfb/iaTmH2kQuNFqa8PKxpMlf3GhWrWBvBPORQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxfmt/binding-openharmony-arm64@0.72.0': + resolution: {integrity: sha512-OKxxgTurl7+hypVplO8QRAbbQlwEs0j1Y6FZv+ZN2qNbdxQk2muMlzuJNBGTCWwxQ0rkkOD1uK/DW1fvzoUSJA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxfmt/binding-win32-arm64-msvc@0.72.0': + resolution: {integrity: sha512-L78TKzURqvjuZOCo88ixMbPXf/RP7u31Y0cmjJ/KEmrHmfYhmhEvsDaTYPiyTRne64jUgCbADfY0YeoQk4/Xyw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxfmt/binding-win32-ia32-msvc@0.72.0': + resolution: {integrity: sha512-gQtFW+Ii8BWgtJTAD17TY/WsdNS5gUfAPov8iI1jeq4r9lRRYImmxPL08UU00/RLaCfBJwh2UgINnDY0iOiZ+A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxfmt/binding-win32-x64-msvc@0.72.0': + resolution: {integrity: sha512-uhooIN+DCzWX5uH7mQkSVCsODqsGluGJ4n3ch4+mITtWKpESMDjUJUSDBAVFuYQDwqY2McPDKdKJbM0oZVW/Qw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@rollup/rollup-android-arm-eabi@4.62.4': resolution: {integrity: sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==} cpu: [arm] @@ -1086,6 +1211,19 @@ packages: resolution: {integrity: sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw==} engines: {node: '>=18'} + oxfmt@0.72.0: + resolution: {integrity: sha512-16OQeL0uhPZbfmT9S9WWM0Nv9+BmVi8Ra1uTYaSKj/qSCs6FB30KOhz9JoNYw6thT+K5bVxsk/tSEOu497i34g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + svelte: ^5.0.0 + vite-plus: '*' + peerDependenciesMeta: + svelte: + optional: true + vite-plus: + optional: true + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -1183,6 +1321,10 @@ packages: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} + tinypool@2.2.0: + resolution: {integrity: sha512-jBrmx4lYmaC9k/mgPbylxs7kBUxHtD8256up+HjLaDFfXScKJQyil+SWXSvhAtT7XHo+yTVlpB81PGmHP8oLSQ==} + engines: {node: ^20.0.0 || >=22.0.0} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -1535,6 +1677,63 @@ snapshots: '@oven/bun-windows-x64@1.3.14': optional: true + '@oxfmt/binding-android-arm-eabi@0.72.0': + optional: true + + '@oxfmt/binding-android-arm64@0.72.0': + optional: true + + '@oxfmt/binding-darwin-arm64@0.72.0': + optional: true + + '@oxfmt/binding-darwin-x64@0.72.0': + optional: true + + '@oxfmt/binding-freebsd-x64@0.72.0': + optional: true + + '@oxfmt/binding-linux-arm-gnueabihf@0.72.0': + optional: true + + '@oxfmt/binding-linux-arm-musleabihf@0.72.0': + optional: true + + '@oxfmt/binding-linux-arm64-gnu@0.72.0': + optional: true + + '@oxfmt/binding-linux-arm64-musl@0.72.0': + optional: true + + '@oxfmt/binding-linux-ppc64-gnu@0.72.0': + optional: true + + '@oxfmt/binding-linux-riscv64-gnu@0.72.0': + optional: true + + '@oxfmt/binding-linux-riscv64-musl@0.72.0': + optional: true + + '@oxfmt/binding-linux-s390x-gnu@0.72.0': + optional: true + + '@oxfmt/binding-linux-x64-gnu@0.72.0': + optional: true + + '@oxfmt/binding-linux-x64-musl@0.72.0': + optional: true + + '@oxfmt/binding-openharmony-arm64@0.72.0': + optional: true + + '@oxfmt/binding-win32-arm64-msvc@0.72.0': + optional: true + + '@oxfmt/binding-win32-ia32-msvc@0.72.0': + optional: true + + '@oxfmt/binding-win32-x64-msvc@0.72.0': + optional: true + '@rollup/rollup-android-arm-eabi@4.62.4': optional: true @@ -1875,6 +2074,30 @@ snapshots: is-inside-container: 1.0.0 is-wsl: 3.1.1 + oxfmt@0.72.0: + dependencies: + tinypool: 2.2.0 + optionalDependencies: + '@oxfmt/binding-android-arm-eabi': 0.72.0 + '@oxfmt/binding-android-arm64': 0.72.0 + '@oxfmt/binding-darwin-arm64': 0.72.0 + '@oxfmt/binding-darwin-x64': 0.72.0 + '@oxfmt/binding-freebsd-x64': 0.72.0 + '@oxfmt/binding-linux-arm-gnueabihf': 0.72.0 + '@oxfmt/binding-linux-arm-musleabihf': 0.72.0 + '@oxfmt/binding-linux-arm64-gnu': 0.72.0 + '@oxfmt/binding-linux-arm64-musl': 0.72.0 + '@oxfmt/binding-linux-ppc64-gnu': 0.72.0 + '@oxfmt/binding-linux-riscv64-gnu': 0.72.0 + '@oxfmt/binding-linux-riscv64-musl': 0.72.0 + '@oxfmt/binding-linux-s390x-gnu': 0.72.0 + '@oxfmt/binding-linux-x64-gnu': 0.72.0 + '@oxfmt/binding-linux-x64-musl': 0.72.0 + '@oxfmt/binding-openharmony-arm64': 0.72.0 + '@oxfmt/binding-win32-arm64-msvc': 0.72.0 + '@oxfmt/binding-win32-ia32-msvc': 0.72.0 + '@oxfmt/binding-win32-x64-msvc': 0.72.0 + pathe@2.0.3: {} perfect-debounce@2.1.0: {} @@ -1980,6 +2203,8 @@ snapshots: fdir: 6.5.0(picomatch@4.0.5) picomatch: 4.0.5 + tinypool@2.2.0: {} + tree-kill@1.2.2: {} ts-interface-checker@0.1.13: {} diff --git a/scripts/build-binaries.ts b/scripts/build-binaries.ts index eea1a61..9d1f327 100644 --- a/scripts/build-binaries.ts +++ b/scripts/build-binaries.ts @@ -31,7 +31,9 @@ const targets = [ function run(cmd: string, args: string[]): void { const result = spawnSync(cmd, args, { stdio: "inherit" }); if (result.status !== 0) { - throw new Error(`${cmd} ${args.join(" ")} failed with code ${result.status}`); + throw new Error( + `${cmd} ${args.join(" ")} failed with code ${result.status}`, + ); } } diff --git a/src/api-client.ts b/src/api-client.ts index 1b98b67..937c9f0 100644 --- a/src/api-client.ts +++ b/src/api-client.ts @@ -29,8 +29,7 @@ export type ApiClient = { function createInstrumentedFetch(flags: GlobalFlags): typeof fetch { return async (input, init) => { const method = - init?.method ?? - (input instanceof Request ? input.method : "GET"); + init?.method ?? (input instanceof Request ? input.method : "GET"); const url = typeof input === "string" ? input @@ -50,7 +49,8 @@ function createInstrumentedFetch(flags: GlobalFlags): typeof fetch { process.stdout.write("\n"); } else { const body = - init?.body ?? (input instanceof Request ? await input.clone().text() : undefined); + init?.body ?? + (input instanceof Request ? await input.clone().text() : undefined); if (typeof body === "string" && body) { try { process.stdout.write( diff --git a/src/auth.test.ts b/src/auth.test.ts index 568af99..8b97236 100644 --- a/src/auth.test.ts +++ b/src/auth.test.ts @@ -20,7 +20,10 @@ describe("credential store selection", () => { if (process.platform === "darwin") { assert.equal(credentialStorageDescription(), "macOS Keychain"); } else if (process.platform === "win32") { - assert.equal(credentialStorageDescription(), "Windows Credential Manager"); + assert.equal( + credentialStorageDescription(), + "Windows Credential Manager", + ); } else { assert.equal(credentialStorageDescription(), "config file"); } diff --git a/src/cli.ts b/src/cli.ts index fe68728..52cd745 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -15,7 +15,7 @@ function buildProgram(): Command { program .name("vanta") .description( - "Vanta CLI for querying and updating resources through the Vanta API.\n\nStart by running \"vanta login\" to save your OAuth client credentials and default API base.", + 'Vanta CLI for querying and updating resources through the Vanta API.\n\nStart by running "vanta login" to save your OAuth client credentials and default API base.', ) .version(displayVersion(Version), "-V, --version", "Print the CLI version") .option( diff --git a/src/commands/controls.ts b/src/commands/controls.ts index 7ec683e..c492d90 100644 --- a/src/commands/controls.ts +++ b/src/commands/controls.ts @@ -200,11 +200,7 @@ export function registerControlsCommand( .description("List documents for a control") .requiredOption("--id ", "Control ID"), ).action( - async (opts: { - id: string; - pageSize?: number; - pageCursor?: string; - }) => { + async (opts: { id: string; pageSize?: number; pageCursor?: string }) => { await runSdk(getFlags, (api) => listDocumentsForControl({ client: api.client, @@ -254,11 +250,7 @@ export function registerControlsCommand( .description("List tests for a control") .requiredOption("--id ", "Control ID"), ).action( - async (opts: { - id: string; - pageSize?: number; - pageCursor?: string; - }) => { + async (opts: { id: string; pageSize?: number; pageCursor?: string }) => { await runSdk(getFlags, (api) => listTestsForControl({ client: api.client, diff --git a/src/commands/customer-trust.ts b/src/commands/customer-trust.ts index 407a8b6..1b36f6c 100644 --- a/src/commands/customer-trust.ts +++ b/src/commands/customer-trust.ts @@ -128,19 +128,21 @@ export function registerCustomerTrustCommand( .command("update-account") .description("Update a Customer Trust account") .requiredOption("--account-id ", "Customer Trust account ID"), - ).action(async (opts: { accountId: string; json?: string; file?: string }) => { - const body = (await readJSONPayload( - opts.json, - opts.file, - )) as UpdateCustomerTrustAccountData["body"]; - await runSdk(getFlags, (api) => - updateCustomerTrustAccount({ - client: api.client, - path: { accountId: opts.accountId }, - body, - }), - ); - }); + ).action( + async (opts: { accountId: string; json?: string; file?: string }) => { + const body = (await readJSONPayload( + opts.json, + opts.file, + )) as UpdateCustomerTrustAccountData["body"]; + await runSdk(getFlags, (api) => + updateCustomerTrustAccount({ + client: api.client, + path: { accountId: opts.accountId }, + body, + }), + ); + }, + ); customerTrust .command("delete-account") @@ -214,8 +216,12 @@ export function registerCustomerTrustCommand( pageSize?: number; pageCursor?: string; q?: string; - statusMatchesAny: NonNullable["statusMatchesAny"]>; - typeMatchesAny: NonNullable["typeMatchesAny"]>; + statusMatchesAny: NonNullable< + NonNullable["statusMatchesAny"] + >; + typeMatchesAny: NonNullable< + NonNullable["typeMatchesAny"] + >; createdAfter?: string; createdBefore?: string; ownerIdMatchesAny: string[]; @@ -242,7 +248,7 @@ export function registerCustomerTrustCommand( customerTrust .command("list-questionnaire-assignable-users") .description("List users who can be assigned to questionnaires") - .option("--role ", "Filter by role: \"owner\" or \"approver\"") + .option("--role ", 'Filter by role: "owner" or "approver"') .option( "--q ", "Optional search string to filter users by name or email", @@ -298,11 +304,11 @@ export function registerCustomerTrustCommand( ) .option( "--owner-assignment ", - "Owner to assign, as a JSON string: {\"type\": \"User\" | \"Team\", \"id\": \"\"}", + 'Owner to assign, as a JSON string: {"type": "User" | "Team", "id": ""}', ) .option( "--approver-assignment ", - "Approver to assign, as a JSON string: {\"type\": \"User\" | \"Team\", \"id\": \"\"}", + 'Approver to assign, as a JSON string: {"type": "User" | "Team", "id": ""}', ) .option("--description ", "Description of the questionnaire") .option( @@ -323,11 +329,11 @@ export function registerCustomerTrustCommand( ) .option( "--metadata ", - "Custom key-value pairs, as a JSON string array: [{\"key\": \"\", \"value\": \"\"}]. Keys and values may contain alphanumeric characters, hyphens, underscores, and periods", + 'Custom key-value pairs, as a JSON string array: [{"key": "", "value": ""}]. Keys and values may contain alphanumeric characters, hyphens, underscores, and periods', ) .option( "--tag-and-category-ids ", - "Tags to assign, as a JSON string array: [{\"categoryId\": \"\", \"tagId\": \"\"}]. Replaces all existing tags", + 'Tags to assign, as a JSON string array: [{"categoryId": "", "tagId": ""}]. Replaces all existing tags', ) .action( async (opts: { @@ -356,7 +362,8 @@ export function registerCustomerTrustCommand( companyUrl: opts.companyUrl, dueDate: opts.dueDate, customerTrustAccountId: opts.customerTrustAccountId, - includeUntaggedEntitiesForCategoryIds: opts.includeUntaggedEntitiesForCategoryIds, + includeUntaggedEntitiesForCategoryIds: + opts.includeUntaggedEntitiesForCategoryIds, metadata: opts.metadata, tagAndCategoryIds: opts.tagAndCategoryIds, }, @@ -398,11 +405,7 @@ export function registerCustomerTrustCommand( .description("Update a questionnaire") .requiredOption("--questionnaire-id ", "Questionnaire ID"), ).action( - async (opts: { - questionnaireId: string; - json?: string; - file?: string; - }) => { + async (opts: { questionnaireId: string; json?: string; file?: string }) => { const body = (await readJSONPayload( opts.json, opts.file, @@ -436,11 +439,7 @@ export function registerCustomerTrustCommand( .description("Approve a questionnaire") .requiredOption("--questionnaire-id ", "Questionnaire ID"), ).action( - async (opts: { - questionnaireId: string; - json?: string; - file?: string; - }) => { + async (opts: { questionnaireId: string; json?: string; file?: string }) => { const body = (await readJSONPayload( opts.json, opts.file, @@ -461,11 +460,7 @@ export function registerCustomerTrustCommand( .description("Complete a questionnaire") .requiredOption("--questionnaire-id ", "Questionnaire ID"), ).action( - async (opts: { - questionnaireId: string; - json?: string; - file?: string; - }) => { + async (opts: { questionnaireId: string; json?: string; file?: string }) => { const body = (await readJSONPayload( opts.json, opts.file, @@ -594,7 +589,11 @@ export function registerCustomerTrustCommand( ) .action( async (opts: { - productContextIdsMatchesAny: NonNullable["productContextIdsMatchesAny"]>; + productContextIdsMatchesAny: NonNullable< + NonNullable< + ListTagCategoriesData["query"] + >["productContextIdsMatchesAny"] + >; }) => { await runSdk(getFlags, (api) => listTagCategories({ @@ -626,11 +625,7 @@ export function registerCustomerTrustCommand( .description("Enable a tag category for a product context") .requiredOption("--tag-category-id ", "Tag category ID"), ).action( - async (opts: { - tagCategoryId: string; - json?: string; - file?: string; - }) => { + async (opts: { tagCategoryId: string; json?: string; file?: string }) => { const body = (await readJSONPayload( opts.json, opts.file, diff --git a/src/commands/discovered-vendors.ts b/src/commands/discovered-vendors.ts index 6150e45..17819ac 100644 --- a/src/commands/discovered-vendors.ts +++ b/src/commands/discovered-vendors.ts @@ -49,11 +49,7 @@ export function registerDiscoveredVendorsCommand( .description("List accounts for a discovered vendor") .requiredOption("--id ", "Discovered vendor ID"), ).action( - async (opts: { - id: string; - pageSize?: number; - pageCursor?: string; - }) => { + async (opts: { id: string; pageSize?: number; pageCursor?: string }) => { await runSdk(getFlags, (api) => listDiscoveredVendorAccounts({ client: api.client, diff --git a/src/commands/documents.ts b/src/commands/documents.ts index dff0548..59fbf9c 100644 --- a/src/commands/documents.ts +++ b/src/commands/documents.ts @@ -64,7 +64,9 @@ export function registerDocumentsCommand( pageSize?: number; pageCursor?: string; frameworkMatchesAny: string[]; - statusMatchesAny: NonNullable["statusMatchesAny"]>; + statusMatchesAny: NonNullable< + NonNullable["statusMatchesAny"] + >; }) => { await runSdk(getFlags, (api) => listDocuments({ @@ -117,11 +119,7 @@ export function registerDocumentsCommand( .description("List controls for a document") .requiredOption("--id ", "Document ID"), ).action( - async (opts: { - id: string; - pageSize?: number; - pageCursor?: string; - }) => { + async (opts: { id: string; pageSize?: number; pageCursor?: string }) => { await runSdk(getFlags, (api) => listControlsForDocument({ client: api.client, @@ -138,11 +136,7 @@ export function registerDocumentsCommand( .description("List links for a document") .requiredOption("--id ", "Document ID"), ).action( - async (opts: { - id: string; - pageSize?: number; - pageCursor?: string; - }) => { + async (opts: { id: string; pageSize?: number; pageCursor?: string }) => { await runSdk(getFlags, (api) => listLinksForDocument({ client: api.client, @@ -224,11 +218,7 @@ export function registerDocumentsCommand( .description("List uploads for a document") .requiredOption("--id ", "Document ID"), ).action( - async (opts: { - id: string; - pageSize?: number; - pageCursor?: string; - }) => { + async (opts: { id: string; pageSize?: number; pageCursor?: string }) => { await runSdk(getFlags, (api) => listFilesForDocument({ client: api.client, @@ -295,11 +285,7 @@ export function registerDocumentsCommand( "Write downloaded bytes to file path (default stdout)", ) .action( - async (opts: { - id: string; - uploadedFileId: string; - output?: string; - }) => { + async (opts: { id: string; uploadedFileId: string; output?: string }) => { await withClient(getFlags, async (api, flags) => { const result = await getUploadedfileMedia({ client: api.client, diff --git a/src/commands/frameworks.ts b/src/commands/frameworks.ts index 201f1c8..d8e9c97 100644 --- a/src/commands/frameworks.ts +++ b/src/commands/frameworks.ts @@ -43,11 +43,7 @@ export function registerFrameworksCommand( .description("List controls for a framework") .requiredOption("--id ", "Framework ID"), ).action( - async (opts: { - id: string; - pageSize?: number; - pageCursor?: string; - }) => { + async (opts: { id: string; pageSize?: number; pageCursor?: string }) => { await runSdk(getFlags, (api) => listControlsForFramework({ client: api.client, diff --git a/src/commands/groups.ts b/src/commands/groups.ts index 0696570..42bfa51 100644 --- a/src/commands/groups.ts +++ b/src/commands/groups.ts @@ -61,9 +61,7 @@ export function registerGroupsCommand( opts.json, opts.file, )) as CreateGroupData["body"]; - await runSdk(getFlags, (api) => - createGroup({ client: api.client, body }), - ); + await runSdk(getFlags, (api) => createGroup({ client: api.client, body })); }); addJsonFileOptions( @@ -135,7 +133,11 @@ export function registerGroupsCommand( opts.file, )) as AddPeopleToGroupData["body"]; await runSdk(getFlags, (api) => - addPeopleToGroup({ client: api.client, path: { groupId: opts.id }, body }), + addPeopleToGroup({ + client: api.client, + path: { groupId: opts.id }, + body, + }), ); }); @@ -160,7 +162,11 @@ export function registerGroupsCommand( opts.file, )) as AddPersonToGroupData["body"]; await runSdk(getFlags, (api) => - addPersonToGroup({ client: api.client, path: { groupId: opts.id }, body }), + addPersonToGroup({ + client: api.client, + path: { groupId: opts.id }, + body, + }), ); }); diff --git a/src/commands/helpers.test.ts b/src/commands/helpers.test.ts index 77c105e..e12dd7d 100644 --- a/src/commands/helpers.test.ts +++ b/src/commands/helpers.test.ts @@ -23,10 +23,7 @@ describe("readBinaryFile", () => { const file = await readBinaryFile(filePath); assert.ok(file instanceof File); assert.equal(file.name, "questions.csv"); - assert.equal( - await file.text(), - "Question\nDo you encrypt data at rest?\n", - ); + assert.equal(await file.text(), "Question\nDo you encrypt data at rest?\n"); }); it("serializes as a multipart file part with a non-empty filename", async () => { diff --git a/src/commands/helpers.ts b/src/commands/helpers.ts index 0459522..7af1396 100644 --- a/src/commands/helpers.ts +++ b/src/commands/helpers.ts @@ -3,7 +3,11 @@ import { basename, extname } from "node:path"; import { Readable } from "node:stream"; import { pipeline } from "node:stream/promises"; import type { Command } from "commander"; -import { newAPIClient, type ApiClient, type GlobalFlags } from "../api-client.js"; +import { + newAPIClient, + type ApiClient, + type GlobalFlags, +} from "../api-client.js"; import { printResponse } from "../output.js"; export type GetFlags = () => GlobalFlags; @@ -32,9 +36,7 @@ export function paginationQuery(opts: { }): { pageSize?: number; pageCursor?: string } { return { ...(opts.pageSize && opts.pageSize > 0 ? { pageSize: opts.pageSize } : {}), - ...(opts.pageCursor?.trim() - ? { pageCursor: opts.pageCursor.trim() } - : {}), + ...(opts.pageCursor?.trim() ? { pageCursor: opts.pageCursor.trim() } : {}), }; } diff --git a/src/commands/index.ts b/src/commands/index.ts index 1ecaa7f..cb1abce 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -28,7 +28,10 @@ import { registerKnowledgeBaseCommand } from "./knowledge-base.js"; import { registerTrustCentersCommand } from "./trust-centers.js"; import type { GetFlags } from "./helpers.js"; -export function registerApiCommands(program: Command, getFlags: GetFlags): void { +export function registerApiCommands( + program: Command, + getFlags: GetFlags, +): void { registerControlsCommand(program, getFlags); registerPoliciesCommand(program, getFlags); registerDocumentsCommand(program, getFlags); diff --git a/src/commands/issues.ts b/src/commands/issues.ts index a9fc796..437d6b7 100644 --- a/src/commands/issues.ts +++ b/src/commands/issues.ts @@ -83,12 +83,17 @@ export function registerIssuesCommand( .option( "--include-issues-without-due-date ", "Include undated issues with --due-before-date or --due-after-date (true/false)", - (value) => parseOptionalBoolString(value, "include-issues-without-due-date"), + (value) => + parseOptionalBoolString(value, "include-issues-without-due-date"), ) .option( "--include-only-issues-without-due-date ", "Include only undated issues (true/false); cannot combine with --due-before-date or --due-after-date", - (value) => parseOptionalBoolString(value, "include-only-issues-without-due-date"), + (value) => + parseOptionalBoolString( + value, + "include-only-issues-without-due-date", + ), ) .option( "--due-after-date ", @@ -140,13 +145,25 @@ export function registerIssuesCommand( pageCursor?: string; search?: string; readableIssueIdMatchesAny: string[]; - statusMatchesAny: NonNullable["statusMatchesAny"]>; - severityMatchesAny: NonNullable["severityMatchesAny"]>; - sourceMatchesAny: NonNullable["sourceMatchesAny"]>; - typeMatchesAny: NonNullable["typeMatchesAny"]>; + statusMatchesAny: NonNullable< + NonNullable["statusMatchesAny"] + >; + severityMatchesAny: NonNullable< + NonNullable["severityMatchesAny"] + >; + sourceMatchesAny: NonNullable< + NonNullable["sourceMatchesAny"] + >; + typeMatchesAny: NonNullable< + NonNullable["typeMatchesAny"] + >; ownerIdMatchesAny: string[]; - templateMatchesAny: NonNullable["templateMatchesAny"]>; - closeReasonMatchesAny: NonNullable["closeReasonMatchesAny"]>; + templateMatchesAny: NonNullable< + NonNullable["templateMatchesAny"] + >; + closeReasonMatchesAny: NonNullable< + NonNullable["closeReasonMatchesAny"] + >; closedAfterDate?: string; closedBeforeDate?: string; includeIssuesWithoutDueDate?: boolean; @@ -179,7 +196,8 @@ export function registerIssuesCommand( closedAfterDate: opts.closedAfterDate, closedBeforeDate: opts.closedBeforeDate, includeIssuesWithoutDueDate: opts.includeIssuesWithoutDueDate, - includeOnlyIssuesWithoutDueDate: opts.includeOnlyIssuesWithoutDueDate, + includeOnlyIssuesWithoutDueDate: + opts.includeOnlyIssuesWithoutDueDate, dueAfterDate: opts.dueAfterDate, dueBeforeDate: opts.dueBeforeDate, detectedAfterDate: opts.detectedAfterDate, diff --git a/src/commands/knowledge-base.ts b/src/commands/knowledge-base.ts index f750514..735ede9 100644 --- a/src/commands/knowledge-base.ts +++ b/src/commands/knowledge-base.ts @@ -194,7 +194,7 @@ export function registerKnowledgeBaseCommand( ) .option( "--matches-tags ", - "JSON-encoded array of `{categoryId, tagId}` pairs. Tags within the same category are OR'd together; tags across different categories are AND'd. For example, passing two tags from \"Framework\" and one tag from \"Region\" matches resources that have either of the two frameworks AND the given region. Find category IDs with `vanta customer-trust list-tag-categories` and tag IDs with `vanta customer-trust get-tag-category --tag-category-id `.", + 'JSON-encoded array of `{categoryId, tagId}` pairs. Tags within the same category are OR\'d together; tags across different categories are AND\'d. For example, passing two tags from "Framework" and one tag from "Region" matches resources that have either of the two frameworks AND the given region. Find category IDs with `vanta customer-trust list-tag-categories` and tag IDs with `vanta customer-trust get-tag-category --tag-category-id `.', ) .option( "--expires-before ", @@ -209,7 +209,9 @@ export function registerKnowledgeBaseCommand( pageSize?: number; pageCursor?: string; q?: string; - typeMatchesAny: NonNullable["typeMatchesAny"]>; + typeMatchesAny: NonNullable< + NonNullable["typeMatchesAny"] + >; lastUpdatedAfter?: string; lastUpdatedBefore?: string; matchesTags?: string; @@ -242,7 +244,7 @@ export function registerKnowledgeBaseCommand( .option("--description ", "Description of the document resource") .option( "--owner-assignment ", - "Owner to assign as a JSON string: {\"type\":\"User\",\"id\":\"\"}", + 'Owner to assign as a JSON string: {"type":"User","id":""}', ) .option( "--customer-visibility ", @@ -262,7 +264,7 @@ export function registerKnowledgeBaseCommand( ) .option( "--tags ", - "Tags as a JSON array: [{\"categoryId\":\"\",\"tagId\":\"\"}]", + 'Tags as a JSON array: [{"categoryId":"","tagId":""}]', ) .option( "--category-id ", @@ -365,7 +367,11 @@ export function registerKnowledgeBaseCommand( opts.file, )) as UpdateWebpageResourceData["body"]; await runSdk(getFlags, (api) => - updateWebpageResource({ client: api.client, path: { id: opts.id }, body }), + updateWebpageResource({ + client: api.client, + path: { id: opts.id }, + body, + }), ); }); diff --git a/src/commands/login.ts b/src/commands/login.ts index e27151a..23bfd44 100644 --- a/src/commands/login.ts +++ b/src/commands/login.ts @@ -45,48 +45,50 @@ export function registerLoginCommand( .option("--client-id ", "OAuth client ID") .option("--client-secret ", "OAuth client secret") .option("--scope ", "OAuth scope", defaultOAuthScope) - .action(async (opts: { - clientId?: string; - clientSecret?: string; - scope?: string; - }) => { - const overrides = getOverrides(); - const apiBaseDefault = await resolveAPIBase(overrides); - const apiBase = await promptValue("API base URL", apiBaseDefault, true); - const clientID = await promptValue( - "OAuth client ID", - opts.clientId ?? "", - true, - ); - const clientSecret = await promptValue( - "OAuth client secret", - opts.clientSecret ?? "", - true, - ); - const scopeDefault = opts.scope?.trim() || defaultOAuthScope; - const scope = - (await promptValue( - `OAuth scope (default: ${scopeDefault})`, - scopeDefault, - false, - )) || scopeDefault; + .action( + async (opts: { + clientId?: string; + clientSecret?: string; + scope?: string; + }) => { + const overrides = getOverrides(); + const apiBaseDefault = await resolveAPIBase(overrides); + const apiBase = await promptValue("API base URL", apiBaseDefault, true); + const clientID = await promptValue( + "OAuth client ID", + opts.clientId ?? "", + true, + ); + const clientSecret = await promptValue( + "OAuth client secret", + opts.clientSecret ?? "", + true, + ); + const scopeDefault = opts.scope?.trim() || defaultOAuthScope; + const scope = + (await promptValue( + `OAuth scope (default: ${scopeDefault})`, + scopeDefault, + false, + )) || scopeDefault; - const { accessToken, expiresAt } = await requestOAuthToken( - apiBase, - clientID, - clientSecret, - scope, - ); - await saveOAuthCredentials(apiBase, clientID, clientSecret, scope); - await cacheAccessToken(accessToken, "Bearer", expiresAt); + const { accessToken, expiresAt } = await requestOAuthToken( + apiBase, + clientID, + clientSecret, + scope, + ); + await saveOAuthCredentials(apiBase, clientID, clientSecret, scope); + await cacheAccessToken(accessToken, "Bearer", expiresAt); - console.log( - `OAuth credentials saved to ${credentialStorageDescription()}`, - ); - console.log(`API base saved as ${apiBase}`); - console.log(`CLI configuration saved to ${configFilePath()}`); - console.log( - `Access token cached (expires at ${expiresAt.toISOString().replace(/\.\d{3}Z$/, "Z")})`, - ); - }); + console.log( + `OAuth credentials saved to ${credentialStorageDescription()}`, + ); + console.log(`API base saved as ${apiBase}`); + console.log(`CLI configuration saved to ${configFilePath()}`); + console.log( + `Access token cached (expires at ${expiresAt.toISOString().replace(/\.\d{3}Z$/, "Z")})`, + ); + }, + ); } diff --git a/src/commands/monitored-computers.ts b/src/commands/monitored-computers.ts index d6f74bb..c700576 100644 --- a/src/commands/monitored-computers.ts +++ b/src/commands/monitored-computers.ts @@ -34,14 +34,19 @@ export function registerMonitoredComputersCommand( async (opts: { pageSize?: number; pageCursor?: string; - complianceStatusFilterMatchesAny: NonNullable["complianceStatusFilterMatchesAny"]>; + complianceStatusFilterMatchesAny: NonNullable< + NonNullable< + ListMonitoredComputersData["query"] + >["complianceStatusFilterMatchesAny"] + >; }) => { await runSdk(getFlags, (api) => listMonitoredComputers({ client: api.client, query: { ...paginationQuery(opts), - complianceStatusFilterMatchesAny: opts.complianceStatusFilterMatchesAny, + complianceStatusFilterMatchesAny: + opts.complianceStatusFilterMatchesAny, }, }), ); diff --git a/src/commands/people.ts b/src/commands/people.ts index 27eb6a6..2228d93 100644 --- a/src/commands/people.ts +++ b/src/commands/people.ts @@ -73,12 +73,20 @@ export function registerPeopleCommand( async (opts: { pageSize?: number; pageCursor?: string; - tasksSummaryStatusMatchesAny: NonNullable["tasksSummaryStatusMatchesAny"]>; - taskTypeMatchesAny: NonNullable["taskTypeMatchesAny"]>; - taskStatusMatchesAny: NonNullable["taskStatusMatchesAny"]>; + tasksSummaryStatusMatchesAny: NonNullable< + NonNullable["tasksSummaryStatusMatchesAny"] + >; + taskTypeMatchesAny: NonNullable< + NonNullable["taskTypeMatchesAny"] + >; + taskStatusMatchesAny: NonNullable< + NonNullable["taskStatusMatchesAny"] + >; emailAndNameFilter?: string; groupIdsMatchesAny: string[]; - employmentStatus?: NonNullable["employmentStatus"]; + employmentStatus?: NonNullable< + ListPeopleData["query"] + >["employmentStatus"]; }) => { await runSdk(getFlags, (api) => listPeople({ @@ -143,9 +151,7 @@ export function registerPeopleCommand( opts.json, opts.file, )) as MarkAsPeopleData["body"]; - await runSdk(getFlags, (api) => - markAsPeople({ client: api.client, body }), - ); + await runSdk(getFlags, (api) => markAsPeople({ client: api.client, body })); }); addJsonFileOptions( @@ -166,7 +172,10 @@ export function registerPeopleCommand( .requiredOption("--id ", "Person ID") .action(async (opts: { id: string }) => { await runSdk(getFlags, (api) => - clearLeaveForPerson({ client: api.client, path: { personId: opts.id } }), + clearLeaveForPerson({ + client: api.client, + path: { personId: opts.id }, + }), ); }); diff --git a/src/commands/personnel-notification-settings.ts b/src/commands/personnel-notification-settings.ts index 4d02701..0f06188 100644 --- a/src/commands/personnel-notification-settings.ts +++ b/src/commands/personnel-notification-settings.ts @@ -20,9 +20,7 @@ export function registerPersonnelNotificationSettingsCommand( .command("get") .description("Get personnel notification settings") .action(async () => { - await runSdk(getFlags, (api) => - getSettings({ client: api.client }), - ); + await runSdk(getFlags, (api) => getSettings({ client: api.client })); }); addJsonFileOptions( diff --git a/src/commands/risk-scenarios.ts b/src/commands/risk-scenarios.ts index a2779d2..b5dfaf3 100644 --- a/src/commands/risk-scenarios.ts +++ b/src/commands/risk-scenarios.ts @@ -49,26 +49,26 @@ export function registerRiskScenariosCommand( ) .option( "--owner-matches-any ", - "Use \"No owner\" to filter scenarios without owner assigned (repeatable)", + 'Use "No owner" to filter scenarios without owner assigned (repeatable)', collectString, [] as string[], ) .option("--search-string ", "Search risk scenarios") .option( "--category-matches-any ", - "Use \"Uncategorized\" to filter scenarios without any category (repeatable)", + 'Use "Uncategorized" to filter scenarios without any category (repeatable)', collectString, [] as string[], ) .option( "--cia-category-matches-any ", - "Use \"Uncategorized\" to filter scenarios with none of Confidentiality, Integrity or Availability assigned (repeatable)", + 'Use "Uncategorized" to filter scenarios with none of Confidentiality, Integrity or Availability assigned (repeatable)', collectString, [] as string[], ) .option( "--treatment-type-matches-any ", - "Use \"No treatment type\" to filter scenarios without treatment specified (repeatable)", + 'Use "No treatment type" to filter scenarios without treatment specified (repeatable)', collectString, [] as string[], ) @@ -92,9 +92,12 @@ export function registerRiskScenariosCommand( ) .option( "--type ", - "Filter by risk scenario type. Defaults to \"Risk Scenario\". Only returns enterprise risks when explicitly set to \"Enterprise Risk\"", + 'Filter by risk scenario type. Defaults to "Risk Scenario". Only returns enterprise risks when explicitly set to "Enterprise Risk"', ) - .option("--order-by ", "Order by field (description or createdAt)"), + .option( + "--order-by ", + "Order by field (description or createdAt)", + ), ).action( async (opts: { pageSize?: number; @@ -103,11 +106,25 @@ export function registerRiskScenariosCommand( ownerMatchesAny: string[]; searchString?: string; categoryMatchesAny: string[]; - ciaCategoryMatchesAny: NonNullable["ciaCategoryMatchesAny"]>; - treatmentTypeMatchesAny: NonNullable["treatmentTypeMatchesAny"]>; - inherentScoreGroupMatchesAny: NonNullable["inherentScoreGroupMatchesAny"]>; - residualScoreGroupMatchesAny: NonNullable["residualScoreGroupMatchesAny"]>; - reviewStatusMatchesAny: NonNullable["reviewStatusMatchesAny"]>; + ciaCategoryMatchesAny: NonNullable< + NonNullable["ciaCategoryMatchesAny"] + >; + treatmentTypeMatchesAny: NonNullable< + NonNullable["treatmentTypeMatchesAny"] + >; + inherentScoreGroupMatchesAny: NonNullable< + NonNullable< + ListRiskScenarioData["query"] + >["inherentScoreGroupMatchesAny"] + >; + residualScoreGroupMatchesAny: NonNullable< + NonNullable< + ListRiskScenarioData["query"] + >["residualScoreGroupMatchesAny"] + >; + reviewStatusMatchesAny: NonNullable< + NonNullable["reviewStatusMatchesAny"] + >; type?: NonNullable["type"]; orderBy?: NonNullable["orderBy"]; }) => { @@ -196,11 +213,7 @@ export function registerRiskScenariosCommand( .description("List controls for a risk scenario") .requiredOption("--id ", "Risk scenario ID"), ).action( - async (opts: { - id: string; - pageSize?: number; - pageCursor?: string; - }) => { + async (opts: { id: string; pageSize?: number; pageCursor?: string }) => { await runSdk(getFlags, (api) => listRiskScenarioControls({ client: api.client, diff --git a/src/commands/trust-centers.ts b/src/commands/trust-centers.ts index 4459396..b14db7e 100644 --- a/src/commands/trust-centers.ts +++ b/src/commands/trust-centers.ts @@ -284,7 +284,11 @@ export function registerTrustCentersCommand( slugId: string; pageSize?: number; pageCursor?: string; - eventTypesMatchesAny: NonNullable["eventTypesMatchesAny"]>; + eventTypesMatchesAny: NonNullable< + NonNullable< + ListTrustCenterActivityEventsData["query"] + >["eventTypesMatchesAny"] + >; afterDate?: string; beforeDate?: string; }) => { @@ -423,11 +427,7 @@ export function registerTrustCentersCommand( .requiredOption("--framework-id ", "Framework ID") .requiredOption("--file ", "Path to file to upload") .action( - async (opts: { - slugId: string; - frameworkId: string; - file: string; - }) => { + async (opts: { slugId: string; frameworkId: string; file: string }) => { const file = await readBinaryFile(opts.file); await runSdk(getFlags, (api) => uploadComplianceFrameworkBadge({ @@ -1139,11 +1139,7 @@ export function registerTrustCentersCommand( "Write downloaded bytes to file path (default stdout)", ) .action( - async (opts: { - slugId: string; - resourceId: string; - output?: string; - }) => { + async (opts: { slugId: string; resourceId: string; output?: string }) => { await withClient(getFlags, async (api, flags) => { const result = await getTrustCenterResourceMedia({ client: api.client, @@ -1321,7 +1317,10 @@ export function registerTrustCentersCommand( await runSdk(getFlags, (api) => updateTrustCenterSubscriberGroup({ client: api.client, - path: { slugId: opts.slugId, subscriberGroupId: opts.subscriberGroupId }, + path: { + slugId: opts.slugId, + subscriberGroupId: opts.subscriberGroupId, + }, body, }), ); @@ -1624,7 +1623,10 @@ export function registerTrustCentersCommand( listTrustCenterViewers({ client: api.client, path: { slugId: opts.slugId }, - query: { ...paginationQuery(opts), includeRemoved: opts.includeRemoved }, + query: { + ...paginationQuery(opts), + includeRemoved: opts.includeRemoved, + }, }), ); }, diff --git a/src/commands/users.ts b/src/commands/users.ts index ce20b3d..75c06a4 100644 --- a/src/commands/users.ts +++ b/src/commands/users.ts @@ -13,13 +13,13 @@ export function registerUsersCommand( ): void { const users = program.command("users").description("Manage users"); - addPaginationOptions( - users.command("list").description("List users"), - ).action(async (opts) => { - await runSdk(getFlags, (api) => - listUsers({ client: api.client, query: paginationQuery(opts) }), - ); - }); + addPaginationOptions(users.command("list").description("List users")).action( + async (opts) => { + await runSdk(getFlags, (api) => + listUsers({ client: api.client, query: paginationQuery(opts) }), + ); + }, + ); users .command("get") diff --git a/src/commands/vendors.ts b/src/commands/vendors.ts index 9d116af..676da1c 100644 --- a/src/commands/vendors.ts +++ b/src/commands/vendors.ts @@ -64,7 +64,9 @@ export function registerVendorsCommand( pageSize?: number; pageCursor?: string; name?: string; - statusMatchesAny: NonNullable["statusMatchesAny"]>; + statusMatchesAny: NonNullable< + NonNullable["statusMatchesAny"] + >; }) => { await runSdk(getFlags, (api) => listVendors({ @@ -96,9 +98,7 @@ export function registerVendorsCommand( opts.json, opts.file, )) as CreateVendorData["body"]; - await runSdk(getFlags, (api) => - createVendor({ client: api.client, body }), - ); + await runSdk(getFlags, (api) => createVendor({ client: api.client, body })); }); addJsonFileOptions( @@ -149,7 +149,9 @@ export function registerVendorsCommand( pageSize?: number; pageCursor?: string; typeIdMatchesAny: string[]; - statusMatchesAny: NonNullable["statusMatchesAny"]>; + statusMatchesAny: NonNullable< + NonNullable["statusMatchesAny"] + >; }) => { await runSdk(getFlags, (api) => getAssessmentsByVendorId({ @@ -185,11 +187,7 @@ export function registerVendorsCommand( .description("List documents for a vendor") .requiredOption("--id ", "Vendor ID"), ).action( - async (opts: { - id: string; - pageSize?: number; - pageCursor?: string; - }) => { + async (opts: { id: string; pageSize?: number; pageCursor?: string }) => { await runSdk(getFlags, (api) => listVendorDocuments({ client: api.client, @@ -330,11 +328,7 @@ export function registerVendorsCommand( .description("List security reviews for a vendor") .requiredOption("--id ", "Vendor ID"), ).action( - async (opts: { - id: string; - pageSize?: number; - pageCursor?: string; - }) => { + async (opts: { id: string; pageSize?: number; pageCursor?: string }) => { await runSdk(getFlags, (api) => getSecurityReviewsByVendorId({ client: api.client, @@ -404,7 +398,10 @@ export function registerVendorsCommand( await runSdk(getFlags, (api) => uploadDocumentForSecurityReview({ client: api.client, - path: { vendorId: opts.id, securityReviewId: opts.securityReviewId }, + path: { + vendorId: opts.id, + securityReviewId: opts.securityReviewId, + }, body: { file, type: opts.type, diff --git a/src/commands/vulnerabilities.ts b/src/commands/vulnerabilities.ts index 2a1f6a1..ed15e1a 100644 --- a/src/commands/vulnerabilities.ts +++ b/src/commands/vulnerabilities.ts @@ -69,7 +69,11 @@ export function registerVulnerabilitiesCommand( .option( "--include-vulnerabilities-without-slas ", "Include vulnerabilities without SLA dates (true/false)", - (value) => parseOptionalBoolString(value, "include-vulnerabilities-without-slas"), + (value) => + parseOptionalBoolString( + value, + "include-vulnerabilities-without-slas", + ), ) .option( "--vulnerable-asset-id ", @@ -108,7 +112,8 @@ export function registerVulnerabilitiesCommand( slaDeadlineBeforeDate: opts.slaDeadlineBeforeDate, severity: opts.severity, integrationId: opts.integrationId, - includeVulnerabilitiesWithoutSlas: opts.includeVulnerabilitiesWithoutSlas, + includeVulnerabilitiesWithoutSlas: + opts.includeVulnerabilitiesWithoutSlas, vulnerableAssetId: opts.vulnerableAssetId, q: opts.q, }, diff --git a/src/commands/vulnerability-remediations.ts b/src/commands/vulnerability-remediations.ts index 43527bd..971f114 100644 --- a/src/commands/vulnerability-remediations.ts +++ b/src/commands/vulnerability-remediations.ts @@ -55,7 +55,9 @@ export function registerVulnerabilityRemediationsCommand( pageSize?: number; pageCursor?: string; integrationId?: string; - severity?: NonNullable["severity"]; + severity?: NonNullable< + ListVulnerabilityRemediationsData["query"] + >["severity"]; isRemediatedOnTime?: boolean; remediatedAfterDate?: string; remediatedBeforeDate?: string; diff --git a/src/output.ts b/src/output.ts index 54f57c4..281e650 100644 --- a/src/output.ts +++ b/src/output.ts @@ -40,7 +40,10 @@ function unwrapResultsData(value: unknown): unknown { } function sanitizeTerminalControls(value: string): string { - return value.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/g, ""); + return value.replace( + /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/g, + "", + ); } export function printResponse( diff --git a/src/update-check.ts b/src/update-check.ts index e6bf9bd..e70f393 100644 --- a/src/update-check.ts +++ b/src/update-check.ts @@ -2,7 +2,12 @@ import { mkdir, readFile, writeFile } from "node:fs/promises"; import { homedir } from "node:os"; import { dirname, join } from "node:path"; import { agentModeEnabled } from "./agent-mode.js"; -import { Version, displayVersion, normalizeVersion, userAgent } from "./version.js"; +import { + Version, + displayVersion, + normalizeVersion, + userAgent, +} from "./version.js"; const updateCheckRepo = "OpenVanta/cli"; const updateCheckIntervalMs = 24 * 60 * 60 * 1000;