-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.go
More file actions
145 lines (129 loc) · 4.33 KB
/
app.go
File metadata and controls
145 lines (129 loc) · 4.33 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
// Package app provides the core application logic for the GitHub bot.
// Coordinates webhook processing, Okta sync, and PR compliance checks.
package app
import (
"context"
"encoding/json"
"log/slog"
"github.com/cockroachdb/errors"
"github.com/cruxstack/github-ops-app/internal/config"
internalerrors "github.com/cruxstack/github-ops-app/internal/errors"
"github.com/cruxstack/github-ops-app/internal/github/client"
"github.com/cruxstack/github-ops-app/internal/notifiers"
"github.com/cruxstack/github-ops-app/internal/okta"
)
// App is the main application instance containing all clients and
// configuration.
type App struct {
Config *config.Config
Logger *slog.Logger
GitHubClient *client.Client
OktaClient *okta.Client
Notifier *notifiers.SlackNotifier
}
// New creates a new App instance with configured clients.
// Initializes GitHub, Okta, and Slack clients based on config.
func New(ctx context.Context, cfg *config.Config) (*App, error) {
logger := config.NewLogger()
app := &App{
Config: cfg,
Logger: logger,
}
if cfg.IsGitHubConfigured() {
ghClient, err := client.NewAppClientWithBaseURL(
cfg.GitHubAppID,
cfg.GitHubInstallationID,
cfg.GitHubAppPrivateKey,
cfg.GitHubOrg,
cfg.GitHubBaseURL,
)
if err != nil {
return nil, errors.Wrap(err, "failed to create github app client")
}
app.GitHubClient = ghClient
}
if cfg.IsOktaSyncEnabled() {
oktaClient, err := okta.NewClientWithContext(ctx, &okta.ClientConfig{
Domain: cfg.OktaDomain,
ClientID: cfg.OktaClientID,
PrivateKey: cfg.OktaPrivateKey,
PrivateKeyID: cfg.OktaPrivateKeyID,
Scopes: cfg.OktaScopes,
GitHubUserField: cfg.OktaGitHubUserField,
BaseURL: cfg.OktaBaseURL,
})
if err != nil {
return nil, errors.Wrap(err, "failed to create okta client")
}
app.OktaClient = oktaClient
}
if cfg.SlackEnabled {
channels := notifiers.SlackChannels{
Default: cfg.SlackChannel,
PRBypass: cfg.SlackChannelPRBypass,
OktaSync: cfg.SlackChannelOktaSync,
OrphanedUsers: cfg.SlackChannelOrphanedUsers,
}
messages := notifiers.SlackMessages{
PRBypassFooterNote: cfg.SlackPRBypassFooterNote,
}
app.Notifier = notifiers.NewSlackNotifierWithAPIURL(cfg.SlackToken, channels, messages, cfg.SlackAPIURL)
}
return app, nil
}
// ScheduledEvent represents a generic scheduled event.
type ScheduledEvent struct {
Action string `json:"action"`
Data json.RawMessage `json:"data,omitempty"`
}
// ProcessScheduledEvent handles scheduled events (e.g., cron jobs).
// Routes to appropriate handlers based on event action.
func (a *App) ProcessScheduledEvent(ctx context.Context, evt ScheduledEvent) error {
if a.Config.DebugEnabled {
j, _ := json.Marshal(evt)
a.Logger.Debug("received scheduled event", slog.String("event", string(j)))
}
switch evt.Action {
case "okta-sync":
return a.handleOktaSync(ctx)
case "slack-test":
return a.handleSlackTest(ctx)
default:
return errors.Newf("unknown scheduled action: %s", evt.Action)
}
}
// ProcessWebhook handles incoming GitHub webhook events.
// Supports pull_request, team, and membership events.
func (a *App) ProcessWebhook(ctx context.Context, payload []byte, eventType string) error {
if a.Config.DebugEnabled {
a.Logger.Debug("received webhook", slog.String("event_type", eventType))
}
switch eventType {
case "pull_request":
return a.handlePullRequestWebhook(ctx, payload)
case "team":
return a.handleTeamWebhook(ctx, payload)
case "membership":
return a.handleMembershipWebhook(ctx, payload)
default:
return errors.Wrapf(internalerrors.ErrInvalidEventType, "%s", eventType)
}
}
// StatusResponse contains application status and feature flags.
type StatusResponse struct {
Status string `json:"status"`
GitHubConfigured bool `json:"github_configured"`
OktaSyncEnabled bool `json:"okta_sync_enabled"`
PRComplianceCheck bool `json:"pr_compliance_check"`
SlackEnabled bool `json:"slack_enabled"`
}
// GetStatus returns current application status and enabled features.
func (a *App) GetStatus() StatusResponse {
return StatusResponse{
Status: "ok",
GitHubConfigured: a.Config.IsGitHubConfigured(),
OktaSyncEnabled: a.Config.IsOktaSyncEnabled(),
PRComplianceCheck: a.Config.IsPRComplianceEnabled(),
SlackEnabled: a.Config.SlackEnabled,
}
}