package qaopsorg import ( "errors" "os" "path/filepath" "time" ) type SyncSettings struct { Enabled bool Tenant string Runner ExecDirectoryRunner } func LoadSyncSettings(getenv func(string) string) (SyncSettings, error) { var s SyncSettings enabled := getenv("DOBOTAI_OPS_DIRECTORY_SYNC_ENABLED") if enabled == "" || enabled == "false" { return s, nil } if enabled != "true" { return s, errors.New("invalid directory sync enable flag") } s.Tenant = getenv("DOBOTAI_OPS_TENANT_KEY") s.Runner = ExecDirectoryRunner{Python: getenv("DOBOTAI_OPS_DIRECTORY_SYNC_PYTHON"), Script: getenv("DOBOTAI_OPS_DIRECTORY_SYNC_SCRIPT"), RuntimeRoot: getenv("DOBOTAI_OPS_DIRECTORY_SYNC_RUNTIME_ROOT"), SpoolRoot: getenv("DOBOTAI_OPS_DIRECTORY_SYNC_SPOOL_ROOT"), Timeout: 20 * time.Minute} if value := getenv("DOBOTAI_OPS_DIRECTORY_SYNC_TIMEOUT"); value != "" { d, err := time.ParseDuration(value) if err != nil { return SyncSettings{}, errors.New("invalid directory sync timeout") } s.Runner.Timeout = d } if !validID(s.Tenant) || s.Runner.Timeout < time.Second || s.Runner.Timeout > 30*time.Minute { return SyncSettings{}, errors.New("directory sync binding is incomplete") } for _, path := range []string{s.Runner.Python, s.Runner.Script, s.Runner.RuntimeRoot, s.Runner.SpoolRoot} { if !filepath.IsAbs(path) || filepath.Clean(path) != path { return SyncSettings{}, errors.New("directory sync requires server-owned absolute paths") } } s.Enabled = true return s, nil } func (s SyncSettings) CheckWorkerRuntime() error { for _, path := range []string{s.Runner.Python, s.Runner.Script} { info, err := os.Stat(path) if err != nil || !info.Mode().IsRegular() { return ErrSyncWorkerUnavailable } } for _, path := range []string{s.Runner.RuntimeRoot, s.Runner.SpoolRoot} { info, err := os.Stat(path) if err != nil || !info.IsDir() { return ErrSyncWorkerUnavailable } } return nil }