fix(aw-sync): forward API key from server config, stop panicking on 401 - #640
Conversation
…n 401 Two bugs compounded to cause a restart loop when auth is configured: 1. AwClient was always created with api_key=None, so requests to an authenticated server always got 401. 2. Several .unwrap() calls in the AwClient AccessMethod impl (get_buckets, get_events, get_event_count, create_bucket) panicked on any HTTP error instead of propagating it as an Err. Fixes: - Add get_server_api_key() to util.rs, reading [auth] api_key from the same server config file already parsed for the port. - Use AwClient::new_with_api_key() in main() with the key read above. - Replace all .unwrap() calls in the AwClient AccessMethod impl with .map_err(|e| e.to_string()), so HTTP errors (including 401) become recoverable errors instead of panics. - Also fix get_bucket to not panic on unexpected status codes. Fixes ActivityWatch#639
Greptile SummaryThis PR forwards local aw-server authentication into aw-sync while replacing panic-prone HTTP handling with propagated errors.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart LR
CLI[aw-sync CLI options] --> Guard{Host is loopback?}
Guard -->|Yes| Config[Read selected aw-server config]
Guard -->|No| Defaults[Use default port without API key]
Config --> Client[Construct AwClient]
Defaults --> Client
Client -->|HTTP with optional Bearer key| Server[aw-server]
Server -->|HTTP failure| Error[Propagate sync error]
Reviews (5): Last reviewed commit: "fix(aw-sync): format IPv6 hosts for clie..." | Re-trigger Greptile |
|
Addressed the Greptile security finding in 9173349. The original code always read the local API key and forwarded it to whatever let is_localhost = matches!(opts.host.as_str(), "127.0.0.1" | "::1" | "localhost");
let api_key = if is_localhost {
util::get_server_api_key(opts.testing)?
} else {
None
};For the non-localhost case ( |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #640 +/- ##
==========================================
+ Coverage 70.81% 76.19% +5.38%
==========================================
Files 51 63 +12
Lines 2916 5126 +2210
==========================================
+ Hits 2065 3906 +1841
- Misses 851 1220 +369 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
@greptileai review |
|
Addressed the remaining Greptile summary finding in
Verification:
@greptileai review |
|
@greptileai review |
✅ Review Adjudication — Ready for MergeAll 3 Greptile threads resolved. Greptile convergence cap hit at attempt 3 (3/5 score), so re-triggering is stopped — the remaining findings were assessed and dismissed. Dismissed (false positives):
Previously fixed:
CI status: All jobs green (Qt + Tauri, all platforms). Greptile: 3/5 with no unaddressed findings (score reflects iteration count, not unresolved issues). Converged after 3 rounds. Acceptable to ship. |
|
Found and fixed the new Greptile summary finding in Bare IPv6 input ( Verified locally:
Fresh CI is running. This supersedes my earlier merge-ready adjudication: the summary-level IPv6 finding was real, not resolved by |
|
@greptileai review |
|
CI-green and mergeable (Greptile 5/5) — waiting only on a maintainer click. This PR is ready to merge, but the bot has pull-only access to this repo and can't self-merge — surfacing it here so it isn't lost. The monitoring loop will stop re-flagging it now that this note is posted. |
Fixes #639
What broke
When
[auth] api_keyis set in the aw-server-rust config,aw-syncenters a crash loop because of two compounding bugs:AwClient::new()always passesNoneforapi_key, so every request to an authenticated server returns 401.AwClientimplementation ofAccessMethod(includingget_buckets, called at startup) used.unwrap()instead of propagating errors — turning any HTTP error into a hard crash.Fix
aw-sync/src/util.rsreads the server port and[auth] api_keytogether from the selected server config.aw-sync/src/main.rsaccepts-c/--config, matching aw-server's config override, and passes the key toAwClient::new_with_api_key().127.0.0.1,::1, orlocalhost). A caller-selected remote--hostnever causes the local credential file to be read or its key to be attached.aw-sync/src/accessmethod.rspropagates HTTP failures instead of panicking inget_buckets,get_events,get_event_count,create_bucket, and non-404get_bucketresponses.Testing
cargo test -p aw-sync --all-targets --no-fail-fastcargo check -p aw-sync --all-targetscargo fmt --all -- --checkcargo clippycargo run -q -p aw-sync --bin aw-sync -- --help(verified-c, --config <CONFIG>)Added focused tests for custom config port/key parsing, production/testing fallback ports, and exact loopback-host classification.
Usage with a custom server config
Pass the same path to both processes:
An explicit aw-sync
--portstill takes precedence over the port read from that config.Out of scope
Android sync uses a JNI-provided port and has no server-config path. Passing Android auth credentials through JNI is a separate interface change and is not included here.