Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion docs/modeldescr/actions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ Actions are predefined batches of specific acts that are yielding
the state of an entity, based on its constraints. Actions are binding
data to modules.

An action normally participates in the internal execution graph of the model. In other words,
the mere presence of an action definition does not automatically mean that the action should be
presented as a public query target. When the model author wishes to expose an action explicitly,
that action may be listed in the model's top-level ``interface.actions`` collection. This keeps
the distinction clear between the implementation of the model and the public surface that callers
are expected to use.

.. important::

The following rules are applied to an action:
Expand Down Expand Up @@ -455,4 +462,4 @@ that checks if the file is really there.
require a valid constraints attached to the corresponding action!

Likewise chain conditions can be used for consistency check: if a specific device is working
as expected, no additional checks are needed (as an example).
as expected, no additional checks are needed (as an example).
34 changes: 32 additions & 2 deletions docs/modeldescr/layout.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Model description index file has the following structure:
This is a description of this model
that gives you more idea what it is etc.
maintainer: John Smith <john.smith@example.com>
interface: null
checkbook: null
config: null

Expand All @@ -75,8 +76,37 @@ The following fields are supported:

``config``

Global configuration section. It is applied to the whole session, globally. However
different model can have a different configuration.
Global configuration section. It is applied to the whole session, globally. However
different model can have a different configuration.

``interface``

The ``interface`` section is optional. Its purpose is to define the public callable surface
of the model explicitly, rather than relying on the full internal structure of the model.
This is especially useful when a model contains helper entities or internal gating actions that
should participate in evaluation, but should not be shown as operator-facing targets.

The syntax is intentionally simple and typed. It accepts three optional lists named
``checkbook``, ``entities`` and ``actions``.

.. code-block:: yaml

interface:
checkbook:
- main-audit
entities:
- all
- summary
actions:
- python-proof

In this form, ``main-audit`` is a public checkbook label, ``all`` and ``summary`` are public
entity entrypoints, and ``python-proof`` is declared as a public direct action entrypoint.
The declaration itself does not change the internal execution graph of the model. It simply
states what should be treated as public by tools that inspect the model.

If ``interface`` is not present at all, SysInspect keeps the historic behaviour. In that case,
every inferred entrypoint is considered public.

``checkbook``

Expand Down
8 changes: 8 additions & 0 deletions docs/modeldescr/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ The declarative approach is much easier to comprehend and use, because it focuse
system should do, rather than how to achieve it. In this way more readable and maintainable
configurations are achieved. Maintenance is easier because the configurations remain simple and predictable.

Recent versions of the model description also allow the author to declare an explicit public
interface for the model. This is useful when a model contains helper entities, gating actions,
or intermediate implementation details that are necessary for evaluation but are not meant to be
presented as first-class query targets to operators. In that situation the model may declare an
``interface`` section and list only those entrypoints that are intended to be public. If the
section is omitted, the legacy behaviour remains in effect and every inferred entrypoint is
considered public.

.. important::

In a nutshell, declarative configurations are easier for teams to understand, update, and share
Expand Down
239 changes: 239 additions & 0 deletions examples/demos/nopython/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
# Python Without Host Python

This demo shows how SysInspect can execute Python-based runtime payloads on a
target that does not provide a system `python3` binary.

The execution path is intentionally split into two layers:

- native SysInspect modules collect host facts and drive the decision logic
- the embedded `runtime.py3` runtime executes Python only when the model DSL
determines that the target matches the intended profile

This keeps the Python payload focused on proof of execution rather than policy
or branching logic.

## Purpose

The demo is designed for compact or appliance-style targets where host Python
should not be treated as a deployment prerequisite.

It demonstrates that SysInspect can:

- identify the target environment using native modules
- evaluate model constraints before runtime dispatch
- execute Python code through the embedded runtime when the target matches
- deliver Python helper libraries as repository payloads rather than operating
system packages

The model is fully local at execution time and does not depend on outbound
network access from the minion.

## Model Behavior

The model evaluates four host-side facts:

- target is Alpine
- target is Fedora
- host `python3` is absent
- host `python3` is present

Based on those facts, the model selects one applicable branch:

- Alpine without host Python:
- run `py3.nopython`
- Fedora:
- return a verification message from YAML
- non-Fedora hosts with host Python present:
- return a verification message from YAML
- non-Alpine, non-Fedora hosts without host Python:
- return a generic verification message from YAML

The Python payload itself returns runtime proof only, including interpreter
identity, version, selected runtime values, and helper-import evidence.

## Repository Contents

Files in this directory:

- `model.cfg`
- `lib/runtime/python3/nopython.py`
- `lib/runtime/python3/nopyproof.py`
- `lib/runtime/python3/site-packages/nopykit/__init__.py`

## Scope And Entities

Install the model under the `nopython` scope.

This demo also declares an explicit public interface:

```yaml
interface:
entities:
- all
actions:
- python-proof
```

The `interface` section is optional.

- if `interface` is present, only listed entity and action entrypoints are
considered part of the model's public surface
- if `interface` is absent, the current legacy behavior remains in effect and
all inferred entrypoints are public

The interface section does not alter internal execution semantics. It describes
which entrypoints are intended to be exposed to callers.

Entities exposed by this model:

- `all`
- `python-proof`
- `verify-fedora`
- `verify-python`
- `verify-other`

## Prerequisites

The master must provide:

- the `runtime.py3` dispatcher module
- the `nopython` model scope
- the runtime Python payload tree from this directory

The minion does not need a system `python3` package.

## Install The Model

Copy `model.cfg` into the master's models root:

```text
$MASTER/data/models/nopython/model.cfg
```

Export the scope from the master configuration:

```yaml
config:
master:
fileserver.models:
- nopython
```

## Install The Embedded Python Runtime

Build and register `runtime.py3`:

```bash
make all-devel
sysinspect module -A --path ./target/debug/runtime/py3-runtime --name runtime.py3 --descr "Python 3 runtime"
```

## Install The Python Runtime Payload Tree

This demo ships its payloads under `lib/` so the runtime directory structure is
preserved during publication.

From `examples/demos/nopython`, publish the `lib` tree itself:

```bash
sysinspect module -A --path ./lib -l
```

Then sync the cluster:

```bash
sysinspect --sync
```

Important:

- select or publish `examples/demos/nopython/lib`
- do not publish the parent directory `examples/demos/nopython`

The runtime expects the published tree to land under:

- `lib/runtime/python3/`
- `lib/runtime/python3/site-packages/`

## Python Runtime Layout Rules

The embedded Python runtime expects the following repository layout:

- executable Python modules:
- `lib/runtime/python3/`
- helper libraries:
- `lib/runtime/python3/site-packages/`

For this demo, that means:

- `lib/runtime/python3/nopython.py`
- `lib/runtime/python3/nopyproof.py`
- `lib/runtime/python3/site-packages/nopykit/__init__.py`

Each runtime Python module should export:

- `run(req)` as the entrypoint
- optional documentation as either:
- `doc = {...}`
- `def doc(): return {...}`

The documentation object must be the payload itself, not wrapped as
`{"doc": ...}`.

## Verify Installation

Inspect the published runtime payloads:

```bash
sysinspect module -Ll
```

Expected library entries include:

- `runtime/python3/nopython.py`
- `runtime/python3/nopyproof.py`
- `runtime/python3/site-packages/nopykit/__init__.py`

## Run The Demo

Run the full model:

```bash
sysinspect "nopython/all" '*'
```

Or run one branch-oriented entity directly:

```bash
sysinspect "nopython/python-proof" '*'
sysinspect "nopython/verify-fedora" '*'
sysinspect "nopython/verify-python" '*'
sysinspect "nopython/verify-other" '*'
```

## Expected Outcomes

When the Python proof branch is selected, the action should return structured
runtime evidence such as:

- Python runtime implementation name
- Python runtime version
- Python platform and byte order
- selected `sys` values
- helper module import evidence

The branch decision itself is made by the model DSL, not by the Python payload.

Typical outcomes:

- Alpine without host Python:
- `python-proof` is applicable
- Fedora:
- `verify-fedora` is applicable
- non-Fedora with host Python present:
- `verify-python` is applicable
- non-Alpine, non-Fedora without host Python:
- `verify-other` is applicable

Non-selected branches are reported as `Not Applicable`, not as execution
failures.
34 changes: 34 additions & 0 deletions examples/demos/nopython/lib/runtime/python3/nopyproof.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import sys

from nopykit import proof_value


doc = {
"name": "nopyproof",
"version": "0.1.0",
"author": "SysInspect Demo",
"description": "Proof module that imports a helper package from runtime site-packages.",
"arguments": [
{"name": "a", "type": "number", "required": False, "description": "First input"},
{"name": "b", "type": "number", "required": False, "description": "Second input"},
],
"returns": {
"description": "Structured proof that helper imports worked.",
"sample": {"import_ok": True, "proof": 12, "python_runtime": "rustpython"},
},
}


def run(req):
args = req.get("args", {})
a = args.get("a", 2)
b = args.get("b", 5)
impl = getattr(getattr(sys, "implementation", None), "name", "python")
return {
"import_ok": True,
"a": a,
"b": b,
"proof": proof_value(a, b),
"python_runtime": impl,
"message": f"Python helper import succeeded inside {impl} without requiring host python3.",
}
Loading
Loading