feat: add midori skeleton, bot scaffolding, CD seeds

This commit is contained in:
41666 2020-09-27 00:32:15 -04:00
parent 7c861b37ca
commit 49d44df231
30 changed files with 854 additions and 123 deletions

41
src/midori/BUILD.bazel Normal file
View file

@ -0,0 +1,41 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
load("@io_bazel_rules_docker//go:image.bzl", "go_image")
load("@io_bazel_rules_docker//container:container.bzl", "container_push")
go_library(
name = "midori_lib",
srcs = ["midori.go"],
importpath = "github.com/roleypoly/roleypoly/src/midori",
visibility = ["//visibility:private"],
deps = [
"//src/common/bot",
"//src/common/version",
"//src/midori/internal/commands/gh",
"//src/midori/internal/commands/tfc",
"//src/midori/internal/config",
"@com_github_bwmarrin_discordgo//:discordgo",
"@com_github_joho_godotenv//autoload",
"@io_k8s_klog//:klog",
],
)
go_binary(
name = "midori",
embed = [":midori_lib"],
visibility = ["//visibility:public"],
)
go_image(
name = "image",
embed = [":midori_lib"],
visibility = ["//visibility:private"],
)
container_push(
name = "+publish",
format = "Docker",
image = ":image",
registry = "docker.pkg.github.com",
repository = "roleypoly/roleypoly/midori",
tag = "{STABLE_GIT_BRANCH}",
)

5
src/midori/README.md Normal file
View file

@ -0,0 +1,5 @@
# Midori
Midori is a GitOps/GitHub Actions/Terraform Cloud helper bot. In it's simplest form, it is a hotline into GitHub Actions and Terraform Cloud to run and act upon the actual pipelines and such.
This is **not** a public bot for very obvious reasons. You may host it yourself, but it is not a required part of a Roleypoly deployment.

View file

@ -0,0 +1,16 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "gh",
srcs = ["gh.go"],
importpath = "github.com/roleypoly/roleypoly/src/midori/internal/commands/gh",
visibility = ["//src/midori:__subpackages__"],
deps = [
"//src/common/bot",
"//src/midori/internal/commands/helpers",
"//src/midori/internal/config",
"@com_github_google_go_github_v32//github:go_default_library",
"@com_github_lampjaw_discordclient//:discordclient",
"@org_golang_x_oauth2//:oauth2",
],
)

View file

@ -0,0 +1,51 @@
package gh
import (
"context"
"encoding/json"
"strings"
"github.com/google/go-github/v32/github"
"github.com/lampjaw/discordclient"
"github.com/roleypoly/roleypoly/src/common/bot"
"github.com/roleypoly/roleypoly/src/midori/internal/commands/helpers"
"github.com/roleypoly/roleypoly/src/midori/internal/config"
"golang.org/x/oauth2"
)
type GitHubCommands struct {
ghClient *github.Client
}
func NewGitHubCommands() GitHubCommands {
ctx := context.Background()
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: config.GitHubToken},
)
tc := oauth2.NewClient(ctx, ts)
ghClient := github.NewClient(tc)
return GitHubCommands{
ghClient: ghClient,
}
}
func (ghc GitHubCommands) CommandGroup() bot.CommandGroup {
return bot.CommandGroup{
{
CommandName: "dispatch",
Handler: helpers.MustHaveElevatedPermissions(ghc.dispatch),
},
}
}
func (ghc GitHubCommands) dispatch(ctx context.Context, message discordclient.Message) {
tokens := bot.Tokenize(message)
repo, webhookName := tokens[0], tokens[1]
payload := json.RawMessage(strings.Join(tokens[2:], " "))
ghc.ghClient.Repositories.Dispatch(ctx, config.GitHubOrg, repo, github.DispatchRequestOptions{
EventType: webhookName,
ClientPayload: &payload,
})
}

View file

@ -0,0 +1,14 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "helpers",
srcs = ["permissions.go"],
importpath = "github.com/roleypoly/roleypoly/src/midori/internal/commands/helpers",
visibility = ["//src/midori:__subpackages__"],
deps = [
"//src/common",
"//src/common/bot",
"//src/midori/internal/config",
"@com_github_lampjaw_discordclient//:discordclient",
],
)

View file

@ -0,0 +1,27 @@
package helpers
import (
"context"
"github.com/lampjaw/discordclient"
"github.com/roleypoly/roleypoly/src/common"
"github.com/roleypoly/roleypoly/src/common/bot"
"github.com/roleypoly/roleypoly/src/midori/internal/config"
)
// MustHaveElevatedPermissions ensures a command has either Developer or Root role conditions.
func MustHaveElevatedPermissions(next bot.HandlerFunc) bot.HandlerFunc {
return func(ctx context.Context, message discordclient.Message) {
if common.FindString(message.UserID(), config.RootUsers) || common.FindString(message.UserID(), config.AllowlistedUsers) {
next(ctx, message)
return
}
NoPermissionsResponse(ctx, message)
}
}
// NoPermissionsResponse responds with a simple message that shows why the command failed.
func NoPermissionsResponse(ctx context.Context, message discordclient.Message) {
bot.ReplyToMessage(ctx, "⛔ You do not have elevated permissions.")
}

View file

@ -0,0 +1,13 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "tfc",
srcs = ["tfc.go"],
importpath = "github.com/roleypoly/roleypoly/src/midori/internal/commands/tfc",
visibility = ["//src/midori:__subpackages__"],
deps = [
"//src/common/bot",
"//src/midori/internal/commands/helpers",
"@com_github_lampjaw_discordclient//:discordclient",
],
)

View file

@ -0,0 +1,25 @@
package tfc
import (
"context"
"github.com/lampjaw/discordclient"
"github.com/roleypoly/roleypoly/src/common/bot"
"github.com/roleypoly/roleypoly/src/midori/internal/commands/helpers"
)
type TerraformCloudCommands struct {
}
func (tfcc TerraformCloudCommands) CommandGroup() bot.CommandGroup {
return bot.CommandGroup{
{
CommandName: "dispatch",
Handler: helpers.MustHaveElevatedPermissions(tfcc.dispatch),
},
}
}
func (tfcc TerraformCloudCommands) dispatch(ctx context.Context, message discordclient.Message) {
bot.ReplyToMessage(ctx, "Ok!")
}

View file

@ -0,0 +1,9 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "config",
srcs = ["config.go"],
importpath = "github.com/roleypoly/roleypoly/src/midori/internal/config",
visibility = ["//src/midori:__subpackages__"],
deps = ["//src/common"],
)

View file

@ -0,0 +1,15 @@
package config
import (
"github.com/roleypoly/roleypoly/src/common"
)
var (
BotToken = common.Getenv("MIDORI_BOT_TOKEN").String()
ClientID = common.Getenv("MIDORI_CLIENT_ID").String()
AllowlistedUsers = common.Getenv("MIDORI_DEVELOPERS").StringSlice()
CommandPrefix = common.Getenv("MIDORI_PREFIX_OVERRIDE", "midori").String()
RootUsers = common.Getenv("ROOT_USERS").StringSlice()
GitHubOrg = common.Getenv("MIDORI_GITHUB_ORG").String()
GitHubToken = common.Getenv("MIDORI_GITHUB_TOKEN").String()
)

33
src/midori/midori.go Normal file
View file

@ -0,0 +1,33 @@
package main
import (
"github.com/bwmarrin/discordgo"
_ "github.com/joho/godotenv/autoload"
"k8s.io/klog"
"github.com/roleypoly/roleypoly/src/common/bot"
"github.com/roleypoly/roleypoly/src/common/version"
"github.com/roleypoly/roleypoly/src/midori/internal/commands/gh"
"github.com/roleypoly/roleypoly/src/midori/internal/commands/tfc"
"github.com/roleypoly/roleypoly/src/midori/internal/config"
)
func main() {
klog.Info(version.StartupInfo("midori"))
mux := bot.NewCommandMux(bot.MentionMatcher(config.ClientID))
mux.RegisterCommandGroup("gh", gh.GitHubCommands{}.CommandGroup())
mux.RegisterCommandGroup("tfc", tfc.TerraformCloudCommands{}.CommandGroup())
err := bot.ScaffoldBot(bot.BotScaffolding{
AllowBots: false,
BotToken: config.BotToken,
BotClientID: config.ClientID,
RootUsers: config.RootUsers,
GatewayIntents: discordgo.IntentsGuildMessages,
Handler: mux.Handler,
})
if err != nil {
klog.Fatal(err)
}
}