| Crates.io | silent-sparrow |
| lib.rs | silent-sparrow |
| version | 0.4.0 |
| created_at | 2025-12-12 21:21:14.722073+00 |
| updated_at | 2025-12-14 23:00:06.458221+00 |
| description | A minimal, scheduled, cryptographically signed status beacon. |
| homepage | https://github.com/0xRogu/silent-sparrow |
| repository | https://github.com/0xRogu/silent-sparrow |
| max_upload_size | |
| id | 1982158 |
| size | 92,821 |
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:
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.
┌─────────────────────┐
│ 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.
The crate uses bird-themed status messages by default:
sparrow-song.json){
"timestamp": "2025-12-12T12:00:00Z",
"message": "All systems chirping normally:)",
"signature": "4a3b2c1d9e8f7g6h5i4j3k2l...",
"public_key": "8f3a1b2c9d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a"
}
{
"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.
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"
cargo install silent-sparrow
git clone https://github.com/yourusername/silentsparrow.git
cd silentsparrow
cargo build --release
Binaries will be in target/release/:
sparrow - Main canary processsparrow-watchdog - Watchdog monitorMain 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.
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
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.
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:
~/.config/silent-sparrow/sparrow.key~/Library/Application Support/org.silent-sparrow.Silent Sparrow/sparrow.key%APPDATA%\silent-sparrow\Silent Sparrow\config\sparrow.keyKeep this key secure! Anyone with access to it can forge canary updates.
The public key is included in every status file for verification.
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.
The CI/CD pipeline is automated. Every git tag matching vX.Y.Z automatically triggers:
This project is licensed under the Mozilla Public License 2.0 (MPL-2.0). See LICENSE for details.
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.