mirror of
https://github.com/usetrmnl/trmnl-android.git
synced 2026-04-29 13:35:26 -07:00
421 lines
19 KiB
YAML
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
|