Files
Krow-workspace/docs/RELEASE/APK_SIGNING_IMPLEMENTATION_SUMMARY.md
Achintha Isuru 8b9a58adb1 feat: Add mobile CI/CD secrets setup for APK signing
- Updated Makefile to include new command for setting up mobile CI secrets.
- Enhanced tools.mk with setup-mobile-ci-secrets target.
- Created setup-mobile-github-secrets.sh script for configuring GitHub Secrets for APK signing.
- Added APK signing implementation summary documentation.
- Created detailed APK signing setup guide.
- Added GitHub secrets checklist for easy reference.
2026-03-05 13:55:38 -05:00

14 KiB
Raw Blame History

APK Signing Implementation - Complete Summary

Status: Implementation Complete | 🟡 Secrets Configuration Pending

Last Updated: 2024


📋 What Was Implemented

1. GitHub Actions Workflow Updates

File: .github/workflows/product-release.yml

New Steps Added:

  1. 🔐 Setup APK Signing (before build)

    • Detects app (worker/client) and environment (dev/stage/prod)
    • Decodes keystore from GitHub Secrets
    • Sets CodeMagic-compatible environment variables
    • Configures CI=true for build.gradle.kts detection
    • Gracefully handles missing secrets with warnings
  2. Verify APK Signature (after build)

    • Verifies APK is properly signed using jarsigner
    • Displays certificate details
    • Shows signer information
    • Provides helpful warnings if unsigned

How It Works:

Setup Signing:
  - Reads: ${{ secrets.WORKER_KEYSTORE_DEV_BASE64 }}
  - Decodes to: /tmp/keystores/release.jks
  - Sets env: CI=true, CM_KEYSTORE_PATH_STAFF=/tmp/keystores/release.jks

Build APK:
  - Runs: make mobile-staff-build PLATFORM=apk MODE=release
  - build.gradle.kts detects CI=true
  - Uses environment variables for signing

Verify Signature:
  - Checks with: jarsigner -verify app-release.apk
  - Displays certificate info

2. Documentation Created

Files Created:

File Purpose Lines
docs/RELEASE/APK_SIGNING_SETUP.md Complete setup guide 300+
docs/RELEASE/GITHUB_SECRETS_CHECKLIST.md Quick reference checklist 120+
.github/scripts/setup-github-secrets.sh Helper script 200+

3. Scripts Created

File: .github/scripts/setup-github-secrets.sh

Purpose: Interactive helper to:

  • Show which secrets are needed
  • Generate base64 from existing keystores
  • Display keytool information
  • Provide copy-paste commands

Usage:

./.github/scripts/setup-github-secrets.sh

🔑 GitHub Secrets Required

Total: 24 Secrets (6 keystores × 4 properties each)

Secret Naming Pattern:

{APP}_KEYSTORE_{ENV}_BASE64
{APP}_KEYSTORE_PASSWORD_{ENV}
{APP}_KEY_ALIAS_{ENV}
{APP}_KEY_PASSWORD_{ENV}

Where:

  • {APP} = WORKER or CLIENT
  • {ENV} = DEV, STAGING, or PROD

Full List:

Worker Mobile (12 secrets):

  • WORKER_KEYSTORE_DEV_BASE64, WORKER_KEYSTORE_PASSWORD_DEV, WORKER_KEY_ALIAS_DEV, WORKER_KEY_PASSWORD_DEV
  • WORKER_KEYSTORE_STAGING_BASE64, WORKER_KEYSTORE_PASSWORD_STAGING, WORKER_KEY_ALIAS_STAGING, WORKER_KEY_PASSWORD_STAGING
  • WORKER_KEYSTORE_PROD_BASE64, WORKER_KEYSTORE_PASSWORD_PROD, WORKER_KEY_ALIAS_PROD, WORKER_KEY_PASSWORD_PROD

Client Mobile (12 secrets):

  • CLIENT_KEYSTORE_DEV_BASE64, CLIENT_KEYSTORE_PASSWORD_DEV, CLIENT_KEY_ALIAS_DEV, CLIENT_KEY_PASSWORD_DEV
  • CLIENT_KEYSTORE_STAGING_BASE64, CLIENT_KEYSTORE_PASSWORD_STAGING, CLIENT_KEY_ALIAS_STAGING, CLIENT_KEY_PASSWORD_STAGING
  • CLIENT_KEYSTORE_PROD_BASE64, CLIENT_KEYSTORE_PASSWORD_PROD, CLIENT_KEY_ALIAS_PROD, CLIENT_KEY_PASSWORD_PROD

🚀 How to Configure

Step 1: Prepare Dev Keystores

Dev keystores are already in the repository:

  • Worker: apps/mobile/apps/staff/android/app/krow_with_us_staff_dev.jks
  • Client: apps/mobile/apps/client/android/app/krow_with_us_client_dev.jks

Generate base64:

# Worker Dev
base64 -i apps/mobile/apps/staff/android/app/krow_with_us_staff_dev.jks

# Client Dev  
base64 -i apps/mobile/apps/client/android/app/krow_with_us_client_dev.jks

Step 2: Retrieve Staging/Prod Keystores

Option A: From CodeMagic

  1. Go to CodeMagic → Team Settings → Code signing identities
  2. Download keystores: krow_staff_staging.jks, krow_staff_prod.jks, etc.
  3. Generate base64 for each

Option B: From Secure Storage

  1. Retrieve from your organization's key management system
  2. Generate base64 for each

Step 3: Add to GitHub

  1. Go to: Repository → Settings → Secrets and variables → Actions
  2. Click: New repository secret
  3. Add all 24 secrets (use checklist: GITHUB_SECRETS_CHECKLIST.md)

Step 4: Test the Workflow

# Test with dev environment first
# Go to: Actions → Product Release → Run workflow
# Select:
#   - App: worker-mobile-app
#   - Environment: dev
#   - Version type: patch
#   - Create GitHub Release: true

Expected Output:

🔐 Setting up Android signing for worker-mobile-app in dev environment...
✅ Keystore decoded successfully
📦 Keystore size: 3.2K
✅ Signing environment configured for STAFF (dev environment)
🔑 Using key alias: krow_staff_dev

📱 Building Staff (Worker) APK...
✅ APK built successfully

🔍 Verifying APK signature...
✅ APK is properly signed!
📜 Certificate Details: [shows cert info]

🔒 Security Considerations

Safe Practices

  1. Dev keystores in repo: Acceptable for development

    • Committed: krow_with_us_staff_dev.jks, krow_with_us_client_dev.jks
    • Password: krowwithus (public knowledge)
  2. Staging/Prod keystores: ONLY in GitHub Secrets

    • Never commit to repository
    • Encrypted at rest by GitHub
    • Only accessible in workflow runs
  3. Keystore cleanup: Workflow stores in ${{ runner.temp }}

    • Automatically deleted after job completes
    • Not persisted in artifacts or logs

⚠️ Important Notes

  1. Same keystores as CodeMagic: Use identical keystores to ensure app updates work
  2. Signature consistency: Apps signed with different keystores cannot update each other
  3. Key rotation: Document process for rotating production keys
  4. Backup keystores: Keep secure backups - lost keystores = can't update app

🧪 Testing Checklist

Before using in production:

  • Configure all 24 GitHub Secrets
  • Run workflow with dev environment
  • Download APK artifact
  • Verify signature: jarsigner -verify -verbose app.apk
  • Install APK on Android device
  • Launch app and verify functionality
  • Compare signature fingerprints with CodeMagic builds
  • Test stage environment
  • Test prod environment (after full validation)

📊 Architecture Overview

┌─────────────────────────────────────────────────────────────┐
│ GitHub Actions Workflow: product-release.yml               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. Validate & Create Release                               │
│     └─> Extract version from pubspec.yaml                  │
│     └─> Create Git tag                                      │
│     └─> Create GitHub Release                               │
│                                                             │
│  2. Build Mobile Artifacts                                  │
│     │                                                       │
│     ├─> Setup Node.js + Firebase CLI                       │
│     ├─> Setup Java 17                                       │
│     ├─> Setup Flutter 3.24.5                                │
│     ├─> Install Melos                                       │
│     ├─> Install Dependencies                                │
│     │                                                       │
│     ├─> 🔐 Setup APK Signing (NEW)                         │
│     │   ├─> Detect app (worker/client)                     │
│     │   ├─> Detect environment (dev/stage/prod)            │
│     │   ├─> Read GitHub Secret:                            │
│     │   │   {APP}_KEYSTORE_{ENV}_BASE64                    │
│     │   ├─> Decode base64 → .jks file                      │
│     │   ├─> Set environment variables:                     │
│     │   │   - CI=true                                      │
│     │   │   - CM_KEYSTORE_PATH_STAFF=/tmp/keystore.jks    │
│     │   │   - CM_KEYSTORE_PASSWORD_STAFF=***              │
│     │   │   - CM_KEY_ALIAS_STAFF=krow_staff_dev           │
│     │   │   - CM_KEY_PASSWORD_STAFF=***                   │
│     │   └─> ✅ Ready for signed build                      │
│     │                                                       │
│     ├─> 🏗️ Build APK                                       │
│     │   └─> make mobile-staff-build PLATFORM=apk          │
│     │       └─> Flutter build detects CI=true              │
│     │           └─> build.gradle.kts uses env vars         │
│     │               └─> Signs APK with keystore            │
│     │                                                       │
│     ├─> ✅ Verify APK Signature (NEW)                      │
│     │   ├─> jarsigner -verify app-release.apk             │
│     │   ├─> Show certificate details                       │
│     │   └─> Confirm signing successful                     │
│     │                                                       │
│     ├─> 📤 Upload APK as Artifact                          │
│     │   └─> 30-day retention in GitHub Actions            │
│     │                                                       │
│     └─> 📦 Attach APK to GitHub Release                    │
│         └─> krow-withus-worker-mobile-dev-v0.1.0.apk      │
│                                                             │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ Build Configuration: build.gradle.kts                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  signingConfigs {                                           │
│      create("release") {                                    │
│          if (System.getenv()["CI"] == "true") {            │
│              // ✅ GitHub Actions / CodeMagic              │
│              storeFile = file(                              │
│                  System.getenv()["CM_KEYSTORE_PATH_STAFF"] │
│              )                                              │
│              storePassword =                                │
│                  System.getenv()["CM_KEYSTORE_PASSWORD_*"] │
│              keyAlias =                                     │
│                  System.getenv()["CM_KEY_ALIAS_*"]        │
│              keyPassword =                                  │
│                  System.getenv()["CM_KEY_PASSWORD_*"]     │
│          } else {                                           │
│              // Local Development                           │
│              use key.properties file                        │
│          }                                                  │
│      }                                                      │
│  }                                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

📖 Documentation Index

  1. APK_SIGNING_SETUP.md

    • Complete setup guide with all details
    • Security best practices
    • Troubleshooting guide
    • Keystore management commands
  2. GITHUB_SECRETS_CHECKLIST.md

    • Quick reference for all 24 secrets
    • Copy-paste checklist
    • Dev environment values
  3. setup-mobile-github-secrets.sh

    • Interactive helper script
    • Shows existing keystores
    • Generates base64 commands
    • Displays keytool info
  4. product-release.yml

    • Updated workflow with signing
    • Lines 198-294: Setup APK Signing
    • Lines 330-364: Verify APK Signature

Next Steps

Immediate (Required for Signed APKs)

  1. Configure GitHub Secrets (30 minutes)

    • Start with dev environment (test first)
    • Use helper script: .github/scripts/setup-mobile-github-secrets.sh
    • Follow checklist: docs/RELEASE/GITHUB_SECRETS_CHECKLIST.md
  2. Test Dev Signing (15 minutes)

    • Run workflow with dev environment
    • Download APK and verify signature
    • Install on device and test
  3. Configure Staging/Prod (30 minutes)

    • Retrieve keystores from CodeMagic/secure storage
    • Add to GitHub Secrets
    • Test each environment

Future Enhancements (Optional)

  • Add AAB (Android App Bundle) support for Play Store
  • Implement iOS signing for IPA files
  • Add automated Play Store upload
  • Set up GitHub Environments with protection rules
  • Add Slack notifications for releases

🆘 Support

If you encounter issues:

  1. Check workflow logs for signing step output
  2. Verify GitHub Secrets are configured correctly
  3. Run helper script: .github/scripts/setup-mobile-github-secrets.sh
  4. Review: docs/RELEASE/APK_SIGNING_SETUP.md → Troubleshooting section

Common Issues:

  • "Keystore not found" → Secret not configured or wrong name
  • "Wrong password" → Secret value doesn't match actual keystore
  • APK unsigned → CI=true not set or build.gradle.kts issue
  • App won't install over existing → Different keystore used

Implementation Date: 2024
Implemented By: GitHub Copilot (Claude Sonnet 4.5)
Status: Code Complete | 🟡 Awaiting Secrets Configuration