chore: sync from fn-registry agent

This commit is contained in:
fn-registry agent
2026-05-30 17:28:38 +02:00
commit 4b0fb61f02
28 changed files with 3271 additions and 0 deletions
+152
View File
@@ -0,0 +1,152 @@
package main
import (
"context"
"fmt"
"os/exec"
"strings"
"time"
)
const gitTimeoutSeconds = 120
// gitRun ejecuta git con argumentos en cwd. Devuelve stdout, stderr, exitCode.
func gitRun(cwd string, args ...string) (string, string, int, error) {
if _, err := exec.LookPath("git"); err != nil {
return "", "", -1, fmt.Errorf("git binary not in PATH")
}
ctx, cancel := context.WithTimeout(context.Background(), gitTimeoutSeconds*time.Second)
defer cancel()
c := exec.CommandContext(ctx, "git", args...) // #nosec G204 — args controlled
if cwd != "" {
c.Dir = cwd
}
var stdout, stderr strings.Builder
c.Stdout = &stdout
c.Stderr = &stderr
err := c.Run()
exitCode := 0
if err != nil {
if ee, ok := err.(*exec.ExitError); ok {
exitCode = ee.ExitCode()
} else {
return stdout.String(), stderr.String(), -1, err
}
}
return stdout.String(), stderr.String(), exitCode, nil
}
// runGitClone clona un repo a dest. Valida dest contra cap.PathsAllowed.
func runGitClone(cap *Capability, args map[string]any) (any, int, error) {
url := mapStringField(args, "url")
dest := mapStringField(args, "dest")
if url == "" || dest == "" {
return nil, -1, fmt.Errorf("url and dest required")
}
if !isPathAllowed(dest, cap.PathsAllowed) {
return nil, -1, fmt.Errorf("dest not allowed by manifest: %s", dest)
}
stdout, stderr, code, err := gitRun("", "clone", url, dest)
if err != nil {
return nil, -1, fmt.Errorf("git clone: %w (%s)", err, stderr)
}
if code != 0 {
return map[string]any{
"stdout": stdout,
"stderr": stderr,
"exit_code": code,
}, code, fmt.Errorf("git clone exit=%d: %s", code, stderr)
}
// recoge HEAD commit + branch
sha, _, _, _ := gitRun(dest, "rev-parse", "HEAD")
branch, _, _, _ := gitRun(dest, "rev-parse", "--abbrev-ref", "HEAD")
return map[string]any{
"dest": dest,
"commit_sha": strings.TrimSpace(sha),
"branch": strings.TrimSpace(branch),
"stdout": stdout,
"exit_code": 0,
}, 0, nil
}
// runGitCommit hace git add + commit en repo. files opcional; vacio = -am.
func runGitCommit(cap *Capability, args map[string]any) (any, int, error) {
repo := mapStringField(args, "repo")
msg := mapStringField(args, "message")
if repo == "" || msg == "" {
return nil, -1, fmt.Errorf("repo and message required")
}
if !isPathAllowed(repo, cap.PathsAllowed) {
return nil, -1, fmt.Errorf("repo not allowed by manifest: %s", repo)
}
var files []string
if raw, ok := args["files"]; ok && raw != nil {
if arr, ok := raw.([]any); ok {
for _, v := range arr {
if s, ok := v.(string); ok {
files = append(files, s)
}
}
}
}
if len(files) > 0 {
addArgs := append([]string{"add", "--"}, files...)
_, addStderr, code, err := gitRun(repo, addArgs...)
if err != nil || code != 0 {
return nil, code, fmt.Errorf("git add: %s", addStderr)
}
_, cStderr, code, err := gitRun(repo, "commit", "-m", msg)
if err != nil || code != 0 {
return map[string]any{"stderr": cStderr, "exit_code": code}, code, fmt.Errorf("git commit exit=%d: %s", code, cStderr)
}
} else {
_, cStderr, code, err := gitRun(repo, "commit", "-am", msg)
if err != nil || code != 0 {
return map[string]any{"stderr": cStderr, "exit_code": code}, code, fmt.Errorf("git commit exit=%d: %s", code, cStderr)
}
}
sha, _, _, _ := gitRun(repo, "rev-parse", "HEAD")
return map[string]any{
"repo": repo,
"commit_sha": strings.TrimSpace(sha),
"exit_code": 0,
}, 0, nil
}
// runGitPush push del repo. remote default "origin", branch default "HEAD".
func runGitPush(cap *Capability, args map[string]any) (any, int, error) {
repo := mapStringField(args, "repo")
if repo == "" {
return nil, -1, fmt.Errorf("repo required")
}
if !isPathAllowed(repo, cap.PathsAllowed) {
return nil, -1, fmt.Errorf("repo not allowed by manifest: %s", repo)
}
remote := mapStringField(args, "remote")
if remote == "" {
remote = "origin"
}
branch := mapStringField(args, "branch")
if branch == "" {
branch = "HEAD"
}
stdout, stderr, code, err := gitRun(repo, "push", remote, branch)
if err != nil {
return nil, -1, fmt.Errorf("git push: %w (%s)", err, stderr)
}
if code != 0 {
return map[string]any{
"stdout": stdout,
"stderr": stderr,
"exit_code": code,
}, code, fmt.Errorf("git push exit=%d: %s", code, stderr)
}
return map[string]any{
"ok": true,
"remote": remote,
"branch": branch,
"stdout": stdout,
"stderr": stderr,
"exit_code": 0,
}, 0, nil
}