Skip to content

Commit 716e71d

Browse files
committed
fix: rust fmt, batch syntax error, k6 json import, ios workspace, kotlin patch
- Run cargo fmt across all contracts: fixes formatting diffs that were causing cargo fmt --check to fail in CI (access_control, api, batch, credit, metering, oracle, proxy, security, subscription modules) - Remove stray match arm in contracts/batch/src/lib.rs:264 that had drifted outside any match expression, causing a compile-time parse error and blocking cargo fmt from processing the file - Fix k6 baseline JSON import: ES module import of .json files is evaluated as JavaScript source by Goja, failing at string-keyed properties. Use JSON.parse(open()) instead, which is the correct k6 API for reading files in the init phase - Fix Detox iOS workspace case: expo prebuild generates SubTrackr.xcworkspace from the app name field but .detoxrc.js was pointing to subtrackr (lowercase), causing xcodebuild to report the workspace does not exist - Strengthen e2e Kotlin patch: the previous sed on android/build.gradle did not reach the four expo Gradle included builds which each declare their own kotlin("jvm") version "1.9.24" independently. Patch all four node_modules plugin build.gradle.kts files directly before Gradle runs
1 parent 2ab1741 commit 716e71d

21 files changed

Lines changed: 362 additions & 272 deletions

File tree

.detoxrc.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ module.exports = {
1818
type: 'ios.app',
1919
binaryPath: 'ios/build/Build/Products/Debug-iphonesimulator/SubTrackr.app',
2020
build:
21-
'xcodebuild -workspace ios/subtrackr.xcworkspace -scheme subtrackr -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build',
21+
'xcodebuild -workspace ios/SubTrackr.xcworkspace -scheme SubTrackr -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build',
2222
},
2323
'ios.release': {
2424
type: 'ios.app',
2525
binaryPath: 'ios/build/Build/Products/Release-iphonesimulator/SubTrackr.app',
2626
build:
27-
'xcodebuild -workspace ios/subtrackr.xcworkspace -scheme subtrackr -configuration Release -sdk iphonesimulator -derivedDataPath ios/build',
27+
'xcodebuild -workspace ios/SubTrackr.xcworkspace -scheme SubTrackr -configuration Release -sdk iphonesimulator -derivedDataPath ios/build',
2828
},
2929
'android.debug': {
3030
type: 'android.apk',

.github/workflows/e2e-detox.yml

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,20 @@ jobs:
8282
java-version: '17'
8383
- name: Expo Prebuild
8484
run: npx expo prebuild -p android
85-
- name: Patch Kotlin version for React Native 0.85 compatibility
85+
- name: Patch Kotlin 1.9 to 2.1.20 in expo Gradle included builds
8686
run: |
87-
if [ -f android/build.gradle ]; then
88-
sed -i 's/kotlinVersion = "1\.[0-9][^"]*"/kotlinVersion = "2.1.20"/' android/build.gradle
89-
echo "android/build.gradle kotlinVersion after patch:"
90-
grep "kotlinVersion" android/build.gradle || echo "(not found)"
91-
fi
87+
for f in \
88+
node_modules/expo-dev-launcher/expo-dev-launcher-gradle-plugin/build.gradle.kts \
89+
node_modules/expo-modules-autolinking/android/expo-gradle-plugin/build.gradle.kts \
90+
node_modules/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin-shared/build.gradle.kts \
91+
node_modules/expo-modules-core/expo-module-gradle-plugin/build.gradle.kts; do
92+
if [ -f "$f" ]; then
93+
sed -i 's/version "1\.[0-9][^"]*"/version "2.1.20"/g' "$f"
94+
echo "Patched $f: $(grep -E 'version \"[0-9]' $f | head -2)"
95+
fi
96+
done
97+
[ -f android/build.gradle ] && \
98+
sed -i 's/kotlinVersion = "1\.[0-9][^"]*"/kotlinVersion = "2.1.20"/' android/build.gradle || true
9299
- name: Build Detox Android
93100
run: npm run e2e:build-android
94101
- name: Detox Android — core lifecycle

contracts/access_control/src/lib.rs

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
mod roles;
44

5-
use roles::{contains_permission, role_permissions, DataKey, Delegation, MultisigAction, MultisigProposal};
5+
use roles::{
6+
contains_permission, role_permissions, DataKey, Delegation, MultisigAction, MultisigProposal,
7+
};
68
use soroban_sdk::{contract, contractimpl, Address, Env, Symbol, Vec};
79
use subtrackr_types::{Permission, Role, RoleChangeAction, RoleChangeEntry};
810

@@ -41,7 +43,10 @@ fn save_role_change(
4143
}
4244

4345
fn get_user_permissions(env: &Env, user: &Address) -> Vec<Permission> {
44-
let roles_opt: Option<Vec<Role>> = env.storage().instance().get(&DataKey::UserRoles(user.clone()));
46+
let roles_opt: Option<Vec<Role>> = env
47+
.storage()
48+
.instance()
49+
.get(&DataKey::UserRoles(user.clone()));
4550
let mut all_perms: Vec<Permission> = Vec::new(env);
4651

4752
if let Some(roles) = roles_opt {
@@ -108,7 +113,13 @@ impl RoleManager {
108113
.instance()
109114
.set(&DataKey::MultisigProposalCount, &0u64);
110115

111-
save_role_change(&env, &admin, &Role::Admin, RoleChangeAction::Granted, &admin);
116+
save_role_change(
117+
&env,
118+
&admin,
119+
&Role::Admin,
120+
RoleChangeAction::Granted,
121+
&admin,
122+
);
112123

113124
env.events().publish(
114125
(Symbol::new(&env, "access_control_initialized"),),
@@ -157,18 +168,10 @@ impl RoleManager {
157168
.instance()
158169
.set(&DataKey::UserRoles(user.clone()), &user_roles);
159170

160-
save_role_change(
161-
&env,
162-
&user,
163-
&role,
164-
RoleChangeAction::Granted,
165-
&caller,
166-
);
171+
save_role_change(&env, &user, &role, RoleChangeAction::Granted, &caller);
167172

168-
env.events().publish(
169-
(Symbol::new(&env, "role_granted"),),
170-
(caller, user, role),
171-
);
173+
env.events()
174+
.publish((Symbol::new(&env, "role_granted"),), (caller, user, role));
172175
}
173176

174177
pub fn revoke_role(env: Env, caller: Address, user: Address, role: Role) {
@@ -273,22 +276,15 @@ impl RoleManager {
273276
}
274277
}
275278

276-
save_role_change(
277-
&env,
278-
&user,
279-
&role,
280-
RoleChangeAction::Revoked,
281-
&caller,
282-
);
279+
save_role_change(&env, &user, &role, RoleChangeAction::Revoked, &caller);
283280

284-
env.events().publish(
285-
(Symbol::new(&env, "role_revoked"),),
286-
(caller, user, role),
287-
);
281+
env.events()
282+
.publish((Symbol::new(&env, "role_revoked"),), (caller, user, role));
288283
}
289284

290285
pub fn has_permission(env: Env, user: Address, permission: Permission) -> bool {
291-
if env.storage()
286+
if env
287+
.storage()
292288
.instance()
293289
.get::<_, bool>(&DataKey::EmergencyPaused)
294290
.unwrap_or(false)
@@ -367,10 +363,7 @@ impl RoleManager {
367363
"Unauthorized: missing DelegatePermission"
368364
);
369365

370-
let expires_at = env
371-
.ledger()
372-
.timestamp()
373-
.saturating_add(duration_secs);
366+
let expires_at = env.ledger().timestamp().saturating_add(duration_secs);
374367

375368
let delegation = Delegation {
376369
delegator: delegator.clone(),
@@ -388,7 +381,12 @@ impl RoleManager {
388381
);
389382
}
390383

391-
pub fn revoke_delegation(env: Env, delegator: Address, delegate: Address, permission: Permission) {
384+
pub fn revoke_delegation(
385+
env: Env,
386+
delegator: Address,
387+
delegate: Address,
388+
permission: Permission,
389+
) {
392390
delegator.require_auth();
393391

394392
let key = DataKey::Delegation(delegate.clone(), permission.clone());
@@ -490,11 +488,7 @@ impl RoleManager {
490488
entries
491489
}
492490

493-
pub fn propose_multisig_action(
494-
env: Env,
495-
proposer: Address,
496-
action: MultisigAction,
497-
) -> u64 {
491+
pub fn propose_multisig_action(env: Env, proposer: Address, action: MultisigAction) -> u64 {
498492
proposer.require_auth();
499493
assert!(
500494
!env.storage()
@@ -605,10 +599,7 @@ impl RoleManager {
605599
);
606600

607601
let now = env.ledger().timestamp();
608-
assert!(
609-
now >= proposal.execute_after,
610-
"Timelock not yet elapsed"
611-
);
602+
assert!(now >= proposal.execute_after, "Timelock not yet elapsed");
612603

613604
match proposal.action {
614605
MultisigAction::SetEmergencyAdmin(ref new_admin) => {

contracts/api/src/auth.rs

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -107,19 +107,12 @@ pub fn revoke_api_key(env: &Env, caller: Address, key_id: ApiKeyId, now: u64) {
107107

108108
key.status = ApiKeyStatus::Revoked;
109109
key.revoked_at = now;
110-
env.storage()
111-
.instance()
112-
.set(&DataKey::ApiKey(key_id), &key);
110+
env.storage().instance().set(&DataKey::ApiKey(key_id), &key);
113111

114112
log_audit(env, key_id, String::from_str(env, "revoked"), caller, now);
115113
}
116114

117-
pub fn rotate_api_key(
118-
env: &Env,
119-
caller: Address,
120-
key_id: ApiKeyId,
121-
now: u64,
122-
) -> Bytes {
115+
pub fn rotate_api_key(env: &Env, caller: Address, key_id: ApiKeyId, now: u64) -> Bytes {
123116
let mut key: ApiKey = env
124117
.storage()
125118
.instance()
@@ -135,9 +128,7 @@ pub fn rotate_api_key(
135128
let new_hash = hash_key_bytes(env, &new_raw);
136129
key.key_hash = new_hash;
137130
key.last_used_at = 0;
138-
env.storage()
139-
.instance()
140-
.set(&DataKey::ApiKey(key_id), &key);
131+
env.storage().instance().set(&DataKey::ApiKey(key_id), &key);
141132

142133
log_audit(env, key_id, String::from_str(env, "rotated"), caller, now);
143134
new_raw
@@ -196,13 +187,7 @@ pub fn get_api_key_audit(env: &Env, key_id: ApiKeyId) -> Vec<ApiKeyAuditEntry> {
196187
entries
197188
}
198189

199-
fn log_audit(
200-
env: &Env,
201-
key_id: ApiKeyId,
202-
action: String,
203-
changed_by: Address,
204-
now: u64,
205-
) {
190+
fn log_audit(env: &Env, key_id: ApiKeyId, action: String, changed_by: Address, now: u64) {
206191
let mut count: u64 = env
207192
.storage()
208193
.instance()

contracts/api/src/lib.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,7 @@ impl SubTrackrApi {
3333

3434
/// Create a new API key. Returns `(key_id, raw_key_bytes)`.
3535
/// The raw key is returned exactly once and must be stored off-chain.
36-
pub fn create_api_key(
37-
env: Env,
38-
owner: Address,
39-
config: ApiKeyConfig,
40-
) -> (ApiKeyId, Bytes) {
36+
pub fn create_api_key(env: Env, owner: Address, config: ApiKeyConfig) -> (ApiKeyId, Bytes) {
4137
owner.require_auth();
4238
let now = env.ledger().timestamp();
4339
auth::create_api_key(&env, owner, config, now)

contracts/api/src/ratelimit.rs

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
use soroban_sdk::Env;
2-
use subtrackr_types::{
3-
ApiKey, ApiKeyId, ApiUsageRecord, RateLimitStatus, TimeRange, UsageReport,
4-
};
2+
use subtrackr_types::{ApiKey, ApiKeyId, ApiUsageRecord, RateLimitStatus, TimeRange, UsageReport};
53

64
use crate::DataKey;
75

@@ -20,17 +18,17 @@ fn bump_window(env: &Env, key: DataKey, now: u64, period: u64) -> (u32, u64) {
2018
Some(r) if r.window_start == ws => r.count + 1,
2119
_ => 1,
2220
};
23-
env.storage()
24-
.instance()
25-
.set(&key, &ApiUsageRecord { window_start: ws, count });
21+
env.storage().instance().set(
22+
&key,
23+
&ApiUsageRecord {
24+
window_start: ws,
25+
count,
26+
},
27+
);
2628
(count, ws + period)
2729
}
2830

29-
pub fn check_rate_limit(
30-
env: &Env,
31-
key: &ApiKey,
32-
now: u64,
33-
) -> RateLimitStatus {
31+
pub fn check_rate_limit(env: &Env, key: &ApiKey, now: u64) -> RateLimitStatus {
3432
let cfg = &key.rate_limit;
3533

3634
let (min_count, min_reset) = bump_window(
@@ -88,11 +86,7 @@ pub fn check_rate_limit(
8886
}
8987
}
9088

91-
pub fn get_api_usage(
92-
env: &Env,
93-
key_id: ApiKeyId,
94-
period: TimeRange,
95-
) -> UsageReport {
89+
pub fn get_api_usage(env: &Env, key_id: ApiKeyId, period: TimeRange) -> UsageReport {
9690
let mut total: u32 = 0;
9791
let mut ws = window_start(period.start, SECS_PER_MINUTE);
9892
let end = period.end;
@@ -114,11 +108,7 @@ pub fn get_api_usage(
114108
}
115109
}
116110

117-
pub fn calculate_api_charge(
118-
env: &Env,
119-
key: &ApiKey,
120-
period: TimeRange,
121-
) -> i128 {
111+
pub fn calculate_api_charge(env: &Env, key: &ApiKey, period: TimeRange) -> i128 {
122112
let usage = get_api_usage(env, key.id, period);
123113
let billable = usage.total_requests.saturating_sub(1000);
124114
let price_per_k = key.usage_tier.price_per_thousand();

contracts/api/src/test.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#![cfg(test)]
22

3-
use soroban_sdk::{
4-
testutils::Address as _, testutils::Ledger as _, Address, Bytes, BytesN, Env,
5-
};
3+
use soroban_sdk::{testutils::Address as _, testutils::Ledger as _, Address, Bytes, BytesN, Env};
64
use subtrackr_types::{ApiKeyConfig, ApiKeyStatus, RateLimitConfig, TimeRange, UsageTier};
75

86
use crate::{SubTrackrApi, SubTrackrApiClient};
@@ -158,8 +156,12 @@ fn test_list_api_keys_by_owner() {
158156
let mut found1 = false;
159157
let mut found2 = false;
160158
for k in keys.iter() {
161-
if k.id == id1 { found1 = true; }
162-
if k.id == id2 { found2 = true; }
159+
if k.id == id1 {
160+
found1 = true;
161+
}
162+
if k.id == id2 {
163+
found2 = true;
164+
}
163165
}
164166
assert!(found1);
165167
assert!(found2);
@@ -179,7 +181,11 @@ fn test_audit_trail() {
179181
client.revoke_api_key(&owner, &key_id);
180182

181183
let audit = client.get_api_key_audit(&key_id);
182-
assert_eq!(audit.len(), 2, "Should have rotate and revoke audit entries");
184+
assert_eq!(
185+
audit.len(),
186+
2,
187+
"Should have rotate and revoke audit entries"
188+
);
183189
assert_eq!(
184190
audit.get(0).unwrap().action,
185191
soroban_sdk::String::from_str(&env, "rotated")
@@ -268,10 +274,7 @@ fn test_rate_limit_per_hour() {
268274
client.check_rate_limit(&key_id, &key_hash);
269275
}
270276
let status = client.check_rate_limit(&key_id, &key_hash);
271-
assert!(
272-
!status.is_allowed,
273-
"Should be blocked by hourly limit"
274-
);
277+
assert!(!status.is_allowed, "Should be blocked by hourly limit");
275278
}
276279

277280
#[test]

0 commit comments

Comments
 (0)