-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from carverauto/new/rbac
New/rbac
- Loading branch information
Showing
32 changed files
with
1,903 additions
and
121 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# (mandatory) | ||
# Path to coverprofile file (output of `go test -coverprofile` command). | ||
# | ||
# For cases where there are many coverage profiles, such as when running | ||
# unit tests and integration tests separately, you can combine all those | ||
# profiles into one. In this case, the profile should have a comma-separated list | ||
# of profile files, e.g., 'cover_unit.out,cover_integration.out'. | ||
profile: cover.out | ||
|
||
# (optional; but recommended to set) | ||
# When specified reported file paths will not contain local prefix in the output | ||
local-prefix: "github.com/carverauto/eventrunner" | ||
|
||
# Holds coverage thresholds percentages, values should be in range [0-100] | ||
threshold: | ||
# (optional; default 0) | ||
# The minimum coverage that each file should have | ||
file: 70 | ||
|
||
# (optional; default 0) | ||
# The minimum coverage that each package should have | ||
package: 80 | ||
|
||
# (optional; default 0) | ||
# The minimum total coverage project should have | ||
total: 95 | ||
|
||
# Holds regexp rules which will override thresholds for matched files or packages | ||
# using their paths. | ||
# | ||
# First rule from this list that matches file or package is going to apply | ||
# new threshold to it. If project has multiple rules that match same path, | ||
# override rules should be listed in order from specific to more general rules. | ||
override: | ||
# Increase coverage threshold to 100% for `foo` package | ||
# (default is 80, as configured above in this example) | ||
- threshold: 100 | ||
path: ^pkg/lib/foo$ | ||
|
||
# Holds regexp rules which will exclude matched files or packages | ||
# from coverage statistics | ||
exclude: | ||
# Exclude files or packages matching their paths | ||
paths: | ||
- \.pb\.go$ # excludes all protobuf generated files | ||
- ^pkg/bar # exclude package `pkg/bar` | ||
|
||
# NOTES: | ||
# - symbol `/` in all path regexps will be replaced by current OS file path separator | ||
# to properly work on Windows |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,23 @@ | ||
name: Go test coverage check | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: actions/setup-go@v3 | ||
|
||
- name: generate test coverage | ||
run: go test ./... -coverprofile=./cover.out -covermode=atomic -coverpkg=./... | ||
|
||
- name: check test coverage | ||
uses: vladopajic/go-test-coverage@v2 | ||
with: | ||
# Configure action using config file (option 1) | ||
config: ./.testcoverage.yml | ||
|
||
# Configure action by specifying input parameters individually (option 2). | ||
# If you are using config file (option 1) you shouldn't use these parameters, however | ||
# specifing these action parameters will override appropriate config values. | ||
profile: cover.out | ||
local-prefix: github.com/carverauto/eventrunner | ||
threshold-file: 80 | ||
threshold-package: 80 | ||
threshold-total: 95 | ||
name: test | ||
on: [push] | ||
permissions: | ||
contents: write | ||
jobs: | ||
test: | ||
name: test | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: checkout | ||
uses: actions/checkout@v4 | ||
- name: setup go | ||
uses: actions/setup-go@v5 | ||
with: | ||
go-version-file: go.mod | ||
- name: test | ||
run: make test | ||
- name: check test coverage | ||
uses: vladopajic/go-test-coverage@v2 | ||
with: | ||
config: ./.github/.testcoverage.yml | ||
git-branch: badges | ||
git-token: ${{ github.ref_name == 'main' && secrets.GITHUB_TOKEN || '' }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,19 @@ | ||
name: golangci-lint | ||
on: | ||
push: | ||
branches: | ||
- main | ||
- master | ||
pull_request: | ||
|
||
permissions: | ||
contents: read | ||
# Optional: allow read access to pull request. Use with `only-new-issues` option. | ||
# pull-requests: read | ||
|
||
name: lint | ||
on: [push] | ||
jobs: | ||
golangci: | ||
lint: | ||
name: lint | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-go@v5 | ||
- name: checkout | ||
uses: actions/checkout@v4 | ||
- name: setup go | ||
uses: actions/setup-go@v5 | ||
with: | ||
go-version: stable | ||
go-version-file: go.mod | ||
- name: golangci-lint | ||
uses: golangci/golangci-lint-action@v6 | ||
with: | ||
version: v1.60 | ||
version: v1.60.3 | ||
- name: go mod tidy check | ||
uses: katexochen/go-tidy-check@v2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
GO ?= go | ||
GOBIN ?= $$($(GO) env GOPATH)/bin | ||
GOLANGCI_LINT ?= $(GOBIN)/golangci-lint | ||
GOLANGCI_LINT_VERSION ?= v1.60.3 | ||
|
||
# Code tidy | ||
.PHONY: tidy | ||
tidy: | ||
go mod tidy | ||
go fmt ./... | ||
|
||
.PHONY: get-golangcilint | ||
get-golangcilint: | ||
test -f $(GOLANGCI_LINT) || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $$($(GO) env GOPATH)/bin $(GOLANGCI_LINT_VERSION) | ||
|
||
# Runs lint on entire repo | ||
.PHONY: lint | ||
lint: get-golangcilint | ||
$(GOLANGCI_LINT) run ./... | ||
|
||
# Runs tests on entire repo | ||
.PHONY: test | ||
test: | ||
go test -timeout=3s -race -count=10 -failfast -shuffle=on -short ./... -coverprofile=./cover.short.profile -covermode=atomic -coverpkg=./... | ||
go test -timeout=10s -race -count=1 -failfast -shuffle=on ./... -coverprofile=./cover.long.profile -covermode=atomic -coverpkg=./... | ||
|
||
# Runs test coverage check | ||
.PHONY: check-coverage | ||
check-coverage: test | ||
go run ./main.go --config=./.github/.testcoverage.yml | ||
|
||
# View coverage profile | ||
.PHONY: view-coverage | ||
view-coverage: | ||
go test ./... -coverprofile=./cover.all.profile -covermode=atomic -coverpkg=./... | ||
go tool cover -html=cover.all.profile -o=cover.html | ||
xdg-open cover.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/carverauto/eventrunner/cmd/api/migrations" | ||
"github.com/carverauto/eventrunner/pkg/api/handlers" | ||
"github.com/carverauto/eventrunner/pkg/api/middleware" | ||
"gofr.dev/pkg/gofr" | ||
"gofr.dev/pkg/gofr/datasource/mongo" | ||
) | ||
|
||
func main() { | ||
app := gofr.New() | ||
|
||
// Set up MongoDB | ||
db := mongo.New(mongo.Config{URI: "mongodb://localhost:27017", Database: "eventrunner"}) | ||
app.AddMongo(db) | ||
|
||
// Run migrations | ||
app.Migrate(migrations.All()) | ||
|
||
// Set up routes | ||
tenantHandler := &handlers.TenantHandler{} | ||
userHandler := &handlers.UserHandler{} | ||
|
||
// Tenant routes (protected by API key) | ||
app.POST("/tenants", tenantHandler.Create, middleware.AuthenticateAPIKey) | ||
app.GET("/tenants", tenantHandler.GetAll, middleware.AuthenticateAPIKey) | ||
|
||
// User routes (protected by API key and role-based access) | ||
app.POST("/tenants/{tenant_id}/users", userHandler.Create, middleware.AuthenticateAPIKey, middleware.RequireRole("admin")) | ||
app.GET("/tenants/{tenant_id}/users", userHandler.GetAll, middleware.AuthenticateAPIKey, middleware.RequireRole("admin", "user")) | ||
|
||
// Run the application | ||
app.Run() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package migrations | ||
|
||
import ( | ||
"gofr.dev/pkg/gofr/migration" | ||
) | ||
|
||
func All() map[int64]migration.Migrate { | ||
return map[int64]migration.Migrate{ | ||
20240226153000: createCollections(), | ||
Check failure on line 9 in cmd/api/migrations/all.go GitHub Actions / lint
|
||
20240226153100: createIndexes(), | ||
Check failure on line 10 in cmd/api/migrations/all.go GitHub Actions / lint
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,99 +1,81 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"os" | ||
"strings" | ||
"time" | ||
|
||
"github.com/carverauto/gofr-nats" | ||
cloudevents "github.com/cloudevents/sdk-go/v2" | ||
"github.com/google/uuid" | ||
"context" | ||
"log" | ||
|
||
"github.com/carverauto/eventrunner/pkg/api/middleware" | ||
"github.com/carverauto/eventrunner/pkg/config" | ||
customctx "github.com/carverauto/eventrunner/pkg/context" | ||
"github.com/carverauto/eventrunner/pkg/eventingest" | ||
"gofr.dev/pkg/gofr" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/credentials/insecure" | ||
) | ||
|
||
type EventRouter struct { | ||
app *gofr.App | ||
natsClient *nats.PubSubWrapper | ||
} | ||
|
||
func NewEventRouter() *EventRouter { | ||
func main() { | ||
app := gofr.New() | ||
|
||
subjects := strings.Split(os.Getenv("NATS_SUBJECTS"), ",") | ||
// Load OAuth configuration | ||
oauthConfig := config.LoadOAuthConfig(app) | ||
|
||
natsClient := nats.New(&nats.Config{ | ||
Server: os.Getenv("PUBSUB_BROKER"), | ||
Stream: nats.StreamConfig{ | ||
Stream: os.Getenv("NATS_STREAM"), | ||
Subjects: subjects, | ||
}, | ||
MaxWait: 5 * time.Second, | ||
BatchSize: 100, | ||
MaxPullWait: 10, | ||
Consumer: os.Getenv("NATS_CONSUMER"), | ||
CredsFile: os.Getenv("NATS_CREDS_FILE"), | ||
}) | ||
natsClient.UseLogger(app.Logger) | ||
natsClient.UseMetrics(app.Metrics()) | ||
natsClient.Connect() | ||
|
||
app.AddPubSub(natsClient) | ||
|
||
return &EventRouter{ | ||
app: app, | ||
natsClient: natsClient, | ||
} | ||
} | ||
|
||
func (er *EventRouter) Start() { | ||
er.app.Subscribe("raw_events", er.handleRawEvent) | ||
er.app.Run() | ||
} | ||
|
||
func (er *EventRouter) handleRawEvent(c *gofr.Context) error { | ||
var rawEvent map[string]interface{} | ||
if err := c.Bind(&rawEvent); err != nil { | ||
return err | ||
// Initialize JWT middleware | ||
jwtMiddleware, err := middleware.NewJWTMiddleware(context.Background(), oauthConfig) | ||
if err != nil { | ||
log.Fatalf("Failed to initialize JWT middleware: %v", err) | ||
} | ||
|
||
event := cloudevents.NewEvent() | ||
event.SetID(uuid.New().String()) | ||
event.SetSource("event-router") | ||
// Set up gRPC connection to API | ||
grpcServerAddress := app.Config.Get("GRPC_SERVER_ADDRESS") | ||
|
||
eventType, ok := rawEvent["type"].(string) | ||
if !ok { | ||
return fmt.Errorf("missing or invalid event type") | ||
conn, err := grpc.Dial(grpcServerAddress, grpc.WithTransportCredentials(insecure.NewCredentials())) | ||
if err != nil { | ||
log.Fatalf("Failed to connect to gRPC server: %v", err) | ||
} | ||
event.SetType(eventType) | ||
|
||
tenantID, ok := rawEvent["tenant_id"].(string) | ||
if !ok { | ||
return fmt.Errorf("missing or invalid tenant_id") | ||
} | ||
event.SetExtension("tenantid", tenantID) | ||
defer conn.Close() | ||
|
||
err := event.SetData(cloudevents.ApplicationJSON, rawEvent) | ||
if err != nil { | ||
return err | ||
} | ||
// Create gRPC event forwarder | ||
eventForwarder := eventingest.NewGRPCEventForwarder(conn) | ||
|
||
eventJSON, err := json.Marshal(event) | ||
if err != nil { | ||
return err | ||
} | ||
// Create and set up HTTP server | ||
httpServer := eventingest.NewHTTPServer(app, eventForwarder) | ||
|
||
// Route to appropriate consumer queue based on event type | ||
consumerQueue := "events." + eventType | ||
if err := er.natsClient.Publish(c.Context, consumerQueue, eventJSON); err != nil { | ||
return err | ||
} | ||
// Register routes with middleware chain | ||
app.POST("/events", combineMiddleware( | ||
jwtMiddleware.Validate, | ||
middleware.AuthenticateAPIKey, | ||
middleware.RequireRole("admin", "event_publisher"), | ||
func(cc *customctx.Context) (interface{}, error) { | ||
return httpServer.HandleEvent(cc) | ||
}, | ||
)) | ||
|
||
return nil | ||
// Run the application | ||
app.Run() | ||
} | ||
|
||
func main() { | ||
router := NewEventRouter() | ||
router.Start() | ||
// combineMiddleware chains multiple middleware functions together | ||
func combineMiddleware(middlewares ...interface{}) gofr.Handler { | ||
return func(c *gofr.Context) (interface{}, error) { | ||
cc := customctx.NewCustomContext(c) | ||
|
||
var handler func(*customctx.Context) (interface{}, error) | ||
|
||
// Apply middlewares in reverse order | ||
for i := len(middlewares) - 1; i >= 0; i-- { | ||
switch m := middlewares[i].(type) { | ||
case func(*customctx.Context) (interface{}, error): | ||
handler = m | ||
case func(func(*customctx.Context) (interface{}, error)) func(*customctx.Context) (interface{}, error): | ||
handler = m(handler) | ||
case func(gofr.Handler) gofr.Handler: | ||
return m(func(*gofr.Context) (interface{}, error) { | ||
return handler(cc) | ||
})(c) | ||
} | ||
} | ||
|
||
return handler(cc) | ||
} | ||
} |
Oops, something went wrong.