fix(droid): align hooks with Factory 0.175
This commit is contained in:
1 parent
827374e7f8
commit
4521cbe32f
15 files changed
+2749
-881
No files matched your search
+122
-45
@@ -1,62 +1,139 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func prepareRenderedDroidChange(rendered *droidRenderedDocument) (*fileChange, error) {
|
||||
if rendered == nil || !rendered.changed {
|
||||
return nil, nil
|
||||
type droidFactoryConfigPaths struct {
|
||||
directory string
|
||||
root string
|
||||
legacyDirectory string
|
||||
legacy string
|
||||
settings string
|
||||
localSettings string
|
||||
}
|
||||
|
||||
func droidFactoryPaths() (*droidFactoryConfigPaths, error) {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("resolve home directory: %w", err)
|
||||
}
|
||||
label := "Factory Droid hooks"
|
||||
if rendered.document.kind == "legacy" {
|
||||
label = "Factory Droid legacy hooks"
|
||||
} else if rendered.document.kind == "settings" {
|
||||
label = "Factory Droid settings"
|
||||
directory := filepath.Join(home, ".factory")
|
||||
legacyDirectory := filepath.Join(directory, "hooks")
|
||||
return &droidFactoryConfigPaths{
|
||||
directory: directory,
|
||||
root: filepath.Join(directory, "hooks.json"),
|
||||
legacyDirectory: legacyDirectory,
|
||||
legacy: filepath.Join(legacyDirectory, "hooks.json"),
|
||||
settings: filepath.Join(directory, "settings.json"),
|
||||
localSettings: filepath.Join(directory, "settings.local.json"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func readDroidDocument(
|
||||
filePath, kind, label string,
|
||||
) (*droidDocument, error) {
|
||||
snapshot, err := readManagedFile(filePath, label, maxManagedSourceBytes)
|
||||
if err != nil || snapshot == nil {
|
||||
return nil, err
|
||||
}
|
||||
return prepareSourceChange(
|
||||
rendered.document.filePath,
|
||||
label,
|
||||
rendered.document.raw,
|
||||
rendered.document.exists,
|
||||
rendered.next,
|
||||
os.FileMode(0600),
|
||||
rendered.remove,
|
||||
return parseDroidDocument(
|
||||
true,
|
||||
filePath,
|
||||
kind,
|
||||
snapshot.contents,
|
||||
snapshot,
|
||||
)
|
||||
}
|
||||
|
||||
func droidRuntimeFilesExist(contracts []droidRuntimeContract) (bool, error) {
|
||||
for _, contract := range contracts {
|
||||
configPath := filepath.Join(filepath.Dir(contract.guardPath), "config.json")
|
||||
raw, exists, err := readOptionalFile(configPath, "Elydora runtime config")
|
||||
func readDroidSources() (*droidSources, error) {
|
||||
paths, err := droidFactoryPaths()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := managedPhysicalDirectoryExists(
|
||||
paths.directory,
|
||||
"Factory Droid user configuration directory",
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := managedPhysicalDirectoryExists(
|
||||
paths.legacyDirectory,
|
||||
"Factory Droid legacy hooks directory",
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
root, err := readDroidDocument(paths.root, "hooks", "Factory Droid user hooks")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if root == nil {
|
||||
root, err = createOwnedDroidDocument(paths.root)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
var config map[string]any
|
||||
if err := json.Unmarshal(raw, &config); err != nil {
|
||||
return false, fmt.Errorf("parse Elydora runtime config at %s: %w", configPath, err)
|
||||
}
|
||||
agentID, ok := config["agent_id"].(string)
|
||||
if !ok || config["agent_name"] != droidAgentKey || !sameDroidAgentID(agentID, contract.agentID) {
|
||||
continue
|
||||
}
|
||||
guardExists, err := regularFileExists(contract.guardPath, "Elydora guard runtime")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
auditExists, err := regularFileExists(contract.auditPath, "Elydora audit runtime")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if guardExists && auditExists {
|
||||
return true, nil
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
legacy, err := readDroidDocument(paths.legacy, "legacy", "Factory Droid legacy hooks")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if legacy == nil {
|
||||
legacy, err = createDroidDocument(paths.legacy, "legacy", []byte("{}\n"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
settings, err := readDroidDocument(paths.settings, "settings", "Factory Droid user settings")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if settings == nil {
|
||||
settings, err = createDroidDocument(paths.settings, "settings", []byte("{}\n"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
localSettings, err := readDroidDocument(
|
||||
paths.localSettings,
|
||||
"local-settings",
|
||||
"Factory Droid local settings",
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if localSettings == nil {
|
||||
localSettings, err = createDroidDocument(
|
||||
paths.localSettings,
|
||||
"local-settings",
|
||||
[]byte("{}\n"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
policy, err := readDroidPolicy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &droidSources{
|
||||
root: root,
|
||||
legacy: legacy,
|
||||
settings: settings,
|
||||
localSettings: localSettings,
|
||||
policy: policy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func requireDroidHooksEnabled(sources *droidSources) error {
|
||||
if blocked := droidHookBlocked(sources); blocked != nil {
|
||||
return fmt.Errorf(
|
||||
"Factory Droid user hooks are disabled by %s in %s at %s",
|
||||
blocked.field,
|
||||
blocked.label,
|
||||
blocked.filePath,
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in new issue
Block a user