# melda-sec, a pluggable security layer for Melda

## WARNING: This is a very early preview / alpha code! Use it at your own risk!

`melda-sec` is a pluggable security layer for [Melda](https://github.com/slashdotted/libmelda) that adds cryptographic signing, signature verification, and policy-based authorization on object-level changes. It is implemented as a decorator over a standard Melda `Adapter`, allowing it to wrap any existing backend without modifying the core behavior of Melda. The purpose of `melda-sec` is to control which changes are considered valid: all data is still written and stored, but only changes that pass signature verification and policy rules are applied when the state is reconstructed. Invalid or unauthorized changes are silently ignored.

## Architecture

The library acts as a wrapper around an existing adapter:

```
Melda
  ↓
SecureAdapter
  ↓
Any Adapter (Memory, Filesystem, SQLite, etc.)
```

Adapters can be composed to build pipelines (e.g. encryption, compression, security).

## Basic Usage

```rust
use melda::memoryadapter::MemoryAdapter;
use melda_sec::{SecureAdapter, KeyStore, PolicyEngine};

let base = MemoryAdapter::new();

let mut ks = KeyStore::new();
ks.set_private_key(&private_key_bytes)?;
ks.add_public_key(&public_key_bytes)?;

let policy = PolicyEngine::from_yaml(r#"
rules:
  - allow:
      objects: "*"
"#)?;

let secure = SecureAdapter::new(base, ks, policy).into_dyn();
```

Then use with Melda:

```rust
let melda = Melda::new(secure)?;
```

## Adapter Composition Examples

The new adapter model allows fluent composition using `.into_dyn()`.

### Secure only

```rust
let adapter = SecureAdapter::new(
    FilesystemAdapter::new("data")?,
    keystore,
    policy
).into_dyn();
```

---

### Encrypted only

```rust
let adapter = EncryptionAdapter::new(
    FilesystemAdapter::new("data")?,
    key
).into_dyn();
```

---

### Secure + Encrypted

```rust
let adapter = SecureAdapter::new(
    EncryptionAdapter::new(
        FilesystemAdapter::new("data")?,
        key
    ),
    keystore,
    policy
).into_dyn();
```

---

### Secure + Encrypted + Compressed (Brotli)

Note: requires `melda/brotliadapter` feature.

```rust
let adapter = SecureAdapter::new(
    BrotliAdapter::new(
        EncryptionAdapter::new(
            FilesystemAdapter::new("data")?,
            key
        ).into_dyn()
    ),
    keystore,
    policy
).into_dyn();
```

---

## KeyStore

The `KeyStore` manages the cryptographic identity of the node and the trust configuration. It holds a private key used for signing, a set of trusted public keys, and optional role assignments.

```rust
let mut ks = KeyStore::new();
ks.set_private_key(&private_key_bytes)?;
ks.add_public_key(&public_key_bytes)?;
ks.add_public_key_with_role(&public_key_bytes, "accountant")?;
```

## Policy Engine

Defines which keys or roles can modify specific objects based on object identifiers.

## Object Identifiers

Policies operate on identifiers generated by Melda:

- Plain `_id` values
- Flattened array identifiers: `^parentid@field♭`

Field-level control for arbitrary object properties is not supported.

## Behavior

On write:
- data is always written
- `.delta` objects are signed

On read:
- signatures are verified
- policy rules are applied
- invalid changes are ignored

## Design Properties

- Cryptographic integrity
- Deterministic validation
- Offline-friendly synchronization

No global consensus or automatic convergence is provided.

## License

GPL-3.0

## Author

Amos Brocco
