Skip to content

feat: add github action to release APK artifact#389

Merged
dewabisma merged 3 commits into
mainfrom
beast/release-apk-artifact
Feb 18, 2026
Merged

feat: add github action to release APK artifact#389
dewabisma merged 3 commits into
mainfrom
beast/release-apk-artifact

Conversation

@dewabisma

Copy link
Copy Markdown
Collaborator

Summary

I added github action to release APK artifact as downloadable. I have also added secrets variables needed in the workflow to the repo.

@dewabisma dewabisma requested a review from n13 February 18, 2026 07:12
@n13

n13 commented Feb 18, 2026

Copy link
Copy Markdown
Collaborator

Here's my review of PR #389: feat: add github action to release APK artifact.


Overview

This PR adds a new GitHub Actions workflow (create_wallet_android_build.yml) for building the Android APK and optionally creating a GitHub release. It's well-structured and follows the patterns from the existing create_miner_build.yml. Nice work overall -- here are the things I'd flag:


Issues

1. Secret injection directly in shell commands (Security)

Secrets are interpolated directly into run: commands via ${{ secrets.* }}. If a command fails, the expanded value can leak into logs. GitHub masks known secret values, but it's still best practice to pass them through environment variables:

# Current (risky)
- name: Create .env file
  run: echo "${{ secrets.MOBILE_APP_ENV }}" > mobile-app/.env

# Recommended
- name: Create .env file
  env:
    MOBILE_APP_ENV: ${{ secrets.MOBILE_APP_ENV }}
  run: echo "$MOBILE_APP_ENV" > mobile-app/.env

Same applies to GOOGLE_SERVICES_JSON, ANDROID_KEYSTORE_BASE64, and the key.properties secrets.

Note: The existing create_miner_build.yml handles secrets via env: for notarization -- would be good to follow that pattern here too.

2. No Rust/Cargo caching

The Rust toolchain is set up with 4 Android targets (aarch64, armv7, x86_64, i686), and quantus_sdk uses flutter_rust_bridge + cargokit which compiles Rust during the Flutter build. Without caching ~/.cargo and the Cargo target directory, this will be very slow on every run. Consider adding:

- name: Cache Cargo
  uses: actions/cache@v4
  with:
    path: |
      ~/.cargo/registry
      ~/.cargo/git
    key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
    restore-keys: ${{ runner.os }}-cargo-

3. Flutter version not pinned

- name: Set up Flutter
  uses: subosito/flutter-action@v2
  with:
    channel: "stable"
    cache: true

This uses whatever the latest stable Flutter version is at build time. Builds could break or behave differently when Flutter releases a new stable. Consider pinning a specific version (flutter-version: "3.x.x") for reproducibility. The miner workflow has the same issue, so this is a repo-wide concern.

4. Deprecated release actions

actions/create-release@v1 and actions/upload-release-asset@v1 are both archived/deprecated. They still work, but won't receive updates. The modern replacement is softprops/action-gh-release which combines both steps into one:

- name: Create Release
  uses: softprops/action-gh-release@v2
  with:
    tag_name: ${{ steps.get_version.outputs.tag }}
    name: Quantus Wallet ${{ steps.get_version.outputs.version }}
    files: ./artifacts/quantus_wallet_*.apk

Note: The miner workflow uses the same deprecated actions, so this is an existing pattern. Could be a follow-up improvement for both workflows.

5. DRY: Duplicate version reading

The "Read version from pubspec.yaml" step is duplicated across build-android and create-release jobs. You could pass the version as a job output from build-android:

build-android:
  outputs:
    version: ${{ steps.get_version.outputs.version }}
    tag: ${{ steps.get_version.outputs.tag }}

Then reference it in the release job as ${{ needs.build-android.outputs.version }}, eliminating the second checkout + grep.

6. contents: write permission is global

The contents: write permission is set at the workflow level, but only the create-release job needs write access (for tagging and creating releases). The build-android job only needs contents: read. Consider scoping permissions per-job for least-privilege:

jobs:
  build-android:
    permissions:
      contents: read
    ...
  create-release:
    permissions:
      contents: write
    ...

Minor Nits

  • The find ./artifacts -type f | sort step is purely for debugging -- consider removing it or guarding it behind a debug flag.
  • The release body says "See commit history for details" which isn't super helpful. Maybe auto-generate from commits since last tag, or at least link to the compare view.

What looks good

  • Clean workflow_dispatch with choice inputs for build mode and release toggle
  • Smart conditional: releases only allowed in release mode (inputs.create_release && inputs.build_mode == 'release')
  • Tag collision detection before pushing
  • APK renaming with version and mode in the filename
  • Proper use of melos bootstrap for the monorepo (vs the miner workflow's direct flutter pub get)

Verdict: Solid workflow that follows existing project patterns. The secret handling (#1) and missing Rust caching (#2) are the most impactful items to address before merge. The rest can be follow-ups.

@n13

n13 commented Feb 18, 2026

Copy link
Copy Markdown
Collaborator

Here's my review of PR #389: feat: add github action to release APK artifact.


Overview

This PR adds create_wallet_android_build.yml — a GitHub Actions workflow for building the Android wallet APK and optionally creating a GitHub release. It's a single new file, 176 lines, well-structured across two jobs: build-android and create-release.

The second commit (abec976) already addressed most of the initial review feedback from n13 — nice turnaround. Here's what's looking good and what I'd still flag.


What looks great

  • Secrets via env: block — all secrets are injected through job-level environment variables, not interpolated inline in run: commands. Clean and secure.
  • Per-job permissionscontents: read on build-android, contents: write only on create-release. Least-privilege, exactly right.
  • Version as job output — version is read once in build-android and passed via outputs to create-release, no duplication.
  • softprops/action-gh-release@v2 — uses the modern, maintained release action instead of the deprecated actions/create-release@v1. The miner workflow should be updated to match this pattern in a follow-up.
  • generate_release_notes: true — auto-generated changelog is much better than the static "See commit history" approach.
  • Cargo caching~/.cargo/registry and ~/.cargo/git are cached with proper key strategy.
  • Smart release guardinputs.create_release && inputs.build_mode == 'release' prevents accidental debug releases.
  • Tag collision detection — checks remote tags before pushing, with a clear error message.
  • Melos bootstrap — correct approach for the monorepo (vs the miner workflow's direct flutter pub get).

Issues to address

1. Missing newline at end of file

The diff ends with \ No newline at end of file. Should add a trailing newline — it's a POSIX convention and avoids noisy diffs when future lines are appended.

2. Flutter version not pinned

- name: Set up Flutter
  uses: subosito/flutter-action@v2
  with:
    channel: "stable"
    cache: true

This uses whatever stable happens to be at build time. A new Flutter stable release could break the build or change behavior silently. Pin it:

flutter-version: "3.29.2"  # or whatever you're developing against

This is a repo-wide issue (miner workflow too), but since this is a new workflow, it's a good opportunity to set the right precedent.

3. Cargo target directory not cached

The cache covers ~/.cargo/registry and ~/.cargo/git (dependency downloads), but the compiled Rust artifacts in the target directory aren't cached. For a cross-compilation build with 4 Android targets, this means recompiling everything from scratch each run. Consider adding the target dir:

- name: Cache Cargo
  uses: actions/cache@v4
  with:
    path: |
      ~/.cargo/registry
      ~/.cargo/git
      quantus_sdk/native/target
    key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
    restore-keys: |
      ${{ runner.os }}-cargo-

The target directory can be large, so weigh the cache storage cost against build time savings. At minimum, worth testing once to see the impact.

4. All signing secrets exposed to every step

The job-level env: block exposes keystore/signing secrets to all steps, including ones that don't need them (checkout, Flutter setup, melos bootstrap, etc.). For tighter least-privilege, move the signing secrets to only the steps that use them:

- name: Decode Android keystore
  if: inputs.build_mode == 'release'
  env:
    ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
  run: echo "$ANDROID_KEYSTORE_BASE64" | base64 --decode > mobile-app/android/app/upload-keystore.jks

- name: Create key.properties
  if: inputs.build_mode == 'release'
  env:
    ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }}
    ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
    ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
  run: |
    cat > mobile-app/android/key.properties << EOF
    storeFile=app/upload-keystore.jks
    storePassword=$ANDROID_STORE_PASSWORD
    keyAlias=$ANDROID_KEY_ALIAS
    keyPassword=$ANDROID_KEY_PASSWORD
    EOF

This is a "nice to have" — the current approach works and is simpler. But if a future step has a bug or runs untrusted code, scoped secrets reduce blast radius.


Minor nits

  • The miner workflow's create-release job still uses the deprecated actions/create-release@v1 and actions/upload-release-asset@v1. Now that this wallet workflow shows the modern pattern with softprops/action-gh-release@v2, consider a follow-up PR to align the miner workflow.
  • The release body includes manual installation instructions alongside generate_release_notes: true. The generated notes will appear after the body — might want to verify the final rendering looks clean and not redundant.

Verdict

Solid workflow that's already been improved from the first round of feedback. Items 1-2 (missing newline, unpinned Flutter) are quick fixes worth doing before merge. Items 3-4 (cargo target cache, scoped secrets) are optimizations that could be follow-ups. Good work!

@n13

n13 commented Feb 18, 2026

Copy link
Copy Markdown
Collaborator

I would recommend doing 1, 2, and 3

rust compilation takes forever, so caching is good - although might also run out of disk space we will see

Update: actually we always want to keep flutter to the latest, so yeah, not fixing flutter ... ;)

@n13 n13 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@dewabisma dewabisma merged commit 078e403 into main Feb 18, 2026
1 check passed
@dewabisma dewabisma deleted the beast/release-apk-artifact branch February 18, 2026 12:25
@dewabisma dewabisma restored the beast/release-apk-artifact branch February 18, 2026 13:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants