mirror of
https://github.com/hatchet-dev/hatchet.git
synced 2025-12-30 13:19:44 -06:00
* feat: add posthog dep * feat: posthog analytics * feat: user events * fix: nil tenant * feat: tenant ident * chore: linting * Update pkg/analytics/posthog/posthog.go Co-authored-by: abelanger5 <belanger@sas.upenn.edu> * fix: typo --------- Co-authored-by: abelanger5 <belanger@sas.upenn.edu>
360 lines
15 KiB
Go
360 lines
15 KiB
Go
package server
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"time"
|
|
|
|
"github.com/rs/zerolog"
|
|
"github.com/spf13/viper"
|
|
"golang.org/x/oauth2"
|
|
|
|
"github.com/hatchet-dev/hatchet/internal/auth/cookie"
|
|
"github.com/hatchet-dev/hatchet/internal/auth/token"
|
|
"github.com/hatchet-dev/hatchet/internal/config/database"
|
|
"github.com/hatchet-dev/hatchet/internal/config/shared"
|
|
"github.com/hatchet-dev/hatchet/internal/encryption"
|
|
"github.com/hatchet-dev/hatchet/internal/integrations/vcs"
|
|
"github.com/hatchet-dev/hatchet/internal/msgqueue"
|
|
"github.com/hatchet-dev/hatchet/internal/services/ingestor"
|
|
"github.com/hatchet-dev/hatchet/internal/validator"
|
|
"github.com/hatchet-dev/hatchet/pkg/analytics"
|
|
"github.com/hatchet-dev/hatchet/pkg/client"
|
|
"github.com/hatchet-dev/hatchet/pkg/errors"
|
|
)
|
|
|
|
type ServerConfigFile struct {
|
|
Auth ConfigFileAuth `mapstructure:"auth" json:"auth,omitempty"`
|
|
|
|
Alerting AlertingConfigFile `mapstructure:"alerting" json:"alerting,omitempty"`
|
|
|
|
Analytics AnalyticsConfigFile `mapstructure:"analytics" json:"analytics,omitempty"`
|
|
|
|
Encryption EncryptionConfigFile `mapstructure:"encryption" json:"encryption,omitempty"`
|
|
|
|
Runtime ConfigFileRuntime `mapstructure:"runtime" json:"runtime,omitempty"`
|
|
|
|
MessageQueue MessageQueueConfigFile `mapstructure:"msgQueue" json:"msgQueue,omitempty"`
|
|
|
|
Services []string `mapstructure:"services" json:"services,omitempty" default:"[\"health\", \"ticker\", \"grpc\", \"eventscontroller\", \"jobscontroller\", \"workflowscontroller\", \"heartbeater\"]"`
|
|
|
|
TLS shared.TLSConfigFile `mapstructure:"tls" json:"tls,omitempty"`
|
|
|
|
Logger shared.LoggerConfigFile `mapstructure:"logger" json:"logger,omitempty"`
|
|
|
|
OpenTelemetry shared.OpenTelemetryConfigFile `mapstructure:"otel" json:"otel,omitempty"`
|
|
|
|
VCS ConfigFileVCS `mapstructure:"vcs" json:"vcs,omitempty"`
|
|
}
|
|
|
|
// General server runtime options
|
|
type ConfigFileRuntime struct {
|
|
// Port is the port that the core server listens on
|
|
Port int `mapstructure:"port" json:"port,omitempty" default:"8080"`
|
|
|
|
// ServerURL is the full server URL of the instance, including protocol.
|
|
ServerURL string `mapstructure:"url" json:"url,omitempty" default:"http://localhost:8080"`
|
|
|
|
// GRPCPort is the port that the grpc service listens on
|
|
GRPCPort int `mapstructure:"grpcPort" json:"grpcPort,omitempty" default:"7070"`
|
|
|
|
// GRPCBindAddress is the address that the grpc server binds to. Should set to 0.0.0.0 if binding in docker container.
|
|
GRPCBindAddress string `mapstructure:"grpcBindAddress" json:"grpcBindAddress,omitempty" default:"127.0.0.1"`
|
|
|
|
// GRPCBroadcastAddress is the address that the grpc server broadcasts to, which is what clients should use when connecting.
|
|
GRPCBroadcastAddress string `mapstructure:"grpcBroadcastAddress" json:"grpcBroadcastAddress,omitempty" default:"127.0.0.1:7070"`
|
|
|
|
// GRPCInsecure controls whether the grpc server is insecure or uses certs
|
|
GRPCInsecure bool `mapstructure:"grpcInsecure" json:"grpcInsecure,omitempty" default:"false"`
|
|
|
|
// Whether the internal worker is enabled for this instance
|
|
WorkerEnabled bool `mapstructure:"workerEnabled" json:"workerEnabled,omitempty" default:"false"`
|
|
|
|
// ShutdownWait is the time between the readiness probe being offline when a shutdown is triggered and the actual start of cleaning up resources.
|
|
ShutdownWait time.Duration `mapstructure:"shutdownWait" json:"shutdownWait,omitempty" default:"20s"`
|
|
}
|
|
|
|
// Alerting options
|
|
type AlertingConfigFile struct {
|
|
Sentry SentryConfigFile `mapstructure:"sentry" json:"sentry,omitempty"`
|
|
}
|
|
|
|
type SentryConfigFile struct {
|
|
// Enabled controls whether the Sentry service is enabled for this Hatchet instance.
|
|
Enabled bool `mapstructure:"enabled" json:"enabled,omitempty"`
|
|
|
|
// DSN is the Data Source Name for the Sentry instance
|
|
DSN string `mapstructure:"dsn" json:"dsn,omitempty"`
|
|
|
|
// Environment is the environment that the instance is running in
|
|
Environment string `mapstructure:"environment" json:"environment,omitempty" default:"development"`
|
|
}
|
|
|
|
type AnalyticsConfigFile struct {
|
|
Posthog PosthogConfigFile `mapstructure:"posthog" json:"posthog,omitempty"`
|
|
}
|
|
|
|
type PosthogConfigFile struct {
|
|
// Enabled controls whether the Posthog service is enabled for this Hatchet instance.
|
|
Enabled bool `mapstructure:"enabled" json:"enabled,omitempty"`
|
|
|
|
// APIKey is the API key for the Posthog instance
|
|
ApiKey string `mapstructure:"apiKey" json:"apiKey,omitempty"`
|
|
|
|
// Endpoint is the endpoint for the Posthog instance
|
|
Endpoint string `mapstructure:"endpoint" json:"endpoint,omitempty"`
|
|
}
|
|
|
|
// Encryption options
|
|
type EncryptionConfigFile struct {
|
|
// MasterKeyset is the raw master keyset for the instance. This should be a base64-encoded JSON string. You must set
|
|
// either MasterKeyset, MasterKeysetFile or cloudKms.enabled with CloudKMS credentials
|
|
MasterKeyset string `mapstructure:"masterKeyset" json:"masterKeyset,omitempty"`
|
|
|
|
// MasterKeysetFile is the path to the master keyset file for the instance.
|
|
MasterKeysetFile string `mapstructure:"masterKeysetFile" json:"masterKeysetFile,omitempty"`
|
|
|
|
JWT EncryptionConfigFileJWT `mapstructure:"jwt" json:"jwt,omitempty"`
|
|
|
|
// CloudKMS is the configuration for Google Cloud KMS. You must set either MasterKeyset or cloudKms.enabled.
|
|
CloudKMS EncryptionConfigFileCloudKMS `mapstructure:"cloudKms" json:"cloudKms,omitempty"`
|
|
}
|
|
|
|
type EncryptionConfigFileJWT struct {
|
|
// PublicJWTKeyset is a base64-encoded JSON string containing the public keyset which has been encrypted
|
|
// by the master key.
|
|
PublicJWTKeyset string `mapstructure:"publicJWTKeyset" json:"publicJWTKeyset,omitempty"`
|
|
|
|
// PublicJWTKeysetFile is the path to the public keyset file for the instance.
|
|
PublicJWTKeysetFile string `mapstructure:"publicJWTKeysetFile" json:"publicJWTKeysetFile,omitempty"`
|
|
|
|
// PrivateJWTKeyset is a base64-encoded JSON string containing the private keyset which has been encrypted
|
|
// by the master key.
|
|
PrivateJWTKeyset string `mapstructure:"privateJWTKeyset" json:"privateJWTKeyset,omitempty"`
|
|
|
|
// PrivateJWTKeysetFile is the path to the private keyset file for the instance.
|
|
PrivateJWTKeysetFile string `mapstructure:"privateJWTKeysetFile" json:"privateJWTKeysetFile,omitempty"`
|
|
}
|
|
|
|
type EncryptionConfigFileCloudKMS struct {
|
|
// Enabled controls whether the Cloud KMS service is enabled for this Hatchet instance.
|
|
Enabled bool `mapstructure:"enabled" json:"enabled,omitempty" default:"false"`
|
|
|
|
// KeyURI is the URI of the key in Google Cloud KMS. This should be in the format of
|
|
// gcp-kms://...
|
|
KeyURI string `mapstructure:"keyURI" json:"keyURI,omitempty"`
|
|
|
|
// CredentialsJSON is the JSON credentials for the Google Cloud KMS service account.
|
|
CredentialsJSON string `mapstructure:"credentialsJSON" json:"credentialsJSON,omitempty"`
|
|
}
|
|
|
|
type ConfigFileAuth struct {
|
|
// RestrictedEmailDomains sets the restricted email domains for the instance.
|
|
RestrictedEmailDomains []string `mapstructure:"restrictedEmailDomains" json:"restrictedEmailDomains,omitempty"`
|
|
|
|
// BasedAuthEnabled controls whether email and password-based login is enabled for this
|
|
// Hatchet instance
|
|
BasicAuthEnabled bool `mapstructure:"basicAuthEnabled" json:"basicAuthEnabled,omitempty" default:"true"`
|
|
|
|
// SetEmailVerified controls whether the user's email is automatically set to verified
|
|
SetEmailVerified bool `mapstructure:"setEmailVerified" json:"setEmailVerified,omitempty" default:"false"`
|
|
|
|
// Configuration options for the cookie
|
|
Cookie ConfigFileAuthCookie `mapstructure:"cookie" json:"cookie,omitempty"`
|
|
|
|
Google ConfigFileAuthGoogle `mapstructure:"google" json:"google,omitempty"`
|
|
|
|
Github ConfigFileAuthGithub `mapstructure:"github" json:"github,omitempty"`
|
|
}
|
|
|
|
type ConfigFileVCS struct {
|
|
Github ConfigFileGithub `mapstructure:"github" json:"github,omitempty"`
|
|
}
|
|
|
|
type ConfigFileGithub struct {
|
|
Enabled bool `mapstructure:"enabled" json:"enabled"`
|
|
GithubAppClientID string `mapstructure:"appClientID" json:"appClientID,omitempty"`
|
|
GithubAppClientSecret string `mapstructure:"appClientSecret" json:"appClientSecret,omitempty"`
|
|
GithubAppName string `mapstructure:"appName" json:"appName,omitempty"`
|
|
GithubAppWebhookSecret string `mapstructure:"appWebhookSecret" json:"appWebhookSecret,omitempty"`
|
|
GithubAppWebhookURL string `mapstructure:"appWebhookURL" json:"appWebhookURL,omitempty"`
|
|
GithubAppID string `mapstructure:"appID" json:"appID,omitempty"`
|
|
GithubAppSecretPath string `mapstructure:"appSecretPath" json:"appSecretPath,omitempty"`
|
|
}
|
|
|
|
type ConfigFileAuthGoogle struct {
|
|
Enabled bool `mapstructure:"enabled" json:"enabled,omitempty" default:"false"`
|
|
|
|
ClientID string `mapstructure:"clientID" json:"clientID,omitempty"`
|
|
ClientSecret string `mapstructure:"clientSecret" json:"clientSecret,omitempty"`
|
|
Scopes []string `mapstructure:"scopes" json:"scopes,omitempty" default:"[\"openid\", \"profile\", \"email\"]"`
|
|
}
|
|
|
|
type ConfigFileAuthGithub struct {
|
|
Enabled bool `mapstructure:"enabled" json:"enabled,omitempty" default:"false"`
|
|
|
|
ClientID string `mapstructure:"clientID" json:"clientID,omitempty"`
|
|
ClientSecret string `mapstructure:"clientSecret" json:"clientSecret,omitempty"`
|
|
Scopes []string `mapstructure:"scopes" json:"scopes,omitempty" default:"[\"read:user\", \"user:email\"]"`
|
|
}
|
|
|
|
type ConfigFileAuthCookie struct {
|
|
Name string `mapstructure:"name" json:"name,omitempty" default:"hatchet"`
|
|
Domain string `mapstructure:"domain" json:"domain,omitempty"`
|
|
Secrets string `mapstructure:"secrets" json:"secrets,omitempty"`
|
|
Insecure bool `mapstructure:"insecure" json:"insecure,omitempty" default:"false"`
|
|
}
|
|
|
|
type MessageQueueConfigFile struct {
|
|
Kind string `mapstructure:"kind" json:"kind,omitempty" validate:"required"`
|
|
|
|
RabbitMQ RabbitMQConfigFile `mapstructure:"rabbitmq" json:"rabbitmq,omitempty" validate:"required"`
|
|
}
|
|
|
|
type RabbitMQConfigFile struct {
|
|
URL string `mapstructure:"url" json:"url,omitempty" validate:"required" default:"amqp://user:password@localhost:5672/"`
|
|
}
|
|
|
|
type AuthConfig struct {
|
|
ConfigFile ConfigFileAuth
|
|
|
|
GoogleOAuthConfig *oauth2.Config
|
|
|
|
GithubOAuthConfig *oauth2.Config
|
|
|
|
JWTManager token.JWTManager
|
|
}
|
|
|
|
type ServerConfig struct {
|
|
*database.Config
|
|
|
|
Auth AuthConfig
|
|
|
|
Alerter errors.Alerter
|
|
|
|
Analytics analytics.Analytics
|
|
|
|
Encryption encryption.EncryptionService
|
|
|
|
Runtime ConfigFileRuntime
|
|
|
|
Services []string
|
|
|
|
Namespaces []string
|
|
|
|
MessageQueue msgqueue.MessageQueue
|
|
|
|
Logger *zerolog.Logger
|
|
|
|
TLSConfig *tls.Config
|
|
|
|
SessionStore *cookie.UserSessionStore
|
|
|
|
Validator validator.Validator
|
|
|
|
Ingestor ingestor.Ingestor
|
|
|
|
OpenTelemetry shared.OpenTelemetryConfigFile
|
|
|
|
VCSProviders map[vcs.VCSRepositoryKind]vcs.VCSProvider
|
|
|
|
InternalClient client.Client
|
|
}
|
|
|
|
func (c *ServerConfig) HasService(name string) bool {
|
|
for _, s := range c.Services {
|
|
if s == name {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func BindAllEnv(v *viper.Viper) {
|
|
// runtime options
|
|
_ = v.BindEnv("runtime.port", "SERVER_PORT")
|
|
_ = v.BindEnv("runtime.url", "SERVER_URL")
|
|
_ = v.BindEnv("runtime.grpcPort", "SERVER_GRPC_PORT")
|
|
_ = v.BindEnv("runtime.grpcBindAddress", "SERVER_GRPC_BIND_ADDRESS")
|
|
_ = v.BindEnv("runtime.grpcBroadcastAddress", "SERVER_GRPC_BROADCAST_ADDRESS")
|
|
_ = v.BindEnv("runtime.grpcInsecure", "SERVER_GRPC_INSECURE")
|
|
_ = v.BindEnv("runtime.workerEnabled", "SERVER_WORKER_ENABLED")
|
|
_ = v.BindEnv("runtime.shutdownWait", "SERVER_SHUTDOWN_WAIT")
|
|
_ = v.BindEnv("services", "SERVER_SERVICES")
|
|
|
|
// alerting options
|
|
_ = v.BindEnv("alerting.sentry.enabled", "SERVER_ALERTING_SENTRY_ENABLED")
|
|
_ = v.BindEnv("alerting.sentry.dsn", "SERVER_ALERTING_SENTRY_DSN")
|
|
_ = v.BindEnv("alerting.sentry.environment", "SERVER_ALERTING_SENTRY_ENVIRONMENT")
|
|
|
|
// analytics options
|
|
_ = v.BindEnv("analytics.posthog.enabled", "SERVER_ANALYTICS_POSTHOG_ENABLED")
|
|
_ = v.BindEnv("analytics.posthog.apiKey", "SERVER_ANALYTICS_POSTHOG_API_KEY")
|
|
_ = v.BindEnv("analytics.posthog.endpoint", "SERVER_ANALYTICS_POSTHOG_ENDPOINT")
|
|
|
|
// encryption options
|
|
_ = v.BindEnv("encryption.masterKeyset", "SERVER_ENCRYPTION_MASTER_KEYSET")
|
|
_ = v.BindEnv("encryption.masterKeysetFile", "SERVER_ENCRYPTION_MASTER_KEYSET_FILE")
|
|
_ = v.BindEnv("encryption.jwt.publicJWTKeyset", "SERVER_ENCRYPTION_JWT_PUBLIC_KEYSET")
|
|
_ = v.BindEnv("encryption.jwt.publicJWTKeysetFile", "SERVER_ENCRYPTION_JWT_PUBLIC_KEYSET_FILE")
|
|
_ = v.BindEnv("encryption.jwt.privateJWTKeyset", "SERVER_ENCRYPTION_JWT_PRIVATE_KEYSET")
|
|
_ = v.BindEnv("encryption.jwt.privateJWTKeysetFile", "SERVER_ENCRYPTION_JWT_PRIVATE_KEYSET_FILE")
|
|
_ = v.BindEnv("encryption.cloudKms.enabled", "SERVER_ENCRYPTION_CLOUDKMS_ENABLED")
|
|
_ = v.BindEnv("encryption.cloudKms.keyURI", "SERVER_ENCRYPTION_CLOUDKMS_KEY_URI")
|
|
_ = v.BindEnv("encryption.cloudKms.credentialsJSON", "SERVER_ENCRYPTION_CLOUDKMS_CREDENTIALS_JSON")
|
|
|
|
// auth options
|
|
_ = v.BindEnv("auth.restrictedEmailDomains", "SERVER_AUTH_RESTRICTED_EMAIL_DOMAINS")
|
|
_ = v.BindEnv("auth.basicAuthEnabled", "SERVER_AUTH_BASIC_AUTH_ENABLED")
|
|
_ = v.BindEnv("auth.setEmailVerified", "SERVER_AUTH_SET_EMAIL_VERIFIED")
|
|
_ = v.BindEnv("auth.cookie.name", "SERVER_AUTH_COOKIE_NAME")
|
|
_ = v.BindEnv("auth.cookie.domain", "SERVER_AUTH_COOKIE_DOMAIN")
|
|
_ = v.BindEnv("auth.cookie.secrets", "SERVER_AUTH_COOKIE_SECRETS")
|
|
_ = v.BindEnv("auth.cookie.insecure", "SERVER_AUTH_COOKIE_INSECURE")
|
|
_ = v.BindEnv("auth.google.enabled", "SERVER_AUTH_GOOGLE_ENABLED")
|
|
_ = v.BindEnv("auth.google.clientID", "SERVER_AUTH_GOOGLE_CLIENT_ID")
|
|
_ = v.BindEnv("auth.google.clientSecret", "SERVER_AUTH_GOOGLE_CLIENT_SECRET")
|
|
_ = v.BindEnv("auth.google.scopes", "SERVER_AUTH_GOOGLE_SCOPES")
|
|
_ = v.BindEnv("auth.github.enabled", "SERVER_AUTH_GITHUB_ENABLED")
|
|
_ = v.BindEnv("auth.github.clientID", "SERVER_AUTH_GITHUB_CLIENT_ID")
|
|
_ = v.BindEnv("auth.github.clientSecret", "SERVER_AUTH_GITHUB_CLIENT_SECRET")
|
|
_ = v.BindEnv("auth.github.scopes", "SERVER_AUTH_GITHUB_SCOPES")
|
|
|
|
// task queue options
|
|
// legacy options
|
|
_ = v.BindEnv("msgQueue.kind", "SERVER_TASKQUEUE_KIND")
|
|
_ = v.BindEnv("msgQueue.rabbitmq.url", "SERVER_TASKQUEUE_RABBITMQ_URL")
|
|
|
|
_ = v.BindEnv("msgQueue.kind", "SERVER_MSGQUEUE_KIND")
|
|
_ = v.BindEnv("msgQueue.rabbitmq.url", "SERVER_MSGQUEUE_RABBITMQ_URL")
|
|
|
|
// tls options
|
|
_ = v.BindEnv("tls.tlsStrategy", "SERVER_TLS_STRATEGY")
|
|
_ = v.BindEnv("tls.tlsCert", "SERVER_TLS_CERT")
|
|
_ = v.BindEnv("tls.tlsCertFile", "SERVER_TLS_CERT_FILE")
|
|
_ = v.BindEnv("tls.tlsKey", "SERVER_TLS_KEY")
|
|
_ = v.BindEnv("tls.tlsKeyFile", "SERVER_TLS_KEY_FILE")
|
|
_ = v.BindEnv("tls.tlsRootCA", "SERVER_TLS_ROOT_CA")
|
|
_ = v.BindEnv("tls.tlsRootCAFile", "SERVER_TLS_ROOT_CA_FILE")
|
|
_ = v.BindEnv("tls.tlsServerName", "SERVER_TLS_SERVER_NAME")
|
|
|
|
// logger options
|
|
_ = v.BindEnv("logger.level", "SERVER_LOGGER_LEVEL")
|
|
_ = v.BindEnv("logger.format", "SERVER_LOGGER_FORMAT")
|
|
|
|
// otel options
|
|
_ = v.BindEnv("otel.serviceName", "SERVER_OTEL_SERVICE_NAME")
|
|
_ = v.BindEnv("otel.collectorURL", "SERVER_OTEL_COLLECTOR_URL")
|
|
|
|
// vcs options
|
|
_ = v.BindEnv("vcs.kind", "SERVER_VCS_KIND")
|
|
_ = v.BindEnv("vcs.github.enabled", "SERVER_VCS_GITHUB_ENABLED")
|
|
_ = v.BindEnv("vcs.github.appClientID", "SERVER_VCS_GITHUB_APP_CLIENT_ID")
|
|
_ = v.BindEnv("vcs.github.appClientSecret", "SERVER_VCS_GITHUB_APP_CLIENT_SECRET")
|
|
_ = v.BindEnv("vcs.github.appName", "SERVER_VCS_GITHUB_APP_NAME")
|
|
_ = v.BindEnv("vcs.github.appWebhookSecret", "SERVER_VCS_GITHUB_APP_WEBHOOK_SECRET")
|
|
_ = v.BindEnv("vcs.github.appWebhookURL", "SERVER_VCS_GITHUB_APP_WEBHOOK_URL")
|
|
_ = v.BindEnv("vcs.github.appID", "SERVER_VCS_GITHUB_APP_ID")
|
|
_ = v.BindEnv("vcs.github.appSecretPath", "SERVER_VCS_GITHUB_APP_SECRET_PATH")
|
|
}
|