diff --git a/.example.env b/.example.env new file mode 100644 index 0000000..5db1516 --- /dev/null +++ b/.example.env @@ -0,0 +1,3 @@ +GOSCAN__forgejo__URL= +GOSCAN__forgejo__BOT_TOKEN= +GOSCAN__forgejo__SECRET= \ No newline at end of file diff --git a/.gitignore b/.gitignore index 69849cf..0e9397d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,167 +9,14 @@ # Local History for Visual Studio Code .history/ -# Built Visual Studio Code Extensions -*.vsix - .idea .fleet -# ---> Go -# If you prefer the allow list template instead of the deny list, see community template: -# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore -# -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib # Test binary, built with `go test -c` *.test -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ - # Go workspace file go.work go.work.sum -# env file -.env - -# ---> Node -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp -.cache - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - +config.yml \ No newline at end of file diff --git a/README.md b/README.md index 07a64dc..bbf4c86 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Gosec with some stuff with actions. name: GoSec Scan on: schedule: - - cron: "@daily" + - cron: "@weekly" push: branches: ["main"] workflow_dispatch: @@ -19,10 +19,6 @@ jobs: steps: - name: Checkout uses: https://git.shadowhosting.xyz/actions/checkout@v4 - - uses: https://git.shadowhosting.xyz/actions/setup-go@v5 - with: - go-version: '1.22' - - run: go mod download - name: Run Gosec Security Scanner uses: https://git.shadowhosting.xyz/actions/goscan@main ``` \ No newline at end of file diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..0649b79 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,23 @@ +version: '3' + +tasks: + build-daemon: + cmds: + - docker buildx build --platform=linux/amd64,linux/arm64/v8 --push -t git.shadowhosting.xyz/actions/goscan-daemon -f docker/Daemon.Dockerfile . + build-action: + cmds: + - docker buildx build --platform=linux/amd64,linux/arm64/v8 --push -t git.shadowhosting.xyz/actions/goscan -f docker/Action.Dockerfile . + build: + cmds: + - task: build-daemon + - task: build-action + build-dev-daemon: + cmds: + - docker build -t goscan-dev-daemon -f docker/Daemon.Dockerfile . + build-dev-action: + cmds: + - docker build -t goscan-dev-action -f docker/Action.Dockerfile . + build-dev: + cmds: + - task: build-dev-daemon + - task: build-dev-action \ No newline at end of file diff --git a/build.sh b/build.sh deleted file mode 100644 index 100ad2d..0000000 --- a/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -docker buildx build --platform=linux/amd64,linux/arm64/v8 --push -t git.shadowhosting.xyz/actions/goscan . \ No newline at end of file diff --git a/cmd/daemon.go b/cmd/daemon.go new file mode 100644 index 0000000..d09e9c4 --- /dev/null +++ b/cmd/daemon.go @@ -0,0 +1,447 @@ +/* +Package cmd +Copyright © 2024 Shane C. +*/ +package cmd + +import ( + "bufio" + "bytes" + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "git.shadowhosting.xyz/actions/goscan/interfaces" + "git.shadowhosting.xyz/shanec/forgejo-sdk/forgejo" + "github.com/ProtonMail/go-crypto/openpgp" + "github.com/ProtonMail/go-crypto/openpgp/armor" + "github.com/ProtonMail/go-crypto/openpgp/packet" + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/config" + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/object" + gitHttp "github.com/go-git/go-git/v5/plumbing/transport/http" + "github.com/goccy/go-json" + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/log" + "github.com/gofiber/fiber/v2/middleware/healthcheck" + "github.com/gofiber/fiber/v2/middleware/limiter" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "io" + "io/fs" + "net/http" + "os" + "strings" + "text/template" + "time" +) + +type ActionTemplate struct { + DefaultBranch string + ServerURL string +} + +const actionTemplate = `name: GoSec Scan +on: + schedule: + - cron: "@weekly" + push: + branches: ["{{.DefaultBranch}}"] + workflow_dispatch: + +jobs: + gosec: + name: Gosec Check + runs-on: node20-bookworm + steps: + - name: Checkout + uses: {{.ServerURL}}/actions/checkout@v4 + - name: Run Gosec Security Scanner + uses: {{.ServerURL}}/actions/goscan@main +` + +type OpenPGPEntity struct { + *openpgp.Entity +} + +func (e *OpenPGPEntity) Sign(message io.Reader) ([]byte, error) { + + signatureBuffer := bytes.NewBuffer(nil) + if err := openpgp.DetachSignText(signatureBuffer, e.Entity, message, nil); err != nil { + return nil, err + } + + return signatureBuffer.Bytes(), nil +} + +// Sign(message io.Reader) ([]byte, error) + +// daemonCmd represents the daemon command +var daemonCmd = &cobra.Command{ + Use: "daemon", + Short: "A brief description of your command", + Run: func(cmd *cobra.Command, args []string) { + + forgeClient, err := forgejo.NewClient(viper.GetString("forgejo.url"), forgejo.SetToken(viper.GetString("forgejo.bot_token"))) + if err != nil { + log.Fatal(err) + } + + user, _, err := forgeClient.GetMyUserInfo() + if err != nil { + log.Fatal(err) + } + + conf := &packet.Config{ + Algorithm: packet.PubKeyAlgoEdDSA, + Curve: packet.Curve25519, + DefaultCipher: packet.CipherAES256, + } + + var pgpEntity OpenPGPEntity + + if _, err := os.Stat(os.Getenv("HOME") + "/keyring.pgp"); err != nil { + if errors.Is(err, fs.ErrNotExist) { + entity, err := openpgp.NewEntity("GoSec Git Signing", "", "gosec@git.shadowhosting.xyz", conf) + if err != nil { + log.Fatal(err) + } + + publicKeyBuffer := bytes.NewBuffer(nil) + publicKeyEncoder, err := armor.Encode(publicKeyBuffer, openpgp.PublicKeyType, nil) + if err != nil { + log.Fatal(err) + } + defer publicKeyEncoder.Close() + + err = entity.Serialize(publicKeyEncoder) + if err != nil { + log.Fatal(err) + } + + publicKeyEncoder.Close() + publicKeyArmor := publicKeyBuffer.String() + + file, err := os.OpenFile("keyring.pgp", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + log.Fatal(err) + } + err = entity.SerializePrivate(file, conf) + file.Close() + + token, _, err := forgeClient.GetGPGToken() + if err != nil { + log.Fatal(err) + } + + signatureBuffer := bytes.NewBuffer(nil) + if err := openpgp.DetachSignText(signatureBuffer, entity, strings.NewReader(token), conf); err != nil { + log.Fatal(err) + } + + encodedSignatureBuffer := bytes.NewBuffer(nil) + signatureEncoder, err := armor.Encode(encodedSignatureBuffer, openpgp.SignatureType, nil) + if err != nil { + log.Fatal(err) + } + defer signatureEncoder.Close() + signatureEncoder.Write(signatureBuffer.Bytes()) + signatureEncoder.Close() + + if _, _, err := forgeClient.CreateGPGKey(forgejo.CreateGPGKeyOption{ + ArmoredKey: publicKeyArmor, + ArmoredSignature: encodedSignatureBuffer.String(), + }); err != nil { + log.Fatal(err) + } + pgpEntity = OpenPGPEntity{ + Entity: entity, + } + } else { + log.Fatal(err) + } + } else if err == nil { + publicKeyFile, err := os.ReadFile(os.Getenv("HOME") + "/keyring.pgp") + if err != nil { + log.Fatal(err) + } + + el, err := openpgp.ReadKeyRing(bytes.NewReader(publicKeyFile)) + if err != nil { + log.Fatal(err) + } + + if len(el) != 1 { + log.Fatal("invalid keyring") + } + + pgpEntity = OpenPGPEntity{ + Entity: el[0], + } + } + + appConfig := fiber.Config{ + AppName: "GoScan (GoSec & Forgejo)", + Network: fiber.NetworkTCP, + JSONDecoder: json.Unmarshal, + JSONEncoder: json.Marshal, + EnableIPValidation: true, + } + + if len(viper.GetString("webserver.proxy")) != 0 { + switch strings.ToLower("webserver.proxy") { + case "cloudflare": + var trustedProxies []string + v4Req, err := http.NewRequest("GET", "https://www.cloudflare.com/ips-v4/#", nil) + if err != nil { + log.Fatal("error creating request", err) + } + + v6Req, err := http.NewRequest("GET", "https://www.cloudflare.com/ips-v6/#", nil) + if err != nil { + log.Fatal("error creating request", err) + } + + client := &http.Client{} + + v4Resp, err := client.Do(v4Req) + if err != nil { + log.Fatal("error doing request", err) + } + defer v4Resp.Body.Close() + + v4Scanner := bufio.NewScanner(v4Resp.Body) + v4Scanner.Split(bufio.ScanLines) + + for v4Scanner.Scan() { + trustedProxies = append(trustedProxies, v4Scanner.Text()) + } + + v6Resp, err := client.Do(v6Req) + if err != nil { + log.Fatal("error doing request", err) + } + defer v6Resp.Body.Close() + + v6Scanner := bufio.NewScanner(v6Resp.Body) + v6Scanner.Split(bufio.ScanLines) + + for v6Scanner.Scan() { + trustedProxies = append(trustedProxies, v6Scanner.Text()) + } + appConfig.TrustedProxies = trustedProxies + appConfig.ProxyHeader = "Cf-Connecting-Ip" + appConfig.EnableTrustedProxyCheck = true + default: + log.Warnf("Unknown proxy type: %s", viper.GetString("webserver.proxy")) + } + } + + app := fiber.New(appConfig) + + app.Use(healthcheck.New()) + app.Use(limiter.New(limiter.Config{ + Max: 175, + Expiration: 25 * time.Second, + LimiterMiddleware: limiter.SlidingWindow{}, + })) + + app.Post("/webhook", func(c *fiber.Ctx) error { + + event := c.Get("X-Forgejo-Event") + signature := c.Get("X-Forgejo-Signature") + bodyType := c.Get("Content-Type") + + if len(event) == 0 || len(signature) == 0 || bodyType != "application/json" { + return c.SendStatus(fiber.StatusBadRequest) + } + + mac := hmac.New(sha256.New, []byte(viper.GetString("forgejo.secret"))) + mac.Write(c.Body()) + bodyHash := hex.EncodeToString(mac.Sum(nil)) + if signature != bodyHash { + return c.SendStatus(fiber.StatusBadRequest) + } + + switch event { + case "push": + pushEvBody := new(interfaces.ForgejoPushEvent) + if err := c.BodyParser(pushEvBody); err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusBadRequest) + } + return handlePush(c, forgeClient, pushEvBody) + case "issues": + issueEvBody := new(interfaces.ForgejoIssueEvent) + if err := c.BodyParser(issueEvBody); err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusBadRequest) + } + return handleIssues(c, forgeClient, issueEvBody, pgpEntity, user) + default: + return c.SendStatus(fiber.StatusBadRequest) + } + + }) + + if err := app.Listen("0.0.0.0:9000"); err != nil { + log.Fatal("error running webserver", err) + } + + }, +} + +func handlePush(c *fiber.Ctx, forgeClient *forgejo.Client, event *interfaces.ForgejoPushEvent) error { + return c.SendStatus(fiber.StatusOK) +} + +func handleIssues(c *fiber.Ctx, forgeClient *forgejo.Client, event *interfaces.ForgejoIssueEvent, entity OpenPGPEntity, user *forgejo.User) error { + if event.Action == "opened" && event.Issue.Title == "setup:goscan" { + if _, err := forgeClient.CreateRepoActionSecret(event.Issue.Repo.Owner, event.Issue.Repo.Name, forgejo.CreateSecretOption{ + Name: "goscan_token", + Data: "hello!", + }); err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + + gitDir, err := os.MkdirTemp("", "goscan-*") + if err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + defer func(path string) { + err := os.RemoveAll(path) + if err != nil { + panic(err) + } + }(gitDir) + + repo, err := git.PlainClone(gitDir, false, &git.CloneOptions{ + URL: event.Repo.CloneURL.String(), + ReferenceName: plumbing.NewBranchReferenceName(event.Repo.DefaultBranch), + Depth: 1, + Auth: &gitHttp.BasicAuth{ + Username: "gosec", + Password: viper.GetString("forgejo.bot_token"), + }, + }) + if err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + + if err := repo.CreateBranch(&config.Branch{ + Name: plumbing.NewBranchReferenceName("goscan/setup").String(), + }); err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + + worktree, err := repo.Worktree() + if err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + + if err := os.MkdirAll(gitDir+"/.forgejo/workflows", 0775); err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + + if err := worktree.Checkout(&git.CheckoutOptions{ + Branch: plumbing.NewBranchReferenceName("goscan/setup"), + Create: true, + }); err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + + tmpl, err := template.New("action_tmpl").Parse(actionTemplate) + if err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + + var tmplBuffer bytes.Buffer + err = tmpl.Execute(&tmplBuffer, ActionTemplate{ + DefaultBranch: event.Repo.DefaultBranch, + ServerURL: viper.GetString("forgejo.url"), + }) + if err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + + if err := os.WriteFile(gitDir+"/.forgejo/workflows/gosec.yml", []byte(tmplBuffer.String()), 0666); err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + + if _, err := worktree.Add(".forgejo/workflows/gosec.yml"); err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + + signature := &object.Signature{ + Name: user.FullName, + Email: user.Email, + When: time.Now(), + } + + if _, err := worktree.Commit("Add GoScan action", &git.CommitOptions{ + SignKey: entity.Entity, + Author: signature, + Committer: signature, + }); err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + + if err := repo.Push(&git.PushOptions{ + RemoteName: "origin", + Auth: &gitHttp.BasicAuth{ + Username: "gosec", + Password: viper.GetString("forgejo.bot_token"), + }, + }); err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + + pr, _, err := forgeClient.CreatePullRequest(event.Issue.Repo.Owner, event.Issue.Repo.Name, forgejo.CreatePullRequestOption{ + Base: event.Repo.DefaultBranch, + Head: "goscan/setup", + Assignees: []string{event.Issue.User.Username}, + Title: "Setup GoScan", + Body: "Here is a default workflow configuration for gosec, feel free to edit it to your liking!", + }) + if err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + + if _, _, err := forgeClient.CreateIssueComment(event.Issue.Repo.Owner, event.Issue.Repo.Name, int64(event.Issue.Number), forgejo.CreateIssueCommentOption{ + Body: fmt.Sprintf("@%s\nCreated GoScan Secret and created a [Pull Request](%s)", event.Issue.User.Username, pr.HTMLURL), + }); err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + + stateClosed := forgejo.StateClosed + if _, _, err := forgeClient.EditIssue(event.Issue.Repo.Owner, event.Issue.Repo.Name, int64(event.Issue.Number), forgejo.EditIssueOption{ + State: &stateClosed, //?? + }); err != nil { + log.Error(err) + return c.SendStatus(fiber.StatusInternalServerError) + } + + } + return c.SendStatus(fiber.StatusOK) +} + +func init() { + rootCmd.AddCommand(daemonCmd) +} diff --git a/cmd/root.go b/cmd/root.go index 05c7e2a..99df7d6 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -5,13 +5,14 @@ Copyright © 2024 Shane C. package cmd import ( - "codeberg.org/mvdkleijn/forgejo-sdk/forgejo" "fmt" "git.eggactyl.cloud/Eggactyl/shell/linux" + "git.shadowhosting.xyz/shanec/forgejo-sdk/forgejo" "github.com/go-git/go-git/v5" "github.com/nao1215/markdown" "github.com/owenrumney/go-sarif/sarif" "github.com/sethvargo/go-githubactions" + "github.com/spf13/viper" "log" "os" "strconv" @@ -121,12 +122,7 @@ var rootCmd = &cobra.Command{ } var linkToFile strings.Builder - - if isGithub { - linkToFile.WriteString("./blob/commit/") - } else { - linkToFile.WriteString("./src/commit/") - } + linkToFile.WriteString("./src/commit/") linkToFile.WriteString(ref.Hash().String() + "/" + *location.PhysicalLocation.ArtifactLocation.URI + "#L" + strconv.Itoa(*location.PhysicalLocation.Region.StartLine)) @@ -239,6 +235,73 @@ func Execute() { } func init() { + cobra.OnInitialize(initConfig) rootCmd.Flags().BoolVar(&isAction, "is-action", false, "If set, will run some things specific to git actions") - rootCmd.Flags().BoolVar(&isGithub, "is-github", false, "If set, will change some outputs to support github") +} + +func initConfig() { + viper.AddConfigPath("/opt/goscan") + viper.SetConfigType("yaml") + viper.SetConfigName("config") + + viper.AutomaticEnv() // read in environment variables that match + + // If a config file is found, read it in. + if err := viper.ReadInConfig(); err == nil { + fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) + } + + for _, variable := range os.Environ() { + + if strings.HasPrefix(variable, "GOSCAN__") { + + sepEnv := strings.SplitN(variable, "=", 1) + key := sepEnv[0] + value := sepEnv[1] + + key = strings.Replace(key, "GOSCAN__", "", 1) + + if strings.HasPrefix(key, "database") { + key = strings.Replace(key, "database", "", 1) + switch strings.ToLower(key) { + case "host": + viper.Set("database.host", value) + case "port": + viper.Set("database.port", value) + case "user": + viper.Set("database.user", value) + case "password": + viper.Set("database.password", value) + case "name": + viper.Set("database.name", value) + case "tz": + viper.Set("database.tz", value) + default: + log.Fatalln("invalid config option") + } + } else if strings.HasPrefix(key, "forgejo") { + key = strings.Replace(key, "forgejo", "", 1) + switch strings.ToLower(key) { + case "url": + viper.Set("forgejo.url", value) + case "bot_token": + viper.Set("forgejo.bot_token", value) + case "secret": + viper.Set("forgejo.secret", value) + default: + log.Fatalln("invalid config option") + } + } else { + log.Fatalln("invalid config option") + } + + } + + } + + if len(viper.ConfigFileUsed()) != 0 { + if err := viper.WriteConfig(); err != nil { + log.Fatalln("error writing to file", err) + } + } } diff --git a/cmd/root_dev.go b/cmd/root_dev.go new file mode 100644 index 0000000..61c2a03 --- /dev/null +++ b/cmd/root_dev.go @@ -0,0 +1,17 @@ +//go:build dev + +package cmd + +import ( + "os" + + "github.com/spf13/viper" +) + +func init() { + path, err := os.Getwd() + if err != nil { + panic(err) + } + viper.AddConfigPath(path) +} diff --git a/Dockerfile b/docker/Action.Dockerfile similarity index 57% rename from Dockerfile rename to docker/Action.Dockerfile index e98051f..2fe9475 100644 --- a/Dockerfile +++ b/docker/Action.Dockerfile @@ -7,12 +7,17 @@ RUN go mod download && go mod verify RUN CGO_ENABLED=0 go build -ldflags="-s -w" -trimpath -o build/goscan FROM alpine:3.20 +LABEL maintainer="shane@scaffoe.com" \ + org.opencontainers.image.authors="Shane C." \ + org.opencontainers.image.source="https://git.shadowhosting.xyz/shanec/goscan" \ + org.opencontainers.image.licenses="Unlicense" \ + org.opencontainers.image.title="GoScan (GoSec Scanner for Forgejo)" RUN apk --no-cache update && apk --no-cache upgrade && apk add curl COPY --from=builder /usr/local/go /usr/local/go COPY --from=builder /app/build/goscan /goscan -COPY ./entrypoint.sh /entrypoint.sh +COPY ./docker/action_entrypoint.sh /entrypoint.sh RUN chmod +x /goscan && chmod +x /entrypoint.sh ENV PATH="/usr/local/go/bin:${PATH}" diff --git a/docker/Daemon.Dockerfile b/docker/Daemon.Dockerfile new file mode 100644 index 0000000..b4f3dcf --- /dev/null +++ b/docker/Daemon.Dockerfile @@ -0,0 +1,30 @@ +FROM golang:1.22-alpine3.20 AS builder + +WORKDIR /app +COPY . . + +RUN go mod download && go mod verify +RUN CGO_ENABLED=0 go build -ldflags="-s -w" -trimpath -o build/goscan + +FROM alpine:3.20 +LABEL maintainer="shane@scaffoe.com" \ + org.opencontainers.image.authors="Shane C." \ + org.opencontainers.image.source="https://git.shadowhosting.xyz/shanec/goscan" \ + org.opencontainers.image.licenses="Unlicense" \ + org.opencontainers.image.title="GoScan (GoSec Scanner for Forgejo)" + +RUN apk --no-cache update && apk --no-cache upgrade && apk add curl dumb-init bash ca-certificates && rm -rf /var/cache/apk/* + +COPY --from=builder /app/build/goscan /goscan +COPY ./docker/daemon_entrypoint.sh /usr/local/bin/docker-entrypoint.sh + +RUN addgroup -S -g 1000 goscan && adduser -S -H -D -h /var/lib/goscan -s /bin/bash -u 1000 -G goscan goscan +RUN mkdir -p /var/lib/goscan && chown -R goscan:goscan /var/lib/goscan + +USER 1000:1000 +ENV HOME="/var/lib/goscan" +VOLUME ["/var/lib/goscan"] +WORKDIR /var/lib/goscan + +ENTRYPOINT ["/usr/bin/dumb-init", "--", "/usr/local/bin/docker-entrypoint.sh"] +CMD [] diff --git a/entrypoint.sh b/docker/action_entrypoint.sh similarity index 100% rename from entrypoint.sh rename to docker/action_entrypoint.sh diff --git a/docker/compose.yml b/docker/compose.yml new file mode 100644 index 0000000..9b95d0a --- /dev/null +++ b/docker/compose.yml @@ -0,0 +1,36 @@ +networks: + goscan: + external: false + +volumes: + goscan: + driver: local + +services: + server: + build: + context: .. + dockerfile: Dockerfile + env_file: + - .env + restart: always + ports: + - "${PORT:-9000}:9000" + networks: + - goscan + volumes: + - goscan:/var/lib/goscan + - ./config.yml:/var/lib/goscan/config.yml + depends_on: + - db + + db: + image: postgres:16-alpine3.20 + env_file: + - .env + restart: always + environment: + POSTGRES_USER: "${POSTGRES_USER:-goscan}" + POSTGRES_DB: "${POSTGRES_DB:-goscan}" + networks: + - goscan \ No newline at end of file diff --git a/docker/daemon_entrypoint.sh b/docker/daemon_entrypoint.sh new file mode 100644 index 0000000..23a7484 --- /dev/null +++ b/docker/daemon_entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +/goscan daemon \ No newline at end of file diff --git a/example.config.yml b/example.config.yml new file mode 100644 index 0000000..e16ee43 --- /dev/null +++ b/example.config.yml @@ -0,0 +1,8 @@ +webserver: + host: 0.0.0.0 + port: 9000 + proxy: 'cloudflare' +forgejo: + url: https://git.shadowhosting.xyz + bot_token: "" + secret: "" \ No newline at end of file diff --git a/go.mod b/go.mod index 8f9f342..7cf81d1 100644 --- a/go.mod +++ b/go.mod @@ -5,18 +5,23 @@ go 1.22.5 require ( codeberg.org/mvdkleijn/forgejo-sdk/forgejo v1.1.1 git.eggactyl.cloud/Eggactyl/shell v0.0.0-20240824225129-2ced31effd66 + git.shadowhosting.xyz/shanec/forgejo-sdk/forgejo v1.1.3 + github.com/ProtonMail/go-crypto v1.0.0 github.com/go-git/go-git/v5 v5.12.0 + github.com/goccy/go-json v0.10.3 + github.com/gofiber/fiber/v2 v2.52.5 github.com/kr/pretty v0.3.1 github.com/nao1215/markdown v0.6.0 github.com/owenrumney/go-sarif v1.1.1 github.com/sethvargo/go-githubactions v1.3.0 github.com/spf13/cobra v1.8.1 + github.com/spf13/viper v1.19.0 ) require ( dario.cat/mergo v1.0.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/ProtonMail/go-crypto v1.0.0 // indirect + github.com/andybalholm/brotli v1.0.5 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/davidmz/go-pageant v1.0.2 // indirect @@ -26,20 +31,25 @@ require ( github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/hashicorp/go-version v1.6.0 // indirect + github.com/google/uuid v1.5.0 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/karrick/godirwalk v1.17.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/klauspost/compress v1.17.2 // indirect github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.7 // indirect - github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/owenrumney/go-sarif/v2 v2.3.3 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/philhofer/fwd v1.1.2 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect + github.com/rivo/uniseg v0.2.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -49,19 +59,23 @@ require ( github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.19.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/tinylib/msgp v1.1.8 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/zclconf/go-cty v1.10.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect - golang.org/x/crypto v0.22.0 // indirect + golang.org/x/crypto v0.27.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.22.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.13.0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 70ce25a..9c2357e 100644 --- a/go.sum +++ b/go.sum @@ -4,12 +4,22 @@ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= git.eggactyl.cloud/Eggactyl/shell v0.0.0-20240824225129-2ced31effd66 h1:nKQ5M7/Ugn536WbH07f6NZGKy+4z04i7KoAwUU8Ibaw= git.eggactyl.cloud/Eggactyl/shell v0.0.0-20240824225129-2ced31effd66/go.mod h1:/QCc50YmA6jiIzIafuDiRJXhZyNu0wKLlgeUMPv5S68= +git.shadowhosting.xyz/shanec/forgejo-sdk/forgejo v1.1.2 h1:JJbb+xcQ/NdKeH1J50LgHv3pctPHff2GJSUkYamunY4= +git.shadowhosting.xyz/shanec/forgejo-sdk/forgejo v1.1.2/go.mod h1:se/RxoDkDZN5IPP0wCUscO+Z5ArOpDJsX6UilAqKEWw= +git.shadowhosting.xyz/shanec/forgejo-sdk/forgejo v1.1.3 h1:sPB0qPctiPqkYJQUTLjnE+k49SsDqncCmNEydnwIbxQ= +git.shadowhosting.xyz/shanec/forgejo-sdk/forgejo v1.1.3/go.mod h1:se/RxoDkDZN5IPP0wCUscO+Z5ArOpDJsX6UilAqKEWw= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= @@ -20,27 +30,45 @@ github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53E github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0= github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= +github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI= github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo= +github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= -github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -51,6 +79,8 @@ github.com/karrick/godirwalk v1.17.0 h1:b4kY7nqDdioR/6qnbHQyDvmA17u5G1cZ6J+CZXwS github.com/karrick/godirwalk v1.17.0/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -60,26 +90,38 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/nao1215/markdown v0.6.0 h1:kqhrC47K434YA1jMTUwJwSV/hla8ifN3NzehMEffI/E= github.com/nao1215/markdown v0.6.0/go.mod h1:ObBhnNduWwPN+bu4dtv4JoLRt57ONla7l//03iHIVhY= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/owenrumney/go-sarif v1.1.1 h1:QNObu6YX1igyFKhdzd7vgzmw7XsWN3/6NMGuDzBgXmE= github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U= -github.com/owenrumney/go-sarif/v2 v2.3.3 h1:ubWDJcF5i3L/EIOER+ZyQ03IfplbSU1BLOE26uKQIIU= -github.com/owenrumney/go-sarif/v2 v2.3.3/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= +github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= @@ -118,9 +160,18 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= +github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= @@ -139,16 +190,15 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -157,13 +207,16 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -174,21 +227,21 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -196,21 +249,25 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= diff --git a/interfaces/forgejo.go b/interfaces/forgejo.go new file mode 100644 index 0000000..f4b2321 --- /dev/null +++ b/interfaces/forgejo.go @@ -0,0 +1,190 @@ +package interfaces + +import ( + "github.com/goccy/go-json" + "net/url" + "time" +) + +type URL struct { + url.URL +} + +func (u *URL) UnmarshalJSON(bytes []byte) error { + var s string + if err := json.Unmarshal(bytes, &s); err != nil { + return err + } + + parsedURL, err := url.Parse(s) + if err != nil { + return err + } + + u.URL = *parsedURL + return nil +} + +type ForgejoIssueEvent struct { + Action string `json:"action"` + Number int `json:"number"` + Repo ForgejoRepo `json:"repository"` + Sender ForgejoUser `json:"sender"` + Issue ForgejoIssue `json:"issue"` +} + +type ForgejoPushEvent struct { + Ref string `json:"ref"` + Before string `json:"before"` + After string `json:"after"` + CompareURL URL `json:"compare_url"` + Commits []ForgejoCommit `json:"commits"` + TotalCommits int `json:"total_commits"` + HeadCommit ForgejoCommit `json:"head_commit"` + Repo ForgejoRepo `json:"repository"` + Pusher ForgejoUser `json:"pusher"` + Sender ForgejoUser `json:"sender"` +} + +type ForgejoCommit struct { + ID string `json:"id"` + Message string `json:"message"` + URL URL `json:"url"` + Author ForgejoPartialUser `json:"author"` + Committer ForgejoPartialUser `json:"committer"` + Timestamp time.Time `json:"timestamp"` + Added []string `json:"added"` + Removed []string `json:"removed"` + Modified []string `json:"modified"` +} + +type ForgejoPartialUser struct { + Name string `json:"name"` + Email string `json:"email"` + Username string `json:"username"` +} + +type ForgejoUser struct { + ID int `json:"id"` + Login string `json:"login"` + LoginName string `json:"login_name"` + SourceID int `json:"source_id"` + FullName string `json:"full_name"` + Email string `json:"email"` + AvatarURL URL `json:"avatar_url"` + HtmlURL URL `json:"html_url"` + Language string `json:"language"` + IsAdmin bool `json:"is_admin"` + LastLogin time.Time `json:"last_login"` + Created time.Time `json:"created"` + IsRestricted bool `json:"restricted"` + IsActive bool `json:"active"` + IsProhbitLogin bool `json:"prohbit_login"` + Location string `json:"location"` + Pronouns string `json:"pronouns"` + Website string `json:"website"` + Description string `json:"description"` + Visibility string `json:"visibility"` + FollowerCount int `json:"followers_count"` + FollowingCount int `json:"following_count"` + StarCount int `json:"starred_repos_count"` + Username string `json:"username"` +} + +type ForgejoPartialRepo struct { + ID int `json:"id"` + Name string `json:"name"` + Owner string `json:"owner"` + FullName string `json:"full_name"` +} + +type ForgejoRepo struct { + ID int `json:"id"` + Owner ForgejoUser `json:"owner"` + Name string `json:"name"` + FullName string `json:"full_name"` + Description string `json:"description"` + IsEmpty bool `json:"empty"` + IsPrivate bool `json:"private"` + IsFork bool `json:"fork"` + IsTemplate bool `json:"template"` + IsMirror bool `json:"mirror"` + Parent *ForgejoRepo `json:"parent"` + Size int `json:"size"` + Language string `json:"language"` + LanguagesURL URL `json:"languages_url"` + HtmlURL URL `json:"html_url"` + URL URL `json:"url"` + Link URL `json:"link"` + SshURL string `json:"ssh_url"` + CloneURL URL `json:"clone_url"` + OriginalURL URL `json:"original_url"` + Website URL `json:"website"` + StarCount int `json:"stars_count"` + ForkCount int `json:"forks_count"` + WatcherCount int `json:"watchers_count"` + OpenIssueCount int `json:"open_issues_count"` + OpenPrCount int `json:"open_pr_counter"` + ReleaseCount int `json:"release_counter"` + DefaultBranch string `json:"default_branch"` + IsArchived bool `json:"archived"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + ArchivedAt time.Time `json:"archived_at"` + Permissions map[string]bool `json:"permissions"` + HasIssues bool `json:"has_issues"` + InternalTracker ForgejoRepoInternalTracker `json:"internal_tracker"` + HasWiki bool `json:"has_wiki"` + WikiBranch string `json:"wiki_branch"` + GloballyEditableWiki bool `json:"globally_editable_wiki"` + HasPullRequests bool `json:"has_pull_requests"` + HasProjects bool `json:"has_projects"` + HasReleases bool `json:"has_releases"` + HasPackages bool `json:"has_packages"` + HasActions bool `json:"has_actions"` + IgnoreWhitespaceConflicts bool `json:"ignore_whitespace_conflicts"` + AllowMergeCommits bool `json:"allow_merge_commits"` + AllowRebase bool `json:"allow_rebase"` + AllowExplicitRebase bool `json:"allow_rebase_explicit"` + AllowSquashMerge bool `json:"allow_squash_merge"` + AllowFastFowardOnlyMerge bool `json:"allow_fast_foward_only_merge"` + AllowRebaseUpdate bool `json:"allow_rebase_update"` + DefaultDeleteBranchAfterMerge bool `json:"default_delete_branch_after_merge"` + DefaultMergeStyle string `json:"default_merge_style"` + DefaultAllowMaintainerEdit bool `json:"default_allow_maintainer_edit"` + AvatarURL URL `json:"avatar_url"` + Internal bool `json:"internal"` + MirrorInterval string `json:"mirror_interval"` + ObjectFormatName string `json:"object_format_name"` + MirrorUpdated time.Time `json:"mirror_updated"` +} + +type ForgejoRepoInternalTracker struct { + TimeTracker bool `json:"time_tracker"` + AllowContribTrackTime bool `json:"allow_only_contributors_to_track_time"` + EnableIssueDependency bool `json:"enable_issue_dependencies"` +} + +type ForgejoIssue struct { + ID int `json:"id"` + URL URL `json:"url"` + HtmlURL URL `json:"html_url"` + Number int `json:"number"` + User ForgejoUser `json:"user"` + OriginalAuthor string `json:"original_author"` + OriginalAuthorID int `json:"original_author_id"` + Title string `json:"title"` + Body string `json:"body"` + Ref string `json:"ref"` + Assets []string `json:"assets"` + Labels []string `json:"labels"` + State string `json:"state"` + IsLocked bool `json:"is_locked"` + Comments int `json:"comments"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + ClosedAt time.Time `json:"closed_at"` + DueDate time.Time `json:"due_date"` + Repo ForgejoPartialRepo `json:"repository"` + PinOrder int `json:"pin_order"` +}