From 0aea7cd6bc4bce035a35afd6667bca790b6cd887 Mon Sep 17 00:00:00 2001 From: Mohamed Beydoun Date: Fri, 16 Oct 2026 18:37:24 -0400 Subject: [PATCH] add bot logs toggle --- LICENSE | 2 +- README.md | 1 + SECURITY.md | 2 +- docker/rustix/manager.py | 2 +- egg-python.json | 14 ++++++++++++-- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/LICENSE b/LICENSE index 6bbcb4a..0fea016 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) Mkkbeydoun and contributors +Copyright (c) Mkkbeydoun and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 1f23da1..a413725 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,7 @@ The server console also controls the bots. Type `help` for the list: | Bot Panel Password (`PANEL_PASSWORD`) | | Web panel password; blank generates one | | Bots Folder (`BOTS_DIR`) | | Folder holding the bot folders; blank is the server's main folder | | Auto Restart Bots (`AUTO_RESTART`) | `1` | Restart crashed bots with backoff | +| Bot Logs In Main Console (`CONSOLE_MIRROR`) | `0` | Also show every bot's output in the main console, not only in its own log in the panel | | Update Check (`UPDATE_CHECK`) | `1` | Say in the console when the egg or the Docker image has an update | ### Git diff --git a/SECURITY.md b/SECURITY.md index f22483a..0aebef1 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ ## Reporting a vulnerability -Please do not open a public issue for security problems. Report them privately through [GitHub's private vulnerability reporting](https://github.com/Rustix-Development/pterodactyl-python-egg/security/advisories/new), or by email to mohamed@beyd.ca. +Please do not open a public issue for security problems. Report them privately through [GitHub's private vulnerability reporting](https://github.com/Rustix-Development/pterodactyl-python-egg/security/advisories/new), or by email to mohamed@rustix.xyz. Include the egg version, the Python version (Docker image) of the server, whether Multi-Bot Mode is on, your panel version and the steps to reproduce. You'll get a reply as soon as possible, and a fix will be released before the issue is made public. diff --git a/docker/rustix/manager.py b/docker/rustix/manager.py index e3e777f..6e816f7 100644 --- a/docker/rustix/manager.py +++ b/docker/rustix/manager.py @@ -44,7 +44,7 @@ def env_on(name, default="1"): LOG_DIR = HOME / "logs" ENTRIES = os.environ.get("BOT_ENTRIES", "bot.py main.py app.py").split() AUTO_RESTART = env_on("AUTO_RESTART") -MIRROR = env_on("CONSOLE_MIRROR") +MIRROR = env_on("CONSOLE_MIRROR", "0") # bot output in the main console too, not just the panel PORT = int(os.environ.get("SERVER_PORT") or os.environ.get("PORT") or 8080) EXCLUDED = {"logs", "__pycache__", "node_modules", "venv", "env", "backup-dont-touch"} # Never hand these to bot processes: panel/git secrets and egg plumbing. diff --git a/egg-python.json b/egg-python.json index 770b27c..dda5990 100644 --- a/egg-python.json +++ b/egg-python.json @@ -6,7 +6,7 @@ }, "exported_at": "2026-10-16T22:00:00+00:00", "name": "Python", - "author": "mohamed@beyd.ca", + "author": "mohamed@rustix.xyz", "description": "Run Python apps and Discord bots, on Python 3.11 to 3.15.\n\n- Dependencies: requirements.txt is installed with uv into a venv, and skipped on restarts when nothing changed\n- Git: clone your bot from a Git repo, optionally pulling updates on every start\n- Multi-Bot Mode (set by an admin): host many bots on one server, each in its own folder with its own packages and .env, managed from a web panel on the server's port\n\nBy Rustix (rustix.xyz).", "features": [], "docker_images": { @@ -26,7 +26,7 @@ }, "scripts": { "installation": { - "script": "#!/bin/ash\n# Rustix Python installer: sets up the server's files (Git clone, or a starter bot folder).\n\n# Bump this whenever the egg changes. Servers compare it with the egg on GitHub at\n# startup and show an update notice in the console.\nEGG_VERSION=\"1.0.0\"\n\nis_true() { [ \"$1\" = \"1\" ] || [ \"$1\" = \"true\" ]; }\n\n# Drop user:token@ from a git URL so a changed token still counts as the same repo\nstrip_auth() { printf '%s' \"$1\" | sed -E 's#^([a-z]+://)[^/@]*@#\\1#'; }\n\n# The install container has a terminal nobody types into: never wait for a git password\nexport GIT_TERMINAL_PROMPT=0\n\ncd /mnt/server || exit 1\napk add --no-cache git || { echo \"Failed to install git\"; exit 1; }\n# Server files belong to the server user, not root; let git work on them anyway\ngit config --global --add safe.directory '*'\n\n# Anything here besides what the egg itself creates?\nhas_files() {\n [ -n \"$(find . -mindepth 1 -maxdepth 1 ! -name .egg-version ! -name logs ! -name .cache ! -name .venv ! -name .rustix | head -n 1)\" ]\n}\n\nfinish() {\n mkdir -p /mnt/server/logs\n echo \"${EGG_VERSION}\" > /mnt/server/.egg-version\n echo \"$1\"\n exit 0\n}\n\n# Starter bot for multi-bot mode, so the panel has something to show. Auto-start is off.\nseed_example_bot() {\n has_files && return\n mkdir -p example-bot\n cat > example-bot/bot.py <<'PY'\n# Example bot: copy this folder for each bot you host. The panel runs every folder\n# that has a bot.py (or main.py / app.py) in it, each with its own packages and .env.\nimport os\nimport time\n\nprint(f\"example-bot running, DISCORD_TOKEN set: {bool(os.getenv('DISCORD_TOKEN'))}\")\nwhile True:\n time.sleep(60)\nPY\n printf '# discord.py>=2.6\\n' > example-bot/requirements.txt\n printf '# Each bot reads its own .env\\nDISCORD_TOKEN=\\n' > example-bot/.env\n touch example-bot/.disabled\n echo \"Added example-bot/ (auto-start off). Copy it for each bot you want to host.\"\n}\n\nif is_true \"${USER_UPLOAD}\"; then\n is_true \"${MULTI_BOT}\" && seed_example_bot\n finish \"User Uploaded Files is on, skipping Git setup. Upload your files.\"\nfi\n\nif [ -z \"${GIT_ADDRESS}\" ]; then\n is_true \"${MULTI_BOT}\" && seed_example_bot\n if is_true \"${MULTI_BOT}\"; then\n finish \"Install complete. Put each bot in its own folder, then open the web panel on this server's address.\"\n fi\n finish \"Install complete. Upload your bot (${PY_FILE:-bot.py}) and its requirements.txt.\"\nfi\n\n# Git\ncase \"${GIT_ADDRESS}\" in\n *.git) ;;\n *) GIT_ADDRESS=\"${GIT_ADDRESS}.git\" ;;\nesac\n\nif [ -n \"${USERNAME}\" ] && [ -n \"${ACCESS_TOKEN}\" ]; then\n GIT_ADDRESS=\"https://${USERNAME}:${ACCESS_TOKEN}@${GIT_ADDRESS#*://}\"\nfi\n\nif has_files; then\n if [ -d .git ]; then\n if [ \"$(strip_auth \"$(git config --get remote.origin.url)\")\" = \"$(strip_auth \"${GIT_ADDRESS}\")\" ]; then\n echo \"Pulling latest files from git\"\n # Picks up a changed Git Username/Access Token\n git remote set-url origin \"${GIT_ADDRESS}\"\n git pull --ff-only || echo \"git pull failed, keeping the current files.\"\n else\n echo \"This server is a clone of a different git repo, leaving it alone.\"\n fi\n else\n echo \"This server already has files that aren't from git, leaving them alone.\"\n fi\nelse\n echo \"Cloning files from git\"\n rm -rf /tmp/clone\n if [ -n \"${BRANCH}\" ]; then\n git clone --single-branch --branch \"${BRANCH}\" \"${GIT_ADDRESS}\" /tmp/clone || { echo \"git clone failed, check Git Repo Address, Git Branch and credentials\"; exit 1; }\n else\n git clone \"${GIT_ADDRESS}\" /tmp/clone || { echo \"git clone failed, check Git Repo Address and credentials\"; exit 1; }\n fi\n cp -a /tmp/clone/. /mnt/server/ && rm -rf /tmp/clone\nfi\n\nfinish \"Install complete.\"\n", + "script": "#!/bin/ash\n# Rustix Python installer: sets up the server's files (Git clone, or a starter bot folder).\n\n# Bump this whenever the egg changes. Servers compare it with the egg on GitHub at\n# startup and show an update notice in the console.\nEGG_VERSION=\"1.0.1\"\n\nis_true() { [ \"$1\" = \"1\" ] || [ \"$1\" = \"true\" ]; }\n\n# Drop user:token@ from a git URL so a changed token still counts as the same repo\nstrip_auth() { printf '%s' \"$1\" | sed -E 's#^([a-z]+://)[^/@]*@#\\1#'; }\n\n# The install container has a terminal nobody types into: never wait for a git password\nexport GIT_TERMINAL_PROMPT=0\n\ncd /mnt/server || exit 1\napk add --no-cache git || { echo \"Failed to install git\"; exit 1; }\n# Server files belong to the server user, not root; let git work on them anyway\ngit config --global --add safe.directory '*'\n\n# Anything here besides what the egg itself creates?\nhas_files() {\n [ -n \"$(find . -mindepth 1 -maxdepth 1 ! -name .egg-version ! -name logs ! -name .cache ! -name .venv ! -name .rustix | head -n 1)\" ]\n}\n\nfinish() {\n mkdir -p /mnt/server/logs\n echo \"${EGG_VERSION}\" > /mnt/server/.egg-version\n echo \"$1\"\n exit 0\n}\n\n# Starter bot for multi-bot mode, so the panel has something to show. Auto-start is off.\nseed_example_bot() {\n has_files && return\n mkdir -p example-bot\n cat > example-bot/bot.py <<'PY'\n# Example bot: copy this folder for each bot you host. The panel runs every folder\n# that has a bot.py (or main.py / app.py) in it, each with its own packages and .env.\nimport os\nimport time\n\nprint(f\"example-bot running, DISCORD_TOKEN set: {bool(os.getenv('DISCORD_TOKEN'))}\")\nwhile True:\n time.sleep(60)\nPY\n printf '# discord.py>=2.6\\n' > example-bot/requirements.txt\n printf '# Each bot reads its own .env\\nDISCORD_TOKEN=\\n' > example-bot/.env\n touch example-bot/.disabled\n echo \"Added example-bot/ (auto-start off). Copy it for each bot you want to host.\"\n}\n\nif is_true \"${USER_UPLOAD}\"; then\n is_true \"${MULTI_BOT}\" && seed_example_bot\n finish \"User Uploaded Files is on, skipping Git setup. Upload your files.\"\nfi\n\nif [ -z \"${GIT_ADDRESS}\" ]; then\n is_true \"${MULTI_BOT}\" && seed_example_bot\n if is_true \"${MULTI_BOT}\"; then\n finish \"Install complete. Put each bot in its own folder, then open the web panel on this server's address.\"\n fi\n finish \"Install complete. Upload your bot (${PY_FILE:-bot.py}) and its requirements.txt.\"\nfi\n\n# Git\ncase \"${GIT_ADDRESS}\" in\n *.git) ;;\n *) GIT_ADDRESS=\"${GIT_ADDRESS}.git\" ;;\nesac\n\nif [ -n \"${USERNAME}\" ] && [ -n \"${ACCESS_TOKEN}\" ]; then\n GIT_ADDRESS=\"https://${USERNAME}:${ACCESS_TOKEN}@${GIT_ADDRESS#*://}\"\nfi\n\nif has_files; then\n if [ -d .git ]; then\n if [ \"$(strip_auth \"$(git config --get remote.origin.url)\")\" = \"$(strip_auth \"${GIT_ADDRESS}\")\" ]; then\n echo \"Pulling latest files from git\"\n # Picks up a changed Git Username/Access Token\n git remote set-url origin \"${GIT_ADDRESS}\"\n git pull --ff-only || echo \"git pull failed, keeping the current files.\"\n else\n echo \"This server is a clone of a different git repo, leaving it alone.\"\n fi\n else\n echo \"This server already has files that aren't from git, leaving them alone.\"\n fi\nelse\n echo \"Cloning files from git\"\n rm -rf /tmp/clone\n if [ -n \"${BRANCH}\" ]; then\n git clone --single-branch --branch \"${BRANCH}\" \"${GIT_ADDRESS}\" /tmp/clone || { echo \"git clone failed, check Git Repo Address, Git Branch and credentials\"; exit 1; }\n else\n git clone \"${GIT_ADDRESS}\" /tmp/clone || { echo \"git clone failed, check Git Repo Address and credentials\"; exit 1; }\n fi\n cp -a /tmp/clone/. /mnt/server/ && rm -rf /tmp/clone\nfi\n\nfinish \"Install complete.\"\n", "container": "alpine:3.24", "entrypoint": "ash" } @@ -122,6 +122,16 @@ "rules": "required|boolean", "field_type": "text" }, + { + "name": "Bot Logs In Main Console", + "description": "Multi-Bot Mode: also show every bot's output in the server's main console. Off shows each bot's output only in its own log in the web panel (and logs/.log).\n\n0 = false (default)\n1 = true", + "env_variable": "CONSOLE_MIRROR", + "default_value": "0", + "user_viewable": true, + "user_editable": true, + "rules": "required|boolean", + "field_type": "text" + }, { "name": "Git Repo Address", "description": "Git repo to clone on install, e.g. https://github.com/you/your-bot",