From 4137b3b77b07724d65786f56fd2f0b963fad0a8e Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Wed, 18 Mar 2026 17:22:57 -0700 Subject: [PATCH] gcpdetails/scopes cleanup #1891 --- src/GamCommands.txt | 8 ++++---- src/GamUpdate.txt | 10 ++++++++++ src/gam/__init__.py | 46 ++++++++++++++++++++++----------------------- 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/GamCommands.txt b/src/GamCommands.txt index 586e288d..fd77a51b 100644 --- a/src/GamCommands.txt +++ b/src/GamCommands.txt @@ -8914,17 +8914,17 @@ gam delete tokens clientid gam print tokens|token [todrive *] [clientid ] [usertokencounts|(aggregateusersby|orderby clientid|id|appname|displaytext)] - [delimiter ] + [delimiter ] [gcpdetails] gam show tokens|token|3lo|oauth [clientid ] [usertokencounts|(aggregateusersby|orderby clientid|id|appname|displaytext)] - [delimiter ] + [delimiter ] [gcpdetails] gam print tokens|token [todrive *] [clientid ] [usertokencounts|(aggregateusersby|orderby clientid|id|appname|displaytext)] - [delimiter ] + [delimiter ] [gcpdetails] [] gam show tokens|token [clientid ] [usertokencounts|(aggregateusersby|orderby clientid|id|appname|displaytext)] - [delimiter ] + [delimiter ] [gcpdetails] [] # Users - YouTube diff --git a/src/GamUpdate.txt b/src/GamUpdate.txt index dbc5977c..e7cabc62 100644 --- a/src/GamUpdate.txt +++ b/src/GamUpdate.txt @@ -1,3 +1,13 @@ +7.37.00 + +Added new client access scopes used by `gam print tokens`. +``` +[*] 52) Resource Manager - Organizations readonly +[*] 53) Resource Manager - Projects readonly +``` + +Added option `gcpdetails` to `gam print tokens` that uses these scopes to get additional project information. + 7.36.03 Added command to send email replies that causes Gmail to recognize the message diff --git a/src/gam/__init__.py b/src/gam/__init__.py index 27ee79ef..af89a0e4 100755 --- a/src/gam/__init__.py +++ b/src/gam/__init__.py @@ -11361,8 +11361,8 @@ def doOAuthCreate(): for scope in scopesList: subScopes = scope.get('subscopes', []) if ((uscope == scope['scope']) or - (uscope.endswith('.action') and 'actiononly' in subscopes) or - (uscope.endswith('.readonly') and 'readonly' in subscopes)): + (uscope.endswith('.action') and 'actiononly' in subScopes) or + (uscope.endswith('.readonly') and 'readonly' in subScopes)): scopes.append(uscope) break else: @@ -72447,22 +72447,25 @@ def _printShowTokens(entityType, users): match = re.search(r'^\d+', client_id) return match.group() - def get_gcp_info(): - if result['project'] in internal_projects: - result['internal'] = True - return - try: - results = callGAPI(crm1.projects(), 'getAncestry', - throwReasons=[GAPI.PERMISSION_DENIED], - projectId=result['project']) - for ancestor in results.get('ancestor', []): - if ancestor.get('resourceId', {}).get('type') == 'organization' and ancestor.get('resourceId', {}).get('id') == org_id: - result['internal'] = True - internal_projects.append(result['project']) - except GAPI.permissionDenied: - # we don't have permission to get project. This might be an external project - # or it might be an internal project we don't have rights to get. - pass + def get_gcp_info(results): + for result in results: + result['project'] = project_from_client_id(result.get('clientId')) + if result['project'] in internal_projects: + result['internal'] = True + continue + result['internal'] = False + try: + results = callGAPI(crm1.projects(), 'getAncestry', + throwReasons=[GAPI.PERMISSION_DENIED], + projectId=result['project']) + for ancestor in results.get('ancestor', []): + if ancestor.get('resourceId', {}).get('type') == 'organization' and ancestor.get('resourceId', {}).get('id') == org_id: + result['internal'] = True + internal_projects.add(result['project']) + except GAPI.permissionDenied: + # we don't have permission to get project. This might be an external project + # or it might be an internal project we don't have rights to get. + pass cd = buildGAPIObject(API.DIRECTORY) csvPF = CSVPrintFile() if Act.csvFormat() else None @@ -72493,7 +72496,6 @@ def _printShowTokens(entityType, users): elif myarg == 'gcpdetails': getGCPDetails = True extra_titles = ['project', 'internal'] - gcp_projects = {} elif not entityType: Cmd.Backup() entityType, users = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS) @@ -72514,7 +72516,7 @@ def _printShowTokens(entityType, users): else: tokenTitle = TOKENS_TITLE_MAP[aggregateUsersBy] if getGCPDetails: - internal_projects = [] # cache + internal_projects = set() # cache crm = buildGAPIObject('cloudresourcemanager') crm1 = buildGAPIObject('cloudresourcemanagerv1') admin_email = _getAdminEmail() @@ -72542,9 +72544,7 @@ def _printShowTokens(entityType, users): GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED], userKey=user, fields=f'items({fields})') if getGCPDetails: - for result in results: - result['project'] = project_from_client_id(result.get('clientId')) - get_gcp_info() + get_gcp_info(results) if not aggregateUsersBy: if not csvPF: jcount = len(results)