migrate naming of azure env vars (#1176)

## Description

migrates the client_id, client_secret, and tenant_id
environment variables to versions prepended with
azure_*.

⚠️  Your local environment will need to change in the following ways:  ⚠️ 
1. prepend `AZURE_` to your clientID, clientSecret, and tenantID env vars.
2. update those same env references in any `.corso.env` files used for copying envs to docker containers.
3. in `.corso.toml` (and any variants such as .corso_test.toml), replace `tenantid` with `azure_tenantid`.

## Type of change

- [x] 🐹 Trivial/Minor

## Issue(s)

* #558

## Test Plan

- [x] 💪 Manual
- [x]  Unit test
- [x] 💚 E2E
This commit is contained in:
Keepers 2022-10-17 14:47:04 -06:00 committed by GitHub
parent fb46f5c7f3
commit a32f86e40d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 167 additions and 152 deletions

View File

@ -135,12 +135,12 @@ jobs:
# run the tests # run the tests
- name: Integration Tests - name: Integration Tests
env: env:
CLIENT_ID: ${{ secrets.CLIENT_ID }} AZURE_CLIENT_ID: ${{ secrets.CLIENT_ID }}
CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} AZURE_CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }}
AZURE_TENANT_ID: ${{ secrets.TENANT_ID }}
CORSO_CI_TESTS: true CORSO_CI_TESTS: true
CORSO_M356_TEST_USER_ID: ${{ secrets.CORSO_M356_TEST_USER_ID }} CORSO_M356_TEST_USER_ID: ${{ secrets.CORSO_M356_TEST_USER_ID }}
CORSO_PASSPHRASE: ${{ secrets.INTEGRATION_TEST_CORSO_PASSPHRASE }} CORSO_PASSPHRASE: ${{ secrets.INTEGRATION_TEST_CORSO_PASSPHRASE }}
TENANT_ID: ${{ secrets.TENANT_ID }}
run: | run: |
set -euo pipefail set -euo pipefail
go test \ go test \

View File

@ -31,11 +31,11 @@ jobs:
- name: Purge folders - name: Purge folders
working-directory: ./src working-directory: ./src
env: env:
CLIENT_ID: ${{ secrets.CLIENT_ID }} AZURE_CLIENT_ID: ${{ secrets.CLIENT_ID }}
CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} AZURE_CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }}
AZURE_TENANT_ID: ${{ secrets.TENANT_ID }}
CORSO_M356_TEST_USER_ID: ${{ secrets.CORSO_M356_TEST_USER_ID }} CORSO_M356_TEST_USER_ID: ${{ secrets.CORSO_M356_TEST_USER_ID }}
DELETE_FOLDER_PREFIX: "Corso_Restore_" DELETE_FOLDER_PREFIX: "Corso_Restore_"
TENANT_ID: ${{ secrets.TENANT_ID }}
run: > run: >
go run ./cmd/purge/purge.go go run ./cmd/purge/purge.go
--user ${{ secrets.CORSO_M356_TEST_USER_ID }} --user ${{ secrets.CORSO_M356_TEST_USER_ID }}

View File

@ -48,11 +48,11 @@ jobs:
# run the tests # run the tests
- name: Integration Tests - name: Integration Tests
env: env:
CORSO_LOAD_TESTS: true AZURE_CLIENT_ID: ${{ secrets.CLIENT_ID }}
CLIENT_ID: ${{ secrets.CLIENT_ID }} AZURE_CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }}
CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} AZURE_TENANT_ID: ${{ secrets.TENANT_ID }}
CORSO_PASSPHRASE: ${{ secrets.INTEGRATION_TEST_CORSO_PASSPHRASE }} CORSO_PASSPHRASE: ${{ secrets.INTEGRATION_TEST_CORSO_PASSPHRASE }}
TENANT_ID: ${{ secrets.TENANT_ID }} CORSO_LOAD_TESTS: true
run: | run: |
set -euo pipefail set -euo pipefail
go test \ go test \
@ -84,10 +84,10 @@ jobs:
if: always() if: always()
working-directory: ./src working-directory: ./src
env: env:
CLIENT_ID: ${{ secrets.CLIENT_ID }} AZURE_CLIENT_ID: ${{ secrets.CLIENT_ID }}
CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} AZURE_CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }}
AZURE_TENANT_ID: ${{ secrets.TENANT_ID }}
DELETE_FOLDER_PREFIX: "Corso_Restore_" DELETE_FOLDER_PREFIX: "Corso_Restore_"
TENANT_ID: ${{ secrets.TENANT_ID }}
run: > run: >
go run ./cmd/purge/purge.go go run ./cmd/purge/purge.go
--user '*' --user '*'

View File

@ -37,8 +37,8 @@ Standard format:
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| repo | * | | | Same as `repo [*] --help`. | | repo | * | | | Same as `repo [*] --help`. |
| repo | init | {repository} | | Initialize a Corso repository. | | repo | init | {repository} | | Initialize a Corso repository. |
| repo | init | {repository} | —tenant {tenant_id} | Provides the accounts tenant ID. | | repo | init | {repository} | —tenant {azure_tenant_id} | Provides the accounts tenant ID. |
| repo | init | {repository} | —client {client_id} | Provides the accounts client ID. | | repo | init | {repository} | —client {azure_client_id} | Provides the accounts client ID. |
| repo | connect | {repository} | | Connects to the specified repo. | | repo | connect | {repository} | | Connects to the specified repo. |
| repo | configure | {repository} | | Sets mutable config properties to the provided values. | | repo | configure | {repository} | | Sets mutable config properties to the provided values. |
| repo | * | * | —config {cfg_file_path} | Specify a repo configuration file. Values may also be provided via individual flags and env vars. | | repo | * | * | —config {cfg_file_path} | Specify a repo configuration file. Values may also be provided via individual flags and env vars. |
@ -68,10 +68,10 @@ Standard format:
**First Run** **First Run**
```bash ```bash
$ export O365_SECRET=my_0365_secret $ export AZURE_CLIENT_SECRET=my_azure_secret
$ export AWS_SECRET_ACCESS_KEY=my_s3_secret $ export AWS_SECRET_ACCESS_KEY=my_s3_secret
$ corso repo init s3 --bucket my_s3_bucket --access-key my_s3_key \ $ corso repo init s3 --bucket my_s3_bucket --access-key my_s3_key \
--tenant my_m365_acct --clientid my_m365_client_id --tenant my_azure_tenant_id --clientid my_azure_client_id
$ corso backup express $ corso backup express
``` ```

View File

@ -60,8 +60,8 @@ To extract the tenant and client ID, select Overview from the app management pan
environment variables. environment variables.
```bash ```bash
export TENANT_ID=<Directory (tenent) ID for configured app> export AZURE_TENANT_ID=<Directory (tenent) ID for configured app>
export CLIENT_ID=<Application (client) ID for configured app> export AZURE_CLIENT_ID=<Application (client) ID for configured app>
``` ```
<img src="/img/m365app_ids.png" className="guideImages"/> <img src="/img/m365app_ids.png" className="guideImages"/>
@ -75,7 +75,7 @@ Click **New Client Secret** and follow the instructions to create a secret. Afte
value right away because it won't be available later and export it as an environment variable. value right away because it won't be available later and export it as an environment variable.
```bash ```bash
export CLIENT_SECRET=<client secret value> export AZURE_CLIENT_SECRET=<client secret value>
``` ```
<img src="/img/m365app_secret.png" className="guideImages"/> <img src="/img/m365app_secret.png" className="guideImages"/>

View File

@ -33,9 +33,9 @@
> You can find more information on how to get these values in [configuration docs](/configuration/m365_access). > You can find more information on how to get these values in [configuration docs](/configuration/m365_access).
```bash ```bash
export TENANT_ID=<tenant> export AZURE_CLIENT_ID=<id>
export CLIENT_ID=<id> export AZURE_CLIENT_SECRET=<secret>
export CLIENT_SECRET=<secret> export AZURE_TENANT_ID=<tenant>
``` ```
## Running tests ## Running tests

View File

@ -36,9 +36,9 @@ To create the environment variables file, you can run the following.
# create an env vars file # create an env vars file
$ cat <<EOF ~/.corso/corso.env $ cat <<EOF ~/.corso/corso.env
CORSO_PASSPHRASE CORSO_PASSPHRASE
TENANT_ID AZURE_TENANT_ID
CLIENT_ID AZURE_CLIENT_ID
CLIENT_SECRET AZURE_CLIENT_SECRET
AWS_ACCESS_KEY_ID AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY AWS_SECRET_ACCESS_KEY
AWS_SESSION_TOKEN AWS_SESSION_TOKEN

View File

@ -21,14 +21,14 @@ func m365ConfigsFromViper(vpr *viper.Viper) (account.M365Config, error) {
return m365, errors.New("unsupported account provider: " + providerType) return m365, errors.New("unsupported account provider: " + providerType)
} }
m365.TenantID = vpr.GetString(TenantIDKey) m365.AzureTenantID = vpr.GetString(AzureTenantIDKey)
return m365, nil return m365, nil
} }
func m365Overrides(in map[string]string) map[string]string { func m365Overrides(in map[string]string) map[string]string {
return map[string]string{ return map[string]string{
account.TenantID: in[account.TenantID], account.AzureTenantID: in[account.AzureTenantID],
AccountProviderTypeKey: in[AccountProviderTypeKey], AccountProviderTypeKey: in[AccountProviderTypeKey],
} }
} }
@ -64,15 +64,18 @@ func configureAccount(
} }
m365Cfg = account.M365Config{ m365Cfg = account.M365Config{
M365: m365, M365: m365,
TenantID: common.First(overrides[account.TenantID], m365Cfg.TenantID, os.Getenv(account.TenantID)), AzureTenantID: common.First(
overrides[account.AzureTenantID],
m365Cfg.AzureTenantID,
os.Getenv(account.AzureTenantID)),
} }
// ensure required properties are present // ensure required properties are present
if err := utils.RequireProps(map[string]string{ if err := utils.RequireProps(map[string]string{
credentials.ClientID: m365Cfg.ClientID, credentials.AzureClientID: m365Cfg.AzureClientID,
credentials.ClientSecret: m365Cfg.ClientSecret, credentials.AzureClientSecret: m365Cfg.AzureClientSecret,
account.TenantID: m365Cfg.TenantID, account.AzureTenantID: m365Cfg.AzureTenantID,
}); err != nil { }); err != nil {
return acct, err return acct, err
} }

View File

@ -26,7 +26,7 @@ const (
// M365 config // M365 config
AccountProviderTypeKey = "account_provider" AccountProviderTypeKey = "account_provider"
TenantIDKey = "tenantid" AzureTenantIDKey = "azure_tenantid"
) )
var ( var (
@ -198,7 +198,7 @@ func writeRepoConfigWithViper(vpr *viper.Viper, s3Config storage.S3Config, m365C
vpr.Set(PrefixKey, s3Config.Prefix) vpr.Set(PrefixKey, s3Config.Prefix)
vpr.Set(AccountProviderTypeKey, account.ProviderM365.String()) vpr.Set(AccountProviderTypeKey, account.ProviderM365.String())
vpr.Set(TenantIDKey, m365Config.TenantID) vpr.Set(AzureTenantIDKey, m365Config.AzureTenantID)
if err := vpr.SafeWriteConfig(); err != nil { if err := vpr.SafeWriteConfig(); err != nil {
if _, ok := err.(viper.ConfigFileAlreadyExistsError); ok { if _, ok := err.(viper.ConfigFileAlreadyExistsError); ok {
@ -266,7 +266,7 @@ func getStorageAndAccountWithViper(
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
var constToTomlKeyMap = map[string]string{ var constToTomlKeyMap = map[string]string{
account.TenantID: TenantIDKey, account.AzureTenantID: AzureTenantIDKey,
AccountProviderTypeKey: AccountProviderTypeKey, AccountProviderTypeKey: AccountProviderTypeKey,
storage.Bucket: BucketNameKey, storage.Bucket: BucketNameKey,
storage.Endpoint: EndpointKey, storage.Endpoint: EndpointKey,

View File

@ -25,7 +25,7 @@ const (
` + PrefixKey + ` = 'test-prefix/' ` + PrefixKey + ` = 'test-prefix/'
` + StorageProviderTypeKey + ` = 'S3' ` + StorageProviderTypeKey + ` = 'S3'
` + AccountProviderTypeKey + ` = 'M365' ` + AccountProviderTypeKey + ` = 'M365'
` + TenantIDKey + ` = '%s' ` + AzureTenantIDKey + ` = '%s'
` `
) )
@ -66,7 +66,7 @@ func (suite *ConfigSuite) TestReadRepoConfigBasic() {
m365, err := m365ConfigsFromViper(vpr) m365, err := m365ConfigsFromViper(vpr)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, tID, m365.TenantID) assert.Equal(t, tID, m365.AzureTenantID)
} }
func (suite *ConfigSuite) TestWriteReadConfig() { func (suite *ConfigSuite) TestWriteReadConfig() {
@ -85,7 +85,7 @@ func (suite *ConfigSuite) TestWriteReadConfig() {
require.NoError(t, initWithViper(vpr, testConfigFilePath), "initializing repo config") require.NoError(t, initWithViper(vpr, testConfigFilePath), "initializing repo config")
s3Cfg := storage.S3Config{Bucket: bkt} s3Cfg := storage.S3Config{Bucket: bkt}
m365 := account.M365Config{TenantID: tid} m365 := account.M365Config{AzureTenantID: tid}
require.NoError(t, writeRepoConfigWithViper(vpr, s3Cfg, m365), "writing repo config") require.NoError(t, writeRepoConfigWithViper(vpr, s3Cfg, m365), "writing repo config")
require.NoError(t, vpr.ReadInConfig(), "reading repo config") require.NoError(t, vpr.ReadInConfig(), "reading repo config")
@ -96,7 +96,7 @@ func (suite *ConfigSuite) TestWriteReadConfig() {
readM365, err := m365ConfigsFromViper(vpr) readM365, err := m365ConfigsFromViper(vpr)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, readM365.TenantID, m365.TenantID) assert.Equal(t, readM365.AzureTenantID, m365.AzureTenantID)
} }
func (suite *ConfigSuite) TestMustMatchConfig() { func (suite *ConfigSuite) TestMustMatchConfig() {
@ -115,7 +115,7 @@ func (suite *ConfigSuite) TestMustMatchConfig() {
require.NoError(t, initWithViper(vpr, testConfigFilePath), "initializing repo config") require.NoError(t, initWithViper(vpr, testConfigFilePath), "initializing repo config")
s3Cfg := storage.S3Config{Bucket: bkt} s3Cfg := storage.S3Config{Bucket: bkt}
m365 := account.M365Config{TenantID: tid} m365 := account.M365Config{AzureTenantID: tid}
require.NoError(t, writeRepoConfigWithViper(vpr, s3Cfg, m365), "writing repo config") require.NoError(t, writeRepoConfigWithViper(vpr, s3Cfg, m365), "writing repo config")
require.NoError(t, vpr.ReadInConfig(), "reading repo config") require.NoError(t, vpr.ReadInConfig(), "reading repo config")
@ -128,16 +128,16 @@ func (suite *ConfigSuite) TestMustMatchConfig() {
{ {
name: "full match", name: "full match",
input: map[string]string{ input: map[string]string{
storage.Bucket: bkt, storage.Bucket: bkt,
account.TenantID: tid, account.AzureTenantID: tid,
}, },
errCheck: assert.NoError, errCheck: assert.NoError,
}, },
{ {
name: "empty values", name: "empty values",
input: map[string]string{ input: map[string]string{
storage.Bucket: "", storage.Bucket: "",
account.TenantID: "", account.AzureTenantID: "",
}, },
errCheck: assert.NoError, errCheck: assert.NoError,
}, },
@ -162,8 +162,8 @@ func (suite *ConfigSuite) TestMustMatchConfig() {
{ {
name: "mismatch", name: "mismatch",
input: map[string]string{ input: map[string]string{
storage.Bucket: tid, storage.Bucket: tid,
account.TenantID: bkt, account.AzureTenantID: bkt,
}, },
errCheck: assert.Error, errCheck: assert.Error,
}, },
@ -221,7 +221,7 @@ func (suite *ConfigIntegrationSuite) TestGetStorageAndAccount() {
Endpoint: end, Endpoint: end,
Prefix: pfx, Prefix: pfx,
} }
m365 := account.M365Config{TenantID: tid} m365 := account.M365Config{AzureTenantID: tid}
require.NoError(t, writeRepoConfigWithViper(vpr, s3Cfg, m365), "writing repo config") require.NoError(t, writeRepoConfigWithViper(vpr, s3Cfg, m365), "writing repo config")
require.NoError(t, vpr.ReadInConfig(), "reading repo config") require.NoError(t, vpr.ReadInConfig(), "reading repo config")
@ -241,9 +241,9 @@ func (suite *ConfigIntegrationSuite) TestGetStorageAndAccount() {
readM365, err := ac.M365Config() readM365, err := ac.M365Config()
require.NoError(t, err, "reading m365 config from account") require.NoError(t, err, "reading m365 config from account")
assert.Equal(t, readM365.TenantID, m365.TenantID) assert.Equal(t, readM365.AzureTenantID, m365.AzureTenantID)
assert.Equal(t, readM365.ClientID, os.Getenv(credentials.ClientID)) assert.Equal(t, readM365.AzureClientID, os.Getenv(credentials.AzureClientID))
assert.Equal(t, readM365.ClientSecret, os.Getenv(credentials.ClientSecret)) assert.Equal(t, readM365.AzureClientSecret, os.Getenv(credentials.AzureClientSecret))
} }
func (suite *ConfigIntegrationSuite) TestGetStorageAndAccount_noFileOnlyOverrides() { func (suite *ConfigIntegrationSuite) TestGetStorageAndAccount_noFileOnlyOverrides() {
@ -263,10 +263,10 @@ func (suite *ConfigIntegrationSuite) TestGetStorageAndAccount_noFileOnlyOverride
Endpoint: end, Endpoint: end,
Prefix: pfx, Prefix: pfx,
} }
m365 := account.M365Config{TenantID: tid} m365 := account.M365Config{AzureTenantID: tid}
overrides := map[string]string{ overrides := map[string]string{
account.TenantID: tid, account.AzureTenantID: tid,
AccountProviderTypeKey: account.ProviderM365.String(), AccountProviderTypeKey: account.ProviderM365.String(),
storage.Bucket: bkt, storage.Bucket: bkt,
storage.Endpoint: end, storage.Endpoint: end,
@ -289,7 +289,7 @@ func (suite *ConfigIntegrationSuite) TestGetStorageAndAccount_noFileOnlyOverride
readM365, err := ac.M365Config() readM365, err := ac.M365Config()
require.NoError(t, err, "reading m365 config from account") require.NoError(t, err, "reading m365 config from account")
assert.Equal(t, readM365.TenantID, m365.TenantID) assert.Equal(t, readM365.AzureTenantID, m365.AzureTenantID)
assert.Equal(t, readM365.ClientID, os.Getenv(credentials.ClientID)) assert.Equal(t, readM365.AzureClientID, os.Getenv(credentials.AzureClientID))
assert.Equal(t, readM365.ClientSecret, os.Getenv(credentials.ClientSecret)) assert.Equal(t, readM365.AzureClientSecret, os.Getenv(credentials.AzureClientSecret))
} }

View File

@ -67,8 +67,8 @@ var (
"It is impossible to use the repository or recover any backups without this key."}, "It is impossible to use the repository or recover any backups without this key."},
} }
azureEVs = []envVar{ azureEVs = []envVar{
{azure, "CLIENT_ID", "Client ID for your Azure AD application used to access your M365 tenant."}, {azure, "AZURE_CLIENT_ID", "Client ID for your Azure AD application used to access your M365 tenant."},
{azure, "CLIENT_SECRET", "Azure secret for your Azure AD application used to access your M365 tenant."}, {azure, "AZURE_CLIENT_SECRET", "Azure secret for your Azure AD application used to access your M365 tenant."},
} }
awsEVs = []envVar{ awsEVs = []envVar{
{aws, "AWS_ACCESS_KEY_ID", "AWS access key for an IAM user or role for accessing S3 bucket repository."}, {aws, "AWS_ACCESS_KEY_ID", "AWS access key for an IAM user or role for accessing S3 bucket repository."},

View File

@ -98,12 +98,12 @@ func handleOneDriveFactory(cmd *cobra.Command, args []string) error {
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
func getGCAndVerifyUser(ctx context.Context, userID string) (*connector.GraphConnector, string, error) { func getGCAndVerifyUser(ctx context.Context, userID string) (*connector.GraphConnector, string, error) {
tid := common.First(tenant, os.Getenv(account.TenantID)) tid := common.First(tenant, os.Getenv(account.AzureTenantID))
// get account info // get account info
m365Cfg := account.M365Config{ m365Cfg := account.M365Config{
M365: credentials.GetM365(), M365: credentials.GetM365(),
TenantID: tid, AzureTenantID: tid,
} }
acct, err := account.NewAccount(account.ProviderM365, m365Cfg) acct, err := account.NewAccount(account.ProviderM365, m365Cfg)

View File

@ -415,8 +415,8 @@ func purgeFolders(
func getGC(ctx context.Context) (*connector.GraphConnector, error) { func getGC(ctx context.Context) (*connector.GraphConnector, error) {
// get account info // get account info
m365Cfg := account.M365Config{ m365Cfg := account.M365Config{
M365: credentials.GetM365(), M365: credentials.GetM365(),
TenantID: common.First(tenant, os.Getenv(account.TenantID)), AzureTenantID: common.First(tenant, os.Getenv(account.AzureTenantID)),
} }
acct, err := account.NewAccount(account.ProviderM365, m365Cfg) acct, err := account.NewAccount(account.ProviderM365, m365Cfg)

View File

@ -38,6 +38,7 @@ func TestContactFolderCacheIntegrationSuite(t *testing.T) {
if err := tester.RunOnAny( if err := tester.RunOnAny(
tester.CorsoCITests, tester.CorsoCITests,
tester.CorsoGraphConnectorTests, tester.CorsoGraphConnectorTests,
tester.CorsoGraphConnectorExchangeTests,
); err != nil { ); err != nil {
t.Skip(err) t.Skip(err)
} }

View File

@ -20,6 +20,7 @@ func TestEventCalendarCacheIntegrationSuite(t *testing.T) {
if err := tester.RunOnAny( if err := tester.RunOnAny(
tester.CorsoCITests, tester.CorsoCITests,
tester.CorsoGraphConnectorTests, tester.CorsoGraphConnectorTests,
tester.CorsoGraphConnectorExchangeTests,
); err != nil { ); err != nil {
t.Skip(err) t.Skip(err)
} }

View File

@ -29,6 +29,7 @@ func TestExchangeServiceSuite(t *testing.T) {
if err := tester.RunOnAny( if err := tester.RunOnAny(
tester.CorsoCITests, tester.CorsoCITests,
tester.CorsoGraphConnectorTests, tester.CorsoGraphConnectorTests,
tester.CorsoGraphConnectorExchangeTests,
); err != nil { ); err != nil {
t.Skip(err) t.Skip(err)
} }
@ -58,7 +59,7 @@ func (suite *ExchangeServiceSuite) SetupSuite() {
func (suite *ExchangeServiceSuite) TestCreateService() { func (suite *ExchangeServiceSuite) TestCreateService() {
creds := suite.es.credentials creds := suite.es.credentials
invalidCredentials := suite.es.credentials invalidCredentials := suite.es.credentials
invalidCredentials.ClientSecret = "" invalidCredentials.AzureClientSecret = ""
tests := []struct { tests := []struct {
name string name string
@ -78,7 +79,7 @@ func (suite *ExchangeServiceSuite) TestCreateService() {
} }
for _, test := range tests { for _, test := range tests {
suite.T().Run(test.name, func(t *testing.T) { suite.T().Run(test.name, func(t *testing.T) {
t.Log(test.credentials.ClientSecret) t.Log(test.credentials.AzureClientSecret)
_, err := createService(test.credentials, false) _, err := createService(test.credentials, false)
test.checkErr(t, err) test.checkErr(t, err)
}) })
@ -587,7 +588,7 @@ func (suite *ExchangeServiceSuite) TestGetContainerIDFromCache() {
pathFunc1: func() path.Path { pathFunc1: func() path.Path {
pth, err := path.Builder{}.Append("Griffindor"). pth, err := path.Builder{}.Append("Griffindor").
Append("Croix").ToDataLayerExchangePathForCategory( Append("Croix").ToDataLayerExchangePathForCategory(
suite.es.credentials.TenantID, suite.es.credentials.AzureTenantID,
user, user,
path.EmailCategory, path.EmailCategory,
false, false,
@ -599,7 +600,7 @@ func (suite *ExchangeServiceSuite) TestGetContainerIDFromCache() {
pathFunc2: func() path.Path { pathFunc2: func() path.Path {
pth, err := path.Builder{}.Append("Griffindor"). pth, err := path.Builder{}.Append("Griffindor").
Append("Felicius").ToDataLayerExchangePathForCategory( Append("Felicius").ToDataLayerExchangePathForCategory(
suite.es.credentials.TenantID, suite.es.credentials.AzureTenantID,
user, user,
path.EmailCategory, path.EmailCategory,
false, false,
@ -615,7 +616,7 @@ func (suite *ExchangeServiceSuite) TestGetContainerIDFromCache() {
pathFunc1: func() path.Path { pathFunc1: func() path.Path {
aPath, err := path.Builder{}.Append("HufflePuff"). aPath, err := path.Builder{}.Append("HufflePuff").
ToDataLayerExchangePathForCategory( ToDataLayerExchangePathForCategory(
suite.es.credentials.TenantID, suite.es.credentials.AzureTenantID,
user, user,
path.ContactsCategory, path.ContactsCategory,
false, false,
@ -627,7 +628,7 @@ func (suite *ExchangeServiceSuite) TestGetContainerIDFromCache() {
pathFunc2: func() path.Path { pathFunc2: func() path.Path {
aPath, err := path.Builder{}.Append("Ravenclaw"). aPath, err := path.Builder{}.Append("Ravenclaw").
ToDataLayerExchangePathForCategory( ToDataLayerExchangePathForCategory(
suite.es.credentials.TenantID, suite.es.credentials.AzureTenantID,
user, user,
path.ContactsCategory, path.ContactsCategory,
false, false,
@ -643,7 +644,7 @@ func (suite *ExchangeServiceSuite) TestGetContainerIDFromCache() {
pathFunc1: func() path.Path { pathFunc1: func() path.Path {
aPath, err := path.Builder{}.Append("Durmstrang"). aPath, err := path.Builder{}.Append("Durmstrang").
ToDataLayerExchangePathForCategory( ToDataLayerExchangePathForCategory(
suite.es.credentials.TenantID, suite.es.credentials.AzureTenantID,
user, user,
path.EventsCategory, path.EventsCategory,
false, false,
@ -654,7 +655,7 @@ func (suite *ExchangeServiceSuite) TestGetContainerIDFromCache() {
pathFunc2: func() path.Path { pathFunc2: func() path.Path {
aPath, err := path.Builder{}.Append("Beauxbatons"). aPath, err := path.Builder{}.Append("Beauxbatons").
ToDataLayerExchangePathForCategory( ToDataLayerExchangePathForCategory(
suite.es.credentials.TenantID, suite.es.credentials.AzureTenantID,
user, user,
path.EventsCategory, path.EventsCategory,
false, false,

View File

@ -25,6 +25,7 @@ func TestExchangeIteratorSuite(t *testing.T) {
if err := tester.RunOnAny( if err := tester.RunOnAny(
tester.CorsoCITests, tester.CorsoCITests,
tester.CorsoGraphConnectorTests, tester.CorsoGraphConnectorTests,
tester.CorsoGraphConnectorExchangeTests,
); err != nil { ); err != nil {
t.Skip(err) t.Skip(err)
} }

View File

@ -323,6 +323,7 @@ func TestMailFolderCacheIntegrationSuite(t *testing.T) {
if err := tester.RunOnAny( if err := tester.RunOnAny(
tester.CorsoCITests, tester.CorsoCITests,
tester.CorsoGraphConnectorTests, tester.CorsoGraphConnectorTests,
tester.CorsoGraphConnectorExchangeTests,
); err != nil { ); err != nil {
t.Skip(err) t.Skip(err)
} }

View File

@ -48,9 +48,9 @@ func (es *exchangeService) ErrPolicy() bool {
// NOTE: Incorrect account information will result in errors on subsequent queries. // NOTE: Incorrect account information will result in errors on subsequent queries.
func createService(credentials account.M365Config, shouldFailFast bool) (*exchangeService, error) { func createService(credentials account.M365Config, shouldFailFast bool) (*exchangeService, error) {
adapter, err := graph.CreateAdapter( adapter, err := graph.CreateAdapter(
credentials.TenantID, credentials.AzureTenantID,
credentials.ClientID, credentials.AzureClientID,
credentials.ClientSecret, credentials.AzureClientSecret,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -460,7 +460,7 @@ func getCollectionPath(
returnPath, err := resolveCollectionPath( returnPath, err := resolveCollectionPath(
ctx, ctx,
resolver, resolver,
qp.Credentials.TenantID, qp.Credentials.AzureTenantID,
qp.User, qp.User,
directory, directory,
category, category,
@ -471,7 +471,7 @@ func getCollectionPath(
aPath, err1 := path.Builder{}.Append(directory). aPath, err1 := path.Builder{}.Append(directory).
ToDataLayerExchangePathForCategory( ToDataLayerExchangePathForCategory(
qp.Credentials.TenantID, qp.Credentials.AzureTenantID,
qp.User, qp.User,
category, category,
false, false,

View File

@ -21,6 +21,7 @@ func TestServiceFunctionsIntegrationSuite(t *testing.T) {
if err := tester.RunOnAny( if err := tester.RunOnAny(
tester.CorsoCITests, tester.CorsoCITests,
tester.CorsoGraphConnectorTests, tester.CorsoGraphConnectorTests,
tester.CorsoGraphConnectorExchangeTests,
); err != nil { ); err != nil {
t.Skip(err) t.Skip(err)
} }

View File

@ -205,7 +205,7 @@ func CollectionsFromResolver(
} }
completePath, err := item.Path().ToDataLayerExchangePathForCategory( completePath, err := item.Path().ToDataLayerExchangePathForCategory(
qp.Credentials.TenantID, qp.Credentials.AzureTenantID,
qp.User, qp.User,
category, category,
false, false,
@ -504,7 +504,7 @@ func IterateSelectAllContactsForCollections(
// Create and Populate Default Contacts folder Collection if true // Create and Populate Default Contacts folder Collection if true
if qp.Scope.Matches(selectors.ExchangeContactFolder, DefaultContactFolder) { if qp.Scope.Matches(selectors.ExchangeContactFolder, DefaultContactFolder) {
dirPath, err := path.Builder{}.Append(DefaultContactFolder).ToDataLayerExchangePathForCategory( dirPath, err := path.Builder{}.Append(DefaultContactFolder).ToDataLayerExchangePathForCategory(
qp.Credentials.TenantID, qp.Credentials.AzureTenantID,
qp.User, qp.User,
path.ContactsCategory, path.ContactsCategory,
false, false,

View File

@ -77,7 +77,7 @@ func NewGraphConnector(ctx context.Context, acct account.Account) (*GraphConnect
} }
gc := GraphConnector{ gc := GraphConnector{
tenant: m365.TenantID, tenant: m365.AzureTenantID,
Users: make(map[string]string, 0), Users: make(map[string]string, 0),
wg: &sync.WaitGroup{}, wg: &sync.WaitGroup{},
credentials: m365, credentials: m365,
@ -101,9 +101,9 @@ func NewGraphConnector(ctx context.Context, acct account.Account) (*GraphConnect
// createService constructor for graphService component // createService constructor for graphService component
func (gc *GraphConnector) createService(shouldFailFast bool) (*graphService, error) { func (gc *GraphConnector) createService(shouldFailFast bool) (*graphService, error) {
adapter, err := graph.CreateAdapter( adapter, err := graph.CreateAdapter(
gc.credentials.TenantID, gc.credentials.AzureTenantID,
gc.credentials.ClientID, gc.credentials.AzureClientID,
gc.credentials.ClientSecret, gc.credentials.AzureClientSecret,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -520,7 +520,7 @@ func (gc *GraphConnector) OneDriveDataCollections(
logger.Ctx(ctx).With("user", user).Debug("Creating OneDrive collections") logger.Ctx(ctx).With("user", user).Debug("Creating OneDrive collections")
odcs, err := onedrive.NewCollections( odcs, err := onedrive.NewCollections(
gc.credentials.TenantID, gc.credentials.AzureTenantID,
user, user,
scope, scope,
&gc.graphService, &gc.graphService,

View File

@ -43,10 +43,10 @@ func (suite *DisconnectedGraphConnectorSuite) TestBadConnection() {
account.ProviderM365, account.ProviderM365,
account.M365Config{ account.M365Config{
M365: credentials.M365{ M365: credentials.M365{
ClientID: "Test", AzureClientID: "Test",
ClientSecret: "without", AzureClientSecret: "without",
}, },
TenantID: "data", AzureTenantID: "data",
}, },
) )
require.NoError(t, err) require.NoError(t, err)

View File

@ -38,6 +38,7 @@ func TestGraphConnectorIntegrationSuite(t *testing.T) {
if err := tester.RunOnAny( if err := tester.RunOnAny(
tester.CorsoCITests, tester.CorsoCITests,
tester.CorsoGraphConnectorTests, tester.CorsoGraphConnectorTests,
tester.CorsoGraphConnectorExchangeTests,
); err != nil { ); err != nil {
t.Skip(err) t.Skip(err)
} }

View File

@ -86,8 +86,10 @@ func collectItems(
} }
// getFolder will lookup the specified folder name under `parentFolderID` // getFolder will lookup the specified folder name under `parentFolderID`
func getFolder(ctx context.Context, service graph.Service, driveID string, parentFolderID string, func getFolder(
folderName string, ctx context.Context,
service graph.Service,
driveID, parentFolderID, folderName string,
) (models.DriveItemable, error) { ) (models.DriveItemable, error) {
// The `Children().Get()` API doesn't yet support $filter, so using that to find a folder // The `Children().Get()` API doesn't yet support $filter, so using that to find a folder
// will be sub-optimal. // will be sub-optimal.

View File

@ -44,9 +44,9 @@ func loadService(t *testing.T) *testService {
require.NoError(t, err) require.NoError(t, err)
adapter, err := graph.CreateAdapter( adapter, err := graph.CreateAdapter(
m365.TenantID, m365.AzureTenantID,
m365.ClientID, m365.AzureClientID,
m365.ClientSecret, m365.AzureClientSecret,
) )
require.NoError(t, err) require.NoError(t, err)

View File

@ -40,6 +40,7 @@ func TestItemIntegrationSuite(t *testing.T) {
if err := tester.RunOnAny( if err := tester.RunOnAny(
tester.CorsoCITests, tester.CorsoCITests,
tester.CorsoGraphConnectorTests, tester.CorsoGraphConnectorTests,
tester.CorsoGraphConnectorOneDriveTests,
); err != nil { ); err != nil {
t.Skip(err) t.Skip(err)
} }
@ -59,7 +60,7 @@ func (suite *ItemIntegrationSuite) SetupSuite() {
m365, err := a.M365Config() m365, err := a.M365Config()
require.NoError(suite.T(), err) require.NoError(suite.T(), err)
adapter, err := graph.CreateAdapter(m365.TenantID, m365.ClientID, m365.ClientSecret) adapter, err := graph.CreateAdapter(m365.AzureTenantID, m365.AzureClientID, m365.AzureClientSecret)
require.NoError(suite.T(), err) require.NoError(suite.T(), err)
suite.client = msgraphsdk.NewGraphServiceClient(adapter) suite.client = msgraphsdk.NewGraphServiceClient(adapter)
suite.adapter = adapter suite.adapter = adapter

View File

@ -42,10 +42,10 @@ func (suite *EventsIntegrationSuite) TestNewBus() {
account.ProviderM365, account.ProviderM365,
account.M365Config{ account.M365Config{
M365: credentials.M365{ M365: credentials.M365{
ClientID: "id", AzureClientID: "id",
ClientSecret: "secret", AzureClientSecret: "secret",
}, },
TenantID: "tid", AzureTenantID: "tid",
}, },
) )
require.NoError(t, err) require.NoError(t, err)

View File

@ -10,8 +10,8 @@ import (
) )
var M365AcctCredEnvs = []string{ var M365AcctCredEnvs = []string{
credentials.ClientID, credentials.AzureClientID,
credentials.ClientSecret, credentials.AzureClientSecret,
} }
// NewM365Account returns an account.Account object initialized with environment // NewM365Account returns an account.Account object initialized with environment
@ -23,8 +23,8 @@ func NewM365Account(t *testing.T) account.Account {
acc, err := account.NewAccount( acc, err := account.NewAccount(
account.ProviderM365, account.ProviderM365,
account.M365Config{ account.M365Config{
M365: credentials.GetM365(), M365: credentials.GetM365(),
TenantID: cfg[TestCfgTenantID], AzureTenantID: cfg[TestCfgAzureTenantID],
}, },
) )
require.NoError(t, err, "initializing account") require.NoError(t, err, "initializing account")

View File

@ -20,7 +20,7 @@ const (
TestCfgStorageProvider = "provider" TestCfgStorageProvider = "provider"
// M365 config // M365 config
TestCfgTenantID = "tenantid" TestCfgAzureTenantID = "azure_tenantid"
TestCfgUserID = "m365userid" TestCfgUserID = "m365userid"
TestCfgAccountProvider = "account_provider" TestCfgAccountProvider = "account_provider"
) )
@ -100,7 +100,7 @@ func readTestConfig() (map[string]string, error) {
fallbackTo(testEnv, TestCfgBucket, vpr.GetString(TestCfgBucket), "test-corso-repo-init") fallbackTo(testEnv, TestCfgBucket, vpr.GetString(TestCfgBucket), "test-corso-repo-init")
fallbackTo(testEnv, TestCfgEndpoint, vpr.GetString(TestCfgEndpoint), "s3.amazonaws.com") fallbackTo(testEnv, TestCfgEndpoint, vpr.GetString(TestCfgEndpoint), "s3.amazonaws.com")
fallbackTo(testEnv, TestCfgPrefix, vpr.GetString(TestCfgPrefix)) fallbackTo(testEnv, TestCfgPrefix, vpr.GetString(TestCfgPrefix))
fallbackTo(testEnv, TestCfgTenantID, os.Getenv(account.TenantID), vpr.GetString(TestCfgTenantID)) fallbackTo(testEnv, TestCfgAzureTenantID, os.Getenv(account.AzureTenantID), vpr.GetString(TestCfgAzureTenantID))
fallbackTo( fallbackTo(
testEnv, testEnv,
TestCfgUserID, TestCfgUserID,

View File

@ -9,19 +9,21 @@ import (
) )
const ( const (
CorsoLoadTests = "CORSO_LOAD_TESTS" CorsoLoadTests = "CORSO_LOAD_TESTS"
CorsoCITests = "CORSO_CI_TESTS" CorsoCITests = "CORSO_CI_TESTS"
CorsoCLIBackupTests = "CORSO_COMMAND_LINE_BACKUP_TESTS" CorsoCLIBackupTests = "CORSO_COMMAND_LINE_BACKUP_TESTS"
CorsoCLIConfigTests = "CORSO_COMMAND_LINE_CONFIG_TESTS" CorsoCLIConfigTests = "CORSO_COMMAND_LINE_CONFIG_TESTS"
CorsoCLIRepoTests = "CORSO_COMMAND_LINE_REPO_TESTS" CorsoCLIRepoTests = "CORSO_COMMAND_LINE_REPO_TESTS"
CorsoCLIRestoreTests = "CORSO_COMMAND_LINE_RESTORE_TESTS" CorsoCLIRestoreTests = "CORSO_COMMAND_LINE_RESTORE_TESTS"
CorsoCLITests = "CORSO_COMMAND_LINE_TESTS" CorsoCLITests = "CORSO_COMMAND_LINE_TESTS"
CorsoGraphConnectorTests = "CORSO_GRAPH_CONNECTOR_TESTS" CorsoGraphConnectorTests = "CORSO_GRAPH_CONNECTOR_TESTS"
CorsoKopiaWrapperTests = "CORSO_KOPIA_WRAPPER_TESTS" CorsoGraphConnectorExchangeTests = "CORSO_GRAPH_CONNECTOR_EXCHANGE_TESTS"
CorsoModelStoreTests = "CORSO_MODEL_STORE_TESTS" CorsoGraphConnectorOneDriveTests = "CORSO_GRAPH_CONNECTOR_ONE_DRIVE_TESTS"
CorsoOneDriveTests = "CORSO_ONE_DRIVE_TESTS" CorsoKopiaWrapperTests = "CORSO_KOPIA_WRAPPER_TESTS"
CorsoOperationTests = "CORSO_OPERATION_TESTS" CorsoModelStoreTests = "CORSO_MODEL_STORE_TESTS"
CorsoRepositoryTests = "CORSO_REPOSITORY_TESTS" CorsoOneDriveTests = "CORSO_ONE_DRIVE_TESTS"
CorsoOperationTests = "CORSO_OPERATION_TESTS"
CorsoRepositoryTests = "CORSO_REPOSITORY_TESTS"
) )
// File needs to be a single message .json // File needs to be a single message .json

View File

@ -8,19 +8,19 @@ import (
// config exported name consts // config exported name consts
const ( const (
TenantID = "TENANT_ID" AzureTenantID = "AZURE_TENANT_ID"
) )
type M365Config struct { type M365Config struct {
credentials.M365 // requires: ClientID, ClientSecret credentials.M365 // requires: ClientID, ClientSecret
TenantID string AzureTenantID string
} }
// config key consts // config key consts
const ( const (
keyM365ClientID = "m365_clientID" keyAzureClientID = "azure_clientid"
keyM365ClientSecret = "m365_clientSecret" keyAzureClientSecret = "azure_clientSecret"
keyM365TenantID = "m365_tenantID" keyAzureTenantID = "azure_tenantid"
) )
// StringConfig transforms a m365Config struct into a plain // StringConfig transforms a m365Config struct into a plain
@ -28,9 +28,9 @@ const (
// serialize into the map are expected to be strings. // serialize into the map are expected to be strings.
func (c M365Config) StringConfig() (map[string]string, error) { func (c M365Config) StringConfig() (map[string]string, error) {
cfg := map[string]string{ cfg := map[string]string{
keyM365ClientID: c.ClientID, keyAzureClientID: c.AzureClientID,
keyM365ClientSecret: c.ClientSecret, keyAzureClientSecret: c.AzureClientSecret,
keyM365TenantID: c.TenantID, keyAzureTenantID: c.AzureTenantID,
} }
return cfg, c.validate() return cfg, c.validate()
@ -39,7 +39,7 @@ func (c M365Config) StringConfig() (map[string]string, error) {
// providerID returns the c.TenantID if ap is a ProviderM365. // providerID returns the c.TenantID if ap is a ProviderM365.
func (c M365Config) providerID(ap accountProvider) string { func (c M365Config) providerID(ap accountProvider) string {
if ap == ProviderM365 { if ap == ProviderM365 {
return c.TenantID return c.AzureTenantID
} }
return "" return ""
@ -49,9 +49,9 @@ func (c M365Config) providerID(ap accountProvider) string {
func (a Account) M365Config() (M365Config, error) { func (a Account) M365Config() (M365Config, error) {
c := M365Config{} c := M365Config{}
if len(a.Config) > 0 { if len(a.Config) > 0 {
c.ClientID = a.Config[keyM365ClientID] c.AzureClientID = a.Config[keyAzureClientID]
c.ClientSecret = a.Config[keyM365ClientSecret] c.AzureClientSecret = a.Config[keyAzureClientSecret]
c.TenantID = a.Config[keyM365TenantID] c.AzureTenantID = a.Config[keyAzureTenantID]
} }
return c, c.validate() return c, c.validate()
@ -59,9 +59,9 @@ func (a Account) M365Config() (M365Config, error) {
func (c M365Config) validate() error { func (c M365Config) validate() error {
check := map[string]string{ check := map[string]string{
credentials.ClientID: c.ClientID, credentials.AzureClientID: c.AzureClientID,
credentials.ClientSecret: c.ClientSecret, credentials.AzureClientSecret: c.AzureClientSecret,
TenantID: c.TenantID, AzureTenantID: c.AzureTenantID,
} }
for k, v := range check { for k, v := range check {

View File

@ -21,10 +21,10 @@ func TestM365CfgSuite(t *testing.T) {
var goodM365Config = account.M365Config{ var goodM365Config = account.M365Config{
M365: credentials.M365{ M365: credentials.M365{
ClientID: "cid", AzureClientID: "cid",
ClientSecret: "cs", AzureClientSecret: "cs",
}, },
TenantID: "tid", AzureTenantID: "tid",
} }
func (suite *M365CfgSuite) TestM365Config_Config() { func (suite *M365CfgSuite) TestM365Config_Config() {
@ -36,9 +36,9 @@ func (suite *M365CfgSuite) TestM365Config_Config() {
key string key string
expect string expect string
}{ }{
{"m365_clientID", m365.ClientID}, {"azure_clientid", m365.AzureClientID},
{"m365_clientSecret", m365.ClientSecret}, {"azure_clientSecret", m365.AzureClientSecret},
{"m365_tenantID", m365.TenantID}, {"azure_tenantid", m365.AzureTenantID},
} }
for _, test := range table { for _, test := range table {
assert.Equal(suite.T(), test.expect, c[test.key]) assert.Equal(suite.T(), test.expect, c[test.key])
@ -54,18 +54,18 @@ func (suite *M365CfgSuite) TestAccount_M365Config() {
out, err := a.M365Config() out, err := a.M365Config()
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, in.ClientID, out.ClientID) assert.Equal(t, in.AzureClientID, out.AzureClientID)
assert.Equal(t, in.ClientSecret, out.ClientSecret) assert.Equal(t, in.AzureClientSecret, out.AzureClientSecret)
assert.Equal(t, in.TenantID, out.TenantID) assert.Equal(t, in.AzureTenantID, out.AzureTenantID)
} }
func makeTestM365Cfg(cid, cs, tid string) account.M365Config { func makeTestM365Cfg(cid, cs, tid string) account.M365Config {
return account.M365Config{ return account.M365Config{
M365: credentials.M365{ M365: credentials.M365{
ClientID: cid, AzureClientID: cid,
ClientSecret: cs, AzureClientSecret: cs,
}, },
TenantID: tid, AzureTenantID: tid,
} }
} }
@ -94,19 +94,19 @@ func (suite *M365CfgSuite) TestAccount_M365Config_InvalidCases() {
{ {
"missing clientID", "missing clientID",
func(a account.Account) { func(a account.Account) {
a.Config["m365_clientID"] = "" a.Config["azure_clientid"] = ""
}, },
}, },
{ {
"missing client secret", "missing client secret",
func(a account.Account) { func(a account.Account) {
a.Config["m365_clientSecret"] = "" a.Config["azure_clientSecret"] = ""
}, },
}, },
{ {
"missing tenant id", "missing tenant id",
func(a account.Account) { func(a account.Account) {
a.Config["m365_tenantID"] = "" a.Config["azure_tenantid"] = ""
}, },
}, },
} }

View File

@ -8,14 +8,14 @@ import (
// envvar consts // envvar consts
const ( const (
ClientID = "CLIENT_ID" AzureClientID = "AZURE_CLIENT_ID"
ClientSecret = "CLIENT_SECRET" AzureClientSecret = "AZURE_CLIENT_SECRET"
) )
// M365 aggregates m365 credentials from flag and env_var values. // M365 aggregates m365 credentials from flag and env_var values.
type M365 struct { type M365 struct {
ClientID string AzureClientID string
ClientSecret string AzureClientSecret string
} }
// M365 is a helper for aggregating m365 secrets and credentials. // M365 is a helper for aggregating m365 secrets and credentials.
@ -23,15 +23,15 @@ func GetM365() M365 {
// todo (rkeeprs): read from either corso config file or env vars. // todo (rkeeprs): read from either corso config file or env vars.
// https://github.com/alcionai/corso/issues/120 // https://github.com/alcionai/corso/issues/120
return M365{ return M365{
ClientID: os.Getenv(ClientID), AzureClientID: os.Getenv(AzureClientID),
ClientSecret: os.Getenv(ClientSecret), AzureClientSecret: os.Getenv(AzureClientSecret),
} }
} }
func (c M365) Validate() error { func (c M365) Validate() error {
check := map[string]string{ check := map[string]string{
ClientID: c.ClientID, AzureClientID: c.AzureClientID,
ClientSecret: c.ClientSecret, AzureClientSecret: c.AzureClientSecret,
} }
for k, v := range check { for k, v := range check {