group_inventory_job.py is the read-only Cloud Run Job companion to the
Google Workspace Admin Assistant and HR distro check. It reuses the
assistant’s existing tenant routes, per-tenant service-account secrets, and
domain-wide delegation.
It does not change Google Groups. It reads direct membership and roles, writes actual state to columns A:B in each email-named extraction tab, and compares that membership with HR Check column C. It also publishes two long-form tabs:
_GW Actual: the current Google membership and role inventory._GW Reconciliation: match, missing_in_google, and extra_in_google
results against the HR-backed column C lists. HR does not define Google
roles, so role drift is deliberately not inferred from the HR check.Each group tab ends its Google inventory in column A with a Last updated on
bold timestamp in Eastern time after two blank rows. Column C independently
ends with the HR sync’s own timestamp using the same spacing and emphasis,
making the freshness of both sources visible.
If any group or tenant fails, the job exits nonzero and changes no sheet output. Writing is disabled by default.
workspace.py for tenant routing and
service-account secrets, but mint a narrower delegated token containing
only admin.directory.group.member.readonly.sheets.googleapis.com in the gw-admin-assistant project.GROUP_INVENTORY_WRITE_ENABLED=true.This keeps central-sheet write access separate from tenant Directory access.
The job uses the assistant’s existing variables:
GW_ROUTES_SECRETGW_ROUTE_SA_SECRET_OVERRIDES when applicableGOOGLE_CLOUD_PROJECTJob-specific variables:
| Variable | Required | Purpose |
|---|---|---|
DESTINATION_SPREADSHEET_ID |
Yes | Extraction workbook ID. |
GROUP_INVENTORY_WRITE_ENABLED |
No | Defaults to false. Set true only after dry-run review. |
GROUP_INVENTORY_INCLUDE_DERIVED |
No | Defaults to false, matching direct Admin Console membership. |
GROUP_TARGETS_JSON |
For writes | Explicit groups. Required in write mode; dry runs may otherwise discover every email-named tab. |
LOG_LEVEL |
No | Defaults to INFO. |
Optional explicit target examples:
[
"staff@example.org",
{
"group": "employees@other.org",
"workspace": "other-prod"
}
]
Use the explicit workspace override only when the group-address domain does
not uniquely resolve through the existing route table.
Automatic discovery is allowed only in dry-run mode and inventories every
email-named tab, including tabs the HR sync intentionally ignores. Publishing
always requires GROUP_TARGETS_JSON, preventing a new or legacy tab from
silently entering the write scope. Reconciliation is against the post-HR-sync
column C values, not directly against the Active EE tab, so schedule this job
after the HR sync.
Deploy this as a separate job in the existing gw-admin-assistant project.
Use the same runtime service account and route-secret environment as the
assistant, plus the destination spreadsheet ID. Start with only the 11th Hour
and Hyperion groups and keep writes disabled. From this integration directory:
First, share the extraction workbook as Editor with
1039144753775-compute@developer.gserviceaccount.com. Viewer is sufficient for
the dry run, but Editor is required for the later A:B pilot; granting Editor
once avoids a second permissions change.
Copy-Item group_inventory_pilot.env.yaml.example group_inventory_pilot.env.yaml
# Replace REPLACE_WITH_EXTRACTION_SPREADSHEET_ID in the copied file.
gcloud.cmd run jobs deploy google-workspace-group-inventory `
--project gw-admin-assistant `
--region us-central1 `
--source . `
--command python `
--args group_inventory_job.py `
--service-account 1039144753775-compute@developer.gserviceaccount.com `
--env-vars-file group_inventory_pilot.env.yaml
Preserve the assistant’s GW_ROUTE_SA_SECRET_OVERRIDES value if the target
list includes its sandbox route. Then execute and inspect logs:
gcloud.cmd run jobs execute google-workspace-group-inventory `
--project gw-admin-assistant `
--region us-central1 `
--wait
The dry-run summary contains counts only; it does not log the membership roster. Resolve every tenant/group error before enabling publishing.
Published runs maintain a _GW Status dashboard with one row per managed
group tab. It records the latest attempt, last successful refresh, Google and
HR counts, difference count, and a short actionable status. Managed group tabs
use the same health colors:
On a partial tenant failure, successful group tabs are updated atomically while the failed tab’s A:B values and prior success metadata are preserved. The status dashboard and tab colors are still updated, and the Cloud Run execution exits non-zero so operations can alert on the degraded run.
After a clean dry run:
GROUP_INVENTORY_WRITE_ENABLED=true.Do not add Directory write scopes or group mutation calls to this job. Any future enforcement workflow needs a separate approval and design review.