A phone's runner follows the app's releases: never offered a runner build (refs andymccall/oxygenflow#84) 2f79b17e089a
- Author
- Andy McCall @andymccall <[email protected]>
- via
- agent
agent:claude@andymccall <[email protected]> · keyless, under your grant for changes,refs,seal · key a93aecb664d7
- When
- · 2026-10-29 01:49 UTC
- Signature
- ◈ sealed by agent:claude@andymccall
- Hash
2f79b17e089af898bccb1236755e2c88c5868fac7edd5b4f5802c4544d1d3175- Depends on
- 42fa95540468 8501fd5815b9 b5668108487f c26267b3aba6
- Depended on by
- 27322cd2755a 93f445fa50d8
- In bookmarks
- main
- In tags
- v0.9.16 v0.9.19 v0.9.20 v0.9.21 v0.9.22 v0.9.23 v0.9.24
- Edits
- 3 atoms, 0 tree operations, 3 files
Browse the tree at this change
modified CHANGELOG.md +4 −0
| … | 1 unchanged lines |
||
| 2 | 2 | ||
| 3 | 3 | OxygenHub runs at https://oxygenhub.io; each deploy's build is on the About page and at `/api/v1/version`. |
|
| 4 | 4 | ||
| 5 | + | ## Unreleased |
|
| 6 | + | ||
| 7 | + | - **A phone's runner follows the app's releases (oxygenflow#84).** A runner on Android is part of the OxygenHub app, so the hub never offers it a runner build: with updates on, it is told it follows the app's releases (update the app to update it), and Admin › Runners › Updates says so. |
|
| 8 | + | ||
| 5 | 9 | ## 0.9.15 (2026-10-28) |
|
| 6 | 10 | ||
| 7 | 11 | - **Run a pipeline's WASM jobs in your browser (oxygenflow#80, first part).** Flow › *run in this tab* (`/OWNER/NAME/flow/tab`) lists the jobs of a bookmark's pipeline whose sandbox is `runtime "wasm"` and runs them in this tab, as a runner's WASM tier does: a worker fetches the bookmark's files as a zip once, unpacks them in memory and runs each job's modules with a WASI preview 1 shim, the files at `/src` and as the current directory, the job's arguments and environment, its output shown as it comes, its exit code and time; Run all, Run and Stop per job. Nothing is claimed or reported: it shows the tier in a browser before a tab can take jobs as a runner. |
|
| … | 416 unchanged lines |
modified crates/hub/src/runner_updates.rs +9 −0
| … | 321 unchanged lines |
||
| 322 | 322 | if !policy.updates { |
|
| 323 | 323 | return Ok((None, format!("updates are off ({})", policy.from[0]))); |
|
| 324 | 324 | } |
|
| 325 | + | // A phone's runner is part of the OxygenHub app (oxygenflow#84, |
|
| 326 | + | // oxygenhub-android#7): it updates when the app does, never from a |
|
| 327 | + | // runner build. |
|
| 328 | + | if r.os == "android" { |
|
| 329 | + | return Ok(( |
|
| 330 | + | None, |
|
| 331 | + | format!("follows the OxygenHub app's releases: runs flow {} (update the app to update it)", version_of(&r.version)), |
|
| 332 | + | )); |
|
| 333 | + | } |
|
| 325 | 334 | let Some(spec) = db::accounts::setting(pool, SETTING_REPO).await?.filter(|s| !s.trim().is_empty()) else { |
|
| 326 | 335 | return Ok((None, "no runner releases repository is set (Admin › Runners › Updates)".into())); |
|
| 327 | 336 | }; |
|
| … | 200 unchanged lines |
modified crates/hub/tests/flow.rs +16 −0
| … | 7114 unchanged lines |
||
| 7115 | 7115 | let (_, page) = web("POST", &format!("/admin/runners/updates/groups/{}/delete", group.id), Some(format!("_csrf={csrf}"))).await; |
|
| 7116 | 7116 | assert!(page.contains("Test group canary removed"), "{page}"); |
|
| 7117 | 7117 | assert!(!ask(0).await.policy.updates, "back to the site's off"); |
|
| 7118 | + | ||
| 7119 | + | // A phone's runner follows the app's releases, never a runner build |
|
| 7120 | + | // (oxygenflow#84): with updates on, it is offered nothing and told why. |
|
| 7121 | + | let (_, page) = web("POST", "/admin/runners/token", Some(format!("_csrf={csrf}"))).await; |
|
| 7122 | + | let i = page.find("--token ").unwrap() + "--token ".len(); |
|
| 7123 | + | let token: String = page[i..].chars().take_while(|c| !c.is_whitespace()).collect(); |
|
| 7124 | + | let identity = SecretKey::generate().identity("phone (OxygenFlow runner)", "", 1); |
|
| 7125 | + | let info = serde_json::json!({ "arch": "aarch64", "os": "android", "version": "0.1.0 (app)", "max_jobs": 1 }); |
|
| 7126 | + | let reg = serde_json::json!({ "token": token, "name": "phone", "identity": hex::encode(identity.encode()), "info": info }); |
|
| 7127 | + | let (_, body) = call(&h.app, "POST", "/api/v1/flow/runners/register", None, Some(reg.to_string())).await; |
|
| 7128 | + | let phone = serde_json::from_str::<serde_json::Value>(&body).unwrap()["credential"].as_str().unwrap().to_string(); |
|
| 7129 | + | web("POST", "/admin/runners/updates/policy", Some(format!("_csrf={csrf}&scope=site&updates=on"))).await; |
|
| 7130 | + | let (st, body) = call(&h.app, "GET", "/api/v1/flow/runner/update", Some(&phone), None).await; |
|
| 7131 | + | assert_eq!(st, StatusCode::OK, "{body}"); |
|
| 7132 | + | let a: flow_core::api::UpdateAnswer = serde_json::from_str(&body).unwrap(); |
|
| 7133 | + | assert!(a.offer.is_none() && a.note.contains("follows the OxygenHub app's releases"), "{a:?}"); |
|
| 7118 | 7134 | } |
|
| 7119 | 7135 | ||
| 7120 | 7136 | /// oxygenflow#84: a version reaches a later wave once every runner of the |
|
| … | 263 unchanged lines |