Skip to content

Latest commit

 

History

History
355 lines (236 loc) · 5.17 KB

File metadata and controls

355 lines (236 loc) · 5.17 KB

📘 ZDTT Plugin Development Guide

Create safe, powerful extensions for the ZDTT Terminal.


🟦 Introduction

ZDTT supports a secure, sandboxed plugin system that allows developers to extend the terminal with custom commands.

Plugins live inside:

~/.zdtt/plugins/

A plugin is simply a Python file that:

  1. Contains no top-level executable code

  2. Defines functions or classes

  3. Defines a mandatory function:

    def register_commands():
        return { "command": callable }

Plugins are automatically loaded when ZDTT starts or when you run:

plugins reload

🛡️ Plugin Security Model

ZDTT has strict safety validation to protect users from malicious plugins. Every plugin must pass six security layers:


1. AST Validation

At load time, ZDTT parses the plugin using Python’s AST.

Allowed at the top level:

  • Imports
  • From-imports
  • Function definitions
  • Class definitions
  • A file-level docstring

Forbidden (causes quarantine):

  • Print statements
  • Assignments
  • Function calls
  • Loops
  • Try/except blocks
  • Any executable code
  • Anything that runs automatically

Example of an unsafe plugin:

print("hacked!")     # ❌ this will be quarantined
os.system("rm -rf /")  # ❌ also quarantined

Unsafe plugins are moved to:

~/.zdtt/quarantine/

2. Import Trust Prompt

Plugins may import modules:

import os
import subprocess

However: Any plugin with imports triggers a trust confirmation.

If the user does not trust the plugin, it is quarantined.

If the user approves, the plugin name is added to:

config.json → trusted_plugins

Only trusted plugins may use __import__.


3. Sandboxed Execution

Plugins run inside a restricted environment:

  • Only safe builtins are exposed
  • Dangerous builtins (like exec or eval) are blocked
  • Imports only work for trusted plugins
  • Code cannot escape the sandbox

4. register_commands() Validation

Every plugin must define:

def register_commands():
    return {"name": function}

ZDTT verifies:

  • The function exists
  • The return value is a dict
  • All values are callable
  • Command names are valid strings

5. Protected Command Names

Plugins cannot override important commands such as:

ssh, sudo, su, cp, mv, rm, ls, cat,
chmod, chown, history, zps, zdtt,
pip, python, python3, curl, wget

Attempting to override them causes quarantine.


6. Runtime Registration

Once the plugin passes all previous checks, ZDTT adds its commands to the shell environment.

Example:

{
  "weather": cmd_weather,
  "hello": cmd_hello
}

These appear in autocomplete and help.


🟩 Plugin Structure

A minimal valid plugin:

"""
My Plugin
"""

def cmd_test(args):
    print("Hello from ZDTT plugin!")

def register_commands():
    return {"test": cmd_test}

🟧 Arguments

ZDTT passes command arguments as a list.

Example:

hello world how are you

Results in:

cmd_hello(["world", "how", "are", "you"])

🟪 Example Plugin (Official)

From example_plugin.py:

"""
Example ZDTT Plugin
"""

import subprocess
import os

def cmd_hello(args):
    ...

def cmd_weather(args):
    ...

def cmd_sysinfo(args):
    ...

def register_commands():
    return {
        "hello": cmd_hello,
        "weather": cmd_weather,
        "sysinfo": cmd_sysinfo
    }

All three commands use argument lists exactly as ZDTT passes them.


🟫 Installing Plugins

Manual Install

Place plugin file in:

~/.zdtt/plugins/

Then reload:

plugins reload

Install via ZPS

Install directly from a URL:

zps install https://raw.githubusercontent.com/user/repo/plugin.py

ZPS will:

  • Download the file
  • Save it to your plugin directory
  • Warn if it already exists
  • Ask if you trust imports (if any)

🟨 Debugging Plugins

ZDTT logs plugin errors to:

~/.zdtt/plugin_errors.log

Quarantined plugins appear in:

~/.zdtt/quarantine/

Reload plugins:

plugins reload

🟩 Best Practices for Plugin Developers

✔ Wrap all code inside functions ✔ Avoid imports unless required ✔ Validate arg lists ✔ Use try/except around risky operations ✔ Keep commands short and simple ✔ Document your commands ✔ Never modify global state ✔ Don’t override protected commands


🟦 Advanced Plugin Tips

Show usage/help

def cmd_calc(args):
    """Usage: calc <expression>"""
    ...

ZDTT automatically pulls these docstrings into the help system.

Combine args into a string

expr = " ".join(args)

Use subprocess safely

try:
    subprocess.run(["ls"])
except Exception as e:
    print("Error:", e)

Read files safely

Use try/except to avoid crashing the shell.


🟣 Full Plugin Template

"""
Plugin Name: <your plugin>
Description: <what it does>
Author: <you>
"""

# Optional imports (will require trust prompt)
import subprocess

def cmd_example(args):
    print("Example plugin working!")

def register_commands():
    return {
        "example": cmd_example
    }