[WIP] User Invites

This commit is contained in:
Alex Emmet 2026-09-10 23:14:25 +02:00
commit 7164f4671d
No known key found for this signature in database
24 changed files with 2829 additions and 170 deletions

View file

@ -5,8 +5,9 @@ pub mod transport;
pub use protocol::{
ClientMessage, CommunitySummary, ComponentHealth, ComponentId, ComponentStatusResponse,
ConfigResponse, ConnectionStatus, CredentialStatus, DaemonMessage, DaemonStatusResponse,
DeploymentMode, ExitIntent, HealthStatus, HelloAck, IpcErrorCode, IpcRole, LifecycleEvent,
LifecyclePhase, LocalRequest, LocalUserState, LogEntriesResponse, LogEntry, MetricSample,
DeploymentMode, ExitIntent, HealthStatus, HelloAck, InvitationAuthority, InvitationCreated,
InvitationState, InvitationSummary, IpcErrorCode, IpcRole, LifecycleEvent, LifecyclePhase,
LocalRequest, LocalUserState, LogEntriesResponse, LogEntry, MetricSample,
OmikronStatusResponse, ReconcileAction, RequestEnvelope, ResponseEnvelope, ResponsePayload,
ResponseResult, SecretString, StartupPhase, StateSnapshot, StatusResponse, SupervisorKind,
TaskSummary, TuCredentialPreview, UpdateStatusResponse, UserDetailResponse, UserDiagnostics,
@ -15,6 +16,6 @@ pub use protocol::{
pub use transport::{MAX_MESSAGE_SIZE, read_msg, write_msg};
/// Current IPC protocol version.
pub const PROTOCOL_VERSION: u16 = 4;
pub const PROTOCOL_VERSION: u16 = 5;
/// Minimum protocol version this daemon understands.
pub const MIN_PROTOCOL_VERSION: u16 = 2;

View file

@ -45,6 +45,19 @@ pub enum LocalRequest {
GetStatus,
ListTasks,
ListUsers,
CreateInvitation {
authority: InvitationAuthority,
lifetime_seconds: u64,
password: Option<SecretString>,
label: Option<String>,
},
ListInvitations {
authority: Option<InvitationAuthority>,
},
RevokeInvitation {
authority: InvitationAuthority,
invitation_id: i64,
},
CreateUser {
username: String,
},
@ -148,6 +161,7 @@ impl LocalRequest {
Self::GetStatus
| Self::ListTasks
| Self::ListUsers
| Self::ListInvitations { .. }
| Self::GetDaemonStatus
| Self::GetOmikronStatus
| Self::ListComponents
@ -160,6 +174,8 @@ impl LocalRequest {
Self::ReconnectOmikron | Self::ReloadConfig => IpcRole::Operate,
Self::CreateUser { .. }
| Self::CreateInvitation { .. }
| Self::RevokeInvitation { .. }
| Self::InspectTuCredential { .. }
| Self::AttachUserFromTu { .. }
| Self::ReconcileUser { .. }
@ -249,6 +265,9 @@ pub enum ResponsePayload {
Status(StatusResponse),
Tasks(Vec<TaskSummary>),
Users(Vec<UserSummary>),
InvitationCreated(InvitationCreated),
Invitations(Vec<InvitationSummary>),
InvitationUpdated(InvitationSummary),
UserCreated {
user_id: i64,
username: String,
@ -327,6 +346,49 @@ pub struct CommunitySummary {
pub title: String,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum InvitationAuthority {
Omega,
Iota,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum InvitationState {
Pending,
RevocationPending,
Provisioning,
Redeemed,
Revoked,
Expired,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct InvitationCreated {
pub authority: InvitationAuthority,
pub invitation_id: i64,
pub raw_token: SecretString,
pub expires_at: i64,
pub short_url: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct InvitationSummary {
pub authority: InvitationAuthority,
pub invitation_id: i64,
pub label: Option<String>,
pub password_protected: bool,
pub created_at: i64,
pub expires_at: Option<i64>,
pub state: InvitationState,
pub redeemed_user_id: Option<i64>,
#[serde(default)]
pub local_provisioned_user_id: Option<i64>,
#[serde(default)]
pub local_provisioned_at: Option<i64>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct StatusResponse {
pub phase: String,
@ -427,6 +489,7 @@ pub enum IpcErrorCode {
Conflict,
StorageFailure,
OmikronUnavailable,
Unsupported,
UnsupportedVersion,
NotReady,
Disconnected,
@ -444,6 +507,7 @@ impl std::fmt::Display for IpcErrorCode {
Self::Conflict => "the request conflicts with current daemon state",
Self::StorageFailure => "the daemon could not access local storage",
Self::OmikronUnavailable => "Omikron is unavailable",
Self::Unsupported => "the requested operation is not implemented",
Self::UnsupportedVersion => "the client and daemon protocol versions are incompatible",
Self::NotReady => "the daemon is not ready yet",
Self::Disconnected => "the daemon connection was lost",