1
0
forked from baron/baron-sso

테스트 개선 및 프로덕션 배포준비

This commit is contained in:
2026-06-19 09:33:07 +09:00
parent 016d783482
commit 62d8563836
16 changed files with 840 additions and 276 deletions

View File

@@ -254,41 +254,46 @@ jobs:
with:
node-version: "24"
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.5.2
- name: Install adminfront dependencies
run: |
cd adminfront
npx pnpm install -C ../common --no-frozen-lockfile
npx pnpm install --no-frozen-lockfile
pnpm install -C ../common --no-frozen-lockfile
pnpm install --no-frozen-lockfile
- name: Biome check adminfront
run: |
cd adminfront
npx biome check . --formatter-enabled=false --assist-enabled=false
npx biome check . --linter-enabled=false --assist-enabled=false
pnpm exec biome check . --formatter-enabled=false --assist-enabled=false
pnpm exec biome check . --linter-enabled=false --assist-enabled=false
- name: Install devfront dependencies
run: |
cd devfront
npx pnpm install -C ../common --no-frozen-lockfile
npx pnpm install --no-frozen-lockfile
pnpm install -C ../common --no-frozen-lockfile
pnpm install --no-frozen-lockfile
- name: Biome check devfront
run: |
cd devfront
npx biome check . --formatter-enabled=false --assist-enabled=false
npx biome check . --linter-enabled=false --assist-enabled=false
pnpm exec biome check . --formatter-enabled=false --assist-enabled=false
pnpm exec biome check . --linter-enabled=false --assist-enabled=false
- name: Install orgfront dependencies
run: |
cd orgfront
npx pnpm install -C ../common --no-frozen-lockfile
npx pnpm install --no-frozen-lockfile
pnpm install -C ../common --no-frozen-lockfile
pnpm install --no-frozen-lockfile
- name: Biome check orgfront
run: |
cd orgfront
npx biome check . --formatter-enabled=false --assist-enabled=false
npx biome check . --linter-enabled=false --assist-enabled=false
pnpm exec biome check . --formatter-enabled=false --assist-enabled=false
pnpm exec biome check . --linter-enabled=false --assist-enabled=false
backend-tests:
needs:
@@ -731,9 +736,9 @@ jobs:
set +e
cd userfront-e2e
if [ "$USERFRONT_E2E_FULL" = "true" ]; then
test_command="npm test"
test_command="npx playwright test"
else
test_command="npm test -- --project=chromium-desktop --project=chromium-mobile-webapp"
test_command="npx playwright test --project=chromium-desktop --project=chromium-mobile-webapp"
fi
workers="${USERFRONT_E2E_WORKERS:-2}"
case "$workers" in
@@ -759,10 +764,10 @@ jobs:
echo "3. \`cd ../userfront && flutter build web --wasm --release\`"
if [ "$USERFRONT_E2E_FULL" = "true" ]; then
echo "4. \`cd ../userfront-e2e && npx playwright install --with-deps\`"
echo "5. \`npm test\`"
echo "5. \`npx playwright test\`"
else
echo "4. \`cd ../userfront-e2e && npx playwright install --with-deps chromium\`"
echo "5. \`npm test -- --project=chromium-desktop --project=chromium-mobile-webapp\`"
echo "5. \`npx playwright test --project=chromium-desktop --project=chromium-mobile-webapp\`"
fi
echo
echo "## Log Tail (last 200 lines)"
@@ -1250,6 +1255,11 @@ jobs:
with:
node-version: "24"
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.5.2
- name: Get Playwright version
id: playwright-version
run: |
@@ -1323,10 +1333,11 @@ jobs:
path: |
reports/adminfront-test-failure-report.md
reports/adminfront-install.log
reports/adminfront-build.log
reports/adminfront-provision.log
reports/adminfront-test.log
adminfront/playwright-report
adminfront/test-results
reports/adminfront-playwright-report
reports/adminfront-test-results
if-no-files-found: ignore
devfront-tests:

View File

@@ -29,39 +29,58 @@ jobs:
IMAGE_DEPLOY_PUBLIC_URL: ${{ vars.PROD_FRONTEND_URL }}
IMAGE_DEPLOY_COMPOSE_TEMPLATE: deploy/templates/docker-compose.images.yaml
IMAGE_DEPLOY_BUNDLE_FILE: prod-image-deploy-bundle.tgz
ADMINFRONT_URL: ${{ vars.ADMINFRONT_URL }}
DEVFRONT_URL: ${{ vars.DEVFRONT_URL }}
ORGFRONT_URL: ${{ vars.ORGFRONT_URL }}
VITE_OIDC_AUTHORITY: ${{ vars.VITE_OIDC_AUTHORITY }}
ADMINFRONT_URL: ${{ vars.PROD_ADMINFRONT_URL }}
DEVFRONT_URL: ${{ vars.PROD_DEVFRONT_URL }}
ORGFRONT_URL: ${{ vars.PROD_ORGFRONT_URL }}
VITE_OIDC_AUTHORITY: ${{ vars.PROD_VITE_OIDC_AUTHORITY }}
IMAGE_DEPLOY_BACKEND_LOG_LEVEL: ${{ vars.PROD_BACKEND_LOG_LEVEL }}
IMAGE_DEPLOY_CLIENT_LOG_DEBUG: ${{ vars.PROD_CLIENT_LOG_DEBUG }}
IMAGE_DEPLOY_BACKEND_PUBLIC_URL: ${{ vars.PROD_BACKEND_URL || vars.PROD_FRONTEND_URL }}
IMAGE_DEPLOY_BACKEND_URL: ${{ vars.PROD_BACKEND_URL || vars.PROD_FRONTEND_URL }}
WORKS_ADMIN_API_BASE_URL: ${{ vars.PROD_WORKS_ADMIN_API_BASE_URL }}
WORKS_ADMIN_OAUTH_TOKEN_URL: ${{ vars.PROD_WORKS_ADMIN_OAUTH_TOKEN_URL }}
PROFILE_CACHE_TTL: ${{ vars.PROD_PROFILE_CACHE_TTL }}
NAVER_CLOUD_ACCESS_KEY: ${{ secrets.PROD_NAVER_CLOUD_ACCESS_KEY }}
NAVER_CLOUD_SECRET_KEY: ${{ secrets.PROD_NAVER_CLOUD_SECRET_KEY }}
NAVER_CLOUD_SERVICE_ID: ${{ vars.PROD_NAVER_CLOUD_SERVICE_ID }}
NAVER_SENDER_PHONE_NUMBER: ${{ vars.PROD_NAVER_SENDER_PHONE_NUMBER }}
AWS_REGION: ${{ vars.PROD_AWS_REGION }}
AWS_ACCESS_KEY_ID: ${{ vars.PROD_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.PROD_AWS_SECRET_ACCESS_KEY }}
AWS_SES_SENDER: ${{ vars.PROD_AWS_SES_SENDER }}
CORS_ALLOWED_ORIGINS: ${{ vars.PROD_CORS_ALLOWED_ORIGINS }}
OATHKEEPER_API_URL: ${{ vars.PROD_OATHKEEPER_API_URL }}
CLICKHOUSE_HOST: ${{ vars.PROD_CLICKHOUSE_HOST }}
CLICKHOUSE_USER: ${{ vars.PROD_CLICKHOUSE_USER }}
IMAGE_DEPLOY_DB_PORT: ${{ vars.PROD_DB_PORT }}
IMAGE_DEPLOY_REDIS_PORT: ${{ vars.PROD_REDIS_PORT }}
IMAGE_DEPLOY_CLICKHOUSE_PORT_HTTP: ${{ vars.PROD_CLICKHOUSE_PORT_HTTP }}
IMAGE_DEPLOY_CLICKHOUSE_PORT_NATIVE: ${{ vars.PROD_CLICKHOUSE_PORT_NATIVE }}
IMAGE_DEPLOY_BACKEND_PORT: ${{ vars.PROD_BACKEND_PORT }}
IMAGE_DEPLOY_FRONTEND_PORT: ${{ vars.PROD_FRONTEND_PORT }}
ADMINFRONT_PORT: ${{ vars.ADMINFRONT_PORT }}
DEVFRONT_PORT: ${{ vars.DEVFRONT_PORT }}
ORGFRONT_PORT: ${{ vars.ORGFRONT_PORT }}
ADMINFRONT_PORT: ${{ vars.PROD_ADMINFRONT_PORT }}
DEVFRONT_PORT: ${{ vars.PROD_DEVFRONT_PORT }}
ORGFRONT_PORT: ${{ vars.PROD_ORGFRONT_PORT }}
IMAGE_DEPLOY_OATHKEEPER_PROXY_PORT: ${{ vars.PROD_OATHKEEPER_PROXY_PORT }}
IMAGE_DEPLOY_DOMAIN_SUFFIX: ${{ vars.PROD_DOMAIN_SUFFIX }}
ADMINFRONT_CALLBACK_URLS: ${{ vars.ADMINFRONT_CALLBACK_URLS }}
DEVFRONT_CALLBACK_URLS: ${{ vars.DEVFRONT_CALLBACK_URLS }}
ORGFRONT_CALLBACK_URLS: ${{ vars.ORGFRONT_CALLBACK_URLS }}
HYDRA_REFRESH_TOKEN_TTL: ${{ vars.HYDRA_REFRESH_TOKEN_TTL }}
ORY_POSTGRES_USER: ${{ vars.ORY_POSTGRES_USER }}
ORY_POSTGRES_DB: ${{ vars.ORY_POSTGRES_DB }}
KRATOS_DB: ${{ vars.KRATOS_DB }}
HYDRA_DB: ${{ vars.HYDRA_DB }}
KETO_DB: ${{ vars.KETO_DB }}
KRATOS_VERSION: ${{ vars.KRATOS_VERSION }}
HYDRA_VERSION: ${{ vars.HYDRA_VERSION }}
KETO_VERSION: ${{ vars.KETO_VERSION }}
OATHKEEPER_VERSION: ${{ vars.OATHKEEPER_VERSION }}
ORY_POSTGRES_TAG: ${{ vars.ORY_POSTGRES_TAG }}
OATHKEEPER_UID: ${{ vars.OATHKEEPER_UID }}
OATHKEEPER_GID: ${{ vars.OATHKEEPER_GID }}
OATHKEEPER_INTROSPECT_CLIENT_ID: ${{ vars.OATHKEEPER_INTROSPECT_CLIENT_ID }}
ADMIN_EMAIL: ${{ vars.ADMIN_EMAIL }}
ADMINFRONT_CALLBACK_URLS: ${{ vars.PROD_ADMINFRONT_CALLBACK_URLS }}
DEVFRONT_CALLBACK_URLS: ${{ vars.PROD_DEVFRONT_CALLBACK_URLS }}
ORGFRONT_CALLBACK_URLS: ${{ vars.PROD_ORGFRONT_CALLBACK_URLS }}
HYDRA_REFRESH_TOKEN_TTL: ${{ vars.PROD_HYDRA_REFRESH_TOKEN_TTL }}
ORY_POSTGRES_USER: ${{ vars.PROD_ORY_POSTGRES_USER }}
ORY_POSTGRES_DB: ${{ vars.PROD_ORY_POSTGRES_DB }}
KRATOS_DB: ${{ vars.PROD_KRATOS_DB }}
HYDRA_DB: ${{ vars.PROD_HYDRA_DB }}
KETO_DB: ${{ vars.PROD_KETO_DB }}
KRATOS_VERSION: ${{ vars.PROD_KRATOS_VERSION }}
HYDRA_VERSION: ${{ vars.PROD_HYDRA_VERSION }}
KETO_VERSION: ${{ vars.PROD_KETO_VERSION }}
OATHKEEPER_VERSION: ${{ vars.PROD_OATHKEEPER_VERSION }}
ORY_POSTGRES_TAG: ${{ vars.PROD_ORY_POSTGRES_TAG }}
OATHKEEPER_UID: ${{ vars.PROD_OATHKEEPER_UID }}
OATHKEEPER_GID: ${{ vars.PROD_OATHKEEPER_GID }}
OATHKEEPER_INTROSPECT_CLIENT_ID: ${{ vars.PROD_OATHKEEPER_INTROSPECT_CLIENT_ID }}
ADMIN_EMAIL: ${{ vars.PROD_ADMIN_EMAIL }}
HARBOR_HOSTNAME: ${{ vars.HARBOR_HOSTNAME }}
BACKEND_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/backend
USERFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/userfront

View File

@@ -101,33 +101,33 @@ jobs:
"PROD_BACKEND_PORT=${{ vars.PROD_BACKEND_PORT }}" \
"BACKEND_PORT=3000" \
"USERFRONT_PORT=${{ vars.PROD_FRONTEND_PORT }}" \
"ADMINFRONT_PORT=${{ vars.ADMINFRONT_PORT }}" \
"DEVFRONT_PORT=${{ vars.DEVFRONT_PORT }}" \
"ORGFRONT_PORT=${{ vars.ORGFRONT_PORT }}" \
"ADMINFRONT_PORT=${{ vars.PROD_ADMINFRONT_PORT }}" \
"DEVFRONT_PORT=${{ vars.PROD_DEVFRONT_PORT }}" \
"ORGFRONT_PORT=${{ vars.PROD_ORGFRONT_PORT }}" \
"DB_USER=${{ vars.PROD_DB_USER }}" \
"DB_PASSWORD=${{ secrets.PROD_DB_PASSWORD }}" \
"DB_NAME=${{ vars.PROD_DB_NAME }}" \
"COOKIE_SECRET=${{ secrets.PROD_COOKIE_SECRET }}" \
"JWT_SECRET=${{ secrets.PROD_JWT_SECRET }}" \
"REDIS_ADDR=${{ vars.PROD_REDIS_ADDR }}" \
"NAVER_CLOUD_ACCESS_KEY=${{ vars.NAVER_CLOUD_ACCESS_KEY }}" \
"NAVER_CLOUD_SECRET_KEY=${{ secrets.NAVER_CLOUD_SECRET_KEY }}" \
"NAVER_CLOUD_SERVICE_ID=${{ vars.NAVER_CLOUD_SERVICE_ID }}" \
"NAVER_SENDER_PHONE_NUMBER=${{ vars.NAVER_SENDER_PHONE_NUMBER }}" \
"AWS_REGION=${{ vars.AWS_REGION }}" \
"AWS_ACCESS_KEY_ID=${{ vars.AWS_ACCESS_KEY_ID }}" \
"AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" \
"AWS_SES_SENDER=${{ vars.AWS_SES_SENDER }}" \
"NAVER_CLOUD_ACCESS_KEY=${{ secrets.PROD_NAVER_CLOUD_ACCESS_KEY }}" \
"NAVER_CLOUD_SECRET_KEY=${{ secrets.PROD_NAVER_CLOUD_SECRET_KEY }}" \
"NAVER_CLOUD_SERVICE_ID=${{ vars.PROD_NAVER_CLOUD_SERVICE_ID }}" \
"NAVER_SENDER_PHONE_NUMBER=${{ vars.PROD_NAVER_SENDER_PHONE_NUMBER }}" \
"AWS_REGION=${{ vars.PROD_AWS_REGION }}" \
"AWS_ACCESS_KEY_ID=${{ vars.PROD_AWS_ACCESS_KEY_ID }}" \
"AWS_SECRET_ACCESS_KEY=${{ secrets.PROD_AWS_SECRET_ACCESS_KEY }}" \
"AWS_SES_SENDER=${{ vars.PROD_AWS_SES_SENDER }}" \
"USERFRONT_URL=${{ vars.PROD_FRONTEND_URL }}" \
"ADMINFRONT_URL=${{ vars.ADMINFRONT_URL }}" \
"DEVFRONT_URL=${{ vars.DEVFRONT_URL }}" \
"ORGFRONT_URL=${{ vars.ORGFRONT_URL }}" \
"ADMINFRONT_URL=${{ vars.PROD_ADMINFRONT_URL }}" \
"DEVFRONT_URL=${{ vars.PROD_DEVFRONT_URL }}" \
"ORGFRONT_URL=${{ vars.PROD_ORGFRONT_URL }}" \
"BACKEND_URL=${{ vars.PROD_BACKEND_URL }}" \
"VITE_OIDC_AUTHORITY=${{ vars.VITE_OIDC_AUTHORITY }}" \
"HYDRA_REFRESH_TOKEN_TTL=${{ vars.HYDRA_REFRESH_TOKEN_TTL }}" \
"ADMINFRONT_CALLBACK_URLS=${{ vars.ADMINFRONT_CALLBACK_URLS }}" \
"DEVFRONT_CALLBACK_URLS=${{ vars.DEVFRONT_CALLBACK_URLS }}" \
"ORGFRONT_CALLBACK_URLS=${{ vars.ORGFRONT_CALLBACK_URLS }}" \
"VITE_OIDC_AUTHORITY=${{ vars.PROD_VITE_OIDC_AUTHORITY }}" \
"HYDRA_REFRESH_TOKEN_TTL=${{ vars.PROD_HYDRA_REFRESH_TOKEN_TTL }}" \
"ADMINFRONT_CALLBACK_URLS=${{ vars.PROD_ADMINFRONT_CALLBACK_URLS }}" \
"DEVFRONT_CALLBACK_URLS=${{ vars.PROD_DEVFRONT_CALLBACK_URLS }}" \
"ORGFRONT_CALLBACK_URLS=${{ vars.PROD_ORGFRONT_CALLBACK_URLS }}" \
> .env
required_dotenv_keys="

View File

@@ -18,13 +18,13 @@ jobs:
- name: Setup SSH
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.STAGE_SSH_PRIVATE_KEY }}
ssh-private-key: ${{ secrets.STG_SSH_PRIVATE_KEY }}
- name: Deploy to Staging by git pull
env:
DEPLOY_PATH: ${{ vars.STAGE_DEPLOY_PATH }}
STAGE_HOST: ${{ vars.STAGE_HOST }}
STAGE_USER: ${{ vars.STAGE_USER }}
DEPLOY_PATH: ${{ vars.STG_DEPLOY_PATH }}
STAGE_HOST: ${{ vars.STG_HOST }}
STAGE_USER: ${{ vars.STG_USER }}
TARGET_BRANCH: ${{ inputs.target_branch }}
run: |
set -euo pipefail
@@ -48,99 +48,99 @@ jobs:
APP_ENV=stage
BACKEND_LOG_LEVEL=debug
CLIENT_LOG_DEBUG=true
WORKS_ADMIN_API_BASE_URL=${{ vars.WORKS_ADMIN_API_BASE_URL }}
WORKS_ADMIN_OAUTH_TOKEN_URL=${{ vars.WORKS_ADMIN_OAUTH_TOKEN_URL }}
WORKS_ADMIN_API_BASE_URL=${{ vars.STG_WORKS_ADMIN_API_BASE_URL }}
WORKS_ADMIN_OAUTH_TOKEN_URL=${{ vars.STG_WORKS_ADMIN_OAUTH_TOKEN_URL }}
TZ=Asia/Seoul
IDP_PROVIDER=ory
# DB & Clickhouse
DB_PORT=${{ vars.DB_PORT }}
CLICKHOUSE_PORT_HTTP=${{ vars.CLICKHOUSE_PORT_HTTP }}
CLICKHOUSE_PORT_NATIVE=${{ vars.CLICKHOUSE_PORT_NATIVE }}
CLICKHOUSE_HOST=${{ vars.CLICKHOUSE_HOST }}
CLICKHOUSE_USER=${{ vars.CLICKHOUSE_USER }}
CLICKHOUSE_PASSWORD=${{ secrets.CLICKHOUSE_PASSWORD }}
DB_PORT=${{ vars.STG_DB_PORT }}
CLICKHOUSE_PORT_HTTP=${{ vars.STG_CLICKHOUSE_PORT_HTTP }}
CLICKHOUSE_PORT_NATIVE=${{ vars.STG_CLICKHOUSE_PORT_NATIVE }}
CLICKHOUSE_HOST=${{ vars.STG_CLICKHOUSE_HOST }}
CLICKHOUSE_USER=${{ vars.STG_CLICKHOUSE_USER }}
CLICKHOUSE_PASSWORD=${{ secrets.STG_CLICKHOUSE_PASSWORD }}
BACKEND_PORT=${{ vars.BACKEND_PORT }}
ADMINFRONT_PORT=${{ vars.ADMINFRONT_PORT }}
DEVFRONT_PORT=${{ vars.DEVFRONT_PORT }}
ORGFRONT_PORT=${{ vars.ORGFRONT_PORT }}
USERFRONT_PORT=${{ vars.USERFRONT_PORT }}
BACKEND_PORT=${{ vars.STG_BACKEND_PORT }}
ADMINFRONT_PORT=${{ vars.STG_ADMINFRONT_PORT }}
DEVFRONT_PORT=${{ vars.STG_DEVFRONT_PORT }}
ORGFRONT_PORT=${{ vars.STG_ORGFRONT_PORT }}
USERFRONT_PORT=${{ vars.STG_USERFRONT_PORT }}
OATHKEEPER_API_URL=${{ vars.OATHKEEPER_API_URL }}
OATHKEEPER_API_URL=${{ vars.STG_OATHKEEPER_API_URL }}
DB_USER=${{ vars.DB_USER }}
DB_USER=${{ vars.STG_DB_USER }}
DB_PASSWORD=${{ secrets.STG_DB_PASSWORD }}
DB_NAME=${{ vars.DB_NAME }}
DB_NAME=${{ vars.STG_DB_NAME }}
COOKIE_SECRET=${{ secrets.STG_COOKIE_SECRET }}
JWT_SECRET=${{ secrets.STG_JWT_SECRET }}
REDIS_ADDR=${{ vars.REDIS_ADDR }}
CORS_ALLOWED_ORIGINS=${{ vars.CORS_ALLOWED_ORIGINS }}
REDIS_ADDR=${{ vars.STG_REDIS_ADDR }}
CORS_ALLOWED_ORIGINS=${{ vars.STG_CORS_ALLOWED_ORIGINS }}
AUDIT_WORKER_COUNT=5
AUDIT_QUEUE_SIZE=2000
PROFILE_CACHE_TTL=${{ vars.PROFILE_CACHE_TTL }}
NAVER_CLOUD_ACCESS_KEY=${{ vars.NAVER_CLOUD_ACCESS_KEY }}
NAVER_CLOUD_SECRET_KEY=${{ secrets.NAVER_CLOUD_SECRET_KEY }}
NAVER_CLOUD_SERVICE_ID=${{ vars.NAVER_CLOUD_SERVICE_ID }}
NAVER_SENDER_PHONE_NUMBER=${{ vars.NAVER_SENDER_PHONE_NUMBER }}
AWS_REGION=${{ vars.AWS_REGION }}
AWS_ACCESS_KEY_ID=${{ vars.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_SES_SENDER=${{ vars.AWS_SES_SENDER }}
ADMIN_EMAIL=${{ vars.ADMIN_EMAIL }}
PROFILE_CACHE_TTL=${{ vars.STG_PROFILE_CACHE_TTL }}
NAVER_CLOUD_ACCESS_KEY=${{ secrets.STG_NAVER_CLOUD_ACCESS_KEY }}
NAVER_CLOUD_SECRET_KEY=${{ secrets.STG_NAVER_CLOUD_SECRET_KEY }}
NAVER_CLOUD_SERVICE_ID=${{ vars.STG_NAVER_CLOUD_SERVICE_ID }}
NAVER_SENDER_PHONE_NUMBER=${{ vars.STG_NAVER_SENDER_PHONE_NUMBER }}
AWS_REGION=${{ vars.STG_AWS_REGION }}
AWS_ACCESS_KEY_ID=${{ vars.STG_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY=${{ secrets.STG_AWS_SECRET_ACCESS_KEY }}
AWS_SES_SENDER=${{ vars.STG_AWS_SES_SENDER }}
ADMIN_EMAIL=${{ vars.STG_ADMIN_EMAIL }}
ADMIN_PASSWORD=${{ secrets.STG_ADMIN_PASSWORD }}
USERFRONT_URL=${{ vars.USERFRONT_URL }}
ADMINFRONT_URL=${{ vars.ADMINFRONT_URL }}
DEVFRONT_URL=${{ vars.DEVFRONT_URL }}
ORGFRONT_URL=${{ vars.ORGFRONT_URL }}
BACKEND_PUBLIC_URL=${{ vars.BACKEND_URL }}
BACKEND_URL=${{ vars.BACKEND_URL }}
OATHKEEPER_PUBLIC_URL=${{ vars.OATHKEEPER_PUBLIC_URL }}
ORY_POSTGRES_TAG=${{ vars.ORY_POSTGRES_TAG }}
ORY_POSTGRES_USER=${{ vars.ORY_POSTGRES_USER }}
USERFRONT_URL=${{ vars.STG_USERFRONT_URL }}
ADMINFRONT_URL=${{ vars.STG_ADMINFRONT_URL }}
DEVFRONT_URL=${{ vars.STG_DEVFRONT_URL }}
ORGFRONT_URL=${{ vars.STG_ORGFRONT_URL }}
BACKEND_PUBLIC_URL=${{ vars.STG_BACKEND_URL }}
BACKEND_URL=${{ vars.STG_BACKEND_URL }}
OATHKEEPER_PUBLIC_URL=${{ vars.STG_OATHKEEPER_PUBLIC_URL }}
ORY_POSTGRES_TAG=${{ vars.STG_ORY_POSTGRES_TAG }}
ORY_POSTGRES_USER=${{ vars.STG_ORY_POSTGRES_USER }}
ORY_POSTGRES_PASSWORD=${{ secrets.STG_ORY_POSTGRES_PASSWORD }}
ORY_POSTGRES_DB=${{ vars.ORY_POSTGRES_DB }}
KRATOS_DB=${{ vars.KRATOS_DB }}
HYDRA_DB=${{ vars.HYDRA_DB }}
KETO_DB=${{ vars.KETO_DB }}
KRATOS_VERSION=${{ vars.KRATOS_VERSION }}
KRATOS_UI_NODE_VERSION=${{ vars.KRATOS_UI_NODE_VERSION }}
HYDRA_VERSION=${{ vars.HYDRA_VERSION }}
KETO_VERSION=${{ vars.KETO_VERSION }}
ORY_SDK_URL=${{ vars.ORY_SDK_URL }}
KRATOS_PUBLIC_URL=${{ vars.KRATOS_PUBLIC_URL }}
KRATOS_ADMIN_URL=${{ vars.KRATOS_ADMIN_URL }}
KRATOS_BROWSER_URL=${{ vars.KRATOS_BROWSER_URL }}
KRATOS_UI_URL=${{ vars.KRATOS_UI_URL }}
HYDRA_ADMIN_URL=${{ vars.HYDRA_ADMIN_URL }}
HYDRA_PUBLIC_URL=${{ vars.HYDRA_PUBLIC_URL }}
HYDRA_REFRESH_TOKEN_TTL=${{ vars.HYDRA_REFRESH_TOKEN_TTL }}
JWKS_URL=${{ vars.JWKS_URL }}
OATHKEEPER_VERSION=${{ vars.OATHKEEPER_VERSION }}
OATHKEEPER_UID=${{ vars.OATHKEEPER_UID }}
OATHKEEPER_GID=${{ vars.OATHKEEPER_GID }}
OATHKEEPER_HEALTH_URL=${{ vars.OATHKEEPER_HEALTH_URL }}
OATHKEEPER_HEALTH_INTERVAL_SECONDS=${{ vars.OATHKEEPER_HEALTH_INTERVAL_SECONDS }}
OATHKEEPER_HEALTH_TIMEOUT_SECONDS=${{ vars.OATHKEEPER_HEALTH_TIMEOUT_SECONDS }}
OATHKEEPER_HEALTH_ENABLED=${{ vars.OATHKEEPER_HEALTH_ENABLED }}
CSRF_COOKIE_NAME=${{ vars.CSRF_COOKIE_NAME }}
ORY_POSTGRES_DB=${{ vars.STG_ORY_POSTGRES_DB }}
KRATOS_DB=${{ vars.STG_KRATOS_DB }}
HYDRA_DB=${{ vars.STG_HYDRA_DB }}
KETO_DB=${{ vars.STG_KETO_DB }}
KRATOS_VERSION=${{ vars.STG_KRATOS_VERSION }}
KRATOS_UI_NODE_VERSION=${{ vars.STG_KRATOS_UI_NODE_VERSION }}
HYDRA_VERSION=${{ vars.STG_HYDRA_VERSION }}
KETO_VERSION=${{ vars.STG_KETO_VERSION }}
ORY_SDK_URL=${{ vars.STG_ORY_SDK_URL }}
KRATOS_PUBLIC_URL=${{ vars.STG_KRATOS_PUBLIC_URL }}
KRATOS_ADMIN_URL=${{ vars.STG_KRATOS_ADMIN_URL }}
KRATOS_BROWSER_URL=${{ vars.STG_KRATOS_BROWSER_URL }}
KRATOS_UI_URL=${{ vars.STG_KRATOS_UI_URL }}
HYDRA_ADMIN_URL=${{ vars.STG_HYDRA_ADMIN_URL }}
HYDRA_PUBLIC_URL=${{ vars.STG_HYDRA_PUBLIC_URL }}
HYDRA_REFRESH_TOKEN_TTL=${{ vars.STG_HYDRA_REFRESH_TOKEN_TTL }}
JWKS_URL=${{ vars.STG_JWKS_URL }}
OATHKEEPER_VERSION=${{ vars.STG_OATHKEEPER_VERSION }}
OATHKEEPER_UID=${{ vars.STG_OATHKEEPER_UID }}
OATHKEEPER_GID=${{ vars.STG_OATHKEEPER_GID }}
OATHKEEPER_HEALTH_URL=${{ vars.STG_OATHKEEPER_HEALTH_URL }}
OATHKEEPER_HEALTH_INTERVAL_SECONDS=${{ vars.STG_OATHKEEPER_HEALTH_INTERVAL_SECONDS }}
OATHKEEPER_HEALTH_TIMEOUT_SECONDS=${{ vars.STG_OATHKEEPER_HEALTH_TIMEOUT_SECONDS }}
OATHKEEPER_HEALTH_ENABLED=${{ vars.STG_OATHKEEPER_HEALTH_ENABLED }}
CSRF_COOKIE_NAME=${{ vars.STG_CSRF_COOKIE_NAME }}
CSRF_COOKIE_SECRET=${{ secrets.STG_CSRF_COOKIE_SECRET }}
# Frontend/Ory URL configs for Staging
VITE_OIDC_AUTHORITY=${{ vars.VITE_OIDC_AUTHORITY }}
ADMINFRONT_CALLBACK_URLS=${{ vars.ADMINFRONT_CALLBACK_URLS }}
DEVFRONT_CALLBACK_URLS=${{ vars.DEVFRONT_CALLBACK_URLS }}
ORGFRONT_CALLBACK_URLS=${{ vars.ORGFRONT_CALLBACK_URLS }}
KRATOS_ALLOWED_RETURN_URLS_JSON=${{ vars.KRATOS_ALLOWED_RETURN_URLS_JSON }}
KRATOS_ALLOWED_RETURN_URLS_EXTRA=${{ vars.KRATOS_ALLOWED_RETURN_URLS_EXTRA }}
# OATHKEEPER_INTROSPECT_CLIENT_ID=${{ vars.OATHKEEPER_INTROSPECT_CLIENT_ID }}
VITE_OIDC_AUTHORITY=${{ vars.STG_VITE_OIDC_AUTHORITY }}
ADMINFRONT_CALLBACK_URLS=${{ vars.STG_ADMINFRONT_CALLBACK_URLS }}
DEVFRONT_CALLBACK_URLS=${{ vars.STG_DEVFRONT_CALLBACK_URLS }}
ORGFRONT_CALLBACK_URLS=${{ vars.STG_ORGFRONT_CALLBACK_URLS }}
KRATOS_ALLOWED_RETURN_URLS_JSON=${{ vars.STG_KRATOS_ALLOWED_RETURN_URLS_JSON }}
KRATOS_ALLOWED_RETURN_URLS_EXTRA=${{ vars.STG_KRATOS_ALLOWED_RETURN_URLS_EXTRA }}
# OATHKEEPER_INTROSPECT_CLIENT_ID=${{ vars.STG_OATHKEEPER_INTROSPECT_CLIENT_ID }}
# OATHKEEPER_INTROSPECT_CLIENT_SECRET=${{ secrets.STG_OATHKEEPER_INTROSPECT_CLIENT_SECRET }}
# Monitoring & Alerts
SMS_WEBHOOK_PORT=${{ vars.SMS_WEBHOOK_PORT || '8080' }}
MONITOR_RECIPIENT_PHONES=${{ vars.MONITOR_RECIPIENT_PHONES || '01012345678,01098765432' }}
LOKI_URL=${{ vars.LOKI_URL || 'http://loki:3100/loki/api/v1/push' }}
SMS_WEBHOOK_PORT=${{ vars.STG_SMS_WEBHOOK_PORT || '8080' }}
MONITOR_RECIPIENT_PHONES=${{ vars.STG_MONITOR_RECIPIENT_PHONES || '01012345678,01098765432' }}
LOKI_URL=${{ vars.STG_LOKI_URL || 'http://loki:3100/loki/api/v1/push' }}
EOF
# 코드 업데이트 (Git)

View File

@@ -18,50 +18,69 @@ jobs:
- name: Setup SSH
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.STAGE_SSH_PRIVATE_KEY }}
ssh-private-key: ${{ secrets.STG_SSH_PRIVATE_KEY }}
- name: Build staging deployment bundle
env:
IMAGE_TAG: ${{ github.event.inputs.image_tag }}
IMAGE_DEPLOY_ENV: stage
IMAGE_DEPLOY_INSTANCE_NAME: ${{ vars.STAGE_INSTANCE_NAME }}
IMAGE_DEPLOY_PORT_PREFIX: ${{ vars.STAGE_PORT_PREFIX }}
IMAGE_DEPLOY_PUBLIC_URL: ${{ vars.USERFRONT_URL }}
IMAGE_DEPLOY_INSTANCE_NAME: ${{ vars.STG_INSTANCE_NAME }}
IMAGE_DEPLOY_PORT_PREFIX: ${{ vars.STG_PORT_PREFIX }}
IMAGE_DEPLOY_PUBLIC_URL: ${{ vars.STG_USERFRONT_URL }}
IMAGE_DEPLOY_COMPOSE_TEMPLATE: deploy/templates/docker-compose.images.yaml
IMAGE_DEPLOY_BUNDLE_FILE: stage-image-deploy-bundle.tgz
ADMINFRONT_URL: ${{ vars.ADMINFRONT_URL }}
DEVFRONT_URL: ${{ vars.DEVFRONT_URL }}
ORGFRONT_URL: ${{ vars.ORGFRONT_URL }}
VITE_OIDC_AUTHORITY: ${{ vars.VITE_OIDC_AUTHORITY }}
IMAGE_DEPLOY_DB_PORT: ${{ vars.DB_PORT }}
IMAGE_DEPLOY_REDIS_PORT: ${{ vars.REDIS_PORT }}
IMAGE_DEPLOY_CLICKHOUSE_PORT_HTTP: ${{ vars.CLICKHOUSE_PORT_HTTP }}
IMAGE_DEPLOY_CLICKHOUSE_PORT_NATIVE: ${{ vars.CLICKHOUSE_PORT_NATIVE }}
IMAGE_DEPLOY_BACKEND_PORT: ${{ vars.BACKEND_PORT }}
IMAGE_DEPLOY_FRONTEND_PORT: ${{ vars.USERFRONT_PORT }}
ADMINFRONT_PORT: ${{ vars.ADMINFRONT_PORT }}
DEVFRONT_PORT: ${{ vars.DEVFRONT_PORT }}
ORGFRONT_PORT: ${{ vars.ORGFRONT_PORT }}
IMAGE_DEPLOY_OATHKEEPER_PROXY_PORT: ${{ vars.OATHKEEPER_PROXY_PORT }}
IMAGE_DEPLOY_DOMAIN_SUFFIX: ${{ vars.DOMAIN_SUFFIX }}
ADMINFRONT_CALLBACK_URLS: ${{ vars.ADMINFRONT_CALLBACK_URLS }}
DEVFRONT_CALLBACK_URLS: ${{ vars.DEVFRONT_CALLBACK_URLS }}
ORGFRONT_CALLBACK_URLS: ${{ vars.ORGFRONT_CALLBACK_URLS }}
HYDRA_REFRESH_TOKEN_TTL: ${{ vars.HYDRA_REFRESH_TOKEN_TTL }}
ORY_POSTGRES_USER: ${{ vars.ORY_POSTGRES_USER }}
ORY_POSTGRES_DB: ${{ vars.ORY_POSTGRES_DB }}
KRATOS_DB: ${{ vars.KRATOS_DB }}
HYDRA_DB: ${{ vars.HYDRA_DB }}
KETO_DB: ${{ vars.KETO_DB }}
KRATOS_VERSION: ${{ vars.KRATOS_VERSION }}
HYDRA_VERSION: ${{ vars.HYDRA_VERSION }}
KETO_VERSION: ${{ vars.KETO_VERSION }}
OATHKEEPER_VERSION: ${{ vars.OATHKEEPER_VERSION }}
ORY_POSTGRES_TAG: ${{ vars.ORY_POSTGRES_TAG }}
OATHKEEPER_UID: ${{ vars.OATHKEEPER_UID }}
OATHKEEPER_GID: ${{ vars.OATHKEEPER_GID }}
OATHKEEPER_INTROSPECT_CLIENT_ID: ${{ vars.OATHKEEPER_INTROSPECT_CLIENT_ID }}
ADMIN_EMAIL: ${{ vars.ADMIN_EMAIL }}
ADMINFRONT_URL: ${{ vars.STG_ADMINFRONT_URL }}
DEVFRONT_URL: ${{ vars.STG_DEVFRONT_URL }}
ORGFRONT_URL: ${{ vars.STG_ORGFRONT_URL }}
VITE_OIDC_AUTHORITY: ${{ vars.STG_VITE_OIDC_AUTHORITY }}
IMAGE_DEPLOY_BACKEND_LOG_LEVEL: ${{ vars.STG_BACKEND_LOG_LEVEL || 'debug' }}
IMAGE_DEPLOY_CLIENT_LOG_DEBUG: ${{ vars.STG_CLIENT_LOG_DEBUG || 'true' }}
IMAGE_DEPLOY_BACKEND_PUBLIC_URL: ${{ vars.STG_BACKEND_URL }}
IMAGE_DEPLOY_BACKEND_URL: ${{ vars.STG_BACKEND_URL }}
WORKS_ADMIN_API_BASE_URL: ${{ vars.STG_WORKS_ADMIN_API_BASE_URL }}
WORKS_ADMIN_OAUTH_TOKEN_URL: ${{ vars.STG_WORKS_ADMIN_OAUTH_TOKEN_URL }}
PROFILE_CACHE_TTL: ${{ vars.STG_PROFILE_CACHE_TTL }}
NAVER_CLOUD_ACCESS_KEY: ${{ secrets.STG_NAVER_CLOUD_ACCESS_KEY }}
NAVER_CLOUD_SECRET_KEY: ${{ secrets.STG_NAVER_CLOUD_SECRET_KEY }}
NAVER_CLOUD_SERVICE_ID: ${{ vars.STG_NAVER_CLOUD_SERVICE_ID }}
NAVER_SENDER_PHONE_NUMBER: ${{ vars.STG_NAVER_SENDER_PHONE_NUMBER }}
AWS_REGION: ${{ vars.STG_AWS_REGION }}
AWS_ACCESS_KEY_ID: ${{ vars.STG_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.STG_AWS_SECRET_ACCESS_KEY }}
AWS_SES_SENDER: ${{ vars.STG_AWS_SES_SENDER }}
CORS_ALLOWED_ORIGINS: ${{ vars.STG_CORS_ALLOWED_ORIGINS }}
OATHKEEPER_API_URL: ${{ vars.STG_OATHKEEPER_API_URL }}
CLICKHOUSE_HOST: ${{ vars.STG_CLICKHOUSE_HOST }}
CLICKHOUSE_USER: ${{ vars.STG_CLICKHOUSE_USER }}
IMAGE_DEPLOY_DB_PORT: ${{ vars.STG_DB_PORT }}
IMAGE_DEPLOY_REDIS_PORT: ${{ vars.STG_REDIS_PORT }}
IMAGE_DEPLOY_CLICKHOUSE_PORT_HTTP: ${{ vars.STG_CLICKHOUSE_PORT_HTTP }}
IMAGE_DEPLOY_CLICKHOUSE_PORT_NATIVE: ${{ vars.STG_CLICKHOUSE_PORT_NATIVE }}
IMAGE_DEPLOY_BACKEND_PORT: ${{ vars.STG_BACKEND_PORT }}
IMAGE_DEPLOY_FRONTEND_PORT: ${{ vars.STG_USERFRONT_PORT }}
ADMINFRONT_PORT: ${{ vars.STG_ADMINFRONT_PORT }}
DEVFRONT_PORT: ${{ vars.STG_DEVFRONT_PORT }}
ORGFRONT_PORT: ${{ vars.STG_ORGFRONT_PORT }}
IMAGE_DEPLOY_OATHKEEPER_PROXY_PORT: ${{ vars.STG_OATHKEEPER_PROXY_PORT }}
IMAGE_DEPLOY_DOMAIN_SUFFIX: ${{ vars.STG_DOMAIN_SUFFIX }}
ADMINFRONT_CALLBACK_URLS: ${{ vars.STG_ADMINFRONT_CALLBACK_URLS }}
DEVFRONT_CALLBACK_URLS: ${{ vars.STG_DEVFRONT_CALLBACK_URLS }}
ORGFRONT_CALLBACK_URLS: ${{ vars.STG_ORGFRONT_CALLBACK_URLS }}
HYDRA_REFRESH_TOKEN_TTL: ${{ vars.STG_HYDRA_REFRESH_TOKEN_TTL }}
ORY_POSTGRES_USER: ${{ vars.STG_ORY_POSTGRES_USER }}
ORY_POSTGRES_DB: ${{ vars.STG_ORY_POSTGRES_DB }}
KRATOS_DB: ${{ vars.STG_KRATOS_DB }}
HYDRA_DB: ${{ vars.STG_HYDRA_DB }}
KETO_DB: ${{ vars.STG_KETO_DB }}
KRATOS_VERSION: ${{ vars.STG_KRATOS_VERSION }}
HYDRA_VERSION: ${{ vars.STG_HYDRA_VERSION }}
KETO_VERSION: ${{ vars.STG_KETO_VERSION }}
OATHKEEPER_VERSION: ${{ vars.STG_OATHKEEPER_VERSION }}
ORY_POSTGRES_TAG: ${{ vars.STG_ORY_POSTGRES_TAG }}
OATHKEEPER_UID: ${{ vars.STG_OATHKEEPER_UID }}
OATHKEEPER_GID: ${{ vars.STG_OATHKEEPER_GID }}
OATHKEEPER_INTROSPECT_CLIENT_ID: ${{ vars.STG_OATHKEEPER_INTROSPECT_CLIENT_ID }}
ADMIN_EMAIL: ${{ vars.STG_ADMIN_EMAIL }}
HARBOR_HOSTNAME: ${{ vars.HARBOR_HOSTNAME }}
BACKEND_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/backend
USERFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/userfront
@@ -71,7 +90,7 @@ jobs:
IMAGE_DEPLOY_DB_PASSWORD: ${{ secrets.STG_DB_PASSWORD }}
IMAGE_DEPLOY_ORY_POSTGRES_PASSWORD: ${{ secrets.STG_ORY_POSTGRES_PASSWORD }}
IMAGE_DEPLOY_OATHKEEPER_INTROSPECT_CLIENT_SECRET: ${{ secrets.STG_OATHKEEPER_INTROSPECT_CLIENT_SECRET }}
IMAGE_DEPLOY_CLICKHOUSE_PASSWORD: ${{ secrets.CLICKHOUSE_PASSWORD }}
IMAGE_DEPLOY_CLICKHOUSE_PASSWORD: ${{ secrets.STG_CLICKHOUSE_PASSWORD }}
IMAGE_DEPLOY_COOKIE_SECRET: ${{ secrets.STG_COOKIE_SECRET }}
IMAGE_DEPLOY_JWT_SECRET: ${{ secrets.STG_JWT_SECRET }}
IMAGE_DEPLOY_CSRF_COOKIE_SECRET: ${{ secrets.STG_CSRF_COOKIE_SECRET }}
@@ -83,9 +102,9 @@ jobs:
- name: Upload bundle and run requested staging image tag
env:
IMAGE_DEPLOY_BUNDLE_FILE: stage-image-deploy-bundle.tgz
DEPLOY_HOST: ${{ vars.STAGE_HOST }}
DEPLOY_USER: ${{ vars.STAGE_USER }}
DEPLOY_PATH: ${{ vars.STAGE_DEPLOY_PATH }}
DEPLOY_HOST: ${{ vars.STG_HOST }}
DEPLOY_USER: ${{ vars.STG_USER }}
DEPLOY_PATH: ${{ vars.STG_DEPLOY_PATH }}
HARBOR_ENDPOINT: ${{ vars.HARBOR_ENDPOINT }}
HARBOR_ROBOT_ACCOUNT: ${{ vars.HARBOR_ROBOT_ACCOUNT }}
HARBOR_ROBOT_KEY: ${{ secrets.HARBOR_ROBOT_KEY }}

View File

@@ -18,7 +18,7 @@ jobs:
- name: Setup SSH
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.STAGE_SSH_PRIVATE_KEY }}
ssh-private-key: ${{ secrets.STG_SSH_PRIVATE_KEY }}
- name: Deploy to Staging
env:
@@ -30,9 +30,9 @@ jobs:
ORGFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/orgfront
# Staging-specific variables
DEPLOY_PATH: ${{ vars.STAGE_DEPLOY_PATH }}
STAGE_HOST: ${{ vars.STAGE_HOST }}
STAGE_USER: ${{ vars.STAGE_USER }}
DEPLOY_PATH: ${{ vars.STG_DEPLOY_PATH }}
STAGE_HOST: ${{ vars.STG_HOST }}
STAGE_USER: ${{ vars.STG_USER }}
HARBOR_ENDPOINT: ${{ vars.HARBOR_ENDPOINT }}
HARBOR_ROBOT_ACCOUNT: ${{ vars.HARBOR_ROBOT_ACCOUNT }}
@@ -58,88 +58,88 @@ jobs:
APP_ENV=stage
BACKEND_LOG_LEVEL=debug
CLIENT_LOG_DEBUG=true
WORKS_ADMIN_API_BASE_URL=${{ vars.WORKS_ADMIN_API_BASE_URL }}
WORKS_ADMIN_OAUTH_TOKEN_URL=${{ vars.WORKS_ADMIN_OAUTH_TOKEN_URL }}
WORKS_ADMIN_API_BASE_URL=${{ vars.STG_WORKS_ADMIN_API_BASE_URL }}
WORKS_ADMIN_OAUTH_TOKEN_URL=${{ vars.STG_WORKS_ADMIN_OAUTH_TOKEN_URL }}
TZ=Asia/Seoul
IDP_PROVIDER=ory
# DB & Clickhouse
DB_PORT=${{ vars.DB_PORT }}
CLICKHOUSE_PORT_HTTP=${{ vars.CLICKHOUSE_PORT_HTTP }}
CLICKHOUSE_PORT_NATIVE=${{ vars.CLICKHOUSE_PORT_NATIVE }}
CLICKHOUSE_HOST=${{ vars.CLICKHOUSE_HOST }}
CLICKHOUSE_USER=${{ vars.CLICKHOUSE_USER }}
CLICKHOUSE_PASSWORD=${{ secrets.CLICKHOUSE_PASSWORD }}
DB_PORT=${{ vars.STG_DB_PORT }}
CLICKHOUSE_PORT_HTTP=${{ vars.STG_CLICKHOUSE_PORT_HTTP }}
CLICKHOUSE_PORT_NATIVE=${{ vars.STG_CLICKHOUSE_PORT_NATIVE }}
CLICKHOUSE_HOST=${{ vars.STG_CLICKHOUSE_HOST }}
CLICKHOUSE_USER=${{ vars.STG_CLICKHOUSE_USER }}
CLICKHOUSE_PASSWORD=${{ secrets.STG_CLICKHOUSE_PASSWORD }}
BACKEND_PORT=${{ vars.BACKEND_PORT }}
ADMINFRONT_PORT=${{ vars.ADMINFRONT_PORT }}
DEVFRONT_PORT=${{ vars.DEVFRONT_PORT }}
ORGFRONT_PORT=${{ vars.ORGFRONT_PORT }}
USERFRONT_PORT=${{ vars.USERFRONT_PORT }}
BACKEND_PORT=${{ vars.STG_BACKEND_PORT }}
ADMINFRONT_PORT=${{ vars.STG_ADMINFRONT_PORT }}
DEVFRONT_PORT=${{ vars.STG_DEVFRONT_PORT }}
ORGFRONT_PORT=${{ vars.STG_ORGFRONT_PORT }}
USERFRONT_PORT=${{ vars.STG_USERFRONT_PORT }}
OATHKEEPER_API_URL=${{ vars.OATHKEEPER_API_URL }}
OATHKEEPER_API_URL=${{ vars.STG_OATHKEEPER_API_URL }}
DB_USER=${{ vars.DB_USER }}
DB_USER=${{ vars.STG_DB_USER }}
DB_PASSWORD=${{ secrets.STG_DB_PASSWORD }}
DB_NAME=${{ vars.DB_NAME }}
DB_NAME=${{ vars.STG_DB_NAME }}
COOKIE_SECRET=${{ secrets.STG_COOKIE_SECRET }}
JWT_SECRET=${{ secrets.STG_JWT_SECRET }}
REDIS_ADDR=${{ vars.REDIS_ADDR }}
CORS_ALLOWED_ORIGINS=${{ vars.CORS_ALLOWED_ORIGINS }}
REDIS_ADDR=${{ vars.STG_REDIS_ADDR }}
CORS_ALLOWED_ORIGINS=${{ vars.STG_CORS_ALLOWED_ORIGINS }}
AUDIT_WORKER_COUNT=5
AUDIT_QUEUE_SIZE=2000
PROFILE_CACHE_TTL=${{ vars.PROFILE_CACHE_TTL }}
NAVER_CLOUD_ACCESS_KEY=${{ vars.NAVER_CLOUD_ACCESS_KEY }}
NAVER_CLOUD_SECRET_KEY=${{ secrets.NAVER_CLOUD_SECRET_KEY }}
NAVER_CLOUD_SERVICE_ID=${{ vars.NAVER_CLOUD_SERVICE_ID }}
NAVER_SENDER_PHONE_NUMBER=${{ vars.NAVER_SENDER_PHONE_NUMBER }}
AWS_REGION=${{ vars.AWS_REGION }}
AWS_ACCESS_KEY_ID=${{ vars.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_SES_SENDER=${{ vars.AWS_SES_SENDER }}
ADMIN_EMAIL=${{ vars.ADMIN_EMAIL }}
PROFILE_CACHE_TTL=${{ vars.STG_PROFILE_CACHE_TTL }}
NAVER_CLOUD_ACCESS_KEY=${{ secrets.STG_NAVER_CLOUD_ACCESS_KEY }}
NAVER_CLOUD_SECRET_KEY=${{ secrets.STG_NAVER_CLOUD_SECRET_KEY }}
NAVER_CLOUD_SERVICE_ID=${{ vars.STG_NAVER_CLOUD_SERVICE_ID }}
NAVER_SENDER_PHONE_NUMBER=${{ vars.STG_NAVER_SENDER_PHONE_NUMBER }}
AWS_REGION=${{ vars.STG_AWS_REGION }}
AWS_ACCESS_KEY_ID=${{ vars.STG_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY=${{ secrets.STG_AWS_SECRET_ACCESS_KEY }}
AWS_SES_SENDER=${{ vars.STG_AWS_SES_SENDER }}
ADMIN_EMAIL=${{ vars.STG_ADMIN_EMAIL }}
ADMIN_PASSWORD=${{ secrets.STG_ADMIN_PASSWORD }}
USERFRONT_URL=${{ vars.USERFRONT_URL }}
ORGFRONT_URL=${{ vars.ORGFRONT_URL }}
BACKEND_PUBLIC_URL=${{ vars.BACKEND_URL }}
BACKEND_URL=${{ vars.BACKEND_URL }}
OATHKEEPER_PUBLIC_URL=${{ vars.OATHKEEPER_PUBLIC_URL }}
ORY_POSTGRES_TAG=${{ vars.ORY_POSTGRES_TAG }}
ORY_POSTGRES_USER=${{ vars.ORY_POSTGRES_USER }}
USERFRONT_URL=${{ vars.STG_USERFRONT_URL }}
ORGFRONT_URL=${{ vars.STG_ORGFRONT_URL }}
BACKEND_PUBLIC_URL=${{ vars.STG_BACKEND_URL }}
BACKEND_URL=${{ vars.STG_BACKEND_URL }}
OATHKEEPER_PUBLIC_URL=${{ vars.STG_OATHKEEPER_PUBLIC_URL }}
ORY_POSTGRES_TAG=${{ vars.STG_ORY_POSTGRES_TAG }}
ORY_POSTGRES_USER=${{ vars.STG_ORY_POSTGRES_USER }}
ORY_POSTGRES_PASSWORD=${{ secrets.STG_ORY_POSTGRES_PASSWORD }}
ORY_POSTGRES_DB=${{ vars.ORY_POSTGRES_DB }}
KRATOS_DB=${{ vars.KRATOS_DB }}
HYDRA_DB=${{ vars.HYDRA_DB }}
KETO_DB=${{ vars.KETO_DB }}
KRATOS_VERSION=${{ vars.KRATOS_VERSION }}
KRATOS_UI_NODE_VERSION=${{ vars.KRATOS_UI_NODE_VERSION }}
HYDRA_VERSION=${{ vars.HYDRA_VERSION }}
KETO_VERSION=${{ vars.KETO_VERSION }}
ORY_SDK_URL=${{ vars.ORY_SDK_URL }}
KRATOS_PUBLIC_URL=${{ vars.KRATOS_PUBLIC_URL }}
KRATOS_ADMIN_URL=${{ vars.KRATOS_ADMIN_URL }}
KRATOS_BROWSER_URL=${{ vars.KRATOS_BROWSER_URL }}
KRATOS_UI_URL=${{ vars.KRATOS_UI_URL }}
HYDRA_ADMIN_URL=${{ vars.HYDRA_ADMIN_URL }}
HYDRA_PUBLIC_URL=${{ vars.HYDRA_PUBLIC_URL }}
HYDRA_REFRESH_TOKEN_TTL=${{ vars.HYDRA_REFRESH_TOKEN_TTL }}
JWKS_URL=${{ vars.JWKS_URL }}
OATHKEEPER_VERSION=${{ vars.OATHKEEPER_VERSION }}
OATHKEEPER_UID=${{ vars.OATHKEEPER_UID }}
OATHKEEPER_GID=${{ vars.OATHKEEPER_GID }}
OATHKEEPER_HEALTH_URL=${{ vars.OATHKEEPER_HEALTH_URL }}
OATHKEEPER_HEALTH_INTERVAL_SECONDS=${{ vars.OATHKEEPER_HEALTH_INTERVAL_SECONDS }}
OATHKEEPER_HEALTH_TIMEOUT_SECONDS=${{ vars.OATHKEEPER_HEALTH_TIMEOUT_SECONDS }}
OATHKEEPER_HEALTH_ENABLED=${{ vars.OATHKEEPER_HEALTH_ENABLED }}
CSRF_COOKIE_NAME=${{ vars.CSRF_COOKIE_NAME }}
ORY_POSTGRES_DB=${{ vars.STG_ORY_POSTGRES_DB }}
KRATOS_DB=${{ vars.STG_KRATOS_DB }}
HYDRA_DB=${{ vars.STG_HYDRA_DB }}
KETO_DB=${{ vars.STG_KETO_DB }}
KRATOS_VERSION=${{ vars.STG_KRATOS_VERSION }}
KRATOS_UI_NODE_VERSION=${{ vars.STG_KRATOS_UI_NODE_VERSION }}
HYDRA_VERSION=${{ vars.STG_HYDRA_VERSION }}
KETO_VERSION=${{ vars.STG_KETO_VERSION }}
ORY_SDK_URL=${{ vars.STG_ORY_SDK_URL }}
KRATOS_PUBLIC_URL=${{ vars.STG_KRATOS_PUBLIC_URL }}
KRATOS_ADMIN_URL=${{ vars.STG_KRATOS_ADMIN_URL }}
KRATOS_BROWSER_URL=${{ vars.STG_KRATOS_BROWSER_URL }}
KRATOS_UI_URL=${{ vars.STG_KRATOS_UI_URL }}
HYDRA_ADMIN_URL=${{ vars.STG_HYDRA_ADMIN_URL }}
HYDRA_PUBLIC_URL=${{ vars.STG_HYDRA_PUBLIC_URL }}
HYDRA_REFRESH_TOKEN_TTL=${{ vars.STG_HYDRA_REFRESH_TOKEN_TTL }}
JWKS_URL=${{ vars.STG_JWKS_URL }}
OATHKEEPER_VERSION=${{ vars.STG_OATHKEEPER_VERSION }}
OATHKEEPER_UID=${{ vars.STG_OATHKEEPER_UID }}
OATHKEEPER_GID=${{ vars.STG_OATHKEEPER_GID }}
OATHKEEPER_HEALTH_URL=${{ vars.STG_OATHKEEPER_HEALTH_URL }}
OATHKEEPER_HEALTH_INTERVAL_SECONDS=${{ vars.STG_OATHKEEPER_HEALTH_INTERVAL_SECONDS }}
OATHKEEPER_HEALTH_TIMEOUT_SECONDS=${{ vars.STG_OATHKEEPER_HEALTH_TIMEOUT_SECONDS }}
OATHKEEPER_HEALTH_ENABLED=${{ vars.STG_OATHKEEPER_HEALTH_ENABLED }}
CSRF_COOKIE_NAME=${{ vars.STG_CSRF_COOKIE_NAME }}
CSRF_COOKIE_SECRET=${{ secrets.STG_CSRF_COOKIE_SECRET }}
VITE_OIDC_AUTHORITY=${{ vars.VITE_OIDC_AUTHORITY }}
ADMINFRONT_CALLBACK_URLS=${{ vars.ADMINFRONT_CALLBACK_URLS }}
DEVFRONT_CALLBACK_URLS=${{ vars.DEVFRONT_CALLBACK_URLS }}
ORGFRONT_CALLBACK_URLS=${{ vars.ORGFRONT_CALLBACK_URLS }}
# OATHKEEPER_INTROSPECT_CLIENT_ID=${{ vars.OATHKEEPER_INTROSPECT_CLIENT_ID }}
VITE_OIDC_AUTHORITY=${{ vars.STG_VITE_OIDC_AUTHORITY }}
ADMINFRONT_CALLBACK_URLS=${{ vars.STG_ADMINFRONT_CALLBACK_URLS }}
DEVFRONT_CALLBACK_URLS=${{ vars.STG_DEVFRONT_CALLBACK_URLS }}
ORGFRONT_CALLBACK_URLS=${{ vars.STG_ORGFRONT_CALLBACK_URLS }}
# OATHKEEPER_INTROSPECT_CLIENT_ID=${{ vars.STG_OATHKEEPER_INTROSPECT_CLIENT_ID }}
# OATHKEEPER_INTROSPECT_CLIENT_SECRET=${{ secrets.STG_OATHKEEPER_INTROSPECT_CLIENT_SECRET }}
EOF

View File

@@ -51,7 +51,7 @@ DOCKER_IMAGE_REF ?=
WORKS_DOCKER_COMMIT_CONTAINER ?=
WORKS_DOCKER_IMAGE_ARCHIVE_DIR ?= /tmp/baron-sso-docker-image-upload
.PHONY: help build-auth-config validate-auth-config verify-auth-config render-ory-config up up-all up-infra up-ory up-app up-backend ensure-networks ensure-infra ensure-ory ensure-restore-containers up-dev up-front-dev dev dev-debug down drop down-app down-backend down-infra down-ory check-infra ps logs-infra logs-ory logs-app backup-tools-build dump restore dump-verify restore-verify dump-list restore-plan upload-cloud works-drive-refresh-token dump-upload-cloud docker-image-upload-works
.PHONY: help build-auth-config validate-auth-config verify-auth-config render-ory-config up up-all up-infra up-ory up-app up-backend ensure-networks ensure-infra ensure-ory ensure-restore-containers up-dev up-front-dev dev dev-debug down drop down-app down-backend down-infra down-ory check-infra ps logs-infra logs-ory logs-app backup-tools-build dump restore dump-verify restore-verify dump-list restore-plan upload-cloud works-drive-refresh-token dump-upload-cloud docker-image-upload-works docker-image-verify-works
help: ## 생성된 타깃과 옵션 목록 표시
@printf "Usage:\n make <target> [OPTION=value ...]\n\n"
@@ -367,6 +367,9 @@ dump-upload-cloud: dump upload-cloud ## 백업 덤프 생성 후 클라우드
docker-image-upload-works: ## Docker 이미지를 WORKS Shared Drive archive로 업로드
WORKS_DOCKER_COMMIT_CONTAINER="$(WORKS_DOCKER_COMMIT_CONTAINER)" DOCKER_IMAGE_REF="$(DOCKER_IMAGE_REF)" WORKS_DOCKER_IMAGE_ARCHIVE_DIR="$(WORKS_DOCKER_IMAGE_ARCHIVE_DIR)" scripts/docker-image/upload_works_drive.sh
docker-image-verify-works: ## WORKS Shared Drive Docker image archive 검증
WORKS_DOCKER_VERIFY_LOAD="$(WORKS_DOCKER_VERIFY_LOAD)" WORKS_DOCKER_IMAGE_ARCHIVE_DIR="$(WORKS_DOCKER_IMAGE_ARCHIVE_DIR)" scripts/docker-image/verify_archive.sh "$(WORKS_DOCKER_IMAGE_ARCHIVE_DIR)"
# --- 로컬 통합 코드 체크 ---
PLAYWRIGHT_BROWSERS_PATH := $(HOME)/.cache/ms-playwright
PLAYWRIGHT_CHROMIUM_COMPLETE := $(PLAYWRIGHT_BROWSERS_PATH)/chromium-1208/INSTALLATION_COMPLETE

View File

@@ -10,6 +10,35 @@ WORKS Drive는 Docker Registry HTTP API v2 backend로 직접 사용하지 않는
- 작은 규모의 프로덕션 배포 이미지 이관
- `docker load` 기반 오프라인 배포
Harbor는 이 흐름의 1차 이미지 저장소다. Gitea Actions의 publish workflow가 `reg.hmac.kr/baron_sso/<service>:<image_tag>` 형태로 이미지를 push하고, staging/production deploy workflow는 같은 image tag를 Harbor에서 pull한다. WORKS Drive는 같은 이미지를 별도로 보관하는 복구용 archive이며, staging/prod가 평상시에 직접 pull하는 대상이 아니다.
## 현재 Gitea Actions 설정 상태
2026-06-19 기준 repo Actions 설정에서 Harbor 변수/시크릿은 등록되어 있다.
- `HARBOR_ENDPOINT=https://reg.hmac.kr`
- `HARBOR_HOSTNAME=reg.hmac.kr`
- `HARBOR_ROBOT_ACCOUNT=robot$namecard_sso`
- secret `HARBOR_ROBOT_KEY`
Docker image archive 업로드 단계는 `.gitea/workflows/production_image_publish.yml``Upload pushed images to WORKS Drive archive` step에서 실행된다. 단, 이 step은 다음 조건을 만족할 때만 실행된다.
```yaml
if: ${{ vars.WORKS_DRIVE_DOCKER_IMAGE_ARCHIVE_ENABLED == 'true' }}
```
현재 repo Actions 설정에는 Docker image archive용 WORKS Drive 변수/시크릿이 등록되어 있지 않다. 업로드를 켜려면 최소한 다음 값을 등록해야 한다.
- variable `WORKS_DRIVE_DOCKER_IMAGE_ARCHIVE_ENABLED=true`
- variable `WORKS_SHAREDRIVE_DOCKER_IMAGE_DIR=docker-build-image`
- variable `WORKS_DRIVE_SHARED_DRIVE_ID`
- 선택 variable `WORKS_DRIVE_PARENT_FILE_ID`
- secret `WORKS_DRIVE_OAUTH_CLIENT_ID`
- secret `WORKS_DRIVE_OAUTH_CLIENT_SECRET`
- secret `WORKS_DRIVE_OAUTH_CLIENT_SERVICE_ACCOUNT`
- secret `WORKS_DRIVE_OAUTH_CLIENT_PRIVATE_KEY`
- refresh token 방식을 쓸 경우 secret `WORKS_DRIVE_OAUTH_REFRESH_TOKEN`
## 저장 구조
기본 최상위 디렉터리는 다음 환경 변수로 지정한다.
@@ -92,6 +121,63 @@ DOCKER_IMAGE_REF=registry.example/baron_sso/backend:v1.2606.ab12 \
scripts/docker-image/upload_works_drive.sh
```
dry-run도 실제 `docker save`, `zstd`, checksum, manifest 생성을 수행한다. WORKS Drive API 호출만 생략하므로 업로드 전 산출물 검증에 사용할 수 있다.
## 다운로드 및 복원 검증 CLI
WORKS Drive에서 다음 세 파일을 같은 로컬 디렉터리로 내려받은 뒤 검증한다.
```text
image.tar.zst
image.tar.zst.sha256
manifest.json
```
checksum, manifest, zstd stream 무결성만 확인하려면 다음을 실행한다.
```bash
scripts/docker-image/verify_archive.sh /path/to/downloaded/archive
```
`make` 타깃을 사용할 수도 있다.
```bash
make docker-image-verify-works \
WORKS_DOCKER_IMAGE_ARCHIVE_DIR=/path/to/downloaded/archive
```
실제 Docker image load까지 검증하려면 다음을 실행한다.
```bash
WORKS_DOCKER_VERIFY_LOAD=true \
scripts/docker-image/verify_archive.sh /path/to/downloaded/archive
```
검증은 다음 조건을 모두 확인한다.
- `image.tar.zst.sha256` checksum 성공
- `manifest.json``schema_version=1`, `format=docker-save-zstd`
- manifest의 archive 파일명, sha256, size와 실제 파일 일치
- `zstd -t` 무결성 성공
- 선택적으로 `docker load` 성공
현재 repo에는 WORKS Drive API에서 파일을 자동 다운로드하는 CLI는 없다. 따라서 자동 다운로드 스크립트를 만들기 전까지는 WORKS Drive UI 또는 운영자가 승인한 API 도구로 세 파일을 내려받고, 위 검증 CLI로 복원 가능성을 확인한다.
API로 다운로드할 때는 대상 archive 폴더의 children을 조회해 각 파일의 `fileId`를 얻은 뒤 다음 endpoint를 호출한다.
```text
GET /v1.0/sharedrives/<sharedDriveId>/files/<fileId>/download
```
검증 결과 이 endpoint는 `302 Location`을 반환한다. `curl -L`만 사용하면 리다이렉트 대상 요청에 인증 헤더가 유지되지 않아 `UNAUTHORIZED` JSON이 파일로 저장될 수 있다. 자동화할 때는 리다이렉트 대상에도 인증 헤더를 유지하도록 처리해야 한다. `curl` 기준으로는 다음 형태를 사용한다.
```bash
curl -sS -L --location-trusted \
-H "Authorization: Bearer <access-token>" \
-o image.tar.zst \
"https://www.worksapis.com/v1.0/sharedrives/<sharedDriveId>/files/<fileId>/download"
```
smoke 검증에는 Alpine 계열보다 운영 환경과 libc/패키지 계열 차이가 적은 Debian slim 계열을 사용한다.
```bash
@@ -103,6 +189,22 @@ DOCKER_IMAGE_REF=registry.example/baron_sso/works-smoke:works-test-ab12 \
scripts/docker-image/upload_works_drive.sh
```
로컬 smoke 검증 예시는 다음과 같다.
```bash
WORKS_DRIVE_DRY_RUN=true \
WORKS_DOCKER_IMAGE_ARCHIVE_DIR=/tmp/baron-sso-works-verify-smoke \
DOCKER_IMAGE_REF=alpine:latest \
scripts/docker-image/upload_works_drive.sh
scripts/docker-image/verify_archive.sh \
/tmp/baron-sso-works-verify-smoke/alpine/latest
WORKS_DOCKER_VERIFY_LOAD=true \
scripts/docker-image/verify_archive.sh \
/tmp/baron-sso-works-verify-smoke/alpine/latest
```
## Staging/Production 계약
Action에서 `dev` 브랜치를 checkout한 뒤 한 번만 이미지를 빌드하고 immutable `image_tag`를 계산한다. staging과 production은 같은 image_tag를 입력받아 같은 registry image를 pull한다.

View File

@@ -23,8 +23,8 @@ host_from_url() {
require_env IMAGE_TAG
require_env IMAGE_DEPLOY_ENV
require_env IMAGE_DEPLOY_PORT_PREFIX
require_env IMAGE_DEPLOY_PUBLIC_URL
require_env IMAGE_DEPLOY_BACKEND_PORT
require_env ADMINFRONT_URL
require_env DEVFRONT_URL
require_env ORGFRONT_URL
@@ -50,26 +50,43 @@ case "$IMAGE_DEPLOY_ENV" in
esac
instance_name="${IMAGE_DEPLOY_INSTANCE_NAME:-$default_instance_name}"
port_prefix="${IMAGE_DEPLOY_PORT_PREFIX:-${IMAGE_DEPLOY_BACKEND_PORT%???}}"
[[ -n "$port_prefix" ]] || die "IMAGE_DEPLOY_PORT_PREFIX is empty and could not be derived from IMAGE_DEPLOY_BACKEND_PORT."
bundle_dir="${IMAGE_DEPLOY_BUNDLE_DIR:-$PWD/${instance_name}-image-deploy-bundle}"
bundle_file="${IMAGE_DEPLOY_BUNDLE_FILE:-$PWD/${instance_name}-image-deploy-bundle.tgz}"
compose_template="${IMAGE_DEPLOY_COMPOSE_TEMPLATE:-$repo_root/deploy/templates/docker-compose.images.yaml}"
rm -rf "$bundle_dir"
TARGET_DIR="$bundle_dir" bash "$repo_root/deploy/create-instance.sh" "$instance_name" "$IMAGE_DEPLOY_PORT_PREFIX"
TARGET_DIR="$bundle_dir" bash "$repo_root/deploy/create-instance.sh" "$instance_name" "$port_prefix"
cp "$compose_template" "$bundle_dir/docker-compose.yml"
sed "s/{{BACKEND_PORT}}/${IMAGE_DEPLOY_BACKEND_PORT}/g" \
"$repo_root/deploy/templates/gateway/nginx.conf" >"$bundle_dir/gateway/nginx.conf"
sed "s/{{BACKEND_PORT}}/${IMAGE_DEPLOY_BACKEND_PORT}/g" \
"$repo_root/deploy/templates/ory/oathkeeper/rules.json" >"$bundle_dir/ory/templates/oathkeeper/rules.json"
cp "$bundle_dir/ory/templates/oathkeeper/rules.json" "$bundle_dir/ory/templates/oathkeeper/rules.stage.json"
cp "$bundle_dir/ory/templates/oathkeeper/rules.json" "$bundle_dir/ory/templates/oathkeeper/rules.prod.json"
cp "$bundle_dir/ory/templates/oathkeeper/rules.json" "$bundle_dir/ory/templates/oathkeeper/rules.active.json"
public_host="$(host_from_url "$IMAGE_DEPLOY_PUBLIC_URL")"
admin_host="$(host_from_url "$ADMINFRONT_URL")"
dev_host="$(host_from_url "$DEVFRONT_URL")"
org_host="$(host_from_url "$ORGFRONT_URL")"
backend_log_level="${IMAGE_DEPLOY_BACKEND_LOG_LEVEL:-${BACKEND_LOG_LEVEL:-info}}"
client_log_debug="${IMAGE_DEPLOY_CLIENT_LOG_DEBUG:-${CLIENT_LOG_DEBUG:-false}}"
backend_public_url="${IMAGE_DEPLOY_BACKEND_PUBLIC_URL:-${BACKEND_PUBLIC_URL:-${BACKEND_URL:-$IMAGE_DEPLOY_PUBLIC_URL}}}"
backend_url="${IMAGE_DEPLOY_BACKEND_URL:-${BACKEND_URL:-$backend_public_url}}"
cat >"$bundle_dir/.env" <<EOF
INSTANCE_NAME=${instance_name}
COMPOSE_PROJECT_NAME=baron-sso-${instance_name}
APP_ENV=${app_env}
BACKEND_LOG_LEVEL=${backend_log_level}
CLIENT_LOG_DEBUG=${client_log_debug}
VITE_CLIENT_LOG_DEBUG=${client_log_debug}
TZ=Asia/Seoul
SOURCE_ROOT=.
P=${IMAGE_DEPLOY_PORT_PREFIX}
P=${port_prefix}
DB_PORT=${IMAGE_DEPLOY_DB_PORT}
REDIS_PORT=${IMAGE_DEPLOY_REDIS_PORT}
CLICKHOUSE_PORT_HTTP=${IMAGE_DEPLOY_CLICKHOUSE_PORT_HTTP}
@@ -85,6 +102,8 @@ USERFRONT_URL=${IMAGE_DEPLOY_PUBLIC_URL}
ADMINFRONT_URL=${ADMINFRONT_URL}
DEVFRONT_URL=${DEVFRONT_URL}
ORGFRONT_URL=${ORGFRONT_URL}
BACKEND_PUBLIC_URL=${backend_public_url}
BACKEND_URL=${backend_url}
PUBLIC_HOST=${public_host}
ADMINFRONT_HOST=${admin_host}
DEVFRONT_HOST=${dev_host}
@@ -106,9 +125,22 @@ HYDRA_CONSENT_URL=${IMAGE_DEPLOY_PUBLIC_URL}/consent
HYDRA_ERROR_URL=${IMAGE_DEPLOY_PUBLIC_URL}/error
HYDRA_REFRESH_TOKEN_TTL=${HYDRA_REFRESH_TOKEN_TTL}
OATHKEEPER_PUBLIC_URL=${IMAGE_DEPLOY_PUBLIC_URL}
OATHKEEPER_API_URL=${OATHKEEPER_API_URL:-}
KETO_READ_URL=http://keto:4466
KETO_WRITE_URL=http://keto:4467
IDP_PROVIDER=ory
WORKS_ADMIN_API_BASE_URL=${WORKS_ADMIN_API_BASE_URL:-}
WORKS_ADMIN_OAUTH_TOKEN_URL=${WORKS_ADMIN_OAUTH_TOKEN_URL:-}
PROFILE_CACHE_TTL=${PROFILE_CACHE_TTL:-}
NAVER_CLOUD_ACCESS_KEY=${NAVER_CLOUD_ACCESS_KEY:-}
NAVER_CLOUD_SECRET_KEY=${NAVER_CLOUD_SECRET_KEY:-}
NAVER_CLOUD_SERVICE_ID=${NAVER_CLOUD_SERVICE_ID:-}
NAVER_SENDER_PHONE_NUMBER=${NAVER_SENDER_PHONE_NUMBER:-}
AWS_REGION=${AWS_REGION:-}
AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-}
AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-}
AWS_SES_SENDER=${AWS_SES_SENDER:-}
CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS:-}
DB_PASSWORD=${IMAGE_DEPLOY_DB_PASSWORD}
ORY_POSTGRES_USER=${ORY_POSTGRES_USER}
ORY_POSTGRES_PASSWORD=${IMAGE_DEPLOY_ORY_POSTGRES_PASSWORD}
@@ -125,6 +157,8 @@ OATHKEEPER_UID=${OATHKEEPER_UID}
OATHKEEPER_GID=${OATHKEEPER_GID}
OATHKEEPER_INTROSPECT_CLIENT_ID=${OATHKEEPER_INTROSPECT_CLIENT_ID}
OATHKEEPER_INTROSPECT_CLIENT_SECRET=${IMAGE_DEPLOY_OATHKEEPER_INTROSPECT_CLIENT_SECRET}
CLICKHOUSE_HOST=${CLICKHOUSE_HOST:-clickhouse}
CLICKHOUSE_USER=${CLICKHOUSE_USER:-baron}
CLICKHOUSE_PASSWORD=${IMAGE_DEPLOY_CLICKHOUSE_PASSWORD}
REDIS_ADDR=redis:6379
COOKIE_SECRET=${IMAGE_DEPLOY_COOKIE_SECRET}
@@ -146,6 +180,7 @@ required_dotenv_keys="
APP_ENV IMAGE_TAG BACKEND_IMAGE_NAME USERFRONT_IMAGE_NAME ADMINFRONT_IMAGE_NAME DEVFRONT_IMAGE_NAME ORGFRONT_IMAGE_NAME
USERFRONT_URL PUBLIC_HOST HYDRA_PUBLIC_URL VITE_OIDC_AUTHORITY TRAEFIK_PUBLIC_NETWORK
DB_PASSWORD ORY_POSTGRES_PASSWORD COOKIE_SECRET JWT_SECRET CSRF_COOKIE_SECRET
BACKEND_LOG_LEVEL CLIENT_LOG_DEBUG BACKEND_PUBLIC_URL BACKEND_URL CLICKHOUSE_HOST CLICKHOUSE_USER
"
for key in $required_dotenv_keys; do
if ! grep -Eq "^${key}=.+" "$bundle_dir/.env"; then

View File

@@ -0,0 +1,61 @@
#!/usr/bin/env bash
set -euo pipefail
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo_root="$(cd "$script_dir/../.." && pwd)"
source "$repo_root/scripts/backup/lib/common.sh"
archive_dir="${1:-${WORKS_DOCKER_IMAGE_ARCHIVE_DIR:-}}"
verify_load="${WORKS_DOCKER_VERIFY_LOAD:-false}"
[[ -n "$archive_dir" ]] || backup_die "archive directory is required. Example: scripts/docker-image/verify_archive.sh /path/to/archive"
backup_require_path "$archive_dir"
backup_require_command jq
backup_require_command sha256sum
backup_require_command stat
backup_require_command zstd
manifest_file="$archive_dir/manifest.json"
backup_require_path "$manifest_file"
schema_version="$(jq -er '.schema_version' "$manifest_file")"
format="$(jq -er '.format' "$manifest_file")"
archive_name="$(jq -er '.archive.file_name' "$manifest_file")"
manifest_sha256="$(jq -er '.archive.sha256' "$manifest_file")"
manifest_size="$(jq -er '.archive.size_bytes' "$manifest_file")"
[[ "$schema_version" == "1" ]] || backup_die "unsupported archive schema_version: $schema_version"
[[ "$format" == "docker-save-zstd" ]] || backup_die "unsupported archive format: $format"
[[ "$archive_name" != */* && -n "$archive_name" ]] || backup_die "manifest archive.file_name must be a file name: $archive_name"
[[ "$manifest_sha256" =~ ^[0-9a-f]{64}$ ]] || backup_die "manifest archive.sha256 is invalid: $manifest_sha256"
[[ "$manifest_size" =~ ^[0-9]+$ ]] || backup_die "manifest archive.size_bytes is invalid: $manifest_size"
archive_file="$archive_dir/$archive_name"
checksum_file="$archive_dir/${archive_name}.sha256"
backup_require_path "$archive_file"
backup_require_path "$checksum_file"
backup_log "Checking archive checksum"
(
cd "$archive_dir"
sha256sum -c "$(basename "$checksum_file")" >/dev/null
)
actual_sha256="$(sha256sum "$archive_file" | awk '{print $1}')"
[[ "$actual_sha256" == "$manifest_sha256" ]] || backup_die "manifest sha256 mismatch: expected=$manifest_sha256 actual=$actual_sha256"
actual_size="$(stat -c '%s' "$archive_file")"
[[ "$actual_size" == "$manifest_size" ]] || backup_die "manifest size mismatch: expected=$manifest_size actual=$actual_size"
backup_log "Testing zstd archive integrity"
zstd -q -t "$archive_file"
if [[ "$verify_load" == "true" ]]; then
backup_require_command docker
backup_log "Loading Docker image from archive"
zstd -q -d -c "$archive_file" | docker load
fi
backup_log "Docker image archive verification passed: $archive_dir"

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env sh
set -eu
fail_if_contains() {
file="$1"
pattern="$2"
if grep -Fq "$pattern" "$file"; then
echo "forbidden pattern in $file: $pattern" >&2
exit 1
fi
}
assert_contains() {
file="$1"
pattern="$2"
if ! grep -Fq "$pattern" "$file"; then
echo "missing pattern in $file: $pattern" >&2
exit 1
fi
}
staging_workflows="
.gitea/workflows/staging_code_pull.yml
.gitea/workflows/staging_release.yml
.gitea/workflows/staging_image_deploy.yml
"
production_workflows="
.gitea/workflows/production_release.yml
.gitea/workflows/production_image_deploy.yml
"
for workflow in $staging_workflows; do
assert_contains "$workflow" "vars.STG_"
assert_contains "$workflow" "secrets.STG_"
fail_if_contains "$workflow" "vars.STAGE_"
fail_if_contains "$workflow" "secrets.STAGE_"
for name in \
USERFRONT_URL ADMINFRONT_URL DEVFRONT_URL ORGFRONT_URL VITE_OIDC_AUTHORITY \
BACKEND_URL BACKEND_LOG_LEVEL CLIENT_LOG_DEBUG PROFILE_CACHE_TTL CORS_ALLOWED_ORIGINS \
WORKS_ADMIN_API_BASE_URL WORKS_ADMIN_OAUTH_TOKEN_URL NAVER_CLOUD_ACCESS_KEY \
NAVER_CLOUD_SERVICE_ID NAVER_SENDER_PHONE_NUMBER AWS_REGION AWS_ACCESS_KEY_ID \
AWS_SES_SENDER CLICKHOUSE_HOST CLICKHOUSE_USER DB_PORT DB_USER DB_NAME REDIS_ADDR
do
fail_if_contains "$workflow" "vars.$name"
done
for name in AWS_SECRET_ACCESS_KEY NAVER_CLOUD_SECRET_KEY CLICKHOUSE_PASSWORD STAGE_SSH_PRIVATE_KEY; do
fail_if_contains "$workflow" "secrets.$name"
done
done
for workflow in $production_workflows; do
assert_contains "$workflow" "vars.PROD_"
assert_contains "$workflow" "secrets.PROD_"
for name in \
ADMINFRONT_URL DEVFRONT_URL ORGFRONT_URL VITE_OIDC_AUTHORITY BACKEND_LOG_LEVEL \
CLIENT_LOG_DEBUG PROFILE_CACHE_TTL CORS_ALLOWED_ORIGINS WORKS_ADMIN_API_BASE_URL \
WORKS_ADMIN_OAUTH_TOKEN_URL NAVER_CLOUD_ACCESS_KEY NAVER_CLOUD_SERVICE_ID \
NAVER_SENDER_PHONE_NUMBER AWS_REGION AWS_ACCESS_KEY_ID AWS_SES_SENDER \
CLICKHOUSE_HOST CLICKHOUSE_USER ADMINFRONT_PORT DEVFRONT_PORT ORGFRONT_PORT
do
fail_if_contains "$workflow" "vars.$name"
done
for name in AWS_SECRET_ACCESS_KEY NAVER_CLOUD_SECRET_KEY CLICKHOUSE_PASSWORD; do
fail_if_contains "$workflow" "secrets.$name"
done
done
echo "deploy workflow env prefix checks passed"

View File

@@ -0,0 +1,80 @@
#!/usr/bin/env sh
set -eu
repo_root="$(cd "$(dirname "$0")/.." && pwd)"
verify_script="$repo_root/scripts/docker-image/verify_archive.sh"
tmp_root="$(mktemp -d)"
cleanup() {
rm -rf "$tmp_root"
}
trap cleanup EXIT INT TERM
require_command() {
command -v "$1" >/dev/null 2>&1 || {
echo "required command not found: $1" >&2
exit 1
}
}
assert_fails() {
if "$@" >/dev/null 2>&1; then
echo "expected command to fail: $*" >&2
exit 1
fi
}
require_command jq
require_command sha256sum
require_command zstd
artifact_dir="$tmp_root/baron_sso/backend/v1.2606.ab12"
mkdir -p "$artifact_dir"
printf 'docker image archive smoke\n' >"$artifact_dir/image.tar"
zstd -q -f -o "$artifact_dir/image.tar.zst" "$artifact_dir/image.tar"
rm -f "$artifact_dir/image.tar"
archive_sha256="$(sha256sum "$artifact_dir/image.tar.zst" | awk '{print $1}')"
archive_size="$(wc -c <"$artifact_dir/image.tar.zst" | tr -d ' ')"
printf '%s image.tar.zst\n' "$archive_sha256" >"$artifact_dir/image.tar.zst.sha256"
jq -n \
--arg remotePath "docker-build-image/baron_sso/backend/v1.2606.ab12" \
--arg archiveSha256 "$archive_sha256" \
--argjson archiveSize "$archive_size" \
'{
schema_version: 1,
format: "docker-save-zstd",
image_ref: "reg.hmac.kr/baron_sso/backend:v1.2606.ab12",
repository: "baron_sso/backend",
tag: "v1.2606.ab12",
remote_path: $remotePath,
archive: {
file_name: "image.tar.zst",
size_bytes: $archiveSize,
sha256: $archiveSha256
}
}' >"$artifact_dir/manifest.json"
"$verify_script" "$artifact_dir" >/dev/null
bad_checksum_dir="$tmp_root/bad-checksum"
cp -R "$artifact_dir" "$bad_checksum_dir"
printf '0000000000000000000000000000000000000000000000000000000000000000 image.tar.zst\n' >"$bad_checksum_dir/image.tar.zst.sha256"
assert_fails "$verify_script" "$bad_checksum_dir"
bad_manifest_dir="$tmp_root/bad-manifest"
cp -R "$artifact_dir" "$bad_manifest_dir"
jq '.archive.sha256 = "1111111111111111111111111111111111111111111111111111111111111111"' \
"$bad_manifest_dir/manifest.json" >"$bad_manifest_dir/manifest.json.tmp"
mv "$bad_manifest_dir/manifest.json.tmp" "$bad_manifest_dir/manifest.json"
assert_fails "$verify_script" "$bad_manifest_dir"
bad_archive_dir="$tmp_root/bad-archive"
cp -R "$artifact_dir" "$bad_archive_dir"
printf 'not a zstd stream\n' >"$bad_archive_dir/image.tar.zst"
sha256sum "$bad_archive_dir/image.tar.zst" | awk '{print $1 " image.tar.zst"}' >"$bad_archive_dir/image.tar.zst.sha256"
assert_fails "$verify_script" "$bad_archive_dir"
echo "docker image archive verification checks passed"

View File

@@ -0,0 +1,169 @@
#!/usr/bin/env bash
set -euo pipefail
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
tmp_root="$(mktemp -d)"
cleanup() {
rm -rf "$tmp_root"
}
trap cleanup EXIT INT TERM
assert_contains() {
local file="$1"
local pattern="$2"
if ! grep -Fq "$pattern" "$file"; then
printf 'missing pattern in %s: %s\n' "$file" "$pattern" >&2
exit 1
fi
}
assert_env_value() {
local file="$1"
local key="$2"
local expected="$3"
if ! grep -Fxq "${key}=${expected}" "$file"; then
printf 'missing env value in %s: %s=%s\n' "$file" "$key" "$expected" >&2
exit 1
fi
}
for workflow in \
"$repo_root/.gitea/workflows/staging_image_deploy.yml" \
"$repo_root/.gitea/workflows/production_image_deploy.yml"
do
assert_contains "$workflow" "IMAGE_DEPLOY_BACKEND_LOG_LEVEL:"
assert_contains "$workflow" "IMAGE_DEPLOY_CLIENT_LOG_DEBUG:"
assert_contains "$workflow" "WORKS_ADMIN_API_BASE_URL:"
assert_contains "$workflow" "WORKS_ADMIN_OAUTH_TOKEN_URL:"
assert_contains "$workflow" "PROFILE_CACHE_TTL:"
assert_contains "$workflow" "NAVER_CLOUD_ACCESS_KEY:"
assert_contains "$workflow" "NAVER_CLOUD_SECRET_KEY:"
assert_contains "$workflow" "NAVER_CLOUD_SERVICE_ID:"
assert_contains "$workflow" "NAVER_SENDER_PHONE_NUMBER:"
assert_contains "$workflow" "AWS_REGION:"
assert_contains "$workflow" "AWS_ACCESS_KEY_ID:"
assert_contains "$workflow" "AWS_SECRET_ACCESS_KEY:"
assert_contains "$workflow" "AWS_SES_SENDER:"
assert_contains "$workflow" "CORS_ALLOWED_ORIGINS:"
assert_contains "$workflow" "OATHKEEPER_API_URL:"
done
assert_contains "$repo_root/.gitea/workflows/staging_image_deploy.yml" "secrets.STG_SSH_PRIVATE_KEY"
assert_contains "$repo_root/.gitea/workflows/staging_image_deploy.yml" "vars.STG_USERFRONT_URL"
assert_contains "$repo_root/.gitea/workflows/staging_image_deploy.yml" "vars.STG_BACKEND_URL"
assert_contains "$repo_root/.gitea/workflows/staging_image_deploy.yml" "vars.STG_WORKS_ADMIN_API_BASE_URL"
assert_contains "$repo_root/.gitea/workflows/staging_image_deploy.yml" "secrets.STG_NAVER_CLOUD_SECRET_KEY"
assert_contains "$repo_root/.gitea/workflows/staging_image_deploy.yml" "secrets.STG_AWS_SECRET_ACCESS_KEY"
assert_contains "$repo_root/.gitea/workflows/staging_image_deploy.yml" "secrets.STG_CLICKHOUSE_PASSWORD"
assert_contains "$repo_root/.gitea/workflows/production_image_deploy.yml" "secrets.PROD_SSH_PRIVATE_KEY"
assert_contains "$repo_root/.gitea/workflows/production_image_deploy.yml" "vars.PROD_FRONTEND_URL"
assert_contains "$repo_root/.gitea/workflows/production_image_deploy.yml" "vars.PROD_BACKEND_URL"
assert_contains "$repo_root/.gitea/workflows/production_image_deploy.yml" "vars.PROD_WORKS_ADMIN_API_BASE_URL"
assert_contains "$repo_root/.gitea/workflows/production_image_deploy.yml" "secrets.PROD_NAVER_CLOUD_SECRET_KEY"
assert_contains "$repo_root/.gitea/workflows/production_image_deploy.yml" "secrets.PROD_AWS_SECRET_ACCESS_KEY"
assert_contains "$repo_root/.gitea/workflows/production_image_deploy.yml" "secrets.PROD_CLICKHOUSE_PASSWORD"
bundle_dir="$tmp_root/stage-image-deploy-bundle"
bundle_file="$tmp_root/stage-image-deploy-bundle.tgz"
(
cd "$repo_root"
IMAGE_TAG=v1.2606.ab12 \
IMAGE_DEPLOY_ENV=stage \
IMAGE_DEPLOY_INSTANCE_NAME=stage-test \
IMAGE_DEPLOY_PORT_PREFIX=19 \
IMAGE_DEPLOY_PUBLIC_URL=https://sso.example.test \
IMAGE_DEPLOY_COMPOSE_TEMPLATE=deploy/templates/docker-compose.images.yaml \
IMAGE_DEPLOY_BUNDLE_DIR="$bundle_dir" \
IMAGE_DEPLOY_BUNDLE_FILE="$bundle_file" \
ADMINFRONT_URL=https://sadmin.example.test \
DEVFRONT_URL=https://sdev.example.test \
ORGFRONT_URL=https://sorg.example.test \
VITE_OIDC_AUTHORITY=https://sso.example.test/oidc \
IMAGE_DEPLOY_DB_PORT=15432 \
IMAGE_DEPLOY_REDIS_PORT=16379 \
IMAGE_DEPLOY_CLICKHOUSE_PORT_HTTP=18123 \
IMAGE_DEPLOY_CLICKHOUSE_PORT_NATIVE=19000 \
IMAGE_DEPLOY_BACKEND_PORT=13000 \
IMAGE_DEPLOY_FRONTEND_PORT=15000 \
ADMINFRONT_PORT=15173 \
DEVFRONT_PORT=15174 \
ORGFRONT_PORT=15175 \
IMAGE_DEPLOY_OATHKEEPER_PROXY_PORT=14455 \
IMAGE_DEPLOY_DOMAIN_SUFFIX=example.test \
ADMINFRONT_CALLBACK_URLS=https://sadmin.example.test/auth/callback \
DEVFRONT_CALLBACK_URLS=https://sdev.example.test/auth/callback \
ORGFRONT_CALLBACK_URLS=https://sorg.example.test/auth/callback \
HYDRA_REFRESH_TOKEN_TTL=720h \
ORY_POSTGRES_USER=ory \
ORY_POSTGRES_DB=ory \
KRATOS_DB=ory_kratos \
HYDRA_DB=ory_hydra \
KETO_DB=ory_keto \
KRATOS_VERSION=v26.2.0-distroless \
HYDRA_VERSION=v26.2.0-distroless \
KETO_VERSION=v26.2.0-distroless \
OATHKEEPER_VERSION=v26.2.0 \
ORY_POSTGRES_TAG=17-trixie \
OATHKEEPER_UID=1001 \
OATHKEEPER_GID=1001 \
OATHKEEPER_INTROSPECT_CLIENT_ID=oathkeeper-introspect \
ADMIN_EMAIL=admin@example.test \
HARBOR_HOSTNAME=reg.example.test \
BACKEND_IMAGE_NAME=reg.example.test/baron_sso/backend \
USERFRONT_IMAGE_NAME=reg.example.test/baron_sso/userfront \
ADMINFRONT_IMAGE_NAME=reg.example.test/baron_sso/adminfront \
DEVFRONT_IMAGE_NAME=reg.example.test/baron_sso/devfront \
ORGFRONT_IMAGE_NAME=reg.example.test/baron_sso/orgfront \
IMAGE_DEPLOY_DB_PASSWORD=db-secret \
IMAGE_DEPLOY_ORY_POSTGRES_PASSWORD=ory-secret \
IMAGE_DEPLOY_OATHKEEPER_INTROSPECT_CLIENT_SECRET=oathkeeper-secret \
IMAGE_DEPLOY_CLICKHOUSE_PASSWORD=clickhouse-secret \
IMAGE_DEPLOY_COOKIE_SECRET=cookie-secret \
IMAGE_DEPLOY_JWT_SECRET=jwt-secret \
IMAGE_DEPLOY_CSRF_COOKIE_SECRET=csrf-secret \
IMAGE_DEPLOY_ADMIN_PASSWORD=admin-secret \
IMAGE_DEPLOY_BACKEND_LOG_LEVEL=debug \
IMAGE_DEPLOY_CLIENT_LOG_DEBUG=true \
WORKS_ADMIN_API_BASE_URL=https://works-api.example.test \
WORKS_ADMIN_OAUTH_TOKEN_URL=https://works-auth.example.test/token \
PROFILE_CACHE_TTL=30m \
NAVER_CLOUD_ACCESS_KEY=naver-access \
NAVER_CLOUD_SECRET_KEY=naver-secret \
NAVER_CLOUD_SERVICE_ID=naver-service \
NAVER_SENDER_PHONE_NUMBER=021234567 \
AWS_REGION=ap-northeast-2 \
AWS_ACCESS_KEY_ID=aws-access \
AWS_SECRET_ACCESS_KEY=aws-secret \
AWS_SES_SENDER=support@example.test \
CORS_ALLOWED_ORIGINS=https://sso.example.test \
OATHKEEPER_API_URL=http://oathkeeper:4456 \
CLICKHOUSE_HOST=clickhouse \
CLICKHOUSE_USER=baron \
scripts/deploy/build_image_deploy_bundle.sh >/dev/null
)
env_file="$bundle_dir/.env"
assert_env_value "$env_file" "BACKEND_LOG_LEVEL" "debug"
assert_env_value "$env_file" "CLIENT_LOG_DEBUG" "true"
assert_env_value "$env_file" "WORKS_ADMIN_API_BASE_URL" "https://works-api.example.test"
assert_env_value "$env_file" "WORKS_ADMIN_OAUTH_TOKEN_URL" "https://works-auth.example.test/token"
assert_env_value "$env_file" "PROFILE_CACHE_TTL" "30m"
assert_env_value "$env_file" "NAVER_CLOUD_ACCESS_KEY" "naver-access"
assert_env_value "$env_file" "NAVER_CLOUD_SECRET_KEY" "naver-secret"
assert_env_value "$env_file" "NAVER_CLOUD_SERVICE_ID" "naver-service"
assert_env_value "$env_file" "NAVER_SENDER_PHONE_NUMBER" "021234567"
assert_env_value "$env_file" "AWS_REGION" "ap-northeast-2"
assert_env_value "$env_file" "AWS_ACCESS_KEY_ID" "aws-access"
assert_env_value "$env_file" "AWS_SECRET_ACCESS_KEY" "aws-secret"
assert_env_value "$env_file" "AWS_SES_SENDER" "support@example.test"
assert_env_value "$env_file" "CORS_ALLOWED_ORIGINS" "https://sso.example.test"
assert_env_value "$env_file" "BACKEND_PUBLIC_URL" "https://sso.example.test"
assert_env_value "$env_file" "BACKEND_URL" "https://sso.example.test"
assert_env_value "$env_file" "OATHKEEPER_API_URL" "http://oathkeeper:4456"
assert_env_value "$env_file" "CLICKHOUSE_HOST" "clickhouse"
assert_env_value "$env_file" "CLICKHOUSE_USER" "baron"
echo "image deploy env override checks passed"

View File

@@ -17,9 +17,12 @@ do
assert_contains "$workflow" "APP_ENV=stage"
assert_contains "$workflow" "BACKEND_LOG_LEVEL=debug"
assert_contains "$workflow" "CLIENT_LOG_DEBUG=true"
assert_contains "$workflow" 'WORKS_ADMIN_API_BASE_URL=${{ vars.WORKS_ADMIN_API_BASE_URL }}'
assert_contains "$workflow" 'WORKS_ADMIN_OAUTH_TOKEN_URL=${{ vars.WORKS_ADMIN_OAUTH_TOKEN_URL }}'
assert_contains "$workflow" 'BACKEND_PUBLIC_URL=${{ vars.BACKEND_URL }}'
assert_contains "$workflow" 'WORKS_ADMIN_API_BASE_URL=${{ vars.STG_WORKS_ADMIN_API_BASE_URL }}'
assert_contains "$workflow" 'WORKS_ADMIN_OAUTH_TOKEN_URL=${{ vars.STG_WORKS_ADMIN_OAUTH_TOKEN_URL }}'
assert_contains "$workflow" 'BACKEND_PUBLIC_URL=${{ vars.STG_BACKEND_URL }}'
assert_contains "$workflow" 'NAVER_CLOUD_SECRET_KEY=${{ secrets.STG_NAVER_CLOUD_SECRET_KEY }}'
assert_contains "$workflow" 'AWS_SECRET_ACCESS_KEY=${{ secrets.STG_AWS_SECRET_ACCESS_KEY }}'
assert_contains "$workflow" 'CLICKHOUSE_PASSWORD=${{ secrets.STG_CLICKHOUSE_PASSWORD }}'
done
assert_contains ".gitea/workflows/staging_release.yml" "scp adminfront/seed-tenant.csv"

View File

@@ -55,7 +55,8 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
context.pop();
} else {
final isLoggedIn = AuthTokenStore.hasToken();
final localeCode = extractLocaleFromPath(Uri.base) ?? resolvePreferredLocaleCode();
final localeCode =
extractLocaleFromPath(Uri.base) ?? resolvePreferredLocaleCode();
if (isLoggedIn) {
context.go('/$localeCode/profile');
} else {

View File

@@ -45,10 +45,10 @@ packages:
dependency: transitive
description:
name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
url: "https://pub.dev"
source: hosted
version: "1.4.0"
version: "1.4.1"
cli_config:
dependency: transitive
description:
@@ -268,14 +268,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.5"
js:
dependency: transitive
description:
name: js
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
leak_tracker:
dependency: transitive
description:
@@ -328,18 +320,18 @@ packages:
dependency: transitive
description:
name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
url: "https://pub.dev"
source: hosted
version: "0.12.17"
version: "0.12.19"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
url: "https://pub.dev"
source: hosted
version: "0.11.1"
version: "0.13.0"
meta:
dependency: transitive
description:
@@ -661,26 +653,26 @@ packages:
dependency: transitive
description:
name: test
sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7"
sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7"
url: "https://pub.dev"
source: hosted
version: "1.26.3"
version: "1.30.0"
test_api:
dependency: transitive
description:
name: test_api
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
url: "https://pub.dev"
source: hosted
version: "0.7.7"
version: "0.7.10"
test_core:
dependency: transitive
description:
name: test_core
sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0"
sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51"
url: "https://pub.dev"
source: hosted
version: "0.6.12"
version: "0.6.16"
toml:
dependency: "direct main"
description: