Skip to content

fix(cli): stabilize native checksums and cover @capacitor/ios + @capacitor/android#2575

Open
riderx wants to merge 5 commits into
mainfrom
fix/native-platform-checksum-stability
Open

fix(cli): stabilize native checksums and cover @capacitor/ios + @capacitor/android#2575
riderx wants to merge 5 commits into
mainfrom
fix/native-platform-checksum-stability

Conversation

@riderx

@riderx riderx commented Jun 23, 2026

Copy link
Copy Markdown
Member

Summary (AI generated)

  • Extract native checksum logic into cli/src/native-checksum.ts with cross-OS normalization (LF line endings, POSIX relative paths).
  • Scan @capacitor/ios (Capacitor/, CapacitorCordova/) and @capacitor/android (capacitor/) layouts so platform packages get real ios_checksum / android_checksum values.
  • Use case-sensitive directory matching so lowercase capacitor/ is not treated as Capacitor/ on case-insensitive filesystems.
  • Add CLI fixtures/tests for LF vs CRLF stability and backend tests confirming same-semver checksum drift remains incompatible.

Motivation (AI generated)

Compatibility events were false-positive for users uploading consecutive OTA bundles with identical plugin versions because checksums differed across OS/environments while @capacitor/android / @capacitor/ios were skipped entirely. This aligns platform packages with plugin checksum behavior and makes hashing stable across macOS/Windows uploads.

Business Impact (AI generated)

Reduces noisy "native build required" compatibility warnings for customers shipping web-only OTA updates, while keeping checksum-based detection when native code actually changes (checksum remains the source of truth over semver).

Test Plan (AI generated)

  • cd cli && bun run lint
  • cd cli && bun run build
  • cd cli && bun run test:native-checksum
  • bun test tests/backend-bundle-compatibility.unit.test.ts
  • Upload two bundles from macOS and Windows CI with identical lockfile; verify plugin checksums match and no false compatibility event

Generated with AI

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Added native dependency checksum calculation for iOS and Android to improve build-cache accuracy.
    • Added a dedicated native-checksum test script to the CLI test pipeline.
  • Bug Fixes

    • Standardized dashboard/console link URLs across onboarding, 2FA “regain access” messaging, and security policy expiration messages.
  • Tests

    • Expanded native checksum coverage with fixtures and validation of normalization and platform detection.
  • Refactor

    • Centralized console URL generation and reused it throughout the CLI flows.

riderx and others added 2 commits June 23, 2026 18:38
Build onboarding and account-help messages pointed at capgo.app or
web.capgo.app instead of the console host. Route them through a shared
consoleWebUrl helper and align tests/goldens.

Co-authored-by: Cursor <cursoragent@cursor.com>
Hash @capacitor/ios and @capacitor/android native layouts, normalize LF
line endings and path separators for cross-OS stability, and add tests
proving checksum drift still flags incompatibility when semver matches.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 008f1b2c-fbd5-46f5-9fc4-799bced6dd12

📥 Commits

Reviewing files that changed from the base of the PR and between 291c7be and fd5f50f.

📒 Files selected for processing (4)
  • cli/src/native-checksum.ts
  • cli/test/fixtures/native-checksum/plugin-config-only/ConfigOnly.podspec
  • cli/test/fixtures/native-checksum/plugin-config-only/android/build.gradle
  • cli/test/test-native-checksum.mjs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)

📝 Walkthrough

Walkthrough

Adds a new native-checksum.ts module implementing deterministic iOS/Android native dependency checksum computation with CRLF normalization, extracted from utils.ts. Introduces a consoleWebUrl helper centralizing console URL construction, replacing hardcoded web.capgo.app/capgo.app strings across CLI modules. Adds corresponding test fixtures, a standalone test runner, and updates backend unit tests and test expectations.

Changes

Native Checksum Module Extraction

Layer / File(s) Summary
native-checksum.ts core implementation
cli/src/native-checksum.ts
Defines exported regexes for plugin vs platform native source layouts, constants for excluded directory names, iOS/Android alternate scan roots, and file extensions requiring line-ending normalization. Implements recursive directory traversal, platform scan-root resolution, iOS/Android config-file collection (.podspec, Package.swift, build.gradle/build.gradle.kts), dependencyHasNativeFiles, and calculatePlatformChecksums with CRLF→LF normalization and concurrent SHA-256 hashing per platform.
utils.ts wiring
cli/src/utils.ts
Imports calculatePlatformChecksums and dependencyHasNativeFiles from ./native-checksum, removes the in-file nativeFileRegex constant and all inline directory-walking/checksum code (~130 lines deleted), and switches getLocalDependencies to use the imported dependencyHasNativeFiles helper.
Test fixtures
cli/test/fixtures/native-checksum/...
Adds native source files (.swift, .java, .h, .m, .kt), Gradle build scripts with android config blocks, and podspec stubs across six fixture directories: plugin-lf, plugin-crlf, plugin-changed, capacitor-ios, capacitor-android, and plugin-config-only.
Test suite, backend tests, and script registration
cli/test/test-native-checksum.mjs, tests/backend-bundle-compatibility.unit.test.ts, cli/package.json
test-native-checksum.mjs covers content normalization (LF vs CRLF), path canonicalization, platform-specific checksum expectations, dependencyHasNativeFiles detection, getNativeScanRoots alternate-root discovery, case-sensitivity rules, and an end-to-end compareNativePackages compatibility assertion. Two backend unit tests verify that checksum changes for @capacitor/android and @capacitor/ios are marked incompatible even when versions match. test:native-checksum script added to package.json and wired into the aggregate test command.

Console URL Centralization

Layer / File(s) Summary
consoleWebUrl helper and URL replacements
cli/src/utils.ts, cli/src/init/command.ts, cli/src/organization/list.ts, cli/src/build/onboarding/mcp/engine.ts, cli/src/build/onboarding/tail/flow.ts, cli/src/utils/security_policy_errors.ts
Adds exported consoleWebUrl(path = '') helper to utils.ts that constructs console URLs from defaultHostWeb. Imports and uses it across all modules that previously embedded hardcoded https://web.capgo.app/... or https://capgo.app/... strings for 2FA account-settings links, build tracking URLs, and API key management URLs.
Test and fixture updates
cli/test/helpers/onboarding-fixtures.mjs, cli/test/test-android-tail-*.mjs, cli/test/test-ios-*.mjs, cli/test/test-frame-fit-android-shared.mjs, cli/test/test-tail-engine-shared.mjs, private/cli-mcp-tests
Updates fixture buildUrl values and expected rendered URL strings from capgo.app to console.capgo.app across onboarding, Android tail (engine, render, routing), iOS tail (handoff, TUI render), frame-fit, and tail-engine-shared tests. Bumps private/cli-mcp-tests submodule commit pointer to include test updates.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Cap-go/capgo#2408: Exposes compareNativePackages/bundle compatibility via dashboard alert — the same compareNativePackages function is exercised by the new end-to-end compatibility test added in this PR.
  • Cap-go/capgo#2523: Enhances the native-dependency compatibility-diff pipeline with requested_version metadata and checksum-only diagnostic reasons — directly extends the same native checksum detection infrastructure being refactored here.
  • Cap-go/capgo#2574: Parallel refactor of the same onboarding URL construction patterns; both introduce/use consoleWebUrl() to replace hardcoded capgo.app/web.capgo.app links across overlapping CLI modules.

Suggested reviewers

  • WcaleNieWolny
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description is comprehensive with Summary, Motivation, Business Impact, and Test Plan sections. However, the provided description template requires explicit sections (Summary, Test plan, Screenshots, Checklist) to be filled in the standard format. While substantive content is provided via AI-generated summaries, consider following the repository's standard description template structure more explicitly with clearly labeled sections and completed checklist items.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the main objective: stabilizing native checksums and extending coverage to @capacitor/ios and @capacitor/android platform packages.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

Comment thread cli/src/native-checksum.ts
@cursor cursor Bot requested a review from WcaleNieWolny June 23, 2026 17:20

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale comment

Risk: medium. Cursor Bugbot finished with status "skipping" and no Bugbot review comment was posted, so I cannot approve. Human review is needed for this CLI native-checksum behavior change.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Approver External

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale comment

Risk: medium. Not approving: Cursor Bugbot skipped and reported one unresolved high-severity finding (native-checksum module unused). Human review is needed before merge.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Approver

@codspeed-hq

codspeed-hq Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 43 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing fix/native-platform-checksum-stability (fd5f50f) with main (d79d1e2)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

…bump

Complete utils.ts integration, register native-checksum tests in CI, add
backend platform-package coverage, and restore private/cli-mcp-tests to main
to fix the TUI preview workflow failure.

Co-authored-by: Cursor <cursoragent@cursor.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale comment

Risk: medium. Not approving: Cursor Bugbot passed on the latest commit but no BUGBOT_REVIEW comment was posted for it, so the automated approval signal is incomplete. WcaleNieWolny is already requested for human review.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Approver

@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

🧪 Builder onboarding TUI preview — ✅ passed

▶ Open the interactive HTML report (zoomable journey tree + cast playback)

Commit: fd5f50f · Job summary with the result table

Co-authored-by: Cursor <cursoragent@cursor.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale comment

Risk: medium. Not approving: Cursor Bugbot passed on the latest commit but no BUGBOT_REVIEW comment was posted for it, so the automated approval signal is incomplete. WcaleNieWolny is already requested for human review.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Approver

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cli/src/native-checksum.ts`:
- Around line 186-191: The `dependencyHasNativeFiles` function currently only
checks for native source files via `collectNativeFilesFromRoots` for iOS and
Android roots, but it should also detect platform configuration-only files like
`.podspec`, `Package.swift`, and `build.gradle(.kts)`. Extend the function to
return true not only when actual native files exist but also when platform
config files are present in the dependency folder, ensuring that config-only
native packages are properly detected and included in the native hashing
process.
- Around line 205-210: The hash inputs in the loop lack frame boundaries and
have ordering issues. First, add delimiters or length-prefixing around the
hash.update calls for relativePath and the result of
normalizeNativeFileContentForChecksum to prevent ambiguous concatenation of
inputs. Second, move the hash.update call for relativePath after the
readFileSync call succeeds, so that unreadable files do not contribute to the
digest. Restructure the code within the try block so that the relativePath is
only hashed after the file content has been successfully read via readFileSync.

In `@private/cli-mcp-tests`:
- Line 1: The private/cli-mcp-tests submodule references an inaccessible
repository at https://github.com/Cap-go/cli-mcp-tests.git, which will cause git
clone and CI to fail. Update the .gitmodules file to correct the submodule URL
to point to an accessible repository location, or if the repository should
remain at that URL, ensure the repository is created or made accessible and that
the commit 66665b74dcab2024e05389ce29511363693780fd is pushed and available.
Verify the corrected URL by running git submodule update --init to confirm the
submodule can be properly cloned.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 352e581f-20ad-4017-b77f-88bfa30f77f8

📥 Commits

Reviewing files that changed from the base of the PR and between 647bf87 and 291c7be.

📒 Files selected for processing (36)
  • cli/package.json
  • cli/src/build/onboarding/mcp/engine.ts
  • cli/src/build/onboarding/tail/flow.ts
  • cli/src/init/command.ts
  • cli/src/native-checksum.ts
  • cli/src/organization/list.ts
  • cli/src/utils.ts
  • cli/src/utils/security_policy_errors.ts
  • cli/test/fixtures/native-checksum/capacitor-android/capacitor/build.gradle
  • cli/test/fixtures/native-checksum/capacitor-android/capacitor/src/main/java/com/getcapacitor/Bridge.java
  • cli/test/fixtures/native-checksum/capacitor-ios/Capacitor.podspec
  • cli/test/fixtures/native-checksum/capacitor-ios/Capacitor/Capacitor/CAPBridge.h
  • cli/test/fixtures/native-checksum/capacitor-ios/Capacitor/Capacitor/CAPBridge.m
  • cli/test/fixtures/native-checksum/capacitor-ios/Capacitor/Capacitor/CAPBridge.swift
  • cli/test/fixtures/native-checksum/plugin-changed/android/build.gradle
  • cli/test/fixtures/native-checksum/plugin-changed/android/src/main/java/com/example/Example.java
  • cli/test/fixtures/native-checksum/plugin-changed/ios/Sources/Plugin/AppPlugin.swift
  • cli/test/fixtures/native-checksum/plugin-crlf/CapacitorApp.podspec
  • cli/test/fixtures/native-checksum/plugin-crlf/android/build.gradle
  • cli/test/fixtures/native-checksum/plugin-crlf/android/src/main/java/com/example/Example.java
  • cli/test/fixtures/native-checksum/plugin-crlf/ios/Sources/Plugin/AppPlugin.swift
  • cli/test/fixtures/native-checksum/plugin-lf/CapacitorApp.podspec
  • cli/test/fixtures/native-checksum/plugin-lf/android/build.gradle
  • cli/test/fixtures/native-checksum/plugin-lf/android/src/main/java/com/example/Example.java
  • cli/test/fixtures/native-checksum/plugin-lf/ios/Sources/Plugin/AppPlugin.swift
  • cli/test/helpers/onboarding-fixtures.mjs
  • cli/test/test-android-tail-engine.mjs
  • cli/test/test-android-tail-render.mjs
  • cli/test/test-android-tail-routing.mjs
  • cli/test/test-frame-fit-android-shared.mjs
  • cli/test/test-ios-tail-handoff.mjs
  • cli/test/test-ios-tui-render.mjs
  • cli/test/test-native-checksum.mjs
  • cli/test/test-tail-engine-shared.mjs
  • private/cli-mcp-tests
  • tests/backend-bundle-compatibility.unit.test.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)

Comment thread cli/src/native-checksum.ts
Comment thread cli/src/native-checksum.ts Outdated
Comment thread private/cli-mcp-tests
@@ -1 +1 @@
Subproject commit a600cbc2dfa62337b05bebfb72e86272d7709039
Subproject commit 66665b74dcab2024e05389ce29511363693780fd

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Resolve the submodule URL and verify the pinned commit exists on the remote.
set -e

# Locate the submodule path/URL from .gitmodules
git config -f .gitmodules --get-regexp 'submodule\..*\.(path|url)' || true

SUBMODULE_PATH="private/cli-mcp-tests"
PIN="66665b74dcab2024e05389ce29511363693780fd"

URL=$(git config -f .gitmodules --get "submodule.${SUBMODULE_PATH}.url" || \
      git config -f .gitmodules --get-regexp 'submodule\..*\.url' | awk -v p="$SUBMODULE_PATH" '$0 ~ p {print $2}' | head -n1)

echo "Submodule URL: ${URL:-<not found>}"

if [ -n "$URL" ]; then
  # Check whether the pinned SHA is advertised/reachable on the remote.
  git ls-remote "$URL" | grep -i "$PIN" || echo "Pinned commit not directly advertised as a ref tip (may still be reachable via a branch history)."
fi

Repository: Cap-go/capgo

Length of output: 551


Submodule repository is not accessible; this will break clones and CI.

The private/cli-mcp-tests submodule points to https://github.com/Cap-go/cli-mcp-tests.git, but that repository is not found or is inaccessible. Any attempt to run git submodule update --init will fail with fatal: repository not found. This must be resolved before merging:

  • Confirm the repository URL is correct.
  • If the repository was deleted or made private, update the submodule URL in .gitmodules.
  • If the repository should exist, ensure it is created and the commit 66665b74dcab2024e05389ce29511363693780fd is pushed and accessible.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@private/cli-mcp-tests` at line 1, The private/cli-mcp-tests submodule
references an inaccessible repository at
https://github.com/Cap-go/cli-mcp-tests.git, which will cause git clone and CI
to fail. Update the .gitmodules file to correct the submodule URL to point to an
accessible repository location, or if the repository should remain at that URL,
ensure the repository is created or made accessible and that the commit
66665b74dcab2024e05389ce29511363693780fd is pushed and available. Verify the
corrected URL by running git submodule update --init to confirm the submodule
can be properly cloned.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Risk: medium. Not approving: Cursor Bugbot passed on the latest commit but no BUGBOT_REVIEW comment was posted, and this CLI native-checksum refactor exceeds the low-risk approval threshold. WcaleNieWolny is already requested for human review.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Approver External

Include config-only packages in native detection, length-prefix hash
inputs for unambiguous digests, and add docstrings plus a config-only
fixture test.

Co-authored-by: Cursor <cursoragent@cursor.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit fd5f50f. Configure here.

const roots = getNativeScanRoots(dependencyFolderPath, platform)
const nativeFiles = collectNativeFilesFromRoots(roots)
const configFiles = getPlatformConfigFiles(dependencyFolderPath, platform)
const allFiles = [...new Set([...nativeFiles, ...configFiles])].sort((a, b) => a.localeCompare(b))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Absolute path sort breaks checksums

High Severity

calculatePlatformChecksums orders files with localeCompare on absolute paths before hashing, while hashed entries use POSIX paths from the dependency root. When both Capacitor/ and CapacitorCordova/ contribute files (e.g. @capacitor/ios), macOS and Windows can sort those trees differently, producing different iOS checksums for identical native content and reviving cross-OS compatibility drift.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit fd5f50f. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Risk: medium. Not approving: Cursor Bugbot finished with status "skipping" and reported one unresolved high-severity finding (absolute-path sort in native checksums). WcaleNieWolny is already requested for human review.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Approver External

@sonarqubecloud

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Risk: medium. Not approving: Cursor Bugbot finished with status "skipping" and reported one unresolved high-severity finding (absolute path sort breaks checksums). WcaleNieWolny is already requested for human review.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Approver

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant