diff --git a/docs/google-setup.md b/docs/google-setup.md index 51821cd..f212e72 100644 --- a/docs/google-setup.md +++ b/docs/google-setup.md @@ -164,10 +164,12 @@ Done for Red Hawk on 2026-09-28. Four parts, in this order. - `https://www.googleapis.com/auth/admin.directory.user.readonly` (step 6) — check each RHR Email is a real account; `admin.directory.user` (step 7) to suspend or restore one after an admin approves it - - `https://www.googleapis.com/auth/admin.directory.rolemanagement.readonly` - (step 8) — to report who holds Groups Admin and Help Desk Admin. - Read-only: only a Super Admin can grant those roles, so hawk-mod reports - and a person acts + + Step 8 adds no scope. It was to have added + `admin.directory.rolemanagement.readonly`, to report who holds which + admin role, but Google lets only a Super Admin read that; step 8 puts + Help Desk Admin on a group instead, which the group scopes already reach + (re-scoped 2026-10-02, `lifecycle-sync.md`). 3. **An account to act as, with a narrow role.** hawk-mod acts as `hawk-mod@redhawkrobotics.org`, so every change it makes appears in the diff --git a/docs/lifecycle-sheet.md b/docs/lifecycle-sheet.md index 12c1aff..4e8a2ef 100644 --- a/docs/lifecycle-sheet.md +++ b/docs/lifecycle-sheet.md @@ -153,12 +153,12 @@ A mentor joins Google Groups and is invited to Slack only once their CORI is cur ### `Mentor_Admin_Roles` (PK: `Person ID`, one row per delegated admin role held) -| Column | Notes | -| ---------- | ----------------------------------------------------------------- | -| Person ID | | -| Admin Role | Dropdown (`Reference_Lists!B`): `Groups Admin`, `Help Desk Admin` | +| Column | Notes | +| ---------- | ------------------------------------------------- | +| Person ID | | +| Admin Role | Dropdown (`Reference_Lists!B`): `Help Desk Admin` | -Only add a row for someone who is actually granted a delegated admin role — most mentors don't get one. **Super Admin is intentionally not tracked here** — it's managed directly in Google Workspace, not via this sheet. +Only add a row for someone who should hold a delegated admin role — most mentors don't get one. **Help Desk Admin is the only one** (decided 2026-10-02): it comes with membership of a security group, which hawk-mod keeps in line with this tab once an administrator clicks, for Active Mentors whose CORI is current. `Groups Admin` is no longer given out, because group membership comes from this sheet. **Super Admin is intentionally not tracked here** — it's managed directly in Google Workspace, not via this sheet. ### `Student_Details` (PK: `Person ID`, one row per student) @@ -227,7 +227,7 @@ One column per dropdown, values top-to-bottom. This is the **only** place free-t | Column | Backs | Values | | ---------------------------- | ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | A — Roles | `People_Roles.Role` | Mentor, Volunteer, Alumni, Student | -| B — Admin Roles | `Mentor_Admin_Roles.Admin Role` | Groups Admin, Help Desk Admin | +| B — Admin Roles | `Mentor_Admin_Roles.Admin Role` | Help Desk Admin | | C — Relationship | `Emergency_Contacts.Relationship` | Parent/Guardian, Grandparent, Spouse, Sibling, Friend, Other | | D — Active/Inactive | `People.Active/Inactive` | Active, Inactive | | E — Y/N | Mentor Lead, RA, Student Lead columns | Y, N | @@ -257,7 +257,7 @@ One column per dropdown, values top-to-bottom. This is the **only** place free-t 2. If genuinely new, generate the next `Person ID` and add a `People` row, including `Rookie Year`. Emergency contact info for mentors goes in `Emergency_Contacts`, not on the `People` row. 3. Add a `People_Roles` row: `Role = Mentor`. 4. Agree the mentor's `@redhawkrobotics.org` address with them (not everyone wants `firstname@`), and add a `Mentor_Details` row with it as `RHR Email`. hawk-mod then asks, in the onboarding channel, for a Super Admin to create the Google account at that address; the request closes once the account exists. If the address is not agreed yet, leave `RHR Email` blank and hawk-mod asks for both. Fill in each requirement date as it's completed (blank = not started yet): `YPT Expiry`, `Background Screening Expiry`, `CORI Expiry`, `Consent & Release Expiry`, `Data Privacy Expiry` (each copied from FIRST or the state, never calculated), and `Mentor Ready Completed` (the date the badge was earned). `RHR Media Release Completed` is the date the one-time form was done; set `Media Release Scope` from what they selected on that form. Set `Mentor Lead (Y/N)` and `RA (Y/N)` — both default to `N` unless told otherwise; `RA` is a manual judgment call, not derived from anything else. Leave `Slack User ID` blank — hawk-mod fills it in. The mentor joins Google Groups and is invited to Slack only once their CORI is current; hawk-mod posts the invite request then. -5. Only add a `Mentor_Admin_Roles` row if they're granted a delegated admin role — most mentors don't get one. +5. Only add a `Mentor_Admin_Roles` row if they should help with password resets (`Help Desk Admin`) — most mentors don't get one. ### New volunteer diff --git a/docs/lifecycle-sync.md b/docs/lifecycle-sync.md index 30dad88..db4c443 100644 --- a/docs/lifecycle-sync.md +++ b/docs/lifecycle-sync.md @@ -6,7 +6,8 @@ first apply on 2026-09-28 (#25–#28), the Google Groups since the same day (#38–#42); all three are checked hourly. Onboarding requests, the welcome and the safety net (step 6) have run hourly since 2026-09-29 (#45–#50), and offboarding (step 7) since 2026-09-29 (#54–#57), tested end to end on -2026-09-30. Step 8, the admin roles report, is next. The scope was settled with Rachel Moore on 2026-09-25 and 26. The big picture +2026-09-30. Step 8, Help Desk Admin through a group, was re-scoped on +2026-10-02 and is next. The scope was settled with Rachel Moore on 2026-09-25 and 26. The big picture below was rewritten on 2026-09-27, after a first step 3 design showed it had never been written down; it replaces the earlier "direction of truth" section. @@ -32,15 +33,15 @@ Decided 2026-09-27. ### Where each fact lives -| Fact | Source of truth | Who changes it | What hawk-mod does | -| ------------------------------------------------------------------ | ----------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | -| Who a person is: role, Active/Inactive, requirement dates, consent | **The sheet** | `grp-ra`, and the Super Admins (Dan, Ty, Rachel) | Reads it. Writes back only a Slack User ID | -| Whether someone has a Slack account | **Slack** | A human invites or deactivates (no API on Slack Pro) | Compares with the sheet; prompts a human | -| Whether someone has a Google account | **Google** | A human creates it | Suspends or un-suspends, only after a click | -| Delegated admin roles | **Google** | A Super Admin only | Reports what differs from the sheet | -| Google Group and Slack user group membership | **Copies of the sheet** | hawk-mod | Google: adds automatically, removes someone leaving after a click. Slack: every change after a click | -| Who is monitored, and as what | **hawk-mod's database** | hawk-mod adds; a person ends | Adds on its own; ends only after a click | -| Messages, findings, history | **hawk-mod's database** | hawk-mod | Records | +| Fact | Source of truth | Who changes it | What hawk-mod does | +| ------------------------------------------------------------------ | --------------------------------- | ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | +| Who a person is: role, Active/Inactive, requirement dates, consent | **The sheet** | `grp-ra`, and the Super Admins (Dan, Ty, Rachel) | Reads it. Writes back only a Slack User ID | +| Whether someone has a Slack account | **Slack** | A human invites or deactivates (no API on Slack Pro) | Compares with the sheet; prompts a human | +| Whether someone has a Google account | **Google** | A human creates it | Suspends or un-suspends, only after a click | +| Delegated admin roles | **The sheet**, carried by a group | `grp-ra` and the Super Admins (the sheet); an RA's or Super Admin's click (the group) | Keeps the role's group in line with the sheet, every change on a click; reports any other admin | +| Google Group and Slack user group membership | **Copies of the sheet** | hawk-mod | Google: adds automatically, removes someone leaving after a click. Slack: every change after a click | +| Who is monitored, and as what | **hawk-mod's database** | hawk-mod adds; a person ends | Adds on its own; ends only after a click | +| Messages, findings, history | **hawk-mod's database** | hawk-mod | Records | ### How data flows @@ -224,7 +225,7 @@ name or form version is stored; the paper forms are the record. | D | Keep computed Google Groups right | join auto, leave on click | `grp-mentors`, `grp-students`, `grp-volunteers`, `grp-parents`, `grp-alumni`, `grp-mentor-leads`, `grp-student-leads`, `grp-all-team`, `grp-ra` | | E | Copy chosen groups to Slack | every change on click | Slack user groups, via `slack/groupAdmin.ts` | | F | ~~Create Workspace accounts~~ | **out of scope** | done by hand; H prompts for it | -| G | Delegated admin roles report | **report only** | Super Admin makes each change; hawk-mod lists what differs from `Mentor_Admin_Roles` | +| G | Help Desk Admin through a group | every change on click | a security group carrying Help Desk Admin, computed from `Mentor_Admin_Roles`; any other admin reported | | H | Onboarding prompts | prompt | `onboarding-channel` (`#bot-onboarding-requests`): Google accounts to create, Slack invites; a count in the morning report | | I | Offboarding / reactivation prompts | on click | end monitoring, Google suspension, Slack deactivation reminder | @@ -396,8 +397,9 @@ that could be taken away, each gated on `administrator()` and recorded: - **Suspend Google account** (step 7). Plus reminders for what hawk-mod cannot do itself: an admin deactivates them -in Slack (manual on Pro), and a Super Admin revokes any delegated admin role -(G reports it). The buttons are independent — ending monitoring and removing +in Slack (manual on Pro). From step 8, Help Desk Admin comes with a group, +so **Remove from groups** takes it away too; any other admin role is reported +for a Super Admin to remove. The buttons are independent — ending monitoring and removing access are different decisions. Inactive → Active raises the reverse: un-suspend, with a reminder to restore roles; monitoring and group membership resume on their own, because they only add. @@ -447,7 +449,6 @@ scoped to: - Sheets (read, plus write for B) - Directory: groups and group members (D) - Directory: users (read, plus suspend for I) -- Directory: role management, read-only (G) The service account must be added to the shared drive holding the sheet, as a writer. Groups that hold students or volunteers must allow external members. @@ -726,12 +727,87 @@ group` refusing copies, the leaving buttons reaching Slack, and the Built as planned, with one difference: the privilege above. -8. **Delegated admin roles (G).** **Report only** (decided 2026-09-26). Only a - Super Admin can grant Groups Admin or Help Desk Admin, and the access plan - keeps Super Admin to three named people — so `hawk-mod@` is never one. - hawk-mod posts the differences from `Mentor_Admin_Roles` as actions - ("grant Help Desk Admin to P0012") for a Super Admin to do by hand. - _Verify:_ the diff is pure and tested; nothing is ever granted. +8. **Help Desk Admin through a group (G).** Re-scoped with Rachel on + 2026-10-02; this replaces the 2026-09-26 "report only" plan, which turned + out to need something Google does not offer. Google lets only a Super + Admin see who holds which admin role, and its privilege list has nothing + a custom role could hold to change that — so `hawk-mod@` could never + have read the assignments it was to report on. + + **What it is for.** Three Super Admins (Dan, Ty, Rachel) run Google, and + a few more people should be able to help with **password resets**. Three + things must hold: + + - someone who is meant to have that power has it; + - someone who should no longer have it, does not; + - someone who leaves and comes back does not come back with a power + nobody meant to give them again. + + Decided 2026-10-02: + + - **Help Desk Admin is the only delegated role.** It resets the passwords + of non-admin accounts, which means it can sign in as any mentor, so it + is treated like access to the mentor groups. **Groups Admin is not + given out**: who is in which group is the sheet's job — hawk-mod edits + the nine computed groups as `hawk-mod@`, and the person clicking needs + no Google power at all — and the other groups are run by their own + owners and managers. `Groups Admin` leaves `Mentor_Admin_Roles`'s + dropdown and `ADMIN_ROLES`, and a row still naming it is a sheet + problem, reported by Person ID. + - **The role is carried by a group.** A Super Admin assigns Help Desk + Admin once, to a new **security group** (Google does not allow Super + Admin on a group, which is why the three stay as they are). Whoever is + in the group holds the role; whoever leaves it loses it. hawk-mod then + needs nothing it does not already have: it reads group membership + today, and never has to read Google's role assignments. + - **The group is computed from the sheet**: Active Mentors with a + `Help Desk Admin` row on `Mentor_Admin_Roles` and **CORI current** + (`mayHaveAccess`, the mentor groups' gate — not the full screening). + - **The group is `grp-helpdesk`**, a new group found by its Directory + ID like the other nine. + - **Every change is a click**, like the Slack copies (step 5): one + finding saying what differs, re-read at the click, so a person stands + between a sheet edit and admin power. The click is accepted only from + an RA — someone the sheet puts in `grp-ra` — or a Google Super Admin, + each checked at the click, and only from a Slack admin, like every + button. Not from every Slack admin: the group resets passwords. RAs + already hold the whole sheet, which is more than this. No second + person is required, even for adding oneself (decided 2026-10-02). + Someone leaving is taken out by their own **Remove from groups**, as + from every other group. Coming back, they rejoin only if their + `Mentor_Admin_Roles` row is still there, and only on that click. + - **Any other admin is reported.** An account Google flags as an admin + (`isAdmin` / `isDelegatedAdmin`, which `hawk-mod@` already reads) that + is not one of the Super Admins, not `hawk-mod@`, and not in the Help + Desk group holds a role nobody wrote down — one a Super Admin gave a + person directly. One warning per account. Each Super Admin is warned + about once and acknowledged, so a fourth is news, with no list of + names kept in code. + - **Slack administrators are a separate step**, after this one, and the + same three questions apply to them. Rachel expects Slack admins and + RAs to end up the same people, though nothing says so yet; if that + becomes the rule, that step needs no new sheet column — it reports any + Slack admin who is not an RA, and any RA who is not a Slack admin. + + To prove before anything depends on it — a privilege is only proven by + a real call (step 7's lesson): + + - **Can `hawk-mod@` change the members of a group that carries an admin + role?** Google may keep that to Super Admins. If it does, the click + cannot work as `hawk-mod@`, and only a Super Admin can make the change, + by hand in the Admin console or by hawk-mod acting as the Super Admin + who clicked — either way an RA could no longer apply it, so the rule + above would need revisiting. + - **Does Google flag a member of the group as `isDelegatedAdmin`?** If + it does, step 7 already offers them no Suspend, and their leaving + alert's Remove from groups is what clears the way. + - **The security label cannot be taken off a group**, so the group is a + new one, never an existing group relabelled. + + _Verify:_ the plan is pure and tested; nothing joins or leaves the group + without a click; Remove from groups takes the role away; a returning + person gets it back only by the click. + 9. **`/config` controls.** "Sync now" and the last run's result on the web page, alongside the Slack command. @@ -933,8 +1009,8 @@ leaving (Inactive, not a Mentor, CORI lapsed), takes someone out. them. The prebuilt role that can, User Management Admin, can also _delete_ accounts, which this plan never does. If someone other than the Super Admins should create accounts, the narrower option is a custom role with - only the "create users" privilege, added to the access plan and to - `ADMIN_ROLES` so step 8 reports it. + only the "create users" privilege, added to the access plan; step 8 + reports anyone holding it as an admin the sheet does not account for. - The account hawk-mod acts as in Google is `hawk-mod@redhawkrobotics.org` (created 2026-09-26, no admin roles). **Decided 2026-09-28:** a custom admin