Repository navigation
Expand file tree
/
Copy pathconfig.go
More file actions
127 lines (104 loc) · 3.03 KB
/
Copy pathconfig.go
File metadata and controls
127 lines (104 loc) · 3.03 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
package main
import (
"crypto/rsa"
"crypto/tls"
"fmt"
"log"
"os"
"os/signal"
"path/filepath"
"strings"
"sync"
"syscall"
"github.com/BurntSushi/toml"
"github.com/golang-jwt/jwt/v5"
)
type Config struct {
Bind string `toml:"bind"`
TLS *struct {
CertFile string `toml:"cert_file"`
KeyFile string `toml:"key_file"`
certificate tls.Certificate
} `toml:"tls"`
GitHubApp struct {
ClientID string `toml:"client_id"`
PrivateKeyFile string `toml:"private_key_file"`
WebhookSecretFile string `toml:"webhook_secret_file"`
privateKey *rsa.PrivateKey
webhookSecret string
} `toml:"github_app"`
GitLFS bool `toml:"git_lfs"`
Projects []*RepoConfig `toml:"projects"`
}
type RepoConfig struct {
Repository string `toml:"repository"`
Branch string `toml:"branch"`
Path string `toml:"path"`
Command string `toml:"command"`
Timeout int `toml:"timeout"`
}
var (
config Config
configPath string
configMutex = sync.Mutex{}
)
func loadConfig(initial bool) error {
var newConfig Config
_, err := toml.DecodeFile(configPath, &newConfig)
if err != nil {
return fmt.Errorf("failed to decode TOML config: %w", err)
}
if newConfig.Bind == "" {
return fmt.Errorf("configuration 'bind' parameter is required")
}
// Validate projects one by one
for _, repo := range newConfig.Projects {
repo.Path, err = filepath.Abs(repo.Path)
if err != nil {
return fmt.Errorf("failed to resolve path: %w", err)
}
if repo.Timeout == 0 {
repo.Timeout = 120
}
}
if newConfig.TLS != nil {
newConfig.TLS.certificate, err = tls.LoadX509KeyPair(os.ExpandEnv(newConfig.TLS.CertFile), os.ExpandEnv(newConfig.TLS.KeyFile))
if err != nil {
return fmt.Errorf("failed to load TLS certificate: %w", err)
}
}
keyBytes, err := os.ReadFile(os.ExpandEnv(newConfig.GitHubApp.PrivateKeyFile))
if err != nil {
return fmt.Errorf("failed to read PEM key: %w", err)
}
newConfig.GitHubApp.privateKey, err = jwt.ParseRSAPrivateKeyFromPEM(keyBytes)
if err != nil {
return fmt.Errorf("failed to parse PEM key: %w", err)
}
webhookSecretBytes, err := os.ReadFile(os.ExpandEnv(newConfig.GitHubApp.WebhookSecretFile))
if err != nil {
return fmt.Errorf("failed to read webhook secret: %w", err)
}
newConfig.GitHubApp.webhookSecret = strings.TrimSpace(string(webhookSecretBytes))
if !initial && ((config.TLS == nil) != (newConfig.TLS == nil) || config.Bind != newConfig.Bind) {
log.Printf("Warning: Changing bind address or toggling TLS requires a restart of the server, updates to these settings are ignored")
}
config = newConfig
return nil
}
func handleConfigReload() {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGHUP)
go func() {
for range sigChan {
configMutex.Lock()
log.Printf("Received SIGHUP, reloading configuration...")
if err := loadConfig(false); err != nil {
log.Fatalf("Failed to reload config: %v", err)
}
log.Printf("Configuration reloaded successfully")
tokenCache.Storage.Flush()
configMutex.Unlock()
}
}()
}