From 454ddc2bd0cb40bad0b0b1379e3cfdd3f4666809 Mon Sep 17 00:00:00 2001 From: vadimsolovey Date: Thu, 1 Oct 2026 17:36:46 +0300 Subject: [PATCH 1/2] docs: changelog for v2.8.0 and curated command docs for 33 new operations Clears both release gates for v2.8.0: the changelog entry, and the command-docs coverage gate (243/243 curated). Supersedes the stale draft stubs in #185. Co-Authored-By: Claude Sonnet 5.5 --- CHANGELOG.md | 41 +++++++++++++++++ command-docs/assign-contract-template.yaml | 40 ++++++++++++++++ command-docs/create-role.yaml | 27 +++++++++++ .../create-service-account-token.yaml | 46 +++++++++++++++++++ command-docs/create-service-account.yaml | 41 +++++++++++++++++ command-docs/create-signup-request.yaml | 34 ++++++++++++++ command-docs/create-signup-session.yaml | 26 +++++++++++ command-docs/delete-role.yaml | 19 ++++++++ .../delete-service-account-token.yaml | 33 +++++++++++++ command-docs/delete-service-account.yaml | 31 +++++++++++++ command-docs/get-commitment-policy.yaml | 23 ++++++++++ command-docs/get-role.yaml | 20 ++++++++ command-docs/get-service-account-token.yaml | 30 ++++++++++++ command-docs/get-service-account.yaml | 20 ++++++++ command-docs/get-signup-request.yaml | 22 +++++++++ command-docs/get-widget.yaml | 25 ++++++++++ .../import-datahub-provider-records.yaml | 44 ++++++++++++++++++ command-docs/list-alert-slack-channels.yaml | 22 +++++++++ command-docs/list-commitment-policies.yaml | 20 ++++++++ command-docs/list-customer-group-users.yaml | 20 ++++++++ command-docs/list-service-account-tokens.yaml | 29 ++++++++++++ command-docs/list-service-accounts.yaml | 23 ++++++++++ .../list-shared-payer-account-mappings.yaml | 24 ++++++++++ ...list-shared-payer-management-accounts.yaml | 20 ++++++++ command-docs/list-shared-payers.yaml | 24 ++++++++++ command-docs/list-widgets.yaml | 16 +++++++ .../reassign-shared-payer-account.yaml | 31 +++++++++++++ command-docs/resend-signup-verification.yaml | 21 +++++++++ command-docs/stop-cloudflow-flow.yaml | 23 ++++++++++ command-docs/trigger-cloudflow-flow.yaml | 37 +++++++++++++++ command-docs/update-role.yaml | 26 +++++++++++ .../update-service-account-token.yaml | 37 +++++++++++++++ command-docs/update-service-account.yaml | 44 ++++++++++++++++++ command-docs/verify-signup-request.yaml | 24 ++++++++++ 34 files changed, 963 insertions(+) create mode 100644 command-docs/assign-contract-template.yaml create mode 100644 command-docs/create-role.yaml create mode 100644 command-docs/create-service-account-token.yaml create mode 100644 command-docs/create-service-account.yaml create mode 100644 command-docs/create-signup-request.yaml create mode 100644 command-docs/create-signup-session.yaml create mode 100644 command-docs/delete-role.yaml create mode 100644 command-docs/delete-service-account-token.yaml create mode 100644 command-docs/delete-service-account.yaml create mode 100644 command-docs/get-commitment-policy.yaml create mode 100644 command-docs/get-role.yaml create mode 100644 command-docs/get-service-account-token.yaml create mode 100644 command-docs/get-service-account.yaml create mode 100644 command-docs/get-signup-request.yaml create mode 100644 command-docs/get-widget.yaml create mode 100644 command-docs/import-datahub-provider-records.yaml create mode 100644 command-docs/list-alert-slack-channels.yaml create mode 100644 command-docs/list-commitment-policies.yaml create mode 100644 command-docs/list-customer-group-users.yaml create mode 100644 command-docs/list-service-account-tokens.yaml create mode 100644 command-docs/list-service-accounts.yaml create mode 100644 command-docs/list-shared-payer-account-mappings.yaml create mode 100644 command-docs/list-shared-payer-management-accounts.yaml create mode 100644 command-docs/list-shared-payers.yaml create mode 100644 command-docs/list-widgets.yaml create mode 100644 command-docs/reassign-shared-payer-account.yaml create mode 100644 command-docs/resend-signup-verification.yaml create mode 100644 command-docs/stop-cloudflow-flow.yaml create mode 100644 command-docs/trigger-cloudflow-flow.yaml create mode 100644 command-docs/update-role.yaml create mode 100644 command-docs/update-service-account-token.yaml create mode 100644 command-docs/update-service-account.yaml create mode 100644 command-docs/verify-signup-request.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index da003a9..8dff5a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,47 @@ latest version, run `dci update`, or see [install and update](https://help.doit.com/docs/cli#download-and-install) in the CLI guide. +## v2.8.0 — October 1, 2026 + +### New + +- `dci commands --search ""` finds the command for a task in plain + words — `dci commands --search "resolve an anomaly"` — and lists the best + matches with a one-line example each, so you or your agent no longer have + to scan the whole catalog. Beta commands are searchable too, marked with + their stage. See [Agent mode](https://help.doit.com/docs/cli#agent-mode). +- `--help` shows curated examples for more commands, including roles, + service accounts and their tokens, customer group users, shared payers, + commitment policies, widgets, CloudFlow `trigger-cloudflow-flow` and + `stop-cloudflow-flow`, and the signup flow. + +### Improved + +- `dci --help` lists only the flags that apply to that command. + Report and query flags such as `--chart`, `--pivot`, and `--rollup` show + up on the commands that return reports and queries, `--output-file` on + exports, and `--all` on commands that page; the options that apply to + every command fold into one line, and `--help-full` still lists + everything. Every flag is still accepted on every command. +- `dci --help` states the exit codes and the error format that scripts and + agents can rely on. See + [Exit codes](https://help.doit.com/docs/cli#exit-codes). +- `dci anomalies-recent` and `dci budgets-at-risk` are listed with the + anomalies and budgets commands instead of under "Additional Commands". +- `dci status` shows when your stored session expires, whether a refresh + token is saved, and where the session cache lives, and no longer calls an + expired token a cached login. + +### Fixed + +- `dci --help` and `dci --help` work without a session. They used + to fail with "no credentials available" when you were signed out or your + cache was stale — or open a browser login just to print usage. +- A login that cannot run, such as in CI or an agent session with no + browser, now fails with `AUTHENTICATION_REQUIRED` and exit code 10 on + every path, instead of "dci encountered an internal error" on some of + them. See [Exit codes](https://help.doit.com/docs/cli#exit-codes). + ## v2.7.6 — September 10, 2026 ### Improved diff --git a/command-docs/assign-contract-template.yaml b/command-docs/assign-contract-template.yaml new file mode 100644 index 0000000..f295d6c --- /dev/null +++ b/command-docs/assign-contract-template.yaml @@ -0,0 +1,40 @@ +command: assign-contract-template + +arguments: + template-id: >- + Contract template ID as shown by `dci list-contract-templates` (the `id` field). The template + must belong to your organization and must not be archived. + +examples: + - description: Create a draft contract from a template for two child customers. + command: "dci assign-contract-template customerIds: [, ]" + output: >- + The response lists `count` and one `createdContracts` entry (`customerId`, `contractId`) per draft, + in the order the customers were given. + - description: Assign the template to a longer list of customers, read from a file. + command: "dci assign-contract-template < customers.json" + output: | + # customers.json + {"customerIds": ["", "", ""]} + - description: Capture the new draft contract IDs for a script. + command: >- + dci assign-contract-template customerIds: [] --output json + | jq -r '.createdContracts[].contractId' + +notes: | + Each customer gets a **draft** contract, which has no billing effect until it is completed and + activated. `customerIds` is required and takes 1 to 250 entries; each must be a tenant one tier + below yours (a distributor supplies resellers, a reseller supplies end customers). Repeated IDs + are ignored, but a customer that already holds a contract from this template receives another + draft. The current date must fall within the template's eligibility window. Requires the + ContractTemplatesAdmin permission, DoiT API access, and the `channelops:contracts:templates` + entitlement. + +related: + [ + list-contract-templates, + get-contract-template, + create-contract-template, + update-contract-template, + archive-contract-template, + ] diff --git a/command-docs/create-role.yaml b/command-docs/create-role.yaml new file mode 100644 index 0000000..e9f5081 --- /dev/null +++ b/command-docs/create-role.yaml @@ -0,0 +1,27 @@ +command: create-role + +examples: + - description: Create a custom role from permission IDs (take them from the `permissions` of `dci list-roles`). + command: >- + dci create-role name: "FinOps Analyst", description: "Read-only access to cost reports and budgets", + permissions: [, ] --idempotency-key "$(uuidgen)" + - description: Create it from a JSON file. + command: 'dci create-role --idempotency-key "$(uuidgen)" < role.json' + output: | + # role.json + {"name": "FinOps Analyst", "description": "Read-only access to cost reports and budgets", + "permissions": ["", ""]} + - description: Capture the new role's ID for a script, for example to assign it to a user. + command: 'dci create-role name: "FinOps Analyst", permissions: [] --idempotency-key "$(uuidgen)" --output json | jq -r .id' + +notes: | + Only `name` is required; omit `permissions` (or send an empty list) to create a role without + any. The name must be nonblank, free of leading or trailing whitespace, and unique among the + customer's roles, preset roles included (`409` otherwise). Duplicate permission IDs, or IDs + that do not exist or are not available to the customer, return `400`. + + The API requires an `Idempotency-Key` on every call: retrying with the same key and body + returns the original response instead of creating a second role, while the same key with a + different body returns `422`. + +related: [list-roles, get-role, update-role, delete-role] diff --git a/command-docs/create-service-account-token.yaml b/command-docs/create-service-account-token.yaml new file mode 100644 index 0000000..98ebb1c --- /dev/null +++ b/command-docs/create-service-account-token.yaml @@ -0,0 +1,46 @@ +command: create-service-account-token + +arguments: + service-account-id: >- + Service account ID or name as shown by `dci list-service-accounts`. Names resolve (exact, + unique substring, or close typo); pass `--id` to force a literal ID. + +examples: + - description: Mint a token that expires on a given date. Run it with --output json and store the `accessToken` in a secret manager at once. + command: >- + dci create-service-account-token name: ci-pipeline-prod, + expiresTime: "2027-09-01T08:00:00Z" --idempotency-key "$(uuidgen)" --output json + - description: Mint a token with the server's default expiry. + command: 'dci create-service-account-token name: ci-pipeline-prod --idempotency-key "$(uuidgen)"' + - description: Check the name server-side first; nothing is created. + command: "dci create-service-account-token name: ci-pipeline-prod --dry-run" + +notes: | + :::caution The secret is shown once + The `accessToken` in the create response is the credential that authenticates as the service + account. It is returned only by this operation and can never be retrieved again, so store it + somewhere safe on receipt and treat it like a password. Later get and list calls never + include it; if it is lost, create a new token and delete the old one. + ::: + + `name` is required (1-100 characters, no leading or trailing whitespace) and unique among + the account's tokens (`409`). The token inherits the service account's permissions as they + stand at creation; there is no per-token scoping. An account holds at most 10 tokens (`422` + at the cap). Requires the `serviceAccountCreator` permission, and the API requires an + `Idempotency-Key` on every real call. + + :::info Dry run is shallow + `--dry-run` sends the API's `dryRun=true`, which checks only the name bounds: it does not + verify that the service account exists, that the name is unused, or that the account is + under the cap, so a dry run can succeed where the real create returns `404`, `409` or `422`. + The preview response has `accessToken` as an empty string. + ::: + +related: + [ + list-service-account-tokens, + get-service-account-token, + update-service-account-token, + delete-service-account-token, + create-service-account, + ] diff --git a/command-docs/create-service-account.yaml b/command-docs/create-service-account.yaml new file mode 100644 index 0000000..77ed003 --- /dev/null +++ b/command-docs/create-service-account.yaml @@ -0,0 +1,41 @@ +command: create-service-account + +examples: + - description: Create a service account with a set of permissions (camelCase names, as in the Console role editor). + command: >- + dci create-service-account name: terraform-ci, description: "Manages DoiT resources from CI", + permissions: [cloudAnalyticsReadOnly, budgetsManager] --idempotency-key "$(uuidgen)" + - description: Check the request server-side first; nothing is created and the CLI supplies a throwaway idempotency key. + command: "dci create-service-account name: terraform-ci, permissions: [cloudAnalyticsReadOnly] --dry-run" + - description: Create it from a JSON file and capture the new ID, to mint its first API token next. + command: 'dci create-service-account --idempotency-key "$(uuidgen)" --output json < service-account.json | jq -r .id' + output: | + # service-account.json + {"name": "terraform-ci", "description": "Manages DoiT resources from CI", + "permissions": ["cloudAnalyticsReadOnly", "budgetsManager"]} + +notes: | + Only `name` is required (1-100 characters, no leading or trailing whitespace, unique among + the customer's service accounts, `409` otherwise). An unknown permission name returns `422`. + Requires the `serviceAccountCreator` permission. + + A new service account cannot authenticate anything until it has an API token: mint one with + `dci create-service-account-token`. The API requires an `Idempotency-Key` on every real + call; retrying with the same key and request returns the stored response (keys are kept for + 24 hours). + + :::info Dry run is server-side + `--dry-run` sends the request with the API's `dryRun=true`: it runs the same checks as a real + create (name bounds and uniqueness, permission names, caller scope) and returns the same + errors without creating anything. In the response, `id`, `createTime`, `updateTime` and + `etag` are `null`. + ::: + +related: + [ + list-service-accounts, + get-service-account, + update-service-account, + create-service-account-token, + delete-service-account, + ] diff --git a/command-docs/create-signup-request.yaml b/command-docs/create-signup-request.yaml new file mode 100644 index 0000000..254ca34 --- /dev/null +++ b/command-docs/create-signup-request.yaml @@ -0,0 +1,34 @@ +command: create-signup-request + +examples: + - description: Start a trial signup for the organization that owns the admin's work email domain. + command: >- + dci create-signup-request --idempotency-key "$(uuidgen)" + email: admin@example.com, companyName: "Example Corp" + output: >- + Returns the signup request with its `id` (sr_ prefix), `status: pending_consent` and a `consentUrl`. + The admin receives a 6-digit verification code by email. + - description: Identify the calling agent for attribution. + command: >- + dci create-signup-request --idempotency-key + email: admin@example.com, companyName: "Example Corp", source{channel: agent, agentClient: "my-agent 1.0"} + - description: Create it from a JSON file, and capture the request ID for the follow-up calls. + command: "dci create-signup-request --idempotency-key --output json < signup.json | jq -r .id" + output: | + # signup.json + {"email": "admin@example.com", "companyName": "Example Corp"} + +notes: | + `email` (the organization admin's work email; free-mail and disposable addresses are rejected) and + `companyName` are required, and so is `--idempotency-key` (1 to 256 characters). Retrying with the + same key returns the same request instead of creating a second one. No authentication is needed. + + Nothing is provisioned until the admin verifies the request. Present the returned `consentUrl` to the + organization's admin, or enter the emailed code yourself with `dci verify-signup-request`, and poll + `dci get-signup-request` until the request is `completed`. The human channels (`console`, `web`) also + require a `turnstileToken` and `termsConsent{version, accepted}`; the default `agent` channel does not. + + Conflicts return `409`: the email or domain is already registered (the response carries `signInUrl`), a + signup is already pending for it (the response carries `signupRequestId`), or the trial was already used. + +related: [verify-signup-request, get-signup-request, resend-signup-verification, create-signup-session] diff --git a/command-docs/create-signup-session.yaml b/command-docs/create-signup-session.yaml new file mode 100644 index 0000000..b450006 --- /dev/null +++ b/command-docs/create-signup-session.yaml @@ -0,0 +1,26 @@ +command: create-signup-session + +arguments: + signup-request-id: >- + Signup request ID (sr_ prefix), the `id` returned by `dci create-signup-request`. + +examples: + - description: Exchange the activation token from verification for a sign-in session for the new tenant. + command: 'dci create-signup-session activationToken: ""' + output: >- + Returns `customToken`, `tenantId`, `customerId` and `consoleUrl`. Sign in with `signInWithCustomToken` + against `tenantId`, then open `consoleUrl`. + - description: Read the body from a file. + command: "dci create-signup-session < session.json" + output: | + # session.json + {"activationToken": ""} + +notes: | + The `activationToken` is the one-time value returned by `dci verify-signup-request`. The session + token is bound to the request, single-use, and valid for 10 minutes. Provisioning may still be + running: `409` with `activation_not_ready` means retry shortly, while `activation_token_used` means + the token was already redeemed. An expired token returns `410` (`activation_token_expired`); use + the sign-in link from the completion page instead. No authentication is needed. + +related: [create-signup-request, verify-signup-request, get-signup-request, resend-signup-verification] diff --git a/command-docs/delete-role.yaml b/command-docs/delete-role.yaml new file mode 100644 index 0000000..4d8d716 --- /dev/null +++ b/command-docs/delete-role.yaml @@ -0,0 +1,19 @@ +command: delete-role + +arguments: + id: >- + Role ID or name as shown by `dci list-roles`. Names resolve (exact, unique substring, or + close typo); the confirmation shows the resolved target. + +examples: + - description: Preview what would be deleted without sending a request. + command: "dci delete-role --dry-run" + - description: Delete the role without an interactive prompt, for scripts. + command: "dci delete-role --yes" + +notes: | + Only custom roles can be deleted; a preset role returns `400`. A role that is still assigned + to users or groups, or held as a child tenant role, cannot be deleted (`409`): unassign it + first. A `503` means role cleanup is temporarily unavailable, so retry the deletion. + +related: [list-roles, get-role, create-role, update-role] diff --git a/command-docs/delete-service-account-token.yaml b/command-docs/delete-service-account-token.yaml new file mode 100644 index 0000000..57d630f --- /dev/null +++ b/command-docs/delete-service-account-token.yaml @@ -0,0 +1,33 @@ +command: delete-service-account-token + +arguments: + service-account-id: >- + Service account ID or name as shown by `dci list-service-accounts`. Names resolve (exact, + unique substring, or close typo); pass `--id` to force a literal ID. + id: >- + API token ID, as shown by `dci list-service-account-tokens` (the `id` field). Tokens are + not resolved by name; pass the ID. + +examples: + - description: Check the deletion server-side without performing it (the CLI supplies a throwaway idempotency key). + command: "dci delete-service-account-token --dry-run" + - description: Delete the token without an interactive prompt, for scripts. + command: 'dci delete-service-account-token --idempotency-key "$(uuidgen)" --yes' + +notes: | + :::caution Permanent + A deleted token stops authenticating immediately and cannot be restored. To pause a token + instead, use `dci update-service-account-token ... state: disabled`. Deleting an ID that no + longer exists returns `404`. Requires the `serviceAccountManager` permission. + ::: + + The API requires an `Idempotency-Key` on every real call. + +related: + [ + list-service-account-tokens, + get-service-account-token, + update-service-account-token, + create-service-account-token, + delete-service-account, + ] diff --git a/command-docs/delete-service-account.yaml b/command-docs/delete-service-account.yaml new file mode 100644 index 0000000..cdefa0b --- /dev/null +++ b/command-docs/delete-service-account.yaml @@ -0,0 +1,31 @@ +command: delete-service-account + +arguments: + id: >- + Service account ID or name as shown by `dci list-service-accounts`. Names resolve (exact, + unique substring, or close typo); the confirmation shows the resolved target. + +examples: + - description: Check the deletion server-side without performing it (the CLI supplies a throwaway idempotency key). + command: "dci delete-service-account --if-match --dry-run" + - description: Delete the account without an interactive prompt, for scripts. + command: 'dci delete-service-account --if-match --idempotency-key "$(uuidgen)" --yes' + +notes: | + :::caution Permanent + Deleting a service account also deletes all of its API tokens, which stop authenticating + immediately. Requires the `serviceAccountManager` permission. Deleting an ID that no longer + exists returns `404`. + ::: + + The API requires `If-Match` with the current ETag (the `etag` field of `dci + get-service-account`); a stale value returns `412`. It also requires an `Idempotency-Key`. + +related: + [ + get-service-account, + list-service-accounts, + create-service-account, + update-service-account, + delete-service-account-token, + ] diff --git a/command-docs/get-commitment-policy.yaml b/command-docs/get-commitment-policy.yaml new file mode 100644 index 0000000..d148ba5 --- /dev/null +++ b/command-docs/get-commitment-policy.yaml @@ -0,0 +1,23 @@ +command: get-commitment-policy + +arguments: + policy-id: >- + Commitment policy ID as shown by `dci list-commitment-policies` (the `id` field). The built-in + policies use `conservative`, `balanced` and `max_savings`; custom policies have an opaque ID. + +examples: + - description: Show a built-in policy and where it is assigned. + command: "dci get-commitment-policy balanced" + - description: Show a custom policy. + command: "dci get-commitment-policy " + - description: The full record as JSON, including its assignments. + command: "dci get-commitment-policy --output json" + +notes: | + `assignments` lists explicit assignments across AWS and GCP only. An account whose settings have not + been materialized falls back to `balanced` implicitly and does not appear there. On AWS the + assignment is currently recorded per tenant and applied to every onboarded organization, so each + organization appears once per product line. The list is not paginated, and the request fails rather + than returning a partial list if either cloud cannot be queried. + +related: [list-commitment-policies] diff --git a/command-docs/get-role.yaml b/command-docs/get-role.yaml new file mode 100644 index 0000000..9c350f4 --- /dev/null +++ b/command-docs/get-role.yaml @@ -0,0 +1,20 @@ +command: get-role + +arguments: + id: >- + Role ID or name as shown by `dci list-roles`. Names resolve (exact, unique substring, or + close typo); pass `--id` to force a literal ID. + +examples: + - description: Show one role, by name. + command: 'dci get-role "FinOps Analyst"' + - description: The full record as JSON, including the permission IDs. + command: "dci get-role --output json" + - description: Only the permission IDs, for example to copy into another role. + command: "dci get-role --fields permissions --output json" + +notes: | + Preset roles are visible to every customer; a custom role is returned only to the customer + that owns it, and an unknown ID or another customer's role returns `404`. + +related: [list-roles, create-role, update-role, delete-role] diff --git a/command-docs/get-service-account-token.yaml b/command-docs/get-service-account-token.yaml new file mode 100644 index 0000000..73295c6 --- /dev/null +++ b/command-docs/get-service-account-token.yaml @@ -0,0 +1,30 @@ +command: get-service-account-token + +arguments: + service-account-id: >- + Service account ID or name as shown by `dci list-service-accounts`. Names resolve (exact, + unique substring, or close typo); pass `--id` to force a literal ID. + id: >- + API token ID, as shown by `dci list-service-account-tokens` (the `id` field). Tokens are + not resolved by name; pass the ID. + +examples: + - description: Show one token's state, expiry and last use. + command: "dci get-service-account-token " + - description: The full record as JSON. + command: "dci get-service-account-token --output json" + - description: Only when the token expires and was last used. + command: "dci get-service-account-token --fields expiresTime,lastUsedTime --output json" + +notes: | + The token secret (`accessToken`) is not included; it is shown only once, by `dci + create-service-account-token`. Requires the `serviceAccountViewer` permission. + +related: + [ + list-service-account-tokens, + create-service-account-token, + update-service-account-token, + delete-service-account-token, + get-service-account, + ] diff --git a/command-docs/get-service-account.yaml b/command-docs/get-service-account.yaml new file mode 100644 index 0000000..a4a401f --- /dev/null +++ b/command-docs/get-service-account.yaml @@ -0,0 +1,20 @@ +command: get-service-account + +arguments: + id: >- + Service account ID or name as shown by `dci list-service-accounts`. Names resolve (exact, + unique substring, or close typo); pass `--id` to force a literal ID. + +examples: + - description: Show one service account and its permissions, by name. + command: "dci get-service-account terraform-ci" + - description: The full record as JSON, including the `etag` that update and delete take as `--if-match`. + command: "dci get-service-account --output json" + - description: Only the current ETag. + command: "dci get-service-account --fields etag --output json" + +notes: | + Requires the `serviceAccountViewer` permission. An ID that belongs to another customer + returns `404`. + +related: [list-service-accounts, update-service-account, delete-service-account, list-service-account-tokens] diff --git a/command-docs/get-signup-request.yaml b/command-docs/get-signup-request.yaml new file mode 100644 index 0000000..97c8576 --- /dev/null +++ b/command-docs/get-signup-request.yaml @@ -0,0 +1,22 @@ +command: get-signup-request + +arguments: + signup-request-id: >- + Signup request ID (sr_ prefix), the `id` returned by `dci create-signup-request`. + +examples: + - description: Check where a signup request stands. + command: "dci get-signup-request " + - description: Just the status, to poll from a script. + command: "dci get-signup-request --fields status,pollAfterSeconds --output json" + - description: Read the new customer ID and sign-in link once the request is completed. + command: "dci get-signup-request --fields status,customerId,consoleUrl,signInUrl" + +notes: | + `status` moves from `pending_consent` through `consented` and `provisioning` to `completed`, or ends + as `rejected`, `expired` or `failed`. While the request is not finished, poll at the returned + `pollAfterSeconds` cadence. A completed request carries `customerId`, `consoleUrl` and `signInUrl`. + The response never includes the admin's email or the verification code. No authentication is needed; + an unknown ID returns `404`. + +related: [create-signup-request, verify-signup-request, resend-signup-verification, create-signup-session] diff --git a/command-docs/get-widget.yaml b/command-docs/get-widget.yaml new file mode 100644 index 0000000..2ed2b99 --- /dev/null +++ b/command-docs/get-widget.yaml @@ -0,0 +1,25 @@ +command: get-widget + +arguments: + widget-id: >- + Widget alias or customer-specific widget ID as shown by `dci list-widgets`. The aliases + `current-month-cloud-spend` and `current-month-cloud-forecast` give the current month's + accumulated spend and its forecast. + +examples: + - description: Cloud spend accumulated so far this calendar month. + command: "dci get-widget current-month-cloud-spend" + - description: Forecast of total cloud spend for the current calendar month. + command: "dci get-widget current-month-cloud-forecast" + - description: Read the amount from a script. + command: "dci get-widget current-month-cloud-spend --output json | jq -r .result.monetaryMetric.value.amount" + +notes: | + This returns the latest precomputed cached result (`generateTime` says when it was computed); it does + not recompute the widget. `amount` is a decimal string and `currency` an ISO 4217 code, and + `period.endTime` is exclusive. `monthToMonthGrowthPercentage` and `monthToMonthGrowthAmount` are + both `null` when there is no comparable prior-period value. A `404` means the widget is unknown, no + cached result is available yet, or the customer has no billing data; `503` means the last background + computation failed and is safe to retry later. + +related: [list-widgets] diff --git a/command-docs/import-datahub-provider-records.yaml b/command-docs/import-datahub-provider-records.yaml new file mode 100644 index 0000000..1897332 --- /dev/null +++ b/command-docs/import-datahub-provider-records.yaml @@ -0,0 +1,44 @@ +command: import-datahub-provider-records + +examples: + - description: Import one day of provider-native records from a JSON file (the usual way, since `records` is an array of objects). + command: "dci import-datahub-provider-records < records.json" + output: | + # records.json + {"provider": "Anthropic Team", + "schemaTemplate": "anthropic-spend-report@1", + "periodStart": "2026-09-10", + "periodEnd": "2026-09-10", + "records": [ + {"user_email": "user@example.com", "account_uuid": "", + "product": "Claude Code", "model": "claude-sonnet-4-6", + "total_requests": 1, "total_prompt_tokens": 100, "total_completion_tokens": 20, + "total_net_spend_usd": "1.20", "total_gross_spend_usd": "1.50", + "total_uncached_input_tokens": 60, "total_cache_read_tokens": 20, + "total_cache_write_5m_tokens": 10, "total_cache_write_1h_tokens": 10, + "total_web_search_count": 0}]} + - description: Re-import a period, replacing the batch already loaded for it. + command: "dci import-datahub-provider-records replace: true < records.json" + - description: Check the result in a script. + command: "dci import-datahub-provider-records < records.json --output json | jq '{batch, ingestedRows, generatedEvents}'" + output: "The response reports `batch`, `ingestedRows`, `sourceRecords`, `generatedEvents` and any `replacedBatches`." + +notes: | + `provider`, `schemaTemplate`, `periodStart`, `periodEnd` and `records` are required. `provider` is + the name of an existing dataset (`dci list-datahub-datasets`). Today the only supported + `schemaTemplate` is `anthropic-spend-report@1`; each record uses that template's CSV column + names, and decimals may be strings or numbers. Records are validated, normalized and booked on + `periodEnd` exactly like a CSV upload, and `replace` has the same meaning as for + `dci ingest-datahub-events-csv`. Data can take up to 15 minutes to appear in the DoiT console. + A `409` means the period overlaps an active batch (upload without `replace`), the template does + not match the dataset, `replace` would remove data outside the period, or an overlapping batch is + still processing. + +related: + [ + ingest-datahub-events-csv, + ingest-datahub-events, + create-datahub-dataset, + list-datahub-datasets, + delete-datahub-events-by-filter, + ] diff --git a/command-docs/list-alert-slack-channels.yaml b/command-docs/list-alert-slack-channels.yaml new file mode 100644 index 0000000..8a0cf8f --- /dev/null +++ b/command-docs/list-alert-slack-channels.yaml @@ -0,0 +1,22 @@ +command: list-alert-slack-channels + +examples: + - description: The Slack channels you can send alert notifications to, with the workspace connection status. + command: "dci list-alert-slack-channels" + - description: Find a channel by part of its name (case-insensitive). + command: "dci list-alert-slack-channels --name-contains finops" + - description: Every page as JSON, to copy a channel's `id` and `workspace` into an alert's `recipientsSlackChannels`. + command: "dci list-alert-slack-channels --all --output json" + - description: Page through a long list manually, 100 channels at a time. + command: "dci list-alert-slack-channels --max-results 100 --page-token " + +notes: | + The response is an object: `items` holds the channels (each with `id`, `name`, `type` of `public` + or `private`, and `workspace` or `shared`), and `workspaceStatus` reports the integration + (`ok`, `inactive`, `missing_private_scope`, or `none` when no usable workspace was found, in + which case a shared channel may still be available). `maxResults` ranges from 1 to 500 and + defaults to 50. User credentials also see the private channels they can view; service accounts + get public and shared channels only. When paging with `--page-token`, keep `--name-contains` + unchanged. A `503` means Slack discovery is temporarily unavailable; retry later. + +related: [create-alert, update-alert, get-alert, list-alerts, delete-alert] diff --git a/command-docs/list-commitment-policies.yaml b/command-docs/list-commitment-policies.yaml new file mode 100644 index 0000000..f3e007a --- /dev/null +++ b/command-docs/list-commitment-policies.yaml @@ -0,0 +1,20 @@ +command: list-commitment-policies + +examples: + - description: Every commitment policy available to your account, built-in policies first. + command: "dci list-commitment-policies" + - description: Compare the policies by target coverage and laddering. + command: "dci list-commitment-policies --fields id,name,targetCoverage,lookbackDays,ladderStepPercent,ladderIntervalDays" + - description: Everything as JSON, for scripts. + command: "dci list-commitment-policies --output json" + - description: Fetch every page when you have many custom policies. + command: "dci list-commitment-policies --all --output json" + +notes: | + The three built-in policies (`conservative`, `balanced`, `max_savings`) come first, ordered from least + to most aggressive target coverage, followed by your custom policies in creation order. One catalog + is shared by AWS and GCP. Percentages are `1` to `100`, unlike the 0 to 1 fractions on + recommendations and inventory. This command is read-only: custom policies are created, edited and + deleted in the DoiT Console on the Commitment Policies page. + +related: [get-commitment-policy] diff --git a/command-docs/list-customer-group-users.yaml b/command-docs/list-customer-group-users.yaml new file mode 100644 index 0000000..b7e306e --- /dev/null +++ b/command-docs/list-customer-group-users.yaml @@ -0,0 +1,20 @@ +command: list-customer-group-users + +arguments: + customer-group-id: >- + Customer group ID as shown by `dci list-customer-groups` (the `id` field). + +examples: + - description: The users assigned to a customer group. + command: "dci list-customer-group-users " + - description: The response as JSON, for scripts. + command: "dci list-customer-group-users --output json" + - description: Only the user IDs. + command: "dci list-customer-group-users --output json | jq -r '.users[].userId'" + +notes: | + Users come back sorted by user ID, as `userId` entries. Requires the users-manager permission. + To change who is assigned, use `dci assign-customer-group-user`. + +related: + [get-customer-group, list-customer-groups, assign-customer-group-user, create-customer-group, delete-customer-group] diff --git a/command-docs/list-service-account-tokens.yaml b/command-docs/list-service-account-tokens.yaml new file mode 100644 index 0000000..669e92b --- /dev/null +++ b/command-docs/list-service-account-tokens.yaml @@ -0,0 +1,29 @@ +command: list-service-account-tokens + +arguments: + service-account-id: >- + Service account ID or name as shown by `dci list-service-accounts`. Names resolve (exact, + unique substring, or close typo); pass `--id` to force a literal ID. + +examples: + - description: The API tokens of one service account, with state and expiry. + command: "dci list-service-account-tokens " + - description: Just the token IDs, names, state and expiry, as JSON. + command: "dci list-service-account-tokens --fields id,name,state,expiresTime --output json" + - description: Find tokens that are due to expire (compare `expiresTime` rather than trusting `state`). + command: "dci list-service-account-tokens --fields name,state,expiresTime,lastUsedTime" + +notes: | + A service account has at most 10 non-deleted tokens, all returned in one response. The + token secret is never shown here; it is returned once, by `dci create-service-account-token`. + `state` is the stored state, not a liveness signal: an expired token keeps its stored + `active` state, so check `expiresTime`. Requires the `serviceAccountViewer` permission. + +related: + [ + create-service-account-token, + get-service-account-token, + update-service-account-token, + delete-service-account-token, + get-service-account, + ] diff --git a/command-docs/list-service-accounts.yaml b/command-docs/list-service-accounts.yaml new file mode 100644 index 0000000..005d065 --- /dev/null +++ b/command-docs/list-service-accounts.yaml @@ -0,0 +1,23 @@ +command: list-service-accounts + +examples: + - description: The service accounts your organization owns, with their permissions. + command: "dci list-service-accounts" + - description: Just the IDs and names, to pick a ``. + command: "dci list-service-accounts --fields id,name --output json" + - description: Everything as JSON, for scripts. + command: "dci list-service-accounts --output json" + +notes: | + A service account is a non-human identity; its API tokens authenticate with exactly the + permissions listed on the account. Requires the `serviceAccountViewer` permission. The whole + list comes back in one response, in no guaranteed order, so there is no paging. + +related: + [ + get-service-account, + create-service-account, + update-service-account, + delete-service-account, + list-service-account-tokens, + ] diff --git a/command-docs/list-shared-payer-account-mappings.yaml b/command-docs/list-shared-payer-account-mappings.yaml new file mode 100644 index 0000000..b78347d --- /dev/null +++ b/command-docs/list-shared-payer-account-mappings.yaml @@ -0,0 +1,24 @@ +command: list-shared-payer-account-mappings + +arguments: + customer-id: >- + ID of the reseller customer your credentials belong to — the same ID that appears in the Console URL + of your account. It must match the customer resolved from the bearer token; a token scoped + to a different customer gets `403`. + +examples: + - description: Every AWS account under the reseller's shared payers and the customer it is currently mapped to. + command: "dci list-shared-payer-account-mappings " + - description: Only the accounts under one management (payer) account. + command: "dci list-shared-payer-account-mappings --management-account " + - description: The asset IDs and mapped customers, for picking an account to reassign. + command: "dci list-shared-payer-account-mappings --fields assetId,accountId,accountName,customerId,customerName" + +notes: | + When an account's `customerId` equals the `` you passed (the reseller itself), the + account has not yet been reassigned to an end customer. Each payer's own management account is + listed alongside its member accounts. Pass the `assetId` to `dci reassign-shared-payer-account`. + Requires the `SharedPayersAdmin` permission and DoiT API access (`platform:externalApi`); user API + tokens must include the permission in their scope. + +related: [list-shared-payers, list-shared-payer-management-accounts, reassign-shared-payer-account] diff --git a/command-docs/list-shared-payer-management-accounts.yaml b/command-docs/list-shared-payer-management-accounts.yaml new file mode 100644 index 0000000..f07965f --- /dev/null +++ b/command-docs/list-shared-payer-management-accounts.yaml @@ -0,0 +1,20 @@ +command: list-shared-payer-management-accounts + +arguments: + customer-id: >- + ID of the reseller customer your credentials belong to — the same ID that appears in the Console URL + of your account. It must match the customer resolved from the bearer token; a token scoped + to a different customer gets `403`. + +examples: + - description: The reseller's shared-payer management accounts that have finished onboarding. + command: "dci list-shared-payer-management-accounts " + - description: As JSON, to pick a payer ID for `--management-account`. + command: "dci list-shared-payer-management-accounts --output json" + +notes: | + Only payers that have completed onboarding are listed; use `dci list-shared-payers` to see + payers that are still onboarding. Requires the `SharedPayersAdmin` permission and DoiT API access + (`platform:externalApi`); user API tokens must include the permission in their scope. + +related: [list-shared-payers, list-shared-payer-account-mappings, reassign-shared-payer-account] diff --git a/command-docs/list-shared-payers.yaml b/command-docs/list-shared-payers.yaml new file mode 100644 index 0000000..bd7021c --- /dev/null +++ b/command-docs/list-shared-payers.yaml @@ -0,0 +1,24 @@ +command: list-shared-payers + +arguments: + customer-id: >- + ID of the reseller customer your credentials belong to — the same ID that appears in the Console URL + of your account. It must match the customer resolved from the bearer token; a token scoped + to a different customer gets `403`. + +examples: + - description: Every shared payer linked to the reseller, with how many of its accounts are already mapped to an end customer. + command: "dci list-shared-payers " + - description: Just the onboarding and mapping progress per payer. + command: "dci list-shared-payers --fields payerId,payerName,mappedAssets,totalAssets,completed" + - description: Everything as JSON, for scripts. + command: "dci list-shared-payers --output json" + +notes: | + The list includes payers that are still onboarding (`completed: false`); those have no accounts yet. + `linkedAccounts` counts the payer's own management account as well as its member accounts, and + `mappedAssets` counts the accounts already reassigned to an end customer. Requires the + `SharedPayersAdmin` permission and DoiT API access (`platform:externalApi`); user API tokens must + include the permission in their scope. + +related: [list-shared-payer-account-mappings, list-shared-payer-management-accounts, reassign-shared-payer-account] diff --git a/command-docs/list-widgets.yaml b/command-docs/list-widgets.yaml new file mode 100644 index 0000000..2253a9c --- /dev/null +++ b/command-docs/list-widgets.yaml @@ -0,0 +1,16 @@ +command: list-widgets + +examples: + - description: The catalogue of preset widgets you can read, with their IDs and stable aliases. + command: "dci list-widgets" + - description: Just the aliases and names. + command: "dci list-widgets --fields alias,name,description --output json" + +notes: | + Each entry has a customer-specific `id` and a stable `alias`; either can be passed to + `dci get-widget`. An `id` can vary by customer or service tier, while an `alias` stays the same. + The whole catalogue comes back in one response, so there is no paging. A `403` means the caller or + the selected customer is not authorized or entitled to use this API. If your credential can act on + more than one customer, select one with `--x-tenant-id `. + +related: [get-widget] diff --git a/command-docs/reassign-shared-payer-account.yaml b/command-docs/reassign-shared-payer-account.yaml new file mode 100644 index 0000000..86f82ed --- /dev/null +++ b/command-docs/reassign-shared-payer-account.yaml @@ -0,0 +1,31 @@ +command: reassign-shared-payer-account + +arguments: + customer-id: >- + ID of the reseller customer your credentials belong to — the same ID that appears in the Console URL + of your account. It must match the customer resolved from the bearer token; a token scoped + to a different customer gets `403`. + asset-id: >- + Asset ID of the AWS account to reassign, as shown by `dci list-shared-payer-account-mappings` + (the `assetId` field). + +examples: + - description: Reassign an AWS account to one of your end customers. + command: "dci reassign-shared-payer-account customerId: " + output: Returns the `assetId` and the `customerId` the account was reassigned to. + - description: Hand the account back to the reseller itself. + command: "dci reassign-shared-payer-account customerId: " + - description: Reassign it with the body read from a file. + command: "dci reassign-shared-payer-account < reassign.json" + output: | + # reassign.json + {"customerId": ""} + +notes: | + The target `customerId` is required and must be the reseller itself or a T3 end customer within its + hierarchy. The account can be a member account or the payer's own management account. Verify the + result with `dci list-shared-payer-account-mappings `. Requires the `SharedPayersAdmin` + permission and DoiT API access (`platform:externalApi`); user API tokens must include the + permission in their scope. + +related: [list-shared-payer-account-mappings, list-shared-payers, list-shared-payer-management-accounts] diff --git a/command-docs/resend-signup-verification.yaml b/command-docs/resend-signup-verification.yaml new file mode 100644 index 0000000..bcc14d8 --- /dev/null +++ b/command-docs/resend-signup-verification.yaml @@ -0,0 +1,21 @@ +command: resend-signup-verification + +arguments: + signup-request-id: >- + Signup request ID (sr_ prefix), the `id` returned by `dci create-signup-request`. + +examples: + - description: Email the admin a fresh 6-digit verification code. + command: "dci resend-signup-verification " + output: >- + Returns the signup request; `verification.sendsRemaining` tells how many resends are left. + - description: Read how many resends remain, for a script. + command: "dci resend-signup-verification --fields verification --output json" + +notes: | + At most three codes are sent per request, at least 60 seconds apart. Resending too soon returns + `429` (`verification_resend_too_soon`, retry later); once the limit is reached the request is + locked (`verification_locked`). A request that is not awaiting verification returns `409`. + No authentication is needed. + +related: [create-signup-request, verify-signup-request, get-signup-request, create-signup-session] diff --git a/command-docs/stop-cloudflow-flow.yaml b/command-docs/stop-cloudflow-flow.yaml new file mode 100644 index 0000000..c805748 --- /dev/null +++ b/command-docs/stop-cloudflow-flow.yaml @@ -0,0 +1,23 @@ +command: stop-cloudflow-flow + +arguments: + flow-id: >- + ID of the flow whose in-progress run should be stopped — the `id` column of `dci list-cloudflows`. + No run ID is needed. + +examples: + - description: Stop the run currently in progress for a flow. + command: "dci stop-cloudflow-flow " + output: The run as it stands after stopping, with its `status`. + - description: Stop it and print only the resulting status. + command: "dci stop-cloudflow-flow --output json | jq -r .status" + - description: Stop it and print the run ID, to look it up afterwards with `dci get-cloudflow-flow-run`. + command: "dci stop-cloudflow-flow --output json | jq -r .id" + +notes: | + A flow can have only one run active at a time, so the run is identified from the flow alone. + The API returns `409` when the flow has no run in progress, including a run that reached a + terminal state between your request and the stop attempt. + +related: + [trigger-cloudflow-flow, list-cloudflow-flow-runs, get-cloudflow-flow-run, list-cloudflows, test-run-cloudflow-flow] diff --git a/command-docs/trigger-cloudflow-flow.yaml b/command-docs/trigger-cloudflow-flow.yaml new file mode 100644 index 0000000..61aad23 --- /dev/null +++ b/command-docs/trigger-cloudflow-flow.yaml @@ -0,0 +1,37 @@ +command: trigger-cloudflow-flow + +arguments: + flow-id: >- + ID of a published flow whose first node is a webhook, scheduled, or manual trigger — the `id` + column of `dci list-cloudflows`. + +examples: + - description: Start a run of a flow that needs no input. + command: "dci trigger-cloudflow-flow " + output: The run summary, with `status` always `pending` because it is a snapshot taken at dispatch. + - description: Start a run and pass a payload to the trigger node. + command: "dci trigger-cloudflow-flow event: deploy, environment: production" + - description: Send a longer payload from a file. + command: "dci trigger-cloudflow-flow < payload.json" + output: | + # payload.json — any JSON object; it is forwarded to the trigger node + {"event": "deploy", "environment": "production", "service": "checkout"} + - description: Start a run, then follow it using the run ID from the response. + command: "dci trigger-cloudflow-flow --output json | jq -r .id" + output: "Pass the ID to `dci get-cloudflow-flow-run ` to follow its progress." + +notes: | + The flow must be published; a draft is rejected with `422` (`flow_not_published`), as is a flow + whose first node is not a startable trigger (`invalid_trigger_type`). To exercise a draft, use + `dci test-run-cloudflow-flow `. A flow holds a concurrency lock while it runs, so + triggering one that is already running returns `409` with the active run in the error body. + The payload is optional; omit it for flows that need no input. + +related: + [ + trigger-cloudflow-webhook, + stop-cloudflow-flow, + test-run-cloudflow-flow, + get-cloudflow-flow-run, + list-cloudflow-flow-runs, + ] diff --git a/command-docs/update-role.yaml b/command-docs/update-role.yaml new file mode 100644 index 0000000..c5b2c07 --- /dev/null +++ b/command-docs/update-role.yaml @@ -0,0 +1,26 @@ +command: update-role + +arguments: + id: >- + Role ID or name as shown by `dci list-roles`. Names resolve (exact, unique substring, or + close typo); pass `--id` to force a literal ID. + +examples: + - description: Rename a custom role. + command: 'dci update-role "FinOps Analyst" name: "FinOps Reader"' + - description: Replace the role's permissions (the list you send is the whole new list, not an addition). + command: "dci update-role permissions: [, , ]" + - description: Change several fields from a JSON file. + command: "dci update-role < role.json" + output: | + # role.json + {"name": "FinOps Reader", "description": "Read-only access to cost reports", + "permissions": ["", ""]} + +notes: | + Send `name`, `description`, `permissions`, or any combination (at least one); fields you + leave out keep their value. `permissions` replaces the whole list and an empty list clears + it; an empty `description` clears the description. Preset roles cannot be modified (`400`), + and a new `name` must be unique among the customer's roles, preset roles included (`409`). + +related: [get-role, list-roles, create-role, delete-role] diff --git a/command-docs/update-service-account-token.yaml b/command-docs/update-service-account-token.yaml new file mode 100644 index 0000000..be44be2 --- /dev/null +++ b/command-docs/update-service-account-token.yaml @@ -0,0 +1,37 @@ +command: update-service-account-token + +arguments: + service-account-id: >- + Service account ID or name as shown by `dci list-service-accounts`. Names resolve (exact, + unique substring, or close typo); pass `--id` to force a literal ID. + id: >- + API token ID, as shown by `dci list-service-account-tokens` (the `id` field). Tokens are + not resolved by name; pass the ID. + +examples: + - description: Disable a token; it stops authenticating immediately until it is re-enabled. + command: 'dci update-service-account-token state: disabled --idempotency-key "$(uuidgen)"' + - description: Re-enable it. + command: 'dci update-service-account-token state: active --idempotency-key "$(uuidgen)"' + - description: Preview the change server-side; the response shows the token as it would look and nothing is written. + command: "dci update-service-account-token state: active --dry-run" + +notes: | + `state` accepts only `active` and `disabled`; any other value, `deleted` and `expired` + included, returns `400` (use `dci delete-service-account-token` to delete). Setting the state + a token already has succeeds and changes nothing. Re-enabling a token whose expiry has passed + returns `422`, because expiry is final: create a new token instead. Disabling an expired token + succeeds. Requires the `serviceAccountManager` permission, and the API requires an + `Idempotency-Key` on every real call. + + With `--dry-run` (the API's `dryRun=true`), a `422` means the real request would be refused + too. When you omit `--idempotency-key` under `--dry-run`, the CLI generates a throwaway one. + +related: + [ + get-service-account-token, + list-service-account-tokens, + create-service-account-token, + delete-service-account-token, + update-service-account, + ] diff --git a/command-docs/update-service-account.yaml b/command-docs/update-service-account.yaml new file mode 100644 index 0000000..c82442e --- /dev/null +++ b/command-docs/update-service-account.yaml @@ -0,0 +1,44 @@ +command: update-service-account + +arguments: + id: >- + Service account ID or name as shown by `dci list-service-accounts`. Names resolve (exact, + unique substring, or close typo); pass `--id` to force a literal ID. + +examples: + - description: Replace the permissions, passing the ETag from `dci get-service-account` (the list you send is the whole new list). + command: >- + dci update-service-account permissions: [cloudAnalyticsReadOnly] + --if-match --idempotency-key "$(uuidgen)" + - description: Preview the result server-side first; the response shows the account as it would look and nothing changes. + command: "dci update-service-account name: terraform-prod --if-match --dry-run" + - description: Clear the description. + command: >- + dci update-service-account description: "" + --if-match --idempotency-key "$(uuidgen)" + +notes: | + Send any of `name`, `description` and `permissions`; the body is a JSON Merge Patch, so + omitted or `null` fields stay unchanged. An empty string clears `description`, and + `permissions` replaces the whole list (`[]` removes every permission). Requires the + `serviceAccountManager` permission. + + The API requires `If-Match` with the current ETag, from the `etag` field of `dci + get-service-account` or of a create or update response. A stale value returns `412`: + re-read the account and retry with the new ETag. It also requires an `Idempotency-Key` + (retrying with the same key returns the stored response; keys are kept for 24 hours). + + :::info Dry run is server-side + `--dry-run` sends the request with the API's `dryRun=true` and runs the same checks as a real + update (`If-Match`, name bounds and uniqueness, permission names, caller scope). When you + omit `--idempotency-key` under `--dry-run`, the CLI generates a throwaway one. + ::: + +related: + [ + get-service-account, + list-service-accounts, + create-service-account, + delete-service-account, + list-service-account-tokens, + ] diff --git a/command-docs/verify-signup-request.yaml b/command-docs/verify-signup-request.yaml new file mode 100644 index 0000000..10f8f1a --- /dev/null +++ b/command-docs/verify-signup-request.yaml @@ -0,0 +1,24 @@ +command: verify-signup-request + +arguments: + signup-request-id: >- + Signup request ID (sr_ prefix), the `id` returned by `dci create-signup-request`. + +examples: + - description: Verify the request with the 6-digit code that was emailed to the admin. + command: 'dci verify-signup-request code: "123456"' + output: >- + The request moves to `consented` and then `completed`. The response carries the one-time + `activationToken` for `dci create-signup-session`. + - description: Capture the activation token for the next step. + command: 'dci verify-signup-request code: "123456" --output json | jq -r .activationToken' + +notes: | + Entering the code confirms ownership of the admin email, records consent and starts provisioning. + The `activationToken` is returned once, by the call that performed the verification. Five wrong + codes lock the current code (`429`, `verification_locked`); request a new one with + `dci resend-signup-verification`. An expired or wrong code returns `400` + (`verification_code_expired`, `verification_code_invalid`), and a request that is not awaiting + verification returns `409`. No authentication is needed. + +related: [create-signup-request, resend-signup-verification, get-signup-request, create-signup-session] From e6d00dfdaed15ccecec72a33843e142762ffe09d Mon Sep 17 00:00:00 2001 From: vadimsolovey Date: Thu, 1 Oct 2026 20:19:32 +0300 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20changelog=20=E2=80=94=20dci=20ai=20?= =?UTF-8?q?flag=20refusal=20in=20v2.8.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dff5a0..882a759 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,11 @@ the CLI guide. ### Fixed +- `dci ai` no longer lets the assistant turn on request logging or point the + CLI at another server. The assistant's commands refuse `-v` / + `--rsh-verbose` and `-s` / `--rsh-server`, so your credentials can never be + printed into the conversation or sent to a host the assistant picked. The + commands fail with `FLAG_NOT_ALLOWED`. - `dci --help` and `dci --help` work without a session. They used to fail with "no credentials available" when you were signed out or your cache was stale — or open a browser login just to print usage.