Skip to content

Commit

Permalink
a3s (#114)
Browse files Browse the repository at this point in the history
* new: added Namespaceable and Propagatable interfaces

* new: added basic namespaces manipulation functions

* new: incorporate namespace propagation concept

* use revive

* new: added SetNamespace to Namespaceable interface

* new: added a backward compat flag to not remove the propagated flag after reading it

* fix github workflow

Co-authored-by: Antoine Mercadal <[email protected]>
  • Loading branch information
t00f and Antoine Mercadal authored Nov 17, 2021
1 parent 44c1aab commit 0c8e5dc
Show file tree
Hide file tree
Showing 11 changed files with 739 additions and 117 deletions.
16 changes: 15 additions & 1 deletion .github/workflows/build-go.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
fail-fast: false
matrix:
go:
- 1.17
- 1.15
- 1.16
steps:
Expand All @@ -28,10 +29,23 @@ jobs:
with:
go-version: ${{ matrix.go }}

- name: setup-for-old-go
if: ${{ matrix.go < 1.17 }}
run: |
# stay on an old version of golangci-lint which still reports properly
#
# see release notes and this file for detail:
# https://github.com/golangci/golangci-lint/blob/v1.43.0/.github/workflows/pr.yml#L67-70
go get github.com/golangci/golangci-lint/cmd/[email protected]
- name: setup-for-current-go
if: ${{ matrix.go >= 1.17 }}
run: |
go get github.com/golangci/golangci-lint/cmd/golangci-lint@latest
- name: setup
run: |
go version
go get github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go get github.com/securego/gosec/cmd/gosec
#go get golang.org/x/tools/cmd/cover
go get github.com/axw/gocov/gocov
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ lint:
--enable=errcheck \
--enable=goimports \
--enable=ineffassign \
--enable=golint \
--enable=revive \
--enable=unused \
--enable=structcheck \
--enable=staticcheck \
Expand Down
13 changes: 13 additions & 0 deletions identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,16 @@ type Patchable interface {
// Patch patches the receiver using the given SparseIdentifiable.
Patch(SparseIdentifiable)
}

// A Namespaceable is the interface of an object that is namespaced.
type Namespaceable interface {
GetNamespace() string
SetNamespace(string)
}

// A Propagatable is the interface of an object that can propagate down
// from a parent namespace.
type Propagatable interface {
GetProgagate() bool
Namespaceable
}
24 changes: 12 additions & 12 deletions matcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2153,12 +2153,12 @@ func TestExistsComparator(t *testing.T) {

// nil fixtures
var (
nilPointer *interface{} = nil
nilMap map[struct{}]struct{} = nil
nilFunc func() = nil
nilChan chan struct{} = nil
nilInterface interface{} = nil
nilSlice []interface{} = nil
nilPointer *interface{}
nilMap map[struct{}]struct{}
nilFunc func()
nilChan chan struct{}
nilInterface interface{}
nilSlice []interface{}
)

testAttributeName := "someAttribute"
Expand Down Expand Up @@ -2396,12 +2396,12 @@ func TestNotExistsComparator(t *testing.T) {

// nil fixtures
var (
nilPointer *interface{} = nil
nilMap map[struct{}]struct{} = nil
nilFunc func() = nil
nilChan chan struct{} = nil
nilInterface interface{} = nil
nilSlice []interface{} = nil
nilPointer *interface{}
nilMap map[struct{}]struct{}
nilFunc func()
nilChan chan struct{}
nilInterface interface{}
nilSlice []interface{}
)

testAttributeName := "someAttribute"
Expand Down
134 changes: 134 additions & 0 deletions namespace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package elemental

import (
"fmt"
"net/http"
"strings"
)

// Namespacer is the interface that any namespace extraction/injection
// implementation should support.
type Namespacer interface {
Extract(r *http.Request) (string, error)
Inject(r *http.Request, namespace string) error
}

var (
namespacer = Namespacer(&defaultNamespacer{})
)

type defaultNamespacer struct{}

// defaultExtractor will retrieve the namespace value from the header X-Namespace.
func (d *defaultNamespacer) Extract(r *http.Request) (string, error) {
return r.Header.Get("X-Namespace"), nil
}

// defaultInjector will set the namespace as an HTTP header.
func (d *defaultNamespacer) Inject(r *http.Request, namespace string) error {
if r.Header == nil {
r.Header = http.Header{}
}
r.Header.Set("X-Namespace", namespace)
return nil
}

// SetNamespacer will configure the package. It must be only called once
// and it is global for the package.
func SetNamespacer(custom Namespacer) {
namespacer = custom
}

// GetNamespacer retrieves the configured namespacer.
func GetNamespacer() Namespacer {
return namespacer
}

// ParentNamespaceFromString returns the parent namespace of a namespace
// It returns empty it the string is invalid
func ParentNamespaceFromString(namespace string) (string, error) {

if namespace == "" {
return "", fmt.Errorf("invalid empty namespace name")
}

if namespace == "/" {
return "", nil
}

index := strings.LastIndex(namespace, "/")

switch index {
case -1:
return "", fmt.Errorf("invalid namespace name")
case 0:
return namespace[:index+1], nil
default:
return namespace[:index], nil
}
}

// IsNamespaceRelatedToNamespace returns true if the given namespace is related to the given parent
func IsNamespaceRelatedToNamespace(ns string, parent string) bool {
return IsNamespaceParentOfNamespace(ns, parent) ||
IsNamespaceChildrenOfNamespace(ns, parent) ||
(ns == parent && ns != "" && parent != "")
}

// IsNamespaceParentOfNamespace returns true if the given namespace is a parent of the given parent
func IsNamespaceParentOfNamespace(ns string, child string) bool {

if ns == "" || child == "" {
return false
}

if ns == child {
return false
}

if ns[len(ns)-1] != '/' {
ns = ns + "/"
}

return strings.HasPrefix(child, ns)
}

// IsNamespaceChildrenOfNamespace returns true of the given ns is a children of the given parent.
func IsNamespaceChildrenOfNamespace(ns string, parent string) bool {

if parent == "" || ns == "" {
return false
}

if ns == parent {
return false
}

if parent[len(parent)-1] != '/' {
parent = parent + "/"
}

return strings.HasPrefix(ns, parent)
}

// NamespaceAncestorsNames returns the list of fully qualified namespaces
// in the hierarchy of a given namespace. It returns an empty
// array for the root namespace
func NamespaceAncestorsNames(namespace string) []string {

if namespace == "/" || namespace == "" {
return []string{}
}

parts := strings.Split(namespace, "/")
sep := "/"
namespaces := []string{}

for i := len(parts) - 1; i >= 2; i-- {
namespaces = append(namespaces, sep+strings.Join(parts[1:i], sep))
}

namespaces = append(namespaces, sep)

return namespaces
}
Loading

0 comments on commit 0c8e5dc

Please sign in to comment.