Skip to content

Add a kizen service-accounts command group - #101

Merged
2 commits merged into
mainfrom
feat/service-accounts-command-group
Oct 27, 2026
Merged

2 commits merged into
mainfrom
feat/service-accounts-command-group

Conversation

@jbedient-kizen

Copy link
Copy Markdown
Contributor

Problem

A Call LLM step runs its MCP tools as a service account, and builds had no way to make one without clicking through Settings.

Solution

A new kizen service-accounts group: list, get, create, update, delete and history for integration accounts, with permission groups by name through --group/-g, resolved the way roles does. It follows the roles surface module for module, and writes go through the usual mutation path, so --dry-run and --yes behave as everywhere else. kizen docs show service-account documents it.

Kizen returns the new account's API key in full on create, under an api_key object the schema doesn't declare. The API wrapper deletes it before anything else sees the response, so no plan, result, table, log or --json output can contain it. Reads show only Kizen's own preview and the key count.

create takes no --api-name, since Kizen derives it from the name, and a name or derived api_name that already exists is refused at plan time (Kizen answers a duplicate with a 500). A rename sends the current api_name with the new name, because Kizen re-derives it from any PATCH that includes name. update and delete refuse automation and plugin accounts, which Kizen or a plugin manages.

Testing

Local checks after merging main: lint, format, typecheck, pytest (2868 passed, 4 skipped, 1 xfailed) and the CLI-tree diff, passed: lint format typecheck test extra_checks. A sentinel key in a mocked create response is asserted absent from every output path.

Live on a test tenant, with a scratch permission group and account: create -g gave the predicted api_name and said a key was issued and not shown; list and get showed the group, one key and the preview; a rename kept the api_name; --clear-groups left it disabled; the refusals for an automation account, a plugin account and a duplicate name each exit 1 at --dry-run; delete removed it (404 after). No key-shaped string sharing the preview's prefix appears in the run log. Account and group counts were the same before and after. The drift tier wasn't run.

Design notes / tradeoffs

Rejected: commands to reveal or rotate keys. run_tools_as references the account by id and never needs a key, and keys shouldn't reach logs. Rotation, if wanted later, belongs in a separate command that writes the key to a mode-0600 file. Rejected too: a spec file, since the write body has three keys and flags cover them, as for roles.

Overlaps: #100 (the mcp-servers command group) adds a second command group and touches the same shared files: the CLI command registry (cli/__init__.py), the docs lists (commands.md, reference.md, specs/README.md), scripts/cli-tree-baseline.txt, tests/drift/contracts.py, tests/drift/schema_snapshot.json, tools/plans.py, CONTRIBUTING.md and CHANGELOG.md. Whichever merges second should need a small conflict fix. #96 (the loops fix) also changes the CLI-tree baseline. The merge from main also refreshes that baseline for #92's new kizen upgrade --check help text, which main's baseline lacks; every PR in this set carries that same line.

A Call LLM step runs its MCP tools as a service account, and builds had
no way to make one without clicking through Settings. The new group
lists, creates, updates, deletes and shows the history of integration
accounts, with permission groups by name as roles takes them.

Kizen returns the new account's API key in full on create, under an
api_key object the schema doesn't declare. The API wrapper drops it
before anything else sees the response, so no plan, result, table or
--json output can contain it; reads show only Kizen's own preview.

A rename sends the current api_name with the new name, because Kizen
re-derives it from any PATCH that includes name. Update and delete
refuse automation and plugin accounts, which Kizen or a plugin manages,
and create refuses a duplicate name, which Kizen answers with a 500.
@jbedient-kizen

Copy link
Copy Markdown
Contributor Author

Included in the 0.4.0 release PR #102; merge that instead.

@sangyeT sangyeT left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the api module, read tools, planners and CLI. Good that the create response's api_key is popped inside the api layer before any plan result or --json can see it, that a rename pins the current api_name so Kizen doesn't re-derive it, and that automation/plugin accounts are refused for update and delete. Approving.

@jbedient-kizen jbedient-kizen closed this pull request by merging all changes into main in 39beea1 Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants