New module: supabase, upstream's self-hosted stack of 13 containers, which ace runs under HAL.
The database stays inside the module (Supabase's own Postgres image, superuser, reserved roles and _supabase). A postgres-database grant cannot hold it, so ace's 2.2 GB data directory moves as a copy.
Secrets reach five containers as files and never through their environment: Kong (a rendered kong.yml, uid 100), GoTrue (auth -c dotenv), PostgREST (config file), Vector (the Logflare key in its yml), and the db (POSTGRES_PASSWORD_FILE plus a rendered jwt.sql, uid 105). The other seven declare secrets-in-environment and give the reason.
Every public URL is https://${bound:route:name}, so this depends on mesh-controller #149. On main the render is refused rather than written empty. On ace, HAL's SITE_URL is broken today ("https://supabase.").
Three run-once steps. The first seeds /etc/postgresql-custom with cp -n, which never overwrites the pgsodium key. The other two wait for the db and for Logflare, replacing compose's depends_on: service_healthy.
settings.json (merge:json) sets the pooler's tenant and pool sizes, so ace keeps the zurag tenant. pooler.exs repoints a tenant whose db host is not supabase-db. HAL created ace's tenant with host db.
Secrets that can never be minted: anon-key and service-role-key (JWTs signed with jwt), and pooler-vault (must be exactly 32 bytes). On ace every secret the data already holds is accepted.
Vector reads only this module's containers. Upstream's config read every container's logs on the machine.
Not carried: Kong 8443 and Logflare 4000 on all interfaces.
Verified: the catalogue tests pass with MESH_CATALOGUE set, on main and on #149. The #149 render was run as a throwaway stack of all 13 pinned digests with dummy secrets:
the db initialised through the rendered scripts;
REST, auth, storage, GraphQL, pg-meta, functions and realtime all answer through Kong;
Studio returns 401 without the dashboard login and 200 with it;
the pooler accepts connections in session and transaction mode as postgres.zurag;
a tenant pointed at host db was repointed by the bootstrap.
New module: **supabase**, upstream's self-hosted stack of 13 containers, which ace runs under HAL.
- The database stays inside the module (Supabase's own Postgres image, superuser, reserved roles and `_supabase`). A `postgres-database` grant cannot hold it, so ace's 2.2 GB data directory moves as a copy.
- Secrets reach five containers as files and never through their environment: Kong (a rendered kong.yml, uid 100), GoTrue (`auth -c` dotenv), PostgREST (config file), Vector (the Logflare key in its yml), and the db (`POSTGRES_PASSWORD_FILE` plus a rendered jwt.sql, uid 105). The other seven declare `secrets-in-environment` and give the reason.
- Every public URL is `https://${bound:route:name}`, so this **depends on mesh-controller #149**. On main the render is refused rather than written empty. On ace, HAL's SITE_URL is broken today ("https://supabase.").
- Three run-once steps. The first seeds `/etc/postgresql-custom` with `cp -n`, which never overwrites the pgsodium key. The other two wait for the db and for Logflare, replacing compose's `depends_on: service_healthy`.
- `settings.json` (merge:json) sets the pooler's tenant and pool sizes, so ace keeps the `zurag` tenant. `pooler.exs` repoints a tenant whose db host is not `supabase-db`. HAL created ace's tenant with host `db`.
- Secrets that can never be minted: `anon-key` and `service-role-key` (JWTs signed with `jwt`), and `pooler-vault` (must be exactly 32 bytes). On ace every secret the data already holds is accepted.
- Vector reads only this module's containers. Upstream's config read every container's logs on the machine.
- Not carried: Kong 8443 and Logflare 4000 on all interfaces.
Verified: the catalogue tests pass with MESH_CATALOGUE set, on main and on #149. The #149 render was run as a throwaway stack of all 13 pinned digests with dummy secrets:
- the db initialised through the rendered scripts;
- REST, auth, storage, GraphQL, pg-meta, functions and realtime all answer through Kong;
- Studio returns 401 without the dashboard login and 200 with it;
- the pooler accepts connections in session and transaction mode as `postgres.zurag`;
- a tenant pointed at host `db` was repointed by the bootstrap.
ace runs Supabase under HAL as upstream's 13-container compose: a 2.2 GB
database (1.8 GB of it the dormant `novox` schema, 5.8 M rows in its largest
table), Kong at supabase.zurag.be, the pooler on 5433/6543. This is that stack
as a catalogue module, same images (the digests ace runs), same container
names so an assignment holds the running ones and a take replaces them.
The database stays inside the module. Supabase is a Postgres distribution: its
own image with pgsodium, pg_graphql, pg_net, vault and timescale preloaded, a
superuser (supabase_admin), a dozen reserved roles and a second database
(_supabase). A postgres-database grant - one database, one unprivileged role -
cannot hold it, so ace's data directory moves as a copy, not a dump/restore.
What HAL did by shell and environment the mesh now renders as files:
- kong.yml carries the anon/service keys and the dashboard login (owned by
kong's uid 100), instead of an entrypoint that eval'd the environment;
- GoTrue reads a dotenv file (auth -c), PostgREST a config file, Vector its yml
with the Logflare key in it, the database POSTGRES_PASSWORD_FILE and a
jwt.sql rendered with the secret (owned by postgres, uid 105). None of these
five containers has a secret in its environment.
- realtime, storage, meta, functions, analytics, studio and supavisor read
their credentials from the environment only; each declares
secrets-in-environment with the reason (ADR 0086).
- Upstreams are container names (supabase-db, supabase-kong, ...) instead of
compose service names, which the mesh does not have.
- SITE_URL / API_EXTERNAL_URL / SUPABASE_PUBLIC_URL are
https://${bound:route:name} (mesh-controller #149); on ace HAL rendered them
as "https://supabase." - broken today.
- Vector reads the docker socket, as upstream does, but now includes only this
module's containers instead of every container's logs on the machine.
Three things compose did that a declaration cannot, done as steps: a run-once
seed copies the image's /etc/postgresql-custom into the placed config
directory with cp -n (a named volume did that implicitly; never overwrites the
pgsodium root key), and two run-once gates wait for the database and for
Logflare, which compose expressed as depends_on: service_healthy.
The pooler bootstrap (pooler.exs) takes the tenant id and pool sizes from
settings.json, the module's one merge:json file, so ace keeps its tenant
"zurag"; and it repoints an existing tenant whose database host is not
supabase-db - HAL created ace's with host "db", which no longer resolves.
Secrets (vault, requires "secret"): postgres, jwt, anon-key,
service-role-key, dashboard-user, dashboard, logflare, pooler-vault,
key-base-a + key-base-b (concatenated: Phoenix wants 64+ bytes, a minted
secret is 40), openai. Three cannot be minted on any machine: anon-key and
service-role-key are JWTs signed with jwt, and pooler-vault must be exactly
32 bytes (AES-256-GCM, found in the bed). They are accepted. On ace every
secret the data already knows is accepted (all but key-base-a/b).
Not carried: Kong's 8443 and Logflare's 4000 on all interfaces (nothing
outside the module uses them); realtime's DB_ENC_KEY stays upstream's constant
(realtime deletes and re-seeds that tenant from its environment every start,
and the key must be exactly 16 bytes).
Verified: catalogue tests with MESH_CATALOGUE pointed here on mesh-controller
main and #149 (on main the render is refused for "name", never written
empty). The #149 resolution with stub providers, turned into a throwaway
stack of all 13 pinned digests with dummy secrets and the rendered files at
their owners and modes: the database initialised through the rendered scripts
(jwt setting applied, _analytics/_supavisor created, roles' password from
POSTGRES_PASSWORD_FILE); through Kong: REST 200 with the anon key and 401
without, auth health and settings 200, storage buckets 200, GraphQL 200, pg-meta
200, an edge function 200, Studio 401 without and 200 with the dashboard login,
realtime tenant health 200; the pooler in session and transaction mode as
postgres.zurag; a tenant set to host "db" was repointed to supabase-db by the
bootstrap and connections worked.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
New module: supabase, upstream's self-hosted stack of 13 containers, which ace runs under HAL.
_supabase). Apostgres-databasegrant cannot hold it, so ace's 2.2 GB data directory moves as a copy.auth -cdotenv), PostgREST (config file), Vector (the Logflare key in its yml), and the db (POSTGRES_PASSWORD_FILEplus a rendered jwt.sql, uid 105). The other seven declaresecrets-in-environmentand give the reason.https://${bound:route:name}, so this depends on mesh-controller #149. On main the render is refused rather than written empty. On ace, HAL's SITE_URL is broken today ("https://supabase.")./etc/postgresql-customwithcp -n, which never overwrites the pgsodium key. The other two wait for the db and for Logflare, replacing compose'sdepends_on: service_healthy.settings.json(merge:json) sets the pooler's tenant and pool sizes, so ace keeps thezuragtenant.pooler.exsrepoints a tenant whose db host is notsupabase-db. HAL created ace's tenant with hostdb.anon-keyandservice-role-key(JWTs signed withjwt), andpooler-vault(must be exactly 32 bytes). On ace every secret the data already holds is accepted.Verified: the catalogue tests pass with MESH_CATALOGUE set, on main and on #149. The #149 render was run as a throwaway stack of all 13 pinned digests with dummy secrets:
postgres.zurag;dbwas repointed by the bootstrap.