Skip to content

Commit 6919476

Browse files
AzimovSclaude
andauthored
chore: migrate to S3 updater endpoint (sync from ethereum/meetily) (#42)
* chore: bump version to v0.1.17 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat: switch updater endpoint to S3 with AzimovS fallback (#2) * feat: switch updater endpoint to S3 with AzimovS fallback Point tauri.conf.json's updater endpoints at the new S3-served latest.json as primary, keeping the AzimovS GitHub Releases URL as a fallback. Pubkey is unchanged — every existing install verifies signatures against the baked-in pubkey, so rotating it would brick auto-update for prior releases. Add a macOS-only CI guard in build.yml that fails the run if entitlements.plist is missing com.apple.security.network.client. Without this entitlement, hardened-runtime macOS binaries silently report "up to date" forever because the updater can't reach the network from Rust. Update the diagnostic-only debug_check_update URL in lib.rs to match the new endpoint, so manual debugging stays consistent with the production auto-update path. Plan: docs/plans/2026-04-28-chore-migrate-releases-to-minio-2-private-repo-validation-plan.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(debug): probe both updater endpoints in debug_check_update Iterate the same [S3, AzimovS] list as tauri.conf.json so the diagnostic shows each endpoint's status independently. A failure on the primary no longer short-circuits inspection of the fallback — the whole point of the command is visibility, not fallback simulation. Endpoint list is hardcoded with a doc comment requiring it to track tauri.conf.json. Reading the config at runtime would remove the drift risk but adds an AppHandle dependency for a debug command that touches the URL list once a year. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: bump version to v0.1.18 (#3) First Rig A release on the new S3 endpoint. Pairs with v0.1.19/v0.1.20 to validate two consecutive auto-updates per platform before Plan 3. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: bump version to v0.1.19 (#4) Second Rig A release. Validates v0.1.18 → v0.1.19 auto-update via S3 endpoint on macOS. Version bump alone is the visible swap signal — no UI churn needed. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: bump version to v0.1.20 (#5) Third Rig A release. Validates v0.1.19 → v0.1.20 auto-update on macOS, completing the two-consecutive-auto-updates bar before Plan 3. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 985405c commit 6919476

5 files changed

Lines changed: 99 additions & 27 deletions

File tree

.github/workflows/build.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ jobs:
6161
ref: ${{ inputs.ref }}
6262
fetch-depth: 0
6363

64+
- name: Verify required macOS entitlements
65+
if: runner.os == 'macOS'
66+
shell: bash
67+
run: |
68+
if ! grep -q "com.apple.security.network.client" frontend/src-tauri/entitlements.plist; then
69+
echo "::error::Missing com.apple.security.network.client entitlement — updater will silently fail (hardened runtime blocks HTTP from Rust)"
70+
exit 1
71+
fi
72+
6473
- name: Get version from tauri.conf.json.
6574
id: get-version
6675
shell: bash

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "meetily",
3-
"version": "0.1.16",
3+
"version": "0.1.20",
44
"private": true,
55
"main": "electron/main.js",
66
"scripts": {

frontend/src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "meetily"
3-
version = "0.1.16"
3+
version = "0.1.20"
44
description = "A Tauri App for meeting minutes"
55
authors = ["Sujith S"]
66
license = "MIT"

frontend/src-tauri/src/lib.rs

Lines changed: 86 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,51 +4,109 @@ use std::sync::Mutex as StdMutex;
44

55
/// Debug command to manually test updater connectivity and version comparison.
66
/// Bypasses the Tauri updater plugin entirely to diagnose issues.
7+
///
8+
/// Keep this endpoint list in sync with `tauri.conf.json`'s
9+
/// `plugins.updater.endpoints` — drift makes the report misleading.
710
#[tauri::command]
811
async fn debug_check_update() -> Result<String, String> {
9-
let url = "https://github.com/AzimovS/meetily/releases/latest/download/latest.json";
12+
const ENDPOINTS: &[(&str, &str)] = &[
13+
(
14+
"S3 (primary)",
15+
"https://s3-dcl1.ethquokkaops.io/automation-public/meetily-updates/latest.json",
16+
),
17+
(
18+
"AzimovS GitHub Releases (fallback)",
19+
"https://github.com/AzimovS/meetily/releases/latest/download/latest.json",
20+
),
21+
];
1022
let current_version = env!("CARGO_PKG_VERSION");
1123

12-
let mut report = format!("=== Updater Debug Report ===\n");
13-
report.push_str(&format!("Compiled version: {}\n", current_version));
14-
report.push_str(&format!("Endpoint: {}\n\n", url));
15-
16-
// Step 1: Fetch latest.json
1724
let client = reqwest::Client::builder()
1825
.user_agent("tauri-plugin-updater/debug")
1926
.build()
2027
.map_err(|e| format!("Failed to create HTTP client: {}", e))?;
2128

22-
let response = client.get(url).send().await
23-
.map_err(|e| format!("HTTP request FAILED: {} (this means network is blocked or endpoint unreachable)", e))?;
29+
let mut report = format!("=== Updater Debug Report ===\n");
30+
report.push_str(&format!("Compiled version: {}\n", current_version));
31+
report.push_str(&format!("Endpoints to probe: {}\n", ENDPOINTS.len()));
32+
33+
for &(label, url) in ENDPOINTS {
34+
report.push_str(&format!("\n--- {} ---\n", label));
35+
report.push_str(&format!("URL: {}\n", url));
36+
probe_endpoint(&client, url, current_version, &mut report).await;
37+
}
38+
39+
Ok(report)
40+
}
41+
42+
async fn probe_endpoint(
43+
client: &reqwest::Client,
44+
url: &str,
45+
current_version: &str,
46+
report: &mut String,
47+
) {
48+
// Step 1: Fetch latest.json
49+
let response = match client.get(url).send().await {
50+
Ok(r) => r,
51+
Err(e) => {
52+
report.push_str(&format!(
53+
"HTTP request FAILED: {} (network blocked or endpoint unreachable)\n",
54+
e
55+
));
56+
return;
57+
}
58+
};
2459

2560
let status = response.status();
2661
report.push_str(&format!("HTTP status: {}\n", status));
2762

2863
if !status.is_success() {
29-
report.push_str(&format!("ERROR: Non-success status. Body: {}\n",
30-
response.text().await.unwrap_or_default()));
31-
return Ok(report);
64+
report.push_str(&format!(
65+
"ERROR: Non-success status. Body: {}\n",
66+
response.text().await.unwrap_or_default()
67+
));
68+
return;
3269
}
3370

34-
let body = response.text().await
35-
.map_err(|e| format!("Failed to read response body: {}", e))?;
71+
let body = match response.text().await {
72+
Ok(b) => b,
73+
Err(e) => {
74+
report.push_str(&format!("Failed to read response body: {}\n", e));
75+
return;
76+
}
77+
};
3678

3779
// Step 2: Parse JSON
38-
let json: serde_json::Value = serde_json::from_str(&body)
39-
.map_err(|e| format!("Failed to parse JSON: {}. Body: {}", e, &body[..200.min(body.len())]))?;
80+
let json: serde_json::Value = match serde_json::from_str(&body) {
81+
Ok(v) => v,
82+
Err(e) => {
83+
report.push_str(&format!(
84+
"Failed to parse JSON: {}. Body: {}\n",
85+
e,
86+
&body[..200.min(body.len())]
87+
));
88+
return;
89+
}
90+
};
4091

4192
let remote_version = json["version"].as_str().unwrap_or("MISSING");
4293
report.push_str(&format!("Remote version: {}\n", remote_version));
4394

4495
// Step 3: Check platforms
4596
if let Some(platforms) = json["platforms"].as_object() {
46-
report.push_str(&format!("Platforms: {:?}\n", platforms.keys().collect::<Vec<_>>()));
97+
report.push_str(&format!(
98+
"Platforms: {:?}\n",
99+
platforms.keys().collect::<Vec<_>>()
100+
));
47101
if let Some(darwin) = platforms.get("darwin-aarch64") {
48-
report.push_str(&format!("darwin-aarch64 URL: {}\n",
49-
darwin["url"].as_str().unwrap_or("MISSING")));
50-
report.push_str(&format!("darwin-aarch64 sig length: {}\n",
51-
darwin["signature"].as_str().map(|s| s.len()).unwrap_or(0)));
102+
report.push_str(&format!(
103+
"darwin-aarch64 URL: {}\n",
104+
darwin["url"].as_str().unwrap_or("MISSING")
105+
));
106+
report.push_str(&format!(
107+
"darwin-aarch64 sig length: {}\n",
108+
darwin["signature"].as_str().map(|s| s.len()).unwrap_or(0)
109+
));
52110
} else {
53111
report.push_str("ERROR: darwin-aarch64 platform MISSING\n");
54112
}
@@ -58,10 +116,14 @@ async fn debug_check_update() -> Result<String, String> {
58116

59117
// Step 4: Version comparison
60118
let remote_clean = remote_version.trim_start_matches('v');
61-
report.push_str(&format!("\nVersion comparison: {} (remote) vs {} (current)\n", remote_clean, current_version));
62-
report.push_str(&format!("Update available: {}\n", remote_clean != current_version && remote_clean > current_version));
63-
64-
Ok(report)
119+
report.push_str(&format!(
120+
"Version comparison: {} (remote) vs {} (current)\n",
121+
remote_clean, current_version
122+
));
123+
report.push_str(&format!(
124+
"Update available: {}\n",
125+
remote_clean != current_version && remote_clean > current_version
126+
));
65127
}
66128
// Removed unused import
67129

frontend/src-tauri/tauri.conf.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
33
"productName": "meetily",
4-
"version": "0.1.16",
4+
"version": "0.1.20",
55
"identifier": "com.meetily.ai",
66
"build": {
77
"frontendDist": "../out",
@@ -119,6 +119,7 @@
119119
"updater": {
120120
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDM4QkU1NDdCNTk5NURGMUUKUldRZTM1VlplMVMrT09KQk1XeSt2N2dWQUVJNkxqdkpFVEpNY3EwNnRjQ2xNcUU5M0g5UDdiVHYK",
121121
"endpoints": [
122+
"https://s3-dcl1.ethquokkaops.io/automation-public/meetily-updates/latest.json",
122123
"https://github.com/AzimovS/meetily/releases/latest/download/latest.json"
123124
]
124125
}

0 commit comments

Comments
 (0)