Compare commits

...

40 Commits

Author SHA1 Message Date
Jay Lee
e4af5e6126 [no ci] Enhance build workflow with custom cryptography wheels
Added conditional installation for custom cryptography wheels on macOS and Windows ARM64.
2026-06-27 15:23:10 -04:00
Jay Lee
6e296e0f2d Clean up build.yml by removing ykman hack
Removed workaround for ykman cryptography dependency.
2026-06-27 15:16:07 -04:00
github-actions[bot]
4b2e14c2d5 chore: upgrade PyPi deps (#1933)
Co-authored-by: jay0lee <4623536+jay0lee@users.noreply.github.com>
2026-06-27 15:13:30 -04:00
Jay Lee
eb59663f6a [no ci] Enhance upgrade_deps.yml with comments and cleanup
Updated comments for clarity and added cleanup for resolved.txt.
2026-06-27 15:10:29 -04:00
Jay Lee
d12289c4f4 [no ci] Add uv installation and enhance dependency resolution
This update adds a step to install the 'uv' package and modifies the dependency resolution process to handle mutually compatible package versions. It also updates the commit message body for clarity.
2026-06-27 15:06:38 -04:00
Jay Lee
738ff3e7fb Modify ykman installation to remove cryptography constraint
Updated the build workflow to patch the ykman METADATA file for cryptography dependency.
2026-06-27 14:51:37 -04:00
Jay Lee
789e543b3f Fix yubikey-manager installation and cryptography dependency
Updated yubikey-manager installation to use version 5.9.1 and modified cryptography dependency handling.
2026-06-27 14:34:01 -04:00
Jay Lee
4e933f4485 Modify yubikey installation commands in build.yml
Updated installation commands for yubikey-manager and dependencies.
2026-06-27 14:11:37 -04:00
Jay Lee
a99f23ce40 Refactor pip installation steps in build workflow
Commented out pip upgrade commands and adjusted yubikey installation.
2026-06-27 14:09:10 -04:00
github-actions[bot]
5462c0359e chore: upgrade PyPi deps (#1931)
Co-authored-by: jay0lee <4623536+jay0lee@users.noreply.github.com>
2026-06-27 14:06:15 -04:00
Jay Lee
0c143414a8 Delete dep-overrides.txt 2026-06-27 14:01:08 -04:00
Jay Lee
bebcfb7c44 Update dependency overrides in dep-overrides.txt 2026-06-27 13:58:00 -04:00
Jay Lee
18ce64886d Modify yubikey-manager installation command
Update yubikey-manager installation to avoid dependency installation.
2026-06-27 13:32:54 -04:00
Jay Lee
db87aa54d8 Update yubikey-manager installation to version 5.9.1
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
Build and test GAM / build (false, test, 19, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 20, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Specify version for yubikey-manager installation
2026-06-27 13:28:14 -04:00
Jay Lee
1867af9366 [actions] Comment out yubikey upgrade command in build.yml
Comment out the upgrade command for yubikey dependency and add note about future upgrade.
2026-06-27 13:18:54 -04:00
github-actions[bot]
e1f2bedd7c chore: upgrade PyPi deps (#1930)
Co-authored-by: jay0lee <4623536+jay0lee@users.noreply.github.com>
2026-06-27 13:01:09 -04:00
Ross Scroggs
8735021c9b Update Vault API error handling 2026-06-27 09:16:54 -07:00
Ross Scroggs
2860ae02a2 Update Users-People-Contacts-Profiles.md
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
2026-06-26 19:26:16 -07:00
github-actions[bot]
31b4b70f0f chore: upgrade PyPi deps (#1929)
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
Build and test GAM / build (false, test, 19, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 20, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Daily Dependency Pinning (2-Week Buffer) / pin-deps (push) Has been cancelled
Co-authored-by: jay0lee <4623536+jay0lee@users.noreply.github.com>
2026-06-25 05:09:11 -04:00
Jay Lee
1c8bf44867 Update checkout action to version 7.0.0
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
Build and test GAM / build (false, test, 19, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 20, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Daily Dependency Pinning (2-Week Buffer) / pin-deps (push) Has been cancelled
2026-06-23 11:33:08 -04:00
Jay Lee
472905d6c0 [no ci] Update checkout action to version 7.0.0 2026-06-23 11:32:46 -04:00
Jay Lee
bed9b5e1b6 [no ci] Update checkout action version in pushwiki.yml 2026-06-23 11:32:19 -04:00
Jay Lee
c8521c6307 [no ci] Update checkout action to version 7.0.0 2026-06-23 11:31:48 -04:00
Jay Lee
870a3149d8 [no ci] Upgrade actions/checkout to version 7.0.0
Updated checkout action version from v5.0.0 to v7.0.0.
2026-06-23 11:31:07 -04:00
Jay Lee
8622ae6c0f Upgrade actions/checkout to version 7.0.0
Updated checkout action version from v6.0.2 to v7.0.0 in build workflows.
2026-06-23 11:30:33 -04:00
Jay Lee
c92468276a [actions] reduce pip verbosity
Remove verbose flag from pip install command for yubikey.
2026-06-23 05:25:54 -04:00
dependabot[bot]
d80b93b86e Bump cryptography in the pip group across 1 directory (#1926)
Bumps the pip group with 1 update in the / directory: [cryptography](https://github.com/pyca/cryptography).


Updates `cryptography` from 48.0.0 to 48.0.1
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/48.0.0...48.0.1)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 48.0.1
  dependency-type: direct:production
  dependency-group: pip
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 04:53:05 -04:00
Ross Scroggs
2d26fa6004 Update GamUpdates.md
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
Build and test GAM / build (false, test, 19, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 20, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Daily Dependency Pinning (2-Week Buffer) / pin-deps (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
2026-06-19 08:10:22 -07:00
Ross Scroggs
a09a98e3ae Updated gam <UserTypeEntity> show calsettings 2026-06-19 08:00:34 -07:00
Ross Scroggs
7d7817664b Updated gam <UserTypeEntity> show calsettings 2026-06-19 07:22:34 -07:00
github-actions[bot]
9aea95e8db chore: upgrade PyPi deps (#1924)
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
Build and test GAM / build (false, test, 19, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 20, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Co-authored-by: jay0lee <4623536+jay0lee@users.noreply.github.com>
2026-06-19 04:01:35 -04:00
Ross Scroggs
8b6781a49b Update Users-Drive-Activity-Settings.md
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
Build and test GAM / build (false, test, 19, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 20, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Daily Dependency Pinning (2-Week Buffer) / pin-deps (push) Has been cancelled
2026-06-18 12:24:09 -07:00
Ross Scroggs
ff59855a2c Update Vault-Takeout.md
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
Build and test GAM / build (false, test, 19, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 20, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Daily Dependency Pinning (2-Week Buffer) / pin-deps (push) Has been cancelled
2026-06-14 17:57:19 -07:00
github-actions[bot]
37d00ff0d8 chore: upgrade PyPi deps (#1923)
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
Build and test GAM / build (false, test, 19, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 20, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Daily Dependency Pinning (2-Week Buffer) / pin-deps (push) Has been cancelled
Co-authored-by: jay0lee <4623536+jay0lee@users.noreply.github.com>
2026-06-12 02:50:17 -04:00
Ross Scroggs
669dffcd39 Fixed bug in `gam <CrOSTypeEntity> issuecommand command <CrOSCommand> ... csv
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
2026-06-11 14:46:18 -07:00
Ross Scroggs
e3ad108c91 Fixed bug in gam <CrOSTypeEntity> issuecommand command <CrOSCommand> ... csv
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
Build and test GAM / build (false, test, 19, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 20, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Daily Dependency Pinning (2-Week Buffer) / pin-deps (push) Has been cancelled
2026-06-11 07:52:46 -07:00
Jay Lee
d7d98d41cd actions: rebuild for Python 3.14.6 2026-06-11 08:57:54 -04:00
Ross Scroggs
213b0f2ba2 Create, update and delete Cloud Identity policies
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
Build and test GAM / build (false, test, 19, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 20, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
2026-06-10 17:46:31 -07:00
Ross Scroggs
d745aa65f5 Create, update and delete Cloud Identity policies 2026-06-10 15:48:00 -07:00
Ross Scroggs
c122a55ad7 Final #1920 update
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
Build and test GAM / build (false, test, 19, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 20, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Daily Dependency Pinning (2-Week Buffer) / pin-deps (push) Has been cancelled
2026-06-09 22:46:29 -07:00
22 changed files with 396 additions and 269 deletions

View File

@@ -145,7 +145,7 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
fetch-depth: 0
@@ -165,7 +165,7 @@ jobs:
with:
path: |
cache.tar.xz
key: gam-${{ matrix.jid }}-20260609
key: gam-${{ matrix.jid }}-20260611
- name: Untar Cache archive
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
@@ -529,18 +529,6 @@ jobs:
echo "gam=${gam}" >> $GITHUB_ENV
fi
#- name: Upgrade pip, wheel, etc
# run: |
# curl $curl_retry -O https://bootstrap.pypa.io/get-pip.py
# "$PYTHON" get-pip.py
# "$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 install --upgrade packaging
# "$PYTHON" -m pip list
- name: Install pip requirements
env:
GH_TOKEN: ${{ github.token }}
@@ -550,8 +538,12 @@ jobs:
# https://github.com/pyca/cryptography/issues/14293
gh release download --repo "jay0lee/cryptography-wheels" --pattern "*win_arm64.whl" --clobber
"$PYTHON" -m pip install cryptography-*.whl
elif [[ "$RUNNER_OS" == "macOS" && "$RUNNER_ARCH" == "x86_64" ]]; then
# custom cryptography wheel for macos x86_64 since it's no longer standard
gh release download --repo "jay0lee/cryptography-wheels" --pattern "*macosx_15_0_x86_64.whl" --clobber
"$PYTHON" -m pip install cryptography-*.whl
fi
"$PYTHON" -m pip install -vvv --upgrade ..[yubikey]
"$PYTHON" -m pip install ..[yubikey]
- name: Install PyInstaller
if: matrix.goal == 'build'
@@ -1121,7 +1113,7 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
fetch-depth: 0

View File

@@ -39,7 +39,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:

View File

@@ -14,7 +14,7 @@ jobs:
check-certs:
runs-on: ubuntu-slim
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token
fetch-depth: 0 # otherwise, you will failed to push refs to dest repo

View File

@@ -18,7 +18,7 @@ jobs:
git clone https://github.com/GAM-team/GAM
- name: Checkout Wiki source
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
path: GAM.wiki
repository: GAM-team/GAM.wiki

View File

@@ -16,7 +16,7 @@ jobs:
id-token: write
steps:
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
fetch-depth: 0

View File

@@ -15,20 +15,25 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
python-version: '3.14'
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
version: "latest"
- name: Calculate and pin two-week old stable versions
shell: python
run: |
import json
import urllib.request
import subprocess
import re
import tomllib
import os
from datetime import datetime, timedelta, timezone
from pathlib import Path
@@ -42,14 +47,10 @@ jobs:
target_deps = set()
# Standard [project.dependencies]
# Gather all dependencies
target_deps.update(parsed_toml.get("project", {}).get("dependencies", []))
# Optional [project.optional-dependencies]
for deps in parsed_toml.get("project", {}).get("optional-dependencies", {}).values():
target_deps.update(deps)
# Dev [dependency-groups] (uv / PEP 735 standard)
for deps in parsed_toml.get("dependency-groups", {}).values():
if isinstance(deps, list):
for d in deps:
@@ -60,73 +61,80 @@ jobs:
print("No dependencies found to process.")
exit(0)
updates = {}
two_weeks_ago = datetime.now(timezone.utc) - timedelta(days=14)
print(f"Evaluating dependencies against cutoff date: {two_weeks_ago.isoformat()}")
# 1. Create a "clean" requirements list (base names + markers only, no versions)
clean_reqs = []
for dep in target_deps:
# Isolate base package name (e.g., "yubikey-manager>=5.6.1" -> "yubikey-manager")
pkg_name = re.split(r'[<>=!~;\s]', dep)[0].strip()
pkg_base = re.split(r'[<>=!~;\s]', dep)[0].strip()
if ";" in dep:
marker = dep.split(";", 1)[1].strip()
clean_reqs.append(f"{pkg_base} ; {marker}")
else:
clean_reqs.append(pkg_base)
temp_in = Path("temp_reqs.in")
temp_in.write_text("\n".join(clean_reqs), encoding="utf-8")
# 2. Calculate Cutoff Date
two_weeks_ago = datetime.now(timezone.utc) - timedelta(days=14)
cutoff_str = two_weeks_ago.strftime("%Y-%m-%dT%H:%M:%SZ")
print(f"Resolving dependencies against cutoff date: {cutoff_str}")
# 3. Use uv to resolve the CLEAN list, allowing free upgrades/downgrades
try:
subprocess.run([
"uv", "pip", "compile",
str(temp_in),
"--exclude-newer", cutoff_str,
"--quiet",
"-o", "resolved.txt"
], check=True)
except subprocess.CalledProcessError:
print("\nDependency resolution failed! Upstream constraints are impossible to satisfy.")
if temp_in.exists(): temp_in.unlink()
exit(1)
# 4. Parse the resolved lockfile
resolved_versions = {}
with open("resolved.txt", "r", encoding="utf-8") as f:
for line in f:
line = line.split("#")[0].strip()
if "==" in line:
pkg, ver = line.split("==", 1)
resolved_versions[pkg.strip().lower()] = ver.strip()
# Cleanup temp files so they don't get committed to the PR
if temp_in.exists():
temp_in.unlink()
if Path("resolved.txt").exists():
Path("resolved.txt").unlink()
# 5. Map the newly resolved versions back to your pyproject.toml updates
updates = {}
for dep in target_deps:
pkg_name_raw = re.split(r'[<>=!~;\s]', dep)[0].strip()
pkg_name_lower = pkg_name_raw.lower()
# Preserve environment markers if they exist
marker = ""
if ";" in dep:
marker = " ; " + dep.split(";", 1)[1].strip()
print(f"Fetching PyPI data for: {pkg_name}")
try:
url = f"https://pypi.org/pypi/{pkg_name}/json"
req = urllib.request.Request(url, headers={'User-Agent': 'GAM-CI-Script'})
with urllib.request.urlopen(req) as response:
data = json.loads(response.read().decode())
if pkg_name_lower in resolved_versions:
target_version = resolved_versions[pkg_name_lower]
pinned_dep = f"{pkg_name_raw}=={target_version}{marker}"
valid_versions = []
for ver, files in data.get("releases", {}).items():
if not files:
continue
upload_time_str = files[0].get("upload_time_iso_8601")
if not upload_time_str:
continue
if upload_time_str.endswith('Z'):
upload_time_str = upload_time_str[:-1] + '+00:00'
upload_time = datetime.fromisoformat(upload_time_str)
# Filter: Must be older than 2 weeks and not a pre-release
if upload_time <= two_weeks_ago and not any(x in ver.lower() for x in ['a', 'b', 'rc', 'dev']):
valid_versions.append((upload_time, ver))
if valid_versions:
# Sort by upload time descending to get the newest valid option
valid_versions.sort(key=lambda x: x[0], reverse=True)
target_version = valid_versions[0][1]
pinned_dep = f"{pkg_name}=={target_version}{marker}"
if pinned_dep != dep:
updates[dep] = pinned_dep
print(f" -> Pinning: '{dep}' => '{pinned_dep}'")
else:
print(f" -> Already pinned correctly to {target_version}")
if pinned_dep != dep:
updates[dep] = pinned_dep
print(f" -> Changing: '{dep}' => '{pinned_dep}'")
else:
print(f" -> No valid historical versions found.")
except urllib.error.HTTPError as e:
print(f" -> Package not found on PyPI or HTTP error: {e}")
except Exception as e:
print(f" -> Error processing {pkg_name}: {e}")
print(f" -> Up to date: {dep}")
# 3. Replace the strings safely in the original file content
# 6. Replace the strings safely in the original file content
new_content = content
for old_dep, new_dep in updates.items():
# Regex targets the exact string inside either single or double quotes
# Using a lambda replacement ensures we don't trip over escape sequences in the new string
escaped_old = re.escape(old_dep)
pattern = r'([\'"])' + escaped_old + r'\1'
new_content = re.sub(pattern, lambda m: m.group(1) + new_dep + m.group(1), new_content)
# Write changes back to pyproject.toml
if content != new_content:
toml_path.write_text(new_content, encoding="utf-8")
print("\npyproject.toml updated successfully.")
@@ -139,6 +147,6 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "chore: upgrade PyPi deps"
title: "Upgrade PyPi deps"
body: "Automated scan checking PyPI for package versions at least 2 weeks old."
body: "Automated scan checking PyPI for mutually compatible package versions at least 2 weeks old. Handles both upgrades and conflict-driven downgrades."
branch: sys-deps-upgrade
force: false # Standard push, plays nice with rulesets

View File

@@ -1,6 +0,0 @@
# overrides uv.lock to force newer dependencies
# when old deps are vulnerable. These should be set
# to expire after 2 weeks when the fixed version will
# be automatically picked up anyway.
# Format: package_requirement | MM/DD/YYYY
urllib3>=2.7.0 | 05/22/2026

View File

@@ -10,13 +10,13 @@ authors = [
dependencies = [
"arrow==1.4.0",
"chardet==7.4.3",
"cryptography==48.0.0",
"cryptography==48.0.1",
"distro==1.9.0 ; sys_platform=='linux'",
"filelock==3.29.0",
"google-api-python-client==2.196.0",
"filelock==3.29.4",
"google-api-python-client==2.197.0",
"google-auth-httplib2==0.4.0",
"google-auth-oauthlib==1.4.0",
"google-auth==2.53.0",
"google-auth==2.54.0",
"httplib2==0.31.2",
"lxml==6.1.1",
"passlib==1.7.4",

View File

@@ -1676,6 +1676,10 @@ gam <UserTypeEntity> show analyticdatastreams
<CalendarACLScopeEntity>::=
<CalendarACLScopeList> | <FileSelector> | <CSVkmdSelector> | <CSVDataSelector>
Transfer ownership of a selection of a users secondary calendars to another user
gam calendars <CalendarEntity> transfer <UserItem>
gam calendars <CalendarEntity> create|add acls|calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
gam calendars <CalendarEntity> update acls|calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
gam calendars <CalendarEntity> delete acls|calendaracls [<CalendarACLRole>] <CalendarACLScopeEntity>
@@ -4378,6 +4382,14 @@ gam show policies
[group <REMatchPattern>] [ou|org|orgunit <REMatchPattern>]
[formatjson]
gam create policy
json <JSONData>
[(ou|orgunit <OrgUnitItem>)|(group <GroupItem>)|(query <String>)]
gam update policy
json <JSONData>
[(ou|orgunit <OrgUnitItem>)|(group <GroupItem>)|(query <String>)]
gam delete policies <CIPolicyNameEntity>
# Inbound SSO
<SSOProfileDisplayName> ::= <String>
@@ -6290,13 +6302,6 @@ gam <UserTypeEntity> print calendaracls <UserCalendarEntity> [todrive <ToDriveAt
[noselfowner] (addcsvdata <FieldName> <String>)*
[formatjson [quotechar <Character>]]
Transfer ownership of a selection of a users secondary calendars to another user
gam <UserTypeEntity> transfer calendars|seccals <UserItem> [<UserCalendarEntity>]
[keepuser | (retainrole <CalendarACLRole>)] [sendnotifications <Boolean>] [noretentionmessages]
<CalendarSettings>* [append description|location|summary] [noupdatemessages]
[deletefromoldowner] [addtonewowner <CalendarAttribute>*] [nolistmessages]
<AttendeeAttendance> ::= optional|required
<AttendeeStatus> ::= accepted|declined|needsaction|tentative

View File

@@ -1,3 +1,26 @@
7.46.03
Updated all Vault related commands to handle the following error: `ERROR: 403: permissionDenied`
7.46.02
Updated `gam calendars <CalendarEntity> show settings` to display `dataOwner` field;
it is labelled `Owner`.
7.46.01
Fixed bug in `gam <CrOSTypeEntity> issuecommand command <CrOSCommand> ... csv` where
command execution status lines were improperly indented.
Upgraded to Python 3.14.6.
7.46.00
Added commands to create, update and delete Cloud Identity policies for data loss prevention (DLP) rules and detectors.
* See: https://github.com/GAM-team/GAM/wiki/Cloud-Identity-Policies
* See: https://workspaceupdates.googleblog.com/2026/06/introducing-workspace-policy-api-mutate-endpoints-for-DLP.html
7.45.00
Added options `isdisabled [<Boolean>]`, `disabledafter <DateTime>` and `disabledbefore <DateTime>`

View File

@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
"""
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
__version__ = '7.45.00'
__version__ = '7.46.03'
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
# pylint: disable=wrong-import-position
@@ -683,7 +683,7 @@ def accessErrorMessage(cd, errMsg=None):
[Ent.Singular(Ent.CUSTOMER_ID), GC.Values[GC.CUSTOMER_ID],
Msg.DOES_NOT_EXIST],
'')
except GAPI.forbidden:
except (GAPI.forbidden, GAPI.permissionDenied):
return formatKeyValueList('',
Ent.FormatEntityValueList([Ent.CUSTOMER_ID, GC.Values[GC.CUSTOMER_ID],
Ent.DOMAIN, GC.Values[GC.DOMAIN],
@@ -24392,7 +24392,7 @@ def displayCrOSCommandResult(cd, deviceId, commandId, checkResultRetries, i, cou
if addCSVData:
result.update(addCSVData)
csvPF.WriteRowTitles(flattenJSON(result, timeObjects=CROS_COMMAND_TIME_OBJECTS))
return
break
showJSON(None, result, timeObjects=CROS_COMMAND_TIME_OBJECTS)
state = result.get('state')
if state in CROS_COMMAND_FINAL_STATES:
@@ -24871,9 +24871,9 @@ def infoCrOSDevices(entityList):
i += 1
try:
cros = callGAPI(cd.chromeosdevices(), 'get',
throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
customerId=GC.Values[GC.CUSTOMER_ID], deviceId=deviceId, projection=projection, fields=fields)
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden, GAPI.permissionDenied):
checkEntityAFDNEorAccessErrorExit(cd, Ent.CROS_DEVICE, deviceId, i, count)
continue
checkTPMVulnerability(cros)
@@ -25498,7 +25498,7 @@ def doPrintCrOSDevices(entityList=None):
try:
feed = callGAPI(cd.chromeosdevices(), 'list',
throwReasons=[GAPI.INVALID_INPUT, GAPI.INVALID_ORGUNIT,
GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
pageToken=pageToken,
customerId=GC.Values[GC.CUSTOMER_ID], query=query, projection=projection,
@@ -25532,7 +25532,7 @@ def doPrintCrOSDevices(entityList=None):
except GAPI.invalidOrgunit as e:
entityActionFailedWarning([Ent.CROS_DEVICE, None], str(e))
return
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden, GAPI.permissionDenied):
accessErrorExit(cd)
if showItemCountOnly:
writeStdout(f'{totalItems}\n')
@@ -38526,37 +38526,25 @@ def _checkPoliciesWithDASA():
systemErrorExit(USAGE_ERROR_RC,
Msg.COMMAND_NOT_COMPATIBLE_WITH_ENABLE_DASA.format(Act.ToPerform().lower(), Cmd.ARG_CIPOLICIES))
def _getCIPolicyOrgUnitTarget(cd, myarg, groupEmail):
if groupEmail:
Cmd.Backup()
usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format(myarg, 'group'))
targetName, targetResource = _getOrgunitsOrgUnitIdPath(cd, getString(Cmd.OB_ORGUNIT_PATH))
return (targetName, targetResource)
def _getCIPolicyGroupTarget(cd, myarg, orgUnit):
if orgUnit:
Cmd.Backup()
usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format(myarg, 'ou|org|orgunit'))
targetName = getEmailAddress(returnUIDprefix='uid:')
targetResource = f"groups/{convertEmailAddressToUID(targetName, cd, emailType='group')}"
return (targetName, targetResource)
# gam create policy
# json <JSONData>
# [(ou|orgunit <OrgUnitItem>)|(group <GroupItem>)]
# [(ou|orgunit <OrgUnitItem>)|(group <GroupItem>)|(query <String>)]
# gam update policy
# json <JSONData>
# [(ou|orgunit <OrgUnitItem>)|(group <GroupItem>)]
# [(ou|orgunit <OrgUnitItem>)|(group <GroupItem>)|(query <String>)]
def doCreateUpdateCIPolicy():
_checkPoliciesWithDASA()
ci = buildGAPIObject(API.CLOUDIDENTITY_POLICY_BETA)
ci = buildGAPIObject(API.CLOUDIDENTITY_POLICY)
cd = buildGAPIObject(API.DIRECTORY)
updateCmd = Act.Get() == Act.UPDATE
groupEmail = orgUnit = None
groupEmail = orgUnit = query = None
checkArgumentPresent('json', True)
policy = getJSON(['customer', 'type'])
if updateCmd:
pname = policy.pop('name', None)
if not pname:
Cmd.Backup()
usageErrorExit(Msg.POLICY_NAME_NOT_FOUND)
else:
policy.pop('name', None)
pname = 'New Policy'
@@ -38564,6 +38552,8 @@ def doCreateUpdateCIPolicy():
policy['policyQuery'].pop('orgUnitPath', None)
policy['policyQuery'].pop('groupEmail', None)
policy['policyQuery'].pop('sortOrder', None)
if 'orgUnit' in policy['policyQuery'] or 'group' in policy['policyQuery']:
policy['policyQuery'].pop('query', None)
if 'setting' in policy:
if 'value' in policy['setting']:
policy['setting']['value'].pop('createTime', None)
@@ -38576,19 +38566,37 @@ def doCreateUpdateCIPolicy():
while Cmd.ArgumentsRemaining():
myarg = getArgument()
if myarg in {'ou', 'org', 'orgunit'}:
orgUnit, targetResource = _getCIPolicyOrgUnitTarget(cd, myarg, groupEmail)
policy.setdefault('policyQuery', {})
policy['policyQuery'].pop('group', None)
policy['policyQuery']['orgUnit'] = f"orgUnits/{targetResource}"
policy['policyQuery']['query'] = f"entity.org_units.exists(org_unit, org_unit.org_unit_id == orgUnitId('{targetResource}'))"
if groupEmail:
Cmd.Backup()
usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format(myarg, 'group'))
if query:
Cmd.Backup()
usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format(myarg, 'query'))
orgUnit, targetResource = _getOrgunitsOrgUnitIdPath(cd, getString(Cmd.OB_ORGUNIT_PATH))
policy['policyQuery'] = {'orgUnit': f"orgUnits/{targetResource}"}
elif myarg == 'group':
groupEmail, targetResource = _getCIPolicyGroupTarget(cd, myarg, orgUnit)
policy.setdefault('policyQuery', {})
policy['policyQuery'].pop('orgUnit', None)
policy['policyQuery']['group'] = f"groups/{targetResource}"
policy['policyQuery']['query'] = f"entity.groups.exists(group, group.group_id == groupId('{targetResource}'))"
if orgUnit:
Cmd.Backup()
usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format(myarg, 'ou|org|orgunit'))
if query:
Cmd.Backup()
usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format(myarg, 'query'))
groupEmail = getEmailAddress(returnUIDprefix='uid:')
targetResource = f"groups/{convertEmailAddressToUID(groupEmail, cd, emailType='group')}"
policy['policyQuery'] = {'group': f"groups/{targetResource}"}
elif myarg == 'query':
if groupEmail:
Cmd.Backup()
usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format(myarg, 'group'))
if orgUnit:
Cmd.Backup()
usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format(myarg, 'ou|org|orgunit'))
query = getString(Cmd.OB_QUERY)
policy['policyQuery'] = {'query': query}
else:
unknownArgumentExit()
if 'policyQuery' not in policy:
missingArgumentExit('ou|org|orgunit|group|query')
policy['customer'] = _getCustomersCustomerIdWithC()
try:
if updateCmd:
@@ -38616,11 +38624,10 @@ def doCreateUpdateCIPolicy():
GAPI.notFound, GAPI.permissionDenied, GAPI.internalError) as e:
entityActionFailedWarning([Ent.POLICY, pname], str(e))
# gam delete policies <CIPolicyNameEntity>
def doDeleteCIPolicies():
_checkPoliciesWithDASA()
ci = buildGAPIObject(API.CLOUDIDENTITY_POLICY_BETA)
ci = buildGAPIObject(API.CLOUDIDENTITY_POLICY)
entityList = getEntityList(Cmd.OB_CIPOLICY_NAME_ENTITY)
checkForExtraneousArguments()
i = 0
@@ -42949,14 +42956,16 @@ def doCalendarsModifySettings(calIds):
def _showCalendarSettings(calendar, j, jcount):
printEntity([Ent.CALENDAR, calendar['id']], j, jcount)
Ind.Increment()
if 'dataOwner' in calendar:
printKeyValueList(['Owner', calendar['dataOwner']])
if 'summaryOverride' in calendar or 'summary' in calendar:
printKeyValueList(['Summary', calendar.get('summaryOverride', calendar.get('summary', ''))])
if 'description' in calendar:
printKeyValueWithCRsNLs('Description', calendar.get('description', ''))
printKeyValueWithCRsNLs('Description', calendar['description'])
if 'location' in calendar:
printKeyValueList(['Location', calendar.get('location', '')])
printKeyValueList(['Location', calendar['location']])
if 'timeZone' in calendar:
printKeyValueList(['Timezone', calendar.get('timeZone', '')])
printKeyValueList(['Timezone', calendar['timeZone']])
if 'conferenceProperties' in calendar:
printKeyValueList(['ConferenceProperties', None])
Ind.Increment()
@@ -43635,7 +43644,7 @@ def convertExportNameToID(v, nameOrId, matterId, matterNameId):
if cg:
try:
export = callGAPI(v.matters().exports(), 'get',
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN,
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED,
GAPI.INVALID_ARGUMENT, GAPI.FAILED_PRECONDITION],
matterId=matterId, exportId=cg.group(1))
return (export['id'], export['name'], formatVaultNameId(export['id'], export['name']))
@@ -43643,14 +43652,14 @@ def convertExportNameToID(v, nameOrId, matterId, matterNameId):
entityDoesNotHaveItemExit([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_EXPORT, nameOrId])
except (GAPI.failedPrecondition) as e:
entityActionFailedExit([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_EXPORT, nameOrId], str(e))
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
ClientAPIAccessDeniedExit(str(e))
nameOrIdlower = nameOrId.lower()
try:
exports = callGAPIpages(v.matters().exports(), 'list', 'exports',
throwReasons=[GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, fields='exports(id,name),nextPageToken')
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
ClientAPIAccessDeniedExit(str(e))
for export in exports:
if export['name'].lower() == nameOrIdlower:
@@ -43662,19 +43671,19 @@ def convertHoldNameToID(v, nameOrId, matterId, matterNameId):
if cg:
try:
hold = callGAPI(v.matters().holds(), 'get',
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, holdId=cg.group(1))
return (hold['holdId'], hold['name'], formatVaultNameId(hold['holdId'], hold['name']))
except (GAPI.notFound, GAPI.badRequest):
entityDoesNotHaveItemExit([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_HOLD, nameOrId])
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
ClientAPIAccessDeniedExit(str(e))
nameOrIdlower = nameOrId.lower()
try:
holds = callGAPIpages(v.matters().holds(), 'list', 'holds',
throwReasons=[GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, fields='holds(holdId,name),nextPageToken')
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
ClientAPIAccessDeniedExit(str(e))
for hold in holds:
if hold['name'].lower() == nameOrIdlower:
@@ -43686,16 +43695,18 @@ def convertMatterNameToID(v, nameOrId, state=None):
if cg:
try:
matter = callGAPI(v.matters(), 'get',
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=cg.group(1), view='BASIC', fields='matterId,name,state')
return (matter['matterId'], matter['name'], formatVaultNameId(matter['name'], matter['matterId']), matter['state'])
except (GAPI.notFound, GAPI.forbidden):
except GAPI.notFound:
entityDoesNotExistExit(Ent.VAULT_MATTER, nameOrId)
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
ClientAPIAccessDeniedExit(str(e))
try:
matters = callGAPIpages(v.matters(), 'list', 'matters',
throwReasons=[GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
view='BASIC', state=state, fields='matters(matterId,name,state),nextPageToken')
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
ClientAPIAccessDeniedExit(str(e))
nameOrIdlower = nameOrId.lower()
ids = []
@@ -43717,19 +43728,19 @@ def convertQueryNameToID(v, nameOrId, matterId, matterNameId):
if cg:
try:
query = callGAPI(v.matters().savedQueries(), 'get',
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, savedQueryId=cg.group(1))
return (query['savedQueryId'], query['displayName'], formatVaultNameId(query['savedQueryId'], query['displayName']), query['query'])
except (GAPI.notFound, GAPI.badRequest):
entityDoesNotHaveItemExit([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_QUERY, nameOrId])
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
ClientAPIAccessDeniedExit(str(e))
nameOrIdlower = nameOrId.lower()
try:
queries = callGAPIpages(v.matters().savedQueries(), 'list', 'savedQueries',
throwReasons=[GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, fields='savedQueries(savedQueryId,displayName,query),nextPageToken')
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
ClientAPIAccessDeniedExit(str(e))
for query in queries:
if query['displayName'].lower() == nameOrIdlower:
@@ -43744,9 +43755,9 @@ def warnMatterNotOpen(v, matter, matterNameId, j, jcount):
if v is not None:
try:
matter['state'] = callGAPI(v.matters(), 'get',
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matter['matterId'], view='BASIC', fields='state')['state']
except (GAPI.notFound, GAPI.forbidden, GAPI.invalidArgument):
except (GAPI.notFound, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument):
matter['state'] = 'Unknown'
else:
setSysExitRC(DATA_NOT_AVALIABLE_RC)
@@ -44117,10 +44128,10 @@ def doDeleteVaultExport():
unknownArgumentExit()
try:
callGAPI(v.matters().exports(), 'delete',
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, exportId=exportId)
entityActionPerformed([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_EXPORT, exportNameId])
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_EXPORT, exportNameId], str(e))
VAULT_EXPORT_FIELDS_CHOICE_MAP = {
@@ -44175,7 +44186,7 @@ def doInfoVaultExport():
GAPI.INVALID_ARGUMENT, GAPI.FAILED_PRECONDITION],
matterId=matterId, exportId=exportId, fields=fields)
_showVaultExport(matterNameId, export, cd, FJQC)
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument, GAPI.failedPrecondition) as e:
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument, GAPI.failedPrecondition) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_EXPORT, exportNameId], str(e))
VAULT_EXPORT_STATUS_MAP = {'completed': 'COMPLETED', 'failed': 'FAILED', 'inprogress': 'IN_PROGRESS'}
@@ -44238,9 +44249,9 @@ def doPrintShowVaultExports():
try:
results = callGAPIpages(v.matters(), 'list', 'matters',
pageMessage=getPageMessage(),
throwReasons=[GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
view='BASIC', state='OPEN', fields='matters(matterId,name,state),nextPageToken')
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_EXPORT, None], str(e))
return
else:
@@ -44268,12 +44279,12 @@ def doPrintShowVaultExports():
try:
exports = callGAPIpages(v.matters().exports(), 'list', 'exports',
pageMessage=pageMessage,
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, fields=fields)
except GAPI.failedPrecondition:
warnMatterNotOpen(v, matter, matterNameId, j, jcount)
continue
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_EXPORT, None], str(e))
break
else:
@@ -44351,7 +44362,7 @@ def doCopyVaultExport():
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN,
GAPI.INVALID_ARGUMENT, GAPI.FAILED_PRECONDITION],
matterId=matterId, exportId=exportId)
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument, GAPI.failedPrecondition) as e:
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument, GAPI.failedPrecondition) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_EXPORT, exportNameId], str(e))
return
if export['status'] == 'COMPLETED':
@@ -44452,7 +44463,7 @@ def doDownloadVaultExport():
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN,
GAPI.INVALID_ARGUMENT, GAPI.FAILED_PRECONDITION],
matterId=matterId, exportId=exportId)
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument, GAPI.failedPrecondition) as e:
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument, GAPI.failedPrecondition) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_EXPORT, exportNameId], str(e))
return
if export['status'] == 'COMPLETED':
@@ -44678,7 +44689,7 @@ def doCreateVaultHold():
try:
hold = callGAPI(v.matters().holds(), 'create',
throwReasons=[GAPI.ALREADY_EXISTS, GAPI.BAD_REQUEST, GAPI.BACKEND_ERROR, GAPI.FAILED_PRECONDITION,
GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, body=body)
if not returnIdOnly:
entityActionPerformed([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_HOLD, formatVaultNameId(hold['name'], hold['holdId'])])
@@ -44687,7 +44698,7 @@ def doCreateVaultHold():
else:
writeStdout(f'{hold["holdId"]}\n')
except (GAPI.alreadyExists, GAPI.badRequest, GAPI.backendError, GAPI.failedPrecondition,
GAPI.forbidden, GAPI.invalidArgument) as e:
GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_HOLD, body.get('name')], str(e))
# gam update vaulthold|hold <HoldItem> matter <MatterItem>
@@ -44732,9 +44743,9 @@ def doUpdateVaultHold():
missingArgumentExit('matter')
try:
old_body = callGAPI(v.matters().holds(), 'get',
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, holdId=holdId, fields='name,corpus,query,orgUnit')
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_HOLD, holdNameId], str(e))
return
accountType = 'group' if old_body['corpus'] == 'GROUPS' else 'user'
@@ -44760,10 +44771,10 @@ def doUpdateVaultHold():
if body:
try:
hold = callGAPI(v.matters().holds(), 'update',
throwReas=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReas=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, holdId=holdId, body=body)
entityActionPerformed([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_HOLD, holdNameId])
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_HOLD, holdNameId], str(e))
return
jcount = len(addAccountIds)
@@ -44776,12 +44787,12 @@ def doUpdateVaultHold():
j += 1
try:
callGAPI(v.matters().holds().accounts(), 'create',
throwReasons=[GAPI.ALREADY_EXISTS, GAPI.BACKEND_ERROR, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.ALREADY_EXISTS, GAPI.BACKEND_ERROR, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, holdId=holdId, body={'accountId': account['id']})
entityActionPerformed([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_HOLD, holdNameId, Ent.ACCOUNT, account['email']], j, jcount)
except (GAPI.alreadyExists, GAPI.backendError) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_HOLD, holdNameId, Ent.ACCOUNT, account['email']], str(e), j, jcount)
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_HOLD, None], str(e))
return
Ind.Decrement()
@@ -44797,12 +44808,12 @@ def doUpdateVaultHold():
j += 1
try:
callGAPI(v.matters().holds().accounts(), 'delete',
throwReasons=[GAPI.NOT_FOUND, GAPI.BACKEND_ERROR, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.NOT_FOUND, GAPI.BACKEND_ERROR, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, holdId=holdId, accountId=account['id'])
entityActionPerformed([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_HOLD, holdNameId, Ent.ACCOUNT, account['email']], j, jcount)
except (GAPI.alreadyExists, GAPI.backendError) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_HOLD, holdNameId, Ent.ACCOUNT, account['email']], str(e), j, jcount)
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_HOLD, None], str(e))
return
Ind.Decrement()
@@ -44827,10 +44838,10 @@ def doDeleteVaultHold():
unknownArgumentExit()
try:
callGAPI(v.matters().holds(), 'delete',
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, holdId=holdId)
entityActionPerformed([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_HOLD, holdNameId])
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_HOLD, holdNameId], str(e))
VAULT_HOLD_FIELDS_CHOICE_MAP = {
@@ -44880,10 +44891,10 @@ def doInfoVaultHold():
fields = getFieldsFromFieldsList(fieldsList)
try:
hold = callGAPI(v.matters().holds(), 'get',
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, holdId=holdId, fields=fields)
_showVaultHold(matterNameId, hold, cd, FJQC)
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_HOLD, holdNameId], str(e))
PRINT_VAULT_HOLDS_TITLES = ['matterId', 'matterName', 'holdId', 'name', 'updateTime']
@@ -44934,9 +44945,9 @@ def doPrintShowVaultHolds():
try:
results = callGAPIpages(v.matters(), 'list', 'matters',
pageMessage=getPageMessage(),
throwReasons=[GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
view='BASIC', state='OPEN', fields='matters(matterId,name,state),nextPageToken')
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_HOLD, None], str(e))
return
else:
@@ -44963,12 +44974,12 @@ def doPrintShowVaultHolds():
try:
holds = callGAPIpages(v.matters().holds(), 'list', 'holds',
pageMessage=pageMessage,
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, fields=fields)
except GAPI.failedPrecondition:
warnMatterNotOpen(v, matter, matterNameId, j, jcount)
continue
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_HOLD, None], str(e))
break
else:
@@ -45014,9 +45025,9 @@ def printShowUserVaultHolds(entityList):
try:
matters = callGAPIpages(v.matters(), 'list', 'matters',
pageMessage=getPageMessage(),
throwReasons=[GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
view='BASIC', state='OPEN', fields='matters(matterId,name,state),nextPageToken')
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_HOLD, None], str(e))
return
jcount = len(matters)
@@ -45030,11 +45041,11 @@ def printShowUserVaultHolds(entityList):
try:
matter['holds'] = callGAPIpages(v.matters().holds(), 'list', 'holds',
pageMessage=getPageMessageForWhom(),
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, fields='holds(holdId,name,accounts(accountId,email),orgUnit(orgUnitId)),nextPageToken')
except GAPI.failedPrecondition:
warnMatterNotOpen(v, matter, matterNameId, j, jcount)
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_HOLD, None], str(e), j, jcount)
totalHolds = 0
_, _, entityList = getEntityArgument(entityList)
@@ -45148,7 +45159,7 @@ def doCreateCopyVaultQuery(copyCmd):
resultNameId = matterNameId
try:
result = callGAPI(v.matters().savedQueries(), 'create',
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT, GAPI.ALREADY_EXISTS],
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT, GAPI.ALREADY_EXISTS],
matterId=resultId, body=body)
if not returnIdOnly:
if not FJQC.formatJSON:
@@ -45157,7 +45168,7 @@ def doCreateCopyVaultQuery(copyCmd):
_showVaultQuery(resultNameId, result, cd, drive, FJQC)
else:
writeStdout(f'{result["savedQueryId"]}\n')
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument, GAPI.alreadyExists) as e:
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument, GAPI.alreadyExists) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, resultNameId, Ent.VAULT_QUERY, body['displayName']], str(e))
# gam create vaultquery <MatterItem> [name <String>]
@@ -45205,10 +45216,10 @@ def doDeleteVaultQuery():
unknownArgumentExit()
try:
callGAPI(v.matters().savedQueries(), 'delete',
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, savedQueryId=queryId)
entityActionPerformed([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_QUERY, queryNameId])
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_QUERY, queryNameId], str(e))
VAULT_QUERY_FIELDS_CHOICE_MAP = {
@@ -45254,10 +45265,10 @@ def doInfoVaultQuery():
fields = getFieldsFromFieldsList(fieldsList)
try:
query = callGAPI(v.matters().savedQueries(), 'get',
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, savedQueryId=queryId, fields=fields)
_showVaultQuery(matterNameId, query, cd, drive, FJQC)
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.notFound, GAPI.badRequest, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_QUERY, queryNameId], str(e))
PRINT_VAULT_QUERIES_TITLES = ['matterId', 'matterName', 'savedQueryId', 'displayName']
@@ -45298,9 +45309,9 @@ def doPrintShowVaultQueries():
try:
results = callGAPIpages(v.matters(), 'list', 'matters',
pageMessage=getPageMessage(),
throwReasons=[GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
view='BASIC', state='OPEN', fields='matters(matterId,name,state),nextPageToken')
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_QUERY, None], str(e))
return
else:
@@ -45327,12 +45338,12 @@ def doPrintShowVaultQueries():
try:
queries = callGAPIpages(v.matters().savedQueries(), 'list', 'savedQueries',
pageMessage=pageMessage,
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, fields=fields)
except GAPI.failedPrecondition:
warnMatterNotOpen(v, matter, matterNameId, j, jcount)
continue
except (GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_QUERY, None], str(e))
break
else:
@@ -45419,7 +45430,7 @@ def doCreateVaultMatter():
body['name'] = f'GAM Matter - {ISOformatTimeStamp(todaysTime())}'
try:
matter = callGAPI(v.matters(), 'create',
throwReasons=[GAPI.ALREADY_EXISTS, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.ALREADY_EXISTS, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
body=body)
matterId = matter['matterId']
matterNameId = formatVaultNameId(matter['name'], matterId)
@@ -45427,7 +45438,7 @@ def doCreateVaultMatter():
entityActionPerformed([Ent.VAULT_MATTER, matterNameId])
else:
writeStdout(f'{matterId}\n')
except (GAPI.alreadyExists, GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.alreadyExists, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, body['name']], str(e))
return
jcount = len(collaborators)
@@ -45442,11 +45453,11 @@ def doCreateVaultMatter():
cbody['matterPermission']['accountId'] = collaborator['id']
try:
callGAPI(v.matters(), 'addPermissions',
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, body=cbody)
if not returnIdOnly:
entityActionPerformed([Ent.VAULT_MATTER, matterNameId, Ent.COLLABORATOR, collaborator['email']], j, jcount)
except (GAPI.failedPrecondition, GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.failedPrecondition, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId], str(e))
break
Ind.Decrement()
@@ -45470,10 +45481,10 @@ def doActionVaultMatter(action, matterId=None, matterNameId=None, v=None):
action_kwargs = {} if action == 'delete' else {'body': {}}
try:
callGAPI(v.matters(), action,
throwReasons=[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, **action_kwargs)
entityActionPerformed([Ent.VAULT_MATTER, matterNameId])
except (GAPI.notFound, GAPI.failedPrecondition, GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.notFound, GAPI.failedPrecondition, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId], str(e))
# gam close vaultmatter|matter <MatterItem>
@@ -45526,7 +45537,7 @@ def doUpdateVaultMatter():
if 'name' not in body or 'description' not in body:
# bah, API requires name/description to be sent on update even when it's not changing
result = callGAPI(v.matters(), 'get',
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, view='BASIC')
body.setdefault('name', result['name'])
body.setdefault('description', result.get('description'))
@@ -45534,7 +45545,7 @@ def doUpdateVaultMatter():
throwReasons=[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN],
matterId=matterId, body=body)
entityActionPerformed([Ent.VAULT_MATTER, matterNameId])
except (GAPI.notFound, GAPI.failedPrecondition, GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.notFound, GAPI.failedPrecondition, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId], str(e))
return
jcount = len(addCollaborators)
@@ -45547,10 +45558,10 @@ def doUpdateVaultMatter():
j += 1
try:
callGAPI(v.matters(), 'addPermissions',
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, body={'matterPermission': {'role': 'COLLABORATOR', 'accountId': collaborator['id']}})
entityActionPerformed([Ent.VAULT_MATTER, matterNameId, Ent.COLLABORATOR, collaborator['email']], j, jcount)
except (GAPI.failedPrecondition, GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.failedPrecondition, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId], str(e))
break
Ind.Decrement()
@@ -45564,10 +45575,10 @@ def doUpdateVaultMatter():
j += 1
try:
callGAPI(v.matters(), 'removePermissions',
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, body={'accountId': collaborator['id']})
entityActionPerformed([Ent.VAULT_MATTER, matterNameId, Ent.COLLABORATOR, collaborator['email']], j, jcount)
except (GAPI.failedPrecondition, GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.failedPrecondition, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId], str(e))
break
Ind.Decrement()
@@ -45600,11 +45611,11 @@ def doInfoVaultMatter():
fields = getFieldsFromFieldsList(fieldsList)
try:
matter = callGAPI(v.matters(), 'get',
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT],
matterId=matterId, view=view, fields=fields)
cd = buildGAPIObject(API.DIRECTORY) if 'matterPermissions' in matter else None
_showVaultMatter(matter, cd, FJQC)
except (GAPI.notFound, GAPI.forbidden, GAPI.invalidArgument) as e:
except (GAPI.notFound, GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId], str(e))
VAULT_MATTER_STATE_MAP = {'open': 'OPEN', 'closed': 'CLOSED', 'deleted': 'DELETED'}
@@ -45660,9 +45671,9 @@ def doPrintShowVaultMatters():
try:
matters = callGAPIpages(v.matters(), 'list', 'matters',
pageMessage=getPageMessage(),
throwReasons=[GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT, GAPI.INVALID_ARGUMENT],
throwReasons=[GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED, GAPI.INVALID_ARGUMENT, GAPI.INVALID_ARGUMENT],
view=view, state=stateParm, fields=fields)
except (GAPI.forbidden, GAPI.invalidArgument, GAPI.invalidArgument) as e:
except (GAPI.forbidden, GAPI.permissionDenied, GAPI.invalidArgument, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, None], str(e))
return
jcount = len(matters)
@@ -55339,16 +55350,30 @@ def printShowCalendarACLs(users):
if csvPF:
csvPF.writeCSVfile('Calendar ACLs')
# gam <UserTypeEntity> transfer calendars|seccals <UserItem> [<UserCalendarEntity>]
# [keepuser | (retainrole <CalendarACLRole>)] [sendnotifications <Boolean>] [noretentionmessages]
# <CalendarSettings>* [append description|location|summary] [noupdatemessages]
# [deletefromoldowner] [addtonewowner <CalendarAttribute>*] [nolistmessages]
def transferCalendars(users):
errMsg = ''' Due to the following Calendar API update, the `gam <UserTypeEntity> transfer calendars` command has been removed.
* See: https://developers.google.com/workspace/calendar/release-notes#October_27_2025
Data ownership can be transferred in the Google Calendar UI.
'''
systemErrorExit(ACTION_FAILED_RC, errMsg)
# gam <CalendarEntity> transfer ownership <UserItem>
def doCalendarsTransferOwnership(calIds):
Act.Set(Act.TRANSFER_OWNERSHIP)
newDataOwner = getEmailAddress()
checkForExtraneousArguments()
count = len(calIds)
i = 0
for calId in calIds:
i += 1
calId, cal = validateCalendar(calId, i, count)
if not cal:
continue
try:
callGAPI(cal.calendars(), 'transferOwnership',
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID, GAPI.INVALID_PARAMETER,
GAPI.FORBIDDEN, GAPI.AUTH_ERROR, GAPI.CONDITION_NOT_MET],
calendarId=calId, newDataOwner=newDataOwner, useAdminAccess=True)
entityPerformActionModifierNewValue([Ent.CALENDAR, calId], Act.MODIFIER_TO, newDataOwner, i, count)
except (GAPI.notFound, GAPI.invalid, GAPI.invalidParameter,
GAPI.forbidden, GAPI.authError, GAPI.conditionNotMet) as e:
entityModifierNewValueActionFailedWarning([Ent.CALENDAR, calId], Act.MODIFIER_TO, newDataOwner, str(e), i, count)
except AttributeError as e:
entityModifierNewValueActionFailedWarning([Ent.CALENDAR, calId], Act.MODIFIER_TO, newDataOwner, str(e), i, count)
return
def _createImportCalendarEvent(users, function):
calendarEntity = getUserCalendarEntity()
@@ -81561,6 +81586,11 @@ CALENDARS_SUBCOMMANDS_WITH_OBJECTS = {
Cmd.ARG_SETTINGS: doCalendarsPrintShowSettings,
}
),
'transfer':
(Act.TRANSFER,
{Cmd.ARG_OWNERSHIP: doCalendarsTransferOwnership,
}
),
'update':
(Act.UPDATE,
{Cmd.ARG_CALENDARACL: doCalendarsUpdateACLs,
@@ -82295,7 +82325,6 @@ USER_COMMANDS_WITH_OBJECTS = {
'transfer':
(Act.TRANSFER,
{Cmd.ARG_DRIVE: transferDrive,
Cmd.ARG_CALENDAR: transferCalendars,
Cmd.ARG_OWNERSHIP: transferOwnership,
}
),

View File

@@ -51,7 +51,6 @@ CLOUDIDENTITY_INBOUND_SSO = 'cloudidentityinboundsso'
CLOUDIDENTITY_ORGUNITS = 'cloudidentityorgunits'
CLOUDIDENTITY_ORGUNITS_BETA = 'cloudidentityorgunitsbeta'
CLOUDIDENTITY_POLICY = 'cloudidentitypolicy'
CLOUDIDENTITY_POLICY_BETA = 'cloudidentitypolicybeta'
CLOUDIDENTITY_USERINVITATIONS = 'cloudidentityuserinvitations'
CLOUDRESOURCEMANAGER = 'cloudresourcemanager'
CLOUDRESOURCEMANAGERV1 = 'cloudresourcemanagerv1'
@@ -261,7 +260,6 @@ _INFO = {
CLOUDIDENTITY_ORGUNITS: {'name': 'Cloud Identity API - OrgUnits', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
CLOUDIDENTITY_ORGUNITS_BETA: {'name': 'Cloud Identity API - OrgUnits Beta', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
CLOUDIDENTITY_POLICY: {'name': 'Cloud Identity API - Policy', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
CLOUDIDENTITY_POLICY_BETA: {'name': 'Cloud Identity API - Policy Beta', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
CLOUDIDENTITY_USERINVITATIONS: {'name': 'Cloud Identity API - User Invitations', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
CLOUDRESOURCEMANAGER: {'name': 'Resource Manager API v3', 'version': 'v3', 'v2discovery': True},
CLOUDRESOURCEMANAGERV1: {'name': 'Resource Manager API v1', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudresourcemanager'},
@@ -405,10 +403,6 @@ _CLIENT_SCOPES = [
'subscopes': READONLY,
'roByDefault': True,
'scope': 'https://www.googleapis.com/auth/cloud-identity.policies'},
{'name': 'Cloud Identity API - Policy Beta',
'api': CLOUDIDENTITY_POLICY_BETA,
'offByDefault': True,
'scope': 'https://www.googleapis.com/auth/cloud-identity.policies'},
{'name': 'Cloud Identity API - User Invitations',
'api': CLOUDIDENTITY_USERINVITATIONS,
'subscopes': READONLY,
@@ -641,10 +635,6 @@ _SVCACCT_SCOPES = [
# 'subscopes': READONLY,
# 'roByDefault': True,
# 'scope': 'https://www.googleapis.com/auth/cloud-identity.policies'},
# {'name': 'Cloud Identity API - Policy Beta',
# 'api': CLOUDIDENTITY_POLICY_BETA,
# 'offByDefault': True,
# 'scope': 'https://www.googleapis.com/auth/cloud-identity.policies'},
# {'name': 'Cloud Identity User Invitations API',
# 'api': CLOUDIDENTITY_USERINVITATIONS,
# 'subscopes': READONLY,

View File

@@ -462,6 +462,7 @@ PLEASE_CORRECT_YOUR_SYSTEM_TIME = 'Please correct your system time.'
PLEASE_ENTER_A_OR_M = 'Please enter a or m ...\n'
PLEASE_SELECT_ENTITY_TO_PROCESS = '{0} {1} found, please select the correct one to {2} and specify with {3}'
PLEASE_SPECIFY_BUILDING_EXACT_CASE_NAME_OR_ID = 'Please specify building by exact case name or ID.'
POLICY_NAME_NOT_FOUND = 'JSON key "name" not found in JSON data'
PREVIEW_ONLY = 'Preview Only'
PRIMARY_EMAIL_DID_NOT_MATCH_PATTERN = 'primaryEmail address did not match pattern: {0}'
PROCESS = 'process'

View File

@@ -5,6 +5,8 @@
- [Definitions](#definitions)
- [Policies](#policies)
- [Display Cloud Identity Policies](#display-cloud-identity-policies)
- [Create and Update Cloud Identity Policies](#create-and-update-cloud-identity-policies)
- [Delete Cloud Identity Policies](#delete-cloud-identity-policies)
## API documentation
* [Policy API](https://cloud.google.com/identity/docs/reference/rest/v1/policies)
@@ -35,6 +37,9 @@ You must enable access to policies in the GCP cloud console.
* Click Organization Policy Administrator
* Click Save
The commands to create, update and delete Cloud Identity policies for data loss prevention (DLP) rules and detectors
were added in version `7.46.00`.
## Definitions
```
<CIPolicyName> ::= policies/<String>|settings/<String>|<String>
@@ -87,7 +92,7 @@ gam show policies
[formatjson]
```
By default, all policies are displayed.
* `filter <String>` - Display filtered policies, See https://cloud.google.com/identity/docs/reference/rest/v1beta1/policies/list
* `filter <String>` - Display filtered policies, See https://cloud.google.com/identity/docs/reference/rest/v1/policies/list
* `group <REMatchPattern>` - Only display policies whose group email address matches the `<REMatchPattern>`
* `ou|org|orgunit <REMatchPattern>` - Only display policies whose OU path matches the `<REMatchPattern>`
@@ -110,7 +115,7 @@ gam print policies [todrive <ToDriveAttribute>*]
[formatjson [quotechar <Character>]]
```
By default, all policies are displayed:
* `filter <String>` - Display filtered policies, See https://cloud.google.com/identity/docs/reference/rest/v1beta1/policies/list
* `filter <String>` - Display filtered policies, See https://cloud.google.com/identity/docs/reference/rest/v1/policies/list
* `group <REMatchPattern>` - Only display policies whose group email address matches the `<REMatchPattern>`
* `ou|org|orgunit <REMatchPattern>` - Only display policies whose OU path matches the `<REMatchPattern>`
@@ -152,3 +157,32 @@ Print all polices that apply to the OU "/Staff" and its sub-OUs.
```
gam redirect csv ./StaffPolicies.csv print policies ou "^/Staff"
```
## Create and Update Cloud Identity Policies
Policies can be complex objects, it is probably easiest to create template policies in the Admin console (under Rules),
output the JSON format data for those policies to be used in subsequent create and update commands.
```
gam create policy
json <JSONData>
[(ou|orgunit <OrgUnitItem>)|(group <GroupItem>)|(query <String>)]
gam update policy
json <JSONData>
[(ou|orgunit <OrgUnitItem>)|(group <GroupItem>)|(query <String>)]
```
```
gam redirect stdout ./policy.json info policies policies/akajj264aoclblvncu
Make changes to policy.json and update the policy.
gam update policy json file policy.json
Update the policy to reference a different group.
gam update policy json file policy.json group <EmailAddress>
Make changes to policy.json and create a new policy in a different OU.
gam create policy json file policy.json ou <OrgUnitPath>
```
## Delete Cloud Identity Policies
```
gam delete policies <CIPolicyNameEntity>
```

View File

@@ -10,6 +10,38 @@ 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.46.02
Updated `gam calendars <CalendarEntity> show settings` to display `dataOwner` field;
it is labelled `Owner`.
### 7.46.01
Fixed bug in `gam <CrOSTypeEntity> issuecommand command <CrOSCommand> ... csv` where
command execution status lines were improperly indented.
Upgraded to Python 3.14.6.
### 7.46.00
Added commands to create, update and delete Cloud Identity policies for data loss prevention (DLP) rules and detectors.
* See: https://github.com/GAM-team/GAM/wiki/Cloud-Identity-Policies
* See: https://workspaceupdates.googleblog.com/2026/06/introducing-workspace-policy-api-mutate-endpoints-for-DLP.html
### 7.45.00
Added options `isdisabled [<Boolean>]`, `disabledafter <DateTime>` and `disabledbefore <DateTime>`
to `gam print users`. These options along with `issuspended [<Boolean>]` and `isarchived [<Boolean>]`
are useful when identifying users to deprovision.
Added option `movefilepermissions [<Boolean>]]` to `gam <UserTypeEntity> move drivefile` that, when False,
causes GAM to remove ACLs from a file before moving it; this will be most useful when moving files to
Shared Drives so that only the Shared Drive ACls apply. When not specified or set True, file permissions
are not removed; this is the current GAM behavior.
Upgraded to OpenSSL 4.0.1.
### 7.44.03
Added `writerwithoutprivateaccess` to `<CalendarACLRole>`; this will become effective 2026-06-29.

View File

@@ -251,10 +251,10 @@ writes the credentials into the file oauth2.txt.
```
gamteam@server:/Users/gamteam$ rm -f /Users/gamteam/GAMConfig/oauth2.txt
gamteam@server:/Users/gamteam$ gam version
GAM 7.44.03 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.46.02 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.5 64-bit final
macOS Tahoe 26.5 arm64
Python 3.14.6 64-bit final
macOS Tahoe 26.5.1 arm64
Path: /Users/gamteam/bin/gam7
Config File: /Users/gamteam/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
@@ -1034,9 +1034,9 @@ writes the credentials into the file oauth2.txt.
```
C:\>del C:\GAMConfig\oauth2.txt
C:\>gam version
GAM 7.44.03 - https://github.com/GAM-team/GAM - pythonsource
GAM 7.46.02 - https://github.com/GAM-team/GAM - pythonsource
GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.5 64-bit final
Python 3.14.6 64-bit final
Windows 11 10.0.26200 AMD64
Path: C:\GAM7
Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com

View File

@@ -81,8 +81,8 @@ gam <UserTypeEntity> print driveactivity [todrive <ToDriveAttributes>*]
By default, drive activity for all files in the top level of My Drive will be displayed.
* `fileid <DriveFileID>` - Display drive activity for file `<DriveFileID>`
* `folderid <DriveFolderID>` - Display drive activity for all files in folder `<DriveFolderID>`
* `drivefilename <DriveFileName>` - Display drive activity for the file with name `<DriveFolderID>`
* `drivefoldername <DriveFolderName>` - Display drive activity for all files in the folder with name `<DriveFolderName>`
* `drivefilename <DriveFileName>` - Display drive activity for the file with name `<DriveFileName>`
* `drivefoldername <DriveFolderName>` - Display drive activity for all files in the folder with name `<DriveFolderName>`
* `query` - Display drive activity for all files/folders selected by the query
Activities can be filtered by time.

View File

@@ -583,6 +583,7 @@ gam <UserTypeEntity> move drivefile <DriveFileEntity> [newfilename <DriveFileNam
[copysubfolderpermissions [<Boolean>]]
[copysubfolderinheritedpermissions [<Boolean>]]
[copysubfoldernoninheritedpermissions never|always|syncallfolders|syncupdatedfolders]
[movefilepermissions [<Boolean>]]
[excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>]
(mappermissionsemail <EmailAddress> <EmailAddress)* [mappermissionsemailfile <CSVFileInput> endcsv]
(mappermissionsdomain <DomainName> <DomainName>)*
@@ -729,6 +730,8 @@ and any remaining copy errors.
### Moved File Permissions
By default, the permissions of a moved file are not modified.
When `movefilerpermissions false` is specified, all ACLs are removed.
When `excludepermissionsfromdomains <DomainNameList>` is specified, any ACL that references a domain in `<DomainNameList>` will be removed.
When `includepermissionsfromdomains <DomainNameList>` is specified, any ACLs that references a domain not in `<DomainNameList>` will be removed.

View File

@@ -535,6 +535,14 @@ User: user@domain.com, Delete maximum of 15 Other Contacts
User: user@domain.com, Other Contact: otherContacts/c6318452176100245073, Deleted
```
Bulk delete Other Contacts
Let's suppose you have a CSV file (OtherContacts.csv) with at least these two headers: User,resourceName
The file can contain multiple users and their other contacts. This is the most API effecient way to delete the contacts.
```
gam redirect stdout ./DeleteOtherContacts.txt redirect stderr stdout csvkmd users OtherContacts.csv keyfield User datafield resourceName delete othercontacts csvdata resourceName
```
## Display User Other Contacts
### Display as an indented list of keys and values.
```

View File

@@ -1122,6 +1122,10 @@ The `isarchived`, `issuspended` and `isdisabled` options can be used to select u
| isdisabled [true] | Archived or Suspended Users |
| isdisabled false | Non-Archived and Non-Suspended Users |
When none of `isarchived`, `issuspended`, `isdisabled` are specified,
but one or both of `disabledafter` or `disabledbefore` is specified,
then `isdisabled true` is selected.
When any of `isarchived [true]`, `issuspended [true]`, `isdisabled [true]` are specified,
the following options can be used to further limit the users displayed.
* `disabledafter <DateTime>` - Display users disabled on/after `<DateTime>`
@@ -1230,6 +1234,10 @@ The `isarchived`, `issuspended` and `isdisabled` options can be used to select u
| isdisabled [true] | Archived or Suspended Users |
| isdisabled false | Non-Archived and Non-Suspended Users |
When none of `isarchived`, `issuspended`, `isdisabled` are specified,
but one or both of `disabledafter` or `disabledbefore` is specified,
then `isdisabled true` is selected.
When any of `isarchived [true]`, `issuspended [true]`, `isdisabled [true]` are specified,
the following options can be used to further limit the users displayed.
* `disabledafter <DateTime>` - Display users disabled on/after `<DateTime>`

View File

@@ -376,7 +376,7 @@ For `corpus calendar`, you can specify advanced search options:
* `minuswords <StringList>`
* Matches only those events that do not contain any of the words in the given set in title, description, location, or attendees.
* Entries in the set are considered in "or".
* `responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*
* `responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*`
* Matches only events for which the custodian gave one of these responses. If the set is empty, there will be no filtering on responses.
* `calendarversiondate <Date>|<Time>`
* Search the current version of the Calendar event, but export the contents of the last version saved before 12:00 AM UTC on the specified date.

View File

@@ -3,10 +3,10 @@
Print the current version of Gam with details
```
gam version
GAM 7.44.03 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.46.02 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.5 64-bit final
macOS Tahoe 26.5 arm64
Python 3.14.6 64-bit final
macOS Tahoe 26.5.1 arm64
Path: /Users/gamteam/bin/gam7
Config File: /Users/gamteam/GamConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
Time: 2026-02-15T07:51:00-08:00
@@ -15,10 +15,10 @@ Time: 2026-02-15T07:51:00-08:00
Print the current version of Gam with details and time offset information
```
gam version timeoffset
GAM 7.44.03 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.46.02 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.5 64-bit final
macOS Tahoe 26.5 arm64
Python 3.14.6 64-bit final
macOS Tahoe 26.5.1 arm64
Path: /Users/gamteam/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
Your system time differs from www.googleapis.com by less than 1 second
@@ -27,29 +27,29 @@ 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.44.03 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.46.02 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.5 64-bit final
macOS Tahoe 26.5 arm64
Python 3.14.6 64-bit final
macOS Tahoe 26.5.1 arm64
Path: /Users/gamteam/bin/gam7
Config File: /Users/gamteam/GamConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
Time: 2026-02-15T07:51:00-08:00
Your system time differs from admin.googleapis.com by less than 1 second
OpenSSL 4.0.0 14 Apr 2026
OpenSSL 4.0.1 9 Jun 2026
arrow 1.4.0
chardet 5.2.0
cryptography 46.0.5
filelock 3.21.2
google-api-python-client 2.190.0
google-auth-httplib2 0.3.0
google-auth-oauthlib 1.2.4
google-auth 2.48.0
lxml 6.0.2
chardet 7.4.3
cryptography 48.0.0
filelock 3.29.0
google-api-python-client 2.196.0
google-auth-httplib2 0.4.0
google-auth-oauthlib 1.4.0
google-auth 2.53.0
lxml 6.1.1
httplib2 0.31.2
passlib 1.7.4
pathvalidate 3.3.1
pyscard 2.3.1
yubikey-manager 5.9.0
yubikey-manager 5.9.1
admin.googleapis.com connects using TLSv1.3 TLS_AES_256_GCM_SHA384
```
@@ -68,7 +68,7 @@ MacOS High Sierra 10.13.6 x86_64
Path: /Users/gamteam/bin/gam7
Version Check:
Current: 5.35.08
Latest: 7.44.03
Latest: 7.46.02
echo $?
1
```
@@ -76,7 +76,7 @@ echo $?
Print the current version number without details
```
gam version simple
7.44.03
7.46.02
```
In Linux/MacOS you can do:
```
@@ -86,10 +86,10 @@ echo $VER
Print the current version of Gam and address of this Wiki
```
gam help
GAM 7.44.03 - https://github.com/GAM-team/GAM
GAM 7.46.02 - https://github.com/GAM-team/GAM
GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.5 64-bit final
macOS Tahoe 26.5 arm64
Python 3.14.6 64-bit final
macOS Tahoe 26.5.1 arm64
Path: /Users/gamteam/bin/gam7
Config File: /Users/gamteam/GamConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
Time: 2026-02-15T07:51:00-08:00