@cdot65/prisma-airs-cli 2.11.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -169
- package/dist/chunk-JXHYQFEK.js +1752 -0
- package/dist/cli/index.js +6511 -4
- package/dist/dlp-5XKWITZX.js +710 -0
- package/dist/index.d.ts +1396 -26
- package/dist/index.js +40 -37
- package/package.json +22 -25
- package/dist/airs/dlp/data-filtering-profiles.d.ts +0 -10
- package/dist/airs/dlp/data-filtering-profiles.d.ts.map +0 -1
- package/dist/airs/dlp/data-filtering-profiles.js +0 -17
- package/dist/airs/dlp/data-filtering-profiles.js.map +0 -1
- package/dist/airs/dlp/data-patterns.d.ts +0 -13
- package/dist/airs/dlp/data-patterns.d.ts.map +0 -1
- package/dist/airs/dlp/data-patterns.js +0 -26
- package/dist/airs/dlp/data-patterns.js.map +0 -1
- package/dist/airs/dlp/data-profiles.d.ts +0 -12
- package/dist/airs/dlp/data-profiles.d.ts.map +0 -1
- package/dist/airs/dlp/data-profiles.js +0 -23
- package/dist/airs/dlp/data-profiles.js.map +0 -1
- package/dist/airs/dlp/dictionaries.d.ts +0 -13
- package/dist/airs/dlp/dictionaries.d.ts.map +0 -1
- package/dist/airs/dlp/dictionaries.js +0 -34
- package/dist/airs/dlp/dictionaries.js.map +0 -1
- package/dist/airs/dlp/index.d.ts +0 -6
- package/dist/airs/dlp/index.d.ts.map +0 -1
- package/dist/airs/dlp/index.js +0 -6
- package/dist/airs/dlp/index.js.map +0 -1
- package/dist/airs/dlp/types.d.ts +0 -36
- package/dist/airs/dlp/types.d.ts.map +0 -1
- package/dist/airs/dlp/types.js +0 -2
- package/dist/airs/dlp/types.js.map +0 -1
- package/dist/airs/management.d.ts +0 -68
- package/dist/airs/management.d.ts.map +0 -1
- package/dist/airs/management.js +0 -317
- package/dist/airs/management.js.map +0 -1
- package/dist/airs/modelsecurity.d.ts +0 -74
- package/dist/airs/modelsecurity.d.ts.map +0 -1
- package/dist/airs/modelsecurity.js +0 -337
- package/dist/airs/modelsecurity.js.map +0 -1
- package/dist/airs/promptsets.d.ts +0 -50
- package/dist/airs/promptsets.d.ts.map +0 -1
- package/dist/airs/promptsets.js +0 -120
- package/dist/airs/promptsets.js.map +0 -1
- package/dist/airs/redteam.d.ts +0 -74
- package/dist/airs/redteam.d.ts.map +0 -1
- package/dist/airs/redteam.js +0 -406
- package/dist/airs/redteam.js.map +0 -1
- package/dist/airs/runtime.d.ts +0 -27
- package/dist/airs/runtime.d.ts.map +0 -1
- package/dist/airs/runtime.js +0 -158
- package/dist/airs/runtime.js.map +0 -1
- package/dist/airs/scanner.d.ts +0 -36
- package/dist/airs/scanner.d.ts.map +0 -1
- package/dist/airs/scanner.js +0 -101
- package/dist/airs/scanner.js.map +0 -1
- package/dist/airs/types.d.ts +0 -780
- package/dist/airs/types.d.ts.map +0 -1
- package/dist/airs/types.js +0 -6
- package/dist/airs/types.js.map +0 -1
- package/dist/audit/evaluator.d.ts +0 -17
- package/dist/audit/evaluator.d.ts.map +0 -1
- package/dist/audit/evaluator.js +0 -82
- package/dist/audit/evaluator.js.map +0 -1
- package/dist/audit/report.d.ts +0 -38
- package/dist/audit/report.d.ts.map +0 -1
- package/dist/audit/report.js +0 -141
- package/dist/audit/report.js.map +0 -1
- package/dist/audit/runner.d.ts +0 -18
- package/dist/audit/runner.d.ts.map +0 -1
- package/dist/audit/runner.js +0 -60
- package/dist/audit/runner.js.map +0 -1
- package/dist/audit/types.d.ts +0 -53
- package/dist/audit/types.d.ts.map +0 -1
- package/dist/audit/types.js +0 -5
- package/dist/audit/types.js.map +0 -1
- package/dist/backup/index.d.ts +0 -3
- package/dist/backup/index.d.ts.map +0 -1
- package/dist/backup/index.js +0 -3
- package/dist/backup/index.js.map +0 -1
- package/dist/backup/io.d.ts +0 -15
- package/dist/backup/io.d.ts.map +0 -1
- package/dist/backup/io.js +0 -67
- package/dist/backup/io.js.map +0 -1
- package/dist/backup/types.d.ts +0 -25
- package/dist/backup/types.d.ts.map +0 -1
- package/dist/backup/types.js +0 -2
- package/dist/backup/types.js.map +0 -1
- package/dist/cli/builders/profile-builder.d.ts +0 -45
- package/dist/cli/builders/profile-builder.d.ts.map +0 -1
- package/dist/cli/builders/profile-builder.js +0 -308
- package/dist/cli/builders/profile-builder.js.map +0 -1
- package/dist/cli/bulk-scan-state.d.ts +0 -15
- package/dist/cli/bulk-scan-state.d.ts.map +0 -1
- package/dist/cli/bulk-scan-state.js +0 -20
- package/dist/cli/bulk-scan-state.js.map +0 -1
- package/dist/cli/commands/audit.d.ts +0 -4
- package/dist/cli/commands/audit.d.ts.map +0 -1
- package/dist/cli/commands/audit.js +0 -113
- package/dist/cli/commands/audit.js.map +0 -1
- package/dist/cli/commands/backup.d.ts +0 -10
- package/dist/cli/commands/backup.d.ts.map +0 -1
- package/dist/cli/commands/backup.js +0 -102
- package/dist/cli/commands/backup.js.map +0 -1
- package/dist/cli/commands/dlp/build-body.d.ts +0 -28
- package/dist/cli/commands/dlp/build-body.d.ts.map +0 -1
- package/dist/cli/commands/dlp/build-body.js +0 -174
- package/dist/cli/commands/dlp/build-body.js.map +0 -1
- package/dist/cli/commands/dlp/dictionaries.d.ts +0 -3
- package/dist/cli/commands/dlp/dictionaries.d.ts.map +0 -1
- package/dist/cli/commands/dlp/dictionaries.js +0 -167
- package/dist/cli/commands/dlp/dictionaries.js.map +0 -1
- package/dist/cli/commands/dlp/filtering-profiles.d.ts +0 -3
- package/dist/cli/commands/dlp/filtering-profiles.d.ts.map +0 -1
- package/dist/cli/commands/dlp/filtering-profiles.js +0 -82
- package/dist/cli/commands/dlp/filtering-profiles.js.map +0 -1
- package/dist/cli/commands/dlp/generate.d.ts +0 -3
- package/dist/cli/commands/dlp/generate.d.ts.map +0 -1
- package/dist/cli/commands/dlp/generate.js +0 -51
- package/dist/cli/commands/dlp/generate.js.map +0 -1
- package/dist/cli/commands/dlp/index.d.ts +0 -3
- package/dist/cli/commands/dlp/index.d.ts.map +0 -1
- package/dist/cli/commands/dlp/index.js +0 -16
- package/dist/cli/commands/dlp/index.js.map +0 -1
- package/dist/cli/commands/dlp/patch.d.ts +0 -15
- package/dist/cli/commands/dlp/patch.d.ts.map +0 -1
- package/dist/cli/commands/dlp/patch.js +0 -70
- package/dist/cli/commands/dlp/patch.js.map +0 -1
- package/dist/cli/commands/dlp/patterns.d.ts +0 -3
- package/dist/cli/commands/dlp/patterns.d.ts.map +0 -1
- package/dist/cli/commands/dlp/patterns.js +0 -127
- package/dist/cli/commands/dlp/patterns.js.map +0 -1
- package/dist/cli/commands/dlp/profiles.d.ts +0 -3
- package/dist/cli/commands/dlp/profiles.d.ts.map +0 -1
- package/dist/cli/commands/dlp/profiles.js +0 -126
- package/dist/cli/commands/dlp/profiles.js.map +0 -1
- package/dist/cli/commands/modelsecurity.d.ts +0 -4
- package/dist/cli/commands/modelsecurity.d.ts.map +0 -1
- package/dist/cli/commands/modelsecurity.js +0 -605
- package/dist/cli/commands/modelsecurity.js.map +0 -1
- package/dist/cli/commands/profiles-cleanup.d.ts +0 -26
- package/dist/cli/commands/profiles-cleanup.d.ts.map +0 -1
- package/dist/cli/commands/profiles-cleanup.js +0 -113
- package/dist/cli/commands/profiles-cleanup.js.map +0 -1
- package/dist/cli/commands/redteam.d.ts +0 -12
- package/dist/cli/commands/redteam.d.ts.map +0 -1
- package/dist/cli/commands/redteam.js +0 -1071
- package/dist/cli/commands/redteam.js.map +0 -1
- package/dist/cli/commands/restore.d.ts +0 -11
- package/dist/cli/commands/restore.d.ts.map +0 -1
- package/dist/cli/commands/restore.js +0 -109
- package/dist/cli/commands/restore.js.map +0 -1
- package/dist/cli/commands/runtime.d.ts +0 -6
- package/dist/cli/commands/runtime.d.ts.map +0 -1
- package/dist/cli/commands/runtime.js +0 -822
- package/dist/cli/commands/runtime.js.map +0 -1
- package/dist/cli/commands/topics-apply.d.ts +0 -16
- package/dist/cli/commands/topics-apply.d.ts.map +0 -1
- package/dist/cli/commands/topics-apply.js +0 -69
- package/dist/cli/commands/topics-apply.js.map +0 -1
- package/dist/cli/commands/topics-create.d.ts +0 -16
- package/dist/cli/commands/topics-create.d.ts.map +0 -1
- package/dist/cli/commands/topics-create.js +0 -71
- package/dist/cli/commands/topics-create.js.map +0 -1
- package/dist/cli/commands/topics-eval.d.ts +0 -7
- package/dist/cli/commands/topics-eval.d.ts.map +0 -1
- package/dist/cli/commands/topics-eval.js +0 -65
- package/dist/cli/commands/topics-eval.js.map +0 -1
- package/dist/cli/commands/topics-revert.d.ts +0 -9
- package/dist/cli/commands/topics-revert.d.ts.map +0 -1
- package/dist/cli/commands/topics-revert.js +0 -52
- package/dist/cli/commands/topics-revert.js.map +0 -1
- package/dist/cli/commands/topics-sample.d.ts +0 -4
- package/dist/cli/commands/topics-sample.d.ts.map +0 -1
- package/dist/cli/commands/topics-sample.js +0 -27
- package/dist/cli/commands/topics-sample.js.map +0 -1
- package/dist/cli/debug-logger.d.ts +0 -11
- package/dist/cli/debug-logger.d.ts.map +0 -1
- package/dist/cli/debug-logger.js +0 -137
- package/dist/cli/debug-logger.js.map +0 -1
- package/dist/cli/index.d.ts +0 -3
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/parse-input.d.ts +0 -9
- package/dist/cli/parse-input.d.ts.map +0 -1
- package/dist/cli/parse-input.js +0 -109
- package/dist/cli/parse-input.js.map +0 -1
- package/dist/cli/program.d.ts +0 -3
- package/dist/cli/program.d.ts.map +0 -1
- package/dist/cli/program.js +0 -32
- package/dist/cli/program.js.map +0 -1
- package/dist/cli/renderer/audit.d.ts +0 -11
- package/dist/cli/renderer/audit.d.ts.map +0 -1
- package/dist/cli/renderer/audit.js +0 -58
- package/dist/cli/renderer/audit.js.map +0 -1
- package/dist/cli/renderer/backup.d.ts +0 -8
- package/dist/cli/renderer/backup.d.ts.map +0 -1
- package/dist/cli/renderer/backup.js +0 -50
- package/dist/cli/renderer/backup.js.map +0 -1
- package/dist/cli/renderer/common.d.ts +0 -14
- package/dist/cli/renderer/common.d.ts.map +0 -1
- package/dist/cli/renderer/common.js +0 -50
- package/dist/cli/renderer/common.js.map +0 -1
- package/dist/cli/renderer/dlp.d.ts +0 -34
- package/dist/cli/renderer/dlp.d.ts.map +0 -1
- package/dist/cli/renderer/dlp.js +0 -348
- package/dist/cli/renderer/dlp.js.map +0 -1
- package/dist/cli/renderer/eval.d.ts +0 -30
- package/dist/cli/renderer/eval.d.ts.map +0 -1
- package/dist/cli/renderer/eval.js +0 -61
- package/dist/cli/renderer/eval.js.map +0 -1
- package/dist/cli/renderer/index.d.ts +0 -9
- package/dist/cli/renderer/index.d.ts.map +0 -1
- package/dist/cli/renderer/index.js +0 -9
- package/dist/cli/renderer/index.js.map +0 -1
- package/dist/cli/renderer/modelsecurity.d.ts +0 -35
- package/dist/cli/renderer/modelsecurity.d.ts.map +0 -1
- package/dist/cli/renderer/modelsecurity.js +0 -339
- package/dist/cli/renderer/modelsecurity.js.map +0 -1
- package/dist/cli/renderer/redteam.d.ts +0 -216
- package/dist/cli/renderer/redteam.d.ts.map +0 -1
- package/dist/cli/renderer/redteam.js +0 -471
- package/dist/cli/renderer/redteam.js.map +0 -1
- package/dist/cli/renderer/runtime.d.ts +0 -107
- package/dist/cli/renderer/runtime.d.ts.map +0 -1
- package/dist/cli/renderer/runtime.js +0 -359
- package/dist/cli/renderer/runtime.js.map +0 -1
- package/dist/config/loader.d.ts +0 -3
- package/dist/config/loader.d.ts.map +0 -1
- package/dist/config/loader.js +0 -59
- package/dist/config/loader.js.map +0 -1
- package/dist/config/schema.d.ts +0 -63
- package/dist/config/schema.d.ts.map +0 -1
- package/dist/config/schema.js +0 -38
- package/dist/config/schema.js.map +0 -1
- package/dist/core/constraints.d.ts +0 -19
- package/dist/core/constraints.d.ts.map +0 -1
- package/dist/core/constraints.js +0 -82
- package/dist/core/constraints.js.map +0 -1
- package/dist/core/metrics.d.ts +0 -13
- package/dist/core/metrics.d.ts.map +0 -1
- package/dist/core/metrics.js +0 -73
- package/dist/core/metrics.js.map +0 -1
- package/dist/core/prompt-loader.d.ts +0 -14
- package/dist/core/prompt-loader.d.ts.map +0 -1
- package/dist/core/prompt-loader.js +0 -122
- package/dist/core/prompt-loader.js.map +0 -1
- package/dist/core/types.d.ts +0 -96
- package/dist/core/types.d.ts.map +0 -1
- package/dist/core/types.js +0 -5
- package/dist/core/types.js.map +0 -1
- package/dist/dlp/embed/docx.d.ts +0 -3
- package/dist/dlp/embed/docx.d.ts.map +0 -1
- package/dist/dlp/embed/docx.js +0 -54
- package/dist/dlp/embed/docx.js.map +0 -1
- package/dist/dlp/embed/index.d.ts +0 -6
- package/dist/dlp/embed/index.d.ts.map +0 -1
- package/dist/dlp/embed/index.js +0 -20
- package/dist/dlp/embed/index.js.map +0 -1
- package/dist/dlp/embed/jpeg.d.ts +0 -5
- package/dist/dlp/embed/jpeg.d.ts.map +0 -1
- package/dist/dlp/embed/jpeg.js +0 -60
- package/dist/dlp/embed/jpeg.js.map +0 -1
- package/dist/dlp/embed/pdf.d.ts +0 -7
- package/dist/dlp/embed/pdf.d.ts.map +0 -1
- package/dist/dlp/embed/pdf.js +0 -92
- package/dist/dlp/embed/pdf.js.map +0 -1
- package/dist/dlp/embed/png-chunks.d.ts +0 -12
- package/dist/dlp/embed/png-chunks.d.ts.map +0 -1
- package/dist/dlp/embed/png-chunks.js +0 -85
- package/dist/dlp/embed/png-chunks.js.map +0 -1
- package/dist/dlp/embed/png.d.ts +0 -5
- package/dist/dlp/embed/png.d.ts.map +0 -1
- package/dist/dlp/embed/png.js +0 -68
- package/dist/dlp/embed/png.js.map +0 -1
- package/dist/dlp/embed/svg.d.ts +0 -3
- package/dist/dlp/embed/svg.d.ts.map +0 -1
- package/dist/dlp/embed/svg.js +0 -28
- package/dist/dlp/embed/svg.js.map +0 -1
- package/dist/dlp/embed/zip.d.ts +0 -3
- package/dist/dlp/embed/zip.d.ts.map +0 -1
- package/dist/dlp/embed/zip.js +0 -25
- package/dist/dlp/embed/zip.js.map +0 -1
- package/dist/dlp/generate/docx.d.ts +0 -3
- package/dist/dlp/generate/docx.d.ts.map +0 -1
- package/dist/dlp/generate/docx.js +0 -24
- package/dist/dlp/generate/docx.js.map +0 -1
- package/dist/dlp/generate/index.d.ts +0 -5
- package/dist/dlp/generate/index.d.ts.map +0 -1
- package/dist/dlp/generate/index.js +0 -21
- package/dist/dlp/generate/index.js.map +0 -1
- package/dist/dlp/generate/jpeg.d.ts +0 -3
- package/dist/dlp/generate/jpeg.d.ts.map +0 -1
- package/dist/dlp/generate/jpeg.js +0 -8
- package/dist/dlp/generate/jpeg.js.map +0 -1
- package/dist/dlp/generate/pdf.d.ts +0 -3
- package/dist/dlp/generate/pdf.d.ts.map +0 -1
- package/dist/dlp/generate/pdf.js +0 -19
- package/dist/dlp/generate/pdf.js.map +0 -1
- package/dist/dlp/generate/png.d.ts +0 -3
- package/dist/dlp/generate/png.d.ts.map +0 -1
- package/dist/dlp/generate/png.js +0 -8
- package/dist/dlp/generate/png.js.map +0 -1
- package/dist/dlp/generate/raster.d.ts +0 -9
- package/dist/dlp/generate/raster.d.ts.map +0 -1
- package/dist/dlp/generate/raster.js +0 -20
- package/dist/dlp/generate/raster.js.map +0 -1
- package/dist/dlp/generate/svg.d.ts +0 -3
- package/dist/dlp/generate/svg.d.ts.map +0 -1
- package/dist/dlp/generate/svg.js +0 -17
- package/dist/dlp/generate/svg.js.map +0 -1
- package/dist/dlp/index.d.ts +0 -15
- package/dist/dlp/index.d.ts.map +0 -1
- package/dist/dlp/index.js +0 -54
- package/dist/dlp/index.js.map +0 -1
- package/dist/dlp/lorem.d.ts +0 -3
- package/dist/dlp/lorem.d.ts.map +0 -1
- package/dist/dlp/lorem.js +0 -65
- package/dist/dlp/lorem.js.map +0 -1
- package/dist/dlp/manifest.d.ts +0 -11
- package/dist/dlp/manifest.d.ts.map +0 -1
- package/dist/dlp/manifest.js +0 -14
- package/dist/dlp/manifest.js.map +0 -1
- package/dist/dlp/payload.d.ts +0 -6
- package/dist/dlp/payload.d.ts.map +0 -1
- package/dist/dlp/payload.js +0 -62
- package/dist/dlp/payload.js.map +0 -1
- package/dist/dlp/rng.d.ts +0 -9
- package/dist/dlp/rng.d.ts.map +0 -1
- package/dist/dlp/rng.js +0 -28
- package/dist/dlp/rng.js.map +0 -1
- package/dist/dlp/types.d.ts +0 -26
- package/dist/dlp/types.d.ts.map +0 -1
- package/dist/dlp/types.js +0 -2
- package/dist/dlp/types.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/llm/prompts/analyze-results.d.ts +0 -3
- package/dist/llm/prompts/analyze-results.d.ts.map +0 -1
- package/dist/llm/prompts/analyze-results.js +0 -52
- package/dist/llm/prompts/analyze-results.js.map +0 -1
- package/dist/llm/prompts/generate-companion.d.ts +0 -3
- package/dist/llm/prompts/generate-companion.d.ts.map +0 -1
- package/dist/llm/prompts/generate-companion.js +0 -42
- package/dist/llm/prompts/generate-companion.js.map +0 -1
- package/dist/llm/prompts/generate-tests.d.ts +0 -3
- package/dist/llm/prompts/generate-tests.d.ts.map +0 -1
- package/dist/llm/prompts/generate-tests.js +0 -46
- package/dist/llm/prompts/generate-tests.js.map +0 -1
- package/dist/llm/prompts/generate-topic.d.ts +0 -4
- package/dist/llm/prompts/generate-topic.d.ts.map +0 -1
- package/dist/llm/prompts/generate-topic.js +0 -41
- package/dist/llm/prompts/generate-topic.js.map +0 -1
- package/dist/llm/prompts/improve-topic.d.ts +0 -3
- package/dist/llm/prompts/improve-topic.d.ts.map +0 -1
- package/dist/llm/prompts/improve-topic.js +0 -77
- package/dist/llm/prompts/improve-topic.js.map +0 -1
- package/dist/llm/prompts/simplify-topic.d.ts +0 -3
- package/dist/llm/prompts/simplify-topic.d.ts.map +0 -1
- package/dist/llm/prompts/simplify-topic.js +0 -50
- package/dist/llm/prompts/simplify-topic.js.map +0 -1
- package/dist/llm/provider.d.ts +0 -21
- package/dist/llm/provider.d.ts.map +0 -1
- package/dist/llm/provider.js +0 -76
- package/dist/llm/provider.js.map +0 -1
- package/dist/llm/schemas.d.ts +0 -97
- package/dist/llm/schemas.d.ts.map +0 -1
- package/dist/llm/schemas.js +0 -24
- package/dist/llm/schemas.js.map +0 -1
- package/dist/llm/service.d.ts +0 -34
- package/dist/llm/service.d.ts.map +0 -1
- package/dist/llm/service.js +0 -268
- package/dist/llm/service.js.map +0 -1
- package/dist/llm/types.d.ts +0 -18
- package/dist/llm/types.d.ts.map +0 -1
- package/dist/llm/types.js +0 -2
- package/dist/llm/types.js.map +0 -1
- package/dist/report/html.d.ts +0 -6
- package/dist/report/html.d.ts.map +0 -1
- package/dist/report/html.js +0 -200
- package/dist/report/html.js.map +0 -1
- package/dist/report/json.d.ts +0 -11
- package/dist/report/json.d.ts.map +0 -1
- package/dist/report/json.js +0 -74
- package/dist/report/json.js.map +0 -1
- package/dist/report/types.d.ts +0 -58
- package/dist/report/types.d.ts.map +0 -1
- package/dist/report/types.js +0 -5
- package/dist/report/types.js.map +0 -1
|
@@ -1,822 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import { SdkManagementService } from '../../airs/management.js';
|
|
5
|
-
import { SdkRuntimeService } from '../../airs/runtime.js';
|
|
6
|
-
import { loadConfig } from '../../config/loader.js';
|
|
7
|
-
import { buildProfileOverrides, buildProfileRequest, mergeProfilePolicy, } from '../builders/profile-builder.js';
|
|
8
|
-
import { loadBulkScanState, saveBulkScanState } from '../bulk-scan-state.js';
|
|
9
|
-
import { parseInputFile } from '../parse-input.js';
|
|
10
|
-
import { OUTPUT_FORMATS, renderApiKeyDetail, renderApiKeyList, renderCustomerAppDetail, renderCustomerAppList, renderDeploymentProfileList, renderError, renderProfileDetail, renderProfileList, renderRuntimeConfigHeader, renderScanLogList, renderTopicDetail, renderTopicList, } from '../renderer/index.js';
|
|
11
|
-
import { registerAuditCommand } from './audit.js';
|
|
12
|
-
import { registerDlpCommands } from './dlp/index.js';
|
|
13
|
-
import { registerCleanupCommand } from './profiles-cleanup.js';
|
|
14
|
-
import { registerApplyCommand } from './topics-apply.js';
|
|
15
|
-
import { registerCreateCommand } from './topics-create.js';
|
|
16
|
-
import { registerEvalCommand } from './topics-eval.js';
|
|
17
|
-
import { registerRevertCommand } from './topics-revert.js';
|
|
18
|
-
import { registerSampleCommand } from './topics-sample.js';
|
|
19
|
-
function renderScanResult(result) {
|
|
20
|
-
const actionColor = result.action === 'block' ? chalk.red : chalk.green;
|
|
21
|
-
console.log(chalk.bold('\n Scan Result'));
|
|
22
|
-
console.log(chalk.dim(' ─────────────────────────'));
|
|
23
|
-
console.log(` Action: ${actionColor(result.action.toUpperCase())}`);
|
|
24
|
-
console.log(` Category: ${result.category}`);
|
|
25
|
-
console.log(` Triggered: ${result.triggered ? chalk.red('yes') : chalk.green('no')}`);
|
|
26
|
-
console.log(` Scan ID: ${chalk.dim(result.scanId)}`);
|
|
27
|
-
console.log(` Report ID: ${chalk.dim(result.reportId)}`);
|
|
28
|
-
const flags = Object.entries(result.detections).filter(([, v]) => v);
|
|
29
|
-
if (flags.length > 0) {
|
|
30
|
-
console.log(chalk.bold('\n Detections:'));
|
|
31
|
-
for (const [key] of flags) {
|
|
32
|
-
console.log(` ${chalk.yellow('●')} ${key}`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
console.log();
|
|
36
|
-
}
|
|
37
|
-
/** Create a management service from config. */
|
|
38
|
-
export async function createMgmtService() {
|
|
39
|
-
const config = await loadConfig();
|
|
40
|
-
return new SdkManagementService({
|
|
41
|
-
clientId: config.mgmtClientId,
|
|
42
|
-
clientSecret: config.mgmtClientSecret,
|
|
43
|
-
tsgId: config.mgmtTsgId,
|
|
44
|
-
tokenEndpoint: config.mgmtTokenEndpoint,
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
export function registerRuntimeCommand(program) {
|
|
48
|
-
const runtime = program
|
|
49
|
-
.command('runtime')
|
|
50
|
-
.description('Runtime prompt scanning against AIRS profiles');
|
|
51
|
-
// -----------------------------------------------------------------------
|
|
52
|
-
// runtime api-keys — API key management subcommands
|
|
53
|
-
// -----------------------------------------------------------------------
|
|
54
|
-
const apiKeys = runtime.command('api-keys').description('Manage AIRS API keys');
|
|
55
|
-
apiKeys
|
|
56
|
-
.command('list')
|
|
57
|
-
.description('List API keys')
|
|
58
|
-
.option('--limit <n>', 'Max results', '100')
|
|
59
|
-
.option('--output <format>', 'Output format: pretty, table, csv, json, yaml', 'pretty')
|
|
60
|
-
.action(async (opts) => {
|
|
61
|
-
try {
|
|
62
|
-
const fmt = opts.output;
|
|
63
|
-
if (fmt === 'pretty')
|
|
64
|
-
renderRuntimeConfigHeader();
|
|
65
|
-
const service = await createMgmtService();
|
|
66
|
-
const result = await service.listApiKeys({
|
|
67
|
-
limit: Number.parseInt(opts.limit, 10),
|
|
68
|
-
});
|
|
69
|
-
renderApiKeyList(result.apiKeys, fmt);
|
|
70
|
-
}
|
|
71
|
-
catch (err) {
|
|
72
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
apiKeys
|
|
77
|
-
.command('create')
|
|
78
|
-
.description('Create a new API key')
|
|
79
|
-
.requiredOption('--config <path>', 'JSON file with API key configuration')
|
|
80
|
-
.action(async (opts) => {
|
|
81
|
-
try {
|
|
82
|
-
renderRuntimeConfigHeader();
|
|
83
|
-
const service = await createMgmtService();
|
|
84
|
-
const config = JSON.parse(fs.readFileSync(opts.config, 'utf-8'));
|
|
85
|
-
const key = await service.createApiKey(config);
|
|
86
|
-
console.log(` API key created: ${key.id}\n`);
|
|
87
|
-
renderApiKeyDetail(key);
|
|
88
|
-
}
|
|
89
|
-
catch (err) {
|
|
90
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
91
|
-
process.exit(1);
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
apiKeys
|
|
95
|
-
.command('regenerate <apiKeyId>')
|
|
96
|
-
.description('Regenerate an API key')
|
|
97
|
-
.requiredOption('--interval <n>', 'Rotation time interval')
|
|
98
|
-
.requiredOption('--unit <unit>', 'Rotation time unit (hours, days, months)')
|
|
99
|
-
.option('--updated-by <email>', 'Email of user performing regeneration')
|
|
100
|
-
.action(async (apiKeyId, opts) => {
|
|
101
|
-
try {
|
|
102
|
-
renderRuntimeConfigHeader();
|
|
103
|
-
const service = await createMgmtService();
|
|
104
|
-
const request = {
|
|
105
|
-
rotation_time_interval: Number.parseInt(opts.interval, 10),
|
|
106
|
-
rotation_time_unit: opts.unit,
|
|
107
|
-
};
|
|
108
|
-
if (opts.updatedBy)
|
|
109
|
-
request.updated_by = opts.updatedBy;
|
|
110
|
-
const key = await service.regenerateApiKey(apiKeyId, request);
|
|
111
|
-
console.log(` API key regenerated: ${key.id}\n`);
|
|
112
|
-
renderApiKeyDetail(key);
|
|
113
|
-
}
|
|
114
|
-
catch (err) {
|
|
115
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
116
|
-
process.exit(1);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
apiKeys
|
|
120
|
-
.command('delete <apiKeyName>')
|
|
121
|
-
.description('Delete an API key')
|
|
122
|
-
.requiredOption('--updated-by <email>', 'Email of user performing deletion')
|
|
123
|
-
.action(async (apiKeyName, opts) => {
|
|
124
|
-
try {
|
|
125
|
-
renderRuntimeConfigHeader();
|
|
126
|
-
const service = await createMgmtService();
|
|
127
|
-
const result = await service.deleteApiKey(apiKeyName, opts.updatedBy);
|
|
128
|
-
console.log(` ${result.message}\n`);
|
|
129
|
-
}
|
|
130
|
-
catch (err) {
|
|
131
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
132
|
-
process.exit(1);
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
// -----------------------------------------------------------------------
|
|
136
|
-
// runtime bulk-scan — async bulk scanning
|
|
137
|
-
// -----------------------------------------------------------------------
|
|
138
|
-
runtime
|
|
139
|
-
.command('bulk-scan')
|
|
140
|
-
.description('Scan multiple prompts via the async AIRS API')
|
|
141
|
-
.requiredOption('--profile <name>', 'Security profile name')
|
|
142
|
-
.requiredOption('--input <file>', 'Input file — .csv (extracts prompt column) or .txt (one per line)')
|
|
143
|
-
.option('--output <file>', 'Output CSV file path')
|
|
144
|
-
.option('--session-id <id>', 'Session ID for grouping scans in AIRS dashboard')
|
|
145
|
-
.action(async (opts) => {
|
|
146
|
-
try {
|
|
147
|
-
const config = await loadConfig({});
|
|
148
|
-
if (!config.airsApiKey) {
|
|
149
|
-
renderError('PANW_AI_SEC_API_KEY is required');
|
|
150
|
-
process.exit(1);
|
|
151
|
-
}
|
|
152
|
-
const raw = await readFile(opts.input, 'utf-8');
|
|
153
|
-
const prompts = parseInputFile(raw, opts.input);
|
|
154
|
-
if (prompts.length === 0) {
|
|
155
|
-
renderError('No prompts found in input file');
|
|
156
|
-
process.exit(1);
|
|
157
|
-
}
|
|
158
|
-
const sessionId = opts.sessionId ?? `prisma-airs-cli-bulk-${Date.now().toString(36)}`;
|
|
159
|
-
const service = new SdkRuntimeService(config.airsApiKey);
|
|
160
|
-
console.log(chalk.bold.cyan('\n Prisma AIRS Bulk Scan'));
|
|
161
|
-
console.log(chalk.dim(` Profile: ${opts.profile}`));
|
|
162
|
-
console.log(chalk.dim(` Session: ${sessionId}`));
|
|
163
|
-
console.log(chalk.dim(` Prompts: ${prompts.length}`));
|
|
164
|
-
console.log(chalk.dim(` Batches: ${Math.ceil(prompts.length / 5)}\n`));
|
|
165
|
-
console.log(chalk.dim(' Submitting async scans...'));
|
|
166
|
-
const scanIds = await service.submitBulkScan(opts.profile, prompts, sessionId);
|
|
167
|
-
const stateDir = config.dataDir.replace(/\/runs$/, '/bulk-scans');
|
|
168
|
-
const statePath = await saveBulkScanState({ scanIds, profile: opts.profile, promptCount: prompts.length, sessionId }, stateDir);
|
|
169
|
-
console.log(chalk.dim(` Scan IDs saved: ${statePath}`));
|
|
170
|
-
console.log(chalk.dim(` Submitted ${scanIds.length} batch(es), polling for results...`));
|
|
171
|
-
const results = await service.pollResults(scanIds, undefined, {
|
|
172
|
-
onRetry: (attempt, delayMs) => {
|
|
173
|
-
console.log(chalk.yellow(` ⚠ Rate limited — retry ${attempt} in ${(delayMs / 1000).toFixed(0)}s...`));
|
|
174
|
-
},
|
|
175
|
-
});
|
|
176
|
-
// Attach prompts to results
|
|
177
|
-
for (let i = 0; i < results.length && i < prompts.length; i++) {
|
|
178
|
-
results[i].prompt = prompts[i];
|
|
179
|
-
}
|
|
180
|
-
const outputPath = opts.output ?? `${opts.profile.replace(/\s+/g, '-')}-bulk-scan.csv`;
|
|
181
|
-
const csv = SdkRuntimeService.formatResultsCsv(results);
|
|
182
|
-
await writeFile(outputPath, csv, 'utf-8');
|
|
183
|
-
const blocked = results.filter((r) => r.action === 'block').length;
|
|
184
|
-
const allowed = results.filter((r) => r.action === 'allow').length;
|
|
185
|
-
console.log(chalk.bold('\n Bulk Scan Complete'));
|
|
186
|
-
console.log(chalk.dim(' ─────────────────────────'));
|
|
187
|
-
console.log(` Total: ${results.length}`);
|
|
188
|
-
console.log(` Blocked: ${chalk.red(String(blocked))}`);
|
|
189
|
-
console.log(` Allowed: ${chalk.green(String(allowed))}`);
|
|
190
|
-
console.log(` Output: ${chalk.cyan(outputPath)}\n`);
|
|
191
|
-
}
|
|
192
|
-
catch (err) {
|
|
193
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
194
|
-
process.exit(1);
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
// -----------------------------------------------------------------------
|
|
198
|
-
// runtime customer-apps — customer app management subcommands
|
|
199
|
-
// -----------------------------------------------------------------------
|
|
200
|
-
const customerApps = runtime.command('customer-apps').description('Manage AIRS customer apps');
|
|
201
|
-
customerApps
|
|
202
|
-
.command('list')
|
|
203
|
-
.description('List customer apps')
|
|
204
|
-
.option('--limit <n>', 'Max results', '100')
|
|
205
|
-
.option('--output <format>', 'Output format: pretty, table, csv, json, yaml', 'pretty')
|
|
206
|
-
.action(async (opts) => {
|
|
207
|
-
try {
|
|
208
|
-
const fmt = opts.output;
|
|
209
|
-
if (fmt === 'pretty')
|
|
210
|
-
renderRuntimeConfigHeader();
|
|
211
|
-
const service = await createMgmtService();
|
|
212
|
-
const result = await service.listCustomerApps({
|
|
213
|
-
limit: Number.parseInt(opts.limit, 10),
|
|
214
|
-
});
|
|
215
|
-
renderCustomerAppList(result.apps, fmt);
|
|
216
|
-
}
|
|
217
|
-
catch (err) {
|
|
218
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
219
|
-
process.exit(1);
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
customerApps
|
|
223
|
-
.command('get <appName>')
|
|
224
|
-
.description('Get customer app details')
|
|
225
|
-
.action(async (appName) => {
|
|
226
|
-
try {
|
|
227
|
-
renderRuntimeConfigHeader();
|
|
228
|
-
const service = await createMgmtService();
|
|
229
|
-
const app = await service.getCustomerApp(appName);
|
|
230
|
-
renderCustomerAppDetail(app);
|
|
231
|
-
}
|
|
232
|
-
catch (err) {
|
|
233
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
234
|
-
process.exit(1);
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
customerApps
|
|
238
|
-
.command('update <appId>')
|
|
239
|
-
.description('Update a customer app')
|
|
240
|
-
.requiredOption('--config <path>', 'JSON file with app updates')
|
|
241
|
-
.action(async (appId, opts) => {
|
|
242
|
-
try {
|
|
243
|
-
renderRuntimeConfigHeader();
|
|
244
|
-
const service = await createMgmtService();
|
|
245
|
-
const config = JSON.parse(fs.readFileSync(opts.config, 'utf-8'));
|
|
246
|
-
const app = await service.updateCustomerApp(appId, config);
|
|
247
|
-
console.log(` Customer app updated: ${app.name}\n`);
|
|
248
|
-
renderCustomerAppDetail(app);
|
|
249
|
-
}
|
|
250
|
-
catch (err) {
|
|
251
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
252
|
-
process.exit(1);
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
customerApps
|
|
256
|
-
.command('delete <appName>')
|
|
257
|
-
.description('Delete a customer app')
|
|
258
|
-
.requiredOption('--updated-by <email>', 'Email of user performing deletion')
|
|
259
|
-
.action(async (appName, opts) => {
|
|
260
|
-
try {
|
|
261
|
-
renderRuntimeConfigHeader();
|
|
262
|
-
const service = await createMgmtService();
|
|
263
|
-
const app = await service.deleteCustomerApp(appName, opts.updatedBy);
|
|
264
|
-
console.log(` Customer app "${app.name}" deleted.\n`);
|
|
265
|
-
}
|
|
266
|
-
catch (err) {
|
|
267
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
268
|
-
process.exit(1);
|
|
269
|
-
}
|
|
270
|
-
});
|
|
271
|
-
// -----------------------------------------------------------------------
|
|
272
|
-
// runtime deployment-profiles — read-only listing
|
|
273
|
-
// -----------------------------------------------------------------------
|
|
274
|
-
const deploymentProfiles = runtime
|
|
275
|
-
.command('deployment-profiles')
|
|
276
|
-
.description('List AIRS deployment profiles');
|
|
277
|
-
deploymentProfiles
|
|
278
|
-
.command('list')
|
|
279
|
-
.description('List deployment profiles')
|
|
280
|
-
.option('--unactivated', 'Include unactivated profiles')
|
|
281
|
-
.option('--output <format>', 'Output format: pretty, table, csv, json, yaml', 'pretty')
|
|
282
|
-
.action(async (opts) => {
|
|
283
|
-
try {
|
|
284
|
-
const fmt = opts.output;
|
|
285
|
-
if (fmt === 'pretty')
|
|
286
|
-
renderRuntimeConfigHeader();
|
|
287
|
-
const service = await createMgmtService();
|
|
288
|
-
const profiles = await service.listDeploymentProfiles({
|
|
289
|
-
unactivated: opts.unactivated,
|
|
290
|
-
});
|
|
291
|
-
renderDeploymentProfileList(profiles, fmt);
|
|
292
|
-
}
|
|
293
|
-
catch (err) {
|
|
294
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
295
|
-
process.exit(1);
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
// -----------------------------------------------------------------------
|
|
299
|
-
// runtime profiles — security profile CRUD subcommands
|
|
300
|
-
// -----------------------------------------------------------------------
|
|
301
|
-
const profiles = runtime.command('profiles').description('Manage AIRS security profiles');
|
|
302
|
-
profiles
|
|
303
|
-
.command('list')
|
|
304
|
-
.description('List security profiles')
|
|
305
|
-
.option('--limit <n>', 'Max results', '100')
|
|
306
|
-
.option('--offset <n>', 'Starting offset', '0')
|
|
307
|
-
.option('--output <format>', 'Output format: pretty, table, csv, json, yaml', 'pretty')
|
|
308
|
-
.action(async (opts) => {
|
|
309
|
-
try {
|
|
310
|
-
const fmt = opts.output;
|
|
311
|
-
if (!OUTPUT_FORMATS.includes(fmt)) {
|
|
312
|
-
renderError(`Invalid output format "${fmt}". Valid: ${OUTPUT_FORMATS.join(', ')}`);
|
|
313
|
-
process.exit(1);
|
|
314
|
-
}
|
|
315
|
-
if (fmt === 'pretty')
|
|
316
|
-
renderRuntimeConfigHeader();
|
|
317
|
-
const service = await createMgmtService();
|
|
318
|
-
const result = await service.listProfiles({
|
|
319
|
-
limit: Number.parseInt(opts.limit, 10),
|
|
320
|
-
offset: Number.parseInt(opts.offset, 10),
|
|
321
|
-
});
|
|
322
|
-
renderProfileList(result.profiles, fmt);
|
|
323
|
-
if (fmt === 'pretty' && result.nextOffset != null) {
|
|
324
|
-
console.log(chalk.dim(` Next offset: ${result.nextOffset}\n`));
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
catch (err) {
|
|
328
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
329
|
-
process.exit(1);
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
profiles
|
|
333
|
-
.command('get <nameOrId>')
|
|
334
|
-
.description('Get a security profile by name or UUID')
|
|
335
|
-
.option('--output <format>', 'Output format: pretty, json, yaml', 'pretty')
|
|
336
|
-
.action(async (nameOrId, opts) => {
|
|
337
|
-
try {
|
|
338
|
-
const fmt = opts.output;
|
|
339
|
-
if (fmt !== 'pretty' && fmt !== 'json' && fmt !== 'yaml') {
|
|
340
|
-
renderError(`Invalid output format "${fmt}". Valid: pretty, json, yaml`);
|
|
341
|
-
process.exit(1);
|
|
342
|
-
}
|
|
343
|
-
if (fmt === 'pretty')
|
|
344
|
-
renderRuntimeConfigHeader();
|
|
345
|
-
const service = await createMgmtService();
|
|
346
|
-
const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(nameOrId);
|
|
347
|
-
const profile = isUuid
|
|
348
|
-
? await service.getProfile(nameOrId)
|
|
349
|
-
: await service.getProfileByName(nameOrId);
|
|
350
|
-
if (fmt === 'json') {
|
|
351
|
-
console.log(JSON.stringify(profile, null, 2));
|
|
352
|
-
}
|
|
353
|
-
else if (fmt === 'yaml') {
|
|
354
|
-
const lines = [`profileId: ${profile.profileId}`, `profileName: ${profile.profileName}`];
|
|
355
|
-
if (profile.revision != null)
|
|
356
|
-
lines.push(`revision: ${profile.revision}`);
|
|
357
|
-
if (profile.active != null)
|
|
358
|
-
lines.push(`active: ${profile.active}`);
|
|
359
|
-
if (profile.createdBy)
|
|
360
|
-
lines.push(`createdBy: ${profile.createdBy}`);
|
|
361
|
-
if (profile.updatedBy)
|
|
362
|
-
lines.push(`updatedBy: ${profile.updatedBy}`);
|
|
363
|
-
if (profile.lastModifiedTs)
|
|
364
|
-
lines.push(`lastModifiedTs: ${profile.lastModifiedTs}`);
|
|
365
|
-
if (profile.policy)
|
|
366
|
-
lines.push(`policy: ${JSON.stringify(profile.policy, null, 2)}`);
|
|
367
|
-
console.log(lines.join('\n'));
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
renderProfileDetail(profile);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
catch (err) {
|
|
374
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
375
|
-
process.exit(1);
|
|
376
|
-
}
|
|
377
|
-
});
|
|
378
|
-
profiles
|
|
379
|
-
.command('create')
|
|
380
|
-
.description('Create a new security profile')
|
|
381
|
-
.requiredOption('--name <name>', 'Profile name')
|
|
382
|
-
.option('--no-active', 'Create profile as inactive')
|
|
383
|
-
.option('--prompt-injection <action>', 'Prompt injection action (block/allow/alert)')
|
|
384
|
-
.option('--toxic-content <action>', 'Toxic content action (e.g. "high:block, moderate:block")')
|
|
385
|
-
.option('--contextual-grounding <action>', 'Contextual grounding action (block/allow/alert)')
|
|
386
|
-
.option('--malicious-code <action>', 'Malicious code protection action (block/allow/alert)')
|
|
387
|
-
.option('--url-action <action>', 'URL detected action (block/allow/alert)')
|
|
388
|
-
.option('--allow-url-categories <list>', 'Comma-separated URL categories to allow')
|
|
389
|
-
.option('--block-url-categories <list>', 'Comma-separated URL categories to block')
|
|
390
|
-
.option('--alert-url-categories <list>', 'Comma-separated URL categories to alert')
|
|
391
|
-
.option('--agent-security <action>', 'Agent security action (block/allow/alert)')
|
|
392
|
-
.option('--dlp-action <action>', 'Data leak detection action (block/allow/alert)')
|
|
393
|
-
.option('--dlp-profiles <list>', 'Comma-separated DLP profile names')
|
|
394
|
-
.option('--mask-data-inline', 'Mask detected data inline')
|
|
395
|
-
.option('--db-security-create <action>', 'Database create action (block/allow/alert)')
|
|
396
|
-
.option('--db-security-read <action>', 'Database read action (block/allow/alert)')
|
|
397
|
-
.option('--db-security-update <action>', 'Database update action (block/allow/alert)')
|
|
398
|
-
.option('--db-security-delete <action>', 'Database delete action (block/allow/alert)')
|
|
399
|
-
.option('--inline-timeout-action <action>', 'Inline timeout action (block/allow)')
|
|
400
|
-
.option('--max-inline-latency <n>', 'Max inline latency in seconds', Number.parseFloat)
|
|
401
|
-
.option('--mask-data-in-storage', 'Mask data in storage')
|
|
402
|
-
.option('--config <path>', 'JSON file with profile configuration (legacy)')
|
|
403
|
-
.action(async (opts) => {
|
|
404
|
-
const service = await createMgmtService();
|
|
405
|
-
try {
|
|
406
|
-
renderRuntimeConfigHeader();
|
|
407
|
-
let profile;
|
|
408
|
-
if (opts.config) {
|
|
409
|
-
// Legacy JSON file path
|
|
410
|
-
const config = JSON.parse(fs.readFileSync(opts.config, 'utf-8'));
|
|
411
|
-
profile = await service.createProfile(config);
|
|
412
|
-
}
|
|
413
|
-
else {
|
|
414
|
-
const request = buildProfileRequest({
|
|
415
|
-
name: opts.name,
|
|
416
|
-
active: opts.active,
|
|
417
|
-
promptInjection: opts.promptInjection,
|
|
418
|
-
toxicContent: opts.toxicContent,
|
|
419
|
-
contextualGrounding: opts.contextualGrounding,
|
|
420
|
-
maliciousCode: opts.maliciousCode,
|
|
421
|
-
urlAction: opts.urlAction,
|
|
422
|
-
allowUrlCategories: opts.allowUrlCategories,
|
|
423
|
-
blockUrlCategories: opts.blockUrlCategories,
|
|
424
|
-
alertUrlCategories: opts.alertUrlCategories,
|
|
425
|
-
agentSecurity: opts.agentSecurity,
|
|
426
|
-
dlpAction: opts.dlpAction,
|
|
427
|
-
dlpProfiles: opts.dlpProfiles,
|
|
428
|
-
maskDataInline: opts.maskDataInline,
|
|
429
|
-
dbSecurityCreate: opts.dbSecurityCreate,
|
|
430
|
-
dbSecurityRead: opts.dbSecurityRead,
|
|
431
|
-
dbSecurityUpdate: opts.dbSecurityUpdate,
|
|
432
|
-
dbSecurityDelete: opts.dbSecurityDelete,
|
|
433
|
-
inlineTimeoutAction: opts.inlineTimeoutAction,
|
|
434
|
-
maxInlineLatency: opts.maxInlineLatency,
|
|
435
|
-
maskDataInStorage: opts.maskDataInStorage,
|
|
436
|
-
});
|
|
437
|
-
profile = await service.createProfile(request);
|
|
438
|
-
}
|
|
439
|
-
console.log(` Profile created: ${profile.profileId}\n`);
|
|
440
|
-
renderProfileDetail(profile);
|
|
441
|
-
}
|
|
442
|
-
catch (err) {
|
|
443
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
444
|
-
if (msg.includes('409')) {
|
|
445
|
-
// AIRS may create the profile but also return 409 — check if it exists
|
|
446
|
-
try {
|
|
447
|
-
const created = await service.getProfileByName(opts.name);
|
|
448
|
-
console.log(` Profile created: ${created.profileId}\n`);
|
|
449
|
-
renderProfileDetail(created);
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
catch {
|
|
453
|
-
// Profile truly already existed before our call
|
|
454
|
-
renderError(`Profile "${opts.name}" already exists. Use 'profiles update' to modify it.`);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
else {
|
|
458
|
-
renderError(msg);
|
|
459
|
-
}
|
|
460
|
-
process.exit(1);
|
|
461
|
-
}
|
|
462
|
-
});
|
|
463
|
-
profiles
|
|
464
|
-
.command('update <nameOrId>')
|
|
465
|
-
.description('Update a security profile by name or UUID')
|
|
466
|
-
.option('--name <name>', 'Update profile name')
|
|
467
|
-
.option('--no-active', 'Set profile as inactive')
|
|
468
|
-
.option('--active', 'Set profile as active')
|
|
469
|
-
.option('--prompt-injection <action>', 'Prompt injection action (block/allow/alert)')
|
|
470
|
-
.option('--toxic-content <action>', 'Toxic content action (e.g. "high:block, moderate:block")')
|
|
471
|
-
.option('--contextual-grounding <action>', 'Contextual grounding action (block/allow/alert)')
|
|
472
|
-
.option('--malicious-code <action>', 'Malicious code protection action (block/allow/alert)')
|
|
473
|
-
.option('--url-action <action>', 'URL detected action (block/allow/alert)')
|
|
474
|
-
.option('--allow-url-categories <list>', 'Comma-separated URL categories to allow')
|
|
475
|
-
.option('--block-url-categories <list>', 'Comma-separated URL categories to block')
|
|
476
|
-
.option('--alert-url-categories <list>', 'Comma-separated URL categories to alert')
|
|
477
|
-
.option('--agent-security <action>', 'Agent security action (block/allow/alert)')
|
|
478
|
-
.option('--dlp-action <action>', 'Data leak detection action (block/allow/alert)')
|
|
479
|
-
.option('--dlp-profiles <list>', 'Comma-separated DLP profile names')
|
|
480
|
-
.option('--mask-data-inline', 'Mask detected data inline')
|
|
481
|
-
.option('--db-security-create <action>', 'Database create action (block/allow/alert)')
|
|
482
|
-
.option('--db-security-read <action>', 'Database read action (block/allow/alert)')
|
|
483
|
-
.option('--db-security-update <action>', 'Database update action (block/allow/alert)')
|
|
484
|
-
.option('--db-security-delete <action>', 'Database delete action (block/allow/alert)')
|
|
485
|
-
.option('--inline-timeout-action <action>', 'Inline timeout action (block/allow)')
|
|
486
|
-
.option('--max-inline-latency <n>', 'Max inline latency in seconds', Number.parseFloat)
|
|
487
|
-
.option('--mask-data-in-storage', 'Mask data in storage')
|
|
488
|
-
.option('--config <path>', 'JSON file with profile updates (legacy)')
|
|
489
|
-
.action(async (nameOrId, opts) => {
|
|
490
|
-
try {
|
|
491
|
-
renderRuntimeConfigHeader();
|
|
492
|
-
const service = await createMgmtService();
|
|
493
|
-
const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(nameOrId);
|
|
494
|
-
const resolved = isUuid
|
|
495
|
-
? await service.getProfile(nameOrId)
|
|
496
|
-
: await service.getProfileByName(nameOrId);
|
|
497
|
-
const profileId = resolved.profileId;
|
|
498
|
-
let profile;
|
|
499
|
-
if (opts.config) {
|
|
500
|
-
// Legacy JSON file path
|
|
501
|
-
const config = JSON.parse(fs.readFileSync(opts.config, 'utf-8'));
|
|
502
|
-
profile = await service.updateProfile(profileId, config);
|
|
503
|
-
}
|
|
504
|
-
else {
|
|
505
|
-
// Read-modify-write: fetch current profile, merge flags, PUT full payload
|
|
506
|
-
const current = resolved;
|
|
507
|
-
const overrides = buildProfileOverrides({
|
|
508
|
-
promptInjection: opts.promptInjection,
|
|
509
|
-
toxicContent: opts.toxicContent,
|
|
510
|
-
contextualGrounding: opts.contextualGrounding,
|
|
511
|
-
maliciousCode: opts.maliciousCode,
|
|
512
|
-
urlAction: opts.urlAction,
|
|
513
|
-
allowUrlCategories: opts.allowUrlCategories,
|
|
514
|
-
blockUrlCategories: opts.blockUrlCategories,
|
|
515
|
-
alertUrlCategories: opts.alertUrlCategories,
|
|
516
|
-
agentSecurity: opts.agentSecurity,
|
|
517
|
-
dlpAction: opts.dlpAction,
|
|
518
|
-
dlpProfiles: opts.dlpProfiles,
|
|
519
|
-
maskDataInline: opts.maskDataInline,
|
|
520
|
-
dbSecurityCreate: opts.dbSecurityCreate,
|
|
521
|
-
dbSecurityRead: opts.dbSecurityRead,
|
|
522
|
-
dbSecurityUpdate: opts.dbSecurityUpdate,
|
|
523
|
-
dbSecurityDelete: opts.dbSecurityDelete,
|
|
524
|
-
inlineTimeoutAction: opts.inlineTimeoutAction,
|
|
525
|
-
maxInlineLatency: opts.maxInlineLatency,
|
|
526
|
-
maskDataInStorage: opts.maskDataInStorage,
|
|
527
|
-
});
|
|
528
|
-
const mergedPolicy = mergeProfilePolicy(current.policy, overrides);
|
|
529
|
-
profile = await service.updateProfile(profileId, {
|
|
530
|
-
profile_name: opts.name ?? current.profileName,
|
|
531
|
-
active: opts.active ?? current.active ?? true,
|
|
532
|
-
policy: mergedPolicy,
|
|
533
|
-
});
|
|
534
|
-
}
|
|
535
|
-
console.log(` Profile updated: ${profile.profileId}\n`);
|
|
536
|
-
renderProfileDetail(profile);
|
|
537
|
-
}
|
|
538
|
-
catch (err) {
|
|
539
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
540
|
-
process.exit(1);
|
|
541
|
-
}
|
|
542
|
-
});
|
|
543
|
-
profiles
|
|
544
|
-
.command('delete <nameOrId>')
|
|
545
|
-
.description('Delete a security profile by name or UUID')
|
|
546
|
-
.option('--force', 'Force delete (removes from referencing policies)')
|
|
547
|
-
.option('--updated-by <email>', 'Email of user performing force deletion')
|
|
548
|
-
.action(async (nameOrId, opts) => {
|
|
549
|
-
try {
|
|
550
|
-
renderRuntimeConfigHeader();
|
|
551
|
-
const service = await createMgmtService();
|
|
552
|
-
const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(nameOrId);
|
|
553
|
-
let profileId = nameOrId;
|
|
554
|
-
let profileName = nameOrId;
|
|
555
|
-
if (isUuid) {
|
|
556
|
-
const profile = await service.getProfile(nameOrId);
|
|
557
|
-
profileName = profile.profileName;
|
|
558
|
-
}
|
|
559
|
-
else {
|
|
560
|
-
const profile = await service.getProfileByName(nameOrId);
|
|
561
|
-
profileId = profile.profileId;
|
|
562
|
-
profileName = profile.profileName;
|
|
563
|
-
}
|
|
564
|
-
if (opts.force) {
|
|
565
|
-
if (!opts.updatedBy) {
|
|
566
|
-
renderError('--updated-by <email> is required with --force');
|
|
567
|
-
process.exit(1);
|
|
568
|
-
}
|
|
569
|
-
await service.forceDeleteProfile(profileId, opts.updatedBy);
|
|
570
|
-
}
|
|
571
|
-
else {
|
|
572
|
-
await service.deleteProfile(profileId);
|
|
573
|
-
}
|
|
574
|
-
console.log(` Profile deleted: ${profileName} (${profileId})\n`);
|
|
575
|
-
}
|
|
576
|
-
catch (err) {
|
|
577
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
578
|
-
process.exit(1);
|
|
579
|
-
}
|
|
580
|
-
});
|
|
581
|
-
// Register cleanup under profiles
|
|
582
|
-
registerCleanupCommand(profiles);
|
|
583
|
-
// Register audit under profiles
|
|
584
|
-
registerAuditCommand(profiles);
|
|
585
|
-
// -----------------------------------------------------------------------
|
|
586
|
-
// runtime resume-poll — resume polling for bulk scans
|
|
587
|
-
// -----------------------------------------------------------------------
|
|
588
|
-
runtime
|
|
589
|
-
.command('resume-poll <stateFile>')
|
|
590
|
-
.description('Resume polling for a previously submitted bulk scan')
|
|
591
|
-
.option('--output <file>', 'Output CSV file path')
|
|
592
|
-
.action(async (stateFile, opts) => {
|
|
593
|
-
try {
|
|
594
|
-
const config = await loadConfig({});
|
|
595
|
-
if (!config.airsApiKey) {
|
|
596
|
-
renderError('PANW_AI_SEC_API_KEY is required');
|
|
597
|
-
process.exit(1);
|
|
598
|
-
}
|
|
599
|
-
const state = await loadBulkScanState(stateFile);
|
|
600
|
-
const service = new SdkRuntimeService(config.airsApiKey);
|
|
601
|
-
console.log(chalk.bold.cyan('\n Prisma AIRS Resume Poll'));
|
|
602
|
-
console.log(chalk.dim(` Profile: ${state.profile}`));
|
|
603
|
-
console.log(chalk.dim(` Scan IDs: ${state.scanIds.length}`));
|
|
604
|
-
console.log(chalk.dim(` Prompts: ${state.promptCount}\n`));
|
|
605
|
-
console.log(chalk.dim(' Polling for results...'));
|
|
606
|
-
const results = await service.pollResults(state.scanIds, undefined, {
|
|
607
|
-
onRetry: (attempt, delayMs) => {
|
|
608
|
-
console.log(chalk.yellow(` ⚠ Rate limited — retry ${attempt} in ${(delayMs / 1000).toFixed(0)}s...`));
|
|
609
|
-
},
|
|
610
|
-
});
|
|
611
|
-
const outputPath = opts.output ?? `${state.profile.replace(/\s+/g, '-')}-bulk-scan.csv`;
|
|
612
|
-
const csv = SdkRuntimeService.formatResultsCsv(results);
|
|
613
|
-
await writeFile(outputPath, csv, 'utf-8');
|
|
614
|
-
const blocked = results.filter((r) => r.action === 'block').length;
|
|
615
|
-
const allowed = results.filter((r) => r.action === 'allow').length;
|
|
616
|
-
console.log(chalk.bold('\n Resume Poll Complete'));
|
|
617
|
-
console.log(chalk.dim(' ─────────────────────────'));
|
|
618
|
-
console.log(` Total: ${results.length}`);
|
|
619
|
-
console.log(` Blocked: ${chalk.red(String(blocked))}`);
|
|
620
|
-
console.log(` Allowed: ${chalk.green(String(allowed))}`);
|
|
621
|
-
console.log(` Output: ${chalk.cyan(outputPath)}\n`);
|
|
622
|
-
}
|
|
623
|
-
catch (err) {
|
|
624
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
625
|
-
process.exit(1);
|
|
626
|
-
}
|
|
627
|
-
});
|
|
628
|
-
// -----------------------------------------------------------------------
|
|
629
|
-
// runtime scan — single prompt scanning
|
|
630
|
-
// -----------------------------------------------------------------------
|
|
631
|
-
runtime
|
|
632
|
-
.command('scan <prompt>')
|
|
633
|
-
.description('Scan a single prompt against an AIRS security profile')
|
|
634
|
-
.requiredOption('--profile <name>', 'Security profile name')
|
|
635
|
-
.option('--response <text>', 'Response text to scan alongside the prompt')
|
|
636
|
-
.action(async (prompt, opts) => {
|
|
637
|
-
try {
|
|
638
|
-
const config = await loadConfig({});
|
|
639
|
-
if (!config.airsApiKey) {
|
|
640
|
-
renderError('PANW_AI_SEC_API_KEY is required');
|
|
641
|
-
process.exit(1);
|
|
642
|
-
}
|
|
643
|
-
const service = new SdkRuntimeService(config.airsApiKey);
|
|
644
|
-
console.log(chalk.bold.cyan('\n Prisma AIRS Runtime Scan'));
|
|
645
|
-
console.log(chalk.dim(` Profile: ${opts.profile}`));
|
|
646
|
-
console.log(chalk.dim(` Prompt: "${prompt.slice(0, 80)}${prompt.length > 80 ? '...' : ''}"`));
|
|
647
|
-
const result = await service.scanPrompt(opts.profile, prompt, opts.response);
|
|
648
|
-
renderScanResult(result);
|
|
649
|
-
}
|
|
650
|
-
catch (err) {
|
|
651
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
652
|
-
process.exit(1);
|
|
653
|
-
}
|
|
654
|
-
});
|
|
655
|
-
// -----------------------------------------------------------------------
|
|
656
|
-
// runtime scan-logs — scan log query
|
|
657
|
-
// -----------------------------------------------------------------------
|
|
658
|
-
const scanLogs = runtime.command('scan-logs').description('Query AIRS scan logs');
|
|
659
|
-
scanLogs
|
|
660
|
-
.command('query')
|
|
661
|
-
.description('Query scan logs')
|
|
662
|
-
.requiredOption('--interval <n>', 'Time interval')
|
|
663
|
-
.requiredOption('--unit <unit>', 'Time unit (hours)')
|
|
664
|
-
.option('--filter <filter>', 'Filter: all, benign, threat', 'all')
|
|
665
|
-
.option('--page <n>', 'Page number', '1')
|
|
666
|
-
.option('--page-size <n>', 'Page size', '50')
|
|
667
|
-
.option('--output <format>', 'Output format: pretty, table, csv, json, yaml', 'pretty')
|
|
668
|
-
.action(async (opts) => {
|
|
669
|
-
try {
|
|
670
|
-
const fmt = opts.output;
|
|
671
|
-
if (fmt === 'pretty')
|
|
672
|
-
renderRuntimeConfigHeader();
|
|
673
|
-
const service = await createMgmtService();
|
|
674
|
-
const result = await service.queryScanLogs({
|
|
675
|
-
timeInterval: Number.parseInt(opts.interval, 10),
|
|
676
|
-
timeUnit: opts.unit,
|
|
677
|
-
pageNumber: Number.parseInt(opts.page, 10),
|
|
678
|
-
pageSize: Number.parseInt(opts.pageSize, 10),
|
|
679
|
-
filter: opts.filter,
|
|
680
|
-
});
|
|
681
|
-
renderScanLogList(result.results, result.pageToken, fmt);
|
|
682
|
-
}
|
|
683
|
-
catch (err) {
|
|
684
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
685
|
-
process.exit(1);
|
|
686
|
-
}
|
|
687
|
-
});
|
|
688
|
-
// -----------------------------------------------------------------------
|
|
689
|
-
// runtime topics — custom topic CRUD + guardrail generation subcommands
|
|
690
|
-
// -----------------------------------------------------------------------
|
|
691
|
-
const topics = runtime
|
|
692
|
-
.command('topics')
|
|
693
|
-
.description('Manage AIRS custom topics and guardrail generation');
|
|
694
|
-
// Register all topics subcommands in alphabetical order
|
|
695
|
-
registerApplyCommand(topics);
|
|
696
|
-
registerCreateCommand(topics);
|
|
697
|
-
topics
|
|
698
|
-
.command('delete <topicId>')
|
|
699
|
-
.description('Delete a custom topic')
|
|
700
|
-
.option('--force', 'Force delete (removes from all referencing profiles)')
|
|
701
|
-
.option('--updated-by <email>', 'Email of user performing force deletion')
|
|
702
|
-
.action(async (topicId, opts) => {
|
|
703
|
-
try {
|
|
704
|
-
renderRuntimeConfigHeader();
|
|
705
|
-
const service = await createMgmtService();
|
|
706
|
-
if (opts.force) {
|
|
707
|
-
const result = await service.forceDeleteTopic(topicId, opts.updatedBy);
|
|
708
|
-
console.log(` ${result.message}\n`);
|
|
709
|
-
}
|
|
710
|
-
else {
|
|
711
|
-
await service.deleteTopic(topicId);
|
|
712
|
-
console.log(` Topic ${topicId} deleted.\n`);
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
catch (err) {
|
|
716
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
717
|
-
process.exit(1);
|
|
718
|
-
}
|
|
719
|
-
});
|
|
720
|
-
registerEvalCommand(topics);
|
|
721
|
-
topics
|
|
722
|
-
.command('get <nameOrId>')
|
|
723
|
-
.description('Get a custom topic by name or UUID')
|
|
724
|
-
.option('--output <format>', 'Output format: pretty, json, yaml', 'pretty')
|
|
725
|
-
.action(async (nameOrId, opts) => {
|
|
726
|
-
try {
|
|
727
|
-
const fmt = opts.output;
|
|
728
|
-
if (fmt !== 'pretty' && fmt !== 'json' && fmt !== 'yaml') {
|
|
729
|
-
renderError(`Invalid output format "${fmt}". Valid: pretty, json, yaml`);
|
|
730
|
-
process.exit(1);
|
|
731
|
-
}
|
|
732
|
-
if (fmt === 'pretty')
|
|
733
|
-
renderRuntimeConfigHeader();
|
|
734
|
-
const service = await createMgmtService();
|
|
735
|
-
const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(nameOrId);
|
|
736
|
-
const topic = isUuid
|
|
737
|
-
? await service.getTopic(nameOrId)
|
|
738
|
-
: await service.getTopicByName(nameOrId);
|
|
739
|
-
if (fmt === 'json') {
|
|
740
|
-
console.log(JSON.stringify(topic, null, 2));
|
|
741
|
-
}
|
|
742
|
-
else if (fmt === 'yaml') {
|
|
743
|
-
const lines = [`topic_id: ${topic.topic_id}`, `topic_name: ${topic.topic_name}`];
|
|
744
|
-
if (topic.revision != null)
|
|
745
|
-
lines.push(`revision: ${topic.revision}`);
|
|
746
|
-
if (topic.description)
|
|
747
|
-
lines.push(`description: ${topic.description}`);
|
|
748
|
-
if (topic.examples?.length) {
|
|
749
|
-
lines.push('examples:');
|
|
750
|
-
for (const ex of topic.examples)
|
|
751
|
-
lines.push(` - ${ex}`);
|
|
752
|
-
}
|
|
753
|
-
if (topic.created_by)
|
|
754
|
-
lines.push(`created_by: ${topic.created_by}`);
|
|
755
|
-
if (topic.updated_by)
|
|
756
|
-
lines.push(`updated_by: ${topic.updated_by}`);
|
|
757
|
-
if (topic.last_modified_ts)
|
|
758
|
-
lines.push(`last_modified_ts: ${topic.last_modified_ts}`);
|
|
759
|
-
console.log(lines.join('\n'));
|
|
760
|
-
}
|
|
761
|
-
else {
|
|
762
|
-
renderTopicDetail(topic);
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
catch (err) {
|
|
766
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
767
|
-
process.exit(1);
|
|
768
|
-
}
|
|
769
|
-
});
|
|
770
|
-
topics
|
|
771
|
-
.command('list')
|
|
772
|
-
.description('List custom topics')
|
|
773
|
-
.option('--limit <n>', 'Max results', '100')
|
|
774
|
-
.option('--offset <n>', 'Starting offset', '0')
|
|
775
|
-
.option('--output <format>', 'Output format: pretty, table, csv, json, yaml', 'pretty')
|
|
776
|
-
.action(async (opts) => {
|
|
777
|
-
try {
|
|
778
|
-
const fmt = opts.output;
|
|
779
|
-
if (fmt === 'pretty')
|
|
780
|
-
renderRuntimeConfigHeader();
|
|
781
|
-
const service = await createMgmtService();
|
|
782
|
-
const allTopics = await service.listTopics();
|
|
783
|
-
// Client-side pagination since SDK returns all
|
|
784
|
-
const offset = Number.parseInt(opts.offset, 10);
|
|
785
|
-
const limit = Number.parseInt(opts.limit, 10);
|
|
786
|
-
const page = allTopics.slice(offset, offset + limit);
|
|
787
|
-
renderTopicList(page, fmt);
|
|
788
|
-
if (fmt === 'pretty' && offset + limit < allTopics.length) {
|
|
789
|
-
console.log(chalk.dim(` Showing ${page.length} of ${allTopics.length} topics\n`));
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
catch (err) {
|
|
793
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
794
|
-
process.exit(1);
|
|
795
|
-
}
|
|
796
|
-
});
|
|
797
|
-
registerRevertCommand(topics);
|
|
798
|
-
registerSampleCommand(topics);
|
|
799
|
-
topics
|
|
800
|
-
.command('update <topicId>')
|
|
801
|
-
.description('Update a custom topic')
|
|
802
|
-
.requiredOption('--config <path>', 'JSON file with topic updates')
|
|
803
|
-
.action(async (topicId, opts) => {
|
|
804
|
-
try {
|
|
805
|
-
renderRuntimeConfigHeader();
|
|
806
|
-
const service = await createMgmtService();
|
|
807
|
-
const config = JSON.parse(fs.readFileSync(opts.config, 'utf-8'));
|
|
808
|
-
const topic = await service.updateTopic(topicId, config);
|
|
809
|
-
console.log(` Topic updated: ${topic.topic_id}\n`);
|
|
810
|
-
renderTopicDetail(topic);
|
|
811
|
-
}
|
|
812
|
-
catch (err) {
|
|
813
|
-
renderError(err instanceof Error ? err.message : String(err));
|
|
814
|
-
process.exit(1);
|
|
815
|
-
}
|
|
816
|
-
});
|
|
817
|
-
// -----------------------------------------------------------------------
|
|
818
|
-
// runtime dlp — DLP management subcommands (incl. `generate`)
|
|
819
|
-
// -----------------------------------------------------------------------
|
|
820
|
-
registerDlpCommands(runtime);
|
|
821
|
-
}
|
|
822
|
-
//# sourceMappingURL=runtime.js.map
|