agent-orchestrator/backend/internal/adapters/agent/amp/auth.go

122 lines
3.2 KiB
Go

package amp
import (
"context"
"encoding/json"
"errors"
"os"
"path/filepath"
"strings"
"time"
"github.com/aoagents/agent-orchestrator/backend/internal/adapters/agent/authprobe"
"github.com/aoagents/agent-orchestrator/backend/internal/ports"
)
var _ ports.AgentAuthChecker = (*Plugin)(nil)
// AuthStatus returns the plugin's local authentication status.
func (p *Plugin) AuthStatus(ctx context.Context) (ports.AgentAuthStatus, error) {
binary, err := p.ResolveBinary(ctx)
if err != nil {
return ports.AgentAuthStatusUnknown, err
}
if status, ok, err := ampLocalAuthStatus(ctx); err != nil || ok {
return status, err
}
return ampUsageAuthStatus(ctx, binary)
}
func ampLocalAuthStatus(ctx context.Context) (ports.AgentAuthStatus, bool, error) {
if err := ctx.Err(); err != nil {
return ports.AgentAuthStatusUnknown, false, err
}
if strings.TrimSpace(os.Getenv("AMP_API_KEY")) != "" {
return ports.AgentAuthStatusAuthorized, true, nil
}
status, ok, err := ampSettingsAuthStatus(ampSettingsPath())
if err != nil {
return ports.AgentAuthStatusUnknown, false, err
}
return status, ok, nil
}
func ampSettingsPath() string {
if path := strings.TrimSpace(os.Getenv("AMP_SETTINGS_FILE")); path != "" {
return expandHome(path)
}
if home, err := os.UserHomeDir(); err == nil && home != "" {
return filepath.Join(home, ".config", "amp", "settings.json")
}
return ""
}
func ampSettingsAuthStatus(path string) (ports.AgentAuthStatus, bool, error) {
if path == "" {
return ports.AgentAuthStatusUnknown, false, nil
}
data, err := os.ReadFile(path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return ports.AgentAuthStatusUnknown, false, nil
}
return ports.AgentAuthStatusUnknown, false, err
}
var settings map[string]any
if err := json.Unmarshal(data, &settings); err != nil {
return ports.AgentAuthStatusUnknown, false, err
}
for _, key := range []string{"amp.apiKey", "amp.api_key", "apiKey", "api_key"} {
if value, ok := settings[key]; ok {
if strings.TrimSpace(stringValue(value)) != "" {
return ports.AgentAuthStatusAuthorized, true, nil
}
return ports.AgentAuthStatusUnauthorized, true, nil
}
}
return ports.AgentAuthStatusUnknown, false, nil
}
func ampUsageAuthStatus(ctx context.Context, binary string) (ports.AgentAuthStatus, error) {
if binary == "" {
return ports.AgentAuthStatusUnknown, nil
}
probeCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
out, err := authprobe.CmdRunner(probeCtx, binary, "usage", "--no-color")
if probeCtx.Err() != nil {
return ports.AgentAuthStatusUnknown, probeCtx.Err()
}
if status := authprobe.StatusFromText(string(out)); status != ports.AgentAuthStatusUnknown {
return status, nil
}
if err == nil {
return ports.AgentAuthStatusAuthorized, nil
}
return ports.AgentAuthStatusUnknown, nil
}
func stringValue(value any) string {
switch v := value.(type) {
case string:
return v
default:
return ""
}
}
func expandHome(path string) string {
if path == "~" {
if home, err := os.UserHomeDir(); err == nil {
return home
}
}
if strings.HasPrefix(path, "~/") {
if home, err := os.UserHomeDir(); err == nil {
return filepath.Join(home, strings.TrimPrefix(path, "~/"))
}
}
return path
}