fetch_ml/internal/config/paths.go
Jeremie Fraeys 4b2782f674
feat(domain): add task visibility and supporting infrastructure
Core domain and utility updates:

- domain/task.go: Task model with visibility system
  * Visibility enum: private, lab, institution, open
  * Group associations for lab-scoped access
  * CreatedBy tracking for ownership
  * Sharing metadata with expiry

- config/paths.go: Group-scoped data directories and audit log paths
- crypto/signing.go: Key management for audit sealing, token signature verification
- container/supply_chain.go: Image provenance tracking, vulnerability scanning
- fileutil/filetype.go: MIME type detection and security validation
- fileutil/secure.go: Protected file permissions, secure deletion
- jupyter/: Package and service manager updates
- experiment/manager.go: Visibility cascade from experiments to tasks
- network/ssh.go: SSH tunneling improvements
- queue/: Filesystem queue enhancements
2026-03-08 13:03:27 -04:00

114 lines
4.3 KiB
Go

// Package config provides centralized path management for the fetch_ml project.
package config
import (
"os"
"path/filepath"
)
// PathRegistry provides centralized path management
type PathRegistry struct {
RootDir string // Repository root (auto-detected or from env)
}
// NewPathRegistry creates a path registry from root directory.
// If root is empty, attempts to auto-detect repository root.
func NewPathRegistry(root string) *PathRegistry {
if root == "" {
root = detectRepoRoot()
}
return &PathRegistry{RootDir: root}
}
// BinDir returns the path to the bin directory where compiled binaries are stored.
func (p *PathRegistry) BinDir() string { return filepath.Join(p.RootDir, "bin") }
func (p *PathRegistry) APIServerBinary() string { return filepath.Join(p.BinDir(), "api-server") }
func (p *PathRegistry) WorkerBinary() string { return filepath.Join(p.BinDir(), "worker") }
func (p *PathRegistry) TUIBinary() string { return filepath.Join(p.BinDir(), "tui") }
func (p *PathRegistry) DataManagerBinary() string { return filepath.Join(p.BinDir(), "data_manager") }
// DataDir returns the path to the data directory where all runtime data is stored.
func (p *PathRegistry) DataDir() string { return filepath.Join(p.RootDir, "data") }
func (p *PathRegistry) ActiveDataDir() string { return filepath.Join(p.DataDir(), "active") }
func (p *PathRegistry) JupyterStateDir() string {
return filepath.Join(p.DataDir(), "active", "jupyter")
}
func (p *PathRegistry) ExperimentsDir() string { return filepath.Join(p.DataDir(), "experiments") }
func (p *PathRegistry) ProdSmokeDir() string { return filepath.Join(p.DataDir(), "prod-smoke") }
// DBDir returns the path to the database directory where all database files are stored.
func (p *PathRegistry) DBDir() string { return filepath.Join(p.RootDir, "db") }
func (p *PathRegistry) SQLitePath() string { return filepath.Join(p.DBDir(), "fetch_ml.db") }
// LogDir returns the path to the log directory where all log files are stored.
func (p *PathRegistry) LogDir() string { return filepath.Join(p.RootDir, "logs") }
func (p *PathRegistry) AuditLogPath() string { return filepath.Join(p.LogDir(), "fetchml-audit.log") }
// ConfigDir returns the path to the config directory where all configuration files are stored.
func (p *PathRegistry) ConfigDir() string { return filepath.Join(p.RootDir, "configs") }
func (p *PathRegistry) APIServerConfig() string {
return filepath.Join(p.ConfigDir(), "api", "dev.yaml")
}
func (p *PathRegistry) WorkerConfigDir() string { return filepath.Join(p.ConfigDir(), "workers") }
// TestResultsDir returns the path to the test results directory where all test outputs are stored.
func (p *PathRegistry) TestResultsDir() string { return filepath.Join(p.RootDir, "test_results") }
func (p *PathRegistry) TempDir() string { return filepath.Join(p.RootDir, "tmp") }
// These files store the state of Jupyter services and workspaces, allowing them to persist across restarts.
func (p *PathRegistry) JupyterServicesFile() string {
return filepath.Join(p.JupyterStateDir(), "fetch_ml_jupyter_services.json")
}
func (p *PathRegistry) JupyterWorkspacesFile() string {
return filepath.Join(p.JupyterStateDir(), "fetch_ml_jupyter_workspaces.json")
}
// EnsureDir creates directory if it doesn't exist with appropriate permissions.
func (p *PathRegistry) EnsureDir(path string) error {
return os.MkdirAll(path, 0o750)
}
// EnsureDirSecure creates directory with restricted permissions (for sensitive data).
func (p *PathRegistry) EnsureDirSecure(path string) error {
return os.MkdirAll(path, 0o700)
}
// FileExists checks if a file exists.
func (p *PathRegistry) FileExists(path string) bool {
_, err := os.Stat(path)
return err == nil
}
// detectRepoRoot finds repository root by looking for go.mod.
// Returns current directory if not found.
func detectRepoRoot() string {
dir, err := os.Getwd()
if err != nil {
return "."
}
// Walk up directory tree looking for go.mod
for {
if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
return dir
}
parent := filepath.Dir(dir)
if parent == dir {
// Reached root
break
}
dir = parent
}
return "."
}
// FromEnv creates PathRegistry with root from FETCHML_ROOT env var,
// or auto-detects if env var not set.
func FromEnv() *PathRegistry {
root := os.Getenv("FETCHML_ROOT")
return NewPathRegistry(root)
}