|
5 | 5 | "os" |
6 | 6 | "os/exec" |
7 | 7 | "os/signal" |
| 8 | + "path/filepath" |
8 | 9 | "syscall" |
9 | 10 | "time" |
10 | 11 |
|
@@ -91,32 +92,32 @@ func main() { |
91 | 92 | "This message appears because the program was started directly instead of using 'start'.") |
92 | 93 | return |
93 | 94 | } |
94 | | - // do not run the auto-update process if its disabled |
95 | | - if !configs.Coordinator.Canopy.AutoUpdate { |
96 | | - logger.Info("auto-update disabled, starting CLI directly") |
97 | | - cli.Start() |
98 | | - return |
| 95 | + // ensure the binary exists before proceeding |
| 96 | + if !isExecutable(configs.Coordinator.BinPath) { |
| 97 | + logger.Fatalf("canopy binary not found or not executable: %s", configs.Coordinator.BinPath) |
| 98 | + } |
| 99 | + if configs.Coordinator.Canopy.AutoUpdate { |
| 100 | + logger.Infof("auto-update enabled, starting coordinator on version %s", rpc.SoftwareVersion) |
| 101 | + } else { |
| 102 | + logger.Infof("auto-update disabled, starting binary: %s", configs.Coordinator.BinPath) |
99 | 103 | } |
100 | | - logger.Infof("auto-update enabled, starting coordinator on version %s", rpc.SoftwareVersion) |
101 | 104 | // handle external shutdown signals |
102 | 105 | sigChan := make(chan os.Signal, 1) |
103 | 106 | signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) |
104 | 107 | // setup the dependencies |
105 | | - updater := NewReleaseManager(configs.Updater, rpc.SoftwareVersion) |
| 108 | + updater := NewReleaseManager(configs.Updater, rpc.SoftwareVersion, configs.Coordinator.Canopy.AutoUpdate) |
106 | 109 | snapshot := NewSnapshotManager(configs.Snapshot) |
107 | | - |
108 | 110 | // setup plugin updater and config if configured |
109 | 111 | var pluginUpdater *ReleaseManager |
110 | 112 | var pluginConfig *PluginReleaseConfig |
111 | 113 | if configs.PluginUpdater != nil { |
112 | | - pluginUpdater = NewReleaseManager(configs.PluginUpdater, "v0.0.0") |
| 114 | + pluginUpdater = NewReleaseManager(configs.PluginUpdater, "v0.0.0", true) |
113 | 115 | pluginConfig = configs.PluginUpdater.PluginConfig |
114 | 116 | logger.Infof("plugin auto-update enabled from %s/%s", |
115 | 117 | configs.PluginUpdater.RepoOwner, |
116 | 118 | configs.PluginUpdater.RepoName) |
117 | 119 | } |
118 | 120 | supervisor := NewSupervisor(logger, pluginConfig) |
119 | | - |
120 | 121 | coordinator := NewCoordinator(configs.Coordinator, updater, pluginUpdater, supervisor, snapshot, logger) |
121 | 122 | // start the update loop |
122 | 123 | err := coordinator.UpdateLoop(sigChan) |
@@ -155,10 +156,20 @@ func getConfigs() (*Configs, lib.LoggerI) { |
155 | 156 | binPath := envOrDefault("BIN_PATH", defaultBinPath) |
156 | 157 | githubToken := envOrDefault("CANOPY_GITHUB_API_TOKEN", "") |
157 | 158 |
|
| 159 | + // core auto-update repo: config.json or defaults |
| 160 | + repoOwner := canopyConfig.AutoUpdateRepoOwner |
| 161 | + if repoOwner == "" { |
| 162 | + repoOwner = defaultRepoOwner |
| 163 | + } |
| 164 | + repoName := canopyConfig.AutoUpdateRepoName |
| 165 | + if repoName == "" { |
| 166 | + repoName = defaultRepoName |
| 167 | + } |
| 168 | + |
158 | 169 | updater := &ReleaseManagerConfig{ |
159 | 170 | Type: ReleaseTypeCLI, |
160 | | - RepoName: envOrDefault("REPO_NAME", defaultRepoName), |
161 | | - RepoOwner: envOrDefault("REPO_OWNER", defaultRepoOwner), |
| 171 | + RepoName: repoName, |
| 172 | + RepoOwner: repoOwner, |
162 | 173 | GithubApiToken: githubToken, |
163 | 174 | BinPath: binPath, |
164 | 175 | SnapshotKey: snapshotMetadataKey, |
@@ -213,6 +224,26 @@ func getConfigs() (*Configs, lib.LoggerI) { |
213 | 224 | }, l |
214 | 225 | } |
215 | 226 |
|
| 227 | +// isExecutable returns true if path exists, is a regular file, and has execute permission. |
| 228 | +func isExecutable(path string) bool { |
| 229 | + // resolve to absolute path to avoid relative path ambiguity |
| 230 | + absPath, err := filepath.Abs(path) |
| 231 | + if err != nil { |
| 232 | + return false |
| 233 | + } |
| 234 | + // check if the file exists and is accessible |
| 235 | + info, err := os.Stat(absPath) |
| 236 | + if err != nil { |
| 237 | + return false |
| 238 | + } |
| 239 | + // directories are not executable binaries |
| 240 | + if info.IsDir() { |
| 241 | + return false |
| 242 | + } |
| 243 | + // check for any execute bit (owner, group, or other) |
| 244 | + return info.Mode()&0111 != 0 |
| 245 | +} |
| 246 | + |
216 | 247 | // envOrDefault returns the value of the environment variable with the given key, |
217 | 248 | // or the default value if the variable is not set. |
218 | 249 | func envOrDefault(key, defaultValue string) string { |
|
0 commit comments