Skip to content

Commit

Permalink
refactor(build): remove authentication from IT matrix
Browse files Browse the repository at this point in the history
  • Loading branch information
GeorgeMac committed Jun 6, 2024
1 parent 54ce56a commit befff01
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 245 deletions.
163 changes: 53 additions & 110 deletions build/testing/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ var (
type testConfig struct {
name string
address string
auth authConfig
port int
references bool
}
Expand All @@ -95,32 +94,6 @@ func filterCases(caseNames ...string) (map[string]testCaseFn, error) {
return cases, nil
}

type authConfig int

const (
noAuth authConfig = iota
staticAuth
jwtAuth
k8sAuth
)

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

func (a authConfig) method() string {
switch a {
case staticAuth:
return "static"
case jwtAuth:
return "jwt"
case k8sAuth:
return "k8s"
default:
return ""
}
}

func Integration(ctx context.Context, client *dagger.Client, base, flipt *dagger.Container, caseNames ...string) error {
cases, err := filterCases(caseNames...)
if err != nil {
Expand All @@ -139,28 +112,13 @@ func Integration(ctx context.Context, client *dagger.Client, base, flipt *dagger
var configs []testConfig

for protocol, port := range protocolPorts {
for _, auth := range []authConfig{noAuth, staticAuth, jwtAuth, k8sAuth} {
auth := auth
config := testConfig{
name: strings.ToUpper(protocol),
auth: auth,
address: fmt.Sprintf("%s://flipt:%d", protocol, port),
port: port,
}

switch auth {
case noAuth:
config.name = fmt.Sprintf("%s without auth", config.name)
case staticAuth:
config.name = fmt.Sprintf("%s with static auth token", config.name)
case jwtAuth:
config.name = fmt.Sprintf("%s with jwt auth", config.name)
case k8sAuth:
config.name = fmt.Sprintf("%s with k8s auth", config.name)
}

configs = append(configs, config)
config := testConfig{
name: strings.ToUpper(protocol),
address: fmt.Sprintf("%s://flipt:%d", protocol, port),
port: port,
}

configs = append(configs, config)
}

var g errgroup.Group
Expand All @@ -175,46 +133,57 @@ func Integration(ctx context.Context, client *dagger.Client, base, flipt *dagger
)

g.Go(take(func() error {
if config.auth.enabled() {
{
// Static token auth configuration
flipt = flipt.
WithEnvVariable("FLIPT_AUTHENTICATION_REQUIRED", "true").
WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_TOKEN_ENABLED", "true").
WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_TOKEN_BOOTSTRAP_TOKEN", bootstrapToken)
}
{
// K8s auth configuration
flipt = flipt.
WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_KUBERNETES_ENABLED", "true")

var saToken string
// run an OIDC server which exposes a JWKS url using a private key we own
// and generate a JWT to act as our SA token
flipt, saToken, err = serveOIDC(ctx, client, base, flipt)
if err != nil {
return err
}

switch config.auth {
case k8sAuth:
flipt = flipt.
WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_KUBERNETES_ENABLED", "true")

var saToken string
// run an OIDC server which exposes a JWKS url using a private key we own
// and generate a JWT to act as our SA token
flipt, saToken, err = serveOIDC(ctx, client, base, flipt)
if err != nil {
return err
}

// mount service account token into base on expected k8s sa token path
base = base.WithNewFile("/var/run/secrets/kubernetes.io/serviceaccount/token", dagger.ContainerWithNewFileOpts{
Contents: saToken,
})
case jwtAuth:
bytes, err := x509.MarshalPKIXPublicKey(priv.Public())
if err != nil {
return err
}

bytes = pem.EncodeToMemory(&pem.Block{
Type: "public key",
Bytes: bytes,
})

flipt = flipt.
WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_JWT_ENABLED", "true").
WithNewFile("/etc/flipt/jwt.pem", dagger.ContainerWithNewFileOpts{Contents: string(bytes)}).
WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_JWT_PUBLIC_KEY_FILE", "/etc/flipt/jwt.pem").
WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_JWT_VALIDATE_CLAIMS_ISSUER", "https://flipt.io")
// mount service account token into base on expected k8s sa token path
base = base.WithNewFile("/var/run/secrets/kubernetes.io/serviceaccount/token", dagger.ContainerWithNewFileOpts{
Contents: saToken,
})
}
{
// JWT auth configuration
bytes, err := x509.MarshalPKIXPublicKey(priv.Public())
if err != nil {
return err
}

bytes = pem.EncodeToMemory(&pem.Block{
Type: "public key",
Bytes: bytes,
})

flipt = flipt.
WithNewFile("/etc/flipt/jwt.pem", dagger.ContainerWithNewFileOpts{Contents: string(bytes)}).
WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_JWT_ENABLED", "true").
WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_JWT_PUBLIC_KEY_FILE", "/etc/flipt/jwt.pem").
WithEnvVariable("FLIPT_AUTHENTICATION_METHODS_JWT_VALIDATE_CLAIMS_ISSUER", "https://flipt.io")

privBytes := pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(priv),
})

base = base.WithNewFile("/var/run/secrets/flipt/private.pem", dagger.ContainerWithNewFileOpts{
Contents: string(privBytes),
})
}

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

// create unique instance for test case
fliptToTest := flipt.
Expand Down Expand Up @@ -658,34 +624,11 @@ func importExport(ctx context.Context, _ *dagger.Client, base, flipt *dagger.Con

func suite(ctx context.Context, dir string, base, flipt *dagger.Container, conf testConfig) func() error {
return func() (err error) {
flags := []string{"--flipt-addr", conf.address}
flags := []string{"--flipt-addr", conf.address, "--flipt-token", bootstrapToken}
if conf.references {
flags = append(flags, "--flipt-supports-references")
}

if conf.auth.enabled() {
flags = append(flags, "--flipt-token-type", conf.auth.method())

switch conf.auth.method() {
case "static":
flags = append(flags, "--flipt-token", bootstrapToken)
case "jwt":
var (
now = time.Now()
nowUnix = float64(now.Unix())
futureUnix = float64(now.Add(2 * jjwt.DefaultLeeway).Unix())
)

token := signJWT(priv, map[string]interface{}{
"iss": "https://flipt.io",
"iat": nowUnix,
"exp": futureUnix,
})

flags = append(flags, "--flipt-token", token)
}
}

_, err = base.
WithWorkdir(path.Join("build/testing/integration", dir)).
WithEnvVariable("UNIQUE", uuid.New().String()).
Expand Down
26 changes: 8 additions & 18 deletions build/testing/integration/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@ import (
"go.flipt.io/flipt/build/testing/integration"
"go.flipt.io/flipt/rpc/flipt"
"go.flipt.io/flipt/rpc/flipt/evaluation"
sdk "go.flipt.io/flipt/sdk/go"
"google.golang.org/protobuf/testing/protocmp"
)

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

t.Run("Namespaces", func(t *testing.T) {
Expand Down Expand Up @@ -1336,17 +1334,13 @@ func API(t *testing.T, ctx context.Context, client sdk.SDK, opts integration.Tes
}

t.Run("Metrics", func(t *testing.T) {
if authConfig.Required() {
t.Skip("Skipping metrics test for now as it requires authentication")
}

if protocol == integration.ProtocolGRPC {
t.Skip("Skipping metrics test for now as it requires HTTP/HTTPS protocol")
t.Skip("TODO: we do not support metric test for grpc yet")
}

t.Log(`Ensure /metrics endpoint is reachable.`)

resp, err := http.Get(fmt.Sprintf("%s/metrics", addr))
resp, err := http.Get(fmt.Sprintf("%s/metrics", opts.URL))
require.NoError(t, err)

require.NotNil(t, resp)
Expand Down Expand Up @@ -1417,11 +1411,6 @@ 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 !authConfig.Required() {
assert.EqualError(t, err, "rpc error: code = Unauthenticated desc = request was not authenticated")
return
}

assert.NoError(t, err)
})
t.Run("Public", func(t *testing.T) {
Expand All @@ -1431,11 +1420,12 @@ func API(t *testing.T, ctx context.Context, client sdk.SDK, opts integration.Tes
})

t.Run("Healthcheck", func(t *testing.T) {
if protocol == "grpc" {
if protocol == integration.ProtocolGRPC {
t.Skip("TODO: we do not support healthcheck test for grpc yet")
}

t.Run("HTTP", func(t *testing.T) {
resp, err := http.Get(fmt.Sprintf("%s/health", addr))
resp, err := http.Get(fmt.Sprintf("%s/health", opts.URL))
require.NoError(t, err)

assert.Equal(t, "application/json", resp.Header.Get("Content-Type"))
Expand Down
11 changes: 4 additions & 7 deletions build/testing/integration/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,15 @@ import (

"go.flipt.io/flipt/build/testing/integration"
"go.flipt.io/flipt/build/testing/integration/api"
sdk "go.flipt.io/flipt/sdk/go"
)

func TestAPI(t *testing.T) {
integration.Harness(t, func(t *testing.T, sdk sdk.SDK, opts integration.TestOpts) {
integration.Harness(t, func(t *testing.T, opts integration.TestOpts) {
ctx := context.Background()

api.API(t, ctx, sdk, opts)
api.API(t, ctx, opts)

// run extra tests in authenticated context
if opts.AuthConfig.Required() {
api.Authenticated(t, sdk, opts)
}
// run extra authenticaiton related tests
api.Authenticated(t, opts)
})
}
13 changes: 3 additions & 10 deletions build/testing/integration/api/authenticated.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ import (
"go.flipt.io/flipt/build/testing/integration"
"go.flipt.io/flipt/rpc/flipt"
"go.flipt.io/flipt/rpc/flipt/auth"
sdk "go.flipt.io/flipt/sdk/go"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

func Authenticated(t *testing.T, client sdk.SDK, opts integration.TestOpts) {
func Authenticated(t *testing.T, opts integration.TestOpts) {
client := opts.DefaultClient(t)

t.Run("Authentication Methods", func(t *testing.T) {
ctx := context.Background()

Expand All @@ -30,10 +31,6 @@ func Authenticated(t *testing.T, client sdk.SDK, opts integration.TestOpts) {
})

t.Run("Get Self", func(t *testing.T) {
if !opts.AuthConfig.StaticToken() {
t.Skip("Skipping test for non-static token authentication")
}

authn, err := client.Auth().AuthenticationService().GetAuthenticationSelf(ctx)

require.NoError(t, err)
Expand Down Expand Up @@ -68,10 +65,6 @@ func Authenticated(t *testing.T, client sdk.SDK, opts integration.TestOpts) {
})

t.Run("Expire Self", func(t *testing.T) {
if !opts.AuthConfig.StaticToken() {
t.Skip("Skipping test for non-static token authentication")
}

err := client.Auth().AuthenticationService().ExpireAuthenticationSelf(ctx, &auth.ExpireAuthenticationSelfRequest{
ExpiresAt: flipt.Now(),
})
Expand Down
Loading

0 comments on commit befff01

Please sign in to comment.