Skip to content

feat: freenet-updates crate (decentralized version-pointer for tooling) #281

@sanity

Description

@sanity

Idea

Build a reusable freenet-updates crate that holds a small Freenet contract whose state is the canonical "current published version + release-key signature" pointer for a given tool. Tools (riverctl first; eventually fdev, river-publish, etc.) consume the crate to check for updates via the local Freenet node — no external HTTP, no crates.io polling, no GitHub API rate limits, no privacy footprint to a centralised registry.

Why now

We just discussed adding an HTTP-based crates.io version check to riverctl. That's the obvious-but-undecentralised approach — and adding a "phone home to a central registry" check to a tool whose purpose is decentralisation feels off. We should eat our own dogfood.

Shape

  • New crate freenet-updates in the freenet/ org (or under river/ workspace if scoped first to River — TBD).
  • Contract: VersionPointerV1 { tool_name: String, latest_version: SemVer, released_at: SystemTime, release_signature: Signature } signed by a known release key.
  • One contract instance per tool (e.g., riverctl, fdev, river contract). Tools know their own contract key.
  • Helper API: freenet_updates::check_for_update(tool_name, current_version) -> Result<UpdateStatus> — GETs the pointer contract via the local Freenet node, validates the release signature, returns UpToDate | Outdated { latest, released_at } | NetworkError.
  • Tools opt in by calling the helper on startup (or via a self-update-check subcommand). Warn-and-continue on outdated. Opt-out env var.

Design questions

  • Release key management: the simplest answer is one Ed25519 release key per tool, held by the release-cutter (today: Ian). Compromise of the release key = false-version attack. Mitigate via signature being verified locally against the bundled public key.
  • Contract update mechanism: each tool publish bumps its version-pointer contract via a delegate or a release-script riverctl-style invocation.
  • Bootstrap: tools need to be able to read the contract via the local Freenet node. If the local node isn't reachable, fall back to a no-op (don't block).
  • Cache: stale-while-revalidate — tools can use the most recent successful check (cached to local disk) for offline scenarios.

Use cases

  1. riverctl: warn on startup if outdated, with a hint to cargo install riverctl --force.
  2. fdev: same shape.
  3. freenet itself: long-term, could underpin auto-update for the daemon.
  4. River UI: the UI could surface a "new River build available" toast once the UI bundles the freenet-updates crate.

Acceptance criteria

  • Crate published to crates.io (or available as a git dep within the freenet org).
  • riverctl uses it for its startup check.
  • Public README documenting the release-key setup.
  • Issue closed after the second tool starts using it (proves the API is genuinely reusable).

Related

  • The "crates.io HTTP check" alternative was considered and rejected on dogfood grounds.
  • Connection to the existing legacy_delegates.toml migration story: not directly, but the release-signature key is the same kind of "centralised trust root we need to manage" problem.

[AI-assisted - Claude]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions