From b28d5dda4c547d21c41c0df6b385fb6a8f6b69a8 Mon Sep 17 00:00:00 2001 From: Zack <33050391+speed2exe@users.noreply.github.com> Date: Wed, 6 Sep 2023 14:12:39 +0800 Subject: [PATCH] feat: ci: dockerize gotrue auth server (#13) * feat: ci: dockerize gotrue auth server * feat: build: add gotrue to docker-compose * fix: build: docker-compose + test * feat: ci: simplify tests * feat: ci: add back needed services for compilation * fix: ci: github secrets * fix: ci: use signup * fix: ci: add export * fix: test: generate unique email for registration to avoid conflict --- .github/workflows/ci.yml | 22 ++++++++++++---- Dockerfile | 5 ++-- build/init.sql | 7 +++++ build/init_gotrue.sh | 19 +++++++++++++ configuration/base.yaml | 5 +++- docker-compose.yml | 37 +++++++++++++++++++++++--- src/component/auth/gotrue/models.rs | 2 +- tests/client/mod.rs | 1 + tests/client/sign_in.rs | 41 +++++++++++++---------------- tests/client/sign_out.rs | 9 ++++--- tests/client/sign_up.rs | 17 +++++++----- tests/client/update.rs | 34 ++++++++++++++---------- tests/client/utils.rs | 15 +++-------- 13 files changed, 143 insertions(+), 71 deletions(-) create mode 100644 build/init.sql create mode 100755 build/init_gotrue.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6fa68ca3..d12c22a5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,9 @@ env: CARGO_TERM_COLOR: always SQLX_VERSION: 0.6.2 SQLX_FEATURES: "rustls,postgres" - APP__GOTRUE__BASE_URL: ${{ secrets.APP__GOTRUE__BASE_URL }} - APP__GOTRUE__JWT_SECRET: ${{ secrets.APP__GOTRUE__JWT_SECRET }} + APP__GOTRUE__BASE_URL: http://localhost:3000 + APP__GOTRUE__JWT_SECRET: hello123 + GOTRUE_SMTP_PASS: ${{ secrets.GOTRUE_SMTP_PASS }} jobs: test: @@ -31,6 +32,7 @@ jobs: image: redis:7 ports: - 6379:6379 + steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable @@ -52,11 +54,21 @@ jobs: - name: Check sqlx-data.json is up-to-date run: | cargo sqlx prepare --check -- --bin appflowy_cloud + - name: Run Docker-Compose + run: | + docker-compose up -d + - name: Add registered user + run: | + export GOTRUE_MAILER_AUTOCONFIRM=true + docker-compose up -d + curl localhost:9998/signup \ + --data-raw '{"email":"xigahi8979@tipent.com","password":"Hello123!"}' \ + --header 'Content-Type: application/json' + export GOTRUE_MAILER_AUTOCONFIRM=false + docker-compose up -d + - name: Run tests run: | - cargo build - cargo run & - sleep 5 # wait some time for server to be ready cargo test diff --git a/Dockerfile b/Dockerfile index 32f4513d..c68bcf32 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,12 @@ -FROM lukemathwalker/cargo-chef:latest-rust-1.65.0 as chef +FROM lukemathwalker/cargo-chef:latest-rust-1.69.0 as chef + WORKDIR /app RUN apt update && apt install lld clang -y FROM chef as planner COPY . . # Compute a lock-like file for our project -RUN cargo chef prepare --recipe-path recipe.json +RUN cargo chef prepare --recipe-path recipe.json FROM chef as builder COPY --from=planner /app/recipe.json recipe.json diff --git a/build/init.sql b/build/init.sql new file mode 100644 index 00000000..d1ef7099 --- /dev/null +++ b/build/init.sql @@ -0,0 +1,7 @@ +CREATE USER supabase_admin LOGIN CREATEROLE CREATEDB REPLICATION BYPASSRLS; + +-- Supabase super admin +CREATE USER supabase_auth_admin NOINHERIT CREATEROLE LOGIN NOREPLICATION PASSWORD 'root'; +CREATE SCHEMA IF NOT EXISTS auth AUTHORIZATION supabase_auth_admin; +GRANT CREATE ON DATABASE postgres TO supabase_auth_admin; +ALTER USER supabase_auth_admin SET search_path = 'auth'; diff --git a/build/init_gotrue.sh b/build/init_gotrue.sh new file mode 100755 index 00000000..3611efb4 --- /dev/null +++ b/build/init_gotrue.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +cd "$(dirname "$0")" +set -e + +git clone https://github.com/supabase/gotrue.git +cp gotrue.env.docker gotrue/.env.docker +cd gotrue + +# avoid port conflict with host postgres +sed -i "s/'5432:5432'/'5433:5432'/" docker-compose-dev.yml + +make dev & + +while true; do + curl localhost:9999/health && break + echo "waiting for gotrue to be ready..." + sleep 1 +done diff --git a/configuration/base.yaml b/configuration/base.yaml index fc5ac2ec..169ed9a6 100644 --- a/configuration/base.yaml +++ b/configuration/base.yaml @@ -9,8 +9,11 @@ database: port: 5432 username: "postgres" password: "password" - database_name: "appflowy" + database_name: "postgres" websocket: heartbeat_interval: 8 client_timeout: 10 redis_uri: "redis://127.0.0.1:6379" +gotrue: + base_url: "http://gotrue:9999" + jwt_secret: "hello123" diff --git a/docker-compose.yml b/docker-compose.yml index 4351a30f..895afe1c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,18 +1,46 @@ version: '3' services: postgres: - image: postgres:14 + image: postgres environment: - POSTGRES_USER=${POSTGRES_USER:-postgres} - POSTGRES_DB=${POSTGRES_DB:-postgres} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-password} - POSTGRES_HOST=${POSTGRES_HOST:-postgres} ports: - - "5433:5432" + - 5433:5432 + volumes: + - ./build/init.sql:/docker-entrypoint-initdb.d/init.sql + redis: - image: redis:7 + image: redis ports: - - "6380:6379" + - 6380:6379 + + gotrue: + image: supabase/gotrue + restart: on-failure + depends_on: + - postgres + environment: + - GOTRUE_SITE_URL=http://localhost:3000 # redirected site + - GOTRUE_JWT_SECRET=${GOTRUE_JWT_SECRET:-hello123} + - GOTRUE_DB_DRIVER=postgres + - DATABASE_URL=postgres://supabase_auth_admin:root@postgres:5432/postgres + - API_EXTERNAL_URL=http://localhost:9998 # verify site + - PORT=9999 + - GOTRUE_SMTP_HOST=smtp.gmail.com + - GOTRUE_SMTP_PORT=465 + - GOTRUE_SMTP_USER=noreply@appflowy.io + - GOTRUE_SMTP_PASS=${GOTRUE_SMTP_PASS:-} + - GOTRUE_SMTP_ADMIN_EMAIL=internal@appflowy.io + - GOTRUE_RATE_LIMIT_EMAIL_SENT=${GOTRUE_RATE_LIMIT_EMAIL_SENT:-100000} + - GOTRUE_SMTP_MAX_FREQUENCY=1ns + - GOTRUE_MAILER_URLPATHS_CONFIRMATION=/verify + - GOTRUE_MAILER_AUTOCONFIRM=${GOTRUE_MAILER_AUTOCONFIRM:-false} + ports: + - 9998:9999 + appflowy_cloud: restart: on-failure environment: @@ -24,5 +52,6 @@ services: depends_on: - redis - postgres + - gotrue ports: - 8000:8000 diff --git a/src/component/auth/gotrue/models.rs b/src/component/auth/gotrue/models.rs index 47b5b0ca..934de7e5 100644 --- a/src/component/auth/gotrue/models.rs +++ b/src/component/auth/gotrue/models.rs @@ -69,7 +69,7 @@ pub struct AccessTokenResponse { pub access_token: String, pub token_type: String, pub expires_in: i64, - pub expires_at: i64, + pub expires_at: Option, // older versions of GoTrue do not return this pub refresh_token: String, pub user: User, pub provider_access_token: Option, diff --git a/tests/client/mod.rs b/tests/client/mod.rs index a19bc1a2..c2f4d027 100644 --- a/tests/client/mod.rs +++ b/tests/client/mod.rs @@ -3,3 +3,4 @@ mod sign_in; mod sign_out; mod sign_up; mod update; +mod utils; diff --git a/tests/client/sign_in.rs b/tests/client/sign_in.rs index d08d2931..84049ef4 100644 --- a/tests/client/sign_in.rs +++ b/tests/client/sign_in.rs @@ -1,13 +1,16 @@ use appflowy_cloud::client::http::Client; -use crate::client::constants::LOCALHOST_URL; +use crate::client::{ + constants::LOCALHOST_URL, + utils::{generate_unique_email, REGISTERED_EMAIL, REGISTERED_PASSWORD}, +}; #[tokio::test] async fn sign_in_unknown_user() { + let email = generate_unique_email(); + let password = "Hello123!"; let mut c = Client::from(reqwest::Client::new(), LOCALHOST_URL); - let resp = c - .sign_in_password("unknown999@appflowy.io", "Hello123!") - .await; + let resp = c.sign_in_password(&email, password).await; let resp = resp.unwrap(); match resp { Ok(()) => panic!("should not be ok"), @@ -22,16 +25,14 @@ async fn sign_in_unknown_user() { async fn sign_in_wrong_password() { let mut c = Client::from(reqwest::Client::new(), LOCALHOST_URL); + let email = generate_unique_email(); + let password = "Hello123!"; { - let _ = c - .sign_up("unknown123@appflowy.io", "Hello123!") - .await - .unwrap(); + let _ = c.sign_up(&email, password).await.unwrap(); } - let resp = c - .sign_in_password("unknown123@appflowy.io", "Hllo123!") - .await; + let wrong_password = "Hllo123!"; + let resp = c.sign_in_password(&email, wrong_password).await; let resp = resp.unwrap(); match resp { Ok(()) => panic!("should not be ok"), @@ -46,16 +47,13 @@ async fn sign_in_wrong_password() { async fn sign_in_unconfirmed_email() { let mut c = Client::from(reqwest::Client::new(), LOCALHOST_URL); + let email = generate_unique_email(); + let password = "Hello123!"; { - let _ = c - .sign_up("unknown123@appflowy.io", "Hello123!") - .await - .unwrap(); + let _ = c.sign_up(&email, password).await.unwrap(); } - let resp = c - .sign_in_password("unknown123@appflowy.io", "Hello123!") - .await; + let resp = c.sign_in_password(&email, password).await; let resp = resp.unwrap(); match resp { Ok(()) => panic!("should not be ok"), @@ -70,10 +68,9 @@ async fn sign_in_unconfirmed_email() { async fn sign_in_success() { let mut c = Client::from(reqwest::Client::new(), LOCALHOST_URL); - // pre-registered and confirmed email - let email = "xigahi8979@tipent.com"; - - let resp = c.sign_in_password(email, "Hello123!").await; + let resp = c + .sign_in_password(REGISTERED_EMAIL, REGISTERED_PASSWORD) + .await; let resp = resp.unwrap(); match resp { Ok(()) => {}, diff --git a/tests/client/sign_out.rs b/tests/client/sign_out.rs index 7d7e9aec..a837e653 100644 --- a/tests/client/sign_out.rs +++ b/tests/client/sign_out.rs @@ -1,6 +1,9 @@ use appflowy_cloud::client::http::Client; -use crate::client::constants::LOCALHOST_URL; +use crate::client::{ + constants::LOCALHOST_URL, + utils::{REGISTERED_EMAIL, REGISTERED_PASSWORD}, +}; #[tokio::test] async fn sign_out_but_not_sign_in() { @@ -13,9 +16,7 @@ async fn sign_out_but_not_sign_in() { async fn sign_out_after_sign_in() { let mut c = Client::from(reqwest::Client::new(), LOCALHOST_URL); - // pre-registered and confirmed email - let email = "xigahi8979@tipent.com"; - c.sign_in_password(email, "Hello123!") + c.sign_in_password(REGISTERED_EMAIL, REGISTERED_PASSWORD) .await .unwrap() .unwrap(); diff --git a/tests/client/sign_up.rs b/tests/client/sign_up.rs index 99f79a45..1e05404a 100644 --- a/tests/client/sign_up.rs +++ b/tests/client/sign_up.rs @@ -1,27 +1,30 @@ -use crate::client::constants::LOCALHOST_URL; +use crate::client::{constants::LOCALHOST_URL, utils::generate_unique_email}; use appflowy_cloud::client::http::Client; #[tokio::test] async fn sign_up_success() { + let email = generate_unique_email(); + let password = "Hello!123#"; let c = Client::from(reqwest::Client::new(), LOCALHOST_URL); - let resp = c - .sign_up("exampleuser@appflowy.io", "Hello!123#") - .await - .unwrap(); + let resp = c.sign_up(&email, password).await.unwrap(); assert!(resp.confirmation_sent_at.is_some()); assert!(resp.confirmed_at.is_none()); } #[tokio::test] async fn sign_up_invalid_email() { + let invalid_email = "not_email_address"; + let password = "Hello!123#"; let c = Client::from(reqwest::Client::new(), LOCALHOST_URL); - let resp = c.sign_up("exampleuser", "Hello!123#").await; + let resp = c.sign_up(invalid_email, password).await; assert!(resp.is_err()); } #[tokio::test] async fn sign_up_invalid_password() { + let email = generate_unique_email(); + let password = "123"; let c = Client::from(reqwest::Client::new(), LOCALHOST_URL); - let resp = c.sign_up("exampleuser@appflowy.io", "123").await; + let resp = c.sign_up(&email, password).await; assert!(resp.is_err()); } diff --git a/tests/client/update.rs b/tests/client/update.rs index 90301a1d..154693e9 100644 --- a/tests/client/update.rs +++ b/tests/client/update.rs @@ -1,46 +1,52 @@ use appflowy_cloud::client::http::Client; -use crate::client::constants::LOCALHOST_URL; +use crate::client::{ + constants::LOCALHOST_URL, + utils::{generate_unique_email, REGISTERED_EMAIL, REGISTERED_PASSWORD}, +}; #[tokio::test] async fn update_but_not_logged_in() { let mut c = Client::from(reqwest::Client::new(), LOCALHOST_URL); - let res = c.update("new_email_182@somemail.com", "Hello123!!").await; + let new_email = generate_unique_email(); + let new_password = "Hello123!"; + let res = c.update(&new_email, new_password).await; assert!(res.is_err()); } #[tokio::test] async fn update_password_same_password() { let mut c = Client::from(reqwest::Client::new(), LOCALHOST_URL); - let email = "xigahi8979@tipent.com"; - let password = "Hello123!"; - c.sign_in_password(email, password).await.unwrap().unwrap(); - - let res = c.update(email, "Hello123!").await; - assert!(res.is_err()); + c.sign_in_password(REGISTERED_EMAIL, REGISTERED_PASSWORD) + .await + .unwrap() + .unwrap(); + c.update(REGISTERED_EMAIL, REGISTERED_PASSWORD) + .await + .unwrap(); } #[tokio::test] async fn update_password_and_revert() { - let email = "xigahi8979@tipent.com"; - let old_password = "Hello123!"; let new_password = "Hello456!"; { // change password to new_password let mut c = Client::from(reqwest::Client::new(), LOCALHOST_URL); - c.sign_in_password(email, old_password) + c.sign_in_password(REGISTERED_EMAIL, REGISTERED_PASSWORD) .await .unwrap() .unwrap(); - c.update(email, new_password).await.unwrap(); + c.update(REGISTERED_EMAIL, new_password).await.unwrap(); } { // revert password to old_password let mut c = Client::from(reqwest::Client::new(), LOCALHOST_URL); - c.sign_in_password(email, new_password) + c.sign_in_password(REGISTERED_EMAIL, new_password) .await .unwrap() .unwrap(); - c.update(email, old_password).await.unwrap(); + c.update(REGISTERED_EMAIL, REGISTERED_PASSWORD) + .await + .unwrap(); } } diff --git a/tests/client/utils.rs b/tests/client/utils.rs index b292d0b2..ffde5a50 100644 --- a/tests/client/utils.rs +++ b/tests/client/utils.rs @@ -1,8 +1,7 @@ use std::time::SystemTime; -use appflowy_cloud::client::http::Client; - -pub const LOCALHOST_URL: &str = "http://localhost:8000"; //TODO: change to default port, use https +pub const REGISTERED_EMAIL: &str = "xigahi8979@tipent.com"; +pub const REGISTERED_PASSWORD: &str = "Hello123!"; pub fn timestamp_nano() -> u128 { SystemTime::now() @@ -11,12 +10,6 @@ pub fn timestamp_nano() -> u128 { .as_nanos() } -pub async fn register_deep_fake(c: &mut Client) -> (String, String, String) { - let email = format!("deep_fake{}@appflowy.io", timestamp_nano()); - let user = "user1"; - let password = "DeepFakePassword!123"; - c.register(user, &email, password).await.unwrap(); - - assert!(c.logged_in_token().is_some()); - (email, user.to_string(), password.to_string()) +pub fn generate_unique_email() -> String { + format!("{}@appflowy.io", timestamp_nano()) }