-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(backend): implement generate name for new access request (#34)
Signed-off-by: Alexandre Gaudreault <[email protected]> Signed-off-by: Leonardo Luz Almeida <[email protected]> Co-authored-by: Leonardo Luz Almeida <[email protected]>
- Loading branch information
1 parent
42f2f85
commit 5cac08b
Showing
5 changed files
with
260 additions
and
7 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
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 |
---|---|---|
|
@@ -4,6 +4,7 @@ import ( | |
"context" | ||
"fmt" | ||
"slices" | ||
"strings" | ||
"testing" | ||
"time" | ||
|
||
|
@@ -16,6 +17,7 @@ import ( | |
"github.com/stretchr/testify/mock" | ||
"github.com/stretchr/testify/require" | ||
"k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/apimachinery/pkg/api/validation" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
|
@@ -67,7 +69,7 @@ func TestServiceCreateAccessRequest(t *testing.T) { | |
// Then | ||
assert.NoError(t, err) | ||
assert.NotNil(t, result) | ||
assert.Equal(t, "todo-", result.GetGenerateName()) | ||
assert.Equal(t, fmt.Sprintf("%s-%s-", key.Username, ab.Spec.RoleTemplateRef.Name), result.GetGenerateName()) | ||
assert.Equal(t, key.Namespace, result.GetNamespace()) | ||
assert.Equal(t, key.ApplicationName, result.Spec.Application.Name) | ||
assert.Equal(t, key.ApplicationNamespace, result.Spec.Application.Namespace) | ||
|
@@ -705,3 +707,71 @@ func Test_defaultAccessRequestSort(t *testing.T) { | |
require.Equal(t, third, items[2]) | ||
}) | ||
} | ||
|
||
func Test_getAccessRequestPrefix(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
username string | ||
roleName string | ||
expected string | ||
}{ | ||
{ | ||
name: "should use the first part of email", | ||
username: "[email protected]", | ||
roleName: "my-role", | ||
expected: "test-my-role-", | ||
}, | ||
{ | ||
name: "should not exceed max length", | ||
username: "loremipsumdolorsitametconsecteturadipiscingelitsuspendissetempussemperleoeuvestibulumsemtincidunttinciduntvestibulumaccumsanmaurissedrisusdignissimaliq", | ||
roleName: "uamaeneanabibendumtellusaeneandapibuslacusetinterdumfeugiatsuspendissevehiculaliberodignissimturpistincidunttristiquepraesentmolestietemporduieugravida", | ||
expected: "loremipsumdolorsitametconsec-uamaeneanabibendumtellusaene-", | ||
}, | ||
{ | ||
name: "should use the maximum amount available for username", | ||
username: "loremipsumdolorsitametconsecteturadipiscingelitsuspendissetem", | ||
roleName: "uamaenea", | ||
expected: "loremipsumdolorsitametconsecteturadipiscingelits-uamaenea-", | ||
}, | ||
{ | ||
name: "should use the maximum amount available for roleName", | ||
username: "uamaenea", | ||
roleName: "loremipsumdolorsitametconsecteturadipiscingelitsuspe", | ||
expected: "uamaenea-loremipsumdolorsitametconsecteturadipiscingelits-", | ||
}, | ||
{ | ||
name: "should not contain any invalid char", | ||
username: "my.(user)[1234567890] +_)(*&^%$#@!~", | ||
roleName: "a-role +_)(*&^%$#@!~", | ||
expected: "my.user1234567890-a-role-", | ||
}, | ||
{ | ||
name: "should not start with a dash", | ||
username: "---username", | ||
roleName: "---role", | ||
expected: "username-role-", | ||
}, | ||
{ | ||
name: "should not start with a period", | ||
username: ".username", | ||
roleName: "...role", | ||
expected: "username-role-", | ||
}, | ||
{ | ||
name: "should be lowercase", | ||
username: "UserName", | ||
roleName: "Role", | ||
expected: "username-role-", | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got := backend.GetAccessRequestPrefix(tt.username, tt.roleName) | ||
validationErrors := validation.NameIsDNSSubdomain(got, true) | ||
|
||
assert.Equal(t, tt.expected, got) | ||
assert.Equalf(t, 0, len(validationErrors), fmt.Sprintf("Validation Errors: \n%s", strings.Join(validationErrors, "\n"))) | ||
assert.LessOrEqual(t, len(got), backend.MaxGeneratedNameLength) | ||
}) | ||
} | ||
} |
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,40 @@ | ||
package generator | ||
|
||
import ( | ||
"math" | ||
"regexp" | ||
"strings" | ||
) | ||
|
||
var ( | ||
DNS1123SubdomainInvalidCharSet = regexp.MustCompile("[^a-z0-9-.]") | ||
DNS1123SubdomainInvalidStartChartSet = regexp.MustCompile("^[^a-z0-9]+") | ||
) | ||
|
||
// ToDNS1123Subdomain removes all invalid char for a DNS1123Subdomain string and transform it to a valid format | ||
func ToDNS1123Subdomain(data string) string { | ||
data = strings.ToLower(data) | ||
data = DNS1123SubdomainInvalidCharSet.ReplaceAllString(data, "") | ||
data = DNS1123SubdomainInvalidStartChartSet.ReplaceAllString(data, "") | ||
return data | ||
} | ||
|
||
// ToMaxLength reduce the total length of the strings, balancing the length as evently as possible | ||
func ToMaxLength(a, b string, max int) (string, string) { | ||
aLength := len(a) | ||
bLength := len(b) | ||
halfLength := max / 2 | ||
remainder := max % 2 | ||
minLength := int(math.Min(float64(aLength), float64(bLength))) | ||
available := int(math.Max(0, float64(halfLength-minLength))) | ||
|
||
if aLength >= halfLength+available+remainder { | ||
a = a[:halfLength+available+remainder] | ||
remainder = 0 | ||
} | ||
if bLength >= halfLength+available+remainder { | ||
b = b[:halfLength+available+remainder] | ||
remainder = 0 | ||
} | ||
return a, b | ||
} |
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,124 @@ | ||
package generator_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/argoproj-labs/ephemeral-access/internal/pkg/generator" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestToDNS1123Subdomain(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
data string | ||
expected string | ||
}{ | ||
{ | ||
name: "should not contain any invalid char", | ||
data: "my.(user)[1234567890] +_)(*&^%$#@!~", | ||
expected: "my.user1234567890", | ||
}, | ||
{ | ||
name: "should not start with a dash", | ||
data: "---username", | ||
expected: "username", | ||
}, | ||
{ | ||
name: "should not start with a period", | ||
data: "...role", | ||
expected: "role", | ||
}, | ||
{ | ||
name: "should be lowercase", | ||
data: "UserName", | ||
expected: "username", | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
if got := generator.ToDNS1123Subdomain(tt.data); got != tt.expected { | ||
t.Errorf("ToDNS1123Subdomain() = %v, want %v", got, tt.expected) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestToMaxLength(t *testing.T) { | ||
type args struct { | ||
a string | ||
b string | ||
max int | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
a string | ||
b string | ||
}{ | ||
{ | ||
name: "strings already balanced", | ||
args: args{ | ||
|
||
a: "abcd", | ||
b: "1234", | ||
max: 99, | ||
}, | ||
a: "abcd", | ||
b: "1234", | ||
}, | ||
{ | ||
name: "strings are balanced to max", | ||
args: args{ | ||
|
||
a: "abcd", | ||
b: "1234", | ||
max: 4, | ||
}, | ||
a: "ab", | ||
b: "12", | ||
}, | ||
{ | ||
name: "remainder to A if max is odd and both too long", | ||
args: args{ | ||
|
||
a: "abcd", | ||
b: "1234", | ||
max: 5, | ||
}, | ||
a: "abc", | ||
b: "12", | ||
}, | ||
{ | ||
name: "remainder to A if max is odd and A too long", | ||
args: args{ | ||
|
||
a: "abcd", | ||
b: "12", | ||
max: 5, | ||
}, | ||
a: "abc", | ||
b: "12", | ||
}, | ||
{ | ||
name: "remainder to B if max is odd and B too long", | ||
args: args{ | ||
|
||
a: "ab", | ||
b: "1234", | ||
max: 5, | ||
}, | ||
a: "ab", | ||
b: "123", | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
a, b := generator.ToMaxLength(tt.args.a, tt.args.b, tt.args.max) | ||
assert.Equal(t, tt.a, a) | ||
assert.Equal(t, tt.b, b) | ||
if len(tt.args.a)+len(tt.args.b) >= tt.args.max { | ||
assert.Equal(t, tt.args.max, len(a)+len(b)) | ||
} | ||
}) | ||
} | ||
} |