전열이 모두 물러난 순간 서버가 500을 내던 것을 고침 #119
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: ci | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| permissions: | |
| contents: read | |
| jobs: | |
| security-audit: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 | |
| - name: Validate GitHub Actions contracts | |
| shell: bash | |
| run: | | |
| archive="$RUNNER_TEMP/actionlint.tar.gz" | |
| curl --fail --location --silent --show-error \ | |
| https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_amd64.tar.gz \ | |
| --output "$archive" | |
| echo "8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8 $archive" \ | |
| | sha256sum --check --strict | |
| tar --extract --gzip --file "$archive" --directory "$RUNNER_TEMP" actionlint | |
| "$RUNNER_TEMP/actionlint" -color | |
| - name: Scan dependencies and deployment configuration | |
| uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0 | |
| with: | |
| scan-type: fs | |
| scan-ref: . | |
| scanners: vuln,misconfig | |
| vuln-type: os,library | |
| severity: CRITICAL,HIGH | |
| ignore-unfixed: true | |
| exit-code: "1" | |
| hide-progress: true | |
| wardrobe-contract: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check wardrobe input changes | |
| id: wardrobe_changes | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| PR_BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
| PUSH_BEFORE_SHA: ${{ github.event.before }} | |
| PUSH_AFTER_SHA: ${{ github.sha }} | |
| run: | | |
| if [ "$EVENT_NAME" = "pull_request" ]; then | |
| base_sha="$PR_BASE_SHA" | |
| head_sha="$PR_HEAD_SHA" | |
| else | |
| base_sha="$PUSH_BEFORE_SHA" | |
| head_sha="$PUSH_AFTER_SHA" | |
| fi | |
| if [[ "$base_sha" =~ ^0+$ ]] || \ | |
| ! git cat-file -e "$base_sha^{commit}" 2>/dev/null; then | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| set +e | |
| git diff --quiet "$base_sha" "$head_sha" -- \ | |
| design-system/concepts/wardrobe-v1/ \ | |
| design-system/scripts/ | |
| diff_status=$? | |
| set -e | |
| if [ "$diff_status" -eq 0 ]; then | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| elif [ "$diff_status" -eq 1 ]; then | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| else | |
| exit "$diff_status" | |
| fi | |
| - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 | |
| if: steps.wardrobe_changes.outputs.changed == 'true' | |
| with: | |
| python-version: "3.12" | |
| - name: Install wardrobe builder dependencies | |
| if: steps.wardrobe_changes.outputs.changed == 'true' | |
| run: python -m pip install Pillow | |
| - name: Validate wardrobe contract | |
| if: steps.wardrobe_changes.outputs.changed == 'true' | |
| run: | | |
| validation_root="$(mktemp -d)" | |
| trap 'rm -rf "$validation_root"' EXIT | |
| python design-system/scripts/build_wardrobe_layers.py \ | |
| --source-root design-system/concepts/wardrobe-v1 \ | |
| --output-root "$validation_root/output" \ | |
| --qa-root "$validation_root/qa" \ | |
| --manifest "$validation_root/wardrobe-layers.json" | |
| server: | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: server | |
| env: | |
| APP_ENV: test | |
| AI_MODE: fake | |
| DATABASE_URL: sqlite+aiosqlite:///./ci.db | |
| JWT_SECRET: ci-only-secret-0123456789abcdef0123456789 | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 | |
| - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install uv==0.11.13 | |
| uv sync --frozen --extra dev --no-install-project | |
| - name: Lint | |
| run: uv run --no-sync python -m ruff check app tests | |
| - name: Test | |
| run: uv run --no-sync python -m pytest -q | |
| - name: Audit locked production dependencies | |
| run: | | |
| uv export --frozen --no-dev --format requirements-txt --no-hashes \ | |
| --output-file "$RUNNER_TEMP/mongroo-production-requirements.txt" | |
| uv run --no-sync pip-audit \ | |
| --requirement "$RUNNER_TEMP/mongroo-production-requirements.txt" \ | |
| --progress-spinner off | |
| - name: Validate expedition content | |
| run: uv run --no-sync python -m app.content.expeditions.validator app/content/expeditions/v1/*.json | |
| - name: OpenAPI drift check | |
| run: | | |
| uv run --no-sync python -m app.export_openapi | |
| git diff --exit-code openapi.json | |
| mysql-production-contract: | |
| runs-on: ubuntu-latest | |
| services: | |
| mysql: | |
| image: mysql:8.4.6 | |
| env: | |
| MYSQL_DATABASE: mongroo | |
| MYSQL_USER: mongroo | |
| MYSQL_PASSWORD: ci-mysql-password | |
| MYSQL_ROOT_PASSWORD: ci-root-password | |
| ports: | |
| - 3306:3306 | |
| options: >- | |
| --health-cmd="mysqladmin ping -h 127.0.0.1 -uroot -pci-root-password --silent" | |
| --health-interval=10s | |
| --health-timeout=5s | |
| --health-retries=20 | |
| defaults: | |
| run: | |
| working-directory: server | |
| env: | |
| APP_ENV: production | |
| DATA_PROFILE: real-data | |
| DATABASE_URL: mysql+aiomysql://mongroo:ci-mysql-password@127.0.0.1:3306/mongroo | |
| JWT_SECRET: ci-production-secret-0123456789abcdef0123456789 | |
| FIELD_ENCRYPTION_KEYS: '{"v1":"MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA="}' | |
| ACTIVE_FIELD_ENCRYPTION_KEY_ID: v1 | |
| TERMS_VERSION: 2026-08-05 | |
| PRIVACY_VERSION: 2026-08-05 | |
| SENSITIVE_CONSENT_VERSION: 2026-08-05 | |
| AI_MODE: disabled | |
| CORS_ORIGINS: '["https://app.mongroo.test"]' | |
| CORS_ORIGIN_REGEX: "" | |
| ALLOWED_HOSTS: '["api.mongroo.test"]' | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 | |
| - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install locked production dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install uv==0.11.13 | |
| uv sync --frozen --no-dev --no-install-project | |
| - name: Apply production schema | |
| run: uv run --no-sync python -m alembic upgrade head | |
| - name: Protect and verify sensitive fields | |
| run: uv run --no-sync python -m app.protect_sensitive_data | |
| - name: Run production lifecycle smoke | |
| run: uv run --no-sync python -m app.release_smoke | |
| flutter: | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: app | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 | |
| - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2 | |
| with: | |
| flutter-version: "3.44.6" | |
| - run: flutter pub get | |
| - run: flutter analyze | |
| - run: flutter test | |
| - name: Build WebAssembly release | |
| run: flutter build web --wasm --release --no-pub --no-web-resources-cdn | |
| - name: Build Android debug APK | |
| run: flutter build apk --debug --no-pub | |
| production-images: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 | |
| - name: Validate production compose | |
| run: MONGROO_ENV_FILE=.env.production.example docker compose --env-file .env.production.example -f docker-compose.prod.yml config --quiet | |
| - name: Build API image | |
| run: docker build --pull --tag mongroo-api:ci server | |
| - name: Build Web image | |
| run: | | |
| docker build --pull --tag mongroo-web:ci \ | |
| --build-arg SERVICE_OPERATOR_NAME="몽그루 CI" \ | |
| --build-arg SERVICE_OPERATOR_ADDRESS="CI synthetic address" \ | |
| --build-arg PRIVACY_CONTACT_EMAIL="privacy@example.invalid" \ | |
| --build-arg DATA_HOSTING_DISCLOSURE="CI synthetic hosting" \ | |
| --build-arg TERMS_VERSION="2026-08-05" \ | |
| --build-arg PRIVACY_VERSION="2026-08-05" \ | |
| --build-arg SENSITIVE_CONSENT_VERSION="2026-08-05" \ | |
| app |