From e6615cba5dc673ab8f8848ce56aed750d9046ac5 Mon Sep 17 00:00:00 2001 From: scthornton Date: Thu, 28 May 2026 09:26:19 -0400 Subject: [PATCH 1/4] feat(runtime): add `customer-apps consumption` for per-app token + violations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Surfaces the SCM "AI Security > Runtime > API Applications" detail panel through the CLI, sourced from the SDK's new mgmt.dashboard namespace: airs runtime customer-apps consumption [appName] [--time-interval 7|30|60] [--output pretty|table|csv|json|yaml] Single-app mode renders a pretty section with token consumption (with K/M scale qualifiers), session counts, and firing detectors. Omitting appName loops every customer app in the tenant. Structured outputs emit one row per detector per app so downstream tools can pivot without join logic. Notes - Resolves appId from `customer-apps list` internally — users only pass the human-readable name. Throws with guidance if the name isn't found. - Validates --time-interval client-side against the API's enum (7, 30, 60); other values are rejected before incurring a request. - Per-detector rows include monitoring_since so the data is self-contained for chargeback reporting. Closes #222. Requires the new mgmt.dashboard SDK API (cdot65/prisma-airs-sdk PR pending) — bump @cdot65/prisma-airs-sdk after that lands and ships. --- .../runtime-customer-apps-consumption.md | 23 ++++ src/airs/management.ts | 65 +++++++++ src/airs/types.ts | 51 +++++++ src/cli/commands/runtime.ts | 51 +++++++ src/cli/renderer/runtime.ts | 109 +++++++++++++++ tests/unit/airs/management.spec.ts | 125 ++++++++++++++++++ 6 files changed, 424 insertions(+) create mode 100644 .changeset/runtime-customer-apps-consumption.md diff --git a/.changeset/runtime-customer-apps-consumption.md b/.changeset/runtime-customer-apps-consumption.md new file mode 100644 index 0000000..3bc5fc5 --- /dev/null +++ b/.changeset/runtime-customer-apps-consumption.md @@ -0,0 +1,23 @@ +--- +'@cdot65/prisma-airs-cli': minor +--- + +Add `airs runtime customer-apps consumption [appName]` for per-app token consumption + violation breakdown, sourced from the SCM AI Security > Runtime > API Applications dashboard endpoints (via the new `mgmt.dashboard` SDK namespace). + +``` +# pretty (default): per-app sections with tokens, sessions, firing detectors +airs runtime customer-apps consumption chatbot + +# all apps in tenant (omit appName) +airs runtime customer-apps consumption + +# 60-day window instead of default 30 +airs runtime customer-apps consumption chatbot --time-interval 60 + +# structured outputs (table / csv / json / yaml) — one row per detector per app +airs runtime customer-apps consumption --output csv > consumption.csv +``` + +The API enforces an enum for `--time-interval`: only `7`, `30`, and `60` are accepted (verified live 2026-05-28; the CLI validates client-side before calling). The dashboard endpoints require both `appId` and `appName`, so the CLI resolves the UUID from the `customer-apps list` endpoint internally - users only supply the human-readable app name. + +Closes #222. diff --git a/src/airs/management.ts b/src/airs/management.ts index 39273eb..d21efa3 100644 --- a/src/airs/management.ts +++ b/src/airs/management.ts @@ -9,6 +9,8 @@ import type { ProfileTopic } from '../audit/types.js'; import type { ApiKeyInfo, ApiKeyListResult, + ConsumptionQueryOptions, + CustomerAppConsumption, CustomerAppInfo, CustomerAppListResult, DeleteResponse, @@ -366,6 +368,69 @@ export class SdkManagementService implements ManagementService { return this.normalizeCustomerApp(response as unknown as Record); } + async getCustomerAppConsumption( + appName: string, + opts?: ConsumptionQueryOptions, + ): Promise { + // The dashboard endpoints need BOTH appId and appName; the only way to resolve appId + // from a name is via the list endpoint, so do that first. + const list = (await this.client.customerApps.list({ + offset: 0, + limit: 100, + })) as unknown as { customer_apps?: Array> }; + const apps = list.customer_apps ?? []; + const target = apps.find((a) => (a.app_name as string) === appName); + const appId = target?.customer_appId as string | undefined; + if (!appId) { + throw new Error( + `Customer app not found: "${appName}". Run \`airs runtime customer-apps list\` to see available apps.`, + ); + } + + const timeInterval = opts?.timeInterval ?? 30; + const query = { appId, appName, timeInterval } as const; + + const [overview, breakdown] = await Promise.all([ + this.client.dashboard.application(query), + this.client.dashboard.applicationViolationBreakdown(query), + ]); + + const ts = overview.token_stats ?? {}; + const ss = overview.session_stats ?? {}; + const detectors = (breakdown.detection_type_violation_breakdown ?? []).map((entry) => { + const vb = entry.violation_breakdown ?? {}; + return { + type: entry.detection_type ?? 'unknown', + critical: vb.critical ?? 0, + high: vb.high ?? 0, + medium: vb.medium ?? 0, + low: vb.low ?? 0, + total: vb.total ?? 0, + }; + }); + + return { + appId, + appName, + cloud: overview.cloud ?? undefined, + source: overview.source ?? undefined, + monitoringSince: overview.created_at ?? undefined, + profiles: overview.profiles ?? [], + tokens: { + dailyAverage: ts.average_daily_tokens ?? undefined, + dailyAverageScale: ts.average_daily_tokens_scale ?? undefined, + monthlyTotal: ts.monthly_total_tokens ?? undefined, + monthlyTotalScale: ts.monthly_total_tokens_scale ?? undefined, + }, + sessions: { + total: ss.total ?? 0, + violating: ss.violating ?? 0, + }, + detectors, + totalViolating: breakdown.total_violating ?? 0, + }; + } + // ------------------------------------------------------------------------- // Deployment Profiles (read-only) // ------------------------------------------------------------------------- diff --git a/src/airs/types.ts b/src/airs/types.ts index 909e168..c15e357 100644 --- a/src/airs/types.ts +++ b/src/airs/types.ts @@ -836,6 +836,52 @@ export interface CustomerAppListResult { nextOffset?: number; } +/** + * Per-app consumption + violation snapshot, normalized from the SDK's dashboard endpoints. + * Time window is fixed at construction. + */ +export interface CustomerAppConsumption { + appId: string; + appName: string; + cloud?: string; + source?: string; + /** ISO timestamp of first monitoring (corresponds to SCM panel's "Monitoring Since"). */ + monitoringSince?: string; + /** Attached security profile names. */ + profiles: string[]; + /** Token consumption stats with scale qualifier (K = thousands, M = millions). */ + tokens: { + dailyAverage?: number; + dailyAverageScale?: string; + monthlyTotal?: number; + monthlyTotalScale?: string; + }; + /** Session activity counts over the window. */ + sessions: { + total: number; + violating: number; + }; + /** Per-detector violation severity counts, one entry per detection_type. */ + detectors: Array<{ + type: string; + critical: number; + high: number; + medium: number; + low: number; + total: number; + }>; + /** Sum of violating sessions across all detectors (mirrors SCM panel's badge). */ + totalViolating: number; +} + +/** Allowed values for `--time-interval`. The API enforces this enum (other values return 400). */ +export type ConsumptionTimeInterval = 7 | 30 | 60; + +/** Options for {@link ManagementService.getCustomerAppConsumption}. */ +export interface ConsumptionQueryOptions { + timeInterval?: ConsumptionTimeInterval; +} + // --------------------------------------------------------------------------- // Deployment profile types // --------------------------------------------------------------------------- @@ -931,6 +977,11 @@ export interface ManagementService { getCustomerApp(appName: string): Promise; updateCustomerApp(appId: string, request: Record): Promise; deleteCustomerApp(appName: string, updatedBy: string): Promise; + /** Get per-app token consumption + violation breakdown from the SCM dashboard endpoints. */ + getCustomerAppConsumption( + appName: string, + opts?: ConsumptionQueryOptions, + ): Promise; // Deployment profiles listDeploymentProfiles(opts?: { unactivated?: boolean }): Promise; diff --git a/src/cli/commands/runtime.ts b/src/cli/commands/runtime.ts index 25e89a5..5d28695 100644 --- a/src/cli/commands/runtime.ts +++ b/src/cli/commands/runtime.ts @@ -18,6 +18,7 @@ import { type OutputFormat, renderApiKeyDetail, renderApiKeyList, + renderCustomerAppConsumption, renderCustomerAppDetail, renderCustomerAppList, renderDeploymentProfileList, @@ -314,6 +315,56 @@ export function registerRuntimeCommand(program: Command): void { } }); + customerApps + .command('consumption [appName]') + .description( + 'Show per-app token consumption + violation breakdown (SCM dashboard). Omit appName to scan all apps.', + ) + .option('--time-interval ', 'Window in days: 7, 30, or 60', '30') + .option('--output ', 'Output format: pretty, table, csv, json, yaml', 'pretty') + .action(async (appName: string | undefined, opts) => { + try { + const fmt = opts.output as OutputFormat; + const interval = Number.parseInt(opts.timeInterval, 10); + if (interval !== 7 && interval !== 30 && interval !== 60) { + renderError('--time-interval must be 7, 30, or 60 (the API rejects other values)'); + process.exit(1); + } + if (fmt === 'pretty') renderRuntimeConfigHeader(); + + const service = await createMgmtService(); + + // Single app mode: explicit name was given. + if (appName) { + const data = await service.getCustomerAppConsumption(appName, { + timeInterval: interval, + }); + renderCustomerAppConsumption(data, fmt); + return; + } + + // All-apps mode: loop the list and emit one record per app. + const list = await service.listCustomerApps({ limit: 100 }); + if (list.apps.length === 0) { + console.log(' No customer apps found.'); + return; + } + for (const app of list.apps) { + try { + const data = await service.getCustomerAppConsumption(app.name, { + timeInterval: interval, + }); + renderCustomerAppConsumption(data, fmt); + } catch (err) { + renderError(`[${app.name}] ${err instanceof Error ? err.message : String(err)}`); + } + } + } catch (err) { + renderError(err instanceof Error ? err.message : String(err)); + process.exit(1); + } + }); + // ----------------------------------------------------------------------- // runtime deployment-profiles — read-only listing // ----------------------------------------------------------------------- diff --git a/src/cli/renderer/runtime.ts b/src/cli/renderer/runtime.ts index b97f12f..7dbfbae 100644 --- a/src/cli/renderer/runtime.ts +++ b/src/cli/renderer/runtime.ts @@ -422,6 +422,115 @@ export function renderCustomerAppDetail(app: { console.log(); } +/** Render per-app consumption + violation breakdown. */ +export function renderCustomerAppConsumption( + data: { + appId: string; + appName: string; + cloud?: string; + source?: string; + monitoringSince?: string; + profiles: string[]; + tokens: { + dailyAverage?: number; + dailyAverageScale?: string; + monthlyTotal?: number; + monthlyTotalScale?: string; + }; + sessions: { total: number; violating: number }; + detectors: Array<{ + type: string; + critical: number; + high: number; + medium: number; + low: number; + total: number; + }>; + totalViolating: number; + }, + format: OutputFormat = 'pretty', +): void { + const fmt = (n?: number, scale?: string) => (n == null ? '-' : `${n}${scale ?? ''}`); + + if (format !== 'pretty') { + // Per-detector rows for table/csv/json/yaml. Adds app-level fields so each row is + // self-contained (useful for piping into reporting tools). + const rows = data.detectors.map((d) => ({ + app_name: data.appName, + app_id: data.appId, + monitoring_since: data.monitoringSince ?? '', + daily_avg: fmt(data.tokens.dailyAverage, data.tokens.dailyAverageScale), + monthly_total: fmt(data.tokens.monthlyTotal, data.tokens.monthlyTotalScale), + sessions_total: data.sessions.total, + sessions_violating: data.sessions.violating, + detector: d.type, + critical: d.critical, + high: d.high, + medium: d.medium, + low: d.low, + total: d.total, + })); + console.log( + formatOutput( + rows, + [ + { key: 'app_name', label: 'App' }, + { key: 'app_id', label: 'AppId' }, + { key: 'monitoring_since', label: 'MonitoringSince' }, + { key: 'daily_avg', label: 'DailyAvg' }, + { key: 'monthly_total', label: 'MonthlyTotal' }, + { key: 'sessions_total', label: 'Sessions' }, + { key: 'sessions_violating', label: 'Violating' }, + { key: 'detector', label: 'Detector' }, + { key: 'critical', label: 'C' }, + { key: 'high', label: 'H' }, + { key: 'medium', label: 'M' }, + { key: 'low', label: 'L' }, + { key: 'total', label: 'Total' }, + ], + format, + ), + ); + return; + } + + console.log(chalk.bold(`\n ${data.appName} ${chalk.dim('(' + data.appId + ')')}`)); + if (data.monitoringSince) console.log(` Monitoring since: ${chalk.dim(data.monitoringSince)}`); + if (data.source) console.log(` Source: ${data.source}`); + if (data.cloud) console.log(` Cloud: ${data.cloud}`); + if (data.profiles.length > 0) { + console.log(` Profiles: ${data.profiles.join(', ')}`); + } + + console.log(chalk.bold('\n Token consumption:')); + console.log( + ` Daily avg: ${fmt(data.tokens.dailyAverage, data.tokens.dailyAverageScale)}`, + ); + console.log( + ` Monthly total: ${fmt(data.tokens.monthlyTotal, data.tokens.monthlyTotalScale)}`, + ); + + console.log(chalk.bold('\n Sessions:')); + console.log(` Total: ${data.sessions.total}`); + console.log(` Violating: ${data.sessions.violating}`); + + const firing = data.detectors.filter((d) => d.total > 0); + console.log( + chalk.bold( + `\n Detectors (${data.totalViolating} violating, ${firing.length}/${data.detectors.length} firing):`, + ), + ); + if (firing.length === 0) { + console.log(chalk.dim(' no detector violations in window')); + } else { + for (const d of firing) { + const sev = `c=${d.critical} h=${d.high} m=${d.medium} l=${d.low}`; + console.log(` ${d.type.padEnd(20)} ${String(d.total).padStart(5)} ${chalk.dim(sev)}`); + } + } + console.log(); +} + /** Render deployment profile list. */ export function renderDeploymentProfileList( profiles: Array<{ raw: Record }>, diff --git a/tests/unit/airs/management.spec.ts b/tests/unit/airs/management.spec.ts index 3a8d86b..07d67b3 100644 --- a/tests/unit/airs/management.spec.ts +++ b/tests/unit/airs/management.spec.ts @@ -47,6 +47,8 @@ const mockCustomerAppsUpdate = vi.fn(); const mockCustomerAppsDelete = vi.fn(); const mockDeploymentProfilesList = vi.fn(); const mockScanLogsQuery = vi.fn(); +const mockDashboardApplication = vi.fn(); +const mockDashboardViolationBreakdown = vi.fn(); vi.mock('@cdot65/prisma-airs-sdk', () => ({ ManagementClient: vi.fn().mockImplementation(() => ({ @@ -84,6 +86,10 @@ vi.mock('@cdot65/prisma-airs-sdk', () => ({ scanLogs: { query: mockScanLogsQuery, }, + dashboard: { + application: mockDashboardApplication, + applicationViolationBreakdown: mockDashboardViolationBreakdown, + }, })), })); @@ -1179,6 +1185,125 @@ describe('SdkManagementService', () => { }); }); }); + + describe('getCustomerAppConsumption', () => { + function primeApps() { + mockCustomerAppsList.mockResolvedValue({ + customer_apps: [ + { customer_appId: 'uuid-chatbot', app_name: 'chatbot' }, + { customer_appId: 'uuid-litellm', app_name: 'litellm' }, + ], + next_offset: 0, + }); + } + + it('resolves appId from list, calls both dashboard endpoints, normalizes the result', async () => { + primeApps(); + mockDashboardApplication.mockResolvedValue({ + id: 'uuid-chatbot', + name: 'chatbot', + cloud: 'other', + source: 'api', + created_at: '2026-04-29T17:04:52Z', + profiles: ['ms-tuned', 'golden-v2'], + token_stats: { + average_daily_tokens: 744.233, + average_daily_tokens_scale: 'K', + monthly_total_tokens: 17.71, + monthly_total_tokens_scale: 'M', + }, + session_stats: { total: 56935, violating: 31136 }, + }); + mockDashboardViolationBreakdown.mockResolvedValue({ + detection_type_violation_breakdown: [ + { + detection_type: 'topic_guardrails', + violation_breakdown: { critical: 0, high: 0, medium: 3, low: 0, total: 3 }, + }, + { + detection_type: 'dlp', + violation_breakdown: { critical: 0, high: 0, medium: 0, low: 0, total: 0 }, + }, + ], + total_violating: 3, + }); + + const result = await service.getCustomerAppConsumption('chatbot'); + + expect(result.appId).toBe('uuid-chatbot'); + expect(result.appName).toBe('chatbot'); + expect(result.tokens.dailyAverage).toBe(744.233); + expect(result.tokens.dailyAverageScale).toBe('K'); + expect(result.tokens.monthlyTotalScale).toBe('M'); + expect(result.sessions.total).toBe(56935); + expect(result.sessions.violating).toBe(31136); + expect(result.profiles).toEqual(['ms-tuned', 'golden-v2']); + expect(result.totalViolating).toBe(3); + expect(result.detectors).toHaveLength(2); + const tg = result.detectors.find((d) => d.type === 'topic_guardrails'); + expect(tg).toEqual({ + type: 'topic_guardrails', + critical: 0, + high: 0, + medium: 3, + low: 0, + total: 3, + }); + + expect(mockDashboardApplication).toHaveBeenCalledWith({ + appId: 'uuid-chatbot', + appName: 'chatbot', + timeInterval: 30, + }); + expect(mockDashboardViolationBreakdown).toHaveBeenCalledWith({ + appId: 'uuid-chatbot', + appName: 'chatbot', + timeInterval: 30, + }); + }); + + it('passes through the timeInterval option', async () => { + primeApps(); + mockDashboardApplication.mockResolvedValue({}); + mockDashboardViolationBreakdown.mockResolvedValue({}); + + await service.getCustomerAppConsumption('litellm', { timeInterval: 60 }); + + expect(mockDashboardApplication).toHaveBeenCalledWith({ + appId: 'uuid-litellm', + appName: 'litellm', + timeInterval: 60, + }); + }); + + it('throws a clear error when the app name is not found in the list', async () => { + mockCustomerAppsList.mockResolvedValue({ customer_apps: [], next_offset: 0 }); + await expect(service.getCustomerAppConsumption('nonexistent')).rejects.toThrow( + /Customer app not found.*nonexistent/i, + ); + expect(mockDashboardApplication).not.toHaveBeenCalled(); + expect(mockDashboardViolationBreakdown).not.toHaveBeenCalled(); + }); + + it('returns zeros for missing/null fields rather than throwing', async () => { + primeApps(); + mockDashboardApplication.mockResolvedValue({ + name: null, + token_stats: null, + session_stats: null, + profiles: null, + }); + mockDashboardViolationBreakdown.mockResolvedValue({}); + + const result = await service.getCustomerAppConsumption('chatbot'); + expect(result.tokens.dailyAverage).toBeUndefined(); + expect(result.sessions.total).toBe(0); + expect(result.sessions.violating).toBe(0); + expect(result.profiles).toEqual([]); + expect(result.detectors).toEqual([]); + expect(result.totalViolating).toBe(0); + }); + }); }); describe('getOrCreateManagementClient', () => { From bed80224c77efa601731ee73f907ea75c1ed79bc Mon Sep 17 00:00:00 2001 From: Calvin Remsburg Date: Thu, 28 May 2026 12:25:13 -0500 Subject: [PATCH 2/4] chore(deps): bump SDK to ^0.11.0 for dashboard namespace --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index db2ad41..f102f66 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "license": "MIT", "dependencies": { "@anthropic-ai/vertex-sdk": "^0.14.4", - "@cdot65/prisma-airs-sdk": "^0.10.0", + "@cdot65/prisma-airs-sdk": "^0.11.0", "@inquirer/prompts": "^8.3.0", "@langchain/anthropic": "^1.3.25", "@langchain/aws": "^1.3.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 550b393..f6f3603 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: specifier: ^0.14.4 version: 0.14.4(zod@3.25.76) '@cdot65/prisma-airs-sdk': - specifier: ^0.10.0 - version: 0.10.0 + specifier: ^0.11.0 + version: 0.11.0 '@inquirer/prompts': specifier: ^8.3.0 version: 8.3.0(@types/node@22.19.13) @@ -334,8 +334,8 @@ packages: cpu: [x64] os: [win32] - '@cdot65/prisma-airs-sdk@0.10.0': - resolution: {integrity: sha512-nRTfxduC69kGfdJd5xTYZN5VuaH8Qq0ZjgtadVaQynygvlF8RFU4f2bNUEK9Y3iLiBF/KguuzbKCOAsg8tRyrg==} + '@cdot65/prisma-airs-sdk@0.11.0': + resolution: {integrity: sha512-rZ5vIfTQaFRfu4ypsiHMNr0btQRMJY57SRu84vy1lXYHd9DByqstLHnNGl25CpuVnMviUHWZ/EYIedxMkySA7w==} engines: {node: '>=18'} '@cfworker/json-schema@4.1.1': @@ -3069,7 +3069,7 @@ snapshots: '@biomejs/cli-win32-x64@2.4.5': optional: true - '@cdot65/prisma-airs-sdk@0.10.0': + '@cdot65/prisma-airs-sdk@0.11.0': dependencies: zod: 3.25.76 From 5f430ffd2f54664f924051b60ebbdb0e9402c668 Mon Sep 17 00:00:00 2001 From: Calvin Remsburg Date: Thu, 28 May 2026 12:25:47 -0500 Subject: [PATCH 3/4] chore(docs): regen customer-apps reference + allowlist consumption pending sidecars --- docs/cli/examples/.missing-allowlist | 2 ++ docs/cli/runtime/customer-apps.md | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/docs/cli/examples/.missing-allowlist b/docs/cli/examples/.missing-allowlist index 66f074d..13268b0 100644 --- a/docs/cli/examples/.missing-allowlist +++ b/docs/cli/examples/.missing-allowlist @@ -4,6 +4,8 @@ runtime api-keys delete # Blocked by upstream — see https://github.com/cdot65/prisma-airs-cli/issues/115 runtime customer-apps get +# Awaiting curated sidecars from PR #236 author — new command in v2.12.0 +runtime customer-apps consumption # Blocked by upstream API 503 — see https://github.com/cdot65/prisma-airs-cli/issues/193 runtime customer-apps update # Blocked by SDK — see https://github.com/cdot65/prisma-airs-sdk/issues/167 diff --git a/docs/cli/runtime/customer-apps.md b/docs/cli/runtime/customer-apps.md index c2d065d..29f4bee 100644 --- a/docs/cli/runtime/customer-apps.md +++ b/docs/cli/runtime/customer-apps.md @@ -139,3 +139,29 @@ airs runtime customer-apps delete [options] !!! warning "Example needed" No curated input/output example for this command yet. + +--- + +### runtime customer-apps consumption + +Show per-app token consumption + violation breakdown (SCM dashboard). Omit appName to scan all apps. + +```text +airs runtime customer-apps consumption [options] [appName] +``` + +#### Arguments + +- `appName` (optional) — + +#### Options + +| Flag | Required | Default | Description | +|------|:--------:|---------|-------------| +| `--time-interval ` | No | `30` | Window in days: 7, 30, or 60 | +| `--output ` | No | `pretty` | Output format: pretty, table, csv, json, yaml | + +#### Examples + +!!! warning "Example needed" + No curated input/output example for this command yet. From fe7f686ebc68909739493397bfc8365751b28e15 Mon Sep 17 00:00:00 2001 From: Calvin Remsburg Date: Thu, 28 May 2026 12:43:59 -0500 Subject: [PATCH 4/4] docs(examples): land curated sidecars for customer-apps consumption Captures 8 examples (pretty/table/csv/json/yaml + 60-day window + all-apps loop + both error paths) from live tenant; removes the allowlist entry; regenerates customer-apps.md so the reference page now renders real input/output instead of "Example needed". Addresses follow-up #1 from the PR #236 validation comment. --- docs/cli/examples/.missing-allowlist | 2 - docs/cli/examples/runtime.yaml | 103 ++++++++++++ docs/cli/runtime/customer-apps.md | 151 +++++++++++++++++- .../api/classes/SdkManagementService.md | 86 ++++++---- 4 files changed, 309 insertions(+), 33 deletions(-) diff --git a/docs/cli/examples/.missing-allowlist b/docs/cli/examples/.missing-allowlist index 13268b0..66f074d 100644 --- a/docs/cli/examples/.missing-allowlist +++ b/docs/cli/examples/.missing-allowlist @@ -4,8 +4,6 @@ runtime api-keys delete # Blocked by upstream — see https://github.com/cdot65/prisma-airs-cli/issues/115 runtime customer-apps get -# Awaiting curated sidecars from PR #236 author — new command in v2.12.0 -runtime customer-apps consumption # Blocked by upstream API 503 — see https://github.com/cdot65/prisma-airs-cli/issues/193 runtime customer-apps update # Blocked by SDK — see https://github.com/cdot65/prisma-airs-sdk/issues/167 diff --git a/docs/cli/examples/runtime.yaml b/docs/cli/examples/runtime.yaml index b6ec682..7a68125 100644 --- a/docs/cli/examples/runtime.yaml +++ b/docs/cli/examples/runtime.yaml @@ -1510,6 +1510,109 @@ name: example-other-app description: +"runtime customer-apps consumption": + examples: + - note: Pretty output (default) — single app, default 30-day window. Only firing detectors are shown. + input: airs runtime customer-apps consumption example-app + output: | + Prisma AIRS — Runtime Configuration + Security profile and topic management + + + example-app (00000000-0000-0000-0000-000000000001) + Monitoring since: 2026-05-25T16:42:52Z + Source: api + Cloud: other + Profiles: AI Gateway - Strict + + Token consumption: + Daily avg: 37 + Monthly total: 37 + + Sessions: + Total: 2 + Violating: 1 + + Detectors (1 violating, 1/8 firing): + tc 1 c=0 h=0 m=1 l=0 + - note: Table output — one row per detector, app-level context repeated on every row. + input: airs runtime customer-apps consumption example-app --output table + output: | + App │ AppId │ MonitoringSince │ DailyAvg │ MonthlyTotal │ Sessions │ Violating │ Detector │ C │ H │ M │ L │ Total + ────────────┼──────────────────────────────────────┼──────────────────────┼──────────┼──────────────┼──────────┼───────────┼────────────────┼───┼───┼───┼───┼─────── + example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ agent_security │ 0 │ 0 │ 0 │ 0 │ 0 + example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ dbs │ 0 │ 0 │ 0 │ 0 │ 0 + example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ dlp │ 0 │ 0 │ 0 │ 0 │ 0 + example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ malicious_code │ 0 │ 0 │ 0 │ 0 │ 0 + example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ pi │ 0 │ 0 │ 0 │ 0 │ 0 + example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ source_code │ 0 │ 0 │ 0 │ 0 │ 0 + example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ tc │ 0 │ 0 │ 1 │ 0 │ 1 + example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ uf │ 0 │ 0 │ 0 │ 0 │ 0 + - note: CSV output — pipe straight into spreadsheets or BigQuery. Self-contained rows; no join needed. + input: airs runtime customer-apps consumption example-app --output csv + output: | + App,AppId,MonitoringSince,DailyAvg,MonthlyTotal,Sessions,Violating,Detector,C,H,M,L,Total + example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,agent_security,0,0,0,0,0 + example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,dbs,0,0,0,0,0 + example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,dlp,0,0,0,0,0 + example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,malicious_code,0,0,0,0,0 + example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,pi,0,0,0,0,0 + example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,source_code,0,0,0,0,0 + example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,tc,0,0,1,0,1 + example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,uf,0,0,0,0,0 + - note: JSON output — one object per detector per app; full app context repeated for self-contained records. + input: airs runtime customer-apps consumption example-app --output json + output: | + [ + { + "app_name": "example-app", + "app_id": "00000000-0000-0000-0000-000000000001", + "monitoring_since": "2026-05-25T16:42:52Z", + "daily_avg": "37", + "monthly_total": "37", + "sessions_total": 2, + "sessions_violating": 1, + "detector": "tc", + "critical": 0, + "high": 0, + "medium": 1, + "low": 0, + "total": 1 + } + ] + - note: YAML output — multi-doc stream, one document per detector per app. + input: airs runtime customer-apps consumption example-app --output yaml + output: | + app_name: example-app + app_id: 00000000-0000-0000-0000-000000000001 + monitoring_since: 2026-05-25T16:42:52Z + daily_avg: '37' + monthly_total: '37' + sessions_total: 2 + sessions_violating: 1 + detector: tc + critical: 0 + high: 0 + medium: 1 + low: 0 + total: 1 + - note: Alternate time window — `--time-interval` accepts 7, 30, or 60 days (server-enforced enum). + input: airs runtime customer-apps consumption example-app --time-interval 60 + - note: All-apps loop — omit `appName` to scan every customer app in the tenant. Errors on individual apps are reported per-app; the loop continues past failures. Zero-traffic apps render `no detector violations in window`. + input: airs runtime customer-apps consumption + - note: Invalid time-interval rejected client-side before incurring an API call. + input: airs runtime customer-apps consumption example-app --time-interval 14 + output: | + Error: --time-interval must be 7, 30, or 60 (the API rejects other values) + - note: Unknown app name returns a helpful error pointing at `customer-apps list`. + input: airs runtime customer-apps consumption no-such-app + output: | + Prisma AIRS — Runtime Configuration + Security profile and topic management + + + Error: Customer app not found: "no-such-app". Run `airs runtime customer-apps list` to see available apps. + "runtime api-keys create": examples: - note: Create a new API key from a config fixture (no JSON output flag — pretty only). The full secret is echoed exactly once; subsequent `list` only shows `last8`. diff --git a/docs/cli/runtime/customer-apps.md b/docs/cli/runtime/customer-apps.md index 29f4bee..7a5175f 100644 --- a/docs/cli/runtime/customer-apps.md +++ b/docs/cli/runtime/customer-apps.md @@ -163,5 +163,152 @@ airs runtime customer-apps consumption [options] [appName] #### Examples -!!! warning "Example needed" - No curated input/output example for this command yet. +*Pretty output (default) — single app, default 30-day window. Only firing detectors are shown.* + +```bash +airs runtime customer-apps consumption example-app +``` + +```text +Prisma AIRS — Runtime Configuration +Security profile and topic management + + +example-app (00000000-0000-0000-0000-000000000001) + Monitoring since: 2026-05-25T16:42:52Z + Source: api + Cloud: other + Profiles: AI Gateway - Strict + + Token consumption: + Daily avg: 37 + Monthly total: 37 + + Sessions: + Total: 2 + Violating: 1 + + Detectors (1 violating, 1/8 firing): + tc 1 c=0 h=0 m=1 l=0 +``` + +*Table output — one row per detector, app-level context repeated on every row.* + +```bash +airs runtime customer-apps consumption example-app --output table +``` + +```text +App │ AppId │ MonitoringSince │ DailyAvg │ MonthlyTotal │ Sessions │ Violating │ Detector │ C │ H │ M │ L │ Total +────────────┼──────────────────────────────────────┼──────────────────────┼──────────┼──────────────┼──────────┼───────────┼────────────────┼───┼───┼───┼───┼─────── +example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ agent_security │ 0 │ 0 │ 0 │ 0 │ 0 +example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ dbs │ 0 │ 0 │ 0 │ 0 │ 0 +example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ dlp │ 0 │ 0 │ 0 │ 0 │ 0 +example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ malicious_code │ 0 │ 0 │ 0 │ 0 │ 0 +example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ pi │ 0 │ 0 │ 0 │ 0 │ 0 +example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ source_code │ 0 │ 0 │ 0 │ 0 │ 0 +example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ tc │ 0 │ 0 │ 1 │ 0 │ 1 +example-app │ 00000000-0000-0000-0000-000000000001 │ 2026-05-25T16:42:52Z │ 37 │ 37 │ 2 │ 1 │ uf │ 0 │ 0 │ 0 │ 0 │ 0 +``` + +*CSV output — pipe straight into spreadsheets or BigQuery. Self-contained rows; no join needed.* + +```bash +airs runtime customer-apps consumption example-app --output csv +``` + +```text +App,AppId,MonitoringSince,DailyAvg,MonthlyTotal,Sessions,Violating,Detector,C,H,M,L,Total +example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,agent_security,0,0,0,0,0 +example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,dbs,0,0,0,0,0 +example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,dlp,0,0,0,0,0 +example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,malicious_code,0,0,0,0,0 +example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,pi,0,0,0,0,0 +example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,source_code,0,0,0,0,0 +example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,tc,0,0,1,0,1 +example-app,00000000-0000-0000-0000-000000000001,2026-05-25T16:42:52Z,37,37,2,1,uf,0,0,0,0,0 +``` + +*JSON output — one object per detector per app; full app context repeated for self-contained records.* + +```bash +airs runtime customer-apps consumption example-app --output json +``` + +```text +[ + { + "app_name": "example-app", + "app_id": "00000000-0000-0000-0000-000000000001", + "monitoring_since": "2026-05-25T16:42:52Z", + "daily_avg": "37", + "monthly_total": "37", + "sessions_total": 2, + "sessions_violating": 1, + "detector": "tc", + "critical": 0, + "high": 0, + "medium": 1, + "low": 0, + "total": 1 + } +] +``` + +*YAML output — multi-doc stream, one document per detector per app.* + +```bash +airs runtime customer-apps consumption example-app --output yaml +``` + +```text +app_name: example-app +app_id: 00000000-0000-0000-0000-000000000001 +monitoring_since: 2026-05-25T16:42:52Z +daily_avg: '37' +monthly_total: '37' +sessions_total: 2 +sessions_violating: 1 +detector: tc +critical: 0 +high: 0 +medium: 1 +low: 0 +total: 1 +``` + +*Alternate time window — `--time-interval` accepts 7, 30, or 60 days (server-enforced enum).* + +```bash +airs runtime customer-apps consumption example-app --time-interval 60 +``` + +*All-apps loop — omit `appName` to scan every customer app in the tenant. Errors on individual apps are reported per-app; the loop continues past failures. Zero-traffic apps render `no detector violations in window`.* + +```bash +airs runtime customer-apps consumption +``` + +*Invalid time-interval rejected client-side before incurring an API call.* + +```bash +airs runtime customer-apps consumption example-app --time-interval 14 +``` + +```text +Error: --time-interval must be 7, 30, or 60 (the API rejects other values) +``` + +*Unknown app name returns a helpful error pointing at `customer-apps list`.* + +```bash +airs runtime customer-apps consumption no-such-app +``` + +```text +Prisma AIRS — Runtime Configuration +Security profile and topic management + + +Error: Customer app not found: "no-such-app". Run `airs runtime customer-apps list` to see available apps. +``` diff --git a/docs/developers/api/classes/SdkManagementService.md b/docs/developers/api/classes/SdkManagementService.md index cfdb765..3340e46 100644 --- a/docs/developers/api/classes/SdkManagementService.md +++ b/docs/developers/api/classes/SdkManagementService.md @@ -1,6 +1,6 @@ # Class: SdkManagementService -Defined in: [src/airs/management.ts:28](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L28) +Defined in: [src/airs/management.ts:30](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L30) Wraps the SDK's ManagementClient to implement our ManagementService interface. OAuth2 token management, caching, and retry are handled by the SDK. @@ -15,7 +15,7 @@ OAuth2 token management, caching, and retry are handled by the SDK. > **new SdkManagementService**(`opts?`): `SdkManagementService` -Defined in: [src/airs/management.ts:31](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L31) +Defined in: [src/airs/management.ts:33](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L33) #### Parameters @@ -33,7 +33,7 @@ Defined in: [src/airs/management.ts:31](https://github.com/cdot65/prisma-airs-cl > **assignTopicsToProfile**(`profileName`, `topics`, `guardrailAction?`): `Promise`\<`void`\> -Defined in: [src/airs/management.ts:93](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L93) +Defined in: [src/airs/management.ts:95](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L95) Sets one or more custom topics on a profile's topic-guardrails config. Replaces any existing topics — previous runs' stale topics are cleared. @@ -71,7 +71,7 @@ it defaults to revision 0 (original content), not the latest. > **assignTopicToProfile**(`profileName`, `topicId`, `topicName`, `action`): `Promise`\<`void`\> -Defined in: [src/airs/management.ts:75](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L75) +Defined in: [src/airs/management.ts:77](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L77) Sets a single custom topic on a profile's topic-guardrails config. Delegates to [assignTopicsToProfile](#assigntopicstoprofile) for backward compatibility. @@ -108,7 +108,7 @@ Delegates to [assignTopicsToProfile](#assigntopicstoprofile) for backward compat > **createApiKey**(`request`): `Promise`\<`ApiKeyInfo`\> -Defined in: [src/airs/management.ts:313](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L313) +Defined in: [src/airs/management.ts:315](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L315) #### Parameters @@ -130,7 +130,7 @@ Defined in: [src/airs/management.ts:313](https://github.com/cdot65/prisma-airs-c > **createProfile**(`request`): `Promise`\<`SecurityProfileInfo`\> -Defined in: [src/airs/management.ts:265](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L265) +Defined in: [src/airs/management.ts:267](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L267) Create a security profile. @@ -154,7 +154,7 @@ Create a security profile. > **createTopic**(`request`): `Promise`\<`objectOutputType`\<\{ `active`: `ZodOptional`\<`ZodBoolean`\>; `created_by`: `ZodOptional`\<`ZodString`\>; `created_ts`: `ZodOptional`\<`ZodString`\>; `description`: `ZodString`; `examples`: `ZodArray`\<`ZodString`, `"many"`\>; `last_modified_ts`: `ZodOptional`\<`ZodString`\>; `revision`: `ZodNumber`; `topic_id`: `ZodOptional`\<`ZodString`\>; `topic_name`: `ZodString`; `updated_by`: `ZodOptional`\<`ZodString`\>; \}, `ZodTypeAny`, `"passthrough"`\>\> -Defined in: [src/airs/management.ts:35](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L35) +Defined in: [src/airs/management.ts:37](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L37) Create a new custom topic. @@ -178,7 +178,7 @@ Create a new custom topic. > **deleteApiKey**(`apiKeyName`, `updatedBy`): `Promise`\<`DeleteResponse`\> -Defined in: [src/airs/management.ts:323](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L323) +Defined in: [src/airs/management.ts:325](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L325) #### Parameters @@ -204,7 +204,7 @@ Defined in: [src/airs/management.ts:323](https://github.com/cdot65/prisma-airs-c > **deleteCustomerApp**(`appName`, `updatedBy`): `Promise`\<`CustomerAppInfo`\> -Defined in: [src/airs/management.ts:364](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L364) +Defined in: [src/airs/management.ts:366](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L366) #### Parameters @@ -230,7 +230,7 @@ Defined in: [src/airs/management.ts:364](https://github.com/cdot65/prisma-airs-c > **deleteProfile**(`profileId`): `Promise`\<`DeleteResponse`\> -Defined in: [src/airs/management.ts:278](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L278) +Defined in: [src/airs/management.ts:280](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L280) Delete a security profile. @@ -254,7 +254,7 @@ Delete a security profile. > **deleteTopic**(`topicId`): `Promise`\<`void`\> -Defined in: [src/airs/management.ts:43](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L43) +Defined in: [src/airs/management.ts:45](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L45) Delete a custom topic by ID. @@ -278,7 +278,7 @@ Delete a custom topic by ID. > **forceDeleteProfile**(`profileId`, `updatedBy`): `Promise`\<`DeleteResponse`\> -Defined in: [src/airs/management.ts:283](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L283) +Defined in: [src/airs/management.ts:285](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L285) Force-delete a security profile (removes from referencing policies). @@ -306,7 +306,7 @@ Force-delete a security profile (removes from referencing policies). > **forceDeleteTopic**(`topicId`, `updatedBy?`): `Promise`\<`DeleteResponse`\> -Defined in: [src/airs/management.ts:47](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L47) +Defined in: [src/airs/management.ts:49](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L49) Force-delete a custom topic (removes from all referencing profiles). @@ -334,7 +334,7 @@ Force-delete a custom topic (removes from all referencing profiles). > **getCustomerApp**(`appName`): `Promise`\<`CustomerAppInfo`\> -Defined in: [src/airs/management.ts:351](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L351) +Defined in: [src/airs/management.ts:353](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L353) #### Parameters @@ -352,11 +352,39 @@ Defined in: [src/airs/management.ts:351](https://github.com/cdot65/prisma-airs-c *** +### getCustomerAppConsumption() + +> **getCustomerAppConsumption**(`appName`, `opts?`): `Promise`\<`CustomerAppConsumption`\> + +Defined in: [src/airs/management.ts:371](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L371) + +Get per-app token consumption + violation breakdown from the SCM dashboard endpoints. + +#### Parameters + +##### appName + +`string` + +##### opts? + +`ConsumptionQueryOptions` + +#### Returns + +`Promise`\<`CustomerAppConsumption`\> + +#### Implementation of + +`ManagementService.getCustomerAppConsumption` + +*** + ### getProfile() > **getProfile**(`profileId`): `Promise`\<`SecurityProfileInfo`\> -Defined in: [src/airs/management.ts:245](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L245) +Defined in: [src/airs/management.ts:247](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L247) Get a single security profile by UUID. @@ -380,7 +408,7 @@ Get a single security profile by UUID. > **getProfileByName**(`profileName`): `Promise`\<`SecurityProfileInfo`\> -Defined in: [src/airs/management.ts:250](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L250) +Defined in: [src/airs/management.ts:252](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L252) Get a single security profile by name (returns highest revision). @@ -404,7 +432,7 @@ Get a single security profile by name (returns highest revision). > **getProfileTopics**(`profileName`): `Promise`\<[`ProfileTopic`](../interfaces/ProfileTopic.md)[]\> -Defined in: [src/airs/management.ts:173](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L173) +Defined in: [src/airs/management.ts:175](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L175) List all topics configured in a profile with full details. @@ -428,7 +456,7 @@ List all topics configured in a profile with full details. > **getTopic**(`topicId`): `Promise`\<`objectOutputType`\<\{ `active`: `ZodOptional`\<`ZodBoolean`\>; `created_by`: `ZodOptional`\<`ZodString`\>; `created_ts`: `ZodOptional`\<`ZodString`\>; `description`: `ZodString`; `examples`: `ZodArray`\<`ZodString`, `"many"`\>; `last_modified_ts`: `ZodOptional`\<`ZodString`\>; `revision`: `ZodNumber`; `topic_id`: `ZodOptional`\<`ZodString`\>; `topic_name`: `ZodString`; `updated_by`: `ZodOptional`\<`ZodString`\>; \}, `ZodTypeAny`, `"passthrough"`\>\> -Defined in: [src/airs/management.ts:57](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L57) +Defined in: [src/airs/management.ts:59](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L59) Get a single custom topic by ID. @@ -452,7 +480,7 @@ Get a single custom topic by ID. > **getTopicByName**(`topicName`): `Promise`\<`objectOutputType`\<\{ `active`: `ZodOptional`\<`ZodBoolean`\>; `created_by`: `ZodOptional`\<`ZodString`\>; `created_ts`: `ZodOptional`\<`ZodString`\>; `description`: `ZodString`; `examples`: `ZodArray`\<`ZodString`, `"many"`\>; `last_modified_ts`: `ZodOptional`\<`ZodString`\>; `revision`: `ZodNumber`; `topic_id`: `ZodOptional`\<`ZodString`\>; `topic_name`: `ZodString`; `updated_by`: `ZodOptional`\<`ZodString`\>; \}, `ZodTypeAny`, `"passthrough"`\>\> -Defined in: [src/airs/management.ts:64](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L64) +Defined in: [src/airs/management.ts:66](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L66) Get a single custom topic by name. @@ -476,7 +504,7 @@ Get a single custom topic by name. > **listApiKeys**(`opts?`): `Promise`\<`ApiKeyListResult`\> -Defined in: [src/airs/management.ts:303](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L303) +Defined in: [src/airs/management.ts:305](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L305) #### Parameters @@ -498,7 +526,7 @@ Defined in: [src/airs/management.ts:303](https://github.com/cdot65/prisma-airs-c > **listCustomerApps**(`opts?`): `Promise`\<`CustomerAppListResult`\> -Defined in: [src/airs/management.ts:341](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L341) +Defined in: [src/airs/management.ts:343](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L343) #### Parameters @@ -520,7 +548,7 @@ Defined in: [src/airs/management.ts:341](https://github.com/cdot65/prisma-airs-c > **listDeploymentProfiles**(`opts?`): `Promise`\<`DeploymentProfileInfo`[]\> -Defined in: [src/airs/management.ts:373](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L373) +Defined in: [src/airs/management.ts:438](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L438) #### Parameters @@ -544,7 +572,7 @@ Defined in: [src/airs/management.ts:373](https://github.com/cdot65/prisma-airs-c > **listProfiles**(`opts?`): `Promise`\<`SecurityProfileListResult`\> -Defined in: [src/airs/management.ts:255](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L255) +Defined in: [src/airs/management.ts:257](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L257) List security profiles. @@ -568,7 +596,7 @@ List security profiles. > **listTopics**(): `Promise`\<`objectOutputType`\<\{ `active`: `ZodOptional`\<`ZodBoolean`\>; `created_by`: `ZodOptional`\<`ZodString`\>; `created_ts`: `ZodOptional`\<`ZodString`\>; `description`: `ZodString`; `examples`: `ZodArray`\<`ZodString`, `"many"`\>; `last_modified_ts`: `ZodOptional`\<`ZodString`\>; `revision`: `ZodNumber`; `topic_id`: `ZodOptional`\<`ZodString`\>; `topic_name`: `ZodString`; `updated_by`: `ZodOptional`\<`ZodString`\>; \}, `ZodTypeAny`, `"passthrough"`\>[]\> -Defined in: [src/airs/management.ts:52](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L52) +Defined in: [src/airs/management.ts:54](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L54) List all custom topics. @@ -586,7 +614,7 @@ List all custom topics. > **queryScanLogs**(`opts`): `Promise`\<`ScanLogQueryResult`\> -Defined in: [src/airs/management.ts:384](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L384) +Defined in: [src/airs/management.ts:449](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L449) #### Parameters @@ -608,7 +636,7 @@ Defined in: [src/airs/management.ts:384](https://github.com/cdot65/prisma-airs-c > **regenerateApiKey**(`apiKeyId`, `request`): `Promise`\<`ApiKeyInfo`\> -Defined in: [src/airs/management.ts:318](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L318) +Defined in: [src/airs/management.ts:320](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L320) #### Parameters @@ -634,7 +662,7 @@ Defined in: [src/airs/management.ts:318](https://github.com/cdot65/prisma-airs-c > **updateCustomerApp**(`appId`, `request`): `Promise`\<`CustomerAppInfo`\> -Defined in: [src/airs/management.ts:356](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L356) +Defined in: [src/airs/management.ts:358](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L358) #### Parameters @@ -660,7 +688,7 @@ Defined in: [src/airs/management.ts:356](https://github.com/cdot65/prisma-airs-c > **updateProfile**(`profileId`, `request`): `Promise`\<`SecurityProfileInfo`\> -Defined in: [src/airs/management.ts:270](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L270) +Defined in: [src/airs/management.ts:272](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L272) Update a security profile. @@ -688,7 +716,7 @@ Update a security profile. > **updateTopic**(`topicId`, `request`): `Promise`\<`objectOutputType`\<\{ `active`: `ZodOptional`\<`ZodBoolean`\>; `created_by`: `ZodOptional`\<`ZodString`\>; `created_ts`: `ZodOptional`\<`ZodString`\>; `description`: `ZodString`; `examples`: `ZodArray`\<`ZodString`, `"many"`\>; `last_modified_ts`: `ZodOptional`\<`ZodString`\>; `revision`: `ZodNumber`; `topic_id`: `ZodOptional`\<`ZodString`\>; `topic_name`: `ZodString`; `updated_by`: `ZodOptional`\<`ZodString`\>; \}, `ZodTypeAny`, `"passthrough"`\>\> -Defined in: [src/airs/management.ts:39](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L39) +Defined in: [src/airs/management.ts:41](https://github.com/cdot65/prisma-airs-cli/blob/main/src/airs/management.ts#L41) Update an existing custom topic by ID.