|
| 1 | +# Supabase Auth Testcontainer Implementation Plan |
| 2 | + |
| 3 | +This document outlines the implementation plan for building a production-ready Supabase Auth testcontainer module following patterns from [testcontainers-rs-modules-community](https://github.com/testcontainers/testcontainers-rs-modules-community). |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +- **Docker Image:** `supabase/gotrue` (v2.183.0) |
| 8 | +- **Port:** 9999 |
| 9 | +- **Health Check:** `GET /health` returns 200 |
| 10 | +- **Database:** Requires PostgreSQL with `auth` schema |
| 11 | + |
| 12 | +--- |
| 13 | + |
| 14 | +## Implementation Steps |
| 15 | + |
| 16 | +### 1. Core Image Configuration Fixes |
| 17 | + |
| 18 | +- [x] 1.1. Update image name from `supabase/auth` to `supabase/gotrue` |
| 19 | +- [x] 1.2. Update image tag from `v2.164.0` to `v2.183.0` |
| 20 | +- [x] 1.3. Add `AUTH_PORT` constant (9999) |
| 21 | +- [x] 1.4. Export `AUTH_PORT` from `lib.rs` |
| 22 | +- [x] 1.5. Remove `cmd()` override (use default entrypoint) |
| 23 | +- [x] 1.6. Implement proper `ready_conditions()` with log-based wait for "API started" |
| 24 | + |
| 25 | +### 2. Struct Refactoring |
| 26 | + |
| 27 | +- [x] 2.1. Change `env_vars` from `HashMap` to `BTreeMap` for consistent ordering |
| 28 | +- [x] 2.2. Add `tag: String` field to allow custom version override |
| 29 | +- [x] 2.3. Update `Image::tag()` to return `&self.tag` instead of constant |
| 30 | +- [x] 2.4. Update `Default` impl for new fields |
| 31 | + |
| 32 | +### 3. Builder Methods |
| 33 | + |
| 34 | +- [x] 3.1. Refactor `new()` to use builder pattern (return `Self::default().with_db_url(...)`) |
| 35 | +- [x] 3.2. Add `with_db_url(impl Into<String>)` method |
| 36 | +- [x] 3.3. Add `with_jwt_secret(impl Into<String>)` method |
| 37 | +- [x] 3.4. Add `with_jwt_expiry(u32)` method |
| 38 | +- [x] 3.5. Add `with_api_external_url(impl Into<String>)` method |
| 39 | +- [x] 3.6. Add `with_site_url(impl Into<String>)` method |
| 40 | +- [x] 3.7. Add `with_signup_disabled(bool)` method |
| 41 | +- [x] 3.8. Add `with_anonymous_users(bool)` method |
| 42 | +- [x] 3.9. Add `with_mailer_autoconfirm(bool)` method |
| 43 | +- [x] 3.10. Add `with_sms_autoconfirm(bool)` method |
| 44 | +- [x] 3.11. Add `with_log_level(impl Into<String>)` method |
| 45 | +- [x] 3.12. Add `with_tag(impl Into<String>)` method |
| 46 | +- [x] 3.13. Add `with_env(impl Into<String>, impl Into<String>)` for custom env vars |
| 47 | +- [x] 3.14. Remove `new_with_env()` (replaced by `with_env()` chain) |
| 48 | + |
| 49 | +### 4. Default Configuration Cleanup |
| 50 | + |
| 51 | +- [x] 4.1. Remove unnecessary default env vars (GitHub OAuth placeholders, etc.) |
| 52 | +- [x] 4.2. Keep only essential defaults (DB driver, API host, port, namespace) |
| 53 | +- [x] 4.3. Set sensible test defaults (autoconfirm enabled, debug logging) |
| 54 | +- [x] 4.4. Use a proper length JWT secret (min 32 chars) |
| 55 | + |
| 56 | +### 5. Database Initialization Improvements |
| 57 | + |
| 58 | +- [x] 5.1. Add `auth_admin_password` parameter to `init_db_schema()` |
| 59 | +- [x] 5.2. Improve error messages with context |
| 60 | +- [x] 5.3. Make `DB_NAMESPACE` have a default fallback ("auth") |
| 61 | +- [x] 5.4. Remove `println!` debug statement |
| 62 | + |
| 63 | +### 6. Dependencies Update |
| 64 | + |
| 65 | +- [x] 6.1. Verify testcontainers supports HTTP wait strategy (using log-based wait) |
| 66 | +- [x] 6.2. Add `reqwest` with `json` feature to dev-dependencies |
| 67 | +- [x] 6.3. Add `serde_json` to dev-dependencies |
| 68 | +- [x] 6.4. Ensure tokio dev-dependency has `full` and `test-util` features |
| 69 | + |
| 70 | +### 7. Unit Tests |
| 71 | + |
| 72 | +- [x] 7.1. Add test for default configuration values |
| 73 | +- [x] 7.2. Add test for `name()` returns correct image name |
| 74 | +- [x] 7.3. Add test for `tag()` returns correct version |
| 75 | +- [x] 7.4. Add test for builder method chaining |
| 76 | +- [x] 7.5. Add test for `with_tag()` overrides default tag |
| 77 | +- [x] 7.6. Add test for `with_env()` adds custom environment variable |
| 78 | + |
| 79 | +### 8. Integration Test Setup |
| 80 | + |
| 81 | +- [x] 8.1. Create `tests/auth_integration.rs` file |
| 82 | +- [x] 8.2. Create helper function `setup_auth_with_postgres()` that starts both containers |
| 83 | +- [x] 8.3. Ensure proper connection string handling (docker internal vs localhost) |
| 84 | + |
| 85 | +### 9. Integration Tests - Basic Functionality |
| 86 | + |
| 87 | +- [x] 9.1. Add test: Auth container starts successfully with PostgreSQL |
| 88 | +- [x] 9.2. Add test: Health endpoint returns 200 |
| 89 | +- [x] 9.3. Add test: Settings endpoint returns configuration |
| 90 | + |
| 91 | +### 10. Integration Tests - Authentication Flows |
| 92 | + |
| 93 | +- [x] 10.1. Add test: Anonymous signup works when enabled |
| 94 | +- [x] 10.2. Add test: Email signup with autoconfirm returns tokens |
| 95 | +- [x] 10.3. Add test: Signup is rejected when disabled |
| 96 | +- [x] 10.4. Add test: Token refresh works |
| 97 | +- [x] 10.5. Add test: User retrieval with access token works |
| 98 | + |
| 99 | +### 11. Integration Tests - Database Verification |
| 100 | + |
| 101 | +- [x] 11.1. Add test: Auth schema is created in PostgreSQL |
| 102 | +- [x] 11.2. Add test: `supabase_auth_admin` user is created |
| 103 | +- [x] 11.3. Add test: Migrations run successfully (verify via health check) |
| 104 | + |
| 105 | +### 12. Documentation |
| 106 | + |
| 107 | +- [x] 12.1. Update module-level doc comment in `auth.rs` |
| 108 | +- [x] 12.2. Add doc comments to all public methods |
| 109 | +- [x] 12.3. Add usage examples in doc comments |
| 110 | +- [x] 12.4. Update README.md with Auth usage example |
| 111 | + |
| 112 | +### 13. Cleanup |
| 113 | + |
| 114 | +- [x] 13.1. Remove commented-out test code in existing `test_auth_default` |
| 115 | +- [x] 13.2. Run `cargo fmt` |
| 116 | +- [x] 13.3. Run `cargo clippy --all-features` and fix warnings |
| 117 | +- [x] 13.4. Run full test suite `cargo test --all-features` |
| 118 | + |
| 119 | +--- |
| 120 | + |
| 121 | +## Code Reference |
| 122 | + |
| 123 | +### Target Struct Design |
| 124 | + |
| 125 | +```rust |
| 126 | +#[derive(Debug, Clone)] |
| 127 | +pub struct Auth { |
| 128 | + env_vars: BTreeMap<String, String>, |
| 129 | + tag: String, |
| 130 | +} |
| 131 | +``` |
| 132 | + |
| 133 | +### Key Constants |
| 134 | + |
| 135 | +```rust |
| 136 | +const NAME: &str = "supabase/gotrue"; |
| 137 | +const TAG: &str = "v2.183.0"; |
| 138 | +pub const AUTH_PORT: u16 = 9999; |
| 139 | +``` |
| 140 | + |
| 141 | +### Ready Condition |
| 142 | + |
| 143 | +```rust |
| 144 | +fn ready_conditions(&self) -> Vec<WaitFor> { |
| 145 | + vec![WaitFor::message_on_stderr("API started")] |
| 146 | + // Or HTTP health check if supported: |
| 147 | + // vec![WaitFor::http("/health").with_port(AUTH_PORT)] |
| 148 | +} |
| 149 | +``` |
| 150 | + |
| 151 | +### PostgreSQL + Auth Container Setup Pattern |
| 152 | + |
| 153 | +```rust |
| 154 | +// 1. Start PostgreSQL testcontainer |
| 155 | +let postgres = Postgres::default().with_host_auth().start().await?; |
| 156 | +let pg_port = postgres.get_host_port_ipv4(5432).await?; |
| 157 | + |
| 158 | +// 2. Connection strings |
| 159 | +let auth_db_url = format!( |
| 160 | + "postgres://supabase_auth_admin:password@host.docker.internal:{}/postgres", |
| 161 | + pg_port |
| 162 | +); |
| 163 | +let local_db_url = format!( |
| 164 | + "postgres://postgres:postgres@localhost:{}/postgres", |
| 165 | + pg_port |
| 166 | +); |
| 167 | + |
| 168 | +// 3. Initialize and start Auth |
| 169 | +let auth = Auth::default() |
| 170 | + .with_db_url(&auth_db_url) |
| 171 | + .init_db_schema(&local_db_url, "password") |
| 172 | + .await? |
| 173 | + .start() |
| 174 | + .await?; |
| 175 | + |
| 176 | +let auth_port = auth.get_host_port_ipv4(AUTH_PORT).await?; |
| 177 | +``` |
| 178 | + |
| 179 | +--- |
| 180 | + |
| 181 | +## Dependencies |
| 182 | + |
| 183 | +```toml |
| 184 | +[dependencies] |
| 185 | +testcontainers = { version = "0.23.1", features = ["default"] } |
| 186 | +testcontainers-modules = { version = "0.11.4", features = ["postgres"] } |
| 187 | +tokio = { version = "1.24.1" } |
| 188 | +tokio-postgres = "0.7.11" |
| 189 | +anyhow = "1.0.86" |
| 190 | +thiserror = "2.0.11" |
| 191 | + |
| 192 | +[dev-dependencies] |
| 193 | +reqwest = { version = "0.12", features = ["json"] } |
| 194 | +serde_json = "1.0" |
| 195 | +tokio = { version = "1.24.1", features = ["full", "test-util"] } |
| 196 | +``` |
| 197 | + |
| 198 | +--- |
| 199 | + |
| 200 | +## Resources |
| 201 | + |
| 202 | +- [Supabase Auth Repository](https://github.com/supabase/auth) |
| 203 | +- [Supabase GoTrue Docker Image](https://hub.docker.com/r/supabase/gotrue) |
| 204 | +- [testcontainers-rs-modules-community](https://github.com/testcontainers/testcontainers-rs-modules-community) |
| 205 | +- [Supabase Self-Hosting Docker Compose](https://github.com/supabase/supabase/tree/master/docker) |
0 commit comments