ci: publish Android releases to Zapstore#426
Conversation
📝 WalkthroughWalkthroughA 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
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Comment |
Deploying maple with
|
| Latest commit: |
1aea642
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://e4cbff40.maple-ca8.pages.dev |
| Branch Preview URL: | https://zapstore.maple-ca8.pages.dev |
Greptile SummaryThis PR integrates Zapstore ( Key observations:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
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
Last reviewed commit: 1aea642 |
| permissions: | ||
| contents: read |
There was a problem hiding this 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:
- Changing permissions to
contents: write(if draft releases are expected), or - 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.There was a problem hiding this comment.
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.
| 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 |
There was a problem hiding this comment.
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.
9f51c98 to
1c7addf
Compare
There was a problem hiding this comment.
🤖 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.
1c7addf to
b6fc4c9
Compare
| 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 |
There was a problem hiding this 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
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>
b6fc4c9 to
1aea642
Compare
| - 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 |
There was a problem hiding this comment.
🔴 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:
- Move the Zapstore publish steps after the GitHub release upload steps, so the primary release is not blocked, or
- Add
continue-on-error: trueto 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.
Was this helpful? React with 👍 or 👎 to provide feedback.
| metadata_sources: | ||
| - github | ||
| - playstore |
There was a problem hiding this 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:
| 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.
Additional Comments (1)
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 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: Prompt To Fix With AIThis 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. |
There was a problem hiding this comment.
🧹 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:
- Adding
continue-on-error: trueto this step- Moving Zapstore steps after the GitHub release uploads
- Using an
ifcondition to skip when the secret isn't configuredIf 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.
|
closing in favor of #427 |
Adds Zapstore (zsp) publishing for Android release builds.
Releaseworkflow succeedsapp-universal-release.apkfrom the GitHub releasezsp publishwith--commit ${{ github.event.workflow_run.head_sha }}for reproducible builds (pinned commit)zapstore.yamlfor minimal app metadataSecrets:
ZAPSTORE_SIGN_WITH(required; set to yournsec1...or bunker URL)Summary by CodeRabbit