package export // entities.go — v0.34.0 CS0 // // Per-entity sanitization: strips sensitive, instance-specific, or // non-portable fields before writing to the export archive. Each // Sanitize* function returns a clean map ready for JSON marshalling. import ( "switchboard-core/models" ) // ── User ───────────────────────────────────── // SanitizeUser strips password_hash (json:"-" already), vault fields, // and external_id. The User struct's json tags already exclude // password_hash, so standard marshalling is safe. We nil out a few // more fields for cross-instance portability. func SanitizeUser(u *models.User) *models.User { out := *u // shallow copy out.PasswordHash = "" out.ExternalID = nil return &out } // ── Channel ────────────────────────────────── // ExportChannel is a Channel without instance-specific provider binding. type ExportChannel struct { models.Channel ProviderConfigID *string `json:"provider_config_id,omitempty"` // always nil in export } // SanitizeChannel strips provider_config_id. func SanitizeChannel(ch *models.Channel) ExportChannel { return ExportChannel{ Channel: *ch, ProviderConfigID: nil, } } // SanitizeChannels batch-sanitizes a slice. func SanitizeChannels(chs []models.Channel) []ExportChannel { out := make([]ExportChannel, len(chs)) for i := range chs { chs[i].ProviderConfigID = nil out[i] = SanitizeChannel(&chs[i]) } return out } // ── Message ────────────────────────────────── // ExportMessage is a Message without provider_config_id. type ExportMessage struct { models.Message ProviderConfigID *string `json:"provider_config_id,omitempty"` // always nil } // SanitizeMessages strips provider_config_id from each message. func SanitizeMessages(msgs []models.Message) []ExportMessage { out := make([]ExportMessage, len(msgs)) for i := range msgs { msgs[i].ProviderConfigID = nil out[i] = ExportMessage{Message: msgs[i]} } return out } // ── Channel Model ──────────────────────────── // ExportChannelModel strips provider_config_id and persona_id. type ExportChannelModel struct { ID string `json:"id"` ChannelID string `json:"channel_id"` ModelID string `json:"model_id"` Handle string `json:"handle,omitempty"` DisplayName string `json:"display_name,omitempty"` SystemPrompt string `json:"system_prompt,omitempty"` IsDefault bool `json:"is_default"` } // SanitizeChannelModels strips instance-specific refs. func SanitizeChannelModels(cms []models.ChannelModel) []ExportChannelModel { out := make([]ExportChannelModel, len(cms)) for i, cm := range cms { out[i] = ExportChannelModel{ ID: cm.ID, ChannelID: cm.ChannelID, ModelID: cm.ModelID, Handle: cm.Handle, DisplayName: cm.DisplayName, SystemPrompt: cm.SystemPrompt, IsDefault: cm.IsDefault, } } return out } // ── User Model Settings ────────────────────── // ExportUserModelSetting strips provider_config_id. type ExportUserModelSetting struct { models.UserModelSetting ProviderConfigID *string `json:"provider_config_id,omitempty"` // always nil } // SanitizeUserModelSettings strips instance-specific provider binding. func SanitizeUserModelSettings(ums []models.UserModelSetting) []ExportUserModelSetting { out := make([]ExportUserModelSetting, len(ums)) for i := range ums { ums[i].ProviderConfigID = nil out[i] = ExportUserModelSetting{UserModelSetting: ums[i]} } return out } // ── Usage Entry ────────────────────────────── // ExportUsageEntry strips provider_config_id and routing_decision. type ExportUsageEntry struct { ID string `json:"id"` ChannelID *string `json:"channel_id,omitempty"` UserID string `json:"user_id"` ModelID string `json:"model_id"` Role *string `json:"role,omitempty"` PromptTokens int `json:"prompt_tokens"` CompletionTokens int `json:"completion_tokens"` CacheCreationTokens int `json:"cache_creation_tokens"` CacheReadTokens int `json:"cache_read_tokens"` CostInput *float64 `json:"cost_input,omitempty"` CostOutput *float64 `json:"cost_output,omitempty"` CreatedAt string `json:"created_at"` } // SanitizeUsageEntries strips instance-specific fields. func SanitizeUsageEntries(ues []models.UsageEntry) []ExportUsageEntry { out := make([]ExportUsageEntry, len(ues)) for i, ue := range ues { out[i] = ExportUsageEntry{ ID: ue.ID, ChannelID: ue.ChannelID, UserID: ue.UserID, ModelID: ue.ModelID, Role: ue.Role, PromptTokens: ue.PromptTokens, CompletionTokens: ue.CompletionTokens, CacheCreationTokens: ue.CacheCreationTokens, CacheReadTokens: ue.CacheReadTokens, CostInput: ue.CostInput, CostOutput: ue.CostOutput, CreatedAt: ue.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), } } return out } // ── Workspace ──────────────────────────────── // ExportWorkspace strips root_path (json:"-" already) and git credentials. type ExportWorkspace struct { models.Workspace GitCredentialID *string `json:"git_credential_id,omitempty"` // always nil } // SanitizeWorkspaces strips git credential refs. func SanitizeWorkspaces(ws []models.Workspace) []ExportWorkspace { out := make([]ExportWorkspace, len(ws)) for i := range ws { ws[i].GitCredentialID = nil ws[i].GitLastSync = nil out[i] = ExportWorkspace{Workspace: ws[i]} } return out } // ── Persona ────────────────────────────────── // ExportPersona strips provider_config_id. type ExportPersona struct { models.Persona ProviderConfigID *string `json:"provider_config_id,omitempty"` // always nil } // SanitizePersonas strips instance-specific provider binding. func SanitizePersonas(ps []models.Persona) []ExportPersona { out := make([]ExportPersona, len(ps)) for i := range ps { ps[i].ProviderConfigID = nil out[i] = ExportPersona{Persona: ps[i]} } return out } // ── Workflow ───────────────────────────────── // SanitizeWorkflows strips webhook secrets. func SanitizeWorkflows(wfs []models.Workflow) []models.Workflow { out := make([]models.Workflow, len(wfs)) for i := range wfs { out[i] = wfs[i] out[i].WebhookSecret = "" } return out } // Note links use models.ExportNoteLink (includes source_note_id). // See models/models.go for the type definition. // Note, Memory, Folder, NotificationPreference, // ChannelParticipant, ChannelCursor, Project, ProjectChannel, // ProjectKB, ProjectNote, WorkspaceFile, PersonaGroup, // PersonaGroupMember, KnowledgeBase, KBDocument, Group, // GroupMember, ResourceGrant, Team, TeamMember, WorkflowVersion, // WorkflowStage — these are exported as-is (no sensitive fields // after query-level exclusion of embeddings).