# MASL — Maduka Authorization Specification Language

[![Crates.io](https://img.shields.io/crates/v/maslc)](https://crates.io/crates/maslc)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![CI](https://github.com/exytech/maduka/actions/workflows/ci.yml/badge.svg)](https://github.com/exytech/maduka/actions)

**MASL** is a declarative, graph-first authorization schema language for [Zanzibar](https://research.google/pubs/zanzibar-googles-consistent-global-authorization-system/)-style authorization systems.

You describe _who can do what on which resource_ in a `.mdk` file.  
`maslc` compiles it to a compact binary (`.mdkc`) loaded at runtime by the Zanzibar engine.

```masl
namespace commerce
schema 1

subject User
subject Group {
    relation {
        member: User | Group::member
    }
}

resource Store {
    relation {
        owner:  User
        staff:  User | Group::member
        org:    Organization
    }
    grant {
        view   => owner | staff | org::member
        manage => owner | org::manage
        delete => owner
    }
}
```

---

## Features

- **Purely declarative** — no variables, no loops, no conditions.
- **Compile-time validation** — type resolution, circular alias detection, unreachable grant checks.
- **Public Contracts** — grants are the public API; relations are implementation details.
- **Zero runtime overhead** — aliases fully expanded at compile time, `.mdkc` loaded once at startup.
- **Rich tooling** — `maslc build`, `maslc check`, `maslc fmt`, `maslc lint`, `maslc doc`, `maslc lsp`.
- **VS Code extension** — real-time diagnostics powered by the LSP server.

---

## Installation

### From crates.io

```bash
cargo install maslc
```

### From source

```bash
git clone https://gitlab.com/exytech/community/masl
cd maduka/masl
cargo build --release --bin maslc
# Optionally install globally:
cargo install --path crates/maslc
```

### Pre-built binaries

Download the latest release from [GitHub Releases](https://gitlab.com/exytech/community/masl/releases) for:

- `x86_64-unknown-linux-gnu`
- `x86_64-apple-darwin` / `aarch64-apple-darwin`
- `x86_64-pc-windows-msvc`

---

## Quick Start

**1. Create a schema file `my_app.mdk`:**

```masl
namespace my_app
schema 1

subject User

resource Document {
    relation {
        author:   User
        reviewer: User
    }
    grant {
        view    => author | reviewer
        edit    => author
        delete  => author
    }
}
```

**2. Validate:**

```bash
maslc check my_app.mdk
```

**3. Compile to binary:**

```bash
maslc build my_app.mdk --out my_app.mdkc
```

**4. Inspect / format / lint:**

```bash
maslc fmt  my_app.mdk       # auto-format in place
maslc lint my_app.mdk       # architectural lint warnings
maslc doc  my_app.mdk       # generate markdown documentation
```

---

## CLI Reference

```
maslc <COMMAND> [OPTIONS]

Commands:
  build   Compile a .mdk schema to a .mdkc binary
  check   Parse and validate a schema without producing output
  fmt     Format a .mdk file in place
  lint    Run the architectural linter
  doc     Generate markdown documentation from the schema
  lsp     Start the LSP server (used by editor extensions)

Options:
  -h, --help       Print help
  -V, --version    Print version
```

### `maslc build`

```
maslc build <INPUT> [--out <OUTPUT>]

Arguments:
  <INPUT>          Path to the .mdk source file
  --out <OUTPUT>   Output path for the .mdkc binary [default: <INPUT>.mdkc]
```

### `maslc check`

```
maslc check <INPUT>
```

Runs parsing, semantic analysis, and validation. Exits `0` on success, `1` on error — suitable for CI.

### `maslc fmt`

```
maslc fmt <INPUT> [--check]

  --check    Fail if the file is not already formatted (for CI)
```

### `maslc lint`

```
maslc lint <INPUT>
```

Emits architectural warnings (public contracts violations, naming conventions, unused aliases, etc.).

### `maslc doc`

```
maslc doc <INPUT> [--out <DIR>]

  --out <DIR>    Output directory for generated markdown [default: ./docs]
```

---

## VS Code Extension

Install from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=exytech.masl-lsp-client) or via VSIX:

```bash
code --install-extension masl-lsp-client-1.0.3.vsix
```

The extension provides:

- Real-time diagnostics (errors & warnings as you type).
- Syntax recognition for `.mdk` files.
- Auto-closing brackets and comment toggling.

**Requires `maslc` in your `PATH`**, or configure:

```json
"masl.compiler.path": "/usr/local/bin/maslc"
```

---

## Library Usage (Rust)

If you want to integrate MASL in your application to evaluate authorization queries, use the `masl_runtime` crate:

```toml
[dependencies]
masl_runtime = { version = "0.1.0" }
```

### Quick Example

```rust
use masl_runtime::prelude::*;

// 1. Define a TupleReader (e.g. connected to your SurrealDB or Postgres database)
struct MyDatabase;

impl TupleReader for MyDatabase {
    async fn exists(
        &self,
        _namespace: &str,
        subject_type: &str,
        subject_id: &str,
        relation: &str,
        object_type: &str,
        object_id: &str,
    ) -> Result<bool, Box<dyn std::error::Error + Send + Sync>> {
        // Query database to check if the tuple exists
        Ok(true)
    }

    async fn lookup_subjects(
        &self,
        _namespace: &str,
        _relation: &str,
        _object_type: &str,
        _object_id: &str,
    ) -> Result<Vec<(String, String)>, Box<dyn std::error::Error + Send + Sync>> {
        // Find indirect relation parent subjects (e.g. groups containing this user)
        Ok(vec![])
    }

    async fn lookup_resources(
        &self,
        _namespace: &str,
        _subject_type: &str,
        _subject_id: &str,
        _relation: &str,
    ) -> Result<Vec<(String, String)>, Box<dyn std::error::Error + Send + Sync>> {
        Ok(vec![])
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    // 2. Load compiled schema(s) (either a folder, file, or raw bytes)
    let schema = CompiledSchema::load_from_directory("policies/compiled/")?;

    // 3. Construct the Authorizer via builder
    let authorizer = Authorizer::builder()
        .schema(schema)
        .tuple_store(MyDatabase)
        .max_depth(32) // recursion limit guard
        .build()?;

    // 4. Run the check!
    let result = authorizer.authorize(AuthorizationQuery {
        namespace: "commerce".to_string(),
        subject_type: "User".to_string(),
        subject_id: "alice".to_string(),
        action: "view".to_string(),
        object_type: "Store".to_string(),
        object_id: "store-42".to_string(),
    }).await?;

    assert_eq!(result, AuthorizationResult::Allowed);
    Ok(())
}
```

---

## Crate Architecture

This repository is a Cargo workspace. The crates are layered as follows:

```
maslc (binary)
 └── masl_compiler      — compilation driver (orchestrates all phases)
      ├── masl_parser   — Pest-based parser, produces AST
      ├── masl_hir      — High-level IR (semantic model)
      ├── masl_validator — architectural & performance lint checks
      ├── masl_ir       — lowered intermediate representation
      └── masl_bytecode — .mdkc binary serialization

masl_runtime            — high-performance ReBAC reference runtime
masl_formatter          — canonical formatting of .mdk source
masl_linter             — standalone linter rules (naming, public contracts)
masl_lsp                — LSP server (tower-lsp, stdio transport)
masl_diagnostics        — shared diagnostic types (errors, warnings, spans)
```

| Crate              | Description             |    Publish    |
| ------------------ | ----------------------- | :-----------: |
| `maslc`            | CLI binary              |      ✅       |
| `masl_compiler`    | Compiler driver         |      ✅       |
| `masl_parser`      | Parser + AST            |      ✅       |
| `masl_hir`         | Semantic HIR            |      ✅       |
| `masl_validator`   | Architectural validator |      ✅       |
| `masl_ir`          | IR types                |      ✅       |
| `masl_bytecode`    | `.mdkc` encoder/decoder |      ✅       |
| `masl_runtime`     | ReBAC reference engine  |      ✅       |
| `masl_formatter`   | Source formatter        |      ✅       |
| `masl_linter`      | Linter rules            |      ✅       |
| `masl_lsp`         | LSP server              |      ✅       |
| `masl_diagnostics` | Shared diagnostics      |      ✅       |

---

## Examples

See the [`examples/`](examples/) directory:

| File           | Description                                               |
| -------------- | --------------------------------------------------------- |
| `commerce.mdk` | Multi-tenant e-commerce schema (stores, products, orders) |

---

## Documentation

- **[MASL Book](docs/book/)** — language guide (concepts, operators, best practices).
- **[RFCs](rfcs/)** — design specifications and architectural decisions.
- **[crates.io docs](https://docs.rs/maslc)** — generated API documentation.

---

## Contributing

1. Fork the repository.
2. Create a feature branch: `git checkout -b feat/my-feature`.
3. Run checks before committing:
   ```bash
   cargo test --workspace
   cargo clippy --workspace --all-targets
   cargo fmt --check
   ```
4. Open a pull request.

New language features must be discussed in an RFC first — see [`rfcs/`](rfcs/).

---

## License

MIT — see [LICENSE](LICENSE).
