2019-11-01 06:43:05 +00:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2021-02-25 09:21:43 +00:00
|
|
|
"github.com/keel-hq/keel/types"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
2019-11-01 06:43:05 +00:00
|
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
|
|
|
var newGithubWebhooksCounter = prometheus.NewCounterVec(
|
|
|
|
prometheus.CounterOpts{
|
|
|
|
Name: "Github_webhook_requests_total",
|
|
|
|
Help: "How many /v1/webhooks/github requests processed, partitioned by image.",
|
|
|
|
},
|
|
|
|
[]string{"image"},
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
prometheus.MustRegister(newGithubWebhooksCounter)
|
|
|
|
}
|
|
|
|
|
2021-02-25 09:21:43 +00:00
|
|
|
type githubRegistryPackageWebhook struct {
|
2019-11-01 06:43:05 +00:00
|
|
|
Action string `json:"action"`
|
|
|
|
RegistryPackage struct {
|
2021-02-25 09:21:43 +00:00
|
|
|
Name string `json:"name"`
|
2019-11-01 06:43:05 +00:00
|
|
|
PackageType string `json:"package_type"`
|
|
|
|
PackageVersion struct {
|
2021-02-25 09:21:43 +00:00
|
|
|
Version string `json:"version"`
|
2019-11-01 06:43:05 +00:00
|
|
|
} `json:"package_version"`
|
|
|
|
UpdatedAt string `json:"updated_at"`
|
|
|
|
} `json:"registry_package"`
|
|
|
|
Repository struct {
|
2021-02-25 09:21:43 +00:00
|
|
|
FullName string `json:"full_name"`
|
2019-11-01 06:43:05 +00:00
|
|
|
} `json:"repository"`
|
2021-02-25 09:21:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type githubPackageV2Webhook struct {
|
|
|
|
Action string `json:"action"`
|
|
|
|
Package struct {
|
|
|
|
Id int `json:"id"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Namespace string `json:"namespace"`
|
|
|
|
Ecosystem string `json:"ecosystem"`
|
|
|
|
PackageVersion struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
ContainerMetadata struct {
|
|
|
|
Tag struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
Digest string `json:"digest"`
|
|
|
|
} `json:"tag"`
|
|
|
|
} `json:"container_metadata"`
|
|
|
|
} `json:"package_version"`
|
|
|
|
} `json:"package"`
|
2019-11-01 06:43:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// githubHandler - used to react to github webhooks
|
|
|
|
func (s *TriggerServer) githubHandler(resp http.ResponseWriter, req *http.Request) {
|
2021-02-25 09:21:43 +00:00
|
|
|
// GitHub provides different webhook events for each registry.
|
|
|
|
// Github Package uses 'registry_package'
|
|
|
|
// Github Container Registry uses 'package_v2'
|
|
|
|
// events can be classified as 'X-GitHub-Event' in Request Header.
|
|
|
|
hookEvent := req.Header.Get("X-GitHub-Event")
|
|
|
|
|
|
|
|
var imageName, imageTag string
|
|
|
|
|
|
|
|
switch hookEvent {
|
2023-09-02 10:01:24 +00:00
|
|
|
case "package":
|
2021-02-25 09:21:43 +00:00
|
|
|
payload := new(githubPackageV2Webhook)
|
|
|
|
if err := json.NewDecoder(req.Body).Decode(payload); err != nil {
|
|
|
|
log.WithFields(log.Fields{
|
|
|
|
"error": err,
|
|
|
|
}).Error("trigger.githubHandler: failed to decode request")
|
|
|
|
resp.WriteHeader(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if payload.Package.Ecosystem != "CONTAINER" {
|
|
|
|
resp.WriteHeader(http.StatusBadRequest)
|
|
|
|
fmt.Fprintf(resp, "registry package type was not container")
|
|
|
|
}
|
|
|
|
|
|
|
|
if payload.Package.Name == "" { // github package name
|
|
|
|
resp.WriteHeader(http.StatusBadRequest)
|
|
|
|
fmt.Fprintf(resp, "repository name cannot be empty")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if payload.Package.Namespace == "" { // github package org
|
|
|
|
resp.WriteHeader(http.StatusBadRequest)
|
|
|
|
fmt.Fprintf(resp, "repository namespace cannot be empty")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if payload.Package.PackageVersion.ContainerMetadata.Tag.Name == "" { // tag
|
|
|
|
resp.WriteHeader(http.StatusBadRequest)
|
|
|
|
fmt.Fprintf(resp, "repository tag cannot be empty")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
imageName = strings.Join(
|
|
|
|
[]string{"ghcr.io", payload.Package.Namespace, payload.Package.Name},
|
|
|
|
"/",
|
|
|
|
)
|
|
|
|
imageTag = payload.Package.PackageVersion.ContainerMetadata.Tag.Name
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
case "registry_package":
|
|
|
|
payload := new(githubRegistryPackageWebhook)
|
|
|
|
if err := json.NewDecoder(req.Body).Decode(payload); err != nil {
|
|
|
|
log.WithFields(log.Fields{
|
|
|
|
"error": err,
|
|
|
|
}).Error("trigger.githubHandler: failed to decode request")
|
|
|
|
resp.WriteHeader(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-11-06 07:22:36 +00:00
|
|
|
if payload.RegistryPackage.PackageType != "CONTAINER" {
|
2021-02-25 09:21:43 +00:00
|
|
|
resp.WriteHeader(http.StatusBadRequest)
|
2024-11-06 07:22:36 +00:00
|
|
|
fmt.Fprintf(resp, "registry package type was not CONTAINER")
|
2021-02-25 09:21:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if payload.Repository.FullName == "" { // github package name
|
|
|
|
resp.WriteHeader(http.StatusBadRequest)
|
|
|
|
fmt.Fprintf(resp, "repository full name cannot be empty")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if payload.RegistryPackage.Name == "" { // github package name
|
|
|
|
resp.WriteHeader(http.StatusBadRequest)
|
|
|
|
fmt.Fprintf(resp, "repository package name cannot be empty")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if payload.RegistryPackage.PackageVersion.Version == "" { // tag
|
|
|
|
resp.WriteHeader(http.StatusBadRequest)
|
|
|
|
fmt.Fprintf(resp, "repository tag cannot be empty")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-09-02 10:01:24 +00:00
|
|
|
// XXX <jsonroot>.registry_package.package_version.package_url could work too but it ends with colon
|
2021-02-25 09:21:43 +00:00
|
|
|
imageName = strings.Join(
|
2023-09-02 10:01:24 +00:00
|
|
|
[]string{"ghcr.io", payload.Repository.FullName},
|
2021-02-25 09:21:43 +00:00
|
|
|
"/",
|
|
|
|
)
|
|
|
|
imageTag = payload.RegistryPackage.PackageVersion.Version
|
|
|
|
|
|
|
|
break
|
2019-11-01 06:43:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
event := types.Event{}
|
|
|
|
event.CreatedAt = time.Now()
|
|
|
|
event.TriggerName = "github"
|
2021-02-25 09:21:43 +00:00
|
|
|
event.Repository.Name = imageName
|
|
|
|
event.Repository.Tag = imageTag
|
2019-11-01 06:43:05 +00:00
|
|
|
|
|
|
|
s.trigger(event)
|
|
|
|
|
|
|
|
resp.WriteHeader(http.StatusOK)
|
|
|
|
|
|
|
|
newGithubWebhooksCounter.With(prometheus.Labels{"image": event.Repository.Name}).Inc()
|
|
|
|
}
|