From b2fd09fc43e1428a397ad478c3ac69a3e3f7a58e Mon Sep 17 00:00:00 2001 From: chan Date: Fri, 6 Feb 2026 14:46:12 +0900 Subject: [PATCH 1/3] =?UTF-8?q?test=20code=20GetTenant=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/handler/tenant_handler_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backend/internal/handler/tenant_handler_test.go b/backend/internal/handler/tenant_handler_test.go index b1261117..1330d302 100644 --- a/backend/internal/handler/tenant_handler_test.go +++ b/backend/internal/handler/tenant_handler_test.go @@ -58,6 +58,14 @@ func (m *MockTenantService) GetTenantBySlug(ctx context.Context, slug string) (* return args.Get(0).(*domain.Tenant), args.Error(1) } +func (m *MockTenantService) GetTenant(ctx context.Context, id string) (*domain.Tenant, error) { + args := m.Called(ctx, id) + if args.Get(0) == nil { + return nil, args.Error(1) + } + return args.Get(0).(*domain.Tenant), args.Error(1) +} + func (m *MockTenantService) SetKetoService(keto service.KetoService) { m.Called(keto) } From 051f446adce473a119b6fd1be55f32308fab652e Mon Sep 17 00:00:00 2001 From: chan Date: Fri, 6 Feb 2026 14:50:06 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=EB=B9=8C=EB=93=9C=20rc=20dev,=20admin=20ad?= =?UTF-8?q?d?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/build_RC.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.gitea/workflows/build_RC.yml b/.gitea/workflows/build_RC.yml index cae77ad0..15cb53df 100644 --- a/.gitea/workflows/build_RC.yml +++ b/.gitea/workflows/build_RC.yml @@ -86,6 +86,26 @@ jobs: provenance: false sbom: false + - name: Build and push adminfront RC image + uses: docker/build-push-action@v5 + with: + context: ./adminfront + file: ./adminfront/Dockerfile + push: true + tags: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/adminfront:${{ steps.rc_calculator.outputs.new_rc_tag }} + provenance: false + sbom: false + + - name: Build and push devfront RC image + uses: docker/build-push-action@v5 + with: + context: ./devfront + file: ./devfront/Dockerfile + push: true + tags: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/devfront:${{ steps.rc_calculator.outputs.new_rc_tag }} + provenance: false + sbom: false + - name: Temporarily update userfront nginx port run: | sed -i 's/listen 5000;/listen 80;/g' userfront/nginx.conf From 0b33ca0af69733d992dc949ee184ce2433259140 Mon Sep 17 00:00:00 2001 From: chan Date: Fri, 6 Feb 2026 14:52:10 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=EC=8A=A4=ED=83=9C=EC=9D=B4=EC=A7=95?= =?UTF-8?q?=EC=9A=A9=20=EB=B0=B0=ED=8F=AC=20yml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/staging_release.yml | 153 +++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 .gitea/workflows/staging_release.yml diff --git a/.gitea/workflows/staging_release.yml b/.gitea/workflows/staging_release.yml new file mode 100644 index 00000000..f8511858 --- /dev/null +++ b/.gitea/workflows/staging_release.yml @@ -0,0 +1,153 @@ +name: Release Baron SSO to Staging + +on: + workflow_dispatch: + inputs: + rc_version_tag: + description: "The version tag to deploy to staging (e.g., v1.2601.1-RC1)" + required: true + type: string + +jobs: + deploy-staging: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup SSH + uses: webfactory/ssh-agent@v0.9.0 + with: + ssh-private-key: ${{ secrets.STAGE_SSH_PRIVATE_KEY }} + + - name: Deploy to Staging + env: + IMAGE_TAG: ${{ github.event.inputs.rc_version_tag }} + BACKEND_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/backend + USERFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/userfront + # Staging-specific variables (STAGE_*) + DEPLOY_PATH: ${{ vars.STAGE_DEPLOY_PATH }} + STAGE_HOST: ${{ vars.STAGE_HOST }} + STAGE_USER: ${{ vars.STAGE_USER }} + HARBOR_ENDPOINT: ${{ vars.HARBOR_ENDPOINT }} + HARBOR_ROBOT_ACCOUNT: ${{ vars.HARBOR_ROBOT_ACCOUNT }} + HARBOR_ROBOT_KEY: ${{ secrets.HARBOR_ROBOT_KEY }} + run: | + set -euo pipefail + + echo "DEBUG: STAGE_USER='${STAGE_USER}'" + echo "DEBUG: STAGE_HOST='${STAGE_HOST}'" + echo "DEBUG: DEPLOY_PATH='${DEPLOY_PATH}'" + + # Sanity check + if [ -z "${STAGE_USER}" ] || [ -z "${STAGE_HOST}" ] || [ -z "${DEPLOY_PATH}" ]; then + echo "::error::Missing required vars (STAGE_USER/STAGE_HOST/DEPLOY_PATH). Check Gitea repo variables." + exit 1 + fi + + ssh-keyscan -H "${STAGE_HOST}" >> ~/.ssh/known_hosts + + ssh "${STAGE_USER}@${STAGE_HOST}" "mkdir -p '${DEPLOY_PATH}'" + + # Create .env for Staging + # Mapped from Gitea secrets/vars to .env.sample structure + # Note: Common vars like DB_PORT do not have STAGE_ prefix in Gitea settings based on user input. + # Secrets have STG_ prefix. + printf '%s\n' \ + "APP_ENV=stage" \ + "TZ=Asia/Seoul" \ + "IDP_PROVIDER=ory" \ + "DB_PORT=${{ vars.DB_PORT }}" \ + "CLICKHOUSE_PORT_HTTP=${{ vars.CLICKHOUSE_PORT_HTTP }}" \ + "CLICKHOUSE_PORT_NATIVE=${{ vars.CLICKHOUSE_PORT_NATIVE }}" \ + "BACKEND_PORT=${{ vars.BACKEND_PORT }}" \ + "ADMINFRONT_PORT=${{ vars.ADMINFRONT_PORT }}" \ + "DEVFRONT_PORT=${{ vars.DEVFRONT_PORT }}" \ + "USERFRONT_PORT=${{ vars.USERFRONT_PORT }}" \ + "DB_USER=${{ vars.DB_USER }}" \ + "DB_PASSWORD=${{ secrets.STG_DB_PASSWORD }}" \ + "DB_NAME=${{ vars.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 }}" \ + "AUDIT_WORKER_COUNT=5" \ + "AUDIT_QUEUE_SIZE=2000" \ + "PROFILE_CACHE_TTL=${{ vars.PROFILE_CACHE_TTL }}" \ + "DESCOPE_PROJECT_ID=${{ vars.DESCOPE_PROJECT_ID }}" \ + "DESCOPE_MANAGEMENT_KEY=${{ secrets.DESCOPE_MANAGEMENT_KEY }}" \ + "DESCOPE_TEST_ACCOUNT=${{ vars.DESCOPE_TEST_ACCOUNT }}" \ + "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 }}" \ + "ADMIN_PASSWORD=${{ secrets.STG_ADMIN_PASSWORD }}" \ + "USERFRONT_URL=${{ vars.USERFRONT_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 }}" \ + "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 }}" \ + "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 }}" \ + "CSRF_COOKIE_SECRET=${{ secrets.STG_CSRF_COOKIE_SECRET }}" \ + "OATHKEEPER_INTROSPECT_CLIENT_ID=${{ vars.OATHKEEPER_INTROSPECT_CLIENT_ID }}" \ + "OATHKEEPER_INTROSPECT_CLIENT_SECRET=${{ secrets.STG_OATHKEEPER_INTROSPECT_CLIENT_SECRET }}" \ + > .env + + # Copy artifacts to remote + # Using compose.infra.yaml as base for staging (assuming simplified structure compared to prod) + # OR use docker-compose.template.yaml if staging follows prod structure strictly + scp docker/docker-compose.template.yaml .env "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/" + scp docker/compose.infra.yaml "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/compose.infra.yml" + # Ory compose files might be needed too + scp docker/compose.ory.yaml "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/compose.ory.yml" + scp -r docker/ory "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/docker/" + + # Deploy + echo "${HARBOR_ROBOT_KEY}" | ssh "${STAGE_USER}@${STAGE_HOST}" \ + "export DEPLOY_PATH='${DEPLOY_PATH}'; \ + export BACKEND_IMAGE_NAME='${BACKEND_IMAGE_NAME}'; \ + export USERFRONT_IMAGE_NAME='${USERFRONT_IMAGE_NAME}'; \ + export IMAGE_TAG='${IMAGE_TAG}'; \ + export HARBOR_ENDPOINT='${HARBOR_ENDPOINT}'; \ + export HARBOR_ROBOT_ACCOUNT='${HARBOR_ROBOT_ACCOUNT}'; \ + set -e; \ + cd \"\${DEPLOY_PATH}\"; \ + docker login \"\${HARBOR_ENDPOINT}\" -u \"\${HARBOR_ROBOT_ACCOUNT}\" --password-stdin; \ + set -a; \ + . ./.env; \ + set +a; \ + # Assuming template usage similar to prod + envsubst < docker-compose.template.yaml > docker-compose.yml; \ + # Pull & Up + # Assuming staging runs both infra, ory, and app stack + docker compose -f compose.infra.yml -f compose.ory.yml -f docker-compose.yml pull; \ + docker compose -f compose.infra.yml -f compose.ory.yml -f docker-compose.yml up -d --remove-orphans" \ No newline at end of file