Compare commits

...

1 Commits

Author SHA1 Message Date
dc-bytedance
0ac3c230fe fix: honor requiredScopes conjunction in CollectScopesForProjects 2026-07-14 16:34:02 +08:00
2 changed files with 45 additions and 6 deletions

View File

@@ -536,6 +536,43 @@ func TestCollectScopesForProjects_NonexistentProject(t *testing.T) {
}
}
// TestCollectScopesForProjects_HonorsRequiredScopes verifies that a method's
// full requiredScopes conjunction is collected, not just the umbrella scope.
// The mail message get/batch_get APIs declare requiredScopes =
// [readonly, subject:read, address:read, body:read]; the conjunction must be
// collected together — the umbrella readonly scope alone does not cover
// subject/address/body.
func TestCollectScopesForProjects_HonorsRequiredScopes(t *testing.T) {
hasMail := false
for _, p := range ListFromMetaProjects() {
if p == "mail" {
hasMail = true
break
}
}
if !hasMail {
t.Skip("mail domain not present in meta catalog")
}
scopes := CollectScopesForProjects([]string{"mail"}, "user")
for _, want := range []string{
"mail:user_mailbox.message.subject:read",
"mail:user_mailbox.message.address:read",
"mail:user_mailbox.message.body:read",
} {
found := false
for _, s := range scopes {
if s == want {
found = true
break
}
}
if !found {
t.Errorf("expected requiredScope %q in collected scopes, got %v", want, scopes)
}
}
}
// --- auth_domain functions ---
func TestGetAuthDomain_Configured(t *testing.T) {

View File

@@ -153,15 +153,17 @@ func CollectAllScopesFromMeta(identity string) []string {
return result
}
// CollectScopesForProjects collects the recommended scope for each API method
// in the specified from_meta projects. For each method, only the scope with
// the highest priority score is selected.
// CollectScopesForProjects collects the effective scopes for each API method in
// the specified from_meta projects. It uses DeclaredScopesForMethod so a
// method's full requiredScopes conjunction is honored (e.g. reading a mail
// message needs the subject/address/body scopes together, not just the umbrella
// readonly scope), falling back to the single recommended scope when a method
// declares no requiredScopes.
func CollectScopesForProjects(projects []string, identity string) []string {
priorities := LoadScopePriorities()
scopeSet := make(map[string]bool)
for _, ref := range methodsForProjects(projects, identity) {
if best := bestScope(ref.Method.Scopes, priorities); best != "" {
scopeSet[best] = true
for _, s := range DeclaredScopesForMethod(ref.Method, identity) {
scopeSet[s] = true
}
}