diff --git a/.github/workflows/general.yml b/.github/workflows/general.yml index c27821a9..9c95a6e4 100644 --- a/.github/workflows/general.yml +++ b/.github/workflows/general.yml @@ -18,6 +18,9 @@ env: CARGO_TERM_COLOR: always SQLX_VERSION: 0.8.0 SQLX_FEATURES: "rustls,postgres" + APP_USER: app + APP_USER_PWD: secret + APP_DB_NAME: newsletter # A workflow run is made up of one or more jobs, which run in parallel by default # Each job runs in a runner environment specified by runs-on @@ -62,6 +65,18 @@ jobs: --features ${{ env.SQLX_FEATURES }} --no-default-features --locked + - name: Create app user in Postgres + run: | + sudo apt-get install postgresql-client + + # Create the application user + CREATE_QUERY="CREATE USER ${APP_USER} WITH PASSWORD '${APP_USER_PWD}';" + psql -U "postgres" -c "${CREATE_QUERY}" + + # Grant create db privileges to the app user + GRANT_QUERY="ALTER USER ${APP_USER} CREATEDB;" + psql -U "postgres" -c "${GRANT_QUERY}" + - name: Migrate database run: SKIP_DOCKER=true ./scripts/init_db.sh @@ -130,6 +145,17 @@ jobs: --features ${{ env.SQLX_FEATURES }} --no-default-features --locked + - name: Create app user in Postgres + run: | + sudo apt-get install postgresql-client + + # Create the application user + CREATE_QUERY="CREATE USER ${APP_USER} WITH PASSWORD '${APP_USER_PWD}';" + psql -U "postgres" -c "${CREATE_QUERY}" + + # Grant create db privileges to the app user + GRANT_QUERY="ALTER USER ${APP_USER} CREATEDB;" + psql -U "postgres" -c "${GRANT_QUERY}" - name: Migrate database run: SKIP_DOCKER=true ./scripts/init_db.sh - name: Install cargo-llvm-cov diff --git a/scripts/init_db.sh b/scripts/init_db.sh index 8c915020..42625bf2 100755 --- a/scripts/init_db.sh +++ b/scripts/init_db.sh @@ -10,16 +10,13 @@ if ! [ -x "$(command -v sqlx)" ]; then exit 1 fi -# Check if a custom user has been set, otherwise default to 'postgres' -DB_USER="${POSTGRES_USER:=postgres}" -# Check if a custom password has been set, otherwise default to 'password' -DB_PASSWORD="${POSTGRES_PASSWORD:=password}" -# Check if a custom database name has been set, otherwise default to 'newsletter' -DB_NAME="${POSTGRES_DB:=newsletter}" -# Check if a custom port has been set, otherwise default to '5432' -DB_PORT="${POSTGRES_PORT:=5432}" -# Check if a custom host has been set, otherwise default to 'localhost' -DB_HOST="${POSTGRES_HOST:=localhost}" +# Check if a custom parameter has been set, otherwise use default values +DB_PORT="${DB_PORT:=5432}" +SUPERUSER="${SUPERUSER:=postgres}" +SUPERUSER_PWD="${SUPERUSER_PWD:=password}" +APP_USER="${APP_USER:=app}" +APP_USER_PWD="${APP_USER_PWD:=secret}" +APP_DB_NAME="${APP_DB_NAME:=newsletter}" # Allow to skip Docker if a dockerized Postgres database is already running if [[ -z "${SKIP_DOCKER}" ]] @@ -34,15 +31,14 @@ then CONTAINER_NAME="postgres_$(date '+%s')" # Launch postgres using Docker docker run \ - -e POSTGRES_USER=${DB_USER} \ - -e POSTGRES_PASSWORD=${DB_PASSWORD} \ - -e POSTGRES_DB=${DB_NAME} \ - --health-cmd="pg_isready -U ${DB_USER} || exit 1" \ + --env POSTGRES_USER=${SUPERUSER} \ + --env POSTGRES_PASSWORD=${SUPERUSER_PWD} \ + --health-cmd="pg_isready -U ${SUPERUSER} || exit 1" \ --health-interval=1s \ --health-timeout=5s \ --health-retries=5 \ - -p "${DB_PORT}":5432 \ - -d \ + --publish "${DB_PORT}":5432 \ + --detach \ --name "${CONTAINER_NAME}" \ postgres -N 1000 # ^ Increased maximum number of connections for testing purposes @@ -54,11 +50,21 @@ then >&2 echo "Postgres is still unavailable - sleeping" sleep 1 done + + # Create the application user + CREATE_QUERY="CREATE USER ${APP_USER} WITH PASSWORD '${APP_USER_PWD}';" + docker exec -it "${CONTAINER_NAME}" psql -U "${SUPERUSER}" -c "${CREATE_QUERY}" + + # Grant create db privileges to the app user + GRANT_QUERY="ALTER USER ${APP_USER} CREATEDB;" + docker exec -it "${CONTAINER_NAME}" psql -U "${SUPERUSER}" -c "${GRANT_QUERY}" fi >&2 echo "Postgres is up and running on port ${DB_PORT} - running migrations now!" -export DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME} +# Create the application database +DATABASE_URL=postgres://${APP_USER}:${APP_USER_PWD}@localhost:${DB_PORT}/${APP_DB_NAME} +export DATABASE_URL sqlx database create sqlx migrate run diff --git a/src/configuration.rs b/src/configuration.rs index b274334b..4ab4305e 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -4,7 +4,7 @@ pub struct Settings { pub application_port: u16, } -#[derive(serde::Deserialize)] +#[derive(serde::Deserialize, Clone)] pub struct DatabaseSettings { pub username: String, pub password: String, @@ -20,13 +20,6 @@ impl DatabaseSettings { self.username, self.password, self.host, self.port, self.database_name ) } - - pub fn connection_string_without_db(&self) -> String { - format!( - "postgres://{}:{}@{}:{}", - self.username, self.password, self.host, self.port - ) - } } pub fn get_configuration() -> Result { diff --git a/tests/health_check.rs b/tests/health_check.rs index 11aca099..27e5ca9f 100644 --- a/tests/health_check.rs +++ b/tests/health_check.rs @@ -29,11 +29,17 @@ async fn spawn_app() -> TestApp { pub async fn configure_database(config: &DatabaseSettings) -> PgPool { // Create database - let mut connection = PgConnection::connect(&config.connection_string_without_db()) + let maintenance_settings = DatabaseSettings { + database_name: "postgres".to_string(), + username: "postgres".to_string(), + password: "password".to_string(), + ..config.clone() + }; + let mut connection = PgConnection::connect(&maintenance_settings.connection_string()) .await .expect("Failed to connect to Postgres"); connection - .execute(&*format!(r#"CREATE DATABASE "{}";"#, config.database_name)) + .execute(format!(r#"CREATE DATABASE "{}";"#, config.database_name).as_str()) .await .expect("Failed to create database."); @@ -45,7 +51,6 @@ pub async fn configure_database(config: &DatabaseSettings) -> PgPool { .run(&connection_pool) .await .expect("Failed to migrate the database"); - connection_pool }