Skip to content

Refactor: unify permission lists via all_permissions! callback macro #16

@bordumb

Description

@bordumb

Problem

The set of permission types is enumerated in multiple places that must stay in sync:

  1. capsec-core/src/permission.rs — struct definitions + Permission impls
  2. capsec-core/src/permission.rssealed::Sealed impls
  3. capsec-core/src/has.rsimpl_ambient! invocation
  4. capsec-core/src/has.rsimpl_tuple_has_first! / impl_tuple_has_second! invocations
  5. capsec-macro/src/lib.rsKNOWN_PERMISSIONS string array

Adding a new permission type requires updating all 5 locations. Missing one causes silent breakage (e.g., Cap<Ambient> loses coverage for the new type, or #[capsec::context] rejects it as unknown).

A compile-time exhaustiveness test was added to catch impl_ambient! omissions, but the root cause — multiple independent lists — remains.

Proposed fix

A small callback macro that defines the canonical list once:

macro_rules! all_permissions {
    ($macro:ident) => {
        $macro!(FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn);
    };
}

Each consumer invokes its own macro with the shared list:

all_permissions!(impl_sealed);
all_permissions!(impl_permission);
all_permissions!(impl_ambient);
all_permissions!(impl_tuple_has_first);
// etc.

Subsumption (FsAll => FsRead, FsWrite) stays hand-written — it's inherently non-uniform and shouldn't be auto-generated.

KNOWN_PERMISSIONS in capsec-macro can't use the Rust macro directly (proc-macro crate boundary), but could be generated by a build script or kept as a separate list with a compile-time test ensuring parity.

Scope

  • One source of truth for the permission enumeration
  • Each consumer site remains a separate, readable, auditable macro
  • No behavior change — pure refactor
  • Touches capsec-core/src/permission.rs, capsec-core/src/has.rs

Priority

v0.2 cleanup. The compile-time test in has.rs covers the immediate risk for v0.1.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions