mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 07:41:27 +00:00
feat: personal access tokens with scoped bearer auth
Add cnp_ personal access tokens so the CLI, MCP server, and external agents authenticate without a browser session — the agent-first spine from ROADMAP2 phase A. Modeled on agent_auth_tokens: raw token shown once, only SHA-256 hash stored. - user_tokens table (goose migration + sqlc), name/prefix/scope/expiry, owner-scoped revoke, last_used_at stamping - middleware: cnp_ bearer resolution, read scope gates mutations with 403 SCOPE_INSUFFICIENT, non-admin scopes cap is_admin even for admin owners — a token never outranks its scope or its owner - GET/POST/DELETE /api/v1/user/tokens + OpenAPI + generated types - Settings UI: create with scope/expiry pickers, one-time token display with copy, list with last-used/expiry, confirm-revoke - docs: OPERATIONS.md section, README feature line Verified end-to-end against live Postgres: create/list/revoke, read scope blocks PUT (403), write PAT on admin owner blocked from admin routes (403), admin scope works, revoked token returns 401. Authored By: TDvorak <[email protected]>
This commit is contained in:
1 parent
f9ae5b962c
commit
e881747388
17 files changed
+1141
-30
No files matched your search
@@ -168,33 +168,39 @@ type ProjectMember struct {
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description sql.NullString `json:"description"`
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
EnvironmentID uuid.UUID `json:"environment_id"`
|
||||
ServiceType string `json:"service_type"`
|
||||
SourceType string `json:"source_type"`
|
||||
SourceUrl sql.NullString `json:"source_url"`
|
||||
ImageName sql.NullString `json:"image_name"`
|
||||
BuildCommand sql.NullString `json:"build_command"`
|
||||
StartCommand sql.NullString `json:"start_command"`
|
||||
CpuLimit sql.NullInt32 `json:"cpu_limit"`
|
||||
MemoryLimit sql.NullInt32 `json:"memory_limit"`
|
||||
PublicUrl sql.NullString `json:"public_url"`
|
||||
HealthCheckUrl sql.NullString `json:"health_check_url"`
|
||||
Status sql.NullString `json:"status"`
|
||||
CreatedAt sql.NullTime `json:"created_at"`
|
||||
UpdatedAt sql.NullTime `json:"updated_at"`
|
||||
Type sql.NullString `json:"type"`
|
||||
Image sql.NullString `json:"image"`
|
||||
Command sql.NullString `json:"command"`
|
||||
Environment sql.NullString `json:"environment"`
|
||||
GitRepo sql.NullString `json:"git_repo"`
|
||||
GitBranch sql.NullString `json:"git_branch"`
|
||||
BuildPath sql.NullString `json:"build_path"`
|
||||
Cpu sql.NullString `json:"cpu"`
|
||||
Memory sql.NullString `json:"memory"`
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description sql.NullString `json:"description"`
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
EnvironmentID uuid.UUID `json:"environment_id"`
|
||||
ServiceType string `json:"service_type"`
|
||||
SourceType string `json:"source_type"`
|
||||
SourceUrl sql.NullString `json:"source_url"`
|
||||
ImageName sql.NullString `json:"image_name"`
|
||||
BuildCommand sql.NullString `json:"build_command"`
|
||||
StartCommand sql.NullString `json:"start_command"`
|
||||
CpuLimit sql.NullInt32 `json:"cpu_limit"`
|
||||
MemoryLimit sql.NullInt32 `json:"memory_limit"`
|
||||
PublicUrl sql.NullString `json:"public_url"`
|
||||
HealthCheckUrl sql.NullString `json:"health_check_url"`
|
||||
Status sql.NullString `json:"status"`
|
||||
CreatedAt sql.NullTime `json:"created_at"`
|
||||
UpdatedAt sql.NullTime `json:"updated_at"`
|
||||
Type sql.NullString `json:"type"`
|
||||
Image sql.NullString `json:"image"`
|
||||
Command sql.NullString `json:"command"`
|
||||
Environment sql.NullString `json:"environment"`
|
||||
GitRepo sql.NullString `json:"git_repo"`
|
||||
GitBranch sql.NullString `json:"git_branch"`
|
||||
BuildPath sql.NullString `json:"build_path"`
|
||||
Cpu sql.NullString `json:"cpu"`
|
||||
Memory sql.NullString `json:"memory"`
|
||||
Replicas int32 `json:"replicas"`
|
||||
Port int32 `json:"port"`
|
||||
Domain string `json:"domain"`
|
||||
HealthcheckPath string `json:"healthcheck_path"`
|
||||
RestartPolicy string `json:"restart_policy"`
|
||||
PublishedPort int32 `json:"published_port"`
|
||||
}
|
||||
|
||||
type ServiceTemplate struct {
|
||||
@@ -211,3 +217,16 @@ type ServiceTemplate struct {
|
||||
CreatedAt sql.NullTime `json:"created_at"`
|
||||
UpdatedAt sql.NullTime `json:"updated_at"`
|
||||
}
|
||||
|
||||
type UserToken struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
Name string `json:"name"`
|
||||
KeyPrefix string `json:"key_prefix"`
|
||||
TokenHash string `json:"token_hash"`
|
||||
Scope string `json:"scope"`
|
||||
ExpiresAt sql.NullTime `json:"expires_at"`
|
||||
LastUsedAt sql.NullTime `json:"last_used_at"`
|
||||
RevokedAt sql.NullTime `json:"revoked_at"`
|
||||
CreatedAt sql.NullTime `json:"created_at"`
|
||||
}
|
||||
Reference in new issue
Block a user