You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PR #535 added programmatic browser auth (kbagent auth login|status|logout) and, in 273d02b, kbagent auth register-projects — which registers projects an existing session can access as local aliases with kbc-session://{project_id} sentinel tokens.
None of the auth group is exposed over kbagent serve. For login that is correct and should stay that way: the flow needs a loopback callback or a human typing a device code, which does not fit a stateless REST call.
register-projects is different. With --all / --project-id / --alias ID=ALIAS it is fully non-interactive, does no browser work, and only reads auth.json plus writes config.json. It is the one piece of the group that maps cleanly onto REST.
Why it matters
kbagent http post ... is the documented way for a scheduled agent task to reach the CLI's own functionality without forking a second kbagent process tree. Today an agent running inside kbagent serve that needs a session project registered has no path: it would have to shell out, or hand-write a sentinel token into config.json, which is exactly the footgun the picker was added to remove.
src/keboola_agent_cli/server/routers/ has no auth.py. There are 30 routers; auth is absent.
AuthService is not in ServiceRegistry (server/dependencies.py) — it is only constructed in cli.py:353 and put on the Typer context. So this is not just "add a router"; the service has to be registered first.
Proposed scope
POST /auth/register-projects accepting {stack?, all?, project_ids?, aliases?}, returning the existing RegisterProjectsResult shape (status, stack_url, registered_projects[], warnings[]).
Add AuthService to ServiceRegistry.
GET /auth/projects returning ProjectCandidatesResult (the candidate list with suggested collision-free aliases), so a caller can choose ids before registering rather than guessing.
Optionally GET /auth/status, which is read-only and equally REST-shaped.
Explicitly out of scope
auth login — requires a human at a browser; must not get an endpoint.
auth logout — revokes credentials for the whole machine, not just the caller. Wants its own think about who is allowed to trigger it over HTTP before it gets an endpoint.
Acceptance criteria
The interactive picker stays CLI-only; the endpoint is selector-driven and never prompts.
No endpoint returns a token value, including the kbc-session:// sentinel. The existing result dataclasses are token-free by construction — keep that property.
SESSION_NOT_FOUND maps to a sensible HTTP status rather than a 500.
Never overwrites an existing alias; the exists / skipped statuses survive the REST boundary.
The --deny-writes / permissions policy is honoured on the serve path too (auth.register-projects is registered as a write operation).
Not a blocker for #535 — the CLI path is complete and tested. Raised because CONTRIBUTING.md's "Plugin synchronization map" lists the serve REST surface, and this is a deliberate omission rather than an oversight.
Context
PR #535 added programmatic browser auth (
kbagent auth login|status|logout) and, in 273d02b,kbagent auth register-projects— which registers projects an existing session can access as local aliases withkbc-session://{project_id}sentinel tokens.None of the
authgroup is exposed overkbagent serve. Forloginthat is correct and should stay that way: the flow needs a loopback callback or a human typing a device code, which does not fit a stateless REST call.register-projectsis different. With--all/--project-id/--alias ID=ALIASit is fully non-interactive, does no browser work, and only readsauth.jsonplus writesconfig.json. It is the one piece of the group that maps cleanly onto REST.Why it matters
kbagent http post ...is the documented way for a scheduled agent task to reach the CLI's own functionality without forking a secondkbagentprocess tree. Today an agent running insidekbagent servethat needs a session project registered has no path: it would have to shell out, or hand-write a sentinel token intoconfig.json, which is exactly the footgun the picker was added to remove.Current state (verified on 273d02b)
src/keboola_agent_cli/server/routers/has noauth.py. There are 30 routers; auth is absent.AuthServiceis not inServiceRegistry(server/dependencies.py) — it is only constructed incli.py:353and put on the Typer context. So this is not just "add a router"; the service has to be registered first.Proposed scope
POST /auth/register-projectsaccepting{stack?, all?, project_ids?, aliases?}, returning the existingRegisterProjectsResultshape (status,stack_url,registered_projects[],warnings[]).AuthServicetoServiceRegistry.GET /auth/projectsreturningProjectCandidatesResult(the candidate list with suggested collision-free aliases), so a caller can choose ids before registering rather than guessing.GET /auth/status, which is read-only and equally REST-shaped.Explicitly out of scope
auth login— requires a human at a browser; must not get an endpoint.auth logout— revokes credentials for the whole machine, not just the caller. Wants its own think about who is allowed to trigger it over HTTP before it gets an endpoint.Acceptance criteria
kbc-session://sentinel. The existing result dataclasses are token-free by construction — keep that property.SESSION_NOT_FOUNDmaps to a sensible HTTP status rather than a 500.exists/skippedstatuses survive the REST boundary.--deny-writes/permissionspolicy is honoured on the serve path too (auth.register-projectsis registered as awriteoperation).Note
Not a blocker for #535 — the CLI path is complete and tested. Raised because CONTRIBUTING.md's "Plugin synchronization map" lists the serve REST surface, and this is a deliberate omission rather than an oversight.