package main import ( "fmt" "os" "gopkg.in/yaml.v3" ) type Capability struct { Name string `yaml:"name"` BinariesAllowed []string `yaml:"binaries_allowed,omitempty"` PathsAllowed []string `yaml:"paths_allowed,omitempty"` RequiresApproval bool `yaml:"requires_approval"` // shell.eval specific fields Blocklist []string `yaml:"blocklist,omitempty"` // regex patterns hardcoded + extendible AutoApprove []string `yaml:"auto_approve,omitempty"` // regex patterns pre-approved ShellMode string `yaml:"shell_mode,omitempty"` // "bash"|"powershell"|"auto" (default auto) MaxOutputBytes int `yaml:"max_output_bytes,omitempty"` // default 1MB TimeoutSeconds int `yaml:"timeout_seconds,omitempty"` // default 60 // browser.* specific fields (CDP) ChromeCDPHost string `yaml:"chrome_cdp_host,omitempty"` // default 127.0.0.1 ChromeCDPPort int `yaml:"chrome_cdp_port,omitempty"` // default 9223 ScreenshotDir string `yaml:"screenshot_dir,omitempty"` // dest dir for screenshots (browser.screenshot) } type Manifest struct { DeviceID string `yaml:"device_id"` Operator string `yaml:"operator"` Capabilities []Capability `yaml:"capabilities"` } func LoadManifest(path string) (*Manifest, error) { data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("read manifest %s: %w", path, err) } var mf Manifest if err := yaml.Unmarshal(data, &mf); err != nil { return nil, fmt.Errorf("parse manifest yaml: %w", err) } if mf.DeviceID == "" { return nil, fmt.Errorf("manifest missing device_id") } if len(mf.Capabilities) == 0 { return nil, fmt.Errorf("manifest has no capabilities") } return &mf, nil } // CapabilityByName devuelve el bloque del manifest para name, o nil si no esta. func (m *Manifest) CapabilityByName(name string) *Capability { for i := range m.Capabilities { if m.Capabilities[i].Name == name { return &m.Capabilities[i] } } return nil }