diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-15 16:37:08 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-17 16:30:22 -0600 |
| commit | 45df4d0d9b577fecee798d672695fe24ff57fb1b (patch) | |
| tree | 1b99bf645035b58e0d6db08c7a83521f41f7a75b /vendor/github.com/xlgmokha/x | |
| parent | f94f79608393d4ab127db63cc41668445ef6b243 (diff) | |
feat: migrate from Cedar to SpiceDB authorization system
This is a major architectural change that replaces the Cedar policy-based
authorization system with SpiceDB's relation-based authorization.
Key changes:
- Migrate from Rust to Go implementation
- Replace Cedar policies with SpiceDB schema and relationships
- Switch from envoy `ext_authz` with Cedar to SpiceDB permission checks
- Update build system and dependencies for Go ecosystem
- Maintain Envoy integration for external authorization
This change enables more flexible permission modeling through SpiceDB's
Google Zanzibar inspired relation-based system, supporting complex
hierarchical permissions that were difficult to express in Cedar.
Breaking change: Existing Cedar policies and Rust-based configuration
will no longer work and need to be migrated to SpiceDB schema.
Diffstat (limited to 'vendor/github.com/xlgmokha/x')
19 files changed, 472 insertions, 0 deletions
diff --git a/vendor/github.com/xlgmokha/x/LICENSE b/vendor/github.com/xlgmokha/x/LICENSE new file mode 100644 index 00000000..a9ea45c0 --- /dev/null +++ b/vendor/github.com/xlgmokha/x/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 mo khan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/xlgmokha/x/pkg/context/key.go b/vendor/github.com/xlgmokha/x/pkg/context/key.go new file mode 100644 index 00000000..80ca7bd2 --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/context/key.go @@ -0,0 +1,20 @@ +package context + +import ( + "context" + + "github.com/xlgmokha/x/pkg/x" +) + +type Key[T any] string + +func (self Key[T]) With(ctx context.Context, value T) context.Context { + return context.WithValue(ctx, self, value) +} + +func (self Key[T]) From(ctx context.Context) T { + if value := ctx.Value(self); value != nil { + return value.(T) + } + return x.Zero[T]() +} diff --git a/vendor/github.com/xlgmokha/x/pkg/convert/ptr.go b/vendor/github.com/xlgmokha/x/pkg/convert/ptr.go new file mode 100644 index 00000000..34c3949f --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/convert/ptr.go @@ -0,0 +1,9 @@ +package convert + +func ToPtr[T any](item T) *T { + return &item +} + +func FromPtr[T any](p *T) T { + return *p +} diff --git a/vendor/github.com/xlgmokha/x/pkg/env/env.go b/vendor/github.com/xlgmokha/x/pkg/env/env.go new file mode 100644 index 00000000..24fb519a --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/env/env.go @@ -0,0 +1,22 @@ +package env + +import ( + "os" + "strings" +) + +func Fetch(key string, defaultValue string) string { + if x := os.Getenv(key); x != "" { + return x + } + return defaultValue +} + +func Variables() Vars { + items := Vars{} + for _, line := range os.Environ() { + segments := strings.SplitN(line, "=", 2) + items[segments[0]] = segments[1] + } + return items +} diff --git a/vendor/github.com/xlgmokha/x/pkg/env/vars.go b/vendor/github.com/xlgmokha/x/pkg/env/vars.go new file mode 100644 index 00000000..aad050ab --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/env/vars.go @@ -0,0 +1,3 @@ +package env + +type Vars map[string]string diff --git a/vendor/github.com/xlgmokha/x/pkg/env/with.go b/vendor/github.com/xlgmokha/x/pkg/env/with.go new file mode 100644 index 00000000..6efeed46 --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/env/with.go @@ -0,0 +1,27 @@ +package env + +import ( + "os" +) + +func With(env Vars, callback func()) { + original := Vars{} + + for key, value := range env { + if val, ok := os.LookupEnv(key); ok { + original[key] = val + } + os.Setenv(key, value) + } + + defer func() { + for key, _ := range env { + os.Unsetenv(key) + } + for key, value := range original { + os.Setenv(key, value) + } + }() + + callback() +} diff --git a/vendor/github.com/xlgmokha/x/pkg/log/context.go b/vendor/github.com/xlgmokha/x/pkg/log/context.go new file mode 100644 index 00000000..ce99fe77 --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/log/context.go @@ -0,0 +1,17 @@ +package log + +import ( + "context" + + "github.com/rs/zerolog" +) + +func WithFields(ctx context.Context, fields Fields) { + From(ctx).UpdateContext(func(c zerolog.Context) zerolog.Context { + return c.Fields(fields.ToMap()) + }) +} + +func From(ctx context.Context) *zerolog.Logger { + return zerolog.Ctx(ctx) +} diff --git a/vendor/github.com/xlgmokha/x/pkg/log/fields.go b/vendor/github.com/xlgmokha/x/pkg/log/fields.go new file mode 100644 index 00000000..8b0d48e2 --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/log/fields.go @@ -0,0 +1,7 @@ +package log + +type Fields map[string]interface{} + +func (f Fields) ToMap() map[string]interface{} { + return map[string]interface{}(f) +} diff --git a/vendor/github.com/xlgmokha/x/pkg/log/http.go b/vendor/github.com/xlgmokha/x/pkg/log/http.go new file mode 100644 index 00000000..2257fa07 --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/log/http.go @@ -0,0 +1,23 @@ +package log + +import ( + "net/http" + + "github.com/rs/zerolog" + "github.com/xlgmokha/x/pkg/mapper" +) + +func HTTP(logger *zerolog.Logger) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := logger.WithContext(r.Context()) + + defer func() { + WithFields(ctx, mapper.MapFrom[*http.Request, Fields](r)) + zerolog.Ctx(ctx).Print() + }() + + next.ServeHTTP(w, r.WithContext(ctx)) + }) + } +} diff --git a/vendor/github.com/xlgmokha/x/pkg/log/init.go b/vendor/github.com/xlgmokha/x/pkg/log/init.go new file mode 100644 index 00000000..202b1864 --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/log/init.go @@ -0,0 +1,18 @@ +package log + +import ( + "net/http" + + "github.com/xlgmokha/x/pkg/mapper" +) + +func init() { + mapper.Register[*http.Request, Fields](func(r *http.Request) Fields { + return Fields{ + "host": r.URL.Host, + "method": r.Method, + "path": r.URL.Path, + "remote_host": r.RemoteAddr, + } + }) +} diff --git a/vendor/github.com/xlgmokha/x/pkg/log/log.go b/vendor/github.com/xlgmokha/x/pkg/log/log.go new file mode 100644 index 00000000..de9098be --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/log/log.go @@ -0,0 +1,19 @@ +package log + +import ( + "io" + + "github.com/rs/zerolog" + "github.com/xlgmokha/x/pkg/convert" +) + +func New(writer io.Writer, fields Fields) *zerolog.Logger { + return convert.ToPtr( + zerolog. + New(writer). + With(). + Timestamp(). + Fields(fields.ToMap()). + Logger(), + ) +} diff --git a/vendor/github.com/xlgmokha/x/pkg/mapper/mapper.go b/vendor/github.com/xlgmokha/x/pkg/mapper/mapper.go new file mode 100644 index 00000000..2057f719 --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/mapper/mapper.go @@ -0,0 +1,46 @@ +package mapper + +import ( + "fmt" + "reflect" +) + +type Mapping[TInput any, TOutput any] func(TInput) TOutput + +var mappings map[string]interface{} + +func init() { + mappings = map[string]interface{}{} +} + +func Register[Input any, Output any](mapping Mapping[Input, Output]) { + mappings[keyFor[Input, Output]()] = mapping +} + +func MapFrom[Input any, Output any](input Input) Output { + if mapping, ok := mappings[keyFor[Input, Output]()]; ok { + return mapping.(Mapping[Input, Output])(input) + } + var output Output + return output +} + +func MapEachFrom[Input any, Output any](input []Input) []Output { + var zero Output + zeroValue := reflect.Zero(reflect.TypeOf(zero)) + + results := []Output{} + for _, item := range input { + tmp := MapFrom[Input, Output](item) + if zeroValue != reflect.ValueOf(tmp) { + results = append(results, tmp) + } + } + return results +} + +func keyFor[Input any, Output any]() string { + var input Input + var output Output + return fmt.Sprintf("%v-%v", reflect.TypeOf(input), reflect.TypeOf(output)) +} diff --git a/vendor/github.com/xlgmokha/x/pkg/mapper/test.go b/vendor/github.com/xlgmokha/x/pkg/mapper/test.go new file mode 100644 index 00000000..6e18807f --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/mapper/test.go @@ -0,0 +1,77 @@ +package mapper + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type unregisteredType struct{} + +type testObject struct { + GivenName string + FamilyName string +} + +type testModel struct { + Name string +} + +func TestMapper(t *testing.T) { + Register[*testObject, *testModel](func(item *testObject) *testModel { + return &testModel{ + Name: fmt.Sprintf("%v %v", item.GivenName, item.FamilyName), + } + }) + + t.Run("MapFrom", func(t *testing.T) { + t.Run("when the mapping is registered", func(t *testing.T) { + item := &testObject{ + GivenName: "Tsuyoshi", + FamilyName: "Garret", + } + + model := MapFrom[*testObject, *testModel](item) + + require.NotNil(t, model) + assert.Equal(t, "Tsuyoshi Garret", model.Name) + }) + + t.Run("When the mapping is not registered", func(t *testing.T) { + item := &unregisteredType{} + model := MapFrom[*unregisteredType, *testModel](item) + + assert.Nil(t, model) + }) + }) + + t.Run("MapEachFrom", func(t *testing.T) { + t.Run("when the mapping is registered", func(t *testing.T) { + datum := []*testObject{ + {GivenName: "Tsuyoshi", FamilyName: "Garret"}, + {GivenName: "Takashi", FamilyName: "Shirogane"}, + } + + results := MapEachFrom[*testObject, *testModel](datum) + + require.NotNil(t, results) + require.Equal(t, 2, len(results)) + + assert.Equal(t, "Tsuyoshi Garret", results[0].Name) + assert.Equal(t, "Takashi Shirogane", results[1].Name) + }) + + t.Run("when the mapping is not registered", func(t *testing.T) { + datum := []*unregisteredType{ + {}, + } + + results := MapEachFrom[*unregisteredType, *testModel](datum) + + require.NotNil(t, results) + assert.Equal(t, 0, len(results)) + }) + }) +} diff --git a/vendor/github.com/xlgmokha/x/pkg/x/error.go b/vendor/github.com/xlgmokha/x/pkg/x/error.go new file mode 100644 index 00000000..be9db9ca --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/x/error.go @@ -0,0 +1,16 @@ +package x + +var Panic = func(err error) { + panic(err) +} + +func Check(err error) { + if err != nil { + Panic(err) + } +} + +func Must[T any](item T, err error) T { + Check(err) + return item +} diff --git a/vendor/github.com/xlgmokha/x/pkg/x/iterate.go b/vendor/github.com/xlgmokha/x/pkg/x/iterate.go new file mode 100644 index 00000000..a1d40a1d --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/x/iterate.go @@ -0,0 +1,60 @@ +package x + +import "slices" + +type Mapper[T any, K any] func(T) K +type Predicate[T any] func(T) bool +type Visitor[T any] func(T) + +func Find[T any](items []T, predicate Predicate[T]) T { + for _, item := range items { + if predicate(item) { + return item + } + } + return Zero[T]() +} + +func FindAll[T any](items []T, predicate Predicate[T]) []T { + results := []T{} + Each[T](items, func(item T) { + if predicate(item) { + results = append(results, item) + } + }) + return results +} + +func Contains[T comparable](items []T, predicate Predicate[T]) bool { + return Find[T](items, predicate) != Zero[T]() +} + +func Map[TInput any, TOutput any](items []TInput, mapFrom Mapper[TInput, TOutput]) []TOutput { + results := []TOutput{} + Each[TInput](items, func(item TInput) { + results = append(results, mapFrom(item)) + }) + return results +} + +func Each[T any](items []T, v Visitor[T]) { + for _, item := range items { + v(item) + } +} + +func Inject[TInput any, TOutput any](items []TInput, memo TOutput, f func(TOutput, TInput)) TOutput { + for _, item := range items { + f(memo, item) + } + return memo +} + +func Prepend[T any](rest []T, beginning ...T) []T { + return append(beginning, rest...) +} + +func Reverse[T any](items []T) []T { + slices.Reverse(items) + return items +} diff --git a/vendor/github.com/xlgmokha/x/pkg/x/middleware.go b/vendor/github.com/xlgmokha/x/pkg/x/middleware.go new file mode 100644 index 00000000..a24580a3 --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/x/middleware.go @@ -0,0 +1,8 @@ +package x + +func Middleware[T any](item T, items ...Option[T]) T { + for _, middleware := range Reverse(items) { + item = middleware(item) + } + return item +} diff --git a/vendor/github.com/xlgmokha/x/pkg/x/option.go b/vendor/github.com/xlgmokha/x/pkg/x/option.go new file mode 100644 index 00000000..b0bf6381 --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/x/option.go @@ -0,0 +1,20 @@ +package x + +type Configure[T any] func(T) +type Option[T any] func(T) T +type Factory[T any] func() T + +func New[T any](options ...Option[T]) T { + item := Default[T]() + for _, option := range options { + item = option(item) + } + return item +} + +func With[T any](with Configure[T]) Option[T] { + return func(item T) T { + with(item) + return item + } +} diff --git a/vendor/github.com/xlgmokha/x/pkg/x/specification.go b/vendor/github.com/xlgmokha/x/pkg/x/specification.go new file mode 100644 index 00000000..c79dc4ad --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/x/specification.go @@ -0,0 +1,21 @@ +package x + +type Specification[T any] interface { + IsSatisfiedBy(T) bool +} + +func (f Predicate[T]) IsSatisfiedBy(item T) bool { + return f(item) +} + +func (s Predicate[T]) Or(other Specification[T]) Predicate[T] { + return Predicate[T](func(item T) bool { + return s.IsSatisfiedBy(item) || other.IsSatisfiedBy(item) + }) +} + +func (s Predicate[T]) And(other Specification[T]) Predicate[T] { + return Predicate[T](func(item T) bool { + return s.IsSatisfiedBy(item) && other.IsSatisfiedBy(item) + }) +} diff --git a/vendor/github.com/xlgmokha/x/pkg/x/types.go b/vendor/github.com/xlgmokha/x/pkg/x/types.go new file mode 100644 index 00000000..7c38c834 --- /dev/null +++ b/vendor/github.com/xlgmokha/x/pkg/x/types.go @@ -0,0 +1,38 @@ +package x + +import "reflect" + +func Default[T any]() T { + item := Zero[T]() + + if IsPtr[T](item) { + return reflect.New(reflect.TypeOf(item).Elem()).Interface().(T) + } + + return item +} + +func Zero[T any]() T { + var item T + return item +} + +func IsZero[T comparable](item T) bool { + return item == Zero[T]() +} + +func IsPresent[T comparable](item T) bool { + return !IsZero[T](item) +} + +func IsPtr[T any](item T) bool { + return Is[T](item, reflect.Pointer) +} + +func IsSlice[T any](item T) bool { + return Is[T](item, reflect.Slice) +} + +func Is[T any](item T, kind reflect.Kind) bool { + return reflect.TypeOf(item).Kind() == kind +} |
