-
Notifications
You must be signed in to change notification settings - Fork 82
Expand file tree
/
Copy pathmain.go
More file actions
189 lines (162 loc) · 6.66 KB
/
main.go
File metadata and controls
189 lines (162 loc) · 6.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package main
import (
"context"
"log"
"os"
"os/signal"
"syscall"
"ambient-code-backend/cmd"
"ambient-code-backend/featureflags"
"ambient-code-backend/git"
"ambient-code-backend/github"
"ambient-code-backend/handlers"
"ambient-code-backend/k8s"
"ambient-code-backend/ldap"
"ambient-code-backend/server"
"ambient-code-backend/websocket"
"github.com/joho/godotenv"
)
// Build-time metadata (set via -ldflags -X during build)
// These are embedded directly in the binary, so they're always accurate
var (
GitCommit = "unknown"
GitBranch = "unknown"
GitVersion = "unknown"
BuildDate = "unknown"
)
func logBuildInfo() {
log.Println("==============================================")
log.Println("Backend API - Build Information")
log.Println("==============================================")
log.Printf("Version: %s", GitVersion)
log.Printf("Commit: %s", GitCommit)
log.Printf("Branch: %s", GitBranch)
log.Printf("Repository: %s", getEnvOrDefault("GIT_REPO", "unknown"))
log.Printf("Built: %s", BuildDate)
log.Printf("Built by: %s", getEnvOrDefault("BUILD_USER", "unknown"))
log.Println("==============================================")
}
func getEnvOrDefault(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
func main() {
// Load environment from .env in development if present
_ = godotenv.Overload(".env.local")
_ = godotenv.Overload(".env")
// Handle subcommands before full server initialization
if len(os.Args) > 1 && os.Args[1] == "sync-model-flags" {
manifestPath := cmd.ParseManifestPath(os.Args[2:])
if err := cmd.SyncModelFlagsFromFile(manifestPath); err != nil {
log.Fatalf("sync-model-flags: %v", err)
}
return
}
// Expose build version to handlers package
handlers.SetVersion(GitVersion)
// Log build information
logBuildInfo()
// Normal server mode - full initialization
log.Println("Starting in normal server mode with K8s client initialization")
// Initialize components
github.InitializeTokenManager()
if err := server.InitK8sClients(); err != nil {
log.Fatalf("Failed to initialize Kubernetes clients: %v", err)
}
server.InitConfig()
// Optional: Unleash feature flags (when UNLEASH_URL and UNLEASH_CLIENT_KEY are set)
featureflags.Init()
// Sync feature flags to Unleash in the background (best-effort, non-blocking).
// Collects flags from two sources:
// 1. Model manifest (models.json) — model-specific flags with scope:workspace tag
// 2. Generic flags config (flags.json) — arbitrary flags with custom tags
// The context is cancelled on SIGTERM/SIGINT so in-flight retries abort
// during graceful shutdown rather than delaying termination.
syncCtx, syncCancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer syncCancel()
var allFlags []cmd.FlagSpec
var staleFlags []string
if manifest, err := handlers.LoadManifest(handlers.ManifestPath()); err != nil {
log.Printf("WARNING: cannot load model manifest for flag sync: %v", err)
} else {
allFlags = append(allFlags, cmd.FlagsFromManifest(manifest)...)
staleFlags = append(staleFlags, cmd.StaleFlagsFromManifest(manifest)...)
}
if extraFlags, err := cmd.FlagsFromConfig(cmd.FlagsConfigPath()); err != nil {
log.Printf("WARNING: cannot load flags config: %v", err)
} else {
allFlags = append(allFlags, extraFlags...)
}
if len(allFlags) > 0 || len(staleFlags) > 0 {
cmd.SyncAndCleanupAsync(syncCtx, allFlags, staleFlags)
}
// Initialize git package
git.GetProjectSettingsResource = k8s.GetProjectSettingsResource
git.GetGitHubInstallation = func(ctx context.Context, userID string) (interface{}, error) {
installation, err := github.GetInstallation(ctx, userID)
if installation == nil {
return nil, err
}
return installation, err
}
git.GetGitHubPATCredentials = func(ctx context.Context, userID string) (interface{}, error) {
creds, err := handlers.GetGitHubPATCredentials(ctx, userID)
if creds == nil {
return nil, err
}
return creds, err
}
git.GetGitLabCredentials = func(ctx context.Context, userID string) (interface{}, error) {
creds, err := handlers.GetGitLabCredentials(ctx, userID)
if creds == nil {
return nil, err
}
return creds, err
}
git.GitHubTokenManager = github.Manager
git.GetBackendNamespace = func() string {
return server.Namespace
}
// Initialize LDAP client (optional - requires LDAP_URL to be set)
// Access is gated by the "ldap.autocomplete.enabled" Unleash feature flag.
if ldapURL := os.Getenv("LDAP_URL"); ldapURL != "" {
ldapBaseDN := getEnvOrDefault("LDAP_BASE_DN", "ou=users,dc=redhat,dc=com")
ldapGroupBaseDN := os.Getenv("LDAP_GROUP_BASE_DN") // optional, derived from LDAP_BASE_DN if empty
skipTLS := os.Getenv("LDAP_SKIP_TLS_VERIFY") == "true"
handlers.LDAPClient = ldap.NewClient(ldapURL, ldapBaseDN, ldapGroupBaseDN, skipTLS)
log.Printf("LDAP client initialized: %s (base DN: %s, group base DN: %s, skipTLSVerify: %v)", ldapURL, ldapBaseDN, ldapGroupBaseDN, skipTLS)
}
// Initialize GitHub auth handlers
handlers.K8sClient = server.K8sClient
handlers.Namespace = server.Namespace
handlers.GithubTokenManager = github.Manager
// Initialize project handlers
handlers.GetOpenShiftProjectResource = k8s.GetOpenShiftProjectResource
handlers.K8sClientProjects = server.K8sClient // Backend SA client for namespace operations
handlers.DynamicClientProjects = server.DynamicClient // Backend SA dynamic client for Project operations
// Initialize session handlers
handlers.GetAgenticSessionV1Alpha1Resource = k8s.GetAgenticSessionV1Alpha1Resource
handlers.DynamicClient = server.DynamicClient
handlers.GetGitHubToken = handlers.WrapGitHubTokenForRepo(git.GetGitHubToken)
handlers.GetGitLabToken = git.GetGitLabToken
handlers.DeriveRepoFolderFromURL = git.DeriveRepoFolderFromURL
// LEGACY: SendMessageToSession removed - AG-UI server uses HTTP/SSE instead of WebSocket
// Initialize scheduled session handlers
handlers.K8sClientScheduled = server.K8sClient
// Initialize repo handlers (default implementation already set in client_selection.go)
// GetK8sClientsForRequestRepoFunc uses getK8sClientsForRequestRepoDefault by default
handlers.GetGitHubTokenRepo = handlers.WrapGitHubTokenForRepo(git.GetGitHubToken)
handlers.DoGitHubRequest = nil // nil means use doGitHubRequest (default implementation)
// Initialize middleware
handlers.BaseKubeConfig = server.BaseKubeConfig
handlers.K8sClientMw = server.K8sClient
// Initialize websocket package
websocket.StateBaseDir = server.StateBaseDir
handlers.DeriveAgentStatusFromEvents = websocket.DeriveAgentStatus
// Normal server mode
if err := server.Run(registerRoutes); err != nil {
log.Fatalf("Server error: %v", err)
}
}