Skip to content

Commit

Permalink
Merge pull request #18 from symbiosis-cloud/feature/add-api-keys
Browse files Browse the repository at this point in the history
added API key management
  • Loading branch information
thecodeassassin authored Nov 17, 2022
2 parents 5759889 + e3a4863 commit 8867f8d
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 23 deletions.
77 changes: 77 additions & 0 deletions api_keys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package symbiosis

import (
"fmt"
"time"
)

type ApiKey struct {
ID string `json:"id"`
Token string `json:"token"`
SubjectID string `json:"subjectId"`
Role UserRole `json:"role"`
Description string `json:"description"`
LastUsedAt time.Time `json:"lastUsedAt"`
}

type ApiKeyService interface {
Create(input ApiKeyInput) (*ApiKey, error)
List() (ApiKeyCollection, error)
Delete(id string) error
}

type ApiKeyInput struct {
Role UserRole `json:"role"`
Description string `json:"description"`
}

type ApiKeyCollection []*ApiKey

type ApiKeyServiceClient struct {
client *Client
}

func (n *ApiKeyServiceClient) Create(input ApiKeyInput) (*ApiKey, error) {
var apiKey *ApiKey

err := n.client.Call(
"/rest/v1/api-keys",
"Post",
&apiKey,
WithBody(input),
)

if err != nil {
return nil, err
}

return apiKey, nil
}

func (n *ApiKeyServiceClient) List() (ApiKeyCollection, error) {
var apiKeys ApiKeyCollection

err := n.client.
Call("/rest/v1/api-keys",
"Get",
&apiKeys)

if err != nil {
return nil, err
}

return apiKeys, nil
}

func (n *ApiKeyServiceClient) Delete(id string) error {
err := n.client.
Call(fmt.Sprintf("/rest/v1/api-keys/%s", id),
"Delete",
nil)

if err != nil {
return err
}

return nil
}
106 changes: 106 additions & 0 deletions api_keys_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package symbiosis

import (
"encoding/json"
"testing"

"github.com/jarcoal/httpmock"
"github.com/stretchr/testify/assert"
)

const apiKeyJSON = `
[
{
"id": "jyduxxxxxxxbdt",
"token": "a0jyduhjjaykagxbdt****************",
"subjectId": "xxxxxxx-040e-401f-a4e5-xxxxxxxxxxx",
"role": "ADMIN",
"lastUsedAt": "2022-06-01T18:36:37.646083Z"
},
{
"id": "pdxxxxxxxxxxxe",
"token": "a0pdxxhusgrasbfxxe****************",
"subjectId": "xxxxxxx-1f16-4e98-893b-xxxxxxxxxxx",
"role": "ADMIN",
"lastUsedAt": null
}
]
`

func TestCreateApiKey(t *testing.T) {
c := getMocketClient()
defer httpmock.DeactivateAndReset()

fakeURL := "/rest/v1/api-keys"

responder := httpmock.NewStringResponder(200, `{
"id": "pdxxxxxxxxxxxe",
"token": "a0pdxxhusgrasbfxxe****************",
"subjectId": "xxxxxxx-1f16-4e98-893b-xxxxxxxxxxx",
"role": "MEMBER",
"lastUsedAt": null
}`)
httpmock.RegisterResponder("POST", fakeURL, responder)

apiKey, err := c.ApiKeys.Create(ApiKeyInput{
Role: ROLE_MEMBER,
Description: "hello world",
})

assert.Nil(t, err)
assert.Equal(t, apiKey.ID, "pdxxxxxxxxxxxe")
assert.Equal(t, apiKey.Role, ROLE_MEMBER)

responder = httpmock.NewErrorResponder(assert.AnError)
httpmock.RegisterResponder("POST", fakeURL, responder)

_, err = c.ApiKeys.Create(ApiKeyInput{
Role: ROLE_MEMBER,
Description: "hello world",
})
assert.Error(t, err)
}

func TestListApiKeys(t *testing.T) {
c := getMocketClient()
defer httpmock.DeactivateAndReset()

fakeURL := "/rest/v1/api-keys"

var fakeApiKeys ApiKeyCollection
json.Unmarshal([]byte(apiKeyJSON), &fakeApiKeys)

responder := httpmock.NewStringResponder(200, apiKeyJSON)
httpmock.RegisterResponder("GET", fakeURL, responder)

apiKeys, err := c.ApiKeys.List()

assert.Nil(t, err)
assert.Equal(t, fakeApiKeys, apiKeys)

responder = httpmock.NewErrorResponder(assert.AnError)
httpmock.RegisterResponder("GET", fakeURL, responder)

_, err = c.ApiKeys.List()
assert.Error(t, err)
}

func TestDeleteApiKey(t *testing.T) {
c := getMocketClient()
defer httpmock.DeactivateAndReset()

fakeURL := "/rest/v1/api-keys/test123"

responder := httpmock.NewStringResponder(200, "")
httpmock.RegisterResponder("DELETE", fakeURL, responder)

err := c.ApiKeys.Delete("test123")

assert.Nil(t, err)

responder = httpmock.NewErrorResponder(assert.AnError)
httpmock.RegisterResponder("DELETE", fakeURL, responder)

err = c.ApiKeys.Delete("test123")
assert.Error(t, err)
}
2 changes: 2 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type Client struct {
Secret SecretService
Project ProjectService
Region RegionService
ApiKeys ApiKeyService
}

type ClientOption func(c *resty.Client)
Expand Down Expand Up @@ -137,6 +138,7 @@ func (c *Client) setServices() {
c.Secret = &SecretServiceClient{c}
c.Project = &ProjectServiceClient{c}
c.Region = &RegionServiceClient{c}
c.ApiKeys = &ApiKeyServiceClient{c}
}

func (c *Client) ValidateResponse(resp *resty.Response) error {
Expand Down
1 change: 0 additions & 1 deletion secrets.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package symbiosis

// /rest/v1/github/{owner}/{repository}/project/secret?environment=preview|development|production
import (
"fmt"
)
Expand Down
32 changes: 16 additions & 16 deletions team.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,45 @@ import (
type TeamService interface {
GetMemberByEmail(email string) (*TeamMember, error)
GetInvitationByEmail(email string) (*TeamMember, error)
InviteMembers(emails []string, role string) ([]*TeamMember, error)
InviteMembers(emails []string, role UserRole) ([]*TeamMember, error)
DeleteMember(email string) error
ChangeRole(email string, role string) error
ValidateRole(role string) error
GetValidRoles() map[string]bool
ChangeRole(email string, role UserRole) error
}

type TeamMember struct {
Email string `json:"email"`
TeamId string `json:"teamId"`
Role string `json:"role"`
Email string `json:"email"`
TeamId string `json:"teamId"`
Role UserRole `json:"role"`
}

type Invite struct {
Emails []string `json:"emails"`
Role string `json:"role"`
Role UserRole `json:"role"`
}

type UserRole string

const (

// Has full access, can create teams
RoleOwner = "OWNER"
ROLE_OWNER UserRole = "OWNER"

// Has full access within a team, can invite other team members
RoleAdmin = "ADMIN"
ROLE_ADMIN UserRole = "ADMIN"

// Can manage resources in clusters but not create them
RoleMember = "MEMBER"
ROLE_MEMBER UserRole = "MEMBER"
)

type TeamServiceClient struct {
client *Client
}

func GetValidRoles() map[string]bool {
return map[string]bool{RoleOwner: true, RoleAdmin: true, RoleMember: true}
func GetValidRoles() map[UserRole]bool {
return map[UserRole]bool{ROLE_OWNER: true, ROLE_ADMIN: true, ROLE_MEMBER: true}
}

func ValidateRole(role string) error {
func ValidateRole(role UserRole) error {
validRoles := GetValidRoles()

if _, ok := validRoles[role]; !ok {
Expand Down Expand Up @@ -88,7 +88,7 @@ func (t *TeamServiceClient) GetInvitationByEmail(email string) (*TeamMember, err
return member, nil
}

func (t *TeamServiceClient) InviteMembers(emails []string, role string) ([]*TeamMember, error) {
func (t *TeamServiceClient) InviteMembers(emails []string, role UserRole) ([]*TeamMember, error) {
err := ValidateRole(role)

if err != nil {
Expand Down Expand Up @@ -126,7 +126,7 @@ func (t *TeamServiceClient) DeleteMember(email string) error {

}

func (t *TeamServiceClient) ChangeRole(email string, role string) error {
func (t *TeamServiceClient) ChangeRole(email string, role UserRole) error {

err := ValidateRole(role)

Expand Down
13 changes: 7 additions & 6 deletions team_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package symbiosis

import (
"encoding/json"
"testing"

"github.com/jarcoal/httpmock"
"github.com/stretchr/testify/assert"
"testing"
)

const teamMemberJSON = `
Expand All @@ -17,7 +18,7 @@ const teamMemberJSON = `
const teamMembersJSON = `[ ` + teamMemberJSON + ` ]`

func TestGetValidRoles(t *testing.T) {
validRoles := map[string]bool{RoleOwner: true, RoleAdmin: true, RoleMember: true}
validRoles := map[UserRole]bool{ROLE_OWNER: true, ROLE_ADMIN: true, ROLE_MEMBER: true}

assert.Equal(t, validRoles, GetValidRoles())
}
Expand Down Expand Up @@ -82,15 +83,15 @@ func TestInviteMembers(t *testing.T) {
responder := httpmock.NewStringResponder(200, teamMembersJSON)
httpmock.RegisterResponder("POST", fakeURL, responder)

teamMembers, err := c.Team.InviteMembers([]string{"[email protected]"}, RoleAdmin)
teamMembers, err := c.Team.InviteMembers([]string{"[email protected]"}, ROLE_ADMIN)

assert.Nil(t, err)
assert.Equal(t, fakeTeamMembers, teamMembers)

responder = httpmock.NewErrorResponder(assert.AnError)
httpmock.RegisterResponder("POST", fakeURL, responder)

_, err = c.Team.InviteMembers([]string{"[email protected]"}, RoleAdmin)
_, err = c.Team.InviteMembers([]string{"[email protected]"}, ROLE_ADMIN)
assert.Error(t, err)

// test invalid role
Expand Down Expand Up @@ -127,14 +128,14 @@ func TestChangeRole(t *testing.T) {
responder := httpmock.NewStringResponder(200, "false")
httpmock.RegisterResponder("PUT", fakeURL, responder)

err := c.Team.ChangeRole("[email protected]", RoleAdmin)
err := c.Team.ChangeRole("[email protected]", ROLE_ADMIN)

assert.Nil(t, err)

responder = httpmock.NewErrorResponder(assert.AnError)
httpmock.RegisterResponder("PUT", fakeURL, responder)

err = c.Team.ChangeRole("[email protected]", RoleAdmin)
err = c.Team.ChangeRole("[email protected]", ROLE_ADMIN)
assert.Error(t, err)

// test invalid role
Expand Down

0 comments on commit 8867f8d

Please sign in to comment.