Skip to content

fix mermaid diagram placement#29

Open
dcbuild3r wants to merge 203 commits into
mainfrom
dev
Open

fix mermaid diagram placement#29
dcbuild3r wants to merge 203 commits into
mainfrom
dev

Conversation

@dcbuild3r
Copy link
Copy Markdown
Collaborator

@dcbuild3r dcbuild3r commented Apr 27, 2026

Summary

  • Move the landing README workflow diagrams to the end, immediately before release notes.

tfe-app Bot and others added 30 commits December 4, 2025 11:51
…fetch, Android logging, iOS UI tests, and docs (#2)

* initial commit

* Fix Android UniFFI integration and benchmark display

This commit resolves multiple issues preventing the Android app from
loading the Rust native library and correctly displaying benchmark results.

Changes implemented:

1. Added JNA dependency (android/app/build.gradle)
   - Added net.java.dev.jna:jna:5.14.0@aar dependency
   - Required for UniFFI's Kotlin bindings to interface with native code
   - Also added NDK version specification and benchmark spec asset directories

2. Fixed library naming mismatch (crates/sample-fns/Cargo.toml)
   - Set explicit lib name = "sample_fns" (not uniffi_sample_fns)
   - Changed crate-type to ["lib", "cdylib", "staticlib"] for UniFFI
   - Added UniFFI dependencies and build configuration
   - Migrated from JNI to UniFFI for cleaner FFI bindings

3. Updated sync script for library renaming (scripts/sync-android-libs.sh)
   - Added TARGET_LIB_NAME variable to rename .so during copy
   - Rust builds libsample_fns.so but JNA expects libuniffi_sample_fns.so
   - Script now copies and renames: libsample_fns.so -> libuniffi_sample_fns.so
   - Ensures FFI symbol prefixes match UniFFI expectations

4. Updated Android MainActivity (android/app/src/main/java/dev/world/bench/MainActivity.kt)
   - Changed System.loadLibrary("sample_fns") to System.loadLibrary("uniffi_sample_fns")
   - Migrated from JNI to UniFFI-generated Kotlin bindings
   - Updated benchmark display to show microseconds (μs) instead of milliseconds
   - Added raw nanosecond display alongside formatted values
   - Improved error handling with UniFFI's BenchException variants
   - Added support for loading benchmark specs from assets (bench_spec.json)

Root cause analysis:
- UniFFI generates Kotlin bindings that expect library name "uniffi_<namespace>"
- The namespace from sample_fns.udl is "sample_fns"
- JNA looks for libuniffi_sample_fns.so based on this naming convention
- Rust builds libsample_fns.so by default (from crate name)
- Solution: Keep Rust lib name simple, rename during Android integration

Benchmark display fix:
- Functions execute in 0-42 nanoseconds (extremely fast)
- Previous millisecond display showed "0.000 ms" for all samples
- Now displays in microseconds with raw nanosecond values for clarity
- Example: "0.042 μs (42 ns)" instead of "0.000 ms"

Testing:
- App builds successfully with ./gradlew :app:assembleDebug
- Native library loads without UnsatisfiedLinkError
- Benchmarks execute and display timing results correctly
- Fibonacci(24) averages ~17 nanoseconds per iteration on ARM64

* Android: log benchmark JSON and fix test matcher

* iOS: add UI test target and accessibility id

* bench-cli: add BrowserStack fetch and artifact download

* Commit remaining workspace changes

* Ignore generated build artifacts

* gitignore: exclude CLI-generated artifacts

- Add run-summary.json (benchmark run results)
- Add bench-config.toml (user configuration template)
- Add device-matrix.yaml (device matrix template)

These files are generated by bench-cli and should not be tracked in git.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* iOS: standardize time units to microseconds

Change benchmark result display from milliseconds (ms) to microseconds (μs)
to match Android's output format. This provides better granularity for
typical function benchmarks and makes cross-platform comparison easier.

Before: 0.045 ms
After:  45.320 μs (45320 ns)

Also add raw nanosecond values in parentheses to match Android formatting.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* bench-cli: add comprehensive BrowserStack client tests

Add 11 new tests covering:
- Client initialization and configuration
- URL construction and path handling
- Input validation for schedule/upload methods
- Error cases for missing artifacts
- Both Espresso (Android) and XCUITest (iOS) code paths

Also suppress dead_code warning for test-only with_base_url helper.

Test coverage increased from 1 to 12 tests for browserstack.rs module.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

---------

Co-authored-by: dcbuilder.eth <dcbuilder@protonmail.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
….1.5) (#4)

* Initial commit

* Add .github/workflows/relyance-sci.yml

* initial commit

* Fix Android UniFFI integration and benchmark display

This commit resolves multiple issues preventing the Android app from
loading the Rust native library and correctly displaying benchmark results.

Changes implemented:

1. Added JNA dependency (android/app/build.gradle)
   - Added net.java.dev.jna:jna:5.14.0@aar dependency
   - Required for UniFFI's Kotlin bindings to interface with native code
   - Also added NDK version specification and benchmark spec asset directories

2. Fixed library naming mismatch (crates/sample-fns/Cargo.toml)
   - Set explicit lib name = "sample_fns" (not uniffi_sample_fns)
   - Changed crate-type to ["lib", "cdylib", "staticlib"] for UniFFI
   - Added UniFFI dependencies and build configuration
   - Migrated from JNI to UniFFI for cleaner FFI bindings

3. Updated sync script for library renaming (scripts/sync-android-libs.sh)
   - Added TARGET_LIB_NAME variable to rename .so during copy
   - Rust builds libsample_fns.so but JNA expects libuniffi_sample_fns.so
   - Script now copies and renames: libsample_fns.so -> libuniffi_sample_fns.so
   - Ensures FFI symbol prefixes match UniFFI expectations

4. Updated Android MainActivity (android/app/src/main/java/dev/world/bench/MainActivity.kt)
   - Changed System.loadLibrary("sample_fns") to System.loadLibrary("uniffi_sample_fns")
   - Migrated from JNI to UniFFI-generated Kotlin bindings
   - Updated benchmark display to show microseconds (μs) instead of milliseconds
   - Added raw nanosecond display alongside formatted values
   - Improved error handling with UniFFI's BenchException variants
   - Added support for loading benchmark specs from assets (bench_spec.json)

Root cause analysis:
- UniFFI generates Kotlin bindings that expect library name "uniffi_<namespace>"
- The namespace from sample_fns.udl is "sample_fns"
- JNA looks for libuniffi_sample_fns.so based on this naming convention
- Rust builds libsample_fns.so by default (from crate name)
- Solution: Keep Rust lib name simple, rename during Android integration

Benchmark display fix:
- Functions execute in 0-42 nanoseconds (extremely fast)
- Previous millisecond display showed "0.000 ms" for all samples
- Now displays in microseconds with raw nanosecond values for clarity
- Example: "0.042 μs (42 ns)" instead of "0.000 ms"

Testing:
- App builds successfully with ./gradlew :app:assembleDebug
- Native library loads without UnsatisfiedLinkError
- Benchmarks execute and display timing results correctly
- Fibonacci(24) averages ~17 nanoseconds per iteration on ARM64

* Android: log benchmark JSON and fix test matcher

* iOS: add UI test target and accessibility id

* bench-cli: add BrowserStack fetch and artifact download

* Commit remaining workspace changes

* Ignore generated build artifacts

* gitignore: exclude CLI-generated artifacts

- Add run-summary.json (benchmark run results)
- Add bench-config.toml (user configuration template)
- Add device-matrix.yaml (device matrix template)

These files are generated by bench-cli and should not be tracked in git.

* iOS: standardize time units to microseconds

Change benchmark result display from milliseconds (ms) to microseconds (μs)
to match Android's output format. This provides better granularity for
typical function benchmarks and makes cross-platform comparison easier.

Before: 0.045 ms
After:  45.320 μs (45320 ns)

Also add raw nanosecond values in parentheses to match Android formatting.

* bench-cli: add comprehensive BrowserStack client tests

Add 11 new tests covering:
- Client initialization and configuration
- URL construction and path handling
- Input validation for schedule/upload methods
- Error cases for missing artifacts
- Both Espresso (Android) and XCUITest (iOS) code paths

Also suppress dead_code warning for test-only with_base_url helper.

Test coverage increased from 1 to 12 tests for browserstack.rs module.

* Migrate from UniFFI UDL to proc macros

Replace manual UDL file with proc macro attributes for better developer
experience and single source of truth in Rust code.

## Changes

### sample-fns crate:
- Add `#[derive(uniffi::Record)]` to BenchSpec, BenchSample, BenchReport
- Add `#[derive(uniffi::Error)]` with `#[uniffi(flat_error)]` to BenchError
- Add `#[uniffi::export]` to run_benchmark function
- Add `uniffi::setup_scaffolding!()` macro to generate scaffolding
- Remove UDL file (sample_fns.udl)
- Update Cargo.toml: enable uniffi "cli" feature
- Update build.rs: remove UDL scaffolding generation (now proc macro-based)
- Update generate-bindings.rs: use library_mode instead of UDL-based generation

### Generated bindings:
- Kotlin bindings regenerated from proc macros
- Swift bindings regenerated from proc macros
- FFI interface remains identical (no breaking changes)

## Benefits

1. **Single source of truth**: Rust code is the only place to define types
2. **Better IDE support**: Type checking and autocomplete in Rust
3. **Automatic sync**: No manual UDL maintenance required
4. **Improved DevEx**: Attributes are inline with type definitions
5. **Type safety**: Compiler enforces FFI boundaries

## Migration notes

- UniFFI 0.28 supports both UDL and proc macros
- Generated bindings are functionally identical
- All tests pass (22 tests)
- CLI demo verified working
- Android/iOS apps use same generated bindings

* docs: update for proc macros and dual workflows

Update documentation to reflect:
1. UniFFI proc macros (no UDL file needed)
2. Two distinct workflows: Local Development vs BrowserStack

## README.md Changes

- Add "Testing Workflows" section with clear separation
- Update UniFFI section for proc macro mode with examples
- Add comprehensive BrowserStack workflow section:
  - Android + Espresso step-by-step
  - iOS + XCUITest step-by-step
  - Config file examples
  - BrowserStack features overview
- Reorganize into Local Development vs BrowserStack sections
- Remove outdated UDL references
- Add requirements for both workflows

## CLAUDE.md Changes

- Update Mobile Integration Flow to mention proc macros
- Rewrite FFI Boundary section with proc macro examples
- Update "Adding New Benchmark Functions" workflow
- Remove references to sample_fns.udl
- Add note that no UDL file is needed

These changes make it much clearer for users:
- How to test locally (fast iteration)
- How to test on BrowserStack (real devices)
- How to add new FFI types with proc macros

* initial procmacros

* feat: Phase 1 - Transform mobile-bench-rs into bench-sdk library crate

This commit implements the complete Phase 1 MVP, transforming mobile-bench-rs
from a standalone tool into a library crate (bench-sdk) that can be imported
into any Rust project for mobile benchmarking.

## Core Features

### 1. Proc Macro System (bench-macros)
- Implement #[benchmark] attribute macro for automatic function registration
- Use inventory crate for compile-time collection, runtime discovery
- Generate fully-qualified function names (e.g., my_crate::my_function)

### 2. Core SDK Library (bench-sdk)
- **types.rs**: Core types (BenchError, Target, BuildConfig, BuildProfile, etc.)
- **registry.rs**: Function discovery via inventory::collect!()
  - discover_benchmarks(), find_benchmark(), list_benchmark_names()
- **runner.rs**: Execution engine with BenchmarkBuilder fluent API
- **codegen.rs**: Template generation system
  - Generates bench-mobile FFI wrapper crate with UniFFI
  - Creates Android/iOS project structures
  - Generates config files and examples
- **builders/android.rs**: Complete Android build pipeline
  - cargo-ndk integration for multi-ABI builds
  - JNI library syncing
  - Gradle APK generation
- **builders/ios.rs**: Complete iOS build pipeline
  - Multi-architecture builds (device + simulator)
  - xcframework creation with proper structure
  - Automatic code signing
  - XcodeGen integration

### 3. CLI Integration (bench-cli)
- Refactor to use SDK API as thin wrapper
- Add new commands:
  - init-sdk: Initialize benchmark project with templates
  - build: Build mobile artifacts using SDK builders
  - list: Discover and list all registered benchmarks
- Maintain backward compatibility with existing commands

### 4. Templates (templates/)
- **Android**: Gradle project, MainActivity, Espresso tests, resources
  - Templatized with package name, library name, etc.
  - Complete build.gradle, settings.gradle, AndroidManifest.xml
- **iOS**: XcodeGen project, SwiftUI app, XCUITest tests
  - Templatized with project name, bundle ID, etc.
  - Complete project.yml, Swift files, bridging headers

### 5. Example Project (examples/basic-benchmark)
- Migrate sample-fns to example demonstrating SDK usage
- Use #[benchmark] attributes with registry-based execution
- Full test coverage (6 passing tests)

## Architecture Changes

### Workspace Structure
```
mobile-bench-rs/
├── crates/
│   ├── bench-sdk/        # Core library (NEW, for crates.io)
│   ├── bench-macros/     # Proc macro crate (NEW)
│   ├── bench-cli/        # CLI tool (REFACTORED)
│   ├── bench-runner/     # Timing harness (UNCHANGED)
│   └── sample-fns/       # Legacy (DEPRECATED)
├── examples/
│   └── basic-benchmark/  # SDK example (NEW)
└── templates/            # Mobile app templates (NEW)
    ├── android/
    └── ios/
```

### Public API Surface
```rust
// Proc macro
#[benchmark]
fn my_function() { /* ... */ }

// Discovery
bench_sdk::discover_benchmarks() -> Vec<&BenchFunction>
bench_sdk::find_benchmark(name) -> Option<&BenchFunction>

// Execution
bench_sdk::run_benchmark(spec) -> Result<BenchReport>
BenchmarkBuilder::new(name).iterations(100).run()

// Builders
AndroidBuilder::new(root, crate_name).build(&config)
IosBuilder::new(root, crate_name).build(&config)

// Codegen
generate_project(&InitConfig) -> Result<PathBuf>
```

## Testing

All tests passing (25 total):
- bench-sdk: 12 tests
- basic-benchmark: 6 tests
- sample-fns: 6 tests (legacy)
- bench-runner: 1 test

## Documentation

- Updated README.md with Phase 1 information
- Inline rustdoc comments throughout
- Working example in examples/basic-benchmark
- Updated references in BUILD.md, TESTING.md

## Migration Path

Users can now:
1. Add bench-sdk to Cargo.toml
2. Annotate functions with #[benchmark]
3. Run `cargo bench-sdk init-sdk` to generate project
4. Run `cargo bench-sdk build` to build mobile artifacts
5. Run `cargo bench-sdk list` to discover benchmarks

## Future Work

Phase 1 provides the foundation for:
- Phase 2: Adaptive iterations, warmup detection
- Phase 3: Statistical analysis, baselines
- Phase 4: Full BrowserStack integration
- Phase 5: cargo bench harness, DevEx improvements
- Phase 6: Caching, reproducibility, CI optimization

* feat: wire sdk scaffolding and bindings

- Render Android/iOS templates with project-specific names and link user crate in bench-mobile

- Run UniFFI binding generation in SDK builders and ensure headers are packaged

- Route CLI builds through SDK builders and detect bench-mobile crate name

- Align Android JNI library naming (sample_fns) and update templates/scripts

- Improve binding generation tooling for ABI-aware Android builds

* docs: align build and binding workflow

- Document ABI-aware Android builds with UNIFFI_ANDROID_ABI

- Update binding regeneration steps to use scripts/generate-bindings.sh

- Simplify Android local/testing steps to use build-android-app.sh

* docs: add bench-sdk integration guide

- Add step-by-step setup for dependencies and annotations

- Document local Android/iOS testing workflow

- Document BrowserStack Espresso/XCUITest runs

* docs: expand integration guide

- Add prerequisites and clarify script availability

- Document CLI build path when scripts are absent

- Link guide from README

* docs: link prerequisite downloads

- Add official download links for Rust, Android, JDK, Xcode, and xcodegen

* docs: clarify JDK requirement

- Use vendor-agnostic JDK 17+ wording and OpenJDK link

- Note AGP official support for Java 17

* feat: Rename bench-cli to mobench and add iOS IPA packaging

Major improvements to CLI tooling and iOS workflow:

1. Rename bench-cli → mobench
   - More memorable and concise name (7 chars)
   - Available on crates.io
   - Dual binaries: mobench + cargo-mobench
   - Updated all documentation and references

2. Add iOS IPA packaging with xcodebuild
   - New command: cargo mobench package-ipa
   - SigningMethod enum: AdHoc and Development
   - Ad-hoc signing (no Apple ID needed) for BrowserStack
   - Development signing for physical devices
   - Pure xcodebuild implementation (no fastlane dependency)
   - Automatic ExportOptions.plist generation

3. Eliminate script dependencies for SDK integrators
   - Added prominent warnings in README and integration docs
   - Deprecation notices in all shell scripts
   - CLI-first approach: cargo mobench build replaces ./scripts/
   - Templates embedded in binary, no repo checkout needed

4. Add package metadata
   - Author: Dominik Clemente - dcbuilder.eth <dc@world.org>
   - Added to mobench, bench-sdk, and bench-macros
   - Repository links and keywords for crates.io

All changes tested and verified:
- 25 tests passing
- cargo mobench --help shows all commands
- package-ipa supports both adhoc and development methods
- Documentation updated across all files

* refactor: Rename bench-sdk → mobench-sdk and bench-macros → mobench-macros

Complete branding consistency across all packages:

1. Crate renames:
   - bench-sdk → mobench-sdk
   - bench-macros → mobench-macros

2. Updated all references:
   - Package names in Cargo.toml files
   - Workspace member names
   - Dependency declarations
   - Import statements (bench_sdk → mobench_sdk)
   - Documentation and code examples
   - CLI help messages

3. All tests passing (25 tests)
   - mobench-sdk: 12 tests
   - sample-fns: 6 tests
   - basic-benchmark: 6 tests
   - mobench CLI verified

Now all three publishable packages have consistent branding:
- mobench (CLI)
- mobench-sdk (core library)
- mobench-macros (proc macros)

* feat: Add metadata to bench-runner for crates.io publication

* fix: Add version requirements to path dependencies in mobench-sdk

* fix: Update repository URLs to worldcoin org and include templates in mobench-sdk package

* fix: Include templates directory in mobench-sdk crate for crates.io packaging

* chore: prepare mobench for crates.io publication

- Update repository URL to worldcoin organization
- Add version requirements to published dependencies (mobench-sdk, bench-runner)

* chore: make sample-fns dependency optional for publishing

- Add 'demo' feature flag for sample-fns dependency
- Feature-gate Demo command to only work when demo feature is enabled
- Users can install with: cargo install mobench --features demo

This allows mobench to be published without requiring sample-fns
(which is not published to crates.io).

* chore: remove Demo command for crates.io publication

- Demo command was only useful for development/testing
- Requires unpublished sample-fns crate
- Move sample-fns to dev-dependencies only
- Published CLI focuses on core functionality

* docs: add BrowserStack test run results and manual test script

Completed test runs on BrowserStack:
- ✅ Android Espresso test PASSED on Pixel 7 (50s duration)
- ⚠️  iOS XCUITest encountered packaging/parsing issues

Build artifacts created:
- Android APK (9.5 MB) + test APK
- iOS IPA (284 KB) + test suite (5.6 MB)

The Android integration is fully functional. iOS XCUITest requires
additional work on test runner packaging to meet BrowserStack's
parsing requirements.

Added test_browserstack.sh for manual BrowserStack API testing,
bypassing CLI's benchmark registry validation.

* refactor: rename bench-runner to mobench-runner for consistency

- Renamed crates/bench-runner to crates/mobench-runner
- Updated package name from bench-runner to mobench-runner
- Updated all imports from bench_runner to mobench_runner
- Updated workspace and all dependent crates:
  - mobench-sdk
  - mobench CLI
  - sample-fns
  - examples/basic-benchmark

This aligns the runner crate naming with the mobench ecosystem
(mobench, mobench-sdk, mobench-macros, mobench-runner).

Preparing for republication to crates.io.

* chore: bump version to 0.1.1 for republication

Updated workspace version to 0.1.1 after:
- Publishing mobench-runner v0.1.0 (new package)
- Republishing mobench-sdk v0.1.1 (updated dependency)
- Republishing mobench v0.1.1 (updated dependency)

All packages now use mobench-runner instead of bench-runner.

* docs: add comprehensive READMEs to all packages for crates.io

Added detailed README files to all packages:

- mobench-runner: Explains timing harness, shows basic usage examples
- mobench-macros: Documents #[benchmark] attribute, macro expansion
- mobench-sdk: Comprehensive SDK guide with examples and architecture
- mobench: Complete CLI documentation with all commands and workflows

Each README includes:
- Feature overview
- Installation instructions
- Usage examples
- API documentation
- Best practices
- Integration with other packages
- Requirements and troubleshooting

Updated Cargo.toml files to include readme = "README.md" field
for proper display on crates.io package pages.

Bumped version to 0.1.2 for republication with documentation.

* chore: add MIT license and update all package licenses

- Added LICENSE.md with MIT license under World Foundation (2026)
- Updated all READMEs to reference MIT license only
- Changed workspace license from 'MIT OR Apache-2.0' to 'MIT'
- Updated license sections in all 4 package READMEs:
  - mobench-runner
  - mobench-macros
  - mobench-sdk
  - mobench
- Bumped version to 0.1.3 for republication

Copyright (c) 2026 World Foundation

* chore: reset version to 0.1.0 for fresh release

Yanked all previous versions (0.1.0-0.1.3) from crates.io.
Starting fresh with proper:
- MIT license under World Foundation (2026)
- Comprehensive READMEs for all packages
- Consistent naming (mobench-runner instead of bench-runner)

This is the canonical first release.

* chore: use version 0.1.4 as canonical first release

Cannot reuse version 0.1.0 even after yanking.
Version 0.1.4 will be the canonical first release with:
- MIT license under World Foundation (2026)
- Comprehensive READMEs
- Proper naming (mobench-runner)

Versions 0.1.0-0.1.3 are yanked.

* docs: update CLAUDE.md to reflect SDK-first architecture and crates.io publication

- Update project overview with published packages (v0.1.4)
- Document recommended cargo mobench build workflow
- Mark scripts/ as legacy for repository development only
- Add SDK integration examples and Quick Start
- Reorganize file structure documentation
- Add template system documentation

* fix: address GitHub Advanced Security and Codex review findings

1. Add explicit workflow permissions (contents: read)
   - Addresses GitHub Advanced Security CodeQL warnings
   - Limits GITHUB_TOKEN permissions to read-only for CI workflow
   - Reduces security risk by following principle of least privilege

2. Fix local smoke test for user benchmarks
   - Only run local smoke test for sample_fns::* functions
   - Skip gracefully for user-defined benchmarks
   - Prevents 'unknown benchmark function' errors
   - User benchmarks aren't linked into CLI binary (will run on device)
   - Addresses Codex P1 review finding

Note: Skipped iOS certificate pinning (Semgrep finding) as the app
does not make network requests. Can be revisited if needed later.

* mobench: support repository structure and fix iOS IPA packaging

Updates CLI and SDK to work seamlessly with both SDK projects (bench-mobile/)
and repository structure (crates/sample-fns/), enabling full end-to-end testing
using only mobench commands.

Changes:

- AndroidBuilder/IosBuilder: Add find_crate_dir() to detect benchmark crate
  in multiple locations (bench-mobile/ or crates/{crate_name}/)

- UniFFI binding generation: Make optional, use pre-existing bindings if
  available, only require uniffi-bindgen CLI for fresh generation

- iOS IPA packaging: Complete rewrite from xcodebuild archive to simpler
  xcodebuild build approach, with ad-hoc signing support for BrowserStack
  testing (no Apple Developer account needed)

- BrowserStack XCUITest: Add only-testing parameter support to specify
  test methods (required by BrowserStack API)

- iOS project: Add schemes configuration to project.yml for proper
  xcodebuild support

Verified working:
- cargo mobench build --target android
- cargo mobench build --target ios
- cargo mobench package-ipa --method adhoc
- cargo mobench run (both Android and iOS on BrowserStack)

* mobench: add --fetch flag for CI-ready result retrieval

Implements automatic polling and result fetching for BrowserStack runs,
making the CLI fully CI-ready with one-command benchmark execution.

BrowserStack Client API:
- poll_build_completion(): Wait for build to finish with configurable timeout
- get_espresso_build_status() / get_xcuitest_build_status(): Check build status
- get_device_logs(): Fetch logs from specific device sessions
- extract_benchmark_results(): Parse benchmark JSON from logs
- wait_and_fetch_results(): Complete workflow (poll + fetch + extract)

CLI Integration:
- --fetch flag on 'run' command triggers automatic result fetching
- Merges benchmark_results into output JSON (device -> results map)
- Configurable timeout (--fetch-timeout-secs, default: 1800)
- Configurable poll interval (--fetch-poll-interval-secs, default: 10)
- Graceful error handling with warnings (command succeeds even if fetch fails)

Output Format Enhancement:
- RunSummary now includes optional benchmark_results field
- Results organized by device name
- Each device has array of benchmark results with samples, mean, min, max

Testing:
- 8 new comprehensive tests for result extraction and parsing
- Tests for BuildStatus conversion and deserialization
- Tests for JSON extraction from logs (single, multiple, invalid, missing)
- All tests passing (21 total in browserstack module)

Documentation:
- FETCH_RESULTS_GUIDE.md: Complete guide for --fetch usage
- BROWSERSTACK_CI_INTEGRATION.md: Programmatic API reference
- GitHub Actions examples with step summaries
- Error handling patterns and best practices

Example Usage:
  cargo mobench run \
    --target android \
    --function sample_fns::fibonacci \
    --iterations 30 \
    --warmup 5 \
    --devices "Google Pixel 7-13.0" \
    --fetch \
    --output results.json

This release makes mobench fully CI-ready with automatic result retrieval,
eliminating the need for manual log parsing or separate fetch commands.

* gitignore: exclude BrowserStack run artifacts and temp files

* mobench: print dashboard URL and result summary with --fetch

Improves CLI output when using --fetch to show:
- Dashboard URL immediately after scheduling (not just on error)
- Summary of benchmark results for each device
- Mean time in both nanoseconds and milliseconds
- Number of samples collected
- Dashboard URL again after successful fetch for easy access

Example output:
  Waiting for build 88f8c5a... to complete...
  Dashboard: https://app-automate.browserstack.com/dashboard/v2/builds/88f8c5a...

  ✓ Successfully fetched results from 1 device(s)

    Device: Google Pixel 7-13.0
      Benchmark 1: sample_fns::fibonacci
        Mean: 1237000 ns (1.24 ms)
        Samples: 30

    View full results: https://app-automate.browserstack.com/...

Makes CI output more informative and actionable without requiring manual
JSON parsing or URL construction.

* docs: document BrowserStack metrics and performance monitoring

Adds comprehensive documentation on what device metrics BrowserStack
provides and what mobench currently captures.

Key points:
- BrowserStack does NOT provide built-in CPU/memory/battery profiling
- Performance metrics must be collected by your app code
- We currently capture: logs, videos, network traces, screenshots
- We extract: benchmark timing data from logs
- Future enhancement: Extract custom performance metrics from logs

Provides examples for collecting memory/CPU metrics on Android/iOS
and logging them as JSON for extraction.

References BrowserStack API documentation and platform-specific APIs
for memory profiling.

* feat(mobench): add performance metrics extraction (v0.1.5)

- Add performance metrics types (PerformanceSnapshot, MemoryMetrics, CpuMetrics, etc.)
- Implement extract_performance_metrics() to parse memory/CPU data from device logs
- Add wait_and_fetch_all_results() to fetch both benchmark and performance results
- Update RunSummary to include performance_metrics field
- Add comprehensive tests for performance metrics extraction
- Update CLI --fetch to display performance metrics alongside benchmark results
- Update BROWSERSTACK_METRICS.md to reflect new functionality

Performance metrics are automatically extracted when using --fetch flag if the app
logs them in JSON format with memory/cpu fields or type='performance'.

Example output format:
{
  "memory": {"used_mb": 128.5, "max_mb": 512.0},
  "cpu": {"usage_percent": 45.2}
}

* refactor: remove dead code and fix compiler warnings

- Remove unused `wait_and_fetch_results()` from browserstack.rs (superseded by `wait_and_fetch_all_results()`)
- Add `#[cfg(test)]` to `run_local_smoke()` in main.rs
- Remove unused iOS signing methods (`identity()`, `export_method()`, `create_export_options_plist()`)
- Remove unused imports (`std::io::Write`, `BenchSpec`, `run_closure`)
- Add explanatory comment for dual binary targets in Cargo.toml

This cleanup addresses all compiler warnings and removes 117 lines of dead code.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: build Android test APK and harden BrowserStack fetch

---------

Co-authored-by: tfe-app[bot] <200245884+tfe-app[bot]@users.noreply.github.com>
Co-authored-by: wld-terraform <infrastructure@toolsforhumanity.com>
Co-authored-by: dcbuilder.eth <dcbuilder@protonmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Improve mobench fetch and iOS/Android builders

* Chore: align docs with markdownlint

* Refine rust-analyzer diagnostics

* Bump workspace version to 0.1.5

* Docs: refresh mobench testing and CLI guidance

Update docs to reflect current CLI usage, remove host demo references, and clarify local device workflows. Ignore Cursor project files and sync lockfile version entries.

* feat: add run summaries and CI artifacts

Add JSON/Markdown (optional CSV) summaries for mobench runs and wire CI to publish host + BrowserStack results.

* fix test

* feat: add compare reports and device tag filters

Add a mobench compare command plus device tag filtering from matrix configs, and publish benchmark summaries to CI job summaries. Refresh docs to cover compare usage and updated config examples.

* chore: clean up formatting in tests and bindgen

* address minor pr codex comments

* fix: treat BrowserStack passed builds as complete

Update polling to accept passed/completed build statuses and ignore run summary outputs in git. This prevents fetch timeouts after successful runs.

* Docs: align configs, devices, and rustdoc naming

Refresh markdown docs and rustdocs to use current mobench config names, BrowserStack device strings, and API references. Update codegen templates and examples to match mobench-sdk naming.

---------

Co-authored-by: dcbuilder.eth <dcbuilder@protonmail.com>
- split CLI entrypoint into library and cargo-mobench bin
- update workspace manifests and lockfile for crate changes
- rewrite README with current workflow and crate list
Drop the unused bench-cli and bench-runner crates, update docs to reflect the current mobench-runner workflow, and adjust legacy scripts/comments to reference cargo mobench.
Simplify basic-benchmark to only show #[benchmark] usage and add a new ffi-benchmark example that contains the UniFFI types and entrypoint. Update workspace metadata and docs to reflect the new example layout.
Drop the unused UniFFI UDL file for sample-fns and update build script notes to reflect the proc-macro binding generation flow.
Delete deprecated build scripts, switch CI and docs to cargo mobench commands, and refresh integration guidance for the new flow.
Update CLAUDE, BUILD, and mobench-sdk README to remove script references, clarify the builder flow, and document the new examples.
The repo_root() function now walks up the directory tree looking for
marker files instead of relying on the compile-time manifest path.
This fixes cases where the CLI is run from subdirectories.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update workspace version and inter-crate dependencies.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add output_dir field to AndroidBuilder and IosBuilder
- Default to {project_root}/target/mobench/ for all mobile artifacts
- Add output_dir() builder method for customization
- Add --output-dir CLI argument to `cargo mobench build`
- Update all path references in builders to use output_dir

This keeps generated mobile artifacts inside target/, following Rust
conventions and preventing accidental commits of Android/iOS project files.
- Update all path references from target/ios/ to target/mobench/ios/
- Update Android paths to target/mobench/android/
- Document --output-dir CLI flag
- Update troubleshooting sections with correct paths
- Add extensive crate-level documentation to all four crates:
  - mobench-sdk: Full SDK docs with examples, architecture, and best practices
  - mobench-macros: #[benchmark] macro documentation with usage examples
  - mobench-runner: Timing harness docs with runnable examples
  - mobench: CLI documentation with command reference

- Document all public types with examples:
  - BenchSpec, BenchSample, BenchReport, BenchError
  - Target, BuildConfig, BuildProfile, BuildResult
  - InitConfig and builder types

- Configure docs.rs metadata in all Cargo.toml files:
  - Add documentation URLs
  - Add maintenance badges
  - Configure rustdoc-args for docs.rs builds

- Add serde_json dev-dependency to mobench-runner for doc tests
This commit implements all 11 developer experience improvements from
IMPROVEMENTS.md, making mobench significantly more user-friendly.

## Key Changes

### P0 - Critical (Tasks 1-3)
- Fix aws-lc-rs Android NDK incompatibility (ring backend)
- Fix workspace target directory detection (cargo metadata)
- Auto-generate project scaffolding during build

### P1 - High Priority (Tasks 4-6)
- Process template variables during build (TemplateContext)
- Improve uniffi-bindgen handling (local binary + fallback)
- Generate error handling code dynamically (generic catch)

### P2 - Medium Priority (Tasks 7-9)
- Add mobench.toml configuration file support
- Improve error messages with actionable suggestions
- Add --crate-path flag for custom crate locations

### P3 - Nice to Have (Tasks 10-11)
- Add --dry-run and --verbose CLI modes
- Auto-generate local.properties for Android

## Code Quality Improvements

- Extract shared utilities to builders/common.rs (DRY)
- Consistent error message formatting with:
  - Clear description of what failed
  - Context (commands, paths, exit status)
  - Actionable fix suggestions
  - Links to documentation
- Standardized path formatting using display()

## New Files
- crates/mobench/src/config.rs - Configuration file support
- crates/mobench-sdk/src/builders/common.rs - Shared utilities
- IMPROVEMENTS.md - Task tracking document

## Consolidation
- Merged mobench-runner crate into mobench-sdk
- Timing functionality now in mobench-sdk/src/timing.rs
The test `ios_requires_artifacts_for_browserstack` was failing because
iOS project scaffolding was not being generated correctly during
auto-build for BrowserStack.

Root causes and fixes:

1. render_dir() was incorrectly joining prefix with file.path(), but
   file.path() from include_dir already returns the full relative path.
   Removed the prefix parameter entirely.

2. project.yml lacked .template extension, so template variables like
   {{PROJECT_NAME_PASCAL}} were not being substituted. Renamed to
   project.yml.template.

3. xcframework path in project.yml.template was wrong (../../target/ios/).
   Fixed to ../{{LIBRARY_NAME}}.xcframework since the iOS project is at
   target/mobench/ios/BenchRunner/.

4. ensure_ios_project now uses fixed "BenchRunner" for PROJECT_NAME_PASCAL
   to match the template directory structure, while deriving LIBRARY_NAME
   from the actual crate name.

All 37 tests now pass.
README updates:
- Document mobench-runner consolidation into mobench-sdk
- Add mobench.toml configuration file documentation
- Document new CLI flags: --dry-run, --verbose, --crate-path
- Update all artifact paths to target/mobench/
- Add examples for new features

Rust doc comments:
- Add comprehensive module docs to builders/{mod,android,ios,common}.rs
- Document build pipelines, requirements, and examples
- Add dry-run mode documentation
- Note mobench-runner consolidation in timing.rs

docs.rs configuration:
- Add targets = ["x86_64-unknown-linux-gnu"] for docs.rs builds
- Add #![cfg_attr(docsrs, feature(doc_cfg))] attributes
- Add crates.io/docs.rs/license badges to crate roots
- Add #[doc(cfg(...))] annotations for feature-gated items
- Update workspace version from 0.1.8 to 0.1.9
- Update mobench-sdk dependency in mobench crate
- Update mobench-macros dependency in mobench-sdk crate
- All mobench-runner versions have been yanked on crates.io
Critical bugs fixed (12):
- Bugs 1-5: Template variables (PROJECT_NAME, PACKAGE_NAME, LIBRARY_NAME,
  PROJECT_NAME_PASCAL, APP_NAME) now properly substituted
- Bug 6: Added gradle.properties template with AndroidX settings
- Bug 7: Auto-generate Gradle wrapper if missing
- Bug 8: Fixed AGP version from 8.13.2 to 8.2.2
- Bug 9: Package name in Kotlin templates now uses {{PACKAGE_NAME}}
- Bug 10: Added x86_64-apple-ios target for Intel Mac simulators
- Bug 11: Fixed path handling by canonicalizing project root
- Bug 12: DEFAULT_FUNCTION now auto-detected from #[benchmark] functions

High severity issues fixed (8):
- Issue 1: Added post-template validation for unreplaced {{...}} patterns
- Issue 2: codesign_xcframework now returns Err on failure
- Issue 3: generate_xcode_project now returns Err on failure
- Issue 4: Missing native libraries always warn (not just verbose)
- Issue 5: Added validate_project_root() for early validation
- Issue 6: cargo metadata fallback now warns when used
- Issue 7: Kotlin catch block logs exceptions instead of swallowing
- Issue 8: Added validate_build_artifacts() post-build validation

Medium/Low issues fixed (4):
- Added .gitignore templates for Android and iOS
- Added README.md templates for Android and iOS

New files:
- templates/android/.gitignore
- templates/android/README.md
- templates/android/gradle.properties
- templates/ios/BenchRunner/.gitignore
- templates/ios/BenchRunner/README.md
- Fix all path references to use target/mobench/ as default output dir
- Update CLAUDE.md version reference to v0.1.9
- Fix PROJECT_PLAN.md to reflect mobench-runner consolidation into mobench-sdk
- Remove dead links to BROWSERSTACK_RUN_2.md (use BROWSERSTACK_METRICS.md)
- Fix all init-sdk references to use correct init command
- Fix duplicate command and step numbering in TESTING.md
- Update iOS artifact paths in BENCH_SDK_INTEGRATION.md
Comment thread .github/workflows/rust.yml Fixed
@semgrep-code-worldcoin
Copy link
Copy Markdown

Semgrep found 1 run-shell-injection finding:

  • .github/workflows/mobile-bench-profile-selftest.yml

Using variable interpolation ${{...}} with github context data in a run: step could allow an attacker to inject their own code into the runner. This would allow them to steal secrets and code. github context data can have arbitrary user input and should be treated as untrusted. Instead, use an intermediate environment variable with env: to store the data and use the environment variable in the run: script. Be sure to use double-quotes the environment variable, like this: "$ENVVAR".

Semgrep found 19 tainted-path findings:

The application builds a file path from potentially untrusted data, which can lead to a path traversal vulnerability. An attacker can manipulate the path which the application uses to access files. If the application does not validate user input and sanitize file paths, sensitive files such as configuration or user data can be accessed, potentially creating or overwriting files. To prevent this vulnerability, validate and sanitize any input that is used to create references to file paths. Also, enforce strict file access controls. For example, choose privileges allowing public-facing applications to access only the required files.

View Dataflow Graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>crates/mobench/src/summarize.rs</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/worldcoin/mobile-bench-rs/blob/f1cd767cac0c0c064b91c301992a655e3cbbcaaa/crates/mobench/src/summarize.rs#L303 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 303] dir</a>"]
        end
        %% Intermediate

        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/worldcoin/mobile-bench-rs/blob/f1cd767cac0c0c064b91c301992a655e3cbbcaaa/crates/mobench/src/summarize.rs#L303 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 303] dir</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    File0:::invis

    %% Connections

    Source --> Sink

Loading

Semgrep found 9 rust-actix-command-injection findings:

Untrusted input might be injected into a command executed by the application, which can lead to a command injection vulnerability. An attacker can execute arbitrary commands, potentially gaining complete control of the system. To prevent this vulnerability, avoid executing OS commands with user input. If this is unavoidable, validate and sanitize the input, and use safe methods for executing the commands.

View Dataflow Graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>crates/mobench/src/profile.rs</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/worldcoin/mobile-bench-rs/blob/f1cd767cac0c0c064b91c301992a655e3cbbcaaa/crates/mobench/src/profile.rs#L3998 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 3998] adb_path</a>"]
        end
        %% Intermediate

        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/worldcoin/mobile-bench-rs/blob/f1cd767cac0c0c064b91c301992a655e3cbbcaaa/crates/mobench/src/profile.rs#L3998 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 3998] adb_path</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    File0:::invis

    %% Connections

    Source --> Sink

Loading

@dcbuild3r dcbuild3r changed the title Merge dev into main fix mermaid diagram placement Apr 27, 2026
@chatgpt-codex-connector
Copy link
Copy Markdown

💡 Codex Review

GH_SHA: ${{ github.event.pull_request.head.sha || github.sha }}

P1 Badge Target check runs to the benchmarked commit SHA

Set GH_SHA from inputs.head_sha (with a fallback) instead of github.sha. This reusable workflow is invoked via workflow_dispatch on the default branch while benchmarking a PR commit passed through head_sha; in that path github.event.pull_request is empty and github.sha points to the default-branch workflow revision, so check runs get created on the wrong commit and won’t appear on the PR head being evaluated.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

0xForerunner
0xForerunner previously approved these changes Apr 27, 2026
Squash merge PR #30 after publishing mobench 0.1.39.
Comment thread crates/mobench/src/lib.rs

fn load_browserstack_failure_reports(output_root: &Path) -> Result<BTreeMap<String, Vec<Value>>> {
let mut failures_by_device: BTreeMap<String, Vec<Value>> = BTreeMap::new();
for entry in fs::read_dir(output_root).with_context(|| {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep identified an issue in your code:

Untrusted path is used in fs::read_dir, allowing path traversal to list arbitrary directories and read each subdir’s failure.json.

More details about this

The function load_browserstack_failure_reports uses the caller‑supplied path output_root directly in fs::read_dir(output_root), then builds failure_path with entry.path().join("failure.json") and reads it with fs::read_to_string. If output_root can be influenced by a request (e.g., an Actix handler parameter or query/path value), an attacker can point output_root at any directory on the server. The code will then list that directory and read any subdirectory’s failure.json, returning its contents via the function’s result.

Concrete exploit path:

  • Attacker sends a request that sets output_root to an arbitrary path (e.g., /, /var, or ../../../../var/app/data). This value becomes the function’s output_root.
  • fs::read_dir(output_root) enumerates that directory. For each child directory, the code computes failure_path = entry.path().join("failure.json").
  • fs::read_to_string(&failure_path) reads those files’ contents, and the function aggregates them into failures_by_device.
  • If the HTTP layer returns or logs this map, the attacker gains the data from any failure.json files under the targeted directory tree.

Example:

  • GET /reports?root=../../../../var/app/artifacts
  • output_root resolves to a server path that the process can read. The code lists it and reads each /failure.json, leaking internal test artifacts or other sensitive JSON files named failure.json.

What’s risky here:

  • output_root is used without normalization or restriction to a trusted base directory, enabling path traversal and arbitrary directory reads within the app’s read permissions.
  • The join on entry.path() means any readable subdir under output_root is in scope, and all their failure.json contents are processed and potentially exposed.
Dataflow graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>crates/mobench/src/lib.rs</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/worldcoin/mobile-bench-rs/blob/581ba614a98a624fa6bf0d27577d768b3b67de17/crates/mobench/src/lib.rs#L2861 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 2861] output_root</a>"]
        end
        %% Intermediate

        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/worldcoin/mobile-bench-rs/blob/581ba614a98a624fa6bf0d27577d768b3b67de17/crates/mobench/src/lib.rs#L2861 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 2861] output_root</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    File0:::invis

    %% Connections

    Source --> Sink


Loading

To resolve this comment:

✨ Commit fix suggestion
  1. Validate and sanitize the value of output_root before passing it to fs::read_dir. Ensure it cannot be manipulated to point outside of the intended directory (for example, that it does not contain .. or absolute paths).
  2. If output_root is derived from user input, reject any value containing path traversal patterns like .., ~, or starting with / or \. For example, before using it:
    • Convert the path to an absolute path with std::fs::canonicalize(output_root)?, and check that it starts with your allowed base directory.
  3. Prefer constructing file system paths using trusted configuration/constants rather than user input whenever possible.
  4. If you must accept user input for part of the path, restrict allowed values (e.g., only allow alphanumeric directory names).
  5. Optionally, log any rejected or sanitized path to help debug attempts at path traversal.

This will ensure attackers cannot use crafted input to access or list files outside of the intended directory.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by tainted-path.

You can view more details about this finding in the Semgrep AppSec Platform.

Comment thread crates/mobench/src/lib.rs

fn load_toml_config_value(path: &Path) -> Result<toml::Value> {
let contents =
fs::read_to_string(path).with_context(|| format!("reading config {}", path.display()))?;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep identified an issue in your code:

Untrusted path is passed to fs::read_to_string in load_toml_config_value, enabling path traversal to read arbitrary files from the server.

More details about this

The code reads a file path from the path parameter without any validation or restriction.

What’s in the code

  • load_toml_config_value(path) calls fs::read_to_string(path) and logs the chosen path via path.display(). There’s no normalization or restriction to a safe base directory.

How this can be exploited

  • If path is influenced by request data (e.g., a query/path/header captured upstream as explicit_config_path or config_path and then passed to load_toml_config_value), an attacker can traverse directories or target absolute paths.
  • Example request: GET /config?path=../../../../etc/passwd
    1. The handler parses the query value into a PathBuf (e.g., explicit_config_path or config_path).
    2. That PathBuf is forwarded to load_toml_config_value(path).
    3. fs::read_to_string(path) reads the attacker-chosen file (e.g., /etc/passwd), returning its contents to the code that invoked it. The format!("reading config {}", path.display()) also confirms which file was accessed and may leak this in logs or error messages.
  • Another example: GET /config?path=/proc/self/environ to read environment variables or secrets.

Impact

  • Arbitrary file read from the server filesystem using .. or absolute paths, exposing configuration, credentials, keys, or source code, all via the unvalidated path used in fs::read_to_string(path).
Dataflow graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>crates/mobench/src/lib.rs</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/worldcoin/mobile-bench-rs/blob/581ba614a98a624fa6bf0d27577d768b3b67de17/crates/mobench/src/lib.rs#L1368 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 1368] path</a>"]
        end
        %% Intermediate

        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/worldcoin/mobile-bench-rs/blob/581ba614a98a624fa6bf0d27577d768b3b67de17/crates/mobench/src/lib.rs#L1368 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 1368] path</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    File0:::invis

    %% Connections

    Source --> Sink


Loading

To resolve this comment:

✨ Commit fix suggestion
  1. Sanitize or validate the path before calling fs::read_to_string(path). Only allow reading files from intended directories (such as a config directory), and reject any user input with characters like .., absolute paths, or path separators that could lead outside the allowed directory.
  2. Create a helper function such as fn validate_config_path(base: &Path, user_path: &Path) -> Result<PathBuf> that checks if the resulting PathBuf is still within base using methods like canonicalize() and starts_with(). Example:
    let canonical = path.canonicalize()?; if !canonical.starts_with(base_dir) { bail!("Invalid config path"); }
  3. Call this validation function before the fs::read_to_string(path) call in load_toml_config_value. Only proceed with reading the file if the path is valid; otherwise, return an error.
  4. Alternatively, if path must come from a fixed set of allowed filenames, compare against a whitelist and reject any others.

Validating file paths prevents attackers from accessing unexpected files and mitigates path traversal vulnerabilities.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by tainted-path.

You can view more details about this finding in the Semgrep AppSec Platform.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants