docs: record verified development delivery and explicit release gates
iOS validation / simulator (push) Canceled after 0s
Android validation / build (push) Canceled after 0s
Android validation / emulator (35) (push) Canceled after 0s
Android validation / emulator (37.0) (push) Canceled after 0s

Document independent native architecture, server compatibility, build/signing procedures, privacy limitations and persistent continuation steps. Record two consecutive seven-test API 35 HTTPS/OIDC passes, portable and host-tool checks, and inspected unsigned artifacts. Explicitly withhold production readiness pending Apple SDK validation, API 37/current-device testing, real IdPs, resource-limit review, human security review and maintainer signing.
This commit is contained in:
Yuvomi Mobile Contributors committed 2026-10-21 07:32:50 +02:00
1 parent 9ca11e4fb5
commit 2d12491516
13 files changed
+674

No files matched your search

+41
View File
@@ -0,0 +1,41 @@
# Architecture
Two independent native applications share a policy, not a cross-platform runtime:
| Responsibility | Android | iOS |
| --- | --- | --- |
| Native entry/configuration | ComponentActivity and platform widgets | SwiftUI |
| Web application | Android WebView | WKWebView |
| Server URL policy | ServerAddress | ServerAddress |
| Reachability/metadata | HttpsURLConnection, no redirects/cookies | Ephemeral URLSession, no redirects/cookies |
| Authentication | Upstream web UI and OS cookie jar | Upstream web UI and WKWebsiteDataStore |
| OIDC | Separate restricted web view after consent | Separate restricted web view after consent |
| Downloads | Origin-bound streaming / bounded blob capture and pull | WKDownload to temporary protected file, system export |
The client never reimplements a Yuvomi module or introduces a backend. The user
selects the origin. Bootstrap calls check the actual upstream unauthenticated
metadata contract before loading the server application. Configuration stores only
the origin and a query/fragment-free last path; auth/reset/invite routes are not
restored. No native password or API-token storage exists.
The current web view remains alive across background/resume and ordinary rotation.
Android handles orientation changes in the existing activity; process recreation
loads the remembered path and retains OS cookies, not unsaved web form memory.
iOS retains a StateObject-owned view; cold launch restores path and persistent
cookies. No resume reload is imposed. Native recovery offers Retry, Keep viewing,
and server management without hiding the route back to configuration.
Server erasure destroys the browsing context and clears all website storage before
another server is loaded. The local wipe does not invalidate the remote session;
logout is still a server-side operation. Web application history remains native
web history. External schemes, universal links and app links are not registered
because arbitrary self-hosted domains cannot be verified by this app in advance.
The optional integration build has a different Android package ID and adds trust
for a fresh test CA generated outside the repository. It uses the same production
code and the unmodified pinned upstream server. Neither normal debug nor release
resources include that CA. Never distribute an integration APK.
Read-only offline functionality belongs to upstream's service worker. The app
preserves it where the platform engine supports it, but does not promise offline
editing, synchronization, or the same PWA cache behavior on all OS versions.
+67
View File
@@ -0,0 +1,67 @@
# Android development
Requirements: JDK 17, Android SDK platform 37.0, build-tools 36.0.0, current
platform-tools, and accepted Android SDK licenses. Minimum Android 8 (API 26).
Use a maintained Android System WebView. Target API 37. On Android 17, choose
"Allow private-network servers" when using a LAN instance; public HTTPS servers
do not need this optional runtime permission. No discovery/scanning is performed.
```sh
export ANDROID_HOME=/path/to/android-sdk
bash android/gradlew -p android testDebugUnitTest lintDebug lintRelease assembleDebug assembleRelease bundleRelease
bash android/gradlew -p android connectedDebugAndroidTest
```
Gradle 9.6.0 is checksum-verified by the wrapper. AGP 9.4.1 uses built-in Kotlin
with the build-cache fix in KGP 2.4.21. Maven versions are locked. No dynamic
application dependencies or private Maven repository is required.
Ordinary outputs:
- `android/app/build/outputs/apk/debug/app-debug.apk` (development-signed)
- `android/app/build/outputs/apk/release/app-release-unsigned.apk`
- `android/app/build/outputs/bundle/release/app-release.aab` (unsigned unless signed later)
- `android/app/build/reports/` (lint, JVM and emulator results)
Immediately after building, collect and inspect the outputs:
```sh
python3 scripts/collect-android-artifacts.py
```
This writes ignored `artifacts/android/` copies, `SHA256SUMS`, source identity and
manifest/network-policy/signature evidence. It requires `ANDROID_HOME` and respects
`YUVOMI_BUILD_DIR`. Source identity records the checkout at collection time; always
rebuild immediately beforehand and use a clean worktree for a release candidate.
The unsigned release cannot be installed/published as-is. See release signing
instructions. `gradle-wrapper.jar` is the standard generated Gradle bootstrap
binary; it is intentionally versioned, unlike generated APKs or caches.
On WSL/Windows mounts that reject POSIX metadata operations, put outputs on the
Linux filesystem:
```sh
export YUVOMI_BUILD_DIR="$HOME/yuvomi-build"
bash android/gradlew -p android testDebugUnitTest assembleDebug
```
The application never permits HTTP, including debug builds. Use real HTTPS for
manual development. For a temporary local HTTPS integration environment:
```sh
git clone --filter=blob:none https://github.com/ulsklyc/yuvomi.git /path/to/upstream
git -C /path/to/upstream checkout 10bfef7686ed7303b4c74c7fcc55a5eb16356c9d
npm ci --omit=dev --prefix /path/to/upstream
python3 scripts/test-integration.py /path/to/upstream --android
```
Requires Node 22.14+ and a running emulator. The harness creates and removes its
own CA/key/database, uses `adb reverse`, and builds `.integration` with explicit
test trust. It does not weaken production TLS. Test credentials are ephemeral.
Keep test reports private if you customize the harness with real data (not advised).
For dependency updates run `:app:dependencies --write-locks`, the full pipeline,
and `python3 scripts/check-dependencies.py`. Review lockfile changes. The version
update lint recommendations are informational, not suppressed correctness errors;
OSV checks independently fail on known advisories.
+39
View File
@@ -0,0 +1,39 @@
# iOS development
Requires macOS, Xcode 16.4 or newer with an iOS simulator, and XcodeGen 2.44.1.
Minimum iOS/iPadOS 18.4: the auth window must be able to deny native file-panel
requests, which earlier WKWebView delegates cannot do. No CocoaPods or external
runtime package is required. For App Store submission use Apple's currently
required Xcode/iOS SDK, not merely the oldest compiler that can build the source.
```sh
bash scripts/install-xcodegen.sh "$HOME/.local/yuvomi-xcodegen"
"$HOME/.local/yuvomi-xcodegen/xcodegen/bin/xcodegen" generate --spec ios/project.yml
device=$(python3 scripts/select-simulator.py)
xcodebuild -project ios/Yuvomi.xcodeproj -scheme Yuvomi \
-destination "platform=iOS Simulator,id=$device" CODE_SIGNING_ALLOWED=NO test
xcodebuild -project ios/Yuvomi.xcodeproj -scheme Yuvomi \
-destination 'generic/platform=iOS' -archivePath artifacts/Yuvomi-unsigned.xcarchive \
CODE_SIGNING_ALLOWED=NO archive
```
`project.yml` is the source of truth. The Xcode project and generated Info.plist
are ignored. The XcodeGen download is version- and SHA256-pinned. The project
includes a privacy manifest, camera/photo/local-network usage strings, universal
app icon, orientation support, unit and UI test targets, and no ATS exception.
On macOS or Linux with Swift 6 installed:
```sh
swift test --package-path ios
swiftc -frontend -parse ios/Sources/*.swift ios/Tests/*.swift ios/UITests/*.swift
```
These portable tests compile the **production URL/metadata policies only**.
Parsing does not typecheck UIKit, SwiftUI or WebKit APIs. Neither command is
evidence that the iOS application builds. Actual Xcode testing is mandatory.
For a device build select your authorized development team in Xcode, use your own
registered bundle identifier, and let Xcode manage development provisioning.
Never commit generated profiles or certificates. See `release-process.md` for
distribution. A Linux environment cannot produce a validated iOS archive.
+77
View File
@@ -0,0 +1,77 @@
# Maintainer continuation
This is a development delivery, not authorization to publish. Preserve the Git
history on `feat/yuvomi-mobile`; use Conventional Commits and normal pushes only.
The authorized community remote is `https://git.nesterovic.cc/nessi/Yuvomi-App`.
Do not push, submit issues or open pull requests against upstream on this task's
behalf. No production credentials or store accounts have been provided.
## Start with the evidence
Read [validation](validation.md), [security review](security-review.md), and
[release gates](release-process.md). Do not repeat completed implementation work
or equate portable Swift checks with an iOS app build. Inspect `git status` before
editing; preserve any newer maintainer changes.
The upstream reference is Yuvomi 2.78.0 at
`10bfef7686ed7303b4c74c7fcc55a5eb16356c9d`. Keep it unmodified. Subpath hosting,
browser-to-native OIDC handoff and native remote push are not implemented.
The extended API 35 HTTPS suite passes all seven tests, including the local-IdP
round trip, native transfers, recovery and back navigation. Portable Swift has
seven passing policy tests; the separate JUnit verifier has eight regressions.
Keep the fixture's scope separate from real-provider or Apple-platform validation.
## Persistent local environment (Linux/WSL)
- Repository: `/mnt/c/Users/neste/Documents/GIT/Yuvomi-App`.
- Upstream and installed dependencies: `/home/neste/yuvomi-tools/upstream`.
- SDK: `/home/neste/yuvomi-tools/android-toolchain/android-sdk`.
- Build outputs/logs: `/home/neste/yuvomi-build`.
- Swift 6.2.1: `/home/neste/yuvomi-tools/swift-6.2.1-RELEASE-ubuntu24.04/usr/bin`.
- Swift compatibility libraries: `/home/neste/yuvomi-tools/compat/usr/lib/x86_64-linux-gnu`.
- Swift scratch output: `/home/neste/yuvomi-swift-build`.
- ktlint and actionlint: `/home/neste/yuvomi-tools/ktlint.jar` and
`/home/neste/yuvomi-tools/actionlint`.
- Local collected artifacts/evidence: ignored `artifacts/android/`.
`/tmp/opencode` is temporary and was cleared by server restarts. Background
processes may also disappear. Keep durable logs under `/home/neste`; never persist
the integration fixture's generated private CA, keys or real household data.
```sh
export ANDROID_HOME=/home/neste/yuvomi-tools/android-toolchain/android-sdk
export YUVOMI_BUILD_DIR=/home/neste/yuvomi-build
"$ANDROID_HOME/platform-tools/adb" devices -l
"$ANDROID_HOME/platform-tools/adb" shell am get-started-user-state 0
# Require RUNNING_UNLOCKED, then:
python3 scripts/test-integration.py /home/neste/yuvomi-tools/upstream --android
bash android/gradlew -p android testDebugUnitTest lintDebug lintRelease assembleDebug assembleRelease bundleRelease
python3 scripts/collect-android-artifacts.py
```
The API 35 AVD is `yuvomi-test`. Its stable attempt uses KVM, `-gpu host`,
`-no-window -no-audio -no-boot-anim -no-snapshot -memory 2560 -cores 2`.
Launch under the SDK/AVD owner with access to the `kvm` group. Other GPU modes
previously crashed the host emulator with SIGSEGV. API 37 had broken services and
locked credential-encrypted storage; no API 37 runtime success is claimed.
For portable Swift checks add the compiler directory to `PATH` and set
`LD_LIBRARY_PATH` to the compatibility-library directory above, then use the
commands in [iOS development](build-ios.md). Apple application/XCTest/UI/archive
validation must happen on macOS with Xcode and real supported devices.
## Highest-priority external work
1. Typecheck/build the iOS app against Apple SDKs, run its actual XCTest/UI tests,
and produce an unsigned archive. Fix any failures; none of these ran locally.
2. Run the API 37 permission grant/denial/revocation scenarios on a working image
or device, plus the minimum-supported Android and current WebView matrix.
3. Review iOS unknown-length download disk-pressure handling before release.
4. Validate real supported IdPs, TOTP after SSO, linking, cancellation, native
file/camera pickers, process death, accessibility and offline account isolation.
5. Establish private vulnerability reporting, owned identifiers, authorized CI,
human security review and owner-controlled signing before any distribution.
The provided GitHub Actions workflows do not automatically execute on the current
non-GitHub forge. Do not claim hosted CI or store readiness without actual runs.
+72
View File
@@ -0,0 +1,72 @@
# Release process
No release is authorized by the existence of these scripts. No workflow publishes
to either store. A debug APK or unsigned archive is not a production release.
1. Complete every outstanding gate in `validation.md` and `security-review.md`.
Obtain independent human review of authentication, navigation, file handlers,
local erasure and privacy disclosures. Run actual supported device/OS tests.
2. Resolve bundle/application identifier ownership. `community.yuvomi.mobile` is
a provisional community identifier, not proof of registry/store ownership.
Confirm use of the Yuvomi name, required attribution and independent status.
3. Bump version/name/code in Android and the iOS project spec; update CHANGELOG.
4. Run JVM/emulator/real-upstream HTTPS tests, portable Swift and Xcode simulator
tests, static checks, OSV scan, release builds and artifact inspection. Record
upstream revision, app SHA, OS/WebView/Xcode versions, results and checksums.
5. Produce signed artifacts only using an authorized maintainer's credentials.
6. Review store privacy/Data Safety answers for the app AND selected-server model,
permission rationale, encryption/export compliance, screenshots, support URL,
vulnerability contact, and device demonstrations. A functional web companion
is not guaranteed to pass Apple's minimum-functionality review.
7. Create a release/tag and publish artifacts/store submissions manually only
after explicit maintainer authorization. Never force-push or rewrite history.
## Android
The manual `release.yml` workflow uses a protected GitHub environment named
`release`. Configure branch restrictions and required reviewers before adding
secrets. With `sign_android=false` it emits unsigned artifacts. Signing requires:
- `ANDROID_KEYSTORE_BASE64`
- `ANDROID_STORE_PASSWORD`
- `ANDROID_KEY_PASSWORD`
- `ANDROID_KEY_ALIAS`
The workflow uses `zipalign`, `apksigner`, and `jarsigner`; private material exists
only in a restrictive runner-temporary file removed on exit. Securely back up the
real upload key and use Play App Signing according to the owner's policy. No
production key is generated here. Manually verify APK/AAB signatures and inspect
the final manifest: no debuggable flag, HTTP/test CA or unintended exported component.
Never distribute an `.integration` package or include its generated test resources.
Run `python3 scripts/collect-android-artifacts.py` immediately after the clean-source
build to inspect unsigned outputs and record local hashes/source identity. This
collector intentionally rejects signed release outputs; collect before signing.
## iOS
The CI archive is unsigned and cannot be uploaded to App Store Connect. An owner
needs Apple Developer Program membership, a registered app ID, distribution
certificate/private key, provisioning profile and App Store Connect permissions.
Generate/open the project, choose the authorized team, set the owned bundle ID,
select a physical/generic iOS destination, and use Product -> Archive. Validate
the archive in Organizer and export using the owner's distribution method. For
CLI export use a **locally supplied** ExportOptions.plist with the correct team,
method and provisioning mappings:
```sh
xcodebuild -exportArchive -archivePath artifacts/Yuvomi.xcarchive \
-exportPath artifacts/ios -exportOptionsPlist /secure/path/ExportOptions.plist
```
Do not add distribution certificates, profiles, App Store keys or passwords to the
repository. Device camera, Files, VoiceOver, memory pressure and app-switcher
privacy need physical-device validation beyond simulator tests.
## CI hosting
GitHub Actions files are provided, but the configured community remote is hosted
on a different forge. GitHub workflows will not automatically run there. Enable
an authorized GitHub mirror/repository (or port the jobs to the forge's runner)
and inspect real runs before claiming CI is operational. No destination is
created automatically. CI service availability is not an application dependency.
+47
View File
@@ -0,0 +1,47 @@
# Security review record
This is an engineering review, not an independent penetration test or certification.
Addressed during implementation:
- Canonical, HTTPS-only origin/port comparison; credential, fragment, query,
subpath, scheme, lookalike-host and TLS-downgrade regression cases.
- A main-frame POST can bypass Android's usual navigation callback. The request
interception gate now rejects **all** cross-origin requests, not only subresources.
The emulator regression was observed failing when the main-frame guard was
deliberately removed, then rerun with the fix restored.
- TLS failures cancel by default. Native download redirects are refused before
cookies can be replayed to another origin. Bootstrap requests use neither
cookies nor automatic redirects and have bounded metadata reads/timeouts.
- Files use explicit system selection/content URIs; no filesystem or storage
permission is granted to web content. Blob exports have no native JS bridge.
- Complete Android browsing-data deletion uses WebStorageCompat, with OS app
reset for engines without that capability. WebStorage.deleteAllData alone was
insufficient for service-worker CacheStorage/IndexedDB and is not relied upon.
- iOS server erase replaces the WKWebView, not only its URL, eliminating old
history/back-forward contexts as well as persistent website data.
- iOS metadata uses typed decoding, rejecting numeric values masquerading as booleans.
- Native picker results are bound to the browsing generation/request. Android
rejects stale upload/download selections, revokes camera URI grants, and clears
capture cache on erasure. iOS ignores export-cancellation callbacks from an old
download. Apple-specific callback regressions have not run without Xcode.
- KGP was upgraded after OSV identified CVE-2026-53914 in the original build tool.
The final OSV scan found no listed advisories across 213 locked/direct Maven
coordinates and build plugins. Rescan after resolution/lock updates.
- The inspected release APK is not debuggable, rejects cleartext, disables backup
and trusts system CAs only. AndroidX's exported profile installer receiver is
protected by the system DUMP permission; app providers are not exported.
Release gates still requiring evidence:
- Actual Xcode typecheck, simulator, archive, physical-device and accessibility review.
- End-to-end IdP flows, especially providers that prohibit embedded agents; no
browser-to-native session transfer is supported by the current upstream protocol.
- iOS unknown-length download disk-pressure behavior; a post-download size check
is not a streaming quota. Verify file picker/camera cancellation on real devices.
- Android file-picker/camera/rotation while a picker is outstanding; cancellation
on process death intentionally loses the selection, never silently retries it.
- Offline sign-out/account switching, stale-worker updates and server erasure on
current WebView/WKWebView versions. Upstream tests are not native device proof.
- Reverify final signed release manifests, signing, store ownership, private vulnerability contact
and applicable privacy disclosures. No claim that all vulnerabilities are absent.
+70
View File
@@ -0,0 +1,70 @@
# Server compatibility and authentication
Source reference: upstream 2.78.0 revision
`10bfef7686ed7303b4c74c7fcc55a5eb16356c9d`. No general version range has been
certified. Anonymous bootstrap metadata deliberately omits the exact version;
native probing verifies shape, not an invented minimum-version comparison.
Use `https://family.example.com` or `https://family.example.com:8443`, backed by a
root-hosted Yuvomi installation and a valid system-trusted certificate. Operators
should set `SESSION_SECURE=true`, correct `BASE_URL`, and correct proxy trust.
Private servers are supported through reachable HTTPS/VPN, not TLS bypasses.
International hostnames should be entered in ASCII/punycode for both platforms.
Root-relative assets, API endpoints, cookie paths, callback redirects and worker
registration mean `/yuvomi/` subpaths are not supported by the inspected source.
Use a dedicated hostname. Reverse proxies must pass `/api/v1/*`, cookies, HTML,
JavaScript and the service worker consistently. An external authentication proxy
that intercepts bootstrap calls is rejected with a connection error; it is not
silently identified as a Yuvomi server.
## Authentication
Password login, TOTP/recovery codes, password reset, invitations, server-side
session expiry/revocation and logout remain upstream web flows. No native code
stores the password, supplies a CSRF bypass, or extends an expired session.
Backgrounding does not clear cookies. Native server erasure does not revoke a
remote session; use Yuvomi logout first or revoke sessions server-side.
### OIDC: local fixture verified; real-provider validation pending
The initiating Yuvomi session contains OIDC state, nonce and PKCE verifier. When
the server redirects to an identity provider, native consent offers an isolated
web sign-in window sharing the OS website cookie store. HTTPS-only redirects
can return to the server callback; the final same-origin page returns to the main
view. No app-capability handlers or JS bridge are installed in that auth window.
Some providers (including configurations that prohibit embedded user agents)
require a system browser. **Those cannot sign the native view in with upstream's
current protocol.** Use Server settings -> Open server in browser, and sign in
there for an independent browser session. Opening only the external authorization
link in a browser does not transfer the initiating cookie. Browser cookies are
never copied into the app, and custom-scheme callbacks are not fabricated.
The API 35 integration suite completes a native isolated-window round trip with
a local test IdP, real RS256 ID tokens, nonce and S256 PKCE. No external
IdP/developer account was supplied. Validate the actual provider, including
cross-site cookies, cancellation, errors, TOTP and account linking, before relying
on that deployment. iOS authentication has not run against Apple SDKs. A native
browser handoff would require an independently reviewed upstream protocol; no
such upstream change is included or published.
Android generated exports require a current WebView supporting document-start
scripts and are capped at 25 MB. A bounded Blob registry preserves a generated
file even when upstream immediately revokes its object URL; it does not fetch
blob URLs or alter the server's CSP. HTTPS file downloads are capped at 100 MB.
Update the system WebView if generated exports are unavailable on an old engine.
## Notifications and offline
Upstream implements Web Push and optional ntfy/Gotify/webhook/email channels.
Embedded web views do not supply a portable native push subscription. This app
has **no native remote-push claim**, no Firebase/APNs secrets, no background
polling service, and no fake notification-registration UI. Configure an existing
optional upstream ntfy/Gotify channel and its client if desired. No centralized
service is required by this application.
Upstream service-worker caching is read-only, allow-listed, and versioned.
Mutations/authentication remain online. Platform-specific cache/resume behavior
and offline account switching still need device validation. Do not rely on offline
editing, synchronization, or closed-app push in this native development build.
+130
View File
@@ -0,0 +1,130 @@
# Validation status
**Partially verified development software, not production-ready.**
Local validation date: 2026-10-21. No unexecuted iOS application test, hosted CI
run, production signing, or store publication is represented as completed.
## Executed evidence
- Android debug APK and unsigned release APK/AAB built successfully; both
`lintDebug` and `lintRelease` passed. JVM security/picker-policy tests: **7 passed,
zero failures/skips**.
- Android API 35 regular emulator suite: **6 passed, zero failures/skips**.
This covers onboarding, invalid URLs, background/resume, hardened settings,
cross-origin POST/subresource isolation, opaque-page Blob rejection and activity
recreation. Its permission test checks that the API 37 permission UI is absent;
it is **not** evidence of API 37 permission grant/denial behavior.
- Unmodified pinned upstream ran behind a temporary HTTPS reverse proxy.
Bootstrap metadata, password login, Secure/HttpOnly/SameSite cookies, persistent
session, CSRF rejection, logout/revocation passed in the harness.
- Android's extended real-server scenario exercises login, HttpOnly cookies,
document upload via upstream fetch, native FileTransfer output, bounded Blob
export, background/resume, recreation, CSRF-protected logout, revocation,
recovery, isolated OIDC return and back navigation. It does not automate the OS
camera/document destination picker or prove every upstream module works.
Two consecutive API 35 runs have **7 passed, zero failures/skips each**, including the
six regular security/onboarding cases and this real-server scenario.
- The cross-origin POST regression was deliberately observed failing without its
guard. The production guard was restored and the API 35 regression passes.
- Portable Swift production-policy tests: 7 passed (URL and typed metadata).
All Swift sources passed format lint and parsing with Swift 6.2.1 on Linux.
The portable package excludes BrowserModelTests. This does not build iOS.
- Selected upstream suites ran successfully: cookie-secure-flag (4),
session-sliding (8), two-factor (22), password-reset (24), sw-api-cache (42).
Upstream's plain OIDC script also exited successfully. These are upstream tests,
not evidence of a provider round-trip or native push support.
- The HTTPS harness independently passed upstream OIDC discovery, RS256 ID-token
signature/nonce validation, S256 PKCE exchange and session creation with a local
test IdP. The fixture checks single-use codes, exact redirect URIs and OAuth
Basic client authentication. Loopback hosts/ports and automatic fixture consent
are not representative of every provider's cross-site/embedded-agent policies.
- OSV: no listed advisories for **213** locked/direct Maven coordinates and build
plugins at scan time. This is not a guarantee that no vulnerabilities exist.
- ktlint 1.7.1, actionlint 1.7.7, repository invariants, Python compilation,
Node syntax and shell syntax checks passed. JUnit-verifier regression suite:
**8 passed**, including rejection of absent, empty, malformed, insufficient,
failed, errored and skipped evidence.
- Release APK inspection confirms API 26 minimum / API 37 target, no debuggable
flag, backups and cleartext disabled, system-only certificate trust. Exported
entry points are the launcher and AndroidX ProfileInstallReceiver protected by
the system DUMP permission; file/startup providers are not exported. Debug APK
signature verifies; release APK/AAB are unsigned. Collected archives contain no
fixture CA/key or signing-key files.
## Emulator limitations and retry evidence
Earlier extended-suite attempts crashed the host emulator with SIGSEGV under
software/off GPU modes. Host-GPU mode remained running and produced actionable
JUnit failures: an OIDC-return synchronization timeout, followed by an outage
assertion that incorrectly assumed the upstream worker could not serve its cached
app shell, then a document-readiness race after recreation. Tests now verify the
loaded JavaScript origin, wait for the sign-in window to close, retry only a probe
lost to document replacement and exercise recovery through uncached metadata.
The completed retry passes all seven tests without disabling the worker or
weakening production TLS/CSP/origin policies.
API 37 attempts encountered broken package/activity services and locked
credential-encrypted storage. **No API 37 runtime pass is claimed.**
Local logs and reports live in `/home/neste/yuvomi-build/`; test XML is under
`app/outputs/androidTest-results/connected/`. Earlier failing JUnit snapshots are
preserved as `integration-host-gpu-oidc-race.xml` and
`integration-host-gpu-sw-cache.xml`, plus
`integration-host-gpu-document-ready.xml`. Passing evidence is preserved in
`integration-api35-first-pass.xml` and `integration-api35-repeat-pass.xml`; logs are
`upstream-integration-final-retry.log` and `upstream-integration-repeat.log`.
These files are local evidence, not published
artifacts or a hosted CI result.
Test environment: JDK 17.0.20.1, Node 22.22.1, Python 3.14.4, Android Emulator
37.2.12, API 35 x86_64 Google APIs image, WebView 124.0.6367.219. The old bundled
WebView is useful compatibility evidence, not a recommendation to use an unpatched
engine; a current engine/device run remains mandatory.
## Artifacts
Ignored `artifacts/android/` contains the development-signed debug APK and unsigned
release APK/AAB, `SHA256SUMS`, `build-info.json` and manifest/policy/signature
inspection evidence. No integration APK is collected. No IPA or Apple archive
exists. See [Android build](build-android.md) for repeatable collection commands.
## Commands
```sh
bash android/gradlew -p android testDebugUnitTest lintDebug lintRelease assembleDebug assembleRelease bundleRelease connectedDebugAndroidTest
python3 scripts/test-integration.py /path/to/pinned-upstream --android
swift test --package-path ios
swiftc -frontend -parse ios/Sources/*.swift ios/Tests/*.swift ios/UITests/*.swift
python3 scripts/check-repository.py
python3 scripts/check-dependencies.py
python3 scripts/test-verifier.py
python3 scripts/collect-android-artifacts.py
git diff --check
```
This environment is Linux/WSL. Android SDK and a KVM emulator were installed for
real execution. Build output relocation was needed because the Windows mount
rejects some Gradle POSIX metadata operations. Swift's Linux toolchain was
installed for portable tests. No macOS, Xcode, Apple simulator or physical device
is available; no iOS build/archive/UI result is claimed.
## Mandatory remaining evidence
- Run Xcode build, XCTest/UI tests and unsigned archive on macOS; fix any compiler
or runtime issues. The app has **not** yet been typechecked against Apple SDKs.
- Validate real IdPs: cancellation, account linking, TOTP after OIDC, and embedded
provider policy. Browser-only providers have no native-session handoff upstream.
- Real-device camera/document picker cancellation, file MIME cases, rotation with
an outstanding picker, network loss/reconnect, process kill/memory pressure,
session expiry/revocation, OS backup, and offline account isolation.
- Android 17 private-network permission grant/denial/revocation on a matching OS.
Also run minimum-supported API 26 and a current OS/WebView device matrix.
- VoiceOver/TalkBack, large text, contrast, keyboard/safe areas, reduced motion,
light/dark appearance and responsive web modules on actual supported devices.
- Operational CI runs on an authorized GitHub repository/runner, private security
reporting contact, human security review, store ownership and production signing.
No Firebase/APNs registration, closed-app push, offline editing, App Store approval,
signing, publication or physical-device validation is claimed. See `SECURITY.md`
and `docs/security-review.md` for residual limitations.
Resume work using [maintainer continuation](continuation.md).