Skip to content

feat(qa-bundle-upload): add batch directory upload action#81

Open
originalix wants to merge 17 commits intoOneKeyHQ:mainfrom
originalix:feat/qa-bundle-upload
Open

feat(qa-bundle-upload): add batch directory upload action#81
originalix wants to merge 17 commits intoOneKeyHQ:mainfrom
originalix:feat/qa-bundle-upload

Conversation

@originalix
Copy link
Contributor

Summary

  • New qa-bundle-upload GitHub Action: scans a directory for *-bundle.zip files + .info metadata, then uploads each bundle to the Utility server via HMAC-signed multipart POST
  • Supports batch upload: one action call handles multiple platforms (e.g., android + ios from native CI, electron from desktop CI)
  • Reads appVersion, platform, sha256 from .info files automatically — no manual input needed
  • SHA256 cross-check between .info and computed hash ensures file integrity
  • Serial upload with exponential backoff retry (configurable max-retries)
  • Partial failure handling: continues uploading remaining bundles, reports all results

Test Plan

  • 14 unit tests passing (scanBundleDir, parseInfoFile, validateZipMagic, fixtures)
  • Verified against real native artifacts (android + ios SHA256 MATCH)
  • Verified against real desktop artifacts (found workflow JSON bug — separate fix needed)
  • End-to-end test in CI workflow after Utility server deployment

Note

release-desktop-bundle.yml in x-app-monorepo has a JSON syntax bug (missing comma in electron-bundle.json.info template, line 117). This needs a separate fix before the desktop workflow can use this action.

🤖 Generated with Claude Code

originalix and others added 12 commits March 3, 2026 09:53
…json

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move ZIP magic check from validateInputs to run() after readFileSync,
  eliminating FD leak risk if readSync throws
- Rebuild FormData inside retry loop to avoid stream reuse after consumption
- Recompute HMAC timestamp/signature per attempt to prevent stale signatures
- Add core.setSecret(secret) to mask upload secret in logs
- Add NaN guard for max-retries input

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SHA256 of the file buffer is constant across retries, so compute it
once in run() instead of inside the retry loop. Also restores the
SHA256 log line for debugging visibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace single-file mode with directory scanning approach that reads
.info metadata files automatically, enabling one action call to upload
multiple platform bundles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7-task plan covering action.yml update, test fixtures, scanBundleDir
and parseInfoFile implementation, dist build, and manual verification.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
C1: Validate server response has bundleVersion/downloadUrl before use
I1: Split try-catch in parseInfoFile to distinguish ENOENT from bad JSON
I3: Validate sha256 is a 64-char hex string
I4: Validate appVersion matches x.y.z format
I5: Only append commitHash to form when truthy

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@revan-zhang
Copy link
Collaborator

revan-zhang commented Mar 3, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 12d8b0c103

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

let hasFailure = false;

for (const bundle of bundles) {
const meta = parseInfoFile(bundle.infoPath);

Choose a reason for hiding this comment

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

P1 Badge Parse metadata inside per-bundle try block

parseInfoFile(bundle.infoPath) runs before the per-bundle try/catch, so a single malformed or incomplete .info file throws into the outer run() catch and aborts the whole loop. In that case, later valid bundles are never attempted and results is not emitted, which breaks the intended partial-failure behavior for batch uploads.

Useful? React with 👍 / 👎.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

core.info(`[${label}] Uploading ${path.basename(bundle.zipPath)} (${fileSizeMB} MB, v${meta.appVersion})...`);

const computedHash = crypto.createHash('sha256').update(fileBuffer).digest('hex');
if (computedHash !== meta.sha256) {

Choose a reason for hiding this comment

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

P2 Badge Normalize SHA256 before comparing with computed hash

The parser accepts uppercase hex hashes (/^[0-9a-f]{64}$/i), but this comparison is case-sensitive against computedHash, which is always lowercase. If a valid .info file contains an uppercase SHA256, this check will falsely report a mismatch and fail the upload; normalize meta.sha256 (or both sides) before equality comparison.

Useful? React with 👍 / 👎.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

originalix and others added 5 commits March 3, 2026 14:51
…rmalize sha256 case

Move parseInfoFile into per-bundle try/catch so a malformed .info file
skips only that bundle instead of aborting the entire loop. Normalize
sha256 to lowercase before comparison to avoid false mismatch on
uppercase hex hashes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add integration README covering inputs/outputs, bundle directory
structure, .info file format, HMAC upload protocol, retry behavior,
and server integration checklist. Update server-url example to
onekeytest.com and upload path to /utility/v1/app-update/bundles/upload.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tigation

Add diagnostic logging of request URL and headers (with signature truncated)
to help identify why Cloudflare WAF is blocking the upload request.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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