Skip to content

ci: publish Android releases to Zapstore#426

Closed
AnthonyRonning wants to merge 1 commit intomasterfrom
zapstore
Closed

ci: publish Android releases to Zapstore#426
AnthonyRonning wants to merge 1 commit intomasterfrom
zapstore

Conversation

@AnthonyRonning
Copy link
Contributor

@AnthonyRonning AnthonyRonning commented Feb 17, 2026

Adds Zapstore (zsp) publishing for Android release builds.

  • New workflow runs after the Release workflow succeeds
  • Downloads app-universal-release.apk from the GitHub release
  • Publishes via zsp publish with --commit ${{ github.event.workflow_run.head_sha }} for reproducible builds (pinned commit)
  • Adds zapstore.yaml for minimal app metadata

Secrets:

  • ZAPSTORE_SIGN_WITH (required; set to your nsec1... or bunker URL)

Open with Devin

Summary by CodeRabbit

  • Chores
    • Integrated Zapstore marketplace into the release pipeline, enabling app distribution through an additional platform with automated publishing and security verification.

@coderabbitai
Copy link

coderabbitai bot commented Feb 17, 2026

📝 Walkthrough

Walkthrough

A new Zapstore integration is added to the release pipeline, consisting of a manifest metadata file and GitHub Actions workflow steps that automate APK preparation and publishing to Zapstore during the Android release process.

Changes

Cohort / File(s) Summary
Zapstore Configuration
zapstore.yaml
New manifest file defining repository metadata for Maple, including name, description, website, license (MIT), tags, icon path, and metadata sources.
Release Workflow
.github/workflows/release.yml
Additions to the Android release pipeline: installs Zapstore CLI, prepares and publishes APK to Zapstore with secret-guarded authentication, and publishes zapstore.yaml manifest with commit SHA reference.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

🐰✨ A zippy new store awaits our app so fine,
Zapstore manifest and workflows align,
With secrets and CLI, the Android path glows,
Publishing magic wherever it flows! 📱🚀

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding CI/CD workflow for publishing Android releases to Zapstore, which is the primary objective of this PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch zapstore

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Feb 17, 2026

Deploying maple with  Cloudflare Pages  Cloudflare Pages

Latest commit: 1aea642
Status: ✅  Deploy successful!
Preview URL: https://e4cbff40.maple-ca8.pages.dev
Branch Preview URL: https://zapstore.maple-ca8.pages.dev

View logs

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 17, 2026

Greptile Summary

This PR integrates Zapstore (zsp) publishing into the existing build-android CI job within release.yml, and adds a zapstore.yaml metadata file. After the Android APK is built and signed, the workflow installs Go, fetches zsp@v0.3.3, and calls zsp publish with the HEAD commit SHA for reproducible-build traceability.

Key observations:

  • Step ordering risk: The Zapstore publish steps are inserted before the "Upload Android APK to Release" and "Upload Android AAB to Release" steps. A failure at the zsp publish step (e.g., missing secret, network error, tool bug) will abort the sequential job via set -euo pipefail and prevent the APK/AAB from reaching the GitHub release — the primary distribution channel. The Zapstore steps should be reordered to run after the GitHub release uploads.
  • SIGN_WITH env var: The SIGN_WITH environment variable is set correctly for the step; based on zsp's documented behavior it reads this env var automatically, so no --sign-with flag is needed in the command — this appears intentional.
  • playstore metadata source: zapstore.yaml lists playstore as a metadata source, but there is no confirmed Play Store listing for cloud.opensecret.maple. If the app is absent from the Play Store, this source may cause zsp to emit warnings or errors during publish.
  • Icon path: ./frontend/src-tauri/icons/icon.png exists in the repository and resolves correctly from the workspace root.

Confidence Score: 3/5

  • Mergeable, but the step ordering issue means a Zapstore failure can prevent the Android APK from reaching the GitHub release.
  • The core Android build and signing logic is untouched and sound. The new Zapstore steps are straightforward, but placing them before the GitHub release upload creates a blocking dependency — any transient Zapstore error will cause the GitHub release to be missing its Android artifacts. This is a meaningful regression risk for the primary distribution channel and warrants fixing before merging.
  • .github/workflows/release.yml — specifically the ordering of the Zapstore publish steps relative to the GitHub release upload steps.

Important Files Changed

Filename Overview
.github/workflows/release.yml Adds Go/zsp installation, APK copy, and Zapstore publish steps to build-android job — placed before the GitHub release APK upload, meaning a Zapstore failure blocks the GitHub release from receiving the APK.
zapstore.yaml New Zapstore metadata config with correct repo URL, icon path, tags, and metadata sources; minor concern is the playstore metadata source may not resolve if the app isn't available on Play Store.

Sequence Diagram

sequenceDiagram
    participant GH as GitHub Release Trigger
    participant BA as build-android job
    participant ZSP as Zapstore (zsp)
    participant GHR as GitHub Release

    GH->>BA: on release created
    BA->>BA: Build Android APK (cargo tauri android build)
    BA->>BA: Setup Go & install zsp
    BA->>BA: Copy APK to ./app-universal-release.apk
    BA->>ZSP: zsp publish --commit sha zapstore.yaml
    note over BA,ZSP: ⚠️ If this fails, APK upload to GitHub is skipped
    ZSP-->>BA: publish success/failure
    BA->>GHR: gh release upload app-universal-release.apk
    BA->>GHR: gh release upload app-universal-release.aab
Loading

Last reviewed commit: 1aea642

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 8 to 9
permissions:
contents: read
Copy link
Contributor

Choose a reason for hiding this comment

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

Draft release access may fail

The Release workflow's tauri-action uses releaseDraft: true, which can result in the GitHub release being in a draft state when this workflow runs. The gh release download step (line 45) uses github.token with only contents: read permission, but the GitHub API requires contents: write to access draft releases. If the release is still a draft when this workflow triggers, the download step will fail with a 404.

Consider either:

  1. Changing permissions to contents: write (if draft releases are expected), or
  2. Confirming that releases are always published (non-draft) before the Release workflow completes
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/zapstore-publish.yml
Line: 8:9

Comment:
**Draft release access may fail**

The Release workflow's `tauri-action` uses `releaseDraft: true`, which can result in the GitHub release being in a draft state when this workflow runs. The `gh release download` step (line 45) uses `github.token` with only `contents: read` permission, but the GitHub API requires `contents: write` to access draft releases. If the release is still a draft when this workflow triggers, the download step will fail with a 404.

Consider either:
1. Changing permissions to `contents: write` (if draft releases are expected), or
2. Confirming that releases are always published (non-draft) before the Release workflow completes

How can I resolve this? If you propose a fix, please make it concise.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/zapstore-publish.yml:
- Around line 1-23: The workflow's publish job uses workflow_run without
verifying origin; update the publish job (job name "publish") to harden its
gating by checking that github.event.workflow_run.head_repository.full_name (or
head_repository.owner.login == github.repository_owner) matches
github.repository and that github.event.workflow_run.event == 'push' (or another
trusted event) before running the Checkout step, and include this guard in the
job's if conditional (the existing if: github.event.workflow_run.conclusion ==
'success') so the job only runs for same-repo, trusted event workflow_runs and
avoids untrusted checkouts.

Comment on lines 1 to 23
name: Publish Android to Zapstore

on:
workflow_run:
workflows: ["Release"]
types: [completed]

permissions:
contents: read

jobs:
publish:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
env:
ZSP_VERSION: v0.3.3

steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Harden workflow_run gating to avoid untrusted checkouts.

workflow_run executes in the base repo context; if the upstream workflow ever runs on untrusted refs, this checkout can expose secrets or publish tampered metadata. Add a guard to ensure the run originates from the same repo and a trusted event type (e.g., push).

🔒 Proposed guard on the job
-    if: ${{ github.event.workflow_run.conclusion == 'success' }}
+    if: >
+      github.event.workflow_run.conclusion == 'success' &&
+      github.event.workflow_run.head_repository.full_name == github.repository &&
+      github.event.workflow_run.event == 'push'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/zapstore-publish.yml around lines 1 - 23, The workflow's
publish job uses workflow_run without verifying origin; update the publish job
(job name "publish") to harden its gating by checking that
github.event.workflow_run.head_repository.full_name (or
head_repository.owner.login == github.repository_owner) matches
github.repository and that github.event.workflow_run.event == 'push' (or another
trusted event) before running the Checkout step, and include this guard in the
job's if conditional (the existing if: github.event.workflow_run.conclusion ==
'success') so the job only runs for same-repo, trusted event workflow_runs and
avoids untrusted checkouts.

greptile-apps[bot]

This comment was marked as resolved.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In @.github/workflows/zapstore-publish.yml:
- Around line 12-23: The publish job's gating is too permissive; update the
job-level if to ensure the triggering workflow run is from the same repo and a
trusted event type. Change the publish job's if to combine the existing success
check with comparisons like github.event.workflow_run.head_repository.full_name
== github.repository and github.event.workflow_run.event in
('push','workflow_dispatch') (or whichever trusted events you choose), so the
publish job (publish) and the Checkout step only run for same-repo, trusted
workflow_run triggers.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 64 to 79
env:
SIGN_WITH: ${{ secrets.ZAPSTORE_SIGN_WITH }}
shell: bash
run: |
set -euo pipefail

if [ -z "${SIGN_WITH}" ]; then
echo "Missing required secret: ZAPSTORE_SIGN_WITH" >&2
exit 1
fi

zsp publish \
-y \
--skip-preview \
--commit "${{ github.event.workflow_run.head_sha }}" \
zapstore.yaml
Copy link
Contributor

Choose a reason for hiding this comment

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

SIGN_WITH env var is validated but never passed to zsp publish - verify that zsp automatically reads this env var, otherwise signing will fail

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/zapstore-publish.yml
Line: 64:79

Comment:
`SIGN_WITH` env var is validated but never passed to `zsp publish` - verify that `zsp` automatically reads this env var, otherwise signing will fail

How can I resolve this? If you propose a fix, please make it concise.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment on lines +350 to +366
- name: Publish to Zapstore
env:
SIGN_WITH: ${{ secrets.ZAPSTORE_SIGN_WITH }}
shell: bash
run: |
set -euo pipefail

if [ -z "${SIGN_WITH}" ]; then
echo "Missing required secret: ZAPSTORE_SIGN_WITH" >&2
exit 1
fi

zsp publish \
-y \
--skip-preview \
--commit "${{ github.sha }}" \
zapstore.yaml
Copy link
Contributor

Choose a reason for hiding this comment

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

🔴 Zapstore publish step blocks GitHub release uploads on failure

The "Publish to Zapstore" step (line 350) runs before the "Upload Android APK to Release" (line 368) and "Upload Android AAB to Release" (line 376) steps. Since there is no continue-on-error: true on the Zapstore step, if zsp publish fails for any reason (network issues with Zapstore relays, invalid secret, tool bugs, etc.), the job will abort and the APK/AAB will never be uploaded to the GitHub release.

Impact and Suggested Fix

This means a failure in an optional third-party distribution channel (Zapstore) would prevent the primary release artifacts (APK and AAB) from being published to GitHub Releases, breaking the entire Android release pipeline.

The fix is either:

  1. Move the Zapstore publish steps after the GitHub release upload steps, so the primary release is not blocked, or
  2. Add continue-on-error: true to the Zapstore publish step so failures don't block subsequent steps.

Option 1 is preferred since it ensures the core release always completes first.

Prompt for agents
In .github/workflows/release.yml, move the four new steps ("Setup Go (zsp)" at line 331, "Install zsp" at line 337, "Prepare APK for Zapstore" at line 344, and "Publish to Zapstore" at line 350) to AFTER the existing "Upload Android AAB to Release" step (which ends around line 382). This ensures that the primary GitHub release upload of APK and AAB artifacts always completes before attempting the optional Zapstore publish. Alternatively, add `continue-on-error: true` to the "Publish to Zapstore" step so that a Zapstore failure does not block the GitHub release uploads.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +24 to +26
metadata_sources:
- github
- playstore
Copy link
Contributor

Choose a reason for hiding this comment

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

playstore metadata source may silently fail

playstore is listed as a metadata_source, but the app (cloud.opensecret.maple) does not appear to have a public Play Store listing. If zsp fails to resolve Play Store metadata, it may either error out or silently fall back, producing incomplete or inconsistent release metadata.

If the app is not on the Play Store, consider removing playstore from metadata_sources to avoid unexpected behaviour:

Suggested change
metadata_sources:
- github
- playstore
metadata_sources:
- github
Prompt To Fix With AI
This is a comment left during a code review.
Path: zapstore.yaml
Line: 24:26

Comment:
**`playstore` metadata source may silently fail**

`playstore` is listed as a `metadata_source`, but the app (`cloud.opensecret.maple`) does not appear to have a public Play Store listing. If `zsp` fails to resolve Play Store metadata, it may either error out or silently fall back, producing incomplete or inconsistent release metadata.

If the app is not on the Play Store, consider removing `playstore` from `metadata_sources` to avoid unexpected behaviour:

```suggestion
metadata_sources:
  - github
```

How can I resolve this? If you propose a fix, please make it concise.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 17, 2026

Additional Comments (1)

.github/workflows/release.yml
Zapstore publish step blocks GitHub release APK upload

The "Publish to Zapstore" step (line 350) is placed before the "Upload Android APK to Release" step (line 368). Because this job runs sequentially with set -euo pipefail, any failure in the Zapstore publish step — including a missing ZAPSTORE_SIGN_WITH secret, a network error contacting Zapstore relays, or a zsp bug — will abort the job before the APK and AAB are uploaded to the GitHub release.

This means the GitHub release could be missing its Android artifacts whenever Zapstore publishing encounters a problem, even if the APK itself built successfully.

Consider moving the Zapstore publish steps to after the GitHub release uploads, so the GitHub release is never blocked by a Zapstore failure:

- name: Upload Android APK to Release   # move to before Zapstore steps
- name: Upload Android AAB to Release   # move to before Zapstore steps
- name: Setup Go (zsp)
- name: Install zsp
- name: Prepare APK for Zapstore
- name: Publish to Zapstore
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/release.yml
Line: 350:376

Comment:
**Zapstore publish step blocks GitHub release APK upload**

The "Publish to Zapstore" step (line 350) is placed **before** the "Upload Android APK to Release" step (line 368). Because this job runs sequentially with `set -euo pipefail`, any failure in the Zapstore publish step — including a missing `ZAPSTORE_SIGN_WITH` secret, a network error contacting Zapstore relays, or a `zsp` bug — will abort the job before the APK and AAB are uploaded to the GitHub release.

This means the GitHub release could be missing its Android artifacts whenever Zapstore publishing encounters a problem, even if the APK itself built successfully.

Consider moving the Zapstore publish steps to *after* the GitHub release uploads, so the GitHub release is never blocked by a Zapstore failure:

```
- name: Upload Android APK to Release   # move to before Zapstore steps
- name: Upload Android AAB to Release   # move to before Zapstore steps
- name: Setup Go (zsp)
- name: Install zsp
- name: Prepare APK for Zapstore
- name: Publish to Zapstore
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
.github/workflows/release.yml (1)

350-366: Consider making Zapstore publishing non-blocking.

The secret validation and publish command look correct. However, this step runs before the GitHub release upload (lines 368-382), meaning a Zapstore failure would prevent the APK from being uploaded to the GitHub release.

If Zapstore publishing is optional or should not block the primary release flow, consider either:

  1. Adding continue-on-error: true to this step
  2. Moving Zapstore steps after the GitHub release uploads
  3. Using an if condition to skip when the secret isn't configured

If blocking on Zapstore failure is intentional, the current implementation is fine.

💡 Option: Make Zapstore non-blocking
       - name: Publish to Zapstore
+        continue-on-error: true
         env:
           SIGN_WITH: ${{ secrets.ZAPSTORE_SIGN_WITH }}
+        if: ${{ secrets.ZAPSTORE_SIGN_WITH != '' }}
         shell: bash
         run: |
           set -euo pipefail
 
           if [ -z "${SIGN_WITH}" ]; then
             echo "Missing required secret: ZAPSTORE_SIGN_WITH" >&2
             exit 1
           fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release.yml around lines 350 - 366, The "Publish to
Zapstore" job step (env var SIGN_WITH / secret ZAPSTORE_SIGN_WITH and command
zsp publish using zapstore.yaml) currently runs before the GitHub release upload
and will block the release if it fails; to fix, make the Zapstore step
non-blocking by either adding continue-on-error: true to the "Publish to
Zapstore" step, or move this step to run after the GitHub release upload steps,
or add an if condition that skips the step when the ZAPSTORE_SIGN_WITH secret is
not set (e.g., guard on secrets.ZAPSTORE_SIGN_WITH) so the zsp publish command
does not prevent APK upload.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.github/workflows/release.yml:
- Around line 350-366: The "Publish to Zapstore" job step (env var SIGN_WITH /
secret ZAPSTORE_SIGN_WITH and command zsp publish using zapstore.yaml) currently
runs before the GitHub release upload and will block the release if it fails; to
fix, make the Zapstore step non-blocking by either adding continue-on-error:
true to the "Publish to Zapstore" step, or move this step to run after the
GitHub release upload steps, or add an if condition that skips the step when the
ZAPSTORE_SIGN_WITH secret is not set (e.g., guard on secrets.ZAPSTORE_SIGN_WITH)
so the zsp publish command does not prevent APK upload.

@AnthonyRonning
Copy link
Contributor Author

closing in favor of #427

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.

1 participant