Skip to content

chore(deps): bump the android group across 1 directory with 23 updates #123

chore(deps): bump the android group across 1 directory with 23 updates

chore(deps): bump the android group across 1 directory with 23 updates #123

Workflow file for this run

name: Android CI/CD
on:
# Build on push to main branch
push:
branches: [ main, master ]
paths-ignore:
- '**.md'
- 'LICENSE'
- '.gitignore'
# Build on pull requests
pull_request:
branches: [ main, master ]
# Manual trigger with release option
workflow_dispatch:
inputs:
create_release:
description: 'Create a GitHub Release'
required: true
type: boolean
default: false
release_version:
description: 'Release version (e.g., 1.0.0)'
required: false
type: string
default: ''
pre_release:
description: 'Mark as pre-release'
required: false
type: boolean
default: false
release_notes:
description: 'Release notes (optional)'
required: false
type: string
default: ''
env:
JAVA_VERSION: '17'
JAVA_DISTRIBUTION: 'temurin'
permissions:
contents: read
jobs:
# ===========================================
# Build Job - Matrix for all flavors
# ===========================================
build:
name: Build (${{ matrix.flavor }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
flavor: [oem, sideload, system]
permissions:
contents: read
id-token: write
attestations: write
outputs:
version_name: ${{ steps.version.outputs.version_name }}
version_code: ${{ steps.version.outputs.version_code }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK ${{ env.JAVA_VERSION }}
uses: actions/setup-java@v4
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: ${{ env.JAVA_DISTRIBUTION }}
cache: 'gradle'
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Extract version info
id: version
run: |
# Extract version from build.gradle.kts
VERSION_NAME=$(grep -oP 'versionName\s*=\s*"\K[^"]+' app/build.gradle.kts || echo "1.0.0")
VERSION_CODE=$(grep -oP 'versionCode\s*=\s*\K\d+' app/build.gradle.kts || echo "1")
# Use input version if provided for release
if [ -n "${{ inputs.release_version }}" ]; then
VERSION_NAME="${{ inputs.release_version }}"
fi
echo "version_name=$VERSION_NAME" >> $GITHUB_OUTPUT
echo "version_code=$VERSION_CODE" >> $GITHUB_OUTPUT
echo "Version: $VERSION_NAME ($VERSION_CODE)"
- name: Clean project
run: ./gradlew clean
- name: Build Debug APK (${{ matrix.flavor }})
run: ./gradlew assemble${{ matrix.flavor }}Debug --stacktrace
- name: Upload Debug APK (${{ matrix.flavor }})
uses: actions/upload-artifact@v4
with:
name: app-${{ matrix.flavor }}-debug
path: app/build/outputs/apk/${{ matrix.flavor }}/debug/*.apk
retention-days: 14
- name: Attest Debug APK (${{ matrix.flavor }})
id: attest-debug
uses: actions/attest-build-provenance@v2
with:
subject-path: app/build/outputs/apk/${{ matrix.flavor }}/debug/*.apk
- name: Build Summary
run: |
echo "## Debug Build Complete (${{ matrix.flavor }})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Build Info" >> $GITHUB_STEP_SUMMARY
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| **Flavor** | ${{ matrix.flavor }} |" >> $GITHUB_STEP_SUMMARY
echo "| **Version** | ${{ steps.version.outputs.version_name }} (${{ steps.version.outputs.version_code }}) |" >> $GITHUB_STEP_SUMMARY
echo "| **Commit** | [\`${GITHUB_SHA::7}\`](${{ github.server_url }}/${{ github.repository }}/commit/${GITHUB_SHA}) |" >> $GITHUB_STEP_SUMMARY
echo "| **Branch** | \`${{ github.ref_name }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **Runner** | \`${{ runner.os }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **Java** | ${{ env.JAVA_VERSION }} (${{ env.JAVA_DISTRIBUTION }}) |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Signing" >> $GITHUB_STEP_SUMMARY
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| **Type** | Debug (Android debug keystore) |" >> $GITHUB_STEP_SUMMARY
echo "| **Key** | Default Android debug key |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Attestation" >> $GITHUB_STEP_SUMMARY
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| **Status** | Attested |" >> $GITHUB_STEP_SUMMARY
echo "| **Type** | [SLSA Build Provenance](https://slsa.dev/spec/v1.0/provenance) |" >> $GITHUB_STEP_SUMMARY
echo "| **Bundle** | [\`${{ steps.attest-debug.outputs.bundle-path }}\`](${{ github.server_url }}/${{ github.repository }}/attestations) |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Links" >> $GITHUB_STEP_SUMMARY
echo "- [Download Artifact](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
echo "- [View Attestations](${{ github.server_url }}/${{ github.repository }}/attestations)" >> $GITHUB_STEP_SUMMARY
echo "- [Workflow File](${{ github.server_url }}/${{ github.repository }}/blob/${{ github.sha }}/.github/workflows/android-ci.yml)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Verify Attestation" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "gh attestation verify app-${{ matrix.flavor }}-debug.apk --owner ${{ github.repository_owner }}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
# ===========================================
# Release Build Job - Only when release is requested
# ===========================================
build-release:
name: Build Release (${{ matrix.flavor }})
runs-on: ubuntu-latest
needs: [build, test]
if: github.event_name == 'workflow_dispatch' && inputs.create_release == true
strategy:
fail-fast: false
matrix:
flavor: [oem, sideload, system]
permissions:
contents: read
id-token: write
attestations: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK ${{ env.JAVA_VERSION }}
uses: actions/setup-java@v4
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: ${{ env.JAVA_DISTRIBUTION }}
cache: 'gradle'
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Decode Keystore
if: env.KEYSTORE_BASE64 != ''
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
run: |
echo "$KEYSTORE_BASE64" | base64 -d > app/release-keystore.jks
echo "Keystore decoded"
- name: Build Release APK (Signed)
if: env.KEYSTORE_BASE64 != ''
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: |
./gradlew assemble${{ matrix.flavor }}Release \
-Pandroid.injected.signing.store.file=${{ github.workspace }}/app/release-keystore.jks \
-Pandroid.injected.signing.store.password=$KEYSTORE_PASSWORD \
-Pandroid.injected.signing.key.alias=$KEY_ALIAS \
-Pandroid.injected.signing.key.password=$KEY_PASSWORD \
--stacktrace
- name: Install step CLI
if: env.KEYSTORE_BASE64 == ''
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
run: |
wget -q https://dl.smallstep.com/cli/docs-cli-install/latest/step-cli_amd64.deb
sudo dpkg -i step-cli_amd64.deb
rm step-cli_amd64.deb
step version
# ===========================================
# Option 2: Step CA with JWK Provisioner
# Requires: STEP_CA_URL, STEP_CA_ROOT_CRT, STEP_CA_JWK_PROVISIONER, STEP_CA_JWK_KEY
# ===========================================
- name: Configure Step CA
id: step-ca-config
if: env.KEYSTORE_BASE64 == '' && env.STEP_CA_URL != ''
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
STEP_CA_URL: ${{ secrets.STEP_CA_URL }}
STEP_CA_ROOT_CRT: ${{ secrets.STEP_CA_ROOT_CRT }}
STEP_CA_FINGERPRINT: ${{ secrets.STEP_CA_FINGERPRINT }}
run: |
echo "Configuring step CLI for CA: $STEP_CA_URL"
# Bootstrap step CLI with the CA
if [ -n "$STEP_CA_ROOT_CRT" ]; then
echo "$STEP_CA_ROOT_CRT" > /tmp/step-ca-root.crt
step ca bootstrap --ca-url "$STEP_CA_URL" --root /tmp/step-ca-root.crt --install
elif [ -n "$STEP_CA_FINGERPRINT" ]; then
step ca bootstrap --ca-url "$STEP_CA_URL" --fingerprint "$STEP_CA_FINGERPRINT" --install
else
echo "Either STEP_CA_ROOT_CRT or STEP_CA_FINGERPRINT must be provided"
exit 1
fi
echo "Step CA configured"
step ca health
- name: Request Certificate from Step CA (JWK Auth)
id: step-ca-cert
if: env.KEYSTORE_BASE64 == '' && env.STEP_CA_URL != ''
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
STEP_CA_URL: ${{ secrets.STEP_CA_URL }}
STEP_CA_JWK_PROVISIONER: ${{ secrets.STEP_CA_JWK_PROVISIONER }}
STEP_CA_JWK_KEY: ${{ secrets.STEP_CA_JWK_KEY }}
STEP_CA_JWK_PASSWORD: ${{ secrets.STEP_CA_JWK_PASSWORD }}
run: |
echo "Requesting certificate from Step CA using JWK provisioner..."
# Write JWK private key to temp file
echo "$STEP_CA_JWK_KEY" > /tmp/jwk-key.json
chmod 600 /tmp/jwk-key.json
# Generate a new key pair for the certificate
step crypto keypair ca-cert-pub.pem ca-cert-key.pem \
--kty RSA \
--size 2048 \
--no-password \
--insecure
# Request certificate from CA using JWK provisioner
if [ -n "$STEP_CA_JWK_PASSWORD" ]; then
echo "$STEP_CA_JWK_PASSWORD" | step ca certificate \
"CN=Flock You Release,O=FlockYou,L=CI,ST=GitHub Actions,C=US" \
ca-cert.pem \
ca-cert-key.pem \
--provisioner "$STEP_CA_JWK_PROVISIONER" \
--provisioner-password-file /dev/stdin \
--not-after 8760h \
--force
else
step ca certificate \
"CN=Flock You Release,O=FlockYou,L=CI,ST=GitHub Actions,C=US" \
ca-cert.pem \
ca-cert-key.pem \
--provisioner "$STEP_CA_JWK_PROVISIONER" \
--not-after 8760h \
--force
fi
# Convert to PKCS12 keystore for Android signing
# Include the full certificate chain
step ca root ca-root.pem
cat ca-cert.pem ca-root.pem > ca-cert-chain.pem
openssl pkcs12 -export \
-in ca-cert-chain.pem \
-inkey ca-cert-key.pem \
-out app/ca-signed-keystore.p12 \
-name ca-signed \
-passout pass:ca-signed
# Verify the keystore
keytool -list -keystore app/ca-signed-keystore.p12 -storepass ca-signed -storetype PKCS12
echo "CA-signed keystore created"
# Output certificate info for transparency
echo "Certificate details:"
step certificate inspect ca-cert.pem
# Output certificate fingerprint for verification
echo "Certificate fingerprint:"
step certificate fingerprint ca-cert.pem
# Store signing type for summary
echo "signing_type=ca" >> $GITHUB_OUTPUT
# Cleanup sensitive files
rm -f /tmp/jwk-key.json ca-cert.pem ca-cert-key.pem ca-cert-chain.pem ca-root.pem ca-cert-pub.pem /tmp/step-ca-root.crt
- name: Build Release APK (CA Signed)
if: env.KEYSTORE_BASE64 == '' && env.STEP_CA_URL != ''
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
STEP_CA_URL: ${{ secrets.STEP_CA_URL }}
run: |
echo "Building with CA-signed certificate from Step CA"
./gradlew assemble${{ matrix.flavor }}Release \
-Pandroid.injected.signing.store.file=${{ github.workspace }}/app/ca-signed-keystore.p12 \
-Pandroid.injected.signing.store.password=ca-signed \
-Pandroid.injected.signing.key.alias=ca-signed \
-Pandroid.injected.signing.key.password=ca-signed \
--stacktrace
# ===========================================
# Option 3: Ephemeral Self-Signed (Fallback)
# Used when no keystore or CA is configured
# ===========================================
- name: Generate Ephemeral Self-Signed Certificate
if: env.KEYSTORE_BASE64 == '' && env.STEP_CA_URL == ''
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
STEP_CA_URL: ${{ secrets.STEP_CA_URL }}
run: |
echo "Generating ephemeral self-signed certificate with step CLI..."
# Generate ephemeral key pair and self-signed certificate
step certificate create \
"CN=Flock You Ephemeral,O=FlockYou,L=CI,ST=GitHub Actions,C=US" \
ephemeral-cert.pem \
ephemeral-key.pem \
--profile leaf \
--not-after 8760h \
--no-password \
--insecure \
--kty RSA \
--size 2048
# Convert to PKCS12 keystore for Android signing
openssl pkcs12 -export \
-in ephemeral-cert.pem \
-inkey ephemeral-key.pem \
-out app/ephemeral-keystore.p12 \
-name ephemeral \
-passout pass:ephemeral
# Verify the keystore
keytool -list -keystore app/ephemeral-keystore.p12 -storepass ephemeral -storetype PKCS12
echo "Ephemeral keystore created"
# Output certificate info for transparency
echo "Certificate details:"
openssl x509 -in ephemeral-cert.pem -text -noout | head -30
# Cleanup PEM files (sensitive key material)
rm -f ephemeral-cert.pem ephemeral-key.pem
- name: Build Release APK (Ephemeral Signed)
if: env.KEYSTORE_BASE64 == '' && env.STEP_CA_URL == ''
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
STEP_CA_URL: ${{ secrets.STEP_CA_URL }}
run: |
echo "No keystore or CA configured, building with ephemeral self-signed certificate"
./gradlew assemble${{ matrix.flavor }}Release \
-Pandroid.injected.signing.store.file=${{ github.workspace }}/app/ephemeral-keystore.p12 \
-Pandroid.injected.signing.store.password=ephemeral \
-Pandroid.injected.signing.key.alias=ephemeral \
-Pandroid.injected.signing.key.password=ephemeral \
--stacktrace
- name: Rename APK with version
run: |
VERSION="${{ needs.build.outputs.version_name }}"
if [ -z "$VERSION" ]; then
VERSION="${{ inputs.release_version }}"
fi
if [ -z "$VERSION" ]; then
VERSION="1.0.0"
fi
# Create a staging directory for renamed APK
mkdir -p app/build/outputs/apk/release-renamed
# Rename the release APK for this flavor
cp "app/build/outputs/apk/${{ matrix.flavor }}/release/"*.apk \
"app/build/outputs/apk/release-renamed/FlockYou-${{ matrix.flavor }}-v${VERSION}.apk"
echo "Renamed ${{ matrix.flavor }} APK to FlockYou-${{ matrix.flavor }}-v${VERSION}.apk"
- name: Upload Release APK (${{ matrix.flavor }})
uses: actions/upload-artifact@v4
with:
name: app-${{ matrix.flavor }}-release
path: app/build/outputs/apk/release-renamed/*.apk
retention-days: 90
- name: Attest Release APK (${{ matrix.flavor }})
id: attest-release
uses: actions/attest-build-provenance@v2
with:
subject-path: app/build/outputs/apk/release-renamed/*.apk
- name: Release Build Summary
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
STEP_CA_URL: ${{ secrets.STEP_CA_URL }}
STEP_CA_JWK_PROVISIONER: ${{ secrets.STEP_CA_JWK_PROVISIONER }}
run: |
VERSION="${{ needs.build.outputs.version_name }}"
if [ -z "$VERSION" ]; then
VERSION="${{ inputs.release_version }}"
fi
if [ -z "$VERSION" ]; then
VERSION="1.0.0"
fi
echo "## Release Build Complete (${{ matrix.flavor }})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Build Info" >> $GITHUB_STEP_SUMMARY
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| **Flavor** | ${{ matrix.flavor }} |" >> $GITHUB_STEP_SUMMARY
echo "| **Version** | v${VERSION} |" >> $GITHUB_STEP_SUMMARY
echo "| **Commit** | [\`${GITHUB_SHA::7}\`](${{ github.server_url }}/${{ github.repository }}/commit/${GITHUB_SHA}) |" >> $GITHUB_STEP_SUMMARY
echo "| **Branch** | \`${{ github.ref_name }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **Runner** | \`${{ runner.os }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **Java** | ${{ env.JAVA_VERSION }} (${{ env.JAVA_DISTRIBUTION }}) |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Signing" >> $GITHUB_STEP_SUMMARY
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
if [ -n "$KEYSTORE_BASE64" ]; then
echo "| **Type** | Production (Configured Keystore) |" >> $GITHUB_STEP_SUMMARY
echo "| **Keystore** | Repository secret (\`KEYSTORE_BASE64\`) |" >> $GITHUB_STEP_SUMMARY
echo "| **Key Alias** | \`${{ secrets.KEY_ALIAS }}\` |" >> $GITHUB_STEP_SUMMARY
elif [ -n "$STEP_CA_URL" ]; then
echo "| **Type** | CA-Signed ([Step CA](https://smallstep.com/docs/step-ca/)) |" >> $GITHUB_STEP_SUMMARY
echo "| **CA URL** | \`$STEP_CA_URL\` |" >> $GITHUB_STEP_SUMMARY
echo "| **Provisioner** | \`$STEP_CA_JWK_PROVISIONER\` (JWK) |" >> $GITHUB_STEP_SUMMARY
echo "| **Algorithm** | RSA 2048-bit |" >> $GITHUB_STEP_SUMMARY
echo "| **Subject** | \`CN=Flock You Release,O=FlockYou,L=CI,ST=GitHub Actions,C=US\` |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "> **Note:** This APK is signed with a certificate issued by your Step CA using JWK provisioner authentication." >> $GITHUB_STEP_SUMMARY
else
echo "| **Type** | Ephemeral (Self-Signed Certificate) |" >> $GITHUB_STEP_SUMMARY
echo "| **Generated By** | [Smallstep CLI](https://smallstep.com/docs/step-cli/) |" >> $GITHUB_STEP_SUMMARY
echo "| **Algorithm** | RSA 2048-bit |" >> $GITHUB_STEP_SUMMARY
echo "| **Validity** | 1 year (ephemeral, CI-only) |" >> $GITHUB_STEP_SUMMARY
echo "| **Subject** | \`CN=Flock You Ephemeral,O=FlockYou,L=CI,ST=GitHub Actions,C=US\` |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "> **Note:** This APK is signed with an ephemeral self-signed certificate generated during CI." >> $GITHUB_STEP_SUMMARY
echo "> For production releases, configure one of:" >> $GITHUB_STEP_SUMMARY
echo "> - **Keystore:** \`KEYSTORE_BASE64\`, \`KEYSTORE_PASSWORD\`, \`KEY_ALIAS\`, \`KEY_PASSWORD\`" >> $GITHUB_STEP_SUMMARY
echo "> - **Step CA:** \`STEP_CA_URL\`, \`STEP_CA_ROOT_CRT\`/\`STEP_CA_FINGERPRINT\`, \`STEP_CA_JWK_PROVISIONER\`, \`STEP_CA_JWK_KEY\`" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Attestation" >> $GITHUB_STEP_SUMMARY
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| **Status** | Attested |" >> $GITHUB_STEP_SUMMARY
echo "| **Type** | [SLSA Build Provenance](https://slsa.dev/spec/v1.0/provenance) |" >> $GITHUB_STEP_SUMMARY
echo "| **Bundle** | [\`${{ steps.attest-release.outputs.bundle-path }}\`](${{ github.server_url }}/${{ github.repository }}/attestations) |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Artifacts" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
ls -lh app/build/outputs/apk/release-renamed/*.apk 2>/dev/null || echo "No APK found"
ls -lh app/build/outputs/apk/release-renamed/*.apk >> $GITHUB_STEP_SUMMARY 2>/dev/null || echo "No APK found" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Links" >> $GITHUB_STEP_SUMMARY
echo "- [Download Artifact](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
echo "- [View Attestations](${{ github.server_url }}/${{ github.repository }}/attestations)" >> $GITHUB_STEP_SUMMARY
echo "- [Workflow File](${{ github.server_url }}/${{ github.repository }}/blob/${{ github.sha }}/.github/workflows/android-ci.yml)" >> $GITHUB_STEP_SUMMARY
echo "- [Smallstep CLI Docs](https://smallstep.com/docs/step-cli/)" >> $GITHUB_STEP_SUMMARY
echo "- [SLSA Provenance Spec](https://slsa.dev/spec/v1.0/provenance)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Verify Attestation" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "# Download and verify the APK attestation" >> $GITHUB_STEP_SUMMARY
echo "gh attestation verify FlockYou-${{ matrix.flavor }}-v${VERSION}.apk --owner ${{ github.repository_owner }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "# View attestation details" >> $GITHUB_STEP_SUMMARY
echo "gh attestation verify FlockYou-${{ matrix.flavor }}-v${VERSION}.apk --owner ${{ github.repository_owner }} --format json | jq" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
- name: Cleanup sensitive files
if: always()
run: |
rm -f app/release-keystore.jks
rm -f app/ephemeral-keystore.p12
rm -f app/ca-signed-keystore.p12
rm -rf app/build/outputs/apk/release-renamed
# ===========================================
# Create GitHub Release
# ===========================================
release:
name: Create Release
runs-on: ubuntu-latest
needs: [build, build-release]
if: github.event_name == 'workflow_dispatch' && inputs.create_release == true
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download Release APKs
uses: actions/download-artifact@v4
with:
pattern: app-*-release
path: release-apk
merge-multiple: true
- name: Determine version
id: version
run: |
if [ -n "${{ inputs.release_version }}" ]; then
VERSION="${{ inputs.release_version }}"
else
VERSION="${{ needs.build.outputs.version_name }}"
fi
if [ -z "$VERSION" ]; then
VERSION="1.0.0"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "tag=v$VERSION" >> $GITHUB_OUTPUT
echo "Release version: $VERSION"
- name: Generate Release Notes
id: notes
run: |
VERSION="${{ steps.version.outputs.version }}"
# Start with custom notes if provided
if [ -n "${{ inputs.release_notes }}" ]; then
NOTES="${{ inputs.release_notes }}"
NOTES="$NOTES"$'\n\n'
else
NOTES=""
fi
# Add standard release info
NOTES="$NOTES## Flock You v$VERSION"$'\n\n'
NOTES="$NOTES### Features"$'\n'
NOTES="$NOTES- WiFi and Bluetooth LE surveillance device detection"$'\n'
NOTES="$NOTES- Flock Safety, Penguin, Pigvision, and Raven device detection"$'\n'
NOTES="$NOTES- Map view with detection locations"$'\n'
NOTES="$NOTES- Real-time alerts with vibration"$'\n'
NOTES="$NOTES- Detection history and filtering"$'\n\n'
NOTES="$NOTES### Installation"$'\n'
NOTES="$NOTES1. Download the APK file below"$'\n'
NOTES="$NOTES2. Enable \"Install from unknown sources\" in Android settings"$'\n'
NOTES="$NOTES3. Open the APK to install"$'\n\n'
NOTES="$NOTES### Requirements"$'\n'
NOTES="$NOTES- Android 8.0 (API 26) or higher"$'\n'
NOTES="$NOTES- Location permissions for scanning"$'\n'
NOTES="$NOTES- Bluetooth permissions for BLE detection"$'\n\n'
NOTES="$NOTES---"$'\n'
NOTES="$NOTES*Based on [colonelpanichacks/flock-you](https://github.com/colonelpanichacks/flock-you)*"
# Save to file to handle multiline
echo "$NOTES" > release_notes.md
echo "Generated release notes"
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.version.outputs.tag }}
name: "Flock You ${{ steps.version.outputs.tag }}"
body_path: release_notes.md
draft: false
prerelease: ${{ inputs.pre_release }}
files: |
release-apk/*.apk
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Release Summary
run: |
echo "## Release Created!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Version:** ${{ steps.version.outputs.tag }}" >> $GITHUB_STEP_SUMMARY
echo "**Pre-release:** ${{ inputs.pre_release }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Artifacts" >> $GITHUB_STEP_SUMMARY
ls -la release-apk/ >> $GITHUB_STEP_SUMMARY
# ===========================================
# Lint Job (runs in parallel)
# ===========================================
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK ${{ env.JAVA_VERSION }}
uses: actions/setup-java@v4
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: ${{ env.JAVA_DISTRIBUTION }}
cache: 'gradle'
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Run Lint
run: ./gradlew lint --stacktrace
continue-on-error: true
- name: Upload Lint Results
uses: actions/upload-artifact@v4
if: always()
with:
name: lint-results
path: app/build/reports/lint-results-*.html
retention-days: 7
# ===========================================
# Unit Tests - Matrix for all flavors
# ===========================================
test:
name: Unit Tests (${{ matrix.flavor }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
flavor: [oem, sideload, system]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK ${{ env.JAVA_VERSION }}
uses: actions/setup-java@v4
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: ${{ env.JAVA_DISTRIBUTION }}
cache: 'gradle'
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Run Unit Tests (${{ matrix.flavor }})
run: ./gradlew test${{ matrix.flavor }}DebugUnitTest --stacktrace
- name: Upload Test Results (${{ matrix.flavor }})
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results-${{ matrix.flavor }}
path: app/build/reports/tests/
retention-days: 7