- go.mod module name
- All 714 import references across 289 Go files
- VERSION: 0.1.0
- CI DB names: switchboard_core_{ci,dev,test}
- Docker image: gobha/switchboard-core
- Test fixtures: JWT issuer, repo names
- .env.example, docker-compose container name
- Compiles clean (go build exit 0)
217 lines
7.3 KiB
Go
217 lines
7.3 KiB
Go
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).
|