# Pupoxide (Puppet for the Rust Era)

Pupoxide is a high-performance, memory-safe, and declarative configuration management tool inspired by Puppet, built with Rust and the Rhai scripting engine.

> [!WARNING]
> **Experimental Project / Proof of Concept**
>
> This project is an attempt to reimplement the core ideas of Puppet using Rust. It is **not ready for production use** and serves primarily as an architectural experiment and a playground for ideas.
>
> We are actively looking for **contributors**! If you are interested in Rust, configuration management, or language design, please feel free to open issues or submit PRs.

## Key Features

- **Declarative DSL**: Use [Rhai](https://rhai.rs/) scripts for clear, modular manifests.
- **Hexagonal Architecture**: Core logic isolated from system-specific implementation.
- **Environment & Module Support**: Organize configuration in environments like `production` or `staging`.
- **Idempotency**: Resources ensure the desired system state without redundant actions.

## Installation

```bash
git clone https://gitverse.ru/itmagelab/pupoxide
cd pupoxide
cargo build --release
```

## Quick Start

### Dry-Run Mode (Preview)

You can preview changes without applying them by using the `--dry-run` flag with `run`, `apply`, or `agent` commands:

```bash
cargo run -- run --dry-run --file ./examples/environments/production/manifests/site.rhai
```

This will log actions as "Would ensure resource" instead of executing them.

### 1. Run a single manifest

You can execute any `.rhai` script directly:

```bash
cargo run -- run --file ./examples/environments/production/manifests/site.rhai
```

### Rollback (Undo)

Pupoxide can undo changes made to the system using the `rollback` command. It uses a selective backup system to restore original file contents.

```bash
# Rollback the last transaction
cargo run -- rollback

# Rollback a specific transaction
cargo run -- rollback --transaction-id tx_123456789
```

To enable rollback for a resource, use the `backup: true` parameter (enabled by default):

```rhai
file("/etc/motd", #{
    content: "Welcome to the server!",
    backup: true,
    max_backup_size: 1024 * 1024 // 1MB limit
});
```

### 2. Apply an environment

Apply all manifests from a specific environment using the Puppet-like directory structure:

```bash
# Default config path is /etc/pupoxide
cargo run -- --config ./examples apply --environment production
```

### 3. Client-Server Mode

Pupoxide can operate in a Master/Agent architecture.

**Start the Master Server:**

```bash
cargo run -- --config ./examples master --port 8080
```

**Run the Agent:**

```bash
cargo run -- --config ./examples agent --server http://localhost:8080 --node my-node --environment production
```

## Example Manifest (`site.rhai`)

Pupoxide uses Rhai with a custom DSL. Resources are defined using object maps, and dependencies can be expressed using the `require` attribute or the arrow operator `->`.

```rust
// Load a module
// examples/environments/production/manifests/site.rhai

// Assign role to the current node
"demo".role;
```

## Directory Structure

Pupoxide follows a modular structure for easier management:

```text
[config_dir]/
  environments/
    production/
      manifests/
        site.rhai      # Entry point for the environment (imports roles)
      modules/
        systemd/       # Systemd module (manages units)
        brew/          # Homebrew module (manages packages)
        common/        # Common settings
        demo/          # Demo module
      role/            # Roles: Business logic abstraction
        demo.rhai      # Example Role
      profile/         # Profiles: Technology stack wrapper
        demo.rhai      # Example Profile

## Roles and Profiles Pattern
Pupoxide encourages the standard "Roles and Profiles" pattern to organize your code logic:

- **Roles**: High-level business abstractions (e.g., "Webserver", "Database Node").
  - **Constraints**: Roles can ONLY include Profiles. They cannot contain resources (`file`, `exec`) or include modules directly.
- **Profiles**: Technical stacks that wrap modules (e.g., "Nginx with PHP", "Postgres Hardened").
```

```rust
// role/demo.rhai
"demo".profile;
```

```rust
// profile/demo.rhai
"common".include;
"demo".include;
```

```rust
// modules/common/manifests/init.rhai
import "brew" as b;

// Install packages using the 'brew' module
b::pkg(["htop", "wget"], #{ ensure: "present" });

// Define a file
file("/tmp/.cacherc", #{
    ensure: "present",
    content: "Global settings"
});

// Conditional logic based on facts
if facts["os_family"] == "Darwin" {
    file("/tmp/pupoxide/mac_only_config", #{
        ensure: "present",
        content: "This is macOS"
    });
}
```

```

## Documentation
- [Project Vision](doc/vision.md)
- [Coding Conventions](doc/conventions.md)
- [Development Workflow](doc/workflow.md)
- [Task List](doc/tasklist.md)
