diff --git a/docs/auth0_terraform_generate.md b/docs/auth0_terraform_generate.md index ae6ac2934..34488f095 100644 --- a/docs/auth0_terraform_generate.md +++ b/docs/auth0_terraform_generate.md @@ -28,7 +28,7 @@ auth0 terraform generate [flags] ``` --force Skip confirmation. -o, --output-dir string Output directory for the generated Terraform config files. If not provided, the files will be saved in the current working directory. (default "./") - -r, --resources strings Resource types to generate Terraform config for. If not provided, config files for all available resources will be generated. (default [auth0_action,auth0_branding,auth0_client,auth0_connection,auth0_custom_domain,auth0_organization,auth0_role,auth0_tenant]) + -r, --resources strings Resource types to generate Terraform config for. If not provided, config files for all available resources will be generated. (default [auth0_action,auth0_branding,auth0_client,auth0_client_grant,auth0_connection,auth0_custom_domain,auth0_organization,auth0_role,auth0_tenant]) ``` diff --git a/internal/auth0/mock/client_grant_mock.go b/internal/auth0/mock/client_grant_mock.go new file mode 100644 index 000000000..11d423f37 --- /dev/null +++ b/internal/auth0/mock/client_grant_mock.go @@ -0,0 +1,56 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: client.go + +// Package mock is a generated GoMock package. +package mock + +import ( + context "context" + reflect "reflect" + + management "github.com/auth0/go-auth0/management" + gomock "github.com/golang/mock/gomock" +) + +// MockClientGrantAPI is a mock of ClientAPI interface. +type MockClientGrantAPI struct { + ctrl *gomock.Controller + recorder *MockClientGrantAPIMockRecorder +} + +// MockClientGrantAPIMockRecorder is the mock recorder for MockClientGrantAPI. +type MockClientGrantAPIMockRecorder struct { + mock *MockClientGrantAPI +} + +// NewMockClientGrantAPI creates a new mock instance. +func NewMockClientGrantAPI(ctrl *gomock.Controller) *MockClientGrantAPI { + mock := &MockClientGrantAPI{ctrl: ctrl} + mock.recorder = &MockClientGrantAPIMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockClientGrantAPI) EXPECT() *MockClientGrantAPIMockRecorder { + return m.recorder +} + +// List mocks base method. +func (m *MockClientGrantAPI) List(ctx context.Context, opts ...management.RequestOption) (*management.ClientGrantList, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "List", varargs...) + ret0, _ := ret[0].(*management.ClientGrantList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// List indicates an expected call of List. +func (mr *MockClientGrantAPIMockRecorder) List(ctx interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockClientGrantAPI)(nil).List), varargs...) +} \ No newline at end of file diff --git a/internal/cli/terraform.go b/internal/cli/terraform.go index 09c0f8dc1..8f2bdb949 100644 --- a/internal/cli/terraform.go +++ b/internal/cli/terraform.go @@ -61,6 +61,8 @@ func (i *terraformInputs) parseResourceFetchers(api *auth0.API) ([]resourceDataF fetchers = append(fetchers, &brandingResourceFetcher{}) case "auth0_client": fetchers = append(fetchers, &clientResourceFetcher{api}) + case "auth0_client_grant": + fetchers = append(fetchers, &clientGrantResourceFetcher{api}) case "auth0_connection": fetchers = append(fetchers, &connectionResourceFetcher{api}) case "auth0_custom_domain": diff --git a/internal/cli/terraform_fetcher.go b/internal/cli/terraform_fetcher.go index d08644420..f04dcd75e 100644 --- a/internal/cli/terraform_fetcher.go +++ b/internal/cli/terraform_fetcher.go @@ -10,7 +10,7 @@ import ( "github.com/auth0/auth0-cli/internal/auth0" ) -var defaultResources = []string{"auth0_action", "auth0_branding", "auth0_client", "auth0_connection", "auth0_custom_domain", "auth0_organization", "auth0_role", "auth0_tenant"} +var defaultResources = []string{"auth0_action", "auth0_branding", "auth0_client", "auth0_client_grant", "auth0_connection", "auth0_custom_domain", "auth0_organization", "auth0_role", "auth0_tenant"} type ( importDataList []importDataItem @@ -35,6 +35,10 @@ type ( api *auth0.API } + clientGrantResourceFetcher struct { + api *auth0.API + } + connectionResourceFetcher struct { api *auth0.API } @@ -93,6 +97,36 @@ func (f *clientResourceFetcher) FetchData(ctx context.Context) (importDataList, return data, nil } +func (f *clientGrantResourceFetcher) FetchData(ctx context.Context) (importDataList, error) { + var data importDataList + + var page int + for { + grants, err := f.api.ClientGrant.List( + ctx, + management.Page(page), + ) + if err != nil { + return nil, err + } + + for _, grant := range grants.ClientGrants { + data = append(data, importDataItem{ + ResourceName: "auth0_client_grant." + grant.GetClientID() + "_" + sanitizeResourceName(grant.GetAudience()), + ImportID: grant.GetID(), + }) + } + + if !grants.HasNext() { + break + } + + page++ + } + + return data, nil +} + func (f *connectionResourceFetcher) FetchData(ctx context.Context) (importDataList, error) { var data importDataList diff --git a/internal/cli/terraform_fetcher_test.go b/internal/cli/terraform_fetcher_test.go index 046db945c..fbc6f65c4 100644 --- a/internal/cli/terraform_fetcher_test.go +++ b/internal/cli/terraform_fetcher_test.go @@ -140,6 +140,19 @@ func TestActionResourceFetcher_FetchData(t *testing.T) { assert.EqualError(t, err, "failed to list actions") }) } + +func TestBrandingResourceFetcher_FetchData(t *testing.T) { + t.Run("it successfully generates branding import data", func(t *testing.T) { + fetcher := brandingResourceFetcher{} + + data, err := fetcher.FetchData(context.Background()) + assert.NoError(t, err) + assert.Len(t, data, 1) + assert.Equal(t, data[0].ResourceName, "auth0_branding.branding") + assert.Greater(t, len(data[0].ImportID), 0) + }) +} + func TestClientResourceFetcher_FetchData(t *testing.T) { t.Run("it successfully retrieves client data", func(t *testing.T) { ctrl := gomock.NewController(t) @@ -241,15 +254,108 @@ func TestClientResourceFetcher_FetchData(t *testing.T) { }) } -func TestBrandingResourceFetcher_FetchData(t *testing.T) { - t.Run("it successfully generates branding import data", func(t *testing.T) { - fetcher := brandingResourceFetcher{} +func TestClientGrantResourceFetcher_FetchData(t *testing.T) { + t.Run("it successfully retrieves client grant data", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + clientGrantAPI := mock.NewMockClientGrantAPI(ctrl) + clientGrantAPI.EXPECT(). + List(gomock.Any(), gomock.Any()). + Return( + &management.ClientGrantList{ + List: management.List{ + Start: 0, + Limit: 2, + Total: 4, + }, + ClientGrants: []*management.ClientGrant{ + { + ID: auth0.String("cgr_1"), + ClientID: auth0.String("client-id-1"), + Audience: auth0.String("https://travel0.com/api"), + }, + { + ID: auth0.String("cgr_2"), + ClientID: auth0.String("client-id-2"), + Audience: auth0.String("https://travel0.com/api"), + }, + }, + }, + nil, + ) + clientGrantAPI.EXPECT(). + List(gomock.Any(), gomock.Any()). + Return( + &management.ClientGrantList{ + List: management.List{ + Start: 2, + Limit: 4, + Total: 4, + }, + ClientGrants: []*management.ClientGrant{ + { + ID: auth0.String("cgr_3"), + ClientID: auth0.String("client-id-1"), + Audience: auth0.String("https://travel0.us.auth0.com/api/v2/"), + }, + { + ID: auth0.String("cgr_4"), + ClientID: auth0.String("client-id-2"), + Audience: auth0.String("https://travel0.us.auth0.com/api/v2/"), + }, + }, + }, + nil, + ) + + fetcher := clientGrantResourceFetcher{ + api: &auth0.API{ + ClientGrant: clientGrantAPI, + }, + } + + expectedData := importDataList{ + { + ResourceName: "auth0_client_grant.client-id-1_httpstravel0comapi", + ImportID: "cgr_1", + }, + { + ResourceName: "auth0_client_grant.client-id-2_httpstravel0comapi", + ImportID: "cgr_2", + }, + { + ResourceName: "auth0_client_grant.client-id-1_httpstravel0usauth0comapiv2", + ImportID: "cgr_3", + }, + { + ResourceName: "auth0_client_grant.client-id-2_httpstravel0usauth0comapiv2", + ImportID: "cgr_4", + }, + } data, err := fetcher.FetchData(context.Background()) assert.NoError(t, err) - assert.Len(t, data, 1) - assert.Equal(t, data[0].ResourceName, "auth0_branding.branding") - assert.Greater(t, len(data[0].ImportID), 0) + assert.Equal(t, expectedData, data) + }) + + t.Run("it returns an error if api call fails", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + clientGrantAPI := mock.NewMockClientGrantAPI(ctrl) + clientGrantAPI.EXPECT(). + List(gomock.Any(), gomock.Any()). + Return(nil, fmt.Errorf("failed to list clients")) + + fetcher := clientGrantResourceFetcher{ + api: &auth0.API{ + ClientGrant: clientGrantAPI, + }, + } + + _, err := fetcher.FetchData(context.Background()) + assert.EqualError(t, err, "failed to list clients") }) }