forked from OurHike/OurHike
-
Notifications
You must be signed in to change notification settings - Fork 0
104 lines (97 loc) · 5.03 KB
/
Copy pathsupabase-keepalive.yml
File metadata and controls
104 lines (97 loc) · 5.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# Gives the Supabase project's database something to do, so the free plan does
# not pause it for inactivity.
#
# Supabase pauses a Free plan project that shows too little activity over a
# rolling seven-day window, and the thing it measures is *database* activity,
# not requests to the project in general
# (https://supabase.com/docs/guides/platform/free-project-pausing). That is why
# this is not a curl of a health endpoint: `/auth/v1/settings` answers from
# GoTrue's configuration without Postgres hearing about it, so a keepalive
# built on it would report success every run and still let the project pause.
# backend/supabase_keepalive.py reads tables over PostgREST instead, which is a
# query Postgres actually runs.
#
# **It is also the RLS check, run against the live project.** The reads use the
# anon key and expect an empty array or a permission error, exactly as
# LAUNCH_CHECKLIST.md 5a describes; rows are the failure. Nothing else asks
# that question of the deployed project - backend/tests/test_migration_rls.py
# reads migrations, which is a different claim - and the front door it asks
# through is the one open to anyone holding the key that ships in the client
# bundle. This job is why a policy or grant that quietly opened `reports` would
# be noticed within a day rather than by whoever found the data.
#
# **The cadence is chosen against Supabase's own wording**, which is "a few
# user requests to the database each day over the previous week" - a per-day
# measure, which is what rules out the weekly job this started as. Twice a day
# clears that with room to spare, at a cost of two checkouts and fourteen small
# HTTPS requests a day.
#
# **There is deliberately only one KEEPALIVE.** Other scheduled workflows do
# reach the same project's databases for jobs of their own - schema-drift.yml
# daily through the migration pooler URLs, publish-conditions.yml daily
# through the conditions reader - which this comment used to deny outright
# (#656). What is enforced now is the honest census:
# .github/tests/test_supabase_keepalive_workflow.py pins the full roster of
# scheduled roads into the project, each with its stated reason, and a new
# one fails there by name. supabase-config-check.yml reaches the project too,
# but is manual by design and so cannot be relied on for any of this.
name: Supabase keepalive
on:
schedule:
# Every 20 hours, as far as cron can express it: 00:50 and 20:50 UTC, every
# day. Cron has no true interval - its hour field repeats within the day -
# so `*/20` means "the hours divisible by 20", which is 0 and 20. The gaps
# are therefore 20 hours and then 4, not a steady 20.
#
# That asymmetry does not matter here and the number that does is the
# larger gap: the project is never left untouched for more than 20 hours.
# test_supabase_keepalive_workflow.py asserts exactly that, rather than
# asserting this string, so a future edit is judged on the gap it produces.
#
# Off the hour because GitHub's scheduler queues everything submitted at
# :00 behind everyone else's cron.
#
# Worth knowing before it looks broken: GitHub runs scheduled workflows
# only from the default branch, so this does nothing at all until it is on
# `main`. It also disables schedules in a repository with no activity for
# 60 days - which would silently take the keepalive with it, so a long
# quiet spell is worth checking the Actions tab after.
- cron: "50 */20 * * *"
workflow_dispatch:
# Reads the repository and nothing else. The job holds no credential that can
# write anywhere: the anon key below is public by design, and RLS is what makes
# that safe (LAUNCH_CHECKLIST.md 5a).
permissions:
contents: read
# Never two at once, and never cancel one in flight. A cancelled run is a
# stretch with no recorded activity, which is the one thing this job exists to
# avoid.
concurrency:
group: supabase-keepalive
cancel-in-progress: false
jobs:
keepalive:
name: Give the database a query to run
runs-on: ubuntu-latest
defaults:
run:
working-directory: backend
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.14"
# No install step: the script is stdlib-only on purpose, the same as
# check_supabase_config.py next to it. A job whose whole point is to run
# unattended for months should not have a dependency tree that can break
# while nobody is watching.
- name: Read the project's tables with the anon key
env:
# Variable-or-secret, the way pages.yml and supabase-config-check.yml
# resolve these - "Secrets and variables" is one settings page with
# two tabs and picking the wrong one is easy. Neither value is
# secret: the anon key is designed to be public and already ships
# inside the client bundle.
SUPABASE_URL: ${{ vars.SUPABASE_URL || secrets.SUPABASE_URL }}
SUPABASE_ANON_KEY: ${{ vars.SUPABASE_ANON_KEY || secrets.SUPABASE_ANON_KEY }}
run: python supabase_keepalive.py