silent-sparrow

Crates.iosilent-sparrow
lib.rssilent-sparrow
version0.4.0
created_at2025-12-12 21:21:14.722073+00
updated_at2025-12-14 23:00:06.458221+00
descriptionA minimal, scheduled, cryptographically signed status beacon.
homepagehttps://github.com/0xRogu/silent-sparrow
repositoryhttps://github.com/0xRogu/silent-sparrow
max_upload_size
id1982158
size92,821
Rogu (0xRogu)

documentation

https://github.com/0xRogu/silent-sparrow#readme

README

🐦 Silent Sparrow

A minimal, self-contained Rust crate that publishes a regularly updated, Ed25519-signed JSON status file.

Silent Sparrow is designed for services that want to give technically inclined users an independent way to verify that the publishing process is still running normally.

The system consists of two components:

  • Main canary process: Refreshes the signed status file on a fixed schedule
  • Watchdog process: Monitors the file and updates the message if updates stop

If the timestamp ever falls behind the expected cadence, the watchdog updates the message to indicate a problem. If the signature no longer validates with the published public key, observers can draw their own conclusions.

No grace period. Either the bird sings on time, or it doesn't.

How It Works

┌─────────────────────┐
│  Silent Sparrow     │  Updates every 24h (configurable)
│  (Main Process)     │  Writes: "All systems chirping normally."
└──────────┬──────────┘
           │
           ▼ writes sparrow-song.json
           │
           ▼
┌─────────────────────┐
│  Watchdog Process   │  Checks every 5 min (configurable)
│  (Safety Net)       │  If file > threshold, overwrites message:
└─────────────────────┘  "The nest has gone quiet."

Key Design: The watchdog is essential. If the main process crashes, it can't update the file to say something is wrong. The watchdog detects staleness and updates the message accordingly.

Default Messages

The crate uses bird-themed status messages by default:

  • Normal: "All systems chirping normally:)"
  • Overdue: "The nest has gone quiet:("
    • Note: This is written by the watchdog process when the file timestamp exceeds the configured threshold.

Example Output (sparrow-song.json)

Normal Operation

{
  "timestamp": "2025-12-12T12:00:00Z",
  "message": "All systems chirping normally:)",
  "signature": "4a3b2c1d9e8f7g6h5i4j3k2l...",
  "public_key": "8f3a1b2c9d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a"
}

When Updates Have Stopped

{
  "timestamp": "2025-12-11T12:05:00Z",
  "message": "The nest has gone quiet:(",
  "signature": "WATCHDOG_OVERRIDE",
  "public_key": "8f3a1b2c9d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a"
}

Note: When the watchdog updates the message, the signature becomes WATCHDOG_OVERRIDE since the original cryptographic signature is no longer valid for the modified message. The stale timestamp and changed signature both indicate a problem.

Configuration

Create a sparrow.toml file to configure the behavior:

# Required update interval in hours
interval_hours = 24

# Where to write the signed file
output_path = "sparrow-song.json"

# Optional – override the default messages
message_normal = "All systems chirping normally:)"
message_overdue = "The nest has gone quiet:("

# Optional – publish to HTTPS endpoint
publish_url = "https://example.com/api/canary"
publish_token = "your-bearer-token"

Installation

From crates.io

cargo install silent-sparrow

From source

git clone https://github.com/yourusername/silentsparrow.git
cd silentsparrow
cargo build --release

Binaries will be in target/release/:

  • sparrow - Main canary process
  • sparrow-watchdog - Watchdog monitor

Usage

Running Both Processes

Main canary process:

sparrow --config=sparrow.toml

Watchdog process (in a separate terminal or service):

# Arguments: <path> <max_age_hours> <check_interval_seconds>
sparrow-watchdog sparrow-song.json 25 300

The watchdog checks every 5 minutes (300 seconds) and marks the canary as overdue if it's older than 25 hours.

As Systemd Services

Create /etc/systemd/system/silent-sparrow.service:

[Unit]
Description=Silent Sparrow Canary
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/sparrow --config=/etc/silent-sparrow/sparrow.toml
Restart=always
User=sparrow
WorkingDirectory=/var/lib/silent-sparrow

[Install]
WantedBy=multi-user.target

Create /etc/systemd/system/sparrow-watchdog.service:

[Unit]
Description=Silent Sparrow Watchdog
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/sparrow-watchdog /var/lib/silent-sparrow/sparrow-song.json 25 300
Restart=always
User=sparrow
WorkingDirectory=/var/lib/silent-sparrow

[Install]
WantedBy=multi-user.target

Enable and start both services:

sudo systemctl enable --now silent-sparrow sparrow-watchdog

As a Library

Add silent-sparrow to your Cargo.toml dependencies:

[dependencies]
silent-sparrow = "0.1"
tokio = { version = "1", features = ["full"] }

Example integration:

use silent_sparrow::{Canary, Config};
use tokio::time::{interval, Duration};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = Config::load_or_default("sparrow.toml")?;
    let mut canary = Canary::new(config.clone());
    
    // Initial update
    if let Err(e) = canary.refresh().await {
        eprintln!("Initial refresh failed: {}", e);
    }
    
    // Run periodic updates
    let mut interval = interval(config.interval_duration());
    loop {
        interval.tick().await;
        if let Err(e) = canary.refresh().await {
            eprintln!("Scheduled refresh failed: {}", e);
        }
    }
}

Remember: You still need to run the watchdog separately to handle the case where your process crashes.

Cryptographic Signing

Silent Sparrow uses Ed25519 for signing. On first run, it generates a key pair and stores the private key securely in your system's config directory:

  • Linux: ~/.config/silent-sparrow/sparrow.key
  • macOS: ~/Library/Application Support/org.silent-sparrow.Silent Sparrow/sparrow.key
  • Windows: %APPDATA%\silent-sparrow\Silent Sparrow\config\sparrow.key

Keep this key secure! Anyone with access to it can forge canary updates.

The public key is included in every status file for verification.

Verifying Signatures

To verify a canary signature independently:

# Extract values from the JSON
TIMESTAMP=$(jq -r '.timestamp' sparrow-song.json)
MESSAGE=$(jq -r '.message' sparrow-song.json)
PUBLIC_KEY=$(jq -r '.public_key' sparrow-song.json)
SIGNATURE=$(jq -r '.signature' sparrow-song.json)

# Construct the signed data (timestamp + newline + message + newline + public_key)
printf "%s\n%s\n%s" "$TIMESTAMP" "$MESSAGE" "$PUBLIC_KEY" > data.txt

# Verify with openssl or a Ed25519 verification tool

Note: If the signature is WATCHDOG_OVERRIDE, the watchdog has modified the message, and the original signature is no longer valid. This is intentional and indicates the main process has stopped updating.

Releases

The CI/CD pipeline is automated. Every git tag matching vX.Y.Z automatically triggers:

  • Cross-platform build & test (Linux, macOS, Windows)
  • Publication to crates.io
  • GitHub Release creation with pre-built binaries

License

This project is licensed under the Mozilla Public License 2.0 (MPL-2.0). See LICENSE for details.


⚠️ Disclaimer

This is a purely technical transparency tool.

It provides no legal protection and makes no representations about what can or cannot be compelled under any jurisdiction's law.

Use at your own discretion.

Commit count: 0

cargo fmt