Skip to main content

Evidence: the daily job

For whoever deploys RiskFlow. Most evidence is re-checked the moment something changes. A few things only change with the clock (an expiry date, a grace period, a due date), so one job runs every day to catch them. What the checks mean for users is in Evidence.

What it is​

PathGET /api/v1/internal/grc-evidence
WhenDaily at 05:00 UTC. Set under crons in apps/backend/vercel.json
NeedsCRON_SECRET on the API project (riskflow-api). Vercel sends it as Authorization: Bearer <secret>. Without it the call gets a 404

It needs no new environment variables beyond CRON_SECRET, which the other jobs already use.

What it does, in order​

  1. Expiry sweep. Finds evidence whose expiry date passed since the last run. For each item it writes compliance.evidence_expired to the audit log (once per item, labelled as the system), then re-checks only the controls that item is attached to. A control whose status changes also gets compliance.control_status_changed.
  2. Time-based re-check. Re-checks every control that has a policy or training attached. A 30-day grace period ending, a due date passing, a policy turning a year old, or a completion turning 12 months old can change those controls with no one doing anything.

Both steps share one time budget.

Fits inside Vercel's limit​

Vercel functions stop at 300 seconds. The job:

  • works in batches of 100;
  • stops starting new batches after about 4 minutes (240 seconds);
  • leaves anything it didn't reach for the next day's run.

It is safe to call twice. An item that was already recorded as expired is not recorded again, so calling it by hand, or Vercel retrying it, doesn't make duplicate audit entries.

The response​

{
"expired": 3,
"controlsChanged": 2,
"failedTeams": 0,
"remaining": false,
"recheck": { "checked": 41, "changed": 1, "failedTeams": 0, "remaining": false }
}

The top-level fields are the expiry sweep, and recheck is the time-based re-check.

FieldMeaning
expiredItems this run recorded as expired
controlsChanged / changedControls whose status changed because of it
checkedControls the re-check looked at
failedTeamsTeams that threw an error. They are logged and skipped, so one broken team can't block the others. Their items are retried on the next run. Should be 0
remainingtrue when the time budget ran out and some work is left for the next run

Running it by hand​

curl -H "Authorization: Bearer $CRON_SECRET" https://api.vodazok.com/api/v1/internal/grc-evidence

Use it after a deploy that changes the rules, or to check that the secret is right. A wrong or missing secret returns 404 on purpose.

If something looks wrong​

SymptomLikely reason
Every call returns 404CRON_SECRET is missing or wrong on the API project, or the Authorization header is missing
failedTeams (either one) is above 0Look at the API logs for that run. The other teams were still checked
A control still shows Passing after its expiry dateIt is under a day old. The daily job hasn't run yet. Any change to the control's evidence re-checks it at once
remaining is true every dayThe 4-minute budget ran out. The rest is picked up the next day. If it happens every day, tell the developers

Other scheduled jobs are listed in Frameworks and Controls.