Files
opencode-mobile/.agents/skills/android-playstore-setup/templates/GITHUB_SECRETS.md
Dennis V 7ea41216c8 feat(release): add keystore setup + Play Store deployment guide
- Generated PKCS12 keystore (production-release.jks, alias: upload)
- Updated GitHub secrets: KEYSTORE_BASE64/PASSWORD/KEY_ALIAS/KEY_PASSWORD
- Added keystores/ to .gitignore
- Added distribution/PLAY_CONSOLE_SETUP.md: step-by-step guide to
  create GCP service account, link to Play Console, first manual
  upload, and configure PLAY_STORE_SERVICE_ACCOUNT_JSON secret
- Installed android-playstore-setup skills (sub-skills)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 10:51:56 +00:00

9.5 KiB

GitHub Secrets Setup for Play Store Deployment

Overview

GitHub Actions requires several secrets to deploy your app to the Play Store. This guide explains how to set up each secret.

Prerequisites

  • Admin access to GitHub repository
  • Service account JSON file from android-playstore-setup
  • Production keystore from android-release-build-setup

Required Secrets

Navigate to: Your Repository → Settings → Secrets and variables → Actions → New repository secret


1. SERVICE_ACCOUNT_JSON_PLAINTEXT

What it is: Complete plaintext contents of the Google Cloud service account JSON file (not base64 encoded)

How to get the value:

  1. Locate the JSON file downloaded during android-playstore-setup

    • Filename: service-account.json (or similar)
    • Location: Where you saved it securely
  2. Open the file in a text editor

  3. Copy the ENTIRE contents

    • From the first { to the last }
    • Include all whitespace and newlines
    • Should be ~2,400 characters
  4. In GitHub:

    • Name: SERVICE_ACCOUNT_JSON_PLAINTEXT
    • Value: Paste the copied JSON (plaintext, not base64 encoded)

Example format (DO NOT use this, use your actual file):

{
  "type": "service_account",
  "project_id": "your-gcp-project",
  "private_key_id": "abc123...",
  "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBg...\n-----END PRIVATE KEY-----\n",
  "client_email": "playstore-deploy@your-project.iam.gserviceaccount.com",
  "client_id": "123456789...",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/..."
}

Verification:

  • ✅ Starts with { and ends with }
  • ✅ Contains "type": "service_account"
  • ✅ Contains "client_email" with @...iam.gserviceaccount.com
  • ✅ Contains "private_key" section with BEGIN/END markers
  • ✅ Valid JSON (no syntax errors)

2. SIGNING_KEY_STORE_BASE64

What it is: Your production keystore file encoded as base64

How to get the value:

On Linux/macOS:

base64 -w 0 keystores/production-release.jks

On macOS (alternative):

base64 -i keystores/production-release.jks | tr -d '\n'

On Windows (PowerShell):

[Convert]::ToBase64String([IO.File]::ReadAllBytes('keystores\production-release.jks'))

On Windows (Git Bash):

base64 -w 0 keystores/production-release.jks

Steps:

  1. Navigate to your project directory
  2. Run the appropriate command above
  3. Copy the output (one long string, no line breaks)
  4. In GitHub:
    • Name: SIGNING_KEY_STORE_BASE64
    • Value: Paste the base64 string

Verification:

  • ✅ String is very long (~5,000+ characters)
  • ✅ Contains only alphanumeric characters, +, /, and = (padding)
  • ✅ No line breaks or spaces

Common mistakes:

  • ❌ Including -----BEGIN CERTIFICATE----- headers (wrong encoding method)
  • ❌ Line breaks in the base64 string
  • ❌ Encoding the wrong file (debug.keystore instead of production)

3. SIGNING_KEY_ALIAS

What it is: The alias used when creating your production keystore

How to get the value:

From keystores/KEYSTORE_INFO.txt:

Alias: upload

Or list keystore contents:

keytool -list -v -keystore keystores/production-release.jks
# Look for "Alias name:"

Typical values:

  • upload (recommended by Google Play)
  • release
  • production
  • key0 (default for some tools)

Steps:

  1. Check your keystore info file
  2. In GitHub:
    • Name: SIGNING_KEY_ALIAS
    • Value: The alias (e.g., upload)

Verification:

  • ✅ Matches the alias in your keystore
  • ✅ Case-sensitive (use exact match)

4. SIGNING_STORE_PASSWORD

What it is: Password for the keystore file itself

How to get the value:

From keystores/KEYSTORE_INFO.txt:

Store Password: your-store-password

Steps:

  1. Get password from secure location (password manager, keystore info file)
  2. In GitHub:
    • Name: SIGNING_STORE_PASSWORD
    • Value: The password (case-sensitive)

Security notes:

  • 🔒 Never commit this password to git
  • 🔒 Store in password manager
  • 🔒 Use strong password (16+ characters)

5. SIGNING_KEY_PASSWORD

What it is: Password for the specific key within the keystore

How to get the value:

From keystores/KEYSTORE_INFO.txt:

Key Password: your-key-password

Note: Key password and store password are often the same, but can be different.

Steps:

  1. Get password from secure location
  2. In GitHub:
    • Name: SIGNING_KEY_PASSWORD
    • Value: The password (case-sensitive)

Verification Checklist

After adding all secrets:

  • All 5 secrets are listed in repository settings
  • No typos in secret names (they're case-sensitive!)
  • SERVICE_ACCOUNT_JSON_PLAINTEXT is valid JSON
  • SIGNING_KEY_STORE_BASE64 has no line breaks
  • Aliases and passwords match your keystore
  • Test deployment workflow to verify

Testing Secrets

To verify secrets are correct without deploying:

  1. Create a test GitHub Actions workflow:
name: Test Secrets

on: workflow_dispatch

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      
      - name: Test SERVICE_ACCOUNT_JSON_PLAINTEXT
        run: |
          echo "${{ secrets.SERVICE_ACCOUNT_JSON_PLAINTEXT }}" | jq -r '.client_email'
          # Should output: playstore-deploy@your-project.iam.gserviceaccount.com
      
      - name: Test Keystore Decode
        run: |
          echo "${{ secrets.SIGNING_KEY_STORE_BASE64 }}" | base64 --decode > test.jks
          keytool -list -v -keystore test.jks \
            -storepass "${{ secrets.SIGNING_STORE_PASSWORD }}" \
            -alias "${{ secrets.SIGNING_KEY_ALIAS }}"
          # Should show keystore details
      
      - name: Cleanup
        if: always()
        run: rm -f test.jks
  1. Run workflow manually
  2. Check logs for verification
  3. Delete test workflow after verification

Common Issues

"Invalid service account JSON (SERVICE_ACCOUNT_JSON_PLAINTEXT)"

Symptom: Deployment fails with authentication error

Causes:

  • JSON is truncated (didn't copy all of it)
  • JSON has syntax errors
  • Wrong service account file

Fix:

  1. Re-copy the entire JSON file
  2. Validate JSON: https://jsonlint.com/
  3. Ensure file is from Google Cloud (has "type": "service_account")

"Failed to decode keystore"

Symptom: Build fails when decoding keystore

Causes:

  • Base64 string has line breaks
  • Wrong file was encoded
  • Encoding method was incorrect

Fix:

  1. Re-encode using commands above
  2. Ensure output is single line
  3. Verify keystore file is correct one

"Keystore password incorrect"

Symptom: Signing fails with password error

Causes:

  • Typo in password
  • Using wrong password (debug instead of release)
  • Password has special characters causing shell issues

Fix:

  1. Verify password from KEYSTORE_INFO.txt
  2. Test locally first: keytool -list -keystore production-release.jks
  3. If password has special characters, escape them

"Alias not found"

Symptom: Cannot find key with specified alias

Causes:

  • Alias name typo
  • Wrong keystore file
  • Case sensitivity

Fix:

  1. List keystore contents: keytool -list -v -keystore production-release.jks
  2. Copy exact alias name (case-sensitive)
  3. Update GitHub secret with correct alias

Security Best Practices

1. Least Privilege

  • Only grant secret access to necessary workflows
  • Use environment-specific secrets if needed
  • Regular audit of who has access

2. Rotation

  • Rotate service account keys annually
  • Update GitHub Secrets after rotation
  • Test deployment after rotation
  • Document rotation date

3. Monitoring

  • Enable GitHub Actions audit log
  • Monitor for unauthorized secret access
  • Review workflow run history
  • Check for failed authentication attempts

4. Backup

  • Keep service account JSON in password manager
  • Store keystore and passwords in company vault
  • Document secret values in secure location (not git!)
  • Have disaster recovery plan

5. Separation

  • Use different service accounts for dev/staging/prod
  • Consider separate repositories for different environments
  • Never share production secrets with development

Updating Secrets

When you need to update a secret:

  1. Navigate to: Repository → Settings → Secrets → Actions
  2. Find the secret to update
  3. Click "Update"
  4. Paste new value
  5. Click "Update secret"
  6. Test deployment to verify

Note: Updating a secret does NOT automatically re-run workflows. You need to trigger a new workflow run.


Deleting Secrets

If you need to rotate or remove a secret:

  1. Before deleting:

    • Ensure new secret is ready (if rotating)
    • Update workflows if secret name changes
    • Test with new secret
  2. Delete:

    • Repository → Settings → Secrets → Actions
    • Click secret to delete
    • Click "Remove secret"
    • Confirm deletion
  3. After deleting:

    • Add new secret immediately
    • Test deployment
    • Update documentation

References