Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add security scan endpoint. #48

Merged
merged 1 commit into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Or manually run:

### Generate Migration Files

Run this command to generate migration files needed for staging/prod database schema changes:
Run this command to generate migration files needed for staging/prod database schema changes:

```shell
atlas migrate diff migration \
Expand Down Expand Up @@ -101,6 +101,14 @@ https://github.com/deepmap/oapi-codegen/issues/795

Here are some common errors and how to resolve them.

### Security Scan

If you are calling the `security-scan` endpoint, you need to add the endpoint url to `docker-compose.yml` and then make sure you have the correct permissions to call that function.

Check the `security-scan` Cloud Function repo for instructions on how to do that with `gcloud`.

For non Comfy-Org contributors, you can use your own hosted function or just avoid touching this part. We keep the security scan code private to avoid exploiters taking advantage of it.

### Firebase Token Errors

Usually in localdev, we use dreamboothy-dev Firebase project for authentication. This conflicts with our machine creation logic because all of those machine images are in dreamboothy. TODO(robinhuang): Figure out a solution for this. Either we replicate things in dreamboothy-dev, or we pass project information separately when creating machine images.
Expand Down
10 changes: 6 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package config

type Config struct {
ProjectID string
DripEnv string
SlackRegistryChannelWebhook string
JWTSecret string
ProjectID string
DripEnv string
SlackRegistryChannelWebhook string
DiscordSecurityChannelWebhook string
JWTSecret string
SecretScannerURL string
}
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ services:
CORS_ORIGIN: "http://localhost:3000"
JWT_SECRET: 8zT9YknYUTZRVAkgov86gT1NLezTtwrd # test secret
LOG_LEVEL: info # Set the log level here
SECRET_SCANNER_URL: ""
111 changes: 101 additions & 10 deletions drip/api.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ent/migrate/schema.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ent/nodeversion/nodeversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions ent/schema/node_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const (
NodeVersionStatusDeleted NodeVersionStatus = "deleted"
NodeVersionStatusBanned NodeVersionStatus = "banned"
NodeVersionStatusPending NodeVersionStatus = "pending"
NodeVersionStatusFlagged NodeVersionStatus = "flagged"
)

func (NodeVersionStatus) Values() (types []string) {
Expand All @@ -75,5 +76,6 @@ func (NodeVersionStatus) Values() (types []string) {
string(NodeVersionStatusBanned),
string(NodeVersionStatusDeleted),
string(NodeVersionStatusPending),
string(NodeVersionStatusFlagged),
}
}
71 changes: 71 additions & 0 deletions gateways/discord/discord.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package discord

import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"registry-backend/config"
)

type DiscordService interface {
SendSecurityCouncilMessage(msg string) error
}

type DripDiscordService struct {
securityDiscordChannelWebhook string
config *config.Config
}

func NewDiscordService(config *config.Config) *DripDiscordService {
return &DripDiscordService{
config: config,
securityDiscordChannelWebhook: config.DiscordSecurityChannelWebhook,
}
}

type discordRequestBody struct {
Content string `json:"content"`
}

func (s *DripDiscordService) SendSecurityCouncilMessage(msg string) error {
if s.config.DripEnv == "prod" {
return sendDiscordNotification(msg, s.securityDiscordChannelWebhook)
} else {
println("Skipping sending message to Discord in non-prod environment. " + msg)
}
return nil
}

func sendDiscordNotification(msg string, discordWebhookURL string) error {
if discordWebhookURL == "" {
return fmt.Errorf("no Discord webhook URL provided, skipping sending message to Discord")
}

body, err := json.Marshal(discordRequestBody{Content: msg})
if err != nil {
return err
}

req, err := http.NewRequest(http.MethodPost, discordWebhookURL, bytes.NewBuffer(body))
if err != nil {
return err
}

req.Header.Set("Content-Type", "application/json")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}

defer resp.Body.Close()

if resp.StatusCode >= 400 {
// You can handle or log the HTTP error status code here
return fmt.Errorf("request to Discord returned error status: %d", resp.StatusCode)
}

return nil
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ require (
github.com/stretchr/testify v1.8.4
github.com/testcontainers/testcontainers-go v0.28.0
github.com/testcontainers/testcontainers-go/modules/postgres v0.28.0
google.golang.org/api v0.165.0
google.golang.org/genproto/googleapis/api v0.0.0-20240213162025-012b6fc9bca9
google.golang.org/protobuf v1.32.0
)
Expand Down Expand Up @@ -114,6 +113,7 @@ require (
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.18.0 // indirect
google.golang.org/api v0.165.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 // indirect
Expand Down
3 changes: 2 additions & 1 deletion integration-tests/ban_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@ func TestBan(t *testing.T) {
// Initialize the Service
mockStorageService := new(gateways.MockStorageService)
mockSlackService := new(gateways.MockSlackService)
mockDiscordService := new(gateways.MockDiscordService)
mockSlackService.
On("SendRegistryMessageToSlack", mock.Anything).
Return(nil) // Do nothing for all slack messsage calls.

impl := implementation.NewStrictServerImplementation(
client, &config.Config{}, mockStorageService, mockSlackService)
client, &config.Config{}, mockStorageService, mockSlackService, mockDiscordService)

authz := drip_authorization.NewAuthorizationManager(client, impl.RegistryService).AuthorizationMiddleware()

Expand Down
3 changes: 2 additions & 1 deletion integration-tests/ci_cd_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ func TestCICD(t *testing.T) {
// Initialize the Service
mockStorageService := new(gateways.MockStorageService)
mockSlackService := new(gateways.MockSlackService)
mockDiscordService := new(gateways.MockDiscordService)
mockSlackService.
On("SendRegistryMessageToSlack", mock.Anything).
Return(nil) // Do nothing for all slack messsage calls.
impl := implementation.NewStrictServerImplementation(
client, &config.Config{}, mockStorageService, mockSlackService)
client, &config.Config{}, mockStorageService, mockSlackService, mockDiscordService)

ctx := context.Background()
now := time.Now()
Expand Down
3 changes: 2 additions & 1 deletion integration-tests/registry_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,12 @@ func TestRegistry(t *testing.T) {
// Initialize the Service
mockStorageService := new(gateways.MockStorageService)
mockSlackService := new(gateways.MockSlackService)
mockDiscordService := new(gateways.MockDiscordService)
mockSlackService.
On("SendRegistryMessageToSlack", mock.Anything).
Return(nil) // Do nothing for all slack messsage calls.
impl := implementation.NewStrictServerImplementation(
client, &config.Config{}, mockStorageService, mockSlackService)
client, &config.Config{}, mockStorageService, mockSlackService, mockDiscordService)
authz := drip_authorization.NewAuthorizationManager(client, impl.RegistryService).
AuthorizationMiddleware()

Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func main() {
DripEnv: os.Getenv("DRIP_ENV"),
SlackRegistryChannelWebhook: os.Getenv("SLACK_REGISTRY_CHANNEL_WEBHOOK"),
JWTSecret: os.Getenv("JWT_SECRET"),
SecretScannerURL: os.Getenv("SECRET_SCANNER_URL"),
}

var dsn string
Expand Down
14 changes: 14 additions & 0 deletions mock/gateways/mock_discord_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package gateways

import (
"github.com/stretchr/testify/mock"
)

type MockDiscordService struct {
mock.Mock
}

func (m *MockDiscordService) SendSecurityCouncilMessage(msg string) error {
args := m.Called(msg)
return args.Error(0)
}
Loading
Loading