Metadata-Version: 2.4
Name: tuoni-script-engine-stubs
Version: 0.15.0
Summary: PEP 561 stub-only package for the Tuoni internal Python scripting
Requires-Python: >=3.12
Description-Content-Type: text/markdown

# Tuoni Script Engine type stubs

Type hints for Python scripts run by Tuoni. Install this package locally to get
editor completion, API documentation, and static type checking for
`tuoni_script_engine`.

The package contains type information only. Tuoni provides the actual
`tuoni_script_engine` module when it runs a server-side script.

Python 3.12 or newer is required.

## Installation

```shell
python -m pip install tuoni-script-engine-stubs
```

To check a script with Pyright:

```shell
python -m pip install pyright
python -m pyright path/to/script.py
```

## Quick example

```python
import tuoni_script_engine as tse

for agent in tse.agents.list(status=tse.AgentStatus.ACTIVE):
    print(agent.guid, agent.metadata.hostname)

tse.discovery.services.create(
    "10.10.20.15",
    445,
    protocol="tcp",
    banner="SMB",
)
```

## API overview

| API | What it provides |
| --- | --- |
| `agents` | Find agents, inspect metadata and listeners, change status, and queue commands. |
| `commands` | Queue, inspect, update, or cancel commands and register dynamic aliases. |
| `command_templates` | Inspect available commands, schemas, and example configurations. |
| `command_aliases` | Create and manage saved aliases with fixed configurations. |
| `discovery` | Create, search, update, archive, and restore hosts, services, and credentials. |
| `events` | Subscribe to live events and query recorded events. |
| `files` | Upload and access files stored by Tuoni. |
| `listeners` | Create, inspect, start, stop, reconfigure, and delete listeners. |
| `payloads` | Create, inspect, generate, and archive payloads. |
| `payload_templates` | Inspect available payload types and their configuration schemas. |
| `plugins` | Inspect loaded listener, command, and payload plugins. |
| `jobs` | Inspect jobs and pause, resume, or restart supported jobs. |
| `settings` | Read server and plugin settings. |
| `ips` | List server IP addresses detected by Tuoni. |

APIs that accept configuration use one of these types:

```python
tuoni_script_engine.JsonConfiguration({"key": "value"})
tuoni_script_engine.BinaryConfiguration(b"content")
tuoni_script_engine.MultipartConfiguration(
    files={"payload.bin": b"content"},
    json={"key": "value"},
)
```

## Dynamic command aliases

A dynamic alias adds a command to Tuoni for as long as its script is loaded.
Register an object that implements these methods:

- `configuration_schema()` returns the command configuration as JSON Schema.
- `can_send_to_agent(agent)` decides whether the command is available for an
  agent.
- `validate_config(config, agent)` performs any additional validation. Raise
  `ValidationError` when the input should be rejected.
- `execute(ctx, config, agent)` runs the alias. Use `ctx` to queue child
  commands, publish results, and finish or fail the alias.

The following alias exposes the native `ps` command under a new name:

```python
import tuoni_script_engine as tse


class ProcessListAlias(tse.DynamicAlias):
    description = "List running processes"

    def configuration_schema(self) -> str:
        return '{"type":"object","properties":{},"additionalProperties":false}'

    def can_send_to_agent(self, agent: tse.Agent) -> bool:
        return agent.type is tse.AgentType.SHELLCODE_AGENT

    def validate_config(
        self,
        config: tse.Configuration,
        agent: tse.Agent,
    ) -> None:
        pass

    def execute(
        self,
        ctx: tse.AliasContext,
        config: tse.Configuration,
        agent: tse.Agent,
    ) -> None:
        command = ctx.queue_command("ps", tse.JsonConfiguration({}))

        if not command.wait_for_completion(timeout=300):
            command.cancel()
            ctx.fail("Process listing timed out")
            return

        if command.is_failed():
            error = command.result.error_message if command.result else None
            ctx.fail(error or "Process listing failed")
            return

        if command.result:
            ctx.set_result(command.result.entries)
        ctx.finish()


tse.commands.register_dynamic_alias("script-ps", ProcessListAlias())
```

An alias must eventually call `ctx.finish()` or `ctx.fail()`. It may call
`ctx.set_result(...)` before completion to publish ongoing or final result
entries.
