Skip to content

Architecture

Morphe Builder is a synchronous Python CLI orchestrating pinned external tools. It turns declarative TOML configuration and untrusted upstream inputs into verified APKs, optional root modules, and linked provenance.

Design priorities:

  1. verify before trust
  2. preserve original split APKs
  3. invoke external tools through public CLI boundaries
  4. publish complete results atomically
  5. keep configuration, not Python code, responsible for app matrix changes

System context

Python owns orchestration, validation, cache policy, provenance, and atomic publication. goopdl, Morphe CLI, APKEditor, and uber-apk-signer remain separate subprocesses.

Package responsibilities

ModuleResponsibility
__init__.pyCLI parsing and dispatch, goopdl subprocess wrapper, Google manifest verification, APK inspection, split-set verification, source provenance.
config.pyStrict tomllib parsing into immutable configuration records.
toolchain.pyJava validation, GitHub release resolution, asset selection, checksums, cache locking, toolchain provenance.
compatibility.pyMorphe patch listing, patch selection, compatible version resolution, confirmed version-code cache.
providers.pyFixed provider fallback order, URL validation, bounded downloads, bundle extraction, provider provenance.
apkmirror.pyResolve APKMirror catalog pages to concrete architecture-specific assets.
uptodown.pyResolve Uptodown pages to concrete assets.
merge.pyRequired split selection, APKEditor merge, merged-stock verification and provenance.
build.pyJob expansion, Morphe patch command, signing, output verification, APK provenance.
module.pyDeterministic Magisk/KernelSU module packaging and archive verification.
orchestrator.pyEnd-to-end build, reporting, cache reuse, staging, fallback integration, summaries.
release.pyRelease artifact verification and preparation used by GitHub workflows.

No general plugin or provider interface exists beyond callable boundaries already required by tests and fixed orchestration. Provider order is product policy, not runtime configuration.

Build lifecycle

Each app with arch = "both" or arch = "all" expands into independent ARM64 and ARMv7 jobs. build-mode = "both" additionally produces root APK and module artifacts.

If no provider can serve one app/architecture, that job is recorded as skipped. Build succeeds only when at least one job completes. Any integrity, merge, patch, signing, module, or publication failure aborts complete staged output.

Trust boundaries

Configuration

config.py rejects unknown keys, malformed URLs, duplicate packages or slugs, invalid signer pins, conflicting patch selections, and unsupported values before network access.

Configuration chooses desired inputs. It does not make downloaded bytes trusted.

External tools

Tool releases resolve to exact tags and unambiguous assets. Upstream checksums are used when available; local SHA-256, size, URL, repository, and resolved tag are always recorded.

Cached assets are validated before reuse. Exclusive lock files and atomic replacement protect concurrent writers.

Stock downloads

Provider content is untrusted until verify_apk_set confirms:

  • expected package
  • requested version name and code
  • required split relationships
  • requested architecture and density policy
  • valid APK ZIP structure
  • signing certificate consistency and optional signer pin
  • Google manifest sizes and digests when Google Play supplied the set

Only verified sets move into cache/trusted/. Reuse triggers verification again.

Build outputs

Merged and patched APKs are inspected after each transformation. Signing password travels through environment or process stdin, never argv. Final files must match expected identity, version, architecture, ZIP structure, and signature before publication.

Static checks establish artifact consistency, not app behavior. Device launch and root-module behavior remain separate validation.

Provider fallback

Provider order is fixed:

text
google-play → direct → archive → apkmirror → uptodown

Fallback advances for provider or version unavailability, mismatched candidate identity, or ambiguous catalog resolution where nothing was trusted. Integrity metadata and signer failures remain terminal.

This distinction prevents a hostile or corrupted source from being hidden by a later successful source.

Storage model

Default cache root:

  • Windows: %LOCALAPPDATA%/morphe-builder
  • Linux: $XDG_CACHE_HOME/morphe-builder or ~/.cache/morphe-builder
text
cache/
├── tools/       # pinned public external tools
├── trusted/     # verified original stock split sets
└── work/        # disposable intermediate state

clean removes only work/. Trusted stock and tools survive cleanup and are revalidated before reuse.

Build output uses a temporary sibling directory. Final os.replace occurs only after all completed jobs, provenance, and summary are ready. Existing output paths are refused.

Provenance chain

Provenance records use hashes and relative links so each result can be traced to downloaded files, selected splits, external tools, patch choices, signer, architecture, and version.

Provenance proves which recorded inputs produced an artifact. It does not audit patch behavior or establish publisher identity when public template key is used.

CI architecture

WorkflowRole
ci.ymlOffline unit tests, lock validation, bytecode compilation across supported Python versions.
security.ymlScheduled dependency and license checks.
manual-verified-build.ymlReusable verified Android build and optional release publication.
daily-verified-build.ymlDetect upstream tool changes and call release build only when needed.
publish-pypi.ymlBuild and publish Python distribution through Trusted Publishing.

Pull-request CI receives no Google Play or signing secrets. Release jobs use protected environments when account credentials or private replacement keystores are configured.

Detailed stage documentation

  1. Configuration
  2. External toolchain
  3. Google Play integrity
  4. Fallback providers
  5. Split merge
  6. APK build
  7. Modules
  8. Security
  9. CI and releases

Released under the MIT License.