diff --git a/cli/azd/cmd/pipeline.go b/cli/azd/cmd/pipeline.go index 561027dfe27..ac168f9443b 100644 --- a/cli/azd/cmd/pipeline.go +++ b/cli/azd/cmd/pipeline.go @@ -55,7 +55,7 @@ func (pc *pipelineConfigFlags) Bind(local *pflag.FlagSet, global *internal.Globa &pc.PipelineAuthTypeName, "auth-type", "", - "The authentication type used between the pipeline provider and Azure for deployment (Only valid for GitHub provider). Valid values: federated, client-credentials.", + "The authentication type used between the pipeline provider and Azure for deployment. Valid values: federated, client-credentials. Both the GitHub and Azure DevOps providers default to federated (OIDC) credentials.", ) //nolint:lll local.StringArrayVar( diff --git a/cli/azd/cmd/testdata/TestFigSpec.ts b/cli/azd/cmd/testdata/TestFigSpec.ts index 373a5ff2945..70a5879087c 100644 --- a/cli/azd/cmd/testdata/TestFigSpec.ts +++ b/cli/azd/cmd/testdata/TestFigSpec.ts @@ -6260,7 +6260,7 @@ const completionSpec: Fig.Spec = { }, { name: ['--auth-type'], - description: 'The authentication type used between the pipeline provider and Azure for deployment (Only valid for GitHub provider). Valid values: federated, client-credentials.', + description: 'The authentication type used between the pipeline provider and Azure for deployment. Valid values: federated, client-credentials. Both the GitHub and Azure DevOps providers default to federated (OIDC) credentials.', args: [ { name: 'auth-type', diff --git a/cli/azd/cmd/testdata/TestUsage-azd-pipeline-config.snap b/cli/azd/cmd/testdata/TestUsage-azd-pipeline-config.snap index 2a553e4233e..a65a22d1f2a 100644 --- a/cli/azd/cmd/testdata/TestUsage-azd-pipeline-config.snap +++ b/cli/azd/cmd/testdata/TestUsage-azd-pipeline-config.snap @@ -10,7 +10,7 @@ Usage Flags -m, --applicationServiceManagementReference string : Service Management Reference. References application or service contact information from a Service or Asset Management database. This value must be a Universally Unique Identifier (UUID). You can set this value globally by running azd config set pipeline.config.applicationServiceManagementReference . - --auth-type string : The authentication type used between the pipeline provider and Azure for deployment (Only valid for GitHub provider). Valid values: federated, client-credentials. + --auth-type string : The authentication type used between the pipeline provider and Azure for deployment. Valid values: federated, client-credentials. Both the GitHub and Azure DevOps providers default to federated (OIDC) credentials. -e, --environment string : The name of the environment to use. --principal-id string : The client id of the service principal to use to grant access to Azure resources as part of the pipeline. --principal-name string : The name of the service principal to use to grant access to Azure resources as part of the pipeline. diff --git a/cli/azd/pkg/pipeline/azdo_provider.go b/cli/azd/pkg/pipeline/azdo_provider.go index 1a4278e1f65..40b7e1369e5 100644 --- a/cli/azd/pkg/pipeline/azdo_provider.go +++ b/cli/azd/pkg/pipeline/azdo_provider.go @@ -18,7 +18,6 @@ import ( "github.com/azure/azure-dev/cli/azd/pkg/graphsdk" "github.com/azure/azure-dev/cli/azd/pkg/infra/provisioning" "github.com/azure/azure-dev/cli/azd/pkg/input" - "github.com/azure/azure-dev/cli/azd/pkg/output" "github.com/azure/azure-dev/cli/azd/pkg/tools" "github.com/azure/azure-dev/cli/azd/pkg/tools/git" "github.com/microsoft/azure-devops-go-api/azuredevops/v7" @@ -707,17 +706,6 @@ func (p *AzdoCiProvider) preConfigureCheck( infraOptions provisioning.Options, projectPath string, ) (bool, error) { - authType := PipelineAuthType(pipelineManagerArgs.PipelineAuthTypeName) - - if authType == AuthTypeFederated { - return false, fmt.Errorf( - //nolint:lll - "Azure DevOps does not support federated authentication. To explicitly use client credentials set the %s flag. %w", - output.WithBackticks("--auth-type client-credentials"), - ErrAuthNotSupported, - ) - } - _, updatedPat, err := azdo.EnsurePatExists(ctx, p.Env, p.console) if err != nil { return updatedPat, err diff --git a/cli/azd/pkg/pipeline/azdo_provider_test.go b/cli/azd/pkg/pipeline/azdo_provider_test.go index d9ccad59f50..52f827d633d 100644 --- a/cli/azd/pkg/pipeline/azdo_provider_test.go +++ b/cli/azd/pkg/pipeline/azdo_provider_test.go @@ -4,7 +4,6 @@ package pipeline import ( - "errors" "strings" "testing" @@ -152,19 +151,24 @@ func Test_azdo_ci_provider_preConfigureCheck(t *testing.T) { require.True(t, updatedConfig) }) - t.Run("fails if auth type is set to federated", func(t *testing.T) { + t.Run("succeeds if auth type is set to federated (default for azdo)", func(t *testing.T) { ctx := t.Context() testConsole := mockinput.NewMockConsole() + testPat := "testPAT12345" + testConsole.WhenPrompt(func(options input.ConsoleOptions) bool { + return options.Message == "Personal Access Token (PAT):" + }).Respond(testPat) pipelineManagerArgs := PipelineManagerArgs{ PipelineAuthTypeName: string(AuthTypeFederated), } provider := getAzdoCiProviderTestHarness(testConsole) - updatedConfig, err := provider.preConfigureCheck(ctx, pipelineManagerArgs, provisioning.Options{}, "") - require.Error(t, err) - require.False(t, updatedConfig) - require.True(t, errors.Is(err, ErrAuthNotSupported)) + // Azure DevOps supports federated (OIDC) credentials and uses them by default, + // so an explicit federated auth type must not be rejected. + _, err := provider.preConfigureCheck(ctx, pipelineManagerArgs, provisioning.Options{}, "") + require.NoError(t, err) + require.NotErrorIs(t, err, ErrAuthNotSupported) }) } diff --git a/cli/azd/pkg/pipeline/pipeline_test.go b/cli/azd/pkg/pipeline/pipeline_test.go index 76ee2327fa4..061f10021fb 100644 --- a/cli/azd/pkg/pipeline/pipeline_test.go +++ b/cli/azd/pkg/pipeline/pipeline_test.go @@ -2072,7 +2072,7 @@ func Test_AzdoCiProvider_preConfigureCheck_clientCredentials(t *testing.T) { require.False(t, updated) }) - t.Run("federated auth type returns error", func(t *testing.T) { + t.Run("federated auth type is accepted (default for azdo)", func(t *testing.T) { t.Parallel() testConsole := mockinput.NewMockConsole() @@ -2090,9 +2090,7 @@ func Test_AzdoCiProvider_preConfigureCheck_clientCredentials(t *testing.T) { _, err := provider.preConfigureCheck(t.Context(), PipelineManagerArgs{ PipelineAuthTypeName: string(AuthTypeFederated), }, provisioning.Options{}, "") - require.Error(t, err) - require.ErrorIs(t, err, ErrAuthNotSupported) - require.Contains(t, err.Error(), "does not support federated") + require.NoError(t, err) }) } @@ -6652,33 +6650,35 @@ func Test_AzdoCiProvider_requiredTools(t *testing.T) { } // --------------------------------------------------------------------------- -// AzdoCiProvider.preConfigureCheck — federated auth returns error +// AzdoCiProvider.preConfigureCheck — federated auth is accepted (default) // --------------------------------------------------------------------------- -func Test_AzdoCiProvider_preConfigureCheck_federatedAuthError(t *testing.T) { +func Test_AzdoCiProvider_preConfigureCheck_federatedAuthAccepted(t *testing.T) { t.Parallel() - tempDir := t.TempDir() - ctx := t.Context() - azdContext := azdcontext.NewAzdContextWithDirectory(tempDir) - mockContext := resetContext(tempDir, ctx) - resetAzureYaml(t, filepath.Join(tempDir, "azure.yaml")) - deleteYamlFiles(t, tempDir) - simulateUserInteraction(mockContext, ciProviderAzureDevOps, true) + testConsole := mockinput.NewMockConsole() - manager, err := createPipelineManager(mockContext, azdContext, nil, nil) - require.NoError(t, err) + // PAT and org already present in the environment so no prompting is required. + env := environment.NewWithValues("test-env", map[string]string{ + "AZURE_DEVOPS_EXT_PAT": "testPAT", + "AZURE_DEVOPS_ORG_NAME": "myorg", + }) + + provider := &AzdoCiProvider{ + Env: env, + console: testConsole, + } - // AzDo CI provider explicitly rejects federated auth - _, err = manager.ciProvider.preConfigureCheck( - ctx, + // Azure DevOps supports federated (OIDC) credentials and uses them by default, + // so requesting federated auth explicitly must not be rejected. + _, err := provider.preConfigureCheck( + t.Context(), PipelineManagerArgs{PipelineAuthTypeName: string(AuthTypeFederated)}, provisioning.Options{}, - tempDir, + "", ) - require.Error(t, err) - assert.ErrorIs(t, err, ErrAuthNotSupported) - assert.Contains(t, err.Error(), "does not support federated") + require.NoError(t, err) + require.NotErrorIs(t, err, ErrAuthNotSupported) } // ---------------------------------------------------------------------------