-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add curated Drata compliance workflows #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
291c6be
79b040b
339270e
8f0d270
a692da1
1f486d5
a276de3
7bd1346
9b5cc9f
dd072d2
33766be
cfad650
b76f981
0ec0148
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,17 @@ import { parseRequestFlags, parseSimpleFlags } from "./lib/args.mjs"; | |
| import { loadDefaultEnvFiles } from "./lib/env.mjs"; | ||
| import { invokeOperation, prepareRequest, resolveEffectiveRequestFlags, serializePreparedRequest } from "./lib/http.mjs"; | ||
| import { renderCompletionScript, runCompletion } from "./lib/completion.mjs"; | ||
| import { | ||
| prepareWorkflowFlags, | ||
| printWorkflowPayload, | ||
| runConnectionsList, | ||
| runControlsFailing, | ||
| runEvidenceExpiring, | ||
| runMonitorsFailing, | ||
| runPersonnelIssues, | ||
| runSummary, | ||
| runWorkflowOperation, | ||
| } from "./lib/workflows.mjs"; | ||
| import { | ||
| filterOperations, | ||
| getRegistry, | ||
|
|
@@ -37,7 +48,13 @@ Usage: | |
| drata ops [v1|v2] [--tag TAG] [--search TEXT] | ||
| drata describe [v1|v2] <operation> | ||
| drata call <v1|v2> <operation> [flags] | ||
| drata auth <login|status|logout> | ||
| drata auth <login|status|check|logout> | ||
| drata summary [--json] [--compact] | ||
| drata controls failing [--json] [--compact] | ||
| drata monitors failing [--json] [--compact] | ||
| drata connections list [--status STATUS] [--json] [--compact] | ||
| drata personnel issues [--json] [--compact] | ||
| drata evidence expiring [--days N] [--json] [--compact] | ||
| drata completion <bash|zsh|fish> | ||
| drata agent-schema [v1|v2] [--tag TAG] [--search TEXT] | ||
| drata <operation> [flags] | ||
|
|
@@ -65,6 +82,8 @@ Flags for request commands: | |
| --dry-run | ||
| --read-only | ||
| --json | ||
| --compact | ||
| --limit 10 | ||
| --retry 2 | ||
| --timeout-ms 30000 | ||
|
|
||
|
|
@@ -73,6 +92,11 @@ Examples: | |
| drata describe get-company | ||
| drata describe v2 get-company | ||
| drata auth status | ||
| drata auth check --json | ||
| drata summary --json --compact | ||
| drata controls failing --json --compact | ||
| drata monitors failing --json --compact | ||
| drata connections list --status DISCONNECTED --json --compact | ||
| drata completion zsh | ||
| drata agent-schema v2 --search controls | ||
| drata get-company | ||
|
|
@@ -157,6 +181,30 @@ async function handleAuth(args) { | |
| return; | ||
| } | ||
|
|
||
| if (subcommand === "check") { | ||
| const flags = await prepareWorkflowFlags(await resolveEffectiveRequestFlags(parseRequestFlags(rest))); | ||
| const { result, operation } = await runWorkflowOperation("v2", "get-company", flags); | ||
| const payload = { | ||
| authenticated: true, | ||
| source: flags.apiKeySource, | ||
| region: flags.region ?? process.env.DRATA_REGION ?? "us", | ||
| operation: serializeOperationSummary(operation), | ||
| company: result.data, | ||
| }; | ||
|
|
||
| if (flags.json) { | ||
| console.log(JSON.stringify(payload, null, 2)); | ||
| return; | ||
| } | ||
|
|
||
| const name = result.data?.name ?? result.data?.companyName ?? result.data?.data?.name ?? "unknown"; | ||
| console.log(`OK Authenticated`); | ||
| console.log(`Company: ${name}`); | ||
| console.log(`Region: ${payload.region}`); | ||
| console.log(`Key from: ${payload.source}`); | ||
| return; | ||
| } | ||
|
|
||
| if (subcommand === "login") { | ||
| const flags = parseRequestFlags(rest); | ||
| const { apiKey, source } = await resolveApiKey(flags); | ||
|
|
@@ -198,7 +246,7 @@ async function handleAuth(args) { | |
| return; | ||
| } | ||
|
|
||
| fail("unknown_auth_command", `Unknown auth command "${subcommand}". Expected login, status, or logout.`, { | ||
| fail("unknown_auth_command", `Unknown auth command "${subcommand}". Expected login, status, check, or logout.`, { | ||
| command: subcommand, | ||
| }); | ||
| } | ||
|
|
@@ -449,6 +497,118 @@ async function writeResponseOutput(parsedFlags, result) { | |
| }; | ||
| } | ||
|
|
||
| function takeWorkflowNamedFlag(flags, name) { | ||
| const values = flags.named.get(name) ?? []; | ||
| flags.named.delete(name); | ||
| return values.at(-1) ?? null; | ||
| } | ||
|
|
||
| async function parseWorkflowRequestFlags(args) { | ||
| return prepareWorkflowFlags(await resolveEffectiveRequestFlags(parseRequestFlags(args))); | ||
| } | ||
|
|
||
| async function handleSummary(args) { | ||
| const flags = await parseWorkflowRequestFlags(args); | ||
| printWorkflowPayload(await runSummary(flags), flags); | ||
| } | ||
|
|
||
| async function handleControlsWorkflow(args) { | ||
| const [subcommand, ...rest] = args; | ||
| if (!subcommand || subcommand === "--help" || subcommand === "help") { | ||
| printUsage(); | ||
| return; | ||
| } | ||
|
|
||
| const flags = await parseWorkflowRequestFlags(rest); | ||
| if (subcommand === "failing") { | ||
| printWorkflowPayload(await runControlsFailing(flags), flags); | ||
| return; | ||
| } | ||
|
|
||
| fail("unknown_controls_command", `Unknown controls command "${subcommand}". Expected failing.`, { | ||
| command: subcommand, | ||
| }); | ||
| } | ||
|
|
||
| async function handleMonitorsWorkflow(args) { | ||
| const [subcommand, ...rest] = args; | ||
| if (!subcommand || subcommand === "--help" || subcommand === "help") { | ||
| printUsage(); | ||
| return; | ||
| } | ||
|
|
||
| const flags = await parseWorkflowRequestFlags(rest); | ||
| if (subcommand === "failing") { | ||
| printWorkflowPayload(await runMonitorsFailing(flags), flags); | ||
| return; | ||
| } | ||
|
|
||
| fail("unknown_monitors_command", `Unknown monitors command "${subcommand}". Expected failing.`, { | ||
| command: subcommand, | ||
| }); | ||
| } | ||
|
|
||
| async function handleConnectionsWorkflow(args) { | ||
| const [subcommand, ...rest] = args; | ||
| if (!subcommand || subcommand === "--help" || subcommand === "help") { | ||
| printUsage(); | ||
| return; | ||
| } | ||
|
|
||
| const flags = await parseWorkflowRequestFlags(rest); | ||
| const status = takeWorkflowNamedFlag(flags, "status"); | ||
| if (subcommand === "list") { | ||
| printWorkflowPayload(await runConnectionsList(flags, { status }), flags); | ||
| return; | ||
| } | ||
|
|
||
| fail("unknown_connections_command", `Unknown connections command "${subcommand}". Expected list.`, { | ||
| command: subcommand, | ||
| }); | ||
| } | ||
|
|
||
| async function handlePersonnelWorkflow(args) { | ||
| const [subcommand, ...rest] = args; | ||
| if (!subcommand || subcommand === "--help" || subcommand === "help") { | ||
| printUsage(); | ||
| return; | ||
| } | ||
|
|
||
| const flags = await parseWorkflowRequestFlags(rest); | ||
| if (subcommand === "issues") { | ||
| printWorkflowPayload(await runPersonnelIssues(flags), flags); | ||
| return; | ||
| } | ||
|
|
||
| fail("unknown_personnel_command", `Unknown personnel command "${subcommand}". Expected issues.`, { | ||
| command: subcommand, | ||
| }); | ||
| } | ||
|
|
||
| async function handleEvidenceWorkflow(args) { | ||
| const [subcommand, ...rest] = args; | ||
| if (!subcommand || subcommand === "--help" || subcommand === "help") { | ||
| printUsage(); | ||
| return; | ||
| } | ||
|
|
||
| const flags = await parseWorkflowRequestFlags(rest); | ||
| const days = Number(takeWorkflowNamedFlag(flags, "days") ?? 30); | ||
| const workspaceId = takeWorkflowNamedFlag(flags, "workspace-id"); | ||
| if (!Number.isInteger(days) || days < 0) { | ||
| fail("invalid_days", `--days must be a non-negative integer`, { days }); | ||
| } | ||
|
|
||
| if (subcommand === "expiring") { | ||
| printWorkflowPayload(await runEvidenceExpiring(flags, { days, workspaceId }), flags); | ||
| return; | ||
|
Comment on lines
+643
to
+664
|
||
| } | ||
|
|
||
| fail("unknown_evidence_command", `Unknown evidence command "${subcommand}". Expected expiring.`, { | ||
| command: subcommand, | ||
| }); | ||
| } | ||
|
|
||
| async function handleAutoCall(operationInput, args) { | ||
| const operation = await resolveOperationAcrossVersions(operationInput, { | ||
| preferredVersion: getPreferredVersion(), | ||
|
|
@@ -511,6 +671,36 @@ async function main() { | |
| return; | ||
| } | ||
|
|
||
| if (command === "summary") { | ||
| await handleSummary(rest); | ||
| return; | ||
| } | ||
|
|
||
| if (command === "controls") { | ||
| await handleControlsWorkflow(rest); | ||
| return; | ||
| } | ||
|
|
||
| if (command === "monitors") { | ||
| await handleMonitorsWorkflow(rest); | ||
| return; | ||
| } | ||
|
|
||
| if (command === "connections") { | ||
| await handleConnectionsWorkflow(rest); | ||
| return; | ||
| } | ||
|
|
||
| if (command === "personnel") { | ||
| await handlePersonnelWorkflow(rest); | ||
| return; | ||
| } | ||
|
|
||
| if (command === "evidence") { | ||
| await handleEvidenceWorkflow(rest); | ||
| return; | ||
| } | ||
|
|
||
| if (command === "completion") { | ||
| await handleCompletion(rest); | ||
| return; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This handler resolves workflow flags (
parseWorkflowRequestFlags) before verifying the subcommand, andparseWorkflowRequestFlagsperforms auth checks. As a result, unauthenticated users seemissing_api_keyfor typos likedrata controls nope(and for... --help) instead of the intended unknown-command/help response, which blocks basic command discovery when not logged in.Useful? React with 👍 / 👎.