Metadata-Version: 2.4
Name: infraclass
Version: 1.1.2
Summary: Infraclass is a lightweight, zero-dependency, and highly secure hierarchical inventory compiler for Python automation engines (like ansible and pyinfra). It allows you to build inventories using a top-down class inheritance layout, natively supporting encrypted secrets using age.
License: MIT
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: System Administrators
Classifier: Topic :: System :: Systems Administration
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyyaml>=6.0
Dynamic: license-file

# Infraclass

Infraclass is a lightweight, zero-dependency inventory compiler. You describe your infrastructure as a hierarchy of YAML files — nodes, and reusable "classes" they inherit from — and infraclass merges them into one flat set of config values per node, decrypting any `age`-encrypted secrets along the way.

Infraclass has no knowledge of pyinfra, Ansible, or any other automation tool. It only produces data — a Python dict, or YAML on stdout. Feeding that data into whatever automation engine you use is a separate step you write yourself (see "Calling it from a script instead of the CLI" below).

## Project Directory Structure

Rename your data directory to `infraclass/` to align with the framework:

```text
automation/
├── your_inventory_script.py   # Your own integration script — see "Calling it from a script instead of the CLI"
└── infraclass/                 # Your hierarchical data directory
    ├── classes/                # Reusable configuration blueprints
    │   ├── components/
    │   ├── platform/
    │   │   └── init.yml        # Standard shared properties & secrets
    │   └── roles/
    ├── nodes/                  # Machine-specific inventory targets
    │   └── node1.example.com.yml
    └── vault/
        └── vault.age            # Encrypted secrets store
```

## Setup

### Install the package
```bash
uv tool install infraclass
```

### Point it at your age key
By default, infraclass looks for your decryption key at `~/.age/identity.age`. Put your private key there, or tell infraclass to use a different path:
```bash
export INFRACLASS_AGE_KEY_FILE="$HOME/.age/identity.age"
```

## Systemd / Credentials Directory Resolution

When running inside a systemd service (e.g. a CI/CD runner) that provides the vault key via `LoadCredentialEncrypted`, infraclass finds it automatically — no config changes needed. Key resolution (in `infraclass/vault.py`) checks, in order:

1. `$CREDENTIALS_DIRECTORY` (set by systemd), for a file matching `age-key*` or `age-pq-key*`
2. `$INFRACLASS_AGE_KEY_FILE`, if set
3. The default location, `~/.age/identity.age`

## Trying it out

### From the command line
```bash
infraclass show node1.example.com
```
Prints that node's fully compiled configuration as YAML. This is the quickest way to sanity-check that a node compiles, and to see exactly what data it produces.

By default (or with `--mask-secret-values`, the same thing spelled out explicitly), the vault isn't decrypted at all — every `!secret` reference is shown as a `<SECRET: id>` placeholder, and no passphrase/Touch ID prompt appears. Add `--reveal-secret-values` to decrypt the vault and print the real secret values instead.

Vault/secret management lives under its own `vault` command — `infraclass vault add`, `infraclass vault remove <id>`, `infraclass vault show <id>`, `infraclass vault audit`, `infraclass vault prune`, `infraclass vault re-encrypt`. Run `infraclass vault --help` for the full list.

### Calling it from a script instead of the CLI

If you need the compiled data inside a script rather than as YAML from the CLI, call `compile_node_data` directly:

```python
import infraclass

node_data = infraclass.compile_node_data("node1.example.com", base_dir="infraclass")

node_data["parameters"]  # merged config for this node, secrets decrypted
node_data["classes"]     # every class this node inherited from
```

`compile_node_data` is a one-shot convenience wrapper — each call decrypts the vault and re-parses class files from scratch. If you're compiling many nodes in a loop, like `pyinfra`'s `inventory.py` does when it builds the full host/group inventory, construct a `Compiler` once and call `.compile()` per node instead — it reuses the decrypted vault and parsed class files across every call:

```python
import infraclass

compiler = infraclass.Compiler(base_dir="infraclass")
for node_data in (compiler.compile(name) for name in node_names):
    ...  # build inventory entries from node_data
```
