Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 43 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,27 @@ starforge network test
starforge network test mainnet
```

### Configuration commands

```bash
# Show all configuration settings
starforge config show

# Get a specific setting
starforge config get telemetry
starforge config get network

# Set a configuration value
starforge config set telemetry false
starforge config set network mainnet
```

Common settings:
- **telemetry**: Enable/disable anonymous usage telemetry (`true` or `false`)
- **network**: Set the default network (`testnet`, `mainnet`, or custom network name)

For privacy information, see [Telemetry & Privacy](#telemetry--privacy).

### Scaffold commands

```bash
Expand Down Expand Up @@ -335,9 +356,29 @@ cargo test

Generate this value outside the codebase using your preferred secure workflow, such as a local Stellar key generation command or an existing throwaway test wallet. The key should live only in your shell environment or secret manager, not in source control.

---
### Telemetry & Privacy

starforge collects **anonymous telemetry** to help us improve the CLI. **No personal data is collected** β€” only command names, success/failure status, and execution time.

## Contract Templates
#### Disable Telemetry

If you prefer not to participate:

```bash
# Permanently disable telemetry
starforge config set telemetry false

# Or use an environment variable (useful for CI/CD)
export STARFORGE_TELEMETRY=0
```

**What's collected**: Command name, timestamp, success status, duration (milliseconds), and a random anonymous ID.

**What's NOT collected**: Wallet addresses, secret keys, contract code, configuration values, error messages, or personal information.

For detailed information, see [TELEMETRY_PRIVACY.md](./TELEMETRY_PRIVACY.md).

---

| Template | Description |
|----------|-------------|
Expand Down
153 changes: 153 additions & 0 deletions TELEMETRY_PRIVACY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Telemetry & Privacy

StarForge collects telemetry data to help us understand usage patterns and improve the CLI. This document explains exactly what is collected, how to disable it, and what we do with the data.

## Privacy-First Design

- **Opt-out by default**: Telemetry is enabled by default but can be easily disabled
- **No personal data**: We never collect personal information, credentials, or sensitive data
- **Anonymous ID**: Usage is tracked with a random UUID, not tied to your identity
- **Local-first**: Telemetry is stored locally in your machine and only sent with explicit consent (future versions)
- **Transparent**: Full source code is available for audit

## What Data is Collected

For each CLI command executed, StarForge collects:

- **Command name**: Which command was run (e.g., `wallet`, `deploy`, `new`)
- **Timestamp**: When the command was executed
- **Success/Failure**: Whether the command completed successfully
- **Duration**: How long the command took in milliseconds
- **Anonymous ID**: A random UUID generated once per machine

### Example Telemetry Event

```json
{
"timestamp": "2025-01-15T10:30:45Z",
"event": "deploy",
"properties": {
"success": true,
"duration_ms": 2500
},
"anonymous_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

### What We Do NOT Collect

- ❌ Wallet addresses or secret keys
- ❌ Contract code or source files
- ❌ Configuration values (network URLs, custom networks)
- ❌ Error messages or stack traces
- ❌ User identity, email, or personal information
- ❌ File paths or local system information

## How to Disable Telemetry

### Option 1: Configuration Command (Recommended)

Disable telemetry permanently using the `config` command:

```bash
starforge config set telemetry false
```

View your current telemetry setting:

```bash
starforge config show
# or
starforge config get telemetry
```

Re-enable telemetry:

```bash
starforge config set telemetry true
```

### Option 2: Environment Variable

Disable telemetry for a single command or session:

```bash
# Disable for a single command
STARFORGE_TELEMETRY=0 starforge deploy --wasm my_contract.wasm

# Disable for the entire shell session
export STARFORGE_TELEMETRY=0
starforge wallet list
starforge deploy --wasm my_contract.wasm
```

Accepted values to disable telemetry:
- `0`, `false`, `off`, `disabled`, `no`

### Option 3: CI/CD Pipelines

For automated environments, set the environment variable:

```bash
# In GitHub Actions
env:
STARFORGE_TELEMETRY: "0"

# In GitLab CI
script:
- export STARFORGE_TELEMETRY=0
- starforge deploy --wasm my_contract.wasm
```

## Configuration Storage

Your telemetry preference is stored in:

```
~/.starforge/config.toml
```

Example:

```toml
network = "testnet"
telemetry_enabled = false

[[wallets]]
name = "deployer"
public_key = "GABC...XYZ"
# ...
```

Telemetry logs are stored in:

```
~/.starforge/data/telemetry.log
~/.starforge/data/anonymous_id
```

These files are created only if telemetry is enabled.

## Future: Remote Telemetry

In future versions, StarForge may offer opt-in remote telemetry (sending anonymous data to a analytics service). This will be:

- **Completely optional**: Requires explicit opt-in, never enabled by default
- **Aggregated**: Only high-level statistics are sent (e.g., "10 deployments per day", not individual events)
- **Auditable**: Full details published on what is collected and where it goes
- **Respectable**: Always respects `STARFORGE_TELEMETRY=0` and config settings

## Questions or Concerns?

If you have privacy concerns or questions about telemetry:

1. **Review the code**: Full source available at https://github.com/Josetic224/StarForge
2. **Check the logs**: Inspect `~/.starforge/data/telemetry.log` to see what was collected
3. **Disable it**: Use `starforge config set telemetry false` if you prefer not to participate
4. **Report issues**: Open an issue on GitHub with any privacy concerns

## Additional Privacy Resources

- [PRIVACY_POLICY.md](./PRIVACY_POLICY.md) - Full privacy policy
- [SECURITY_LOGGING_AUDIT.md](./SECURITY_LOGGING_AUDIT.md) - Security logging details
- [GitHub Repository](https://github.com/Josetic224/StarForge) - Open source, fully auditable
120 changes: 120 additions & 0 deletions src/commands/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use anyhow::{bail, Result};
use clap::Subcommand;
use colored::*;

#[derive(Subcommand)]
pub enum ConfigCommands {
/// Get a configuration value
Get {
/// Configuration key to retrieve (e.g., telemetry, network, wallet)
key: String,
},
/// Set a configuration value
Set {
/// Configuration key to set (e.g., telemetry)
key: String,
/// Configuration value (e.g., true, false)
value: String,
},
/// Show all configuration settings
Show,
}

pub fn handle_config(cmd: ConfigCommands) -> Result<()> {
match cmd {
ConfigCommands::Get { key } => handle_get(&key),
ConfigCommands::Set { key, value } => handle_set(&key, &value),
ConfigCommands::Show => handle_show(),
}
}

fn handle_get(key: &str) -> Result<()> {
let cfg = crate::utils::config::load()?;

match key.to_lowercase().as_str() {
"telemetry" => {
let enabled = cfg.telemetry_enabled.unwrap_or(true);
println!("{}: {}", key.cyan(), if enabled { "enabled" } else { "disabled" });
Ok(())
}
"network" => {
println!("{}: {}", key.cyan(), cfg.network);
Ok(())
}
_ => {
bail!(
"Unknown configuration key: '{}'\n\nAvailable keys:\n - telemetry\n - network",
key
);
}
}
}

fn handle_set(key: &str, value: &str) -> Result<()> {
let mut cfg = crate::utils::config::load()?;

match key.to_lowercase().as_str() {
"telemetry" => {
let enabled = match value.to_lowercase().as_str() {
"true" | "on" | "enabled" | "yes" => true,
"false" | "off" | "disabled" | "no" => false,
_ => {
bail!(
"Invalid value for telemetry: '{}'\n\nUse 'true'/'enabled'/'on'/'yes' or 'false'/'disabled'/'off'/'no'.",
value
);
}
};
cfg.telemetry_enabled = Some(enabled);
crate::utils::config::save(&cfg)?;
println!(
"βœ“ {} set to {}",
"telemetry".green(),
if enabled { "enabled" } else { "disabled" }
);
Ok(())
}
"network" => {
crate::utils::config::validate_network(value)?;
cfg.network = value.to_string();
crate::utils::config::save(&cfg)?;
println!("βœ“ {} set to {}", "network".green(), value);
Ok(())
}
_ => {
bail!(
"Unknown configuration key: '{}'\n\nAvailable keys:\n - telemetry\n - network",
key
);
}
}
}

fn handle_show() -> Result<()> {
let cfg = crate::utils::config::load()?;

println!("\n{}", "=== StarForge Configuration ===".bold());
println!();
println!(" {}: {}", "Network".cyan(), cfg.network);

let telemetry_status = cfg.telemetry_enabled.unwrap_or(true);
println!(
" {}: {}",
"Telemetry".cyan(),
if telemetry_status { "enabled" } else { "disabled" }
);

println!("\n{}", "Configuration file:".cyan());
if let Ok(cfg_path) = crate::utils::config::get_config_path() {
println!(" {}", cfg_path.display());
}

println!("\n{}", "Data directory:".cyan());
if let Ok(data_dir) = crate::utils::config::get_data_dir() {
println!(" {}", data_dir.display());
}

println!();

Ok(())
}
1 change: 1 addition & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod benchmark;
pub mod completions;
pub mod config;
pub mod contract;
pub mod deploy;
pub mod gas;
Expand Down
5 changes: 5 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ enum Commands {
Deploy(commands::deploy::DeployArgs),
/// Show starforge config and environment info
Info,
/// Manage starforge configuration (telemetry, network)
#[command(subcommand)]
Config(commands::config::ConfigCommands),

Tx(commands::tx::TxArgs), // fetch transaction for the account

Expand Down Expand Up @@ -129,6 +132,7 @@ fn main() {
Commands::Inspect(_) => "inspect",
Commands::Deploy(_) => "deploy",
Commands::Info => "info",
Commands::Config(_) => "config",
Commands::Tx(_) => "tx",
Commands::Network(_) => "network",
Commands::Node(_) => "node",
Expand All @@ -155,6 +159,7 @@ fn main() {
Commands::Inspect(cmd) => commands::inspect::handle(cmd),
Commands::Deploy(args) => commands::deploy::handle(args),
Commands::Info => commands::info::handle(),
Commands::Config(cmd) => commands::config::handle_config(cmd),
Commands::Tx(args) => commands::tx::handle(args),
Commands::Network(cmd) => commands::network::handle(cmd),
Commands::Node(cmd) => commands::node::handle(cmd),
Expand Down
4 changes: 4 additions & 0 deletions src/utils/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,10 @@ pub fn get_data_dir() -> Result<PathBuf> {
Ok(dir)
}

pub fn get_config_path() -> Result<PathBuf> {
Ok(config_path())
}

pub fn config_path() -> PathBuf {
config_dir().join("config.toml")
}
Expand Down
11 changes: 11 additions & 0 deletions src/utils/telemetry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ pub struct TelemetryData {
}

pub fn track_event(event: &str, properties: serde_json::Value) -> Result<()> {
// Check environment variable first (for CI/automation that cannot modify config)
if let Ok(env_val) = std::env::var("STARFORGE_TELEMETRY") {
let disabled = matches!(
env_val.to_lowercase().as_str(),
"0" | "false" | "off" | "disabled" | "no"
);
if disabled {
return Ok(());
}
}

let cfg = config::load()?;

// Check if telemetry is enabled (default to true, but respect opt-out)
Expand Down