Add flag to toggle webhook management

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
This commit is contained in:
Gabriel Adrian Samfira 2023-08-16 10:48:25 +00:00
parent c00048e128
commit 1c0ff85a0d
No known key found for this signature in database
GPG key ID: 7D073DCC2C074CB5
8 changed files with 48 additions and 27 deletions

View file

@ -61,7 +61,7 @@ type APIController struct {
} }
func handleError(w http.ResponseWriter, err error) { func handleError(w http.ResponseWriter, err error) {
w.Header().Add("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
origErr := errors.Cause(err) origErr := errors.Cause(err)
apiErr := params.APIErrorResponse{ apiErr := params.APIErrorResponse{
Details: origErr.Error(), Details: origErr.Error(),
@ -214,8 +214,9 @@ func (a *APIController) NotFoundHandler(w http.ResponseWriter, r *http.Request)
Details: "Resource not found", Details: "Resource not found",
Error: "Not found", Error: "Not found",
} }
w.WriteHeader(http.StatusNotFound)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusNotFound)
if err := json.NewEncoder(w).Encode(apiErr); err != nil { if err := json.NewEncoder(w).Encode(apiErr); err != nil {
log.Printf("failet to write response: %q", err) log.Printf("failet to write response: %q", err)
} }

View file

@ -82,7 +82,7 @@ func WithDebugServer(parentRouter *mux.Router) *mux.Router {
return parentRouter return parentRouter
} }
func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddleware, initMiddleware, instanceMiddleware auth.Middleware) *mux.Router { func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddleware, initMiddleware, instanceMiddleware auth.Middleware, manageWebhooks bool) *mux.Router {
router := mux.NewRouter() router := mux.NewRouter()
logMiddleware := util.NewLoggingMiddleware(logWriter) logMiddleware := util.NewLoggingMiddleware(logWriter)
router.Use(logMiddleware) router.Use(logMiddleware)
@ -204,16 +204,17 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
apiRouter.Handle("/repositories/", http.HandlerFunc(han.CreateRepoHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/repositories/", http.HandlerFunc(han.CreateRepoHandler)).Methods("POST", "OPTIONS")
apiRouter.Handle("/repositories", http.HandlerFunc(han.CreateRepoHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/repositories", http.HandlerFunc(han.CreateRepoHandler)).Methods("POST", "OPTIONS")
// Install Webhook if manageWebhooks {
apiRouter.Handle("/repositories/{repoID}/webhook/", http.HandlerFunc(han.InstallRepoWebhookHandler)).Methods("POST", "OPTIONS") // Install Webhook
apiRouter.Handle("/repositories/{repoID}/webhook", http.HandlerFunc(han.InstallRepoWebhookHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/repositories/{repoID}/webhook/", http.HandlerFunc(han.InstallRepoWebhookHandler)).Methods("POST", "OPTIONS")
// Uninstall Webhook apiRouter.Handle("/repositories/{repoID}/webhook", http.HandlerFunc(han.InstallRepoWebhookHandler)).Methods("POST", "OPTIONS")
apiRouter.Handle("/repositories/{repoID}/webhook/", http.HandlerFunc(han.UninstallRepoWebhookHandler)).Methods("DELETE", "OPTIONS") // Uninstall Webhook
apiRouter.Handle("/repositories/{repoID}/webhook", http.HandlerFunc(han.UninstallRepoWebhookHandler)).Methods("DELETE", "OPTIONS") apiRouter.Handle("/repositories/{repoID}/webhook/", http.HandlerFunc(han.UninstallRepoWebhookHandler)).Methods("DELETE", "OPTIONS")
// Get webhook info apiRouter.Handle("/repositories/{repoID}/webhook", http.HandlerFunc(han.UninstallRepoWebhookHandler)).Methods("DELETE", "OPTIONS")
apiRouter.Handle("/repositories/{repoID}/webhook/", http.HandlerFunc(han.GetRepoWebhookInfoHandler)).Methods("GET", "OPTIONS") // Get webhook info
apiRouter.Handle("/repositories/{repoID}/webhook", http.HandlerFunc(han.GetRepoWebhookInfoHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/repositories/{repoID}/webhook/", http.HandlerFunc(han.GetRepoWebhookInfoHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/repositories/{repoID}/webhook", http.HandlerFunc(han.GetRepoWebhookInfoHandler)).Methods("GET", "OPTIONS")
}
///////////////////////////// /////////////////////////////
// Organizations and pools // // Organizations and pools //
///////////////////////////// /////////////////////////////
@ -253,16 +254,17 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
apiRouter.Handle("/organizations/", http.HandlerFunc(han.CreateOrgHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/organizations/", http.HandlerFunc(han.CreateOrgHandler)).Methods("POST", "OPTIONS")
apiRouter.Handle("/organizations", http.HandlerFunc(han.CreateOrgHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/organizations", http.HandlerFunc(han.CreateOrgHandler)).Methods("POST", "OPTIONS")
// Install Webhook if manageWebhooks {
apiRouter.Handle("/organizations/{orgID}/webhook/", http.HandlerFunc(han.InstallOrgWebhookHandler)).Methods("POST", "OPTIONS") // Install Webhook
apiRouter.Handle("/organizations/{orgID}/webhook", http.HandlerFunc(han.InstallOrgWebhookHandler)).Methods("POST", "OPTIONS") apiRouter.Handle("/organizations/{orgID}/webhook/", http.HandlerFunc(han.InstallOrgWebhookHandler)).Methods("POST", "OPTIONS")
// Uninstall Webhook apiRouter.Handle("/organizations/{orgID}/webhook", http.HandlerFunc(han.InstallOrgWebhookHandler)).Methods("POST", "OPTIONS")
apiRouter.Handle("/organizations/{orgID}/webhook/", http.HandlerFunc(han.UninstallOrgWebhookHandler)).Methods("DELETE", "OPTIONS") // Uninstall Webhook
apiRouter.Handle("/organizations/{orgID}/webhook", http.HandlerFunc(han.UninstallOrgWebhookHandler)).Methods("DELETE", "OPTIONS") apiRouter.Handle("/organizations/{orgID}/webhook/", http.HandlerFunc(han.UninstallOrgWebhookHandler)).Methods("DELETE", "OPTIONS")
// Get webhook info apiRouter.Handle("/organizations/{orgID}/webhook", http.HandlerFunc(han.UninstallOrgWebhookHandler)).Methods("DELETE", "OPTIONS")
apiRouter.Handle("/organizations/{orgID}/webhook/", http.HandlerFunc(han.GetOrgWebhookInfoHandler)).Methods("GET", "OPTIONS") // Get webhook info
apiRouter.Handle("/organizations/{orgID}/webhook", http.HandlerFunc(han.GetOrgWebhookInfoHandler)).Methods("GET", "OPTIONS") apiRouter.Handle("/organizations/{orgID}/webhook/", http.HandlerFunc(han.GetOrgWebhookInfoHandler)).Methods("GET", "OPTIONS")
apiRouter.Handle("/organizations/{orgID}/webhook", http.HandlerFunc(han.GetOrgWebhookInfoHandler)).Methods("GET", "OPTIONS")
}
///////////////////////////// /////////////////////////////
// Enterprises and pools // // Enterprises and pools //
///////////////////////////// /////////////////////////////
@ -314,5 +316,8 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
// Websocket log writer // Websocket log writer
apiRouter.Handle("/{ws:ws\\/?}", http.HandlerFunc(han.WSHandler)).Methods("GET") apiRouter.Handle("/{ws:ws\\/?}", http.HandlerFunc(han.WSHandler)).Methods("GET")
// NotFound handler
apiRouter.PathPrefix("/").HandlerFunc(han.NotFoundHandler).Methods("GET", "POST", "PUT", "DELETE", "OPTIONS")
return router return router
} }

View file

@ -170,7 +170,7 @@ func main() {
log.Fatal(err) log.Fatal(err)
} }
router := routers.NewAPIRouter(controller, multiWriter, jwtMiddleware, initMiddleware, instanceMiddleware) router := routers.NewAPIRouter(controller, multiWriter, jwtMiddleware, initMiddleware, instanceMiddleware, cfg.Default.EnableWebhookManagement)
if cfg.Metrics.Enable { if cfg.Metrics.Enable {
log.Printf("registering prometheus metrics collectors") log.Printf("registering prometheus metrics collectors")

View file

@ -112,6 +112,8 @@ type Default struct {
MetadataURL string `toml:"metadata_url" json:"metadata-url"` MetadataURL string `toml:"metadata_url" json:"metadata-url"`
// WebhookURL is the URL that will be installed as a webhook target in github. // WebhookURL is the URL that will be installed as a webhook target in github.
WebhookURL string `toml:"webhook_url" json:"webhook-url"` WebhookURL string `toml:"webhook_url" json:"webhook-url"`
// EnableWebhookManagement enables the webhook management API.
EnableWebhookManagement bool `toml:"enable_webhook_management" json:"enable-webhook-management"`
// LogFile is the location of the log file. // LogFile is the location of the log file.
LogFile string `toml:"log_file,omitempty" json:"log-file"` LogFile string `toml:"log_file,omitempty" json:"log-file"`

2
go.mod
View file

@ -8,6 +8,7 @@ require (
github.com/go-openapi/errors v0.20.4 github.com/go-openapi/errors v0.20.4
github.com/go-openapi/runtime v0.26.0 github.com/go-openapi/runtime v0.26.0
github.com/go-openapi/strfmt v0.21.7 github.com/go-openapi/strfmt v0.21.7
github.com/go-openapi/swag v0.22.4
github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/go-github/v53 v53.2.0 github.com/google/go-github/v53 v53.2.0
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
@ -55,7 +56,6 @@ require (
github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/loads v0.21.2 // indirect github.com/go-openapi/loads v0.21.2 // indirect
github.com/go-openapi/spec v0.20.8 // indirect github.com/go-openapi/spec v0.20.8 // indirect
github.com/go-openapi/swag v0.22.4 // indirect
github.com/go-openapi/validate v0.22.1 // indirect github.com/go-openapi/validate v0.22.1 // indirect
github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect

View file

@ -148,7 +148,7 @@ func (r *Runner) DeleteOrganization(ctx context.Context, orgID string, keepWebho
return runnerErrors.NewBadRequestError("org has pools defined (%s)", strings.Join(poolIds, ", ")) return runnerErrors.NewBadRequestError("org has pools defined (%s)", strings.Join(poolIds, ", "))
} }
if !keepWebhook { if !keepWebhook && r.config.Default.EnableWebhookManagement {
poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org) poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching pool manager") return errors.Wrap(err, "fetching pool manager")

View file

@ -147,7 +147,7 @@ func (r *Runner) DeleteRepository(ctx context.Context, repoID string, keepWebhoo
return runnerErrors.NewBadRequestError("repo has pools defined (%s)", strings.Join(poolIds, ", ")) return runnerErrors.NewBadRequestError("repo has pools defined (%s)", strings.Join(poolIds, ", "))
} }
if !keepWebhook { if !keepWebhook && r.config.Default.EnableWebhookManagement {
poolMgr, err := r.poolManagerCtrl.GetRepoPoolManager(repo) poolMgr, err := r.poolManagerCtrl.GetRepoPoolManager(repo)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching pool manager") return errors.Wrap(err, "fetching pool manager")

13
testdata/config.toml vendored
View file

@ -17,8 +17,21 @@ callback_url = "https://garm.example.com/api/v1/callbacks"
# highly encouraged. # highly encouraged.
metadata_url = "https://garm.example.com/api/v1/metadata" metadata_url = "https://garm.example.com/api/v1/metadata"
# This is the base URL where GARM will listen for webhook events from github. This
# URL can be directly configured in github to send events to.
# If GARM is allowed to manage webhooks, this URL will be used as a base to optionally
# create webhooks for repositories and organizations. To avoid clashes, the unique
# controller ID that gets generated when GARM is first installed, will be added as a suffix
# to this URL.
#
# For example, assuming that your GARM controller ID is "18225ce4-e3bd-43f0-9c85-7d7858bcc5b2"
# the webhook URL will be "https://garm.example.com/webhooks/18225ce4-e3bd-43f0-9c85-7d7858bcc5b2"
webhook_url = "https://garm.example.com/webhooks" webhook_url = "https://garm.example.com/webhooks"
# This option enables GARM to manage webhooks for repositories and organizations. Set this
# to false to disable the API routes that manage webhooks.
enable_webhook_management = true
# Uncomment this line if you'd like to log to a file instead of standard output. # Uncomment this line if you'd like to log to a file instead of standard output.
# log_file = "/tmp/runner-manager.log" # log_file = "/tmp/runner-manager.log"