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: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with: with:
persist-credentials: false persist-credentials: false
fetch-depth: 0 fetch-depth: 0
@@ -165,7 +165,7 @@ jobs:
with: with:
path: | path: |
cache.tar.xz cache.tar.xz
key: gam-${{ matrix.jid }}-20260609 key: gam-${{ matrix.jid }}-20260611
- name: Untar Cache archive - name: Untar Cache archive
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true' if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
@@ -529,18 +529,6 @@ jobs:
echo "gam=${gam}" >> $GITHUB_ENV echo "gam=${gam}" >> $GITHUB_ENV
fi 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 - name: Install pip requirements
env: env:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
@@ -550,8 +538,12 @@ jobs:
# https://github.com/pyca/cryptography/issues/14293 # https://github.com/pyca/cryptography/issues/14293
gh release download --repo "jay0lee/cryptography-wheels" --pattern "*win_arm64.whl" --clobber gh release download --repo "jay0lee/cryptography-wheels" --pattern "*win_arm64.whl" --clobber
"$PYTHON" -m pip install cryptography-*.whl "$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 fi
"$PYTHON" -m pip install -vvv --upgrade ..[yubikey] "$PYTHON" -m pip install ..[yubikey]
- name: Install PyInstaller - name: Install PyInstaller
if: matrix.goal == 'build' if: matrix.goal == 'build'
@@ -1121,7 +1113,7 @@ jobs:
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with: with:
persist-credentials: false persist-credentials: false
fetch-depth: 0 fetch-depth: 0

View File

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

View File

@@ -14,7 +14,7 @@ jobs:
check-certs: check-certs:
runs-on: ubuntu-slim runs-on: ubuntu-slim
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with: with:
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token 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 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 git clone https://github.com/GAM-team/GAM
- name: Checkout Wiki source - name: Checkout Wiki source
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0 uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with: with:
path: GAM.wiki path: GAM.wiki
repository: GAM-team/GAM.wiki repository: GAM-team/GAM.wiki

View File

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

View File

@@ -15,20 +15,25 @@ jobs:
steps: steps:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Python - name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with: with:
python-version: '3.14' 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 - name: Calculate and pin two-week old stable versions
shell: python shell: python
run: | run: |
import json import subprocess
import urllib.request
import re import re
import tomllib import tomllib
import os
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from pathlib import Path from pathlib import Path
@@ -42,14 +47,10 @@ jobs:
target_deps = set() target_deps = set()
# Standard [project.dependencies] # Gather all dependencies
target_deps.update(parsed_toml.get("project", {}).get("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(): for deps in parsed_toml.get("project", {}).get("optional-dependencies", {}).values():
target_deps.update(deps) target_deps.update(deps)
# Dev [dependency-groups] (uv / PEP 735 standard)
for deps in parsed_toml.get("dependency-groups", {}).values(): for deps in parsed_toml.get("dependency-groups", {}).values():
if isinstance(deps, list): if isinstance(deps, list):
for d in deps: for d in deps:
@@ -60,73 +61,80 @@ jobs:
print("No dependencies found to process.") print("No dependencies found to process.")
exit(0) exit(0)
updates = {} # 1. Create a "clean" requirements list (base names + markers only, no versions)
two_weeks_ago = datetime.now(timezone.utc) - timedelta(days=14) clean_reqs = []
print(f"Evaluating dependencies against cutoff date: {two_weeks_ago.isoformat()}")
for dep in target_deps: for dep in target_deps:
# Isolate base package name (e.g., "yubikey-manager>=5.6.1" -> "yubikey-manager") pkg_base = re.split(r'[<>=!~;\s]', dep)[0].strip()
pkg_name = 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 = "" marker = ""
if ";" in dep: if ";" in dep:
marker = " ; " + dep.split(";", 1)[1].strip() marker = " ; " + dep.split(";", 1)[1].strip()
print(f"Fetching PyPI data for: {pkg_name}") if pkg_name_lower in resolved_versions:
try: target_version = resolved_versions[pkg_name_lower]
url = f"https://pypi.org/pypi/{pkg_name}/json" pinned_dep = f"{pkg_name_raw}=={target_version}{marker}"
req = urllib.request.Request(url, headers={'User-Agent': 'GAM-CI-Script'})
with urllib.request.urlopen(req) as response:
data = json.loads(response.read().decode())
valid_versions = [] if pinned_dep != dep:
for ver, files in data.get("releases", {}).items(): updates[dep] = pinned_dep
if not files: print(f" -> Changing: '{dep}' => '{pinned_dep}'")
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}")
else: else:
print(f" -> No valid historical versions found.") print(f" -> Up to date: {dep}")
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}")
# 3. Replace the strings safely in the original file content # 6. Replace the strings safely in the original file content
new_content = content new_content = content
for old_dep, new_dep in updates.items(): 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) escaped_old = re.escape(old_dep)
pattern = r'([\'"])' + escaped_old + r'\1' pattern = r'([\'"])' + escaped_old + r'\1'
new_content = re.sub(pattern, lambda m: m.group(1) + new_dep + m.group(1), new_content) 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: if content != new_content:
toml_path.write_text(new_content, encoding="utf-8") toml_path.write_text(new_content, encoding="utf-8")
print("\npyproject.toml updated successfully.") print("\npyproject.toml updated successfully.")
@@ -139,6 +147,6 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "chore: upgrade PyPi deps" commit-message: "chore: upgrade PyPi deps"
title: "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 branch: sys-deps-upgrade
force: false # Standard push, plays nice with rulesets 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 = [ dependencies = [
"arrow==1.4.0", "arrow==1.4.0",
"chardet==7.4.3", "chardet==7.4.3",
"cryptography==48.0.0", "cryptography==48.0.1",
"distro==1.9.0 ; sys_platform=='linux'", "distro==1.9.0 ; sys_platform=='linux'",
"filelock==3.29.0", "filelock==3.29.4",
"google-api-python-client==2.196.0", "google-api-python-client==2.197.0",
"google-auth-httplib2==0.4.0", "google-auth-httplib2==0.4.0",
"google-auth-oauthlib==1.4.0", "google-auth-oauthlib==1.4.0",
"google-auth==2.53.0", "google-auth==2.54.0",
"httplib2==0.31.2", "httplib2==0.31.2",
"lxml==6.1.1", "lxml==6.1.1",
"passlib==1.7.4", "passlib==1.7.4",

View File

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

View File

@@ -51,7 +51,6 @@ CLOUDIDENTITY_INBOUND_SSO = 'cloudidentityinboundsso'
CLOUDIDENTITY_ORGUNITS = 'cloudidentityorgunits' CLOUDIDENTITY_ORGUNITS = 'cloudidentityorgunits'
CLOUDIDENTITY_ORGUNITS_BETA = 'cloudidentityorgunitsbeta' CLOUDIDENTITY_ORGUNITS_BETA = 'cloudidentityorgunitsbeta'
CLOUDIDENTITY_POLICY = 'cloudidentitypolicy' CLOUDIDENTITY_POLICY = 'cloudidentitypolicy'
CLOUDIDENTITY_POLICY_BETA = 'cloudidentitypolicybeta'
CLOUDIDENTITY_USERINVITATIONS = 'cloudidentityuserinvitations' CLOUDIDENTITY_USERINVITATIONS = 'cloudidentityuserinvitations'
CLOUDRESOURCEMANAGER = 'cloudresourcemanager' CLOUDRESOURCEMANAGER = 'cloudresourcemanager'
CLOUDRESOURCEMANAGERV1 = 'cloudresourcemanagerv1' CLOUDRESOURCEMANAGERV1 = 'cloudresourcemanagerv1'
@@ -261,7 +260,6 @@ _INFO = {
CLOUDIDENTITY_ORGUNITS: {'name': 'Cloud Identity API - OrgUnits', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, 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_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: {'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'}, CLOUDIDENTITY_USERINVITATIONS: {'name': 'Cloud Identity API - User Invitations', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'},
CLOUDRESOURCEMANAGER: {'name': 'Resource Manager API v3', 'version': 'v3', 'v2discovery': True}, CLOUDRESOURCEMANAGER: {'name': 'Resource Manager API v3', 'version': 'v3', 'v2discovery': True},
CLOUDRESOURCEMANAGERV1: {'name': 'Resource Manager API v1', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudresourcemanager'}, CLOUDRESOURCEMANAGERV1: {'name': 'Resource Manager API v1', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudresourcemanager'},
@@ -405,10 +403,6 @@ _CLIENT_SCOPES = [
'subscopes': READONLY, 'subscopes': READONLY,
'roByDefault': True, 'roByDefault': True,
'scope': 'https://www.googleapis.com/auth/cloud-identity.policies'}, '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', {'name': 'Cloud Identity API - User Invitations',
'api': CLOUDIDENTITY_USERINVITATIONS, 'api': CLOUDIDENTITY_USERINVITATIONS,
'subscopes': READONLY, 'subscopes': READONLY,
@@ -641,10 +635,6 @@ _SVCACCT_SCOPES = [
# 'subscopes': READONLY, # 'subscopes': READONLY,
# 'roByDefault': True, # 'roByDefault': True,
# 'scope': 'https://www.googleapis.com/auth/cloud-identity.policies'}, # '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', # {'name': 'Cloud Identity User Invitations API',
# 'api': CLOUDIDENTITY_USERINVITATIONS, # 'api': CLOUDIDENTITY_USERINVITATIONS,
# 'subscopes': READONLY, # '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_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_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.' 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' PREVIEW_ONLY = 'Preview Only'
PRIMARY_EMAIL_DID_NOT_MATCH_PATTERN = 'primaryEmail address did not match pattern: {0}' PRIMARY_EMAIL_DID_NOT_MATCH_PATTERN = 'primaryEmail address did not match pattern: {0}'
PROCESS = 'process' PROCESS = 'process'

View File

@@ -5,6 +5,8 @@
- [Definitions](#definitions) - [Definitions](#definitions)
- [Policies](#policies) - [Policies](#policies)
- [Display Cloud Identity Policies](#display-cloud-identity-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 ## API documentation
* [Policy API](https://cloud.google.com/identity/docs/reference/rest/v1/policies) * [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 Organization Policy Administrator
* Click Save * 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 ## Definitions
``` ```
<CIPolicyName> ::= policies/<String>|settings/<String>|<String> <CIPolicyName> ::= policies/<String>|settings/<String>|<String>
@@ -87,7 +92,7 @@ gam show policies
[formatjson] [formatjson]
``` ```
By default, all policies are displayed. 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>` * `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>` * `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>]] [formatjson [quotechar <Character>]]
``` ```
By default, all policies are displayed: 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>` * `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>` * `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" 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 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 ### 7.44.03
Added `writerwithoutprivateaccess` to `<CalendarACLRole>`; this will become effective 2026-06-29. 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$ rm -f /Users/gamteam/GAMConfig/oauth2.txt
gamteam@server:/Users/gamteam$ gam version 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> GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.5 64-bit final Python 3.14.6 64-bit final
macOS Tahoe 26.5 arm64 macOS Tahoe 26.5.1 arm64
Path: /Users/gamteam/bin/gam7 Path: /Users/gamteam/bin/gam7
Config File: /Users/gamteam/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com 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:\>del C:\GAMConfig\oauth2.txt
C:\>gam version 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> 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 Windows 11 10.0.26200 AMD64
Path: C:\GAM7 Path: C:\GAM7
Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com 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. 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>` * `fileid <DriveFileID>` - Display drive activity for file `<DriveFileID>`
* `folderid <DriveFolderID>` - Display drive activity for all files in folder `<DriveFolderID>` * `folderid <DriveFolderID>` - Display drive activity for all files in folder `<DriveFolderID>`
* `drivefilename <DriveFileName>` - Display drive activity for the file with name `<DriveFolderID>` * `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>` * `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 * `query` - Display drive activity for all files/folders selected by the query
Activities can be filtered by time. Activities can be filtered by time.

View File

@@ -583,6 +583,7 @@ gam <UserTypeEntity> move drivefile <DriveFileEntity> [newfilename <DriveFileNam
[copysubfolderpermissions [<Boolean>]] [copysubfolderpermissions [<Boolean>]]
[copysubfolderinheritedpermissions [<Boolean>]] [copysubfolderinheritedpermissions [<Boolean>]]
[copysubfoldernoninheritedpermissions never|always|syncallfolders|syncupdatedfolders] [copysubfoldernoninheritedpermissions never|always|syncallfolders|syncupdatedfolders]
[movefilepermissions [<Boolean>]]
[excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>] [excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>]
(mappermissionsemail <EmailAddress> <EmailAddress)* [mappermissionsemailfile <CSVFileInput> endcsv] (mappermissionsemail <EmailAddress> <EmailAddress)* [mappermissionsemailfile <CSVFileInput> endcsv]
(mappermissionsdomain <DomainName> <DomainName>)* (mappermissionsdomain <DomainName> <DomainName>)*
@@ -729,6 +730,8 @@ and any remaining copy errors.
### Moved File Permissions ### Moved File Permissions
By default, the permissions of a moved file are not modified. 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 `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. 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 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 User Other Contacts
### Display as an indented list of keys and values. ### 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 [true] | Archived or Suspended Users |
| isdisabled false | Non-Archived and Non-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, When any of `isarchived [true]`, `issuspended [true]`, `isdisabled [true]` are specified,
the following options can be used to further limit the users displayed. the following options can be used to further limit the users displayed.
* `disabledafter <DateTime>` - Display users disabled on/after `<DateTime>` * `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 [true] | Archived or Suspended Users |
| isdisabled false | Non-Archived and Non-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, When any of `isarchived [true]`, `issuspended [true]`, `isdisabled [true]` are specified,
the following options can be used to further limit the users displayed. the following options can be used to further limit the users displayed.
* `disabledafter <DateTime>` - Display users disabled on/after `<DateTime>` * `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>` * `minuswords <StringList>`
* Matches only those events that do not contain any of the words in the given set in title, description, location, or attendees. * 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". * 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. * 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>` * `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. * 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 Print the current version of Gam with details
``` ```
gam version 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> GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.5 64-bit final Python 3.14.6 64-bit final
macOS Tahoe 26.5 arm64 macOS Tahoe 26.5.1 arm64
Path: /Users/gamteam/bin/gam7 Path: /Users/gamteam/bin/gam7
Config File: /Users/gamteam/GamConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com Config File: /Users/gamteam/GamConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
Time: 2026-02-15T07:51:00-08:00 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 Print the current version of Gam with details and time offset information
``` ```
gam version timeoffset 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> GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.5 64-bit final Python 3.14.6 64-bit final
macOS Tahoe 26.5 arm64 macOS Tahoe 26.5.1 arm64
Path: /Users/gamteam/bin/gam7 Path: /Users/gamteam/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com 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 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 Print the current version of Gam with extended details and SSL information
``` ```
gam version extended 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> GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.5 64-bit final Python 3.14.6 64-bit final
macOS Tahoe 26.5 arm64 macOS Tahoe 26.5.1 arm64
Path: /Users/gamteam/bin/gam7 Path: /Users/gamteam/bin/gam7
Config File: /Users/gamteam/GamConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com Config File: /Users/gamteam/GamConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
Time: 2026-02-15T07:51:00-08:00 Time: 2026-02-15T07:51:00-08:00
Your system time differs from admin.googleapis.com by less than 1 second 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 arrow 1.4.0
chardet 5.2.0 chardet 7.4.3
cryptography 46.0.5 cryptography 48.0.0
filelock 3.21.2 filelock 3.29.0
google-api-python-client 2.190.0 google-api-python-client 2.196.0
google-auth-httplib2 0.3.0 google-auth-httplib2 0.4.0
google-auth-oauthlib 1.2.4 google-auth-oauthlib 1.4.0
google-auth 2.48.0 google-auth 2.53.0
lxml 6.0.2 lxml 6.1.1
httplib2 0.31.2 httplib2 0.31.2
passlib 1.7.4 passlib 1.7.4
pathvalidate 3.3.1 pathvalidate 3.3.1
pyscard 2.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 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 Path: /Users/gamteam/bin/gam7
Version Check: Version Check:
Current: 5.35.08 Current: 5.35.08
Latest: 7.44.03 Latest: 7.46.02
echo $? echo $?
1 1
``` ```
@@ -76,7 +76,7 @@ echo $?
Print the current version number without details Print the current version number without details
``` ```
gam version simple gam version simple
7.44.03 7.46.02
``` ```
In Linux/MacOS you can do: In Linux/MacOS you can do:
``` ```
@@ -86,10 +86,10 @@ echo $VER
Print the current version of Gam and address of this Wiki Print the current version of Gam and address of this Wiki
``` ```
gam help 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> GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.5 64-bit final Python 3.14.6 64-bit final
macOS Tahoe 26.5 arm64 macOS Tahoe 26.5.1 arm64
Path: /Users/gamteam/bin/gam7 Path: /Users/gamteam/bin/gam7
Config File: /Users/gamteam/GamConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com Config File: /Users/gamteam/GamConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
Time: 2026-02-15T07:51:00-08:00 Time: 2026-02-15T07:51:00-08:00