feat(auth): add kbagent auth pat-create/pat-revoke for CI/CD credentials - #561
Draft
Matovidlo wants to merge 1 commit into
Draft
feat(auth): add kbagent auth pat-create/pat-revoke for CI/CD credentials#561Matovidlo wants to merge 1 commit into
Matovidlo wants to merge 1 commit into
Conversation
Adds Personal Access Token (PAT) support on top of the existing browser-login session (auth login): `auth pat-create` spends an already-live session's access token to do a TOTP step-up (POST /v1/auth/sudo) then mint a scoped, long-lived kbc_pat_... token (POST /v1/auth/pat) -- the sanctioned alternative to pasting a raw Storage token into a CI secret. `auth pat-revoke` revokes one. Neither opens a browser or logs in itself; minting/revoking a PAT is an ordinary bearer-authenticated call once a session exists, so this does not relax auth login's own "requires a human at a browser" boundary -- a live TOTP code is still required and never something an agent may invent. The resulting PAT is a drop-in for KBC_TOKEN under KBAGENT_PROJECT_FROM_ENV=1 (or `project add --token`): make_client_factory now recognizes the kbc_pat_ prefix on a plain static token and routes it to Authorization: Bearer instead of X-StorageApi-Token, since the Storage API's own OpenAPI security schemes define those as distinct auth mechanisms, not interchangeable encodings of one -- confirmed against the live spec before writing this. A PAT does not rotate like a session does; replace it (pat-create again) instead of expecting a refresh. New error codes: AUTH_SUDO_REQUIRED, AUTH_MFA_INVALID.
Contributor
Author
|
@claude review |
There was a problem hiding this comment.
Pull request overview
This PR adds Personal Access Token (PAT) support to kbagent as a CI/CD-friendly credential option, building on the existing browser-login session flow by performing a TOTP sudo step-up and then minting/revoking PATs via the auth service. It also extends client credential dispatch so kbc_pat_... tokens are treated as Bearer auth (not Storage-token header auth), allowing PATs to work as a drop-in for KBC_TOKEN.
Changes:
- Add new CLI commands
kbagent auth pat-createandkbagent auth pat-revoke, including permission classification and human/JSON output handling. - Add auth-layer support for sudo step-up + PAT create/revoke (client methods + wire models) and service methods that orchestrate “sudo then mint”.
- Extend
make_client_factoryto routekbc_pat_...tokens toAuthorization: Bearer, and bump version/docs/changelog accordingly.
Reviewed changes
Copilot reviewed 22 out of 23 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| uv.lock | Bumps locked version metadata to 0.81.0. |
| pyproject.toml | Bumps project version to 0.81.0. |
| plugins/kbagent/.claude-plugin/plugin.json | Syncs plugin version to 0.81.0. |
| .claude-plugin/marketplace.json | Syncs marketplace version to 0.81.0. |
| src/keboola_agent_cli/constants.py | Adds PAT token prefix constant and auth endpoint constants. |
| src/keboola_agent_cli/errors.py | Adds new error codes for sudo/PAT flows and categorization. |
| src/keboola_agent_cli/services/base.py | Adds PAT-prefix detection and Bearer-auth dispatch in make_client_factory. |
| src/keboola_agent_cli/services/auth_service.py | Implements service-level create/revoke PAT flows and CLI result dataclasses. |
| src/keboola_agent_cli/auth/auth_client.py | Adds API client methods for sudo_totp, create_pat, and revoke_pat. |
| src/keboola_agent_cli/auth/models.py | Adds wire models for sudo + PAT create responses. |
| src/keboola_agent_cli/auth/token_provider.py | Adds StaticBearerAuth for non-rotating PAT Bearer auth. |
| src/keboola_agent_cli/commands/auth.py | Wires new auth pat-create / auth pat-revoke commands and output formatters. |
| src/keboola_agent_cli/commands/context.py | Updates embedded CLI context/help text to include PAT commands and guidance. |
| src/keboola_agent_cli/permissions.py | Registers PAT commands as admin operations. |
| src/keboola_agent_cli/changelog.py | Adds 0.81.0 changelog entries describing PAT support. |
| docs/error-codes.md | Documents new error codes. |
| CLAUDE.md | Updates the “All CLI Commands” section for the new auth commands and PAT behavior. |
| plugins/kbagent/skills/kbagent/SKILL.md | Updates skill decision table entries for PAT commands. |
| plugins/kbagent/skills/kbagent/references/commands-reference.md | Adds reference documentation for PAT create/revoke commands. |
| tests/test_cli_auth.py | Adds CLI tests for new auth commands, JSON/TTY behavior, and permission gating. |
| tests/test_auth_client.py | Adds unit tests for sudo and PAT client calls. |
| tests/test_auth_service.py | Adds service-layer tests for sudo-before-create ordering and revoke behavior. |
| tests/test_base_service.py | Adds tests ensuring PAT tokens dispatch via Bearer auth and static tokens remain unchanged. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| formatter = get_formatter(ctx) | ||
| check_cli_operation(ctx, "auth.pat-create") | ||
| if totp_code is None: | ||
| if formatter.json_mode or not _is_stdout_tty(): |
| error_code=ErrorCode.INVALID_ARGUMENT, | ||
| ) | ||
| raise typer.Exit(code=2) | ||
| totp_code = typer.prompt("Current TOTP code") |
| @auth_app.command("pat-revoke") | ||
| def auth_pat_revoke( | ||
| ctx: typer.Context, | ||
| pat_id: str = typer.Argument(..., help="PAT id (UUID) to revoke"), |
Matovidlo
added a commit
that referenced
this pull request
Aug 7, 2026
Depends on #561 (kbagent auth pat-create/pat-revoke, v0.81.0). Updates the migration skill to recommend minting a scoped Personal Access Token (kbagent auth pat-create --project-id <id>) for each project's KBC_TOKEN_<ALIAS> secret instead of pasting a raw Storage token from the Keboola UI -- a PAT is scoped to one project, has a controllable expiry (--ttl-days), and revokes independently of the account (kbagent auth pat-revoke) without touching anything else that account can do. No change to the generated GitHub Actions YAML itself: a kbc_pat_... value is a drop-in for KBC_TOKEN under KBAGENT_PROJECT_FROM_ENV=1 (kbagent detects the prefix and sends it as Authorization: Bearer automatically), so this is purely a change in how the operator obtains the secret's value. The raw Storage token path remains documented as the fallback for stacks/accounts that can't complete auth login + TOTP step-up.
Matovidlo
force-pushed
the
martinvasko-kbagent-ci-mfa-token-setup
branch
from
August 7, 2026 10:45
ccd61f3 to
8ab16fc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
kbagent auth pat-create --name NAME [--totp-code CODE] [--read-only] [--ttl-days N] [--project-id ID ...]andkbagent auth pat-revoke PAT_ID [--yes], built on top of the existing browser-login session from DMD-1825 feat(auth): browser login via PKCE + device authorization (programmatic auth) #535.pat-createspends an already-liveauth loginsession's access token to do a TOTP step-up (POST /v1/auth/sudo) and then mint a scoped, long-livedkbc_pat_...token (POST /v1/auth/pat). It never opens a browser and never logs in itself -- it does not relaxauth login's "requires a human at a browser" boundary; a live TOTP code is still required (interactive prompt, or--totp-code, and REQUIRED under--json/non-TTY -- there is no unattended path to mint one).--project-id(repeatable) scopes the PAT to an explicit allow-list instead of every accessible project, for a one-project-per-CI-secret setup.KBC_TOKENunderKBAGENT_PROJECT_FROM_ENV=1(orproject add --token):make_client_factorynow recognizes thekbc_pat_prefix on a plain static token and routes it toAuthorization: Bearerinstead ofX-StorageApi-Token-- confirmed against the Storage API's own live OpenAPI security schemes that these are genuinely distinct auth mechanisms, not interchangeable encodings of one, before writing any of this.pat-revokeneeds no step-up and is idempotent.AUTH_SUDO_REQUIRED,AUTH_MFA_INVALID.Follow-up in #563 (stacked on this branch): a
--webauthnstep-up alternative to--totp-code, opening a browser for a passkey ceremony instead of a typed code. Split out because it depends on a not-yet-confirmed server-hosted ceremony page/redirect contract that needs live-stack testing before it's ready for review; this PR (TOTP-only) has no such dependency and is ready now.Why
CI/CD pipelines need a long-lived, non-interactive credential, but the only two options today are a raw Storage API token (no scoping, no easy revoke story tied to a person) or the browser-login session from #535 (explicitly human-only, never usable in CI). The Connection Auth Service already has first-class PAT support (
/v1/auth/pat,/v1/auth/sudo) purpose-built for exactly this "authenticate once interactively, mint a durable scoped credential, use it non-interactively forever after" pattern -- this PR wires kbagent up to it. Thekbagent-cicd-migrationskill (#402) already recommends this command for CI secrets.Change type
Feature -- new CLI commands + a small credential-dispatch extension. No breaking changes; version bump 0.80.0 -> 0.81.0.
Impact analysis
services/base.py:make_client_factorygains one new branch (PAT-prefix detection) before the existing session-sentinel branch; a plain static token or session-sentinel token takes the byte-identical path as before.auth/auth_client.py/auth/models.py/auth/token_provider.py: three new client methods (sudo_totp,create_pat,revoke_pat), three new wire models (SudoResult,PatItem,PatCreateResult), one new lightweightStaticBearerAuth(no refresh/retry -- a PAT doesn't rotate).services/auth_service.py,commands/auth.py,permissions.py: two new commands, classifiedadminrisk (same class asproject add's pasted static token /project remove).Test plan
test_auth_client.py(sudo/create/revoke against a mocked HTTP transport, including the 404 feature-flag mapping and the sudo-not-active 403),test_auth_service.py(sudo-before-create ordering, sudo-failure aborts before create, no-session error, ttl/project-id forwarding),test_cli_auth.py(argument wiring,--json-without---totp-codefails fast, admin permission-class gating, revoke confirm/abort),test_base_service.py(PAT-prefix dispatch toAuthorization: Bearer, plain static token unaffected).make checkgreen end-to-end: ruff, ty (0 new diagnostics vs. main),make skill-check/command-sync-check/changelog-check/check-error-codes/check-sentinel-guards/loc-check, full test suite (5436 passed, 11 skipped, 0 failed).Deployment
Merge & automatic deploy. No migration.
Rollback plan
Revert of this PR.