Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Global Settings
NODE_ENV=development
JWT_SECRET="your_common_jwt_secret_key"
DATABASE_URL="postgresql://app_runtime_login:password@host:port/database"
DATABASE_URL="postgresql://app_runtime:password@host:port/database"

# Frontend Configuration (Next.js)
FRONTEND_URL="http://localhost:3000"
Expand All @@ -24,4 +24,4 @@ DISCORD_CLIENT_ID="your_discord_client_id"
DISCORD_CLIENT_SECRET="your_discord_client_secret"

# Wrangler Hyperdrive Local Connection Emulation String (Secure, ignored by git)
CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE="postgresql://app_runtime_login:your_password@your_postgres_host:5432/postgres"
CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE="postgresql://app_runtime:your_password@your_postgres_host:5432/postgres"
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ cp member/.dev.vars.example member/.dev.vars
ローカル開発時(`wrangler dev`)は、Hyperdriveの接続先をWranglerプロセスの環境変数で上書きします。`.dev.vars` の通常のWorker bindingとは別なので、APIを起動する各シェルで設定してください。

```bash
export CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE="postgresql://app_runtime_login:password@host:5432/database"
export CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE="postgresql://app_runtime:password@host:5432/database"
```

`app_runtime_login` はDB運用runbookで作る非superuser・非`BYPASSRLS`の専用ロールです。アプリケーションから`postgres`/owner資格情報を使わないでください。
`app_runtime` はDB運用runbookで作る非superuser・非`BYPASSRLS`の専用ロールです。アプリケーションから`postgres`/owner資格情報を使わないでください。

### 3. 各プロジェクトのローカル起動
それぞれのディレクトリで開発サーバーを起動します。
Expand Down
2 changes: 1 addition & 1 deletion community/.dev.vars.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Database
DATABASE_URL=postgresql://app_runtime_login:password@host:port/dbname
DATABASE_URL=postgresql://app_runtime:password@host:port/dbname

# Better Auth Configuration
BETTER_AUTH_SECRET=your_secure_random_32_char_string
Expand Down
2 changes: 1 addition & 1 deletion community/.env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Database
DATABASE_URL=postgresql://app_runtime_login:password@host:port/dbname
DATABASE_URL=postgresql://app_runtime:password@host:port/dbname

# Better Auth Configuration
BETTER_AUTH_SECRET=your_secure_random_32_char_string
Expand Down
39 changes: 35 additions & 4 deletions docs/hyperdrive-security.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,40 @@ this sequence.

Each result must show `caching.disabled: true`, and the origin user must be
the dedicated login rather than `postgres`.
7. Deploy both Workers and exercise sign-in, Discord verification, application
submission, approval, and directory access. Restore writes only after these
checks pass.
7. Apply the schema split, `20260727000000_split_auth_schema.sql`.
8. Confirm every Worker has the secrets listed under "Required secrets" before
deploying. A missing one fails at runtime, not at deploy time.
9. Deploy all three Workers and exercise sign-in, Discord verification,
application submission, approval, and directory access. Restore writes only
after these checks pass.

## Required secrets

Check these with `npx wrangler secret list` in each directory. Deploying a
Worker whose secrets were only ever set through the dashboard can drop values
that are not also in `wrangler.jsonc`, so re-check after any deploy.

| Secret | community | member | frontend |
| --- | --- | --- | --- |
| `JWT_SECRET` | signs the app token | verifies it | verifies it in middleware |
| `BETTER_AUTH_SECRET` | yes | — | — |
| `DISCORD_CLIENT_ID` / `DISCORD_CLIENT_SECRET` | yes | — | — |
| `DISCORD_TOKEN` / `DISCORD_GUILD_ID` | yes | yes | — |
| `COMMUNITY_URL` / `FRONTEND_URL` | yes | yes | — |
| `COOKIE_DOMAIN` | yes | — | — |

`JWT_SECRET` must be identical in all three. The frontend needs it because
`middleware.ts` verifies the token to route admins; without it every request
throws, redirects to `/login`, and bounces back into a redirect loop.

`member` needs `DISCORD_TOKEN` and `DISCORD_GUILD_ID` because it re-verifies
guild membership when an application is submitted and again when it is
approved. A deployment that predates that behaviour will not have them, and the
join endpoint answers 500 until they are set.

`DATABASE_URL` is only a fallback for the Hyperdrive binding. Leave it unset in
production rather than holding credentials that would bypass the dedicated
runtime role if Hyperdrive were unavailable.

## Database verification

Expand Down Expand Up @@ -104,7 +135,7 @@ connection override is a Wrangler **process environment variable**, not a
normal Worker variable:

```bash
export CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE='postgresql://app_runtime_login:password@localhost:5432/postgres'
export CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE='postgresql://app_runtime:password@localhost:5432/postgres'
```

Do not copy the repository-wide `.env` into both Workers; that exposes secrets
Expand Down
2 changes: 1 addition & 1 deletion member/.dev.vars.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Database
DATABASE_URL=postgresql://app_runtime_login:password@host:port/dbname
DATABASE_URL=postgresql://app_runtime:password@host:port/dbname

# Application JWT verification (must match community JWT_SECRET)
JWT_SECRET=your_application_jwt_secret
Expand Down
2 changes: 1 addition & 1 deletion member/.env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Database
DATABASE_URL=postgresql://app_runtime_login:password@host:port/dbname
DATABASE_URL=postgresql://app_runtime:password@host:port/dbname

# Application JWT verification (must match the community service JWT_SECRET;
# it must be different from BETTER_AUTH_SECRET)
Expand Down
3 changes: 2 additions & 1 deletion supabase/runbooks/promote_initial_admin.sql
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ begin
from public.community_identities identity
join public.community_memberships membership
on membership.identity_id = identity.identity_id
join public.account auth_account
-- The authentication tables live in app_auth since the schema split.
join app_auth.account auth_account
on auth_account.id = identity.auth_account_id
where identity.provider = 'discord'
and identity.provider_account_id = target_discord_account_id
Expand Down
6 changes: 5 additions & 1 deletion supabase/runbooks/provision_app_runtime_login.sql
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,12 @@ begin
raise exception 'runtime role % owns a database or database objects and cannot be safely constrained', runtime_role;
end if;

-- Only the password is set here. Restating the attributes would require
-- SUPERUSER, which the operator role is not on a managed platform such as
-- Supabase, and it is unnecessary: the create above sets them, and the branch
-- for an existing role has already verified them.
execute format(
'alter role %I login inherit nosuperuser nocreatedb nocreaterole noreplication nobypassrls password %L',
'alter role %I password %L',
runtime_role,
runtime_password
);
Expand Down
Loading