mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-10 17:21:36 +00:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7b31550f3 | ||
|
|
ed19f877a5 | ||
|
|
0ab08c968e | ||
|
|
02a7a1a106 | ||
|
|
170a2e593b | ||
|
|
8339b92537 | ||
|
|
ce16aa252e | ||
|
|
8a70470281 | ||
|
|
981301a878 | ||
|
|
13cfb77811 | ||
|
|
458e08645d | ||
|
|
98d4d3c06f | ||
|
|
2204c35193 | ||
|
|
87827badb8 | ||
|
|
319bedd338 | ||
|
|
b3e4541b9d | ||
|
|
9d17ea2d68 | ||
|
|
9c4b348909 | ||
|
|
a8fafd0dcc | ||
|
|
ac31042576 | ||
|
|
a0d695c57d | ||
|
|
bf742ec88a | ||
|
|
f2206d02e4 | ||
|
|
c3add48f2a | ||
|
|
119047bf2b | ||
|
|
662b7d857c | ||
|
|
3bb9724e50 | ||
|
|
b450716c23 | ||
|
|
73333f921d | ||
|
|
c5d194489f |
18
.github/workflows/build.yml
vendored
18
.github/workflows/build.yml
vendored
@@ -28,6 +28,8 @@ env:
|
||||
OPENSSL_SOURCE_PATH: ${{ github.workspace }}/src/openssl
|
||||
PYTHON_INSTALL_PATH: ${{ github.workspace }}/bin/python
|
||||
PYTHON_SOURCE_PATH: ${{ github.workspace }}/src/cpython
|
||||
CRYPTOGRAPHY_BUILD_OPENSSL_NO_LEGACY: 1
|
||||
CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -124,7 +126,7 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
cache.tar.xz
|
||||
key: gam-${{ matrix.jid }}-20250408-01
|
||||
key: gam-${{ matrix.jid }}-20250422
|
||||
|
||||
- name: Untar Cache archive
|
||||
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
|
||||
@@ -197,7 +199,7 @@ jobs:
|
||||
run: |
|
||||
echo "RUNNING: apt update..."
|
||||
sudo apt-get -qq --yes update
|
||||
sudo apt-get -qq --yes install swig libpcsclite-dev libxslt1-dev libsqlite3-dev
|
||||
sudo apt-get -qq --yes install swig libpcsclite-dev libxslt1-dev libsqlite3-dev libffi-dev pkg-config
|
||||
|
||||
- name: MacOS install tools
|
||||
if: runner.os == 'macOS'
|
||||
@@ -450,6 +452,9 @@ jobs:
|
||||
"$PYTHON" -m pip install --upgrade pip
|
||||
"$PYTHON" -m pip install --upgrade wheel
|
||||
"$PYTHON" -m pip install --upgrade setuptools
|
||||
"$PYTHON" -m pip install --upgrade importlib-metadata
|
||||
"$PYTHON" -m pip install --upgrade setuptools-scm
|
||||
"$PYTHON" -m pip list
|
||||
|
||||
- name: Custom wheels for Win arm64
|
||||
if: runner.os == 'Windows' && runner.arch == 'ARM64'
|
||||
@@ -462,7 +467,14 @@ jobs:
|
||||
echo "Downloading ${latest_crypt_whl}..."
|
||||
curl -O -L "$latest_crypt_whl"
|
||||
"$PYTHON" -m pip install cryptography*.whl
|
||||
|
||||
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
|
||||
# - name: Compile cryptography from source (no legacy)
|
||||
# if: runner.os != 'Windows' || runner.arch != 'ARM64'
|
||||
# run: |
|
||||
# pip install --no-binary ":all:" --force cryptography
|
||||
|
||||
- name: Install pip requirements
|
||||
run: |
|
||||
echo "before anything..."
|
||||
|
||||
2
.github/workflows/pypi.yml
vendored
2
.github/workflows/pypi.yml
vendored
@@ -31,3 +31,5 @@ jobs:
|
||||
|
||||
- name: Publish package distributions to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
attestation: true
|
||||
|
||||
@@ -7,19 +7,21 @@ authors = [
|
||||
{ name="Jay Lee", email="jay0lee@gmail.com" },
|
||||
{ name="Ross Scroggs", email="Ross.Scroggs@gmail.com" },
|
||||
]
|
||||
# # The following files should be edited to match: setup.cfg, requirements.txt
|
||||
dependencies = [
|
||||
"chardet",
|
||||
"cryptography",
|
||||
"chardet>=5.2.0",
|
||||
"cryptography>=44.0.2",
|
||||
"distro; sys_platform=='linux'",
|
||||
"filelock",
|
||||
"google-api-python-client>=2.1",
|
||||
"google-auth-httplib2",
|
||||
"google-auth-oauthlib>=0.4.1",
|
||||
"google-auth>=2.3.2",
|
||||
"httplib2>=0.17.0",
|
||||
"lxml",
|
||||
"passlib>=1.7.2",
|
||||
"pathvalidate",
|
||||
"filelock>=3.18.0",
|
||||
"google-api-python-client>=2.167.0",
|
||||
"google-auth-httplib2>=0.2.0",
|
||||
"google-auth-oauthlib>=1.2.2",
|
||||
"google-auth>=2.39.0",
|
||||
"httplib2>=0.22.0",
|
||||
"lxml>=5.4.0",
|
||||
"passlib>=1.7.4",
|
||||
"pathvalidate>=3.2.3",
|
||||
"pyscard==2.2.1",
|
||||
"python-dateutil",
|
||||
]
|
||||
description = "CLI tool to manage Google Workspace"
|
||||
@@ -39,7 +41,7 @@ license = {text = "Apache License (2.0)"}
|
||||
license-files = ["LICEN[CS]E*"]
|
||||
|
||||
[project.optional-dependencies]
|
||||
yubikey = ["yubikey-manager>=5.0"]
|
||||
yubikey = ["yubikey-manager>=5.6.1"]
|
||||
|
||||
[project.scripts]
|
||||
gam = "gam.__main__:main"
|
||||
|
||||
@@ -322,7 +322,8 @@ If an item contains spaces, it should be surrounded by ".
|
||||
wsess | workspaceesentials | gsuiteessentials | essentials | d4e | driveenterprise | drive4enterprise | 1010060001 | Google Workspace Essentials |
|
||||
wsessplus | workspaceessentialsplus | 1010060005 | Google Workspace Essentials Plus |
|
||||
wsflw | workspacefrontline | workspacefrontlineworker | 1010020030 | Google Workspace Frontline Starter |
|
||||
wsflwstan | workspacefrontlinestan | workspacefrontlineworkerstan | 1010020031 | Google Workspace Frontline Standard
|
||||
wsflwstan | workspacefrontlinestan | workspacefrontlineworkerstan | 1010020031 | Google Workspace Frontline Standard |
|
||||
wsflwplus | workspacefrontlineplus | workspacefrontlineworkerplus | 1010020034 | Google Workspace Frontline Plus
|
||||
|
||||
## Items built from primitives
|
||||
|
||||
@@ -782,7 +783,7 @@ Items, separated by spaces, with spaces, commas or single quotes in the items th
|
||||
|
||||
## Collections of ChromeOS Devices
|
||||
|
||||
Specify a collection of ChromeOS devices by directly specifying them or by specifiying items that will yield a list of ChromeOS devices.
|
||||
Specify a collection of ChromeOS devices by directly specifying them or by specifying items that will yield a list of ChromeOS devices.
|
||||
|
||||
<CrOSTypeEntity> ::=
|
||||
(all cros)|
|
||||
@@ -865,7 +866,7 @@ Specify a collection of ChromeOS devices by directly specifying them or by speci
|
||||
|
||||
## Collections of Users
|
||||
|
||||
Specify a collection of Users by directly specifying them or by specifiying items that will yield a list of users.
|
||||
Specify a collection of Users by directly specifying them or by specifying items that will yield a list of users.
|
||||
|
||||
<UserTypeEntity> ::=
|
||||
(all users|users_ns|users_susp|users_ns_susp)|
|
||||
@@ -4458,6 +4459,7 @@ gam report usage customer [todrive <ToDriveAttribute>*]
|
||||
domain|
|
||||
drive|doc|docs|
|
||||
gcp|
|
||||
gemini|geminiforworkspace|
|
||||
groups|group|
|
||||
groupsenterprise|enterprisegroups|
|
||||
jamboard|
|
||||
|
||||
@@ -1,7 +1,44 @@
|
||||
7.06.11
|
||||
|
||||
Improved `gam checkconn`.
|
||||
|
||||
Updated `gam print group-members` and `gam print cigroup-members` to recognize members
|
||||
that are groups representing chat spaces. For now, these groups are not expanded when
|
||||
`recursive` is specified.
|
||||
|
||||
7.06.10
|
||||
|
||||
Added the following license SKU.
|
||||
```
|
||||
1010020034 - Google Workspace Frontline Plus
|
||||
```
|
||||
|
||||
7.06.09
|
||||
|
||||
Added `gemini` and `geminiforworkspace` to `<ActivityApplicationName>` for use in
|
||||
`gam report <ActivityApplicationName>`.
|
||||
|
||||
7.06.08
|
||||
|
||||
Fixed problem where Yubikeys caused a trap.
|
||||
|
||||
7.06.07
|
||||
|
||||
Updated private key rotation progress messages in `gam create|use|update project`
|
||||
and `gam upload sakey`.
|
||||
|
||||
Updated `gam use project` to display the following error message when the specifed project
|
||||
already has a service account.
|
||||
```
|
||||
Re-run the command specify a new service account name with: saname <ServiceAccountName>'
|
||||
```
|
||||
|
||||
7.06.06
|
||||
|
||||
Native support for Windows 11 Arm-based devices.
|
||||
|
||||
Renamed some MacOS and Linux binary installer files to align on terminology. Everything is "arm64" now, no "aarch64".
|
||||
|
||||
7.06.05
|
||||
|
||||
Updated code in `gam delete|update chromepolicy` to handle the `policyTargetKey[additionalTargetKeys]`
|
||||
|
||||
@@ -8,7 +8,7 @@ GAM installation script.
|
||||
OPTIONS:
|
||||
-h show help.
|
||||
-d Directory where gam folder will be installed. Default is \$HOME/bin/
|
||||
-a Architecture to install (i386, x86_64, x86_64_legacy, arm, arm64). Default is to detect your arch with "uname -m".
|
||||
-a Architecture to install (x86_64, arm64). Default is to detect your arch with "uname -m".
|
||||
-o OS we are running (linux, macos). Default is to detect your OS with "uname -s".
|
||||
-b OS version. Default is to detect on MacOS and Linux.
|
||||
-l Just upgrade GAM to latest version. Skips project creation and auth.
|
||||
|
||||
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
|
||||
"""
|
||||
|
||||
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
|
||||
__version__ = '7.06.06'
|
||||
__version__ = '7.06.11'
|
||||
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||
|
||||
#pylint: disable=wrong-import-position
|
||||
@@ -95,6 +95,8 @@ import wsgiref.simple_server
|
||||
import wsgiref.util
|
||||
import zipfile
|
||||
|
||||
# disable legacy stuff we don't use and isn't secure
|
||||
os.environ['CRYPTOGRAPHY_OPENSSL_NO_LEGACY'] = "1"
|
||||
from cryptography import x509
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
@@ -9358,32 +9360,9 @@ def getOSPlatform():
|
||||
|
||||
# gam checkconnection
|
||||
def doCheckConnection():
|
||||
hosts = ['api.github.com',
|
||||
'raw.githubusercontent.com',
|
||||
'accounts.google.com',
|
||||
'workspace.google.com',
|
||||
'oauth2.googleapis.com',
|
||||
'www.googleapis.com']
|
||||
fix_hosts = {'calendar-json.googleapis.com': 'www.googleapis.com',
|
||||
'storage-api.googleapis.com': 'storage.googleapis.com'}
|
||||
api_hosts = ['apps-apis.google.com',
|
||||
'sites.google.com',
|
||||
'versionhistory.googleapis.com',
|
||||
'www.google.com']
|
||||
for host in API.PROJECT_APIS:
|
||||
host = fix_hosts.get(host, host)
|
||||
if host not in api_hosts and host not in hosts:
|
||||
api_hosts.append(host)
|
||||
hosts.extend(sorted(api_hosts))
|
||||
host_count = len(hosts)
|
||||
httpObj = getHttpObj(timeout=30)
|
||||
httpObj.follow_redirects = False
|
||||
headers = {'user-agent': GAM_USER_AGENT}
|
||||
okay = createGreenText('OK')
|
||||
not_okay = createRedText('ERROR')
|
||||
try_count = 0
|
||||
success_count = 0
|
||||
for host in hosts:
|
||||
|
||||
def check_host(host):
|
||||
nonlocal try_count, okay, not_okay, success_count
|
||||
try_count += 1
|
||||
dns_err = None
|
||||
ip = 'unknown'
|
||||
@@ -9393,12 +9372,12 @@ def doCheckConnection():
|
||||
dns_err = f'{not_okay}\n DNS failure: {str(e)}\n'
|
||||
except Exception as e:
|
||||
dns_err = f'{not_okay}\n Unknown DNS failure: {str(e)}\n'
|
||||
check_line = f'Checking {host} ({ip}) ({try_count}/{host_count})...'
|
||||
check_line = f'Checking {host} ({ip}) ({try_count})...'
|
||||
writeStdout(f'{check_line:<100}')
|
||||
flushStdout()
|
||||
if dns_err:
|
||||
writeStdout(dns_err)
|
||||
continue
|
||||
return
|
||||
gen_firewall = 'You probably have security software or a firewall on your machine or network that is preventing GAM from making Internet connections. Check your network configuration or try running GAM on a hotspot or home network to see if the problem exists only on your organization\'s network.'
|
||||
try:
|
||||
if host.startswith('http'):
|
||||
@@ -9427,7 +9406,54 @@ def doCheckConnection():
|
||||
writeStdout(f'{not_okay}\n Timed out trying to connect to host\n')
|
||||
except Exception as e:
|
||||
writeStdout(f'{not_okay}\n {str(e)}\n')
|
||||
if success_count == host_count:
|
||||
|
||||
try_count = 0
|
||||
httpObj = getHttpObj(timeout=30)
|
||||
httpObj.follow_redirects = False
|
||||
headers = {'user-agent': GAM_USER_AGENT}
|
||||
okay = createGreenText('OK')
|
||||
not_okay = createRedText('ERROR')
|
||||
success_count = 0
|
||||
initial_hosts = ['api.github.com',
|
||||
'raw.githubusercontent.com',
|
||||
'accounts.google.com',
|
||||
'oauth2.googleapis.com',
|
||||
'www.googleapis.com']
|
||||
for host in initial_hosts:
|
||||
check_host(host)
|
||||
api_hosts = ['apps-apis.google.com',
|
||||
'www.google.com']
|
||||
for host in api_hosts:
|
||||
check_host(host)
|
||||
# For v2 discovery APIs, GAM gets discovery file from <api>.googleapis.com so
|
||||
# add those domains.
|
||||
disc_hosts = []
|
||||
for api, config in API._INFO.items():
|
||||
if config.get('v2discovery') and not config.get('localdiscovery'):
|
||||
if mapped_api := config.get('mappedAPI'):
|
||||
api = mapped_api
|
||||
host = f'{api}.googleapis.com'
|
||||
if host not in disc_hosts:
|
||||
disc_hosts.append(host)
|
||||
for host in disc_hosts:
|
||||
check_host(host)
|
||||
checked_hosts = initial_hosts + api_hosts + disc_hosts
|
||||
# now we need to "build" each API and check it's base URL host
|
||||
# if we haven't already. This may not be any hosts at all but
|
||||
# to ensure we are checking all hosts GAM may use we should
|
||||
# keep this.
|
||||
for api in API._INFO:
|
||||
if api in [API.CONTACTS, API.EMAIL_AUDIT]:
|
||||
continue
|
||||
svc = getService(api, httpObj)
|
||||
base_url = svc._rootDesc.get('baseUrl')
|
||||
parsed_base_url = urlparse(base_url)
|
||||
base_host = parsed_base_url.netloc
|
||||
if base_host not in checked_hosts:
|
||||
print(f'checking {base_host} for {api}')
|
||||
check_host(base_host)
|
||||
checked_hosts.append(base_host)
|
||||
if success_count == try_count:
|
||||
writeStdout(createGreenText('All hosts passed!\n'))
|
||||
else:
|
||||
systemErrorExit(3, createYellowText('Some hosts failed to connect! Please follow the recommendations for those hosts to correct any issues and try again.'))
|
||||
@@ -11384,25 +11410,26 @@ def _waitForSvcAcctCompletion(i):
|
||||
sys.stdout.write(Msg.WAITING_FOR_ITEM_CREATION_TO_COMPLETE_SLEEPING.format(Ent.Singular(Ent.SVCACCT), sleep_time))
|
||||
time.sleep(sleep_time)
|
||||
|
||||
def _grantRotateRights(iam, projectId, service_account, email, account_type='serviceAccount'):
|
||||
def _grantRotateRights(iam, projectId, service_account, account_type='serviceAccount'):
|
||||
body = {'policy': {'bindings': [{'role': 'roles/iam.serviceAccountKeyAdmin',
|
||||
'members': [f'{account_type}:{email}']}]}}
|
||||
'members': [f'{account_type}:{service_account}']}]}}
|
||||
maxRetries = 10
|
||||
printEntityMessage([Ent.PROJECT, projectId, Ent.SVCACCT, email],
|
||||
Msg.HAS_RIGHTS_TO_ROTATE_OWN_PRIVATE_KEY.format(email, service_account))
|
||||
kvList = [Ent.PROJECT, projectId, Ent.SVCACCT, service_account]
|
||||
printEntityMessage(kvList, Msg.GRANTING_RIGHTS_TO_ROTATE_ITS_OWN_PRIVATE_KEY.format('Granting'))
|
||||
for retry in range(1, maxRetries+1):
|
||||
try:
|
||||
callGAPI(iam.projects().serviceAccounts(), 'setIamPolicy',
|
||||
throwReasons=[GAPI.INVALID_ARGUMENT],
|
||||
resource=f'projects/{projectId}/serviceAccounts/{service_account}', body=body)
|
||||
printEntityMessage(kvList, Msg.GRANTING_RIGHTS_TO_ROTATE_ITS_OWN_PRIVATE_KEY.format('Granted'))
|
||||
return True
|
||||
except GAPI.invalidArgument as e:
|
||||
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, service_account], str(e))
|
||||
entityActionFailedWarning(kvList, str(e))
|
||||
if 'does not exist' not in str(e) or retry == maxRetries:
|
||||
return False
|
||||
_waitForSvcAcctCompletion(retry)
|
||||
except Exception as e:
|
||||
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, service_account], str(e))
|
||||
entityActionFailedWarning(kvList, str(e))
|
||||
return False
|
||||
|
||||
def _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key=True):
|
||||
@@ -11420,6 +11447,7 @@ def _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key=True)
|
||||
return False
|
||||
except GAPI.alreadyExists as e:
|
||||
entityActionFailedWarning([Ent.PROJECT, projectInfo['projectId'], Ent.SVCACCT, svcAcctInfo['name']], str(e))
|
||||
writeStderr(Msg.RERUN_THE_COMMAND_AND_SPECIFY_A_NEW_SANAME)
|
||||
return False
|
||||
GM.Globals[GM.SVCACCT_SCOPES_DEFINED] = False
|
||||
if create_key and not doProcessSvcAcctKeys(mode='retainexisting', iam=iam,
|
||||
@@ -11428,7 +11456,7 @@ def _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key=True)
|
||||
clientId=service_account['uniqueId']):
|
||||
return False
|
||||
sa_email = service_account['name'].rsplit('/', 1)[-1]
|
||||
return _grantRotateRights(iam, projectInfo['projectId'], sa_email, sa_email)
|
||||
return _grantRotateRights(iam, projectInfo['projectId'], sa_email)
|
||||
|
||||
def _createClientSecretsOauth2service(httpObj, login_hint, appInfo, projectInfo, svcAcctInfo, create_key=True):
|
||||
def _checkClientAndSecret(csHttpObj, client_id, client_secret):
|
||||
@@ -11921,9 +11949,7 @@ def doUpdateProject():
|
||||
continue
|
||||
iam = getAPIService(API.IAM, httpObj)
|
||||
_getSvcAcctData() # needed to read in GM.OAUTH2SERVICE_JSON_DATA
|
||||
_grantRotateRights(iam, projectId,
|
||||
GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['client_email'],
|
||||
GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['client_email'])
|
||||
_grantRotateRights(iam, projectId, GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['client_email'])
|
||||
Ind.Decrement()
|
||||
|
||||
# gam delete project [[admin] <EmailAddress>] [<ProjectIDEntity>]
|
||||
@@ -12786,7 +12812,7 @@ def doUploadSvcAcctKeys():
|
||||
iam = getAPIService(API.IAM, httpObj)
|
||||
if doProcessSvcAcctKeys(mode='upload', iam=iam):
|
||||
sa_email = GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['client_email']
|
||||
_grantRotateRights(iam, GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['project_id'], sa_email, sa_email)
|
||||
_grantRotateRights(iam, GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['project_id'], sa_email)
|
||||
sys.stdout.write(Msg.YOUR_GAM_PROJECT_IS_CREATED_AND_READY_TO_USE)
|
||||
|
||||
# gam delete sakeys <ServiceAccountKeyList>
|
||||
@@ -13491,6 +13517,8 @@ REPORT_CHOICE_MAP = {
|
||||
'drive': 'drive',
|
||||
'enterprisegroups': 'groups_enterprise',
|
||||
'gcp': 'gcp',
|
||||
'gemini': 'gemini_for_workspace',
|
||||
'geminiforworkspace': 'gemini_for_workspace',
|
||||
'gplus': 'gplus',
|
||||
'google+': 'gplus',
|
||||
'group': 'groups',
|
||||
@@ -13788,6 +13816,20 @@ def doReport():
|
||||
csvPF.WriteRow(row)
|
||||
return (True, lastDate)
|
||||
|
||||
# dynamically extend our choices with other reports Google dynamically adds
|
||||
rep = buildGAPIObject(API.REPORTS)
|
||||
dyn_choices = rep._rootDesc \
|
||||
.get('resources', {}) \
|
||||
.get('activities', {}) \
|
||||
.get('methods', {}) \
|
||||
.get('list', {}) \
|
||||
.get('parameters', {}) \
|
||||
.get('applicationName', {}) \
|
||||
.get('enum', [])
|
||||
for dyn_choice in dyn_choices:
|
||||
if dyn_choice.replace('_', '') not in REPORT_CHOICE_MAP and \
|
||||
dyn_choice not in REPORT_CHOICE_MAP.values():
|
||||
REPORT_CHOICE_MAP[dyn_choice.replace('_', '')] = dyn_choice
|
||||
report = getChoice(REPORT_CHOICE_MAP, mapChoice=True)
|
||||
if report == 'usage':
|
||||
doReportUsage()
|
||||
@@ -13795,7 +13837,6 @@ def doReport():
|
||||
if report == 'usageparameters':
|
||||
doReportUsageParameters()
|
||||
return
|
||||
rep = buildGAPIObject(API.REPORTS)
|
||||
customerId = GC.Values[GC.CUSTOMER_ID]
|
||||
if customerId == GC.MY_CUSTOMER:
|
||||
customerId = None
|
||||
@@ -34164,7 +34205,8 @@ def getGroupMembers(cd, groupEmail, memberRoles, membersList, membersSet, i, cou
|
||||
elif memberOptions[MEMBEROPTION_NODUPLICATES]:
|
||||
groupMemberList = []
|
||||
for member in groupMembers:
|
||||
if member['type'] != Ent.TYPE_GROUP:
|
||||
namespace = member['email'].find('@') == -1
|
||||
if member['type'] != Ent.TYPE_GROUP or namespace:
|
||||
if ((member['type'] in typesSet and
|
||||
checkMemberMatch(member, memberOptions) and
|
||||
_checkMemberRoleIsSuspendedIsArchived(member, validRoles, memberOptions[MEMBEROPTION_ISSUSPENDED], memberOptions[MEMBEROPTION_ISARCHIVED]) and
|
||||
@@ -34193,7 +34235,8 @@ def getGroupMembers(cd, groupEmail, memberRoles, membersList, membersSet, i, cou
|
||||
memberOptions, memberDisplayOptions, level+1, typesSet)
|
||||
else:
|
||||
for member in groupMembers:
|
||||
if member['type'] != Ent.TYPE_GROUP:
|
||||
namespace = member['email'].find('@') == -1
|
||||
if member['type'] != Ent.TYPE_GROUP or namespace:
|
||||
if ((member['type'] in typesSet) and
|
||||
checkMemberMatch(member, memberOptions) and
|
||||
_checkMemberRoleIsSuspendedIsArchived(member, validRoles,
|
||||
@@ -36292,7 +36335,8 @@ def getCIGroupMembers(ci, groupName, memberRoles, membersList, membersSet, i, co
|
||||
for member in groupMembers:
|
||||
getCIGroupMemberRoleFixType(member)
|
||||
memberName = member.get('preferredMemberKey', {}).get('id', '')
|
||||
if member['type'] != Ent.TYPE_GROUP:
|
||||
namespace = member.get('preferredMemberKey', {}).get('namespace', '')
|
||||
if member['type'] != Ent.TYPE_GROUP or namespace:
|
||||
if (member['type'] in typesSet and
|
||||
checkCIMemberMatch(member, memberOptions) and
|
||||
_checkMemberRole(member, validRoles) and
|
||||
@@ -36320,7 +36364,8 @@ def getCIGroupMembers(ci, groupName, memberRoles, membersList, membersSet, i, co
|
||||
for member in groupMembers:
|
||||
getCIGroupMemberRoleFixType(member)
|
||||
memberName = member.get('preferredMemberKey', {}).get('id', '')
|
||||
if member['type'] != Ent.TYPE_GROUP:
|
||||
namespace = member.get('preferredMemberKey', {}).get('namespace', '')
|
||||
if member['type'] != Ent.TYPE_GROUP or namespace:
|
||||
if (member['type'] in typesSet and
|
||||
checkCIMemberMatch(member, memberOptions) and
|
||||
_checkMemberRole(member, validRoles) and
|
||||
|
||||
@@ -244,7 +244,7 @@ _INFO = {
|
||||
EMAIL_AUDIT: {'name': 'Email Audit API', 'version': 'v1', 'v2discovery': False},
|
||||
FORMS: {'name': 'Forms API', 'version': 'v1', 'v2discovery': True},
|
||||
GMAIL: {'name': 'Gmail API', 'version': 'v1', 'v2discovery': True},
|
||||
GROUPSMIGRATION: {'name': 'Groups Migration API', 'version': 'v1', 'v2discovery': False},
|
||||
GROUPSMIGRATION: {'name': 'Groups Migration API', 'version': 'v1', 'v2discovery': True},
|
||||
GROUPSSETTINGS: {'name': 'Groups Settings API', 'version': 'v1', 'v2discovery': True},
|
||||
IAM: {'name': 'Identity and Access Management API', 'version': 'v1', 'v2discovery': True},
|
||||
IAM_CREDENTIALS: {'name': 'Identity and Access Management Credentials API', 'version': 'v1', 'v2discovery': True},
|
||||
|
||||
@@ -72,7 +72,7 @@ Please go to:
|
||||
24. Paste it at the "Enter your Client Secret: " prompt in your terminal
|
||||
25. Press return/enter in your terminal
|
||||
26. Switch back to the browser
|
||||
27. Click "CANCEL"
|
||||
27. Click "OK"
|
||||
28. These steps are complete
|
||||
'''
|
||||
ENTER_YOUR_CLIENT_ID = '\nEnter your Client ID: '
|
||||
@@ -287,6 +287,7 @@ GAM_OUT_OF_MEMORY = 'GAM has run out of memory. If this is a large Google Worksp
|
||||
GENERATING_NEW_PRIVATE_KEY = 'Generating new private key'
|
||||
GETTING = 'Getting'
|
||||
GETTING_ALL = 'Getting all'
|
||||
GRANTING_RIGHTS_TO_ROTATE_ITS_OWN_PRIVATE_KEY = '{0} rights to rotate its own private key'
|
||||
GOOGLE_DELEGATION_ERROR = 'Google delegation error, delegator and delegate both exist and are valid for delegation'
|
||||
GOT = 'Got'
|
||||
GROUP_MAPS_TO_MULTIPLE_OUS = 'File: {0}, Group: {1} references multiple OUs: {2}'
|
||||
@@ -294,13 +295,12 @@ GROUP_MAPS_TO_OU_INVALID_ROW = 'File: {0}, Invalid row, must contain non-blank <
|
||||
GUARDIAN_INVITATION_STATUS_NOT_PENDING = 'Guardian invitation status is not PENDING'
|
||||
HAS_CHILD_ORGS = 'Has child {0}'
|
||||
HAS_INVALID_FORMAT = '{0}: {1}, Has invalid format'
|
||||
HAS_RIGHTS_TO_ROTATE_OWN_PRIVATE_KEY = 'Giving account {0} rights to rotate {1} private key'
|
||||
HEADER_NOT_FOUND_IN_CSV_HEADERS = 'Header "{0}" not found in CSV headers of "{1}".'
|
||||
HELP_SYNTAX = 'Help: Syntax in file {0}\n'
|
||||
HELP_WIKI = 'Help: Documentation is at {0}\n'
|
||||
IGNORED = 'Ignored'
|
||||
INSTRUCTIONS_CLIENT_SECRETS_JSON = 'Please run\n\ngam create|use project\ngam oauth create\n\nto create and authorize a Client account.\n'
|
||||
INSTRUCTIONS_OAUTH2SERVICE_JSON = 'Please run\n\ngam create|use project\ngam user <user> check serviceaccount\n\nto create and authorize a Service account.\n'
|
||||
INSTRUCTIONS_OAUTH2SERVICE_JSON = 'Please run\n\ngam create|use project\ngam user <user> update serviceaccount\n\nto create and authorize a Service account.\n'
|
||||
INSUFFICIENT_PERMISSIONS_TO_PERFORM_TASK = 'Insufficient permissions to perform this task'
|
||||
INTER_BATCH_WAIT_INCREASED = 'inter_batch_wait increased to {0:.2f}'
|
||||
INVALID = 'Invalid'
|
||||
@@ -468,6 +468,10 @@ REFUSING_TO_DEPROVISION_DEVICES = 'Refusing to deprovision {0} devices because a
|
||||
REPLY_TO_CUSTOM_REQUIRES_EMAIL_ADDRESS = 'replyto REPLY_TO_CUSTOM requires customReplyTo <EmailAddress>'
|
||||
REQUEST_COMPLETED_NO_FILES = 'Request completed but no results/files were returned, try requesting again'
|
||||
REQUEST_NOT_COMPLETE = 'Request needs to be completed before downloading, current status is: {0}'
|
||||
RERUN_THE_COMMAND_AND_SPECIFY_A_NEW_SANAME = """
|
||||
Re-run the command specify a new service account name with: saname <ServiceAccountName>
|
||||
See: https://github.com/GAM-team/GAM/wiki/Authorization#advanced-use
|
||||
"""
|
||||
RESOURCE_CAPACITY_FLOOR_REQUIRED = 'Options "capacity <Number>" (<Number> > 0) and "floor <String>" required'
|
||||
RESOURCE_FLOOR_REQUIRED = 'Option "floor <String>" required'
|
||||
RESULTS_TOO_LARGE_FOR_GOOGLE_SPREADSHEET = 'Results are too large for Google Spreadsheets. Uploading as a regular CSV file.'
|
||||
|
||||
@@ -144,6 +144,8 @@ _SKUS = {
|
||||
'product': 'Google-Apps', 'aliases': ['wsflw', 'workspacefrontline', 'workspacefrontlineworker'], 'displayName': 'Google Workspace Frontline Starter'},
|
||||
'1010020031': {
|
||||
'product': 'Google-Apps', 'aliases': ['wsflwstan', 'workspacefrontlinestan', 'workspacefrontlineworkerstan'], 'displayName': 'Google Workspace Frontline Standard'},
|
||||
'1010020034': {
|
||||
'product': 'Google-Apps', 'aliases': ['wsflwplus', 'workspacefrontlineplus', 'workspacefrontlineworkerplus'], 'displayName': 'Google Workspace Frontline Plus'},
|
||||
'1010340001': {
|
||||
'product': '101034', 'aliases': ['gseau', 'enterprisearchived', 'gsuiteenterprisearchived'], 'displayName': 'Google Workspace Enterprise Plus - Archived User'},
|
||||
'1010340002': {
|
||||
|
||||
@@ -20,14 +20,19 @@
|
||||
|
||||
"""
|
||||
|
||||
GAM_VER_LIBS = ['cryptography',
|
||||
'filelock',
|
||||
'google-api-python-client',
|
||||
'google-auth-httplib2',
|
||||
'google-auth-oauthlib',
|
||||
'google-auth',
|
||||
'httplib2',
|
||||
'passlib',
|
||||
'python-dateutil',
|
||||
'yubikey-manager',
|
||||
]
|
||||
GAM_VER_LIBS = [
|
||||
'chardet',
|
||||
'cryptography',
|
||||
'filelock',
|
||||
'google-api-python-client',
|
||||
'google-auth-httplib2',
|
||||
'google-auth-oauthlib',
|
||||
'google-auth',
|
||||
'lxml',
|
||||
'httplib2',
|
||||
'passlib',
|
||||
'pathvalidate',
|
||||
'pyscard',
|
||||
'python-dateutil',
|
||||
'yubikey-manager',
|
||||
]
|
||||
|
||||
BIN
src/license.rtf
BIN
src/license.rtf
Binary file not shown.
@@ -1,14 +1,15 @@
|
||||
chardet
|
||||
cryptography
|
||||
chardet>=5.2.0
|
||||
cryptography>=44.0.2
|
||||
distro; sys_platform=='linux'
|
||||
filelock
|
||||
google-api-python-client>=2.166.0
|
||||
filelock>=3.18.0
|
||||
google-api-python-client>=2.167.0
|
||||
google-auth-httplib2>=0.2.0
|
||||
google-auth-oauthlib>=1.2.1
|
||||
google-auth>=2.38.0
|
||||
google-auth-oauthlib>=1.2.2
|
||||
google-auth>=2.39.0
|
||||
httplib2>=0.22.0
|
||||
lxml
|
||||
lxml>=5.4.0
|
||||
passlib>=1.7.4
|
||||
pathvalidate
|
||||
pathvalidate>=3.2.3
|
||||
pyscard==2.2.1
|
||||
python-dateutil
|
||||
yubikey-manager[yubikey]>=5.6.1
|
||||
yubikey-manager>=5.6.1
|
||||
|
||||
@@ -17,26 +17,29 @@ classifiers =
|
||||
Programming Language :: Python :: 3.10
|
||||
Programming Language :: Python :: 3.11
|
||||
Programming Language :: Python :: 3.12
|
||||
Programming Language :: Python :: 3.13
|
||||
License :: OSI Approved :: Apache License
|
||||
|
||||
[options]
|
||||
packages = find:
|
||||
python_requires = >= 3.8
|
||||
python_requires = >= 3.9
|
||||
# The following files should be edited to match: pyproject.toml, requirements.txt
|
||||
install_requires =
|
||||
chardet
|
||||
cryptography
|
||||
chardet >= 5.2.0
|
||||
cryptography >= 44.0.2
|
||||
distro; sys_platform == 'linux'
|
||||
filelock
|
||||
google-api-python-client >= 2.36
|
||||
google-auth-httplib2
|
||||
google-auth-oauthlib >= 0.4.6
|
||||
google-auth >= 2.3.3
|
||||
httplib2 >= 0.20.2
|
||||
lxml
|
||||
filelock >= 3.18.0
|
||||
google-api-python-client >= 2.167.0
|
||||
google-auth-httplib2 >= 0.2.0
|
||||
google-auth-oauthlib >= 1.2.2
|
||||
google-auth >= 2.39.0
|
||||
httplib2 >= 0.22.0
|
||||
lxml >= 5.4.0
|
||||
passlib >= 1.7.4
|
||||
pathvalidate
|
||||
pathvalidate >= 3.2.3
|
||||
pyscard == 2.2.1
|
||||
python-dateutil
|
||||
yubikey-manager >= 5.0
|
||||
yubikey-manager >= 5.6.1
|
||||
|
||||
[options.package_data]
|
||||
* = *.pem
|
||||
|
||||
@@ -24,18 +24,19 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
|
||||
- Start a terminal session.
|
||||
|
||||
* Executable Archive, Manual, Raspberry Pi/ChromeOS ARM devices
|
||||
- `gam-7.wx.yz-linux-aarch64-glibc2.35.tar.xz`
|
||||
- `gam-7.wx.yz-linux-aarch64-legacy.tar.xz`
|
||||
- `gam-7.wx.yz-linux-arm64-glibc2.35.tar.xz`
|
||||
- `gam-7.wx.yz-linux-arm64-glibc2.39.tar.xz`
|
||||
- `gam-7.wx.yz-linux-arm64-legacy.tar.xz`
|
||||
- Download the archive, extract the contents into some directory.
|
||||
- Start a terminal session.
|
||||
|
||||
* Executable Archive, Manual, Mac OS versions Sonoma, Sequoia - M1/M2
|
||||
- `gam-7.wx.yz-macos14.7-aarch64.tar.xz`
|
||||
- `gam-7.wx.yz-macos14.7-arm64.tar.xz`
|
||||
- Download the archive, extract the contents into some directory.
|
||||
- Start a terminal session.
|
||||
|
||||
* Executable Archive, Manual, Mac OS versions Sequoia - M3
|
||||
- `gam-7.wx.yz-macos15.2-aarch64.tar.xz`
|
||||
- `gam-7.wx.yz-macos15.4-arm64.tar.xz`
|
||||
- Download the archive, extract the contents into some directory.
|
||||
- Start a terminal session.
|
||||
|
||||
@@ -54,6 +55,16 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
|
||||
- Download the installer and run it.
|
||||
- Start a Command Prompt/PowerShell session.
|
||||
|
||||
* Executable Archive, Manual, Windows 11 ARM
|
||||
- `gam-7.wx.yz-windows-arm64.zip`
|
||||
- Download the archive, extract the contents into some directory.
|
||||
- Start a Command Prompt/PowerShell session.
|
||||
|
||||
* Executable Installer, Manual, Windows 11 ARM
|
||||
- `gam-7.wx.yz-windows-arm64.msi`
|
||||
- Download the installer and run it.
|
||||
- Start a Command Prompt/PowerShell session.
|
||||
|
||||
* Source, all platforms
|
||||
- `Source code(zip)`
|
||||
- `Source code(tar.gz)`
|
||||
|
||||
@@ -10,6 +10,47 @@ 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.06.11
|
||||
|
||||
Improved `gam checkconn`.
|
||||
|
||||
Updated `gam print group-members` and `gam print cigroup-members` to recognize members
|
||||
that are groups representing chat spaces. For now, these groups are not expanded when
|
||||
`recursive` is specified.
|
||||
|
||||
### 7.06.10
|
||||
|
||||
Added the following license SKU.
|
||||
```
|
||||
1010020034 - Google Workspace Frontline Plus
|
||||
```
|
||||
|
||||
### 7.06.09
|
||||
|
||||
Added `gemini` and `geminiforworkspace` to `<ActivityApplicationName>` for use in
|
||||
`gam report <ActivityApplicationName>`.
|
||||
|
||||
### 7.06.08
|
||||
|
||||
Fixed problem where Yubikeys caused a trap.
|
||||
|
||||
### 7.06.07
|
||||
|
||||
Updated private key rotation progress messages in `gam create|use|update project`
|
||||
and `gam upload sakey`.
|
||||
|
||||
Updated `gam use project` to display the following error message when the specifed project
|
||||
already has a service account.
|
||||
```
|
||||
Re-run the command specify a new service account name with: saname <ServiceAccountName>'
|
||||
```
|
||||
|
||||
### 7.06.06
|
||||
|
||||
Native support for Windows 11 Arm-based devices.
|
||||
|
||||
Renamed some MacOS and Linux binary installer files to align on terminology. Everything is "arm64" now, no "aarch64".
|
||||
|
||||
### 7.06.05
|
||||
|
||||
Updated code in `gam delete|update chromepolicy` to handle the `policyTargetKey[additionalTargetKeys]`
|
||||
|
||||
@@ -251,7 +251,7 @@ writes the credentials into the file oauth2.txt.
|
||||
admin@server:/Users/admin$ rm -f /Users/admin/GAMConfig/oauth2.txt
|
||||
admin@server:/Users/admin$ gam version
|
||||
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
|
||||
GAM 7.06.05 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.06.11 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.3 64-bit final
|
||||
MacOS Sequoia 15.4.1 x86_64
|
||||
@@ -989,7 +989,7 @@ writes the credentials into the file oauth2.txt.
|
||||
C:\>del C:\GAMConfig\oauth2.txt
|
||||
C:\>gam version
|
||||
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
|
||||
GAM 7.06.05 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM 7.06.11 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.3 64-bit final
|
||||
Windows-10-10.0.17134 AMD64
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
| Google Workspace for Education: Teaching and Learning Upgrade | 1010370001 | gwetlu |
|
||||
| Google Workspace Frontline Starter | 1010020030 | wsflw |
|
||||
| Google Workspace Frontline Standard | 1010020031 | wsflwstan |
|
||||
| Google Workspace Frontline Plus | 1010020034 | wsflwplus |
|
||||
| Google Workspace Government | Google-Apps-For-Government | gsuitegov |
|
||||
| Google Workspace Labs | 1010470002 | gwlabs | workspacelabs |
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ config csv_output_row_filter "'\"accounts:used_quota_in_mb\":count>15000'"
|
||||
domain|
|
||||
drive|doc|docs|
|
||||
gcp|
|
||||
gemini|geminiforworkspace|
|
||||
groups|group|
|
||||
groupsenterprise|enterprisegroups|
|
||||
jamboard|
|
||||
|
||||
@@ -42,12 +42,12 @@ Google requires that you have a Chat Bot configured in order to use the Chat API
|
||||
|
||||
## Set up a Chat Bot
|
||||
|
||||
* Run the command `gam setup chat`; it will point you to a URL to configure your Chat Bot; this is required to use the Chat API.
|
||||
* Run the command `gam setup chat`; it will point you to a URL to configure your Chat Bot.
|
||||
* Enter an App name and Description of your choosing.
|
||||
* For the Avatar URL you can use `https://dummyimage.com/384x256/4d4d4d/0011ff.png&text=+GAM` or a public URL to an image of your own choosing.
|
||||
* In Functionality, uncheck both "Receive 1:1 messages" and "Join spaces and group conversations"
|
||||
* In Connection settings, choose "Cloud Pub/Sub" and enter "no-topic" for the topic name. GAM doesn't yet listen to pub/sub so this option is not used.
|
||||
* In Visibility, uncheck "Make this Chat app available to specific people and groups in Domain Workspace".
|
||||
* In Connection settings, choose "Cloud Pub/Sub" and enter `projects/<ProjectID>/topics/no-topic` for the topic name. Replace `<ProjectID>` with your GAM project ID. GAM doesn't yet listen to pub/sub so this option is not used.
|
||||
* In Visibility, uncheck "Make this Chat app available to specific people and groups in Domain Workspace".
|
||||
* Click Save.
|
||||
|
||||
## API documentation
|
||||
|
||||
@@ -4,7 +4,7 @@ k
|
||||
Print the current version of Gam with details
|
||||
```
|
||||
gam version
|
||||
GAM 7.06.05 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.06.11 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.3 64-bit final
|
||||
MacOS Sequoia 15.4.1 x86_64
|
||||
@@ -16,7 +16,7 @@ Time: 2023-06-02T21:10:00-07:00
|
||||
Print the current version of Gam with details and time offset information
|
||||
```
|
||||
gam version timeoffset
|
||||
GAM 7.06.05 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.06.11 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.3 64-bit final
|
||||
MacOS Sequoia 15.4.1 x86_64
|
||||
@@ -28,7 +28,7 @@ Your system time differs from www.googleapis.com by less than 1 second
|
||||
Print the current version of Gam with extended details and SSL information
|
||||
```
|
||||
gam version extended
|
||||
GAM 7.06.05 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.06.11 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.3 64-bit final
|
||||
MacOS Sequoia 15.4.1 x86_64
|
||||
@@ -65,7 +65,7 @@ MacOS High Sierra 10.13.6 x86_64
|
||||
Path: /Users/Admin/bin/gam7
|
||||
Version Check:
|
||||
Current: 5.35.08
|
||||
Latest: 7.06.05
|
||||
Latest: 7.06.11
|
||||
echo $?
|
||||
1
|
||||
```
|
||||
@@ -73,7 +73,7 @@ echo $?
|
||||
Print the current version number without details
|
||||
```
|
||||
gam version simple
|
||||
7.06.05
|
||||
7.06.11
|
||||
```
|
||||
In Linux/MacOS you can do:
|
||||
```
|
||||
@@ -83,7 +83,7 @@ echo $VER
|
||||
Print the current version of Gam and address of this Wiki
|
||||
```
|
||||
gam help
|
||||
GAM 7.06.05 - https://github.com/GAM-team/GAM
|
||||
GAM 7.06.11 - https://github.com/GAM-team/GAM
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.3 64-bit final
|
||||
MacOS Sequoia 15.4.1 x86_64
|
||||
|
||||
Reference in New Issue
Block a user