Skip to content

Commit

Permalink
Merge branch 'main' into small-visual-tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
markphelps authored Nov 14, 2023
2 parents 0b6101e + d6b83dd commit 6334bd5
Show file tree
Hide file tree
Showing 51 changed files with 1,425 additions and 604 deletions.
4 changes: 2 additions & 2 deletions build/generate/screenshots.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
)

func Screenshots(ctx context.Context, client *dagger.Client, flipt *dagger.Container) error {
if err := os.RemoveAll("./screenshots"); err != nil {
if err := os.RemoveAll("./tmp/screenshots"); err != nil {
return err
}
src := client.Host().Directory("./ui/", dagger.HostDirectoryOpts{
Expand Down Expand Up @@ -110,7 +110,7 @@ func Screenshots(ctx context.Context, client *dagger.Client, flipt *dagger.Conta

for c := range containers {
if _, err := c.Directory("screenshots").
Export(ctx, "screenshots"); err != nil {
Export(ctx, "./tmp/screenshots"); err != nil {
return err
}
}
Expand Down
61 changes: 41 additions & 20 deletions build/testing/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"golang.org/x/sync/errgroup"
)

const bootstrapToken = "s3cr3t"

var (
protocolPorts = map[string]int{"http": 8080, "grpc": 9000}
replacer = strings.NewReplacer(" ", "-", "/", "-")
Expand All @@ -39,7 +41,7 @@ type testConfig struct {
name string
namespace string
address string
token string
auth authConfig
port int
}

Expand All @@ -62,6 +64,18 @@ func filterCases(caseNames ...string) (map[string]testCaseFn, error) {
return cases, nil
}

type authConfig int

const (
noAuth authConfig = iota
authNoNamespace
authNamespaced
)

func (a authConfig) enabled() bool {
return a != noAuth
}

func Integration(ctx context.Context, client *dagger.Client, base, flipt *dagger.Container, caseNames ...string) error {
cases, err := filterCases(caseNames...)
if err != nil {
Expand All @@ -81,21 +95,25 @@ func Integration(ctx context.Context, client *dagger.Client, base, flipt *dagger

for _, namespace := range []string{"", "production"} {
for protocol, port := range protocolPorts {
for _, token := range []string{"", "some-token"} {
name := fmt.Sprintf("%s namespace %s", strings.ToUpper(protocol), namespace)
if token != "" {
name = fmt.Sprintf("%s with token %s", name, token)
for _, auth := range []authConfig{noAuth, authNoNamespace, authNamespaced} {
config := testConfig{
name: fmt.Sprintf("%s namespace %s", strings.ToUpper(protocol), namespace),
namespace: namespace,
auth: auth,
address: fmt.Sprintf("%s://flipt:%d", protocol, port),
port: port,
}

configs = append(configs,
testConfig{
name: name,
namespace: namespace,
address: fmt.Sprintf("%s://flipt:%d", protocol, port),
token: token,
port: port,
},
)
switch auth {
case noAuth:
config.name = fmt.Sprintf("%s without auth", config.name)
case authNoNamespace:
config.name = fmt.Sprintf("%s with auth no namespaced token", config.name)
case authNamespaced:
config.name = fmt.Sprintf("%s with auth namespaced token", config.name)
}

configs = append(configs, config)
}
}
}
Expand All @@ -112,11 +130,11 @@ func Integration(ctx context.Context, client *dagger.Client, base, flipt *dagger
)

flipt := flipt
if config.token != "" {
if config.auth.enabled() {
flipt = flipt.
WithEnvVariable("FLIPT_AUTHENTICATION_REQUIRED", "true").
WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_TOKEN_ENABLED", "true").
WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_TOKEN_BOOTSTRAP_TOKEN", config.token)
WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_TOKEN_BOOTSTRAP_TOKEN", bootstrapToken)
}

name := strings.ToLower(replacer.Replace(fmt.Sprintf("flipt-test-%s-config-%s", caseName, config.name)))
Expand Down Expand Up @@ -306,8 +324,8 @@ func importExport(ctx context.Context, _ *dagger.Client, base, flipt *dagger.Con
return func() error {
// import testdata before running readonly suite
flags := []string{"--address", conf.address}
if conf.token != "" {
flags = append(flags, "--token", conf.token)
if conf.auth.enabled() {
flags = append(flags, "--token", bootstrapToken)
}

ns := "default"
Expand Down Expand Up @@ -394,8 +412,11 @@ func suite(ctx context.Context, dir string, base, flipt *dagger.Container, conf
flags = append(flags, "--flipt-namespace", conf.namespace)
}

if conf.token != "" {
flags = append(flags, "--flipt-token", conf.token)
if conf.auth.enabled() {
flags = append(flags, "--flipt-token", bootstrapToken)
if conf.auth == authNamespaced {
flags = append(flags, "--flipt-create-namespaced-token")
}
}

_, err = base.
Expand Down
38 changes: 29 additions & 9 deletions build/testing/integration/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,26 @@ import (

func API(t *testing.T, ctx context.Context, client sdk.SDK, opts integration.TestOpts) {
var (
namespace = opts.Namespace
authenticated = opts.Authenticated
addr = opts.Addr
protocol = opts.Protocol
addr = opts.Addr
protocol = opts.Protocol
namespace = opts.Namespace
authConfig = opts.AuthConfig
)

t.Run("Namespaces", func(t *testing.T) {
if !namespaceIsDefault(namespace) {
if authConfig == integration.AuthNamespaced {
t.Log("Create namespace.")

_, err := client.Flipt().CreateNamespace(ctx, &flipt.CreateNamespaceRequest{
Key: namespace,
Name: namespace,
})

require.NoError(t, err)
return
}

t.Log(`Create namespace.`)

created, err := client.Flipt().CreateNamespace(ctx, &flipt.CreateNamespaceRequest{
Expand Down Expand Up @@ -494,7 +506,7 @@ func API(t *testing.T, ctx context.Context, client sdk.SDK, opts integration.Tes
assert.Equal(t, int32(3), updatedRuleThree.Rank)

// ensure you can not link flags and segments from different namespaces.
if !namespaceIsDefault(namespace) {
if !namespaceIsDefault(namespace) && authConfig != integration.AuthNamespaced {
t.Log(`Ensure that rules can only link entities in the same namespace.`)
_, err = client.Flipt().CreateRule(ctx, &flipt.CreateRuleRequest{
FlagKey: "test",
Expand Down Expand Up @@ -574,7 +586,7 @@ func API(t *testing.T, ctx context.Context, client sdk.SDK, opts integration.Tes
})
require.NoError(t, err)

if !namespaceIsDefault(namespace) {
if !namespaceIsDefault(namespace) && authConfig != integration.AuthNamespaced {
t.Log(`Ensure that distributions and all entities associated with them are part of same namespace.`)
var (
flagKey = "defaultflag"
Expand Down Expand Up @@ -1035,7 +1047,7 @@ func API(t *testing.T, ctx context.Context, client sdk.SDK, opts integration.Tes
})
})

t.Run("Compatability", func(t *testing.T) {
t.Run("Compatibility", func(t *testing.T) {
// ensure we can leverage new and old evaluation paths and produce consistent results
t.Run("new API to legacy API", func(t *testing.T) {
entity := uuid.Must(uuid.NewV4()).String()
Expand Down Expand Up @@ -1269,7 +1281,7 @@ func API(t *testing.T, ctx context.Context, client sdk.SDK, opts integration.Tes
require.NoError(t, err)

for _, rule := range rules.Rules {
client.Flipt().DeleteRule(ctx, &flipt.DeleteRuleRequest{
_ = client.Flipt().DeleteRule(ctx, &flipt.DeleteRuleRequest{
NamespaceKey: namespace,
FlagKey: "test",
Id: rule.Id,
Expand Down Expand Up @@ -1326,6 +1338,13 @@ func API(t *testing.T, ctx context.Context, client sdk.SDK, opts integration.Tes
t.Run("Meta", func(t *testing.T) {
t.Log(`Returns Flipt service information.`)

// meta shouldn't be reachable with a namespace scoped token
if authConfig == integration.AuthNamespaced {
_, err := client.Meta().GetInfo(ctx)
require.EqualError(t, err, "rpc error: code = Unauthenticated desc = request was not authenticated")
return
}

info, err := client.Meta().GetInfo(ctx)
require.NoError(t, err)

Expand Down Expand Up @@ -1373,7 +1392,8 @@ func API(t *testing.T, ctx context.Context, client sdk.SDK, opts integration.Tes
t.Run("Auth", func(t *testing.T) {
t.Run("Self", func(t *testing.T) {
_, err := client.Auth().AuthenticationService().GetAuthenticationSelf(ctx)
if authenticated {
if authConfig == integration.AuthNoNamespace {
// only valid with a non-scoped token
assert.NoError(t, err)
} else {
assert.EqualError(t, err, "rpc error: code = Unauthenticated desc = request was not authenticated")
Expand Down
4 changes: 2 additions & 2 deletions build/testing/integration/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ func TestAPI(t *testing.T) {
api.API(t, ctx, sdk, opts)

// run extra tests in authenticated context
if opts.Authenticated {
api.Authenticated(t, sdk)
if opts.AuthConfig.Required() {
api.Authenticated(t, sdk, opts)
}
})
}
77 changes: 65 additions & 12 deletions build/testing/integration/api/authenticated.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,36 @@ import (

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.flipt.io/flipt/build/testing/integration"
"go.flipt.io/flipt/rpc/flipt/auth"
sdk "go.flipt.io/flipt/sdk/go"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
)

func Authenticated(t *testing.T, client sdk.SDK) {
func Authenticated(t *testing.T, client sdk.SDK, opts integration.TestOpts) {
t.Run("Authentication Methods", func(t *testing.T) {
ctx := context.Background()

t.Log(`List methods (ensure at-least 1).`)
t.Run("List methods", func(t *testing.T) {
t.Log(`List methods (ensure at-least 1).`)

methods, err := client.Auth().PublicAuthenticationService().ListAuthenticationMethods(ctx)
require.NoError(t, err)
methods, err := client.Auth().PublicAuthenticationService().ListAuthenticationMethods(ctx)

assert.NotEmpty(t, methods)
require.NoError(t, err)

assert.NotEmpty(t, methods)
})

t.Run("Get Self", func(t *testing.T) {
authn, err := client.Auth().AuthenticationService().GetAuthenticationSelf(ctx)

if opts.AuthConfig == integration.AuthNamespaced {
require.EqualError(t, err, "rpc error: code = Unauthenticated desc = request was not authenticated")
return
}

require.NoError(t, err)

assert.NotEmpty(t, authn.Id)
Expand All @@ -34,21 +44,64 @@ func Authenticated(t *testing.T, client sdk.SDK) {
t.Run("Static Token", func(t *testing.T) {
t.Log(`Create token.`)

resp, err := client.Auth().AuthenticationMethodTokenService().CreateToken(ctx, &auth.CreateTokenRequest{
Name: "Access Token",
Description: "Some kind of access token.",
t.Run("With name and description", func(t *testing.T) {
resp, err := client.Auth().AuthenticationMethodTokenService().CreateToken(ctx, &auth.CreateTokenRequest{
Name: "Access Token",
Description: "Some kind of access token.",
})

// a namespaced token should not be able to create any other tokens
if opts.AuthConfig == integration.AuthNamespaced {
require.EqualError(t, err, "rpc error: code = Unauthenticated desc = request was not authenticated")
return
}

require.NoError(t, err)

assert.NotEmpty(t, resp.ClientToken)
assert.Equal(t, "Access Token", resp.Authentication.Metadata["io.flipt.auth.token.name"])
assert.Equal(t, "Some kind of access token.", resp.Authentication.Metadata["io.flipt.auth.token.description"])
})
require.NoError(t, err)

assert.NotEmpty(t, resp.ClientToken)
assert.Equal(t, "Access Token", resp.Authentication.Metadata["io.flipt.auth.token.name"])
assert.Equal(t, "Some kind of access token.", resp.Authentication.Metadata["io.flipt.auth.token.description"])
t.Run("With name and namespaceKey", func(t *testing.T) {
// namespaced scoped tokens can only create tokens
// in the same namespace
// this ensures that the scope is appropriate for that condition
namespace := opts.Namespace
if namespace == "" {
namespace = "some-namespace"
}

resp, err := client.Auth().AuthenticationMethodTokenService().CreateToken(ctx, &auth.CreateTokenRequest{
Name: "Scoped Access Token",
NamespaceKey: namespace,
})

// a namespaced token should not be able to create any other tokens
if opts.AuthConfig == integration.AuthNamespaced {
require.EqualError(t, err, "rpc error: code = Unauthenticated desc = request was not authenticated")
return
}

require.NoError(t, err)

assert.NotEmpty(t, resp.ClientToken)
assert.Equal(t, "Scoped Access Token", resp.Authentication.Metadata["io.flipt.auth.token.name"])
assert.Empty(t, resp.Authentication.Metadata["io.flipt.auth.token.description"])
assert.Equal(t, namespace, resp.Authentication.Metadata["io.flipt.auth.token.namespace"])
})
})

t.Run("Expire Self", func(t *testing.T) {
err := client.Auth().AuthenticationService().ExpireAuthenticationSelf(ctx, &auth.ExpireAuthenticationSelfRequest{
ExpiresAt: timestamppb.Now(),
})

if opts.AuthConfig == integration.AuthNamespaced {
require.EqualError(t, err, "rpc error: code = Unauthenticated desc = request was not authenticated")
return
}

require.NoError(t, err)

t.Log(`Ensure token is no longer valid.`)
Expand Down
Loading

0 comments on commit 6334bd5

Please sign in to comment.