Skip to content

Multi-writer ACL (Phase 1.1) #3

@sanity

Description

@sanity

Problem

Phase 1.0 is single-writer (only the repo owner can sign anything). Phase 1.1 introduces a real ACL so collaborators can push directly to the canonical repo without each running their own clone-and-pull dance.

What needs to happen

The data structures (AclState, WriterGrant, RefEntry.auth_epoch, etc.) are already in place in freenet-git-types — they're carried in the schema with epoch=0 and no grants. Phase 1.1:

  1. Update freenet-git-types::validate_state to enforce the epoch model:
    • Require grants[entry.updater] exists.
    • Require grant.granted_at_epoch <= entry.auth_epoch.
    • Require grant.revoked_at_epoch.is_none() OR entry.auth_epoch < revoked_at_epoch.unwrap().
  2. Add freenet-git CLI commands:
    • add-writer — owner signs an updated AclState.
    • remove-writer — owner signs an AclState with revoked_at_epoch set, AND owner re-signs every RefEntry currently authored by the revoked writer (per the spec's "Pre-revoke replay window" mitigation).

Schema compatibility

Phase 1.0 schema already includes the ACL fields, so Phase 1.1's contract WASM upgrade does NOT change the schema layout — only the validate_state logic. Existing Phase 1.0 repos are forward-compatible: owner-only validates correctly under the Phase 1.1 contract because the owner is implicitly authorized regardless of grants.

But the repo contract WASM hash WILL change, which changes the contract key. This is a migration: announce the upgrade pointer in the old contract's RepoState.upgrade field, point at the new key. River has prior art for permissionless migration.

Tests

  • Grant W, push as W, revoke W, assert old W-signed entries still validate while new W-signed entries (claiming the current epoch) are rejected.
  • Property test: owner re-signs every refs[r] where updater == revoked_writer at revocation time, assert no surviving W-signed entries point at refs (the operational mitigation).

[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