-
Notifications
You must be signed in to change notification settings - Fork 288
fix(agents): return actionable auth error when Graph token is missing #7546
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| words: | ||
| - aadsts | ||
| - aiservices | ||
| - agentserver | ||
| - anonymousconnection | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,13 +5,16 @@ package project | |||||||||
|
|
||||||||||
| import ( | ||||||||||
| "context" | ||||||||||
| "errors" | ||||||||||
| "fmt" | ||||||||||
| "os" | ||||||||||
| "strconv" | ||||||||||
| "strings" | ||||||||||
| "sync" | ||||||||||
| "time" | ||||||||||
|
|
||||||||||
| "azureaiagent/internal/exterrors" | ||||||||||
|
|
||||||||||
| "github.com/Azure/azure-sdk-for-go/sdk/azidentity" | ||||||||||
| "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v3" | ||||||||||
| "github.com/azure/azure-dev/cli/azd/pkg/azdext" | ||||||||||
|
|
@@ -183,6 +186,15 @@ func ensureAgentIdentityRBACWithCred( | |||||||||
| for attempt := range identityLookupMaxAttempts { | ||||||||||
| agentIdentities, err = discoverAgentIdentity(ctx, graphClient, displayName) | ||||||||||
| if err != nil { | ||||||||||
| if isCredentialAuthError(err) { | ||||||||||
| return exterrors.Auth( | ||||||||||
| exterrors.CodeRbacAuthFailed, | ||||||||||
| "agent identity RBAC setup failed: "+ | ||||||||||
| "could not acquire a Microsoft Graph token", | ||||||||||
| "run 'azd auth login --scope https://graph.microsoft.com/.default' "+ | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Low] Original error discarded without debug logging The structured error provides a clean user message (correctly per @jongio's resolved feedback), but the original error is completely discarded — not wrapped, not logged. The correlation IDs and specific failure reason from the Azure SDK are lost for post-incident debugging. Consider logging the original error at debug level before returning. |
||||||||||
| "and re-run 'azd deploy'", | ||||||||||
|
Comment on lines
+194
to
+195
|
||||||||||
| "run 'azd auth login --scope https://graph.microsoft.com/.default' "+ | |
| "and re-run 'azd deploy'", | |
| "run `azd auth login --scope https://graph.microsoft.com/.default` "+ | |
| "and re-run `azd deploy`", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Medium] AADSTS string fallback breadth
strings.Contains(err.Error(), "AADSTS") matches any error containing "AADSTS", not just token acquisition failures. While Azure consistently returns uppercase "AADSTS", add a test case for lowercase aadsts (expected false) to document the case-sensitivity assumption and lock in the behavior contract.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,8 +4,12 @@ | |
| package project | ||
|
|
||
| import ( | ||
| "errors" | ||
| "fmt" | ||
| "net/http" | ||
| "testing" | ||
|
|
||
| "github.com/Azure/azure-sdk-for-go/sdk/azidentity" | ||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
@@ -198,3 +202,54 @@ func TestConstants(t *testing.T) { | |
| assert.Equal(t, "5e0bd9bd-7b93-4f28-af87-19fc36ad61bd", roleCognitiveServicesOpenAIUser) | ||
| assert.Equal(t, "3913510d-42f4-4e42-8a64-420c390055eb", roleMonitoringMetricsPublisher) | ||
| } | ||
|
|
||
| func TestIsCredentialAuthError(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| err error | ||
| want bool | ||
| }{ | ||
| { | ||
| name: "nil error", | ||
| err: nil, | ||
| want: false, | ||
| }, | ||
| { | ||
| name: "unrelated error", | ||
| err: fmt.Errorf("network timeout"), | ||
| want: false, | ||
| }, | ||
| { | ||
| name: "typed AuthenticationFailedError", | ||
| err: &azidentity.AuthenticationFailedError{ | ||
| RawResponse: &http.Response{StatusCode: 401}, | ||
| }, | ||
| want: true, | ||
| }, | ||
| { | ||
| name: "wrapped AuthenticationFailedError", | ||
| err: fmt.Errorf("graph query failed: %w", | ||
| &azidentity.AuthenticationFailedError{ | ||
| RawResponse: &http.Response{StatusCode: 401}, | ||
| }), | ||
| want: true, | ||
| }, | ||
| { | ||
| name: "AADSTS error code fallback", | ||
| err: fmt.Errorf("AADSTS70043: The refresh token has expired"), | ||
| want: true, | ||
| }, | ||
| { | ||
| name: "string-only error without AADSTS not matched", | ||
| err: errors.New("AzureDeveloperCLICredential: please run azd auth login"), | ||
| want: false, | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| got := isCredentialAuthError(tt.err) | ||
| assert.Equal(t, tt.want, got) | ||
| }) | ||
| } | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Medium] Missing test for structured error return path
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this handler, repo guidance prefers
errors.AsType[T](err)overerrors.As(...)for type checks (see cli/azd/AGENTS.md). Switching toerrors.AsType[*azdext.LocalError]/errors.AsType[*azdext.ServiceError]will keep style consistent and avoiderrorlintcomplaints.