fix: prevent setup restart bypass

This commit is contained in:
Hermes Agent
2026-07-24 18:52:54 +00:00
parent 5b3263ef14
commit 77807608e2
5 changed files with 29 additions and 12 deletions
+4
View File
@@ -57,6 +57,7 @@ All notable Hermes Mobile source changes are recorded here. Entries are added du
- Ignored `.gradle-user/` and `.dev/` alongside existing generated build artifacts.
### Fixed
- Fixed first-run setup so a profile saved by a failed/offline compatibility test cannot bypass mandatory setup after process restart; only completed or migrated valid profiles skip the wizard.
- Fixed durable stream completion so a stale request ID cannot publish a terminal state or clear a newer reservation.
- Fixed stream failure handling so HTTP, I/O, and malformed-SSE failures are reported and reduced only against the original lease, while upstream `error` events remain session failures rather than route failures.
- Fixed bearer handling so `/health` is checked without credentials and the token is sent only to the documented authenticated `/v1/models` compatibility route.
@@ -64,6 +65,9 @@ All notable Hermes Mobile source changes are recorded here. Entries are added du
- Fixed companion/mobile lint issues from missing Node globals and an unused React settings value.
### Verification
- `./gradlew --offline --no-daemon -Dorg.gradle.jvmargs= -Dorg.gradle.daemon=false -Pkotlin.compiler.execution.strategy=in-process :app:testDebugUnitTest --tests 'cloud.molberg.hermesmobile.onboarding.SetupWizardReducerTest'` — passed (28 tests), after the new regression first failed as expected.
- `./gradlew --offline --no-daemon -Dorg.gradle.jvmargs= -Dorg.gradle.daemon=false -Pkotlin.compiler.execution.strategy=in-process :app:testDebugUnitTest :app:assembleDebug` — passed (43 tasks, 4 executed).
- `git diff --check` — passed for the setup restart-bypass fix.
- First-run Setup Wizard source verification: the source-current offline Android `:app:testDebugUnitTest :app:assembleDebug` run passed on 2026-07-24 with 43 tasks (4 executed, 39 up-to-date) and 104 tests (0 failures); a final identical rerun was blocked before project execution by the sandbox TCP restriction. `git diff --check` passed. No device, release, or real gateway credential test is claimed.
- `/root/.openclaw/workspace/scripts/hermes-mobile-preflight.sh` — passed; Android `:app:assembleDebug` BUILD SUCCESSFUL (37 tasks, 14 executed).
- `GRADLE_USER_HOME=/root/hermes-mobile/.gradle-user ./gradlew --offline --no-daemon -Dorg.gradle.jvmargs= -Dorg.gradle.daemon=false -Pkotlin.compiler.execution.strategy=in-process :app:testDebugUnitTest :app:assembleDebug` — passed (43 tasks, 5 executed), including `BetaPackageMetadataTest` for application ID `cloud.molberg.hermesmobile`, `versionName` `0.1.0-beta.1`, and `versionCode` `10001`.
+3 -2
View File
@@ -53,11 +53,12 @@ Complete the Android/client contract pivot before implementing backend behavior.
_Move finished items here with date, commit, and verification. Keep this section factual; do not claim unverified work._
- [x] **P0 — First-run Setup Wizard** — 2026-07-24, commit `1b4abfa` (`feat: add first-run setup wizard`).
- [x] **P0 — First-run Setup Wizard** — 2026-07-24, commits `1b4abfa` (`feat: add first-run setup wizard`) and pending follow-up (`fix: prevent setup restart bypass`).
- Added a Compose first-run flow covering welcome/privacy guidance, required Remote HTTPS and optional Local HTTPS routes, None/Bearer/username-password authentication, local-first connection testing, and completion only after a successful test.
- Added direct password login through `/auth/password-login`, allowlisted session-cookie extraction, encrypted cookie/password storage, credential redaction, replacement/retention rules, and cookie-authenticated gateway probes without persisting raw credentials in UI state or connection forms.
- Added Settings entry for editing the same profile, skip behavior for existing valid configurations, one-time legacy/current-profile setup-version migration, and accessible adaptive Compose semantics plus phone/tablet/light/dark previews.
- Verification on 2026-07-24: the source-current offline `:app:testDebugUnitTest :app:assembleDebug` run passed (43 tasks, 4 executed; 104 tests, 0 failures), and `git diff --check` passed. A final identical Gradle rerun was blocked before project execution by the sandbox TCP restriction (`java.net.SocketException: Operation not permitted`). No device, release, or real gateway credential test is claimed.
- Fixed a restart bypass: a profile saved by a failed first-run connection test remains in mandatory setup until setup completion is durably recorded; valid migrated and completed profiles still skip setup.
- Verification on 2026-07-24: source-current offline `:app:testDebugUnitTest :app:assembleDebug` passed (43 tasks, 4 executed; all unit tests passed), including the focused restart-regression test; `git diff --check` passed. No device, release, or real gateway credential test is claimed.
- [x] **R2a — Establish beta source packaging and install documentation** — 2026-07-24, commit `98b183e` (`build: establish Android beta packaging`).
- Set Android package metadata to semantic `versionName` `0.1.0-beta.1` with monotonic `versionCode` `10001`, enabled generated metadata coverage, and named the debug APK `hermes-mobile-v0.1.0-beta.1-debug.apk`.
- Added a direct-gateway-only build, metadata inspection, clean-install, launch, configuration, evidence, and known-limitations guide; changed the npm Android build command to run the native Gradle project without Capacitor synchronization.
@@ -262,7 +262,11 @@ object SetupWizardReducer {
hasLegacyConfiguration &&
existing
return SetupGateResolution(
entry = entry,
entry = if (setupVersion >= CURRENT_SETUP_VERSION || migrateExistingUser) {
entry
} else {
SetupEntry.Mandatory(firstRun())
},
migrateExistingUser = migrateExistingUser
)
}
@@ -214,7 +214,22 @@ class SetupWizardReducerTest {
}
@Test
fun currentOrNonLegacyExistingConfigDoesNotRequestMigration() {
fun failedFirstRunSavedProfileCannotSkipMandatorySetupAfterRestart() {
val resolution = SetupWizardReducer.resolveEntry(
config = ConnectionConfig(
remoteUrl = REMOTE,
authMode = ConnectionAuthMode.None
),
setupVersion = 0,
hasLegacyConfiguration = false
)
assertTrue(resolution.entry is SetupEntry.Mandatory)
assertFalse(resolution.migrateExistingUser)
}
@Test
fun completedExistingConfigSkipsWithoutRequestingMigration() {
val config = ConnectionConfig(
remoteUrl = REMOTE,
authMode = ConnectionAuthMode.None
@@ -225,16 +240,9 @@ class SetupWizardReducerTest {
setupVersion = SetupWizardReducer.CURRENT_SETUP_VERSION,
hasLegacyConfiguration = true
)
val nonLegacy = SetupWizardReducer.resolveEntry(
config = config,
setupVersion = 0,
hasLegacyConfiguration = false
)
assertTrue(current.entry is SetupEntry.ExistingConfiguration)
assertFalse(current.migrateExistingUser)
assertTrue(nonLegacy.entry is SetupEntry.ExistingConfiguration)
assertFalse(nonLegacy.migrateExistingUser)
}
@Test
+1 -1
View File
@@ -7,7 +7,7 @@
- Welcome/privacy guidance precedes configuration; Remote HTTPS is required and Local HTTPS is optional for the same logical gateway profile.
- Authentication choices are None, Bearer token, or username/password. Password login exchanges credentials directly with the configured remote gateway and stores encrypted credentials/session state outside Compose UI models.
- Test-and-finish uses the existing local-first route selection, requires a successful compatibility check before completion, and exposes the same profile for later Settings edits.
- Existing valid profiles skip mandatory setup; legacy/current valid profiles receive a one-time setup-version migration without forcing re-entry.
- Existing completed valid profiles skip mandatory setup; legacy/current valid profiles receive a one-time setup-version migration without forcing re-entry. A failed/offline first-run test cannot create a restart bypass.
- Compose semantics, minimum touch targets, adaptive layout behavior, and phone/tablet/light/dark previews cover the wizard source contract.
- Source verification passed with 104 unit tests and debug assembly. No real device, release, or real gateway credential walkthrough has been performed; those remain part of R1/R2 evidence.