Files
trmnl-android/.github/workflows/test-keystore.yml
T
2025-06-28 18:23:20 -04:00

421 lines
19 KiB
YAML

name: Keystore Diagnostics and Testing
# This workflow provides comprehensive keystore diagnostics and testing
# It can be triggered manually to verify and troubleshoot keystore configuration:
# 1. Base64 keystore decoding and validation
# 2. Keystore password verification
# 3. Key alias existence and accessibility
# 4. Key password validation
# 5. Keystore type detection (JKS, PKCS12, JCEKS)
# 6. File signing capability testing with jarsigner
# 7. Private key accessibility analysis
# 8. Comparison with working debug keystore
# 9. Multiple signing approach testing
# 10. Comprehensive error diagnostics and artifact collection
on:
# Manual trigger only - run this to test your keystore configuration
workflow_dispatch:
jobs:
test-keystore:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '17' # Using a stable JDK version
distribution: 'temurin'
- name: Verify Java and Keytool Installation
run: |
echo "Java version:"
java -version
echo "Keytool version:"
keytool -help | head -n 1
- name: Create Test Directory
run: mkdir -p keystore-test
- name: Check KEYSTORE_BASE64 Secret Length
run: |
if [[ -n "${{ secrets.KEYSTORE_BASE64 }}" ]]; then
SECRET_LENGTH=$(echo "${{ secrets.KEYSTORE_BASE64 }}" | wc -c)
echo "✅ KEYSTORE_BASE64 secret is set (length: $SECRET_LENGTH chars)"
else
echo "❌ KEYSTORE_BASE64 secret is not set"
exit 1
fi
- name: Decode Keystore
run: |
# Decode the base64 keystore to a file
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > keystore-test/release.keystore
# Check if the file was created and has content
if [ -s keystore-test/release.keystore ]; then
echo "✅ Keystore decoded successfully"
echo "File size: $(wc -c < keystore-test/release.keystore) bytes"
echo "File details:"
ls -la keystore-test/release.keystore
# Check file type
file keystore-test/release.keystore
# Show first few bytes as hex (for debugging)
echo "First 32 bytes as hex:"
hexdump -C -n 32 keystore-test/release.keystore
else
echo "❌ Keystore file is empty or not created properly"
exit 1
fi
- name: Dump Keystore Information
if: always() # Run even if previous steps failed
run: |
echo "Dumping keystore information (with sensitive data redacted)..."
# List all entries without showing certificates
echo "All keystore entries:"
keytool -list -keystore keystore-test/release.keystore -storepass "${{ secrets.KEYSTORE_PASSWORD }}" | grep -v "Certificate fingerprint"
# Try to extract aliases
echo "Attempting to extract aliases:"
keytool -list -keystore keystore-test/release.keystore -storepass "${{ secrets.KEYSTORE_PASSWORD }}" | grep -E ',[^,]+, PrivateKeyEntry' | sed 's/,.*//' || echo "No aliases could be extracted"
# Check if the configured alias exists
echo "Checking if configured alias exists:"
keytool -list -keystore keystore-test/release.keystore -storepass "${{ secrets.KEYSTORE_PASSWORD }}" -alias "${{ secrets.KEY_ALIAS }}" > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "✅ Alias '${{ secrets.KEY_ALIAS }}' exists in keystore"
else
echo "❌ Alias '${{ secrets.KEY_ALIAS }}' NOT found in keystore"
fi
- name: Test Keystore with Password
run: |
echo "Testing keystore with provided password..."
keytool -list -keystore keystore-test/release.keystore -storepass "${{ secrets.KEYSTORE_PASSWORD }}" > keystore-test/output.txt 2>&1 || true
if grep -q "Keystore type:" keystore-test/output.txt; then
echo "✅ Keystore password is correct"
cat keystore-test/output.txt
else
echo "❌ Keystore password is incorrect or keystore format is invalid"
echo "Error output:"
cat keystore-test/output.txt
# Try common default passwords
echo "Trying with empty password..."
keytool -list -keystore keystore-test/release.keystore -storepass "" > keystore-test/empty.txt 2>&1 || true
if grep -q "Keystore type:" keystore-test/empty.txt; then
echo "✅ Keystore works with EMPTY password"
else
echo "❌ Empty password doesn't work either"
fi
echo "Trying with 'android' as password..."
keytool -list -keystore keystore-test/release.keystore -storepass "android" > keystore-test/android.txt 2>&1 || true
if grep -q "Keystore type:" keystore-test/android.txt; then
echo "✅ Keystore works with 'android' as password"
else
echo "❌ 'android' password doesn't work either"
fi
fi
- name: Test Key Alias
if: always()
run: |
echo "Testing key alias..."
keytool -list -keystore keystore-test/release.keystore -storepass "${{ secrets.KEYSTORE_PASSWORD }}" -alias "${{ secrets.KEY_ALIAS }}" > keystore-test/alias.txt 2>&1 || true
# Check success by looking for the certificate fingerprint instead of "Alias name:"
if grep -q "PrivateKeyEntry" keystore-test/alias.txt; then
echo "✅ Key alias exists in the keystore"
cat keystore-test/alias.txt
else
echo "❌ Key alias does not exist in the keystore or other error"
echo "Error output:"
cat keystore-test/alias.txt
echo "Available aliases in the keystore (if any):"
keytool -list -keystore keystore-test/release.keystore -storepass "${{ secrets.KEYSTORE_PASSWORD }}" 2>/dev/null | grep -i "alias" || echo "Could not list aliases"
fi
- name: Test Different Store Types
if: always() # Run even if previous steps failed
run: |
echo "Testing with different keystore types..."
for type in "JKS" "PKCS12" "JCEKS"; do
echo "Testing with store type: $type"
keytool -list -keystore keystore-test/release.keystore -storetype $type -storepass "${{ secrets.KEYSTORE_PASSWORD }}" > keystore-test/storetype-$type.txt 2>&1 || true
if grep -q "Keystore type:" keystore-test/storetype-$type.txt; then
echo "✅ Keystore works with type $type"
cat keystore-test/storetype-$type.txt | head -5
else
echo "❌ Keystore does not work with type $type"
fi
done
- name: Test Signing a File
if: always() # Run even if previous steps failed
run: |
echo "Testing if keystore can actually sign files..."
# Create a small dummy file to sign
echo "Test content for signing" > keystore-test/test-file.txt
# Create a simple JAR file for signing
jar cf keystore-test/test.jar keystore-test/test-file.txt
# Try to sign the JAR with the keystore
jarsigner -keystore keystore-test/release.keystore \
-storepass "${{ secrets.KEYSTORE_PASSWORD }}" \
-keypass "${{ secrets.KEY_PASSWORD }}" \
-signedjar keystore-test/signed.jar \
keystore-test/test.jar \
"${{ secrets.KEY_ALIAS }}" \
> keystore-test/signing.txt 2>&1 || true
# Check if the signing was successful
if [ -f keystore-test/signed.jar ] && jarsigner -verify -keystore keystore-test/release.keystore -storepass "${{ secrets.KEYSTORE_PASSWORD }}" keystore-test/signed.jar > keystore-test/verify.txt 2>&1; then
echo "✅ Successfully signed and verified a file with the keystore"
ls -la keystore-test/signed.jar
cat keystore-test/verify.txt | grep -v password
else
echo "❌ Failed to sign a file with the keystore"
echo "Signing output:"
cat keystore-test/signing.txt | grep -v password
# If the signed JAR exists, try to verify it anyway
if [ -f keystore-test/signed.jar ]; then
echo "Attempting to verify the signed file anyway:"
jarsigner -verify keystore-test/signed.jar > keystore-test/verify-anyway.txt 2>&1 || true
cat keystore-test/verify-anyway.txt | grep -v password
fi
fi
- name: Create Test Keystore (Sanity Check)
if: always() # Run even if previous steps failed
run: |
echo "Creating a test keystore to verify keytool is working correctly..."
keytool -genkey -v -keystore keystore-test/debug.keystore -storepass android -keypass android -alias androiddebugkey -keyalg RSA -keysize 2048 -validity 10000 -dname "CN=Android Debug,O=Android,C=US"
echo "Testing the newly created keystore:"
keytool -list -keystore keystore-test/debug.keystore -storepass android
- name: Prepare Artifacts (Excluding Keystore)
if: always() # Run even if previous steps failed
run: |
# Create a directory for artifacts without the keystore
mkdir -p keystore-test-artifacts
# Copy all txt files and other diagnostic outputs, but not the keystores
cp keystore-test/*.txt keystore-test-artifacts/ 2>/dev/null || true
echo "Excluded keystores from artifacts for security"
ls -la keystore-test-artifacts/
- name: Debug Secret Values (Redacted)
run: |
echo "Debugging secret configuration (values redacted for security):"
echo "KEYSTORE_PASSWORD length: $(echo '${{ secrets.KEYSTORE_PASSWORD }}' | wc -c)"
echo "KEY_PASSWORD length: $(echo '${{ secrets.KEY_PASSWORD }}' | wc -c)"
echo "KEY_ALIAS length: $(echo '${{ secrets.KEY_ALIAS }}' | wc -c)"
echo "KEY_ALIAS value: '${{ secrets.KEY_ALIAS }}'"
# Check if any secrets are empty
if [[ -z "${{ secrets.KEYSTORE_PASSWORD }}" ]]; then
echo "❌ KEYSTORE_PASSWORD is empty or not set"
fi
if [[ -z "${{ secrets.KEY_PASSWORD }}" ]]; then
echo "❌ KEY_PASSWORD is empty or not set"
fi
if [[ -z "${{ secrets.KEY_ALIAS }}" ]]; then
echo "❌ KEY_ALIAS is empty or not set"
fi
- name: Test Key Password Specifically
if: always()
run: |
echo "Testing if the key password works for the private key..."
# Try to change the key password (this requires the current key password to work)
keytool -keypasswd -keystore keystore-test/release.keystore \
-storepass "${{ secrets.KEYSTORE_PASSWORD }}" \
-alias "${{ secrets.KEY_ALIAS }}" \
-keypass "${{ secrets.KEY_PASSWORD }}" \
-new "${{ secrets.KEY_PASSWORD }}" > keystore-test/keypasswd.txt 2>&1 || true
if grep -q "Warning" keystore-test/keypasswd.txt || grep -q "keystore password was incorrect" keystore-test/keypasswd.txt; then
echo "❌ Key password is incorrect for the private key"
echo "Key password test output:"
cat keystore-test/keypasswd.txt
else
echo "✅ Key password appears to be correct"
fi
- name: Verify Keystore Entry Type
if: always()
run: |
echo "Checking the exact type of entry in the keystore..."
keytool -list -v -keystore keystore-test/release.keystore \
-storepass "${{ secrets.KEYSTORE_PASSWORD }}" \
-alias "${{ secrets.KEY_ALIAS }}" > keystore-test/entry-details.txt 2>&1 || true
if grep -q "Entry type: PrivateKeyEntry" keystore-test/entry-details.txt; then
echo "✅ Entry is correctly a PrivateKeyEntry"
echo "Key details:"
grep -A 5 -B 5 "Entry type:" keystore-test/entry-details.txt
elif grep -q "Entry type: trustedCertEntry" keystore-test/entry-details.txt; then
echo "❌ Entry is a trustedCertEntry (certificate only, no private key)"
echo "This explains why signing fails - you only have a certificate, not a private key"
else
echo "❓ Could not determine entry type"
echo "Full entry details:"
cat keystore-test/entry-details.txt
fi
- name: Compare Working vs Broken Keystore
if: always()
run: |
echo "Comparing your keystore with the working debug keystore..."
echo "=== Your keystore details ==="
keytool -list -v -keystore keystore-test/release.keystore \
-storepass "${{ secrets.KEYSTORE_PASSWORD }}" \
-alias "${{ secrets.KEY_ALIAS }}" > keystore-test/your-keystore-details.txt 2>&1 || true
echo "=== Debug keystore details ==="
keytool -list -v -keystore keystore-test/debug.keystore \
-storepass "android" \
-alias "androiddebugkey" > keystore-test/debug-keystore-details.txt 2>&1 || true
echo "=== Testing jarsigner with debug keystore ==="
jarsigner -keystore keystore-test/debug.keystore \
-storepass "android" \
-keypass "android" \
-signedjar keystore-test/debug-signed.jar \
keystore-test/test.jar \
"androiddebugkey" > keystore-test/debug-signing.txt 2>&1 || true
if [ -f keystore-test/debug-signed.jar ]; then
echo "✅ Debug keystore can sign files successfully"
ls -la keystore-test/debug-signed.jar
else
echo "❌ Even debug keystore failed to sign"
cat keystore-test/debug-signing.txt
fi
- name: Test with Different jarsigner Options
if: always()
run: |
echo "Testing jarsigner with different options..."
# Try with explicit storetype
echo "=== Trying with explicit -storetype PKCS12 ==="
jarsigner -keystore keystore-test/release.keystore \
-storetype PKCS12 \
-storepass "${{ secrets.KEYSTORE_PASSWORD }}" \
-keypass "${{ secrets.KEY_PASSWORD }}" \
-signedjar keystore-test/signed-pkcs12.jar \
keystore-test/test.jar \
"${{ secrets.KEY_ALIAS }}" > keystore-test/signing-pkcs12.txt 2>&1 || true
# Try with JKS storetype
echo "=== Trying with explicit -storetype JKS ==="
jarsigner -keystore keystore-test/release.keystore \
-storetype JKS \
-storepass "${{ secrets.KEYSTORE_PASSWORD }}" \
-keypass "${{ secrets.KEY_PASSWORD }}" \
-signedjar keystore-test/signed-jks.jar \
keystore-test/test.jar \
"${{ secrets.KEY_ALIAS }}" > keystore-test/signing-jks.txt 2>&1 || true
# Try without keypass (in case store and key passwords are the same)
echo "=== Trying without explicit -keypass ==="
jarsigner -keystore keystore-test/release.keystore \
-storepass "${{ secrets.KEYSTORE_PASSWORD }}" \
-signedjar keystore-test/signed-no-keypass.jar \
keystore-test/test.jar \
"${{ secrets.KEY_ALIAS }}" > keystore-test/signing-no-keypass.txt 2>&1 || true
echo "Results summary:"
for test in pkcs12 jks no-keypass; do
if [ -f keystore-test/signed-$test.jar ]; then
echo "✅ $test approach worked"
else
echo "❌ $test approach failed:"
cat keystore-test/signing-$test.txt | head -2
fi
done
- name: Analyze Private Key Accessibility
if: always()
run: |
echo "Analyzing private key accessibility..."
# Try to export the private key (this will fail but give us info)
echo "=== Attempting to access private key directly ==="
keytool -exportcert -keystore keystore-test/release.keystore \
-storepass "${{ secrets.KEYSTORE_PASSWORD }}" \
-alias "${{ secrets.KEY_ALIAS }}" \
-file keystore-test/cert.der > keystore-test/export-cert.txt 2>&1 || true
if [ -f keystore-test/cert.der ]; then
echo "✅ Certificate export successful"
file keystore-test/cert.der
openssl x509 -in keystore-test/cert.der -inform DER -text -noout | head -10
else
echo "❌ Certificate export failed"
cat keystore-test/export-cert.txt
fi
# Check if we can change the key password (requires private key access)
echo "=== Testing private key access by changing key password ==="
cp keystore-test/release.keystore keystore-test/test-copy.keystore
keytool -keypasswd -keystore keystore-test/test-copy.keystore \
-storepass "${{ secrets.KEYSTORE_PASSWORD }}" \
-alias "${{ secrets.KEY_ALIAS }}" \
-keypass "${{ secrets.KEY_PASSWORD }}" \
-new "newpassword123" > keystore-test/keypasswd-test.txt 2>&1 || true
if grep -q "Warning" keystore-test/keypasswd-test.txt; then
echo "❌ Cannot access private key for password change"
cat keystore-test/keypasswd-test.txt
else
echo "✅ Private key is accessible for password changes"
# Now try jarsigner with the new password
echo "=== Testing jarsigner with new key password ==="
jarsigner -keystore keystore-test/test-copy.keystore \
-storepass "${{ secrets.KEYSTORE_PASSWORD }}" \
-keypass "newpassword123" \
-signedjar keystore-test/signed-newpass.jar \
keystore-test/test.jar \
"${{ secrets.KEY_ALIAS }}" > keystore-test/signing-newpass.txt 2>&1 || true
if [ -f keystore-test/signed-newpass.jar ]; then
echo "✅ Signing worked with new key password!"
else
echo "❌ Still failed with new key password"
cat keystore-test/signing-newpass.txt
fi
fi
- name: Upload Diagnostic Files
if: always() # Run even if previous steps failed
uses: actions/upload-artifact@v4
with:
name: keystore-diagnostic-files
path: keystore-test-artifacts/
retention-days: 1 # Only keep for a day since it contains diagnostic info