fix(android): retain HTTPS sessions with upstream default cookie flags
Android validation / emulator (37.0) (push) Failing after 3s
Android validation / emulator (35) (push) Failing after 9s
iOS validation / simulator (push) Successful in 1m48s
Android validation / build (push) Successful in 5m10s

Reproduce browser-success/native-401 with unmodified upstream SESSION_SECURE=false behind HTTPS. Keep cookies in the existing HTTPS-only origin-bound encrypted jar regardless of the server Secure attribute; preserve TLS, redirect, expiry and origin protections. Distinguish credential/2FA rejection from missing/rejected session handoff and clear stale login errors on retry. Verify 13 JVM tests plus the 7-test real-server suite in both Secure/default-cookie modes, including bad-password then successful native login. Bump Android preview to 0.2.1/code 3; extend CI and document the defect without claiming access to the user's production server.
This commit is contained in:
Yuvomi Mobile Contributors committed 2026-10-21 09:53:55 +02:00
1 parent 129eac675c
commit 4b483c20e3
16 files changed
+220 -22

No files matched your search

+9 -5
View File
@@ -41,7 +41,7 @@ def collect_native_screenshot(additional, screenshots):
(screenshots / "native-dashboard.png").write_bytes(capture)
def run(upstream, android):
def run(upstream, android, cookie_without_secure=False):
revision = subprocess.check_output(["git", "-C", str(upstream), "rev-parse", "HEAD"], text=True).strip()
assert revision == REVISION, f"Expected pinned upstream {REVISION}, got {revision}"
base_temp = Path("/tmp/opencode") if Path("/tmp/opencode").exists() else Path(tempfile.gettempdir())
@@ -56,7 +56,8 @@ def run(upstream, android):
with (directory / "server.log").open("w") as log:
process = subprocess.Popen(["node", str(ROOT / "scripts/integration-server.mjs"), str(upstream), temporary],
cwd=upstream, stdout=log, stderr=log,
env={**os.environ, "NODE_EXTRA_CA_CERTS": str(directory / "cert.pem")})
env={**os.environ, "NODE_EXTRA_CA_CERTS": str(directory / "cert.pem"),
"YUVOMI_TEST_SESSION_SECURE": "false" if cookie_without_secure else "true"})
try:
for _ in range(200):
if (directory / "ready.json").exists():
@@ -102,7 +103,7 @@ def run(upstream, android):
status, body, headers = request("/api/v1/auth/login", {"username": "mobiletest", "password": password})
assert status == 200
session = [cookie for cookie in cookies if cookie.name == "yuvomi.sid"][0]
assert session.secure and session.has_nonstandard_attr("HttpOnly")
assert session.secure == (not cookie_without_secure) and session.has_nonstandard_attr("HttpOnly")
assert "SameSite=Lax" in " ".join(headers.get_all("Set-Cookie"))
csrf = json.loads(body)["csrfToken"]
assert request("/api/v1/auth/me")[0] == 200
@@ -110,7 +111,8 @@ def run(upstream, android):
assert request("/api/v1/auth/logout", {})[0] == 403
assert request("/api/v1/auth/logout", {}, {"X-CSRF-Token": csrf})[0] == 200
assert request("/api/v1/auth/me")[0] == 401
print("PASS: login, Secure/HttpOnly/SameSite cookies, persistence, CSRF rejection and logout/revocation")
cookie_mode = "HTTPS with upstream-default non-Secure session cookie" if cookie_without_secure else "Secure session cookie"
print(f"PASS: login, {cookie_mode}, HttpOnly/SameSite, persistence, CSRF rejection and logout/revocation")
assert request("/api/v1/auth/oidc/start")[0] == 200
status, body, _ = request("/api/v1/auth/me")
identity = json.loads(body)
@@ -168,5 +170,7 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("upstream", type=Path)
parser.add_argument("--android", action="store_true")
parser.add_argument("--cookie-without-secure", action="store_true",
help="Test upstream's default session-cookie attributes over HTTPS; never enables HTTP")
arguments = parser.parse_args()
run(arguments.upstream.resolve(), arguments.android)
run(arguments.upstream.resolve(), arguments.android, arguments.cookie_without_secure)