Integrations and tests
This page explains how RiskFlow checks your Google Workspace for you: connecting it on the Integrations page, the Tests page that shows what was found, and how the results turn your controls red or green.
The idea in one minute
- An admin connects Google Workspace once. The connection belongs to your team, not to the person who clicked Connect, so it keeps working without anyone being signed in.
- Every night RiskFlow reads your Google security settings and runs 48 tests on them (for example, "2-step verification is enforced"). An admin can also press Run now.
- Every result is saved. Tests shows each one as passing or failing, since when, and which org units fail. The Risk Assessment page shows the same saved results; it never calls Google itself.
- Each test is linked to one or more recommended controls. A failing test turns its control Failing on Controls, and a passing one turns it Passing. That is where green and red come from, and it feeds your readiness score.
Who can do what
| Role | Integrations and tests |
|---|---|
| ORG Admin | See everything. Connect, reconnect, disconnect, Run now, excuse tests |
| ORG Auditor | See the status and the results. Read-only |
| Other ORG roles | No access to Integrations. Roles with Controls or Risk Assessment access can read the results |
Each team sees only its own integrations.
Connecting Google Workspace
- Open Integrations.
- On the Google Workspace card, select Connect.
- Sign in to Google in the pop-up with a Workspace admin account on your organization's domain, and approve the read-only access.
RiskFlow asks for read-only access only: Cloud Identity policies and organizational units. It checks that the account can read your policies before saving anything.
The card then shows Connected, your domain, and who connected it and when.
RiskFlow keeps working if the person who connected leaves RiskFlow. It stops if their Google account is suspended or deleted, because Google then rejects the saved login. Connect with a long-lived admin account.
Statuses
The card on Integrations shows one of these:
| Status | Meaning | What to do |
|---|---|---|
| Connected | Working | Nothing |
| Needs reconnect | Google rejected the saved login (password reset, account suspended, access revoked) | An admin selects Reconnect |
| Error | The last check failed for another reason | See the error on the card; it retries on the next run |
| Disconnected | You disconnected it | Select Connect to start again |
Reconnecting
If the card says Needs reconnect, Google no longer accepts the saved login. This happens when the connecting account's password was reset, the account was suspended or deleted, or someone removed RiskFlow's access in the Google Admin console.
- An admin opens Integrations and selects Reconnect.
- Sign in to Google with a Workspace admin account and approve the read-only access again.
While the card says Needs reconnect:
- the nightly run skips your team and Run now is not offered;
- the last results stay visible on Tests, but they no longer count: the linked controls go back to Not started;
- the audit log records when the connection broke.
After you reconnect, press Run now (or wait for the next night) and the controls fill in again.
The Tests page
Tests lists every test with the team's latest result, worst first. Open a test to see what it checks, how to fix it in the Google Admin console, the org units that fail, the controls it feeds, and its last 90 results.
| Result | Meaning |
|---|---|
| Passing | The setting matches best practice in every org unit |
| Failing | At least one org unit doesn't match. Shows "failing since" and which org units |
| Excused | It fails, but your team has excused it. See below |
| Error | RiskFlow couldn't tell (for example, Google returned data it couldn't read). Counts as neither passing nor failing |
| Not run yet | The test hasn't run for your team |
When the checks run
Once Google Workspace is connected, RiskFlow checks it every night on its own. An admin can also start a check at any time with Run now (once every 5 minutes per team).
- Every result is saved, so RiskFlow can say when a check started failing ("failing since Oct 3") and show the history.
- If Google can't be reached or rejects the login, that run is marked failed and nothing is overwritten: the last good results stay as they were. The card shows the error, and the next nightly run tries again.
- A check that changes between passing and failing is recorded in the audit log.
How checks turn controls red or green
Each check is linked to one or more recommended controls (for example, "2-step verification is enforced" is linked to MFA enforced). After every run, RiskFlow updates those controls:
| Latest result of a linked check | The control |
|---|---|
| Failing | Turns Failing |
| Passing, or excused | Counts it as passing |
| Error | Ignores it |
- RiskFlow only uses a result if it is less than 48 hours old and the integration is Connected. The nightly run refreshes results every 24 hours, so one missed night is fine. Otherwise the check says nothing, so a broken connection never leaves a control green (or red) by mistake. A control with nothing checking it shows Not started.
- So if the connection shows Error or Needs reconnect, its linked controls go back to Not started until the next good run.
- Controls you wrote yourself (custom controls) are never changed by checks.
- Every control status change is recorded in the audit log.
Excusing a check
Sometimes a check fails for a good reason. For example, shared kiosk devices in their own org unit can't use 2-step verification. Someone who can manage controls can excuse the check:
- for the whole check, or for one org unit only;
- with a reason (20 to 2000 characters; auditors read it, like a control's N/A reason);
- with an end date, at most 12 months away.
What happens:
- The check shows Excused when an exception covers every failing org unit. If another org unit still fails, the check stays Failing and lists only that org unit.
- An excused check counts as passing for its controls, so a control can stop being Failing right away. RiskFlow does not ask Google again; it re-reads the last result.
- When the end date passes, the next nightly run ignores the exception and the check fails again (its "failing since" date starts over).
- Removing an exception works the same way, at once.
- Adding and removing exceptions are both recorded in the audit log, with who did it and the reason.
Disconnecting
Disconnect tells Google to revoke RiskFlow's access (if Google can't be reached, RiskFlow still disconnects), erases the saved login, and records who did it in the audit log. Past results are kept, but they no longer count: controls linked to the checks go back to Not started.
If your team used the old Risk Assessment check
Earlier versions of the Risk Assessment page asked whoever opened it to sign in to Google in their own browser tab. That per-person sign-in is gone, along with the saved logins behind it. Connect Google Workspace once on Integrations. The Risk Assessment page then fills in from the saved results after the first run.
For whoever deploys RiskFlow
Saved logins are encrypted with INTEGRATION_ENCRYPTION_KEY (AES-256-GCM).
- Generate it once:
openssl rand -base64 32. - It is required in production. The API refuses to start without a valid key (32 bytes, base64), so set it on the API project before deploying this version. Locally it is only needed to connect an integration.
- Set it with the Vercel REST API or dashboard, not
vercel env addpiped non-interactively (that stores an empty value), and check the value has no trailing newline. - Do not change or lose it. Credentials encrypted with the old key can't be read with a new one; every team would have to reconnect. Keep a copy in the team password manager.
- Google OAuth must already be configured (
GOOGLE_OAUTH_CLIENT_ID,GOOGLE_OAUTH_CLIENT_SECRET,GOOGLE_OAUTH_REDIRECT_URI). The Integrations pop-up uses that client and redirect URI.
The nightly checks run from Vercel Cron (/api/v1/internal/grc-tests, every 15 minutes, in apps/backend/vercel.json). Each call checks the teams whose last run is more than 24 hours old, oldest first, and stops starting new ones after about 4 minutes, so many teams spread across several calls. It needs CRON_SECRET set on the API project, like the training reminders.
The old Risk Assessment login. The user_tokens table, which held the old per-person Google logins in plain text, was dropped by migration drop_user_tokens. A team that used the old check connects once through Integrations instead.
See ADR 008 for the design.