feat: split auth into sso/git, Planka token exchange, board discovery

Auth:
- sunbeam auth login runs SSO (Hydra OIDC) then Git (Gitea PAT)
- SSO callback auto-redirects browser to Gitea token page
- sunbeam auth sso / sunbeam auth git for individual flows
- Gitea PAT verified against API before saving

Planka:
- Token exchange via /api/access-tokens/exchange-using-token endpoint
- Board discovery via GET /api/projects
- String IDs (snowflake) handled throughout

Config:
- kubectl-style contexts: --context flag > current-context > "local"
- Removed --env flag
- Per-domain auth token storage
This commit is contained in:
2026-03-20 19:25:10 +00:00
parent ded0ab442e
commit ffc0fe917b
3 changed files with 311 additions and 87 deletions

View File

@@ -149,13 +149,25 @@ pub enum Verb {
#[derive(Subcommand, Debug)]
pub enum AuthAction {
/// Log in via browser (OAuth2 authorization code flow).
/// Log in to both SSO and Gitea.
Login {
/// Domain to authenticate against (e.g. sunbeam.pt).
#[arg(long)]
domain: Option<String>,
},
/// Log out (remove cached tokens).
/// Log in to SSO only (Hydra OIDC — for Planka, identity management).
Sso {
/// Domain to authenticate against.
#[arg(long)]
domain: Option<String>,
},
/// Log in to Gitea only (personal access token).
Git {
/// Domain to authenticate against.
#[arg(long)]
domain: Option<String>,
},
/// Log out (remove all cached tokens).
Logout,
/// Show current authentication status.
Status,
@@ -1022,11 +1034,15 @@ pub async fn dispatch() -> Result<()> {
},
Some(Verb::Auth { action }) => match action {
None => {
crate::auth::cmd_auth_status().await
}
None => crate::auth::cmd_auth_status().await,
Some(AuthAction::Login { domain }) => {
crate::auth::cmd_auth_login(domain.as_deref()).await
crate::auth::cmd_auth_login_all(domain.as_deref()).await
}
Some(AuthAction::Sso { domain }) => {
crate::auth::cmd_auth_sso_login(domain.as_deref()).await
}
Some(AuthAction::Git { domain }) => {
crate::auth::cmd_auth_git_login(domain.as_deref()).await
}
Some(AuthAction::Logout) => crate::auth::cmd_auth_logout().await,
Some(AuthAction::Status) => crate::auth::cmd_auth_status().await,