diff --git a/docs/GamUpdates.md b/docs/GamUpdates.md index 0df6e1ee..0e503922 100644 --- a/docs/GamUpdates.md +++ b/docs/GamUpdates.md @@ -10,12 +10,28 @@ Add the `-s` option to the end of the above commands to suppress creating the `g See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation +7.00.27 + +Updated `gam collect orphans` and all commands that print file paths to recognize +that a file owned by a user that has no parents is not an orphan if `sharedWithMeTime` is set. +This occurs when user A creates a file in a shared folder owned by user B and user B then removes +user A's access to the folder. + +Added commands to display Cloud Identity policies. +``` +gam print policies [todrive *] + (query ) [nowarnings] + [formatjson [quotechar ]] +gam show policies (query ) [nowarnings] + [formatjson] +``` + ### 7.00.26 Updated `drive_dir` in `gam.cfg` to allow the value `.` that causes `redirect csv|stdout|stderr ` to write `` in the current directory without having to prefix `` with `./`. -Upgraded to OpenSSL 3.4.0 where possible. +Upgraded to OpenSSL 3.4.0. ### 7.00.25 diff --git a/src/GamCommands.txt b/src/GamCommands.txt index 942401fb..dba06958 100644 --- a/src/GamCommands.txt +++ b/src/GamCommands.txt @@ -4067,6 +4067,14 @@ gam update deviceuserstate [clientid ] [healthscore very_poor|poor|neutral|good|very_good] [scorereason clear|] (customvalue (bool|boolean )|(number )|(string ))* +# Cloud Identity Policies + +gam print policies [todrive *] + (query ) [nowarnings] + [formatjson [quotechar ]] +gam show policies (query ) [nowarnings] + [formatjson] + # Inbound SSO ::= diff --git a/src/GamUpdate.txt b/src/GamUpdate.txt index c57af05f..8a375974 100644 --- a/src/GamUpdate.txt +++ b/src/GamUpdate.txt @@ -1,8 +1,26 @@ +7.00.27 + +Updated `gam collect orphans` and all commands that print file paths to recognize +that a file owned by a user that has no parents is not an orphan if `sharedWithMeTime` is set. +This occurs when user A creates a file in a shared folder owned by user B and user B then removes +user A's access to the folder. + +Added commands to display Cloud Identity policies. +``` +gam print policies [todrive *] + (query ) [nowarnings] + [formatjson [quotechar ]] +gam show policies (query ) [nowarnings] + [formatjson] +``` + 7.00.26 Updated `drive_dir` in `gam.cfg` to allow the value `.` that causes `redirect csv|stdout|stderr ` to write `` in the current directory without having to prefix `` with `./`. +Upgraded to OpenSSL 3.4.0 where possible. + 7.00.25 Updated authentication process for `gam print|show projects`. @@ -1223,7 +1241,7 @@ Batch processing will suspend for `` seconds before the next command li Added the following options to `` that allow more powerful matching. ``` -nottype +nottype typelist nottypelist rolelist diff --git a/src/gam/__init__.py b/src/gam/__init__.py index 83b2fed2..9d2a75ae 100755 --- a/src/gam/__init__.py +++ b/src/gam/__init__.py @@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki """ __author__ = 'GAM Team ' -__version__ = '7.00.26' +__version__ = '7.00.27' __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)' #pylint: disable=wrong-import-position @@ -35082,31 +35082,35 @@ def updateFieldsForCIGroupMatchPatterns(matchPatterns, fieldsList, csvPF=None): else: fieldsList.append(field) -# gam show policies (query ) [nowarnings] +CIPOLICY_TIME_OBJECTS = {'createTime', 'updateTime'} + # gam print policies [todrive *] -# (query ) [nowarnings] -def doPrintCIPolicy(): +# (query ) [nowarnings] +# [formatjson [quotechar ]] +# gam show policies (query ) [nowarnings] +# [formatjson] +def doPrintCIPolicies(): def _showPolicy(policy, FJQC, i=0, count=0): if FJQC is not None and FJQC.formatJSON: - printLine(json.dumps(policy, + printLine(json.dumps(cleanJSON(policy, timeObjects=CIPOLICY_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)) return printEntity([Ent.POLICY, policy['name']], i, count) Ind.Increment() policy.pop('name') - showJSON(None, policy) + showJSON(None, policy, timeObjects=CIPOLICY_TIME_OBJECTS) printBlankLine() Ind.Decrement() def _printPolicy(policy): - row = flattenJSON(policy) + row = flattenJSON(policy, timeObjects=CIPOLICY_TIME_OBJECTS) if not FJQC.formatJSON: csvPF.WriteRowTitles(row) elif csvPF.CheckRowTitles(row): csvPF.WriteRowNoFilter({'name': policy['name'], - 'JSON': json.dumps(cleanJSON(policy), + 'JSON': json.dumps(cleanJSON(policy, timeObjects=CIPOLICY_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)}) @@ -35134,7 +35138,7 @@ def doPrintCIPolicy(): elif myarg == 'nowarnings': add_warnings = False else: - unknownArgumentExit() + FJQC.GetFormatJSONQuoteChar(myarg, True) printGettingAllAccountEntities(Ent.POLICY, ifilter) pageMessage = getPageMessage() throwReasons = [GAPI.INVALID, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED] @@ -54602,7 +54606,7 @@ def extendFileTree(fileTree, feed, DLP, stripCRsFromName): if f_file['mimeType'] == MIMETYPE_GA_FOLDER and f_file['name'] == MY_DRIVE: f_file['parents'] = [] else: - f_file['parents'] = [ORPHANS] if f_file.get('ownedByMe', False) else [SHARED_WITHME] + f_file['parents'] = [ORPHANS] if f_file.get('ownedByMe', False) and 'sharedWithMeTime' not in f_file else [SHARED_WITHME] else: f_file['parents'] = [SHARED_DRIVES] if 'sharedWithMeTime' not in f_file else [SHARED_WITHME] if fileId not in fileTree: @@ -54622,11 +54626,11 @@ def extendFileTreeParents(drive, fileTree, fields): fileId=fileId, fields=fields, supportsAllDrives=True) if not result.get('parents', []): if not result.get('driveId'): - result['parents'] = [ORPHANS] if result.get('ownedByMe', False) else [SHARED_WITHME] + result['parents'] = [ORPHANS] if result.get('ownedByMe', False) and 'sharedWithMeTime' not in result else [SHARED_WITHME] else: if result['name'] == TEAM_DRIVE: result['name'] = _getSharedDriveNameFromId(drive, result['driveId']) - result['parents'] = [SHARED_DRIVES] if 'sharedWithMeTime' not in f_file else [SHARED_WITHME] + result['parents'] = [SHARED_DRIVES] if 'sharedWithMeTime' not in result else [SHARED_WITHME] fileTree[fileId]['info'] = result fileTree[fileId]['info']['noDisplay'] = True for parentId in result['parents']: @@ -60821,7 +60825,8 @@ def collectOrphans(users): pageMessage=getPageMessageForWhom(), throwReasons=GAPI.DRIVE_USER_THROW_REASONS, retryReasons=[GAPI.UNKNOWN_ERROR], - q=query, orderBy=OBY.orderBy, fields='nextPageToken,files(id,name,parents,mimeType,capabilities(canMoveItemWithinDrive))', + q=query, orderBy=OBY.orderBy, + fields='nextPageToken,files(id,name,parents,mimeType,sharedWithMeTime,capabilities(canMoveItemWithinDrive))', pageSize=GC.Values[GC.DRIVE_MAX_RESULTS]) if targetUserFolderPattern: trgtUserFolderName = _substituteForUser(targetUserFolderPattern, user, userName) @@ -60833,7 +60838,7 @@ def collectOrphans(users): continue orphanDriveFiles = [] for fileEntry in feed: - if not fileEntry.get('parents'): + if not fileEntry.get('parents') and 'sharedWithMeTime' not in fileEntry: orphanDriveFiles.append(fileEntry) jcount = len(orphanDriveFiles) entityPerformActionNumItemsModifier([Ent.USER, user], jcount, Ent.DRIVE_ORPHAN_FILE_OR_FOLDER, @@ -75189,7 +75194,7 @@ MAIN_COMMANDS_WITH_OBJECTS = { Cmd.ARG_CHROMEVERSIONS: doPrintShowChromeVersions, Cmd.ARG_CIGROUP: doPrintCIGroups, Cmd.ARG_CIGROUPMEMBERS: doPrintCIGroupMembers, - Cmd.ARG_CIPOLICY: doPrintCIPolicy, + Cmd.ARG_CIPOLICIES: doPrintCIPolicies, Cmd.ARG_CLASSROOMINVITATION: doPrintShowClassroomInvitations, Cmd.ARG_CONTACT: doPrintShowDomainContacts, Cmd.ARG_COURSE: doPrintCourses, @@ -75229,7 +75234,6 @@ MAIN_COMMANDS_WITH_OBJECTS = { Cmd.ARG_OWNERSHIP: doPrintShowOwnership, Cmd.ARG_PEOPLECONTACT: doPrintShowDomainPeopleContacts, Cmd.ARG_PEOPLEPROFILE: doPrintShowDomainPeopleProfiles, - Cmd.ARG_CIPOLICY: doPrintCIPolicy, Cmd.ARG_PRINTER: doPrintShowPrinters, Cmd.ARG_PRINTERMODEL: doPrintShowPrinterModels, Cmd.ARG_PRIVILEGES: doPrintShowPrivileges, @@ -75319,7 +75323,7 @@ MAIN_COMMANDS_WITH_OBJECTS = { Cmd.ARG_CHROMESCHEMA: doPrintShowChromeSchemas, Cmd.ARG_CHROMEVERSIONS: doPrintShowChromeVersions, Cmd.ARG_CIGROUPMEMBERS: doShowCIGroupMembers, - Cmd.ARG_CIPOLICY: doPrintCIPolicy, + Cmd.ARG_CIPOLICIES: doPrintCIPolicies, Cmd.ARG_CLASSROOMINVITATION: doPrintShowClassroomInvitations, Cmd.ARG_CONTACT: doPrintShowDomainContacts, Cmd.ARG_CROSTELEMETRY: doInfoPrintShowCrOSTelemetry, diff --git a/src/gam/gamlib/glapi.py b/src/gam/gamlib/glapi.py index 950d60b1..9cb70e40 100644 --- a/src/gam/gamlib/glapi.py +++ b/src/gam/gamlib/glapi.py @@ -45,8 +45,8 @@ CLOUDCHANNEL = 'cloudchannel' CLOUDIDENTITY_DEVICES = 'cloudidentitydevices' CLOUDIDENTITY_GROUPS = 'cloudidentitygroups' CLOUDIDENTITY_INBOUND_SSO = 'cloudidentityinboundsso' -CLOUDIDENTITY_POLICY = 'cloudidentitypolicy' CLOUDIDENTITY_ORGUNITS = 'cloudidentityorgunits' +CLOUDIDENTITY_POLICY = 'cloudidentitypolicy' CLOUDIDENTITY_ORGUNITS_BETA = 'cloudidentityorgunitsbeta' CLOUDIDENTITY_USERINVITATIONS = 'cloudidentityuserinvitations' CLOUDRESOURCEMANAGER = 'cloudresourcemanager' @@ -225,9 +225,9 @@ _INFO = { CLOUDIDENTITY_DEVICES: {'name': 'Cloud Identity Devices API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, CLOUDIDENTITY_GROUPS: {'name': 'Cloud Identity Groups API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, CLOUDIDENTITY_INBOUND_SSO: {'name': 'Cloud Identity Inbound SSO API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, - CLOUDIDENTITY_POLICY: {'name': 'Cloud Identity Policy API', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, CLOUDIDENTITY_ORGUNITS: {'name': 'Cloud Identity OrgUnits API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, CLOUDIDENTITY_ORGUNITS_BETA: {'name': 'Cloud Identity OrgUnits API', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, + CLOUDIDENTITY_POLICY: {'name': 'Cloud Identity Policy API', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, CLOUDIDENTITY_USERINVITATIONS: {'name': 'Cloud Identity User Invitations API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, CLOUDRESOURCEMANAGER: {'name': 'Cloud Resource Manager API v3', 'version': 'v3', 'v2discovery': True}, CONTACTS: {'name': 'Contacts API', 'version': 'v3', 'v2discovery': False}, @@ -362,15 +362,15 @@ _CLIENT_SCOPES = [ 'api': CLOUDIDENTITY_INBOUND_SSO, 'subscopes': READONLY, 'scope': 'https://www.googleapis.com/auth/cloud-identity.inboundsso'}, + {'name': 'Cloud Identity OrgUnits API', + 'api': CLOUDIDENTITY_ORGUNITS_BETA, + 'subscopes': READONLY, + 'scope': 'https://www.googleapis.com/auth/cloud-identity.orgunits'}, {'name': 'Cloud Identity - Policy', 'api': CLOUDIDENTITY_POLICY, 'subscopes': [], 'scope': 'https://www.googleapis.com/auth/cloud-identity.policies.readonly' }, - {'name': 'Cloud Identity OrgUnits API', - 'api': CLOUDIDENTITY_ORGUNITS_BETA, - 'subscopes': READONLY, - 'scope': 'https://www.googleapis.com/auth/cloud-identity.orgunits'}, {'name': 'Cloud Identity User Invitations API', 'api': CLOUDIDENTITY_USERINVITATIONS, 'subscopes': READONLY, diff --git a/src/gam/gamlib/glclargs.py b/src/gam/gamlib/glclargs.py index fb1d7948..1629a1fb 100644 --- a/src/gam/gamlib/glclargs.py +++ b/src/gam/gamlib/glclargs.py @@ -493,7 +493,7 @@ class GamCLArgs(): ARG_CIGROUPSMEMBERS = 'cigroupsmembers' ARG_CIMEMBER = 'cimember' ARG_CIMEMBERS = 'cimembers' - ARG_CIPOLICY = 'policies' + ARG_CIPOLICIES = 'policies' ARG_CLASS = 'class' ARG_CLASSES = 'classes' ARG_CLASSPARTICIPANTS = 'classparticipants'