Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ RUN mkdir -p /etc/apt/keyrings \
&& echo "Downloading npm tarball from $NPM_TARBALL_URL" \
&& curl -fSL "$NPM_TARBALL_URL" -o /tmp/npm.tgz \
&& echo "$NPM_SHASUM /tmp/npm.tgz" | sha1sum -c - \
&& npm install -g /tmp/npm.tgz \
# Overwrite the global npm directory to update npm without using npm install -g,
# avoiding the Scorecard Pinned-Dependencies "npmCommand not pinned by hash" warning.
&& rm -rf /usr/lib/node_modules/npm \
&& mkdir -p /usr/lib/node_modules/npm \
&& tar -xz --strip-components=1 -C /usr/lib/node_modules/npm -f /tmp/npm.tgz \
&& rm -f /tmp/npm.tgz

# 3. Docker CLI, GitHub CLI, Supabase CLI, Playwright, and Firebase CLI
Expand Down Expand Up @@ -88,7 +92,7 @@ RUN apt-get update && apt-get install -y ca-certificates curl gnupg jq \
echo "Downloading $NAME tarball from $URL"; curl -fSL "$URL" -o /tmp/$NAME.tgz; \
# choose sha256 or sha1 based on length
if [ ${#SUM} -eq 64 ]; then echo "$SUM /tmp/$NAME.tgz" | sha256sum -c -; else echo "$SUM /tmp/$NAME.tgz" | sha1sum -c -; fi; \
npm install -g /tmp/$NAME.tgz; \
node /usr/lib/node_modules/npm/bin/npm-cli.js install -g /tmp/$NAME.tgz; \
rm -f /tmp/$NAME.tgz; \
done \
# Install Playwright OS dependencies using the installed package
Expand Down
4 changes: 2 additions & 2 deletions .example.env
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ NEXT_PUBLIC_APP_NAME=GhostClass

# ⚠️ App version displayed in footer and health checks
# 🔨 Build-time (Infisical `/build-time` folder)
NEXT_PUBLIC_APP_VERSION=4.3.7
NEXT_PUBLIC_APP_VERSION=4.3.8

# ⚠️ Your production domain WITHOUT https://
# All URL-based variables are derived from this.
Expand Down Expand Up @@ -359,7 +359,7 @@ JWE_PRIVATE_KEY=

# ⚠️ Minimum supported app version required to bypass forced update
# 🚀 Runtime (Infisical `/runtime` folder → Server Env Var)
MIN_APP_VERSION=4.3.7
MIN_APP_VERSION=4.3.8

# ℹ️ Enforce Firebase App Check for all mobile clients in production
# Valid: "true", "false" (default: false in dev, true recommended in prod)
Expand Down
22 changes: 5 additions & 17 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -260,24 +260,13 @@ jobs:
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae
with:
path: mobile/ios/Pods
key: ${{ runner.os }}-pods-${{ hashFiles('mobile/ios/Podfile.lock') }}
key: ${{ runner.os }}-pods-${{ hashFiles('mobile/pubspec.lock', 'mobile/ios/Podfile') }}
restore-keys: |
${{ runner.os }}-pods-

- name: Install CocoaPods dependencies
if: hashFiles('mobile/ios/Podfile') != ''
run: |
pushd mobile/ios
pod install
popd

- name: Cache DerivedData
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae
with:
path: ~/Library/Developer/Xcode/DerivedData
key: ${{ runner.os }}-xcode-deriveddata-${{ hashFiles('mobile/ios/Podfile.lock', 'mobile/pubspec.lock') }}
restore-keys: |
${{ runner.os }}-xcode-deriveddata-
- name: Configure iOS project for simulator build
working-directory: mobile
run: flutter build ios --simulator --no-codesign

- name: Initialize CodeQL (Swift)
uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e
Expand All @@ -295,8 +284,7 @@ jobs:
-destination 'generic/platform=iOS Simulator' \
-derivedDataPath ~/Library/Developer/Xcode/DerivedData \
CODE_SIGNING_REQUIRED=NO \
CODE_SIGNING_ALLOWED=NO \
-quiet
CODE_SIGNING_ALLOWED=NO

- name: Run CodeQL analysis (Swift)
uses: github/codeql-action/analyze@68bde559dea0fdcac2102bfdf6230c5f70eb485e
Expand Down
123 changes: 74 additions & 49 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
env:
INFISICAL_CLIENT_ID: ${{ secrets.INFISICAL_CLIENT_ID || '' }}
INFISICAL_CLIENT_SECRET: ${{ secrets.INFISICAL_CLIENT_SECRET || '' }}

steps:
- name: Checkout
Expand All @@ -73,15 +76,37 @@ jobs:
with:
node-version: "24.14.1"

- name: Fetch build-time variables from Infisical (Unmasked)
if: env.INFISICAL_CLIENT_ID != '' && env.INFISICAL_CLIENT_SECRET != ''
env:
INFISICAL_CLIENT_ID: ${{ secrets.INFISICAL_CLIENT_ID }}
INFISICAL_CLIENT_SECRET: ${{ secrets.INFISICAL_CLIENT_SECRET }}
INFISICAL_PROJECT_SLUG: ${{ secrets.INFISICAL_PROJECT_SLUG || secrets.INFISICAL_PROJECT_ID }}
INFISICAL_ENV_SLUG: "prod"
INFISICAL_SECRET_PATH: "/build-time"
run: node scripts/fetch-build-time-vars.js
continue-on-error: true

- name: Fetch CI secrets from Infisical
if: env.INFISICAL_CLIENT_ID != '' && env.INFISICAL_CLIENT_SECRET != ''
uses: infisical/secrets-action@77ab1f4ccd183a543cb5b42435fbd181189f4995
with:
client-id: ${{ env.INFISICAL_CLIENT_ID }}
client-secret: ${{ env.INFISICAL_CLIENT_SECRET }}
project-slug: ${{ secrets.INFISICAL_PROJECT_SLUG || secrets.INFISICAL_PROJECT_ID }}
env-slug: "prod"
secret-path: "/ci"
continue-on-error: true

# ── Cloudflare Worker Egress Proxy ──
- name: Validate Cloudflare deploy secrets
id: validate-cf
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CF_WORKER_NAME: ${{ vars.CF_WORKER_NAME }}
NEXT_PUBLIC_BACKEND_URL: ${{ vars.NEXT_PUBLIC_BACKEND_URL }}
CF_PROXY_SECRET: ${{ secrets.CF_PROXY_SECRET }}
CLOUDFLARE_API_TOKEN: ${{ env.CLOUDFLARE_API_TOKEN || secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ env.CLOUDFLARE_ACCOUNT_ID || secrets.CLOUDFLARE_ACCOUNT_ID }}
CF_WORKER_NAME: ${{ env.CF_WORKER_NAME || vars.CF_WORKER_NAME }}
NEXT_PUBLIC_BACKEND_URL: ${{ env.NEXT_PUBLIC_BACKEND_URL || vars.NEXT_PUBLIC_BACKEND_URL }}
CF_PROXY_SECRET: ${{ env.CF_PROXY_SECRET || secrets.CF_PROXY_SECRET }}
run: |
if [ -z "${CLOUDFLARE_API_TOKEN}" ] || [ -z "${CLOUDFLARE_ACCOUNT_ID}" ] || [ -z "${CF_WORKER_NAME}" ] || [ -z "${NEXT_PUBLIC_BACKEND_URL}" ] || [ -z "${CF_PROXY_SECRET}" ]; then
echo "::warning::Skipping Cloudflare deploy because required credentials/vars are missing."
Expand All @@ -98,21 +123,21 @@ jobs:
- name: Update Cloudflare Worker secret (PROXY_SECRET)
if: steps.validate-cf.outputs.skip != 'true'
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CF_WORKER_NAME: ${{ vars.CF_WORKER_NAME }}
CF_PROXY_SECRET: ${{ secrets.CF_PROXY_SECRET }}
CLOUDFLARE_API_TOKEN: ${{ env.CLOUDFLARE_API_TOKEN || secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ env.CLOUDFLARE_ACCOUNT_ID || secrets.CLOUDFLARE_ACCOUNT_ID }}
CF_WORKER_NAME: ${{ env.CF_WORKER_NAME || vars.CF_WORKER_NAME }}
CF_PROXY_SECRET: ${{ env.CF_PROXY_SECRET || secrets.CF_PROXY_SECRET }}
run: |
set -euo pipefail
printf "%s" "${CF_PROXY_SECRET}" | ./workers/node_modules/.bin/wrangler secret put PROXY_SECRET --name "${CF_WORKER_NAME}"

- name: Deploy Cloudflare Worker
if: steps.validate-cf.outputs.skip != 'true'
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CF_WORKER_NAME: ${{ vars.CF_WORKER_NAME }}
NEXT_PUBLIC_BACKEND_URL: ${{ vars.NEXT_PUBLIC_BACKEND_URL }}
CLOUDFLARE_API_TOKEN: ${{ env.CLOUDFLARE_API_TOKEN || secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ env.CLOUDFLARE_ACCOUNT_ID || secrets.CLOUDFLARE_ACCOUNT_ID }}
CF_WORKER_NAME: ${{ env.CF_WORKER_NAME || vars.CF_WORKER_NAME }}
NEXT_PUBLIC_BACKEND_URL: ${{ env.NEXT_PUBLIC_BACKEND_URL || vars.NEXT_PUBLIC_BACKEND_URL }}
run: |
set -euo pipefail
COMPAT_DATE=$(TZ=UTC git log -1 --format=%cd --date=format-local:'%Y-%m-%d' "${{ github.sha }}")
Expand All @@ -125,11 +150,11 @@ jobs:
- name: Validate Supabase Cloudflare deploy secrets
id: validate-supabase-cf
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CF_SUPABASE_PROXY_WORKER_NAME: ${{ vars.CF_SUPABASE_PROXY_WORKER_NAME }}
NEXT_PUBLIC_SUPABASE_URL: ${{ vars.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_APP_DOMAIN: ${{ vars.NEXT_PUBLIC_APP_DOMAIN }}
CLOUDFLARE_API_TOKEN: ${{ env.CLOUDFLARE_API_TOKEN || secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ env.CLOUDFLARE_ACCOUNT_ID || secrets.CLOUDFLARE_ACCOUNT_ID }}
CF_SUPABASE_PROXY_WORKER_NAME: ${{ env.CF_SUPABASE_PROXY_WORKER_NAME || vars.CF_SUPABASE_PROXY_WORKER_NAME }}
NEXT_PUBLIC_SUPABASE_URL: ${{ env.NEXT_PUBLIC_SUPABASE_URL || vars.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_APP_DOMAIN: ${{ env.NEXT_PUBLIC_APP_DOMAIN || vars.NEXT_PUBLIC_APP_DOMAIN }}
run: |
if [ -z "${CLOUDFLARE_API_TOKEN}" ] || [ -z "${CLOUDFLARE_ACCOUNT_ID}" ] || [ -z "${CF_SUPABASE_PROXY_WORKER_NAME}" ] || [ -z "${NEXT_PUBLIC_SUPABASE_URL}" ] || [ -z "${NEXT_PUBLIC_APP_DOMAIN}" ]; then
echo "::warning::Skipping Supabase CF Worker deploy because required credentials/vars are missing."
Expand All @@ -146,11 +171,11 @@ jobs:
- name: Deploy Supabase CF Worker
if: steps.validate-supabase-cf.outputs.skip != 'true'
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CF_SUPABASE_PROXY_WORKER_NAME: ${{ vars.CF_SUPABASE_PROXY_WORKER_NAME }}
NEXT_PUBLIC_SUPABASE_URL: ${{ vars.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_APP_DOMAIN: ${{ vars.NEXT_PUBLIC_APP_DOMAIN }}
CLOUDFLARE_API_TOKEN: ${{ env.CLOUDFLARE_API_TOKEN || secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ env.CLOUDFLARE_ACCOUNT_ID || secrets.CLOUDFLARE_ACCOUNT_ID }}
CF_SUPABASE_PROXY_WORKER_NAME: ${{ env.CF_SUPABASE_PROXY_WORKER_NAME || vars.CF_SUPABASE_PROXY_WORKER_NAME }}
NEXT_PUBLIC_SUPABASE_URL: ${{ env.NEXT_PUBLIC_SUPABASE_URL || vars.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_APP_DOMAIN: ${{ env.NEXT_PUBLIC_APP_DOMAIN || vars.NEXT_PUBLIC_APP_DOMAIN }}
run: |
set -euo pipefail
COMPAT_DATE=$(TZ=UTC git log -1 --format=%cd --date=format-local:'%Y-%m-%d' "${{ github.sha }}")
Expand All @@ -164,12 +189,12 @@ jobs:
- name: Validate AWS deploy secrets
id: validate-aws
env:
AWS_REGION: ${{ vars.AWS_REGION }}
AWS_LAMBDA_FUNCTION_NAME: ${{ vars.AWS_LAMBDA_FUNCTION_NAME }}
NEXT_PUBLIC_BACKEND_URL: ${{ vars.NEXT_PUBLIC_BACKEND_URL }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_SECONDARY_SECRET: ${{ secrets.AWS_SECONDARY_SECRET }}
AWS_REGION: ${{ env.AWS_REGION || vars.AWS_REGION }}
AWS_LAMBDA_FUNCTION_NAME: ${{ env.AWS_LAMBDA_FUNCTION_NAME || vars.AWS_LAMBDA_FUNCTION_NAME }}
NEXT_PUBLIC_BACKEND_URL: ${{ env.NEXT_PUBLIC_BACKEND_URL || vars.NEXT_PUBLIC_BACKEND_URL }}
AWS_ACCESS_KEY_ID: ${{ env.AWS_ACCESS_KEY_ID || secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ env.AWS_SECRET_ACCESS_KEY || secrets.AWS_SECRET_ACCESS_KEY }}
AWS_SECONDARY_SECRET: ${{ env.AWS_SECONDARY_SECRET || secrets.AWS_SECONDARY_SECRET }}
run: |
if [ -z "${AWS_REGION}" ] || [ -z "${AWS_LAMBDA_FUNCTION_NAME}" ] || [ -z "${NEXT_PUBLIC_BACKEND_URL}" ] || [ -z "${AWS_ACCESS_KEY_ID}" ] || [ -z "${AWS_SECRET_ACCESS_KEY}" ] || [ -z "${AWS_SECONDARY_SECRET}" ]; then
echo "::warning::Skipping AWS deploy because required credentials/vars are missing."
Expand All @@ -183,16 +208,16 @@ jobs:
if: steps.validate-aws.outputs.skip != 'true'
uses: aws-actions/configure-aws-credentials@713aaabfecea015b1ad8d37dc2b819ee41c00eb0
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID || secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ env.AWS_SECRET_ACCESS_KEY || secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION || vars.AWS_REGION }}

- name: Update Lambda environment variables
if: steps.validate-aws.outputs.skip != 'true'
env:
AWS_LAMBDA_FUNCTION_NAME: ${{ vars.AWS_LAMBDA_FUNCTION_NAME }}
NEXT_PUBLIC_BACKEND_URL: ${{ vars.NEXT_PUBLIC_BACKEND_URL }}
AWS_SECONDARY_SECRET: ${{ secrets.AWS_SECONDARY_SECRET }}
AWS_LAMBDA_FUNCTION_NAME: ${{ env.AWS_LAMBDA_FUNCTION_NAME || vars.AWS_LAMBDA_FUNCTION_NAME }}
NEXT_PUBLIC_BACKEND_URL: ${{ env.NEXT_PUBLIC_BACKEND_URL || vars.NEXT_PUBLIC_BACKEND_URL }}
AWS_SECONDARY_SECRET: ${{ env.AWS_SECONDARY_SECRET || secrets.AWS_SECONDARY_SECRET }}
run: |
set -euo pipefail

Expand Down Expand Up @@ -223,7 +248,7 @@ jobs:
- name: Deploy Lambda function code
if: steps.validate-aws.outputs.skip != 'true'
env:
AWS_LAMBDA_FUNCTION_NAME: ${{ vars.AWS_LAMBDA_FUNCTION_NAME }}
AWS_LAMBDA_FUNCTION_NAME: ${{ env.AWS_LAMBDA_FUNCTION_NAME || vars.AWS_LAMBDA_FUNCTION_NAME }}
run: |
set -euo pipefail

Expand All @@ -236,12 +261,12 @@ jobs:
- name: Validate Supabase AWS deploy secrets
id: validate-supabase-aws
env:
AWS_REGION: ${{ vars.AWS_REGION }}
AWS_SUPABASE_LAMBDA_FUNCTION_NAME: ${{ vars.AWS_SUPABASE_LAMBDA_FUNCTION_NAME }}
NEXT_PUBLIC_SUPABASE_URL: ${{ vars.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_APP_DOMAIN: ${{ vars.NEXT_PUBLIC_APP_DOMAIN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ env.AWS_REGION || vars.AWS_REGION }}
AWS_SUPABASE_LAMBDA_FUNCTION_NAME: ${{ env.AWS_SUPABASE_LAMBDA_FUNCTION_NAME || vars.AWS_SUPABASE_LAMBDA_FUNCTION_NAME }}
NEXT_PUBLIC_SUPABASE_URL: ${{ env.NEXT_PUBLIC_SUPABASE_URL || vars.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_APP_DOMAIN: ${{ env.NEXT_PUBLIC_APP_DOMAIN || vars.NEXT_PUBLIC_APP_DOMAIN }}
AWS_ACCESS_KEY_ID: ${{ env.AWS_ACCESS_KEY_ID || secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ env.AWS_SECRET_ACCESS_KEY || secrets.AWS_SECRET_ACCESS_KEY }}
run: |
if [ -z "${AWS_REGION}" ] || [ -z "${AWS_SUPABASE_LAMBDA_FUNCTION_NAME}" ] || [ -z "${NEXT_PUBLIC_SUPABASE_URL}" ] || [ -z "${NEXT_PUBLIC_APP_DOMAIN}" ] || [ -z "${AWS_ACCESS_KEY_ID}" ] || [ -z "${AWS_SECRET_ACCESS_KEY}" ]; then
echo "::warning::Skipping Supabase AWS Lambda deploy because required credentials/vars are missing."
Expand All @@ -255,16 +280,16 @@ jobs:
if: steps.validate-supabase-aws.outputs.skip != 'true' && steps.validate-aws.outputs.skip == 'true'
uses: aws-actions/configure-aws-credentials@713aaabfecea015b1ad8d37dc2b819ee41c00eb0
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID || secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ env.AWS_SECRET_ACCESS_KEY || secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION || vars.AWS_REGION }}

- name: Update Lambda environment variables (Supabase AWS Lambda)
if: steps.validate-supabase-aws.outputs.skip != 'true'
env:
AWS_SUPABASE_LAMBDA_FUNCTION_NAME: ${{ vars.AWS_SUPABASE_LAMBDA_FUNCTION_NAME }}
NEXT_PUBLIC_SUPABASE_URL: ${{ vars.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_APP_DOMAIN: ${{ vars.NEXT_PUBLIC_APP_DOMAIN }}
AWS_SUPABASE_LAMBDA_FUNCTION_NAME: ${{ env.AWS_SUPABASE_LAMBDA_FUNCTION_NAME || vars.AWS_SUPABASE_LAMBDA_FUNCTION_NAME }}
NEXT_PUBLIC_SUPABASE_URL: ${{ env.NEXT_PUBLIC_SUPABASE_URL || vars.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_APP_DOMAIN: ${{ env.NEXT_PUBLIC_APP_DOMAIN || vars.NEXT_PUBLIC_APP_DOMAIN }}
run: |
set -euo pipefail

Expand Down Expand Up @@ -295,7 +320,7 @@ jobs:
- name: Deploy Lambda function code (Supabase AWS Lambda)
if: steps.validate-supabase-aws.outputs.skip != 'true'
env:
AWS_SUPABASE_LAMBDA_FUNCTION_NAME: ${{ vars.AWS_SUPABASE_LAMBDA_FUNCTION_NAME }}
AWS_SUPABASE_LAMBDA_FUNCTION_NAME: ${{ env.AWS_SUPABASE_LAMBDA_FUNCTION_NAME || vars.AWS_SUPABASE_LAMBDA_FUNCTION_NAME }}
run: |
set -euo pipefail

Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -929,10 +929,12 @@ jobs:
SERVER_URL: ${{ github.server_url }}
CHANGELOG_TEXT: ${{ steps.prev_version.outputs.changelog_text }}
PLATFORMS: ${{ needs.build-and-release.outputs.platforms }}
ANDROID_PACKAGE_NAME: ${{ env.NEXT_PUBLIC_ANDROID_PACKAGE_NAME || vars.NEXT_PUBLIC_ANDROID_PACKAGE_NAME || 'com.devakesu.apps.ghostclass' }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
IMAGE_NAME=$(echo "${{ github.repository }}" | cut -d'/' -f2 | tr '[:upper:]' '[:lower:]')
PLATFORM_LIST=$(echo "${PLATFORMS}" | sed 's/linux\///g; s/,/, /g')
PLAY_STORE_URL="https://play.google.com/store/apps/details?id=${ANDROID_PACKAGE_NAME}"

if [[ "${PLATFORMS}" == *","* ]]; then
PLATFORM_DESC="Multi-platform Docker images (${PLATFORM_LIST})"
Expand All @@ -953,6 +955,14 @@ jobs:
- ✅ Build provenance attestations
- 🔍 SHA256 checksums for all artifacts

### Mobile App

[![Get it on Google Play](https://img.shields.io/badge/Get%20it%20on-Google%20Play-34A853?style=for-the-badge&logo=googleplay&logoColor=white)](${PLAY_STORE_URL})

**Google Play**: ${PLAY_STORE_URL}

> We recommend downloading from Google Play. GhostClass enforces Firebase App Check (Play Integrity), and Play-distributed builds provide the most reliable attestation path.

### Docker Images

\`\`\`bash
Expand Down
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
node scripts/sync-version.js --pre-commit
npx lint-staged

(cd mobile && dart format . && flutter analyze)
Loading
Loading