From 4d2a9bd7b41ed88b00862445072c5013470ec0c6 Mon Sep 17 00:00:00 2001 From: GitLab Deploy Bot Date: Fri, 31 Oct 2025 10:32:05 +0700 Subject: [PATCH] update secure DB setup and env isolation for LTI API --- .env.dev | 59 +++++++++++++++++ Dockerfile.dev | 20 ++++++ Makefile.dev | 139 ++++++++++++++++++++++++++++++++++++++++ docker-compose.dev.yaml | 98 ++++++++++++++++++++++++++++ 4 files changed, 316 insertions(+) create mode 100644 .env.dev create mode 100644 Dockerfile.dev create mode 100644 Makefile.dev create mode 100644 docker-compose.dev.yaml diff --git a/.env.dev b/.env.dev new file mode 100644 index 00000000..9294be56 --- /dev/null +++ b/.env.dev @@ -0,0 +1,59 @@ +# .env.lti-api (Development Server with Domain) +# ============================================= + +# Server configuration +VERSION=0.0.1 +APP_ENV=dev +APP_HOST=0.0.0.0 +APP_PORT=8081 +APP_URL=https://dev-api-lti.mbugroup.id + +# Database configuration (pakai PostgreSQL milik SSO) +DB_HOST=dev-postgres-lti +DB_USER=app_lti_user +DB_PASSWORD=AppLti@Secure2025! +DB_NAME=db_lti_erp +DB_PORT=5432 + +# JWT configuration +JWT_SECRET=changeme +JWT_ACCESS_EXP_MINUTES=30 +JWT_REFRESH_EXP_DAYS=30 +JWT_RESET_PASSWORD_EXP_MINUTES=10 +JWT_VERIFY_EMAIL_EXP_MINUTES=10 + +# Redis (pakai Redis milik SSO) +REDIS_URL=redis://sso-redis:6379/0 + +# CORS configuration +CORS_ALLOW_ORIGINS=https://dev-api-sso.mbugroup.id,https://dev-lti.mbugroup.id,https://dev-api-lti.mbugroup.id,http://localhost:3000 +CORS_ALLOW_METHODS=GET,POST,PUT,PATCH,DELETE,OPTIONS +CORS_ALLOW_HEADERS=Authorization,Content-Type,X-Requested-With +CORS_EXPOSE_HEADERS=Link,Location +CORS_ALLOW_CREDENTIALS=true +CORS_MAX_AGE=600 + +# SSO Integration (Gunakan domain backend SSO) +SSO_ISSUER=https://dev-api-sso.mbugroup.id +SSO_JWKS_URL=https://dev-api-sso.mbugroup.id/api/.well-known/jwks.json +SSO_ALLOWED_AUDIENCES= +SSO_AUTHORIZE_URL=https://dev-api-sso.mbugroup.id/api/sso/authorize +SSO_TOKEN_URL=https://dev-api-sso.mbugroup.id/api/sso/token +SSO_GETME_URL=https://dev-api-sso.mbugroup.id/api/auth/get-me + +# Cookie & session configuration +SSO_ACCESS_COOKIE_NAME=sso_access +SSO_REFRESH_COOKIE_NAME=sso_refresh +SSO_COOKIE_DOMAIN=.mbugroup.id +SSO_COOKIE_SECURE=true +SSO_COOKIE_SAMESITE=Lax +SSO_PKCE_TTL_SECONDS=300 + +# SSO webhook / user sync settings +SSO_USER_SYNC_SIGNATURE_DRIFT_SECONDS=120 +SSO_USER_SYNC_NONCE_TTL_SECONDS=600 +SSO_USER_SYNC_MAX_BODY_BYTES=32768 + +# Client registration for SSO +#SSO_CLIENTS={"Lumbung-Telur-Indonesia":{"public_id":"Lumbung-Telur-Indonesia","redirect_uri":"https://dev-api-lti.mbugroup.id/api/sso/callback","scope":"openid profile","default_return_uri":"https://dev-lti.mbugroup.id","allowed_return_origins":["https://dev-lti.mbugroup.id","http://localhost:3000"],"sync_secret":"onUyfODIMHOh4TgGLgyWLmsNeVNxFRHqoLJFLPjr"}} +SSO_CLIENTS="{\"Lumbung-Telur-Indonesia\":{\"public_id\":\"Lumbung-Telur-Indonesia\",\"redirect_uri\":\"https://dev-api-lti.mbugroup.id/api/sso/callback\",\"scope\":\"openid profile\",\"default_return_uri\":\"https://dev-lti.mbugroup.id\",\"allowed_return_origins\":[\"https://dev-lti.mbugroup.id\",\"http://localhost:3000\"],\"sync_secret\":\"onUyfODIMHOh4TgGLgyWLmsNeVNxFRHqoLJFLPjr\"}}" \ No newline at end of file diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 00000000..87781228 --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,20 @@ +FROM golang:1.23-alpine + +# Install dependensi dasar +RUN apk add --no-cache git curl bash build-base + +# Install Air (pakai repo baru air-verse) +RUN go install github.com/air-verse/air@v1.52.3 + +WORKDIR /lti-api + +# Cache dependencies +COPY go.mod go.sum ./ +RUN go mod download + +# Copy source code +COPY . . + +EXPOSE 8081 + +CMD ["air", "-c", ".air.toml"] diff --git a/Makefile.dev b/Makefile.dev new file mode 100644 index 00000000..723c8421 --- /dev/null +++ b/Makefile.dev @@ -0,0 +1,139 @@ +# ============================================================ +# ๐Ÿง  MAKEFILE โ€” DEV ENVIRONMENT (SSO-MBUGROUP) +# ============================================================ + +# --- Load environment --- +ifneq (,$(wildcard .env.dev)) +include .env.dev +export +endif + +# --- Configuration --- +COMPOSE ?= docker compose -f docker-compose.dev.yaml +NETWORK ?= lti-api_lti-network +APP_CONTAINER ?= dev-api-sso +DB_CONTAINER ?= dev-postgres-sso +REDIS_CONTAINER?= dev-redis-sso +MIGRATE_IMAGE ?= migrate/migrate:v4.15.2 +MIGRATIONS_DIR := $(PWD)/internal/database/migrations + +DB_USER ?= postgres +DB_PASSWORD ?= Postgres@Secure2025! +DB_NAME ?= db_lti_erp +DB_PORT ?= 5432 +DB_HOST ?= dev-postgres-lti + +DB_URL := postgres://$(DB_USER):$(DB_PASSWORD)@$(DB_HOST):$(DB_PORT)/$(DB_NAME)?sslmode=disable + +# ============================================================ +# ๐Ÿงฑ DATABASE MIGRATION COMMANDS +# ============================================================ + +migrate-up: + @echo "๐Ÿงฑ Running database migrations..." + @docker run --rm \ + --network $(NETWORK) \ + -v $(MIGRATIONS_DIR):/migrations \ + $(MIGRATE_IMAGE) \ + -path=/migrations/ -database "$(DB_URL)" up + +migrate-down: + @echo "โฌ‡๏ธ Rolling back last migration..." + @docker run --rm \ + --network $(NETWORK) \ + -v $(MIGRATIONS_DIR):/migrations \ + $(MIGRATE_IMAGE) \ + -path=/migrations/ -database "$(DB_URL)" down 1 + +migrate-fresh: + @echo "๐Ÿงฑ Rebuilding database from scratch..." + @echo "๐Ÿ”น Terminating active connections..." + @docker exec -i $(DB_CONTAINER) psql -U $(DB_USER) -d postgres -c \ + "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname='$(DB_NAME)' AND pid <> pg_backend_pid();" || true + @echo "๐Ÿ”น Dropping and recreating database..." + @docker exec -i $(DB_CONTAINER) psql -U $(DB_USER) -d postgres -c "DROP DATABASE IF EXISTS $(DB_NAME);" || true + @docker exec -i $(DB_CONTAINER) psql -U $(DB_USER) -d postgres -c "CREATE DATABASE $(DB_NAME);" || true + @sleep 3 + @make -f Makefile.dev migrate-up + @make -f Makefile.dev seed + @echo "โœ… Fresh migration complete!" + +# ========================================== +# ๐Ÿงน FIX DIRTY MIGRATION / FORCE VERSION +# ========================================== + +# Pakai: make migrate-force v=20250825071938 +migrate-force: + @if [ -z "$(v)" ]; then \ + echo "โŒ Error: versi migrasi belum ditentukan!"; \ + echo "Gunakan contoh: make migrate-force v=20250825071938"; \ + exit 1; \ + fi; \ + echo "โš™๏ธ Forcing migration version $(v)..."; \ + docker run --rm \ + -v $(PWD)/internal/database/migrations:/migrations \ + --network $(NETWORK) \ + $(MIGRATE_IMAGE) \ + -path=/migrations/ -database "$(DB_URL)" force $(v); \ + echo "โœ… Migration forced to version $(v)" + + +migrate-super: + @echo "๐Ÿš€ Running migration as superuser..." + @docker cp internal/database/migrations/superuser_migrations.sql $(DB_CONTAINER):/tmp/superuser_migrations.sql + @docker exec -it $(DB_CONTAINER) psql -U $(DB_USER) -d $(DB_NAME) -f /tmp/superuser_migrations.sql + @echo "โœ… Superuser migrations complete!" + +# ============================================================ +# ๐ŸŒฑ SEEDER +# ============================================================ + +seed: + @echo "๐ŸŒฑ Running Go-based seeder..." + @docker run --rm \ + --network $(NETWORK) \ + --env-file .env.dev \ + -v $(PWD):/app \ + -w /app \ + golang:1.23-alpine \ + sh -c "apk add --no-cache git && go run cmd/seed/main.go" + @echo "โœ… Seeder completed successfully!" + +# ============================================================ +# ๐Ÿณ DOCKER MANAGEMENT +# ============================================================ + +up: + @echo "๐Ÿš€ Starting all containers..." + @$(COMPOSE) up -d + +down: + @echo "๐Ÿงน Stopping all containers..." + @$(COMPOSE) down --remove-orphans + +restart: + @echo "โ™ป๏ธ Restarting application container..." + @docker restart $(APP_CONTAINER) + +ps: + @$(COMPOSE) ps + +logs: + @docker logs -f $(APP_CONTAINER) + +psql: + @docker exec -it $(DB_CONTAINER) psql -U $(DB_USER) -d $(DB_NAME) + +# ============================================================ +# โš™๏ธ UTILITIES +# ============================================================ + +fix-db: + @echo "๐Ÿ”ง Checking if database exists..." + @docker exec -i $(DB_CONTAINER) psql -U $(DB_USER) -tc "SELECT 1 FROM pg_database WHERE datname='$(DB_NAME)';" | grep -q 1 \ + && echo "โœ… Database exists: $(DB_NAME)" \ + || (echo "โš ๏ธ Creating database..." && docker exec -i $(DB_CONTAINER) psql -U $(DB_USER) -c "CREATE DATABASE $(DB_NAME);") + +clean: + @echo "๐Ÿงน Removing dangling images and cache..." + @docker builder prune -f \ No newline at end of file diff --git a/docker-compose.dev.yaml b/docker-compose.dev.yaml new file mode 100644 index 00000000..161b1177 --- /dev/null +++ b/docker-compose.dev.yaml @@ -0,0 +1,98 @@ +services: + dev-api-lti: + build: + context: . + dockerfile: Dockerfile.dev + container_name: dev-api-lti + working_dir: /lti-api + command: ["/bin/sh", "credential/entrypoint.sh"] + ports: + - "8081:8081" + env_file: + - .env.dev + environment: + # override agar koneksi ke container internal + DB_HOST: dev-postgres-lti + DB_PORT: 5432 + REDIS_URL: redis://dev-redis-lti:6379/0 + volumes: + - .:/lti-api + - ./.air.toml:/lti-api/.air.toml:ro + - ./internal/config/jwtRS256.key:/run/keys/jwtRS256.key + - ./internal/config/jwtRS256.key.pub:/run/keys/jwtRS256.key.pub + depends_on: + - dev-postgres-lti + - dev-redis-lti + networks: + - lti-network + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:8081/healthz || exit 1"] + interval: 10s + timeout: 3s + retries: 10 + start_period: 10s + deploy: + resources: + limits: + cpus: "2.0" + memory: 2G + reservations: + cpus: "1.0" + memory: 512M + + dev-postgres-lti: + image: postgres:15-alpine + container_name: dev-postgres-lti + restart: always + env_file: + - credential/.env.db + ports: + - "5433:5432" + volumes: + - dev-postgres-lti-data:/var/lib/postgresql/data + - ./credential:/docker-entrypoint-initdb.d:ro + networks: + - lti-network + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres} -d ${DB_NAME:-db_lti_erp}"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 5s + deploy: + resources: + limits: + cpus: "1.0" + memory: 2G + reservations: + cpus: "0.5" + memory: 512M + + dev-redis-lti: + image: redis:7-alpine + container_name: dev-redis-lti + restart: always + ports: + - "6380:6379" + networks: + - lti-network + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 3s + retries: 10 + deploy: + resources: + limits: + cpus: "0.5" + memory: 512M + reservations: + cpus: "0.2" + memory: 256M + +networks: + lti-network: + driver: bridge + +volumes: + dev-postgres-lti-data: