From 88fd5398adfdd520a17240b4626ed3aa2f936ecc Mon Sep 17 00:00:00 2001 From: STELS37 <138387422+STELS37@users.noreply.github.com> Date: Fri, 21 Aug 2026 19:36:56 +0300 Subject: [PATCH 1/4] Add read-only Mleco Visuals production discovery --- .github/workflows/mlecovisuals-discovery.yml | 75 ++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 .github/workflows/mlecovisuals-discovery.yml diff --git a/.github/workflows/mlecovisuals-discovery.yml b/.github/workflows/mlecovisuals-discovery.yml new file mode 100644 index 0000000..d9a1353 --- /dev/null +++ b/.github/workflows/mlecovisuals-discovery.yml @@ -0,0 +1,75 @@ +name: Mleco Visuals Production Discovery + +on: + push: + branches: [mlecovisuals-release] + workflow_dispatch: + +permissions: + contents: read + +jobs: + discover: + runs-on: ubuntu-latest + environment: production + env: + SERVER_HOST: ${{ secrets.SERVER_HOST }} + SERVER_USER: ${{ secrets.SERVER_USER }} + SERVER_SSH_KEY: ${{ secrets.SERVER_SSH_KEY }} + steps: + - name: Validate management connection configuration + run: | + test -n "$SERVER_HOST" || { echo "SERVER_HOST_MISSING"; exit 2; } + test -n "$SERVER_USER" || { echo "SERVER_USER_MISSING"; exit 2; } + test -n "$SERVER_SSH_KEY" || { echo "SERVER_SSH_KEY_MISSING"; exit 2; } + echo "MANAGEMENT_CONFIG=OK" + + - name: Read-only infrastructure discovery through MCP management VPS + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ env.SERVER_HOST }} + username: ${{ env.SERVER_USER }} + key: ${{ env.SERVER_SSH_KEY }} + port: ${{ secrets.SERVER_PORT || 22 }} + command_timeout: 5m + script: | + set -u + echo "DISCOVERY_VERSION=1" + echo "MANAGEMENT_HOST=$(hostname)" + if [ -f /root/.secrets/spaceweb-panel.env ]; then echo "MGMT_SPACEWEB_CREDS=YES"; else echo "MGMT_SPACEWEB_CREDS=NO"; fi + python3 - <<'PY' + import json, os, pathlib, subprocess + cfg = pathlib.Path('/a0/usr/projects/mcp_server/.runtime/ssh_targets.json') + if not cfg.exists(): + print('TARGET_CATALOG=NOT_FOUND') + raise SystemExit(0) + try: + targets = json.loads(cfg.read_text()) + except Exception as exc: + print('TARGET_CATALOG=INVALID', type(exc).__name__) + raise SystemExit(0) + print('TARGET_COUNT=' + str(len(targets))) + remote_probe = r'''echo REMOTE_HOST=$(hostname); if command -v nginx >/dev/null 2>&1; then echo NGINX=YES; nginx -T 2>/dev/null | grep -E 'server_name[^;]*(globalsystem\.cc|mlecovisuals)' | head -40 || true; else echo NGINX=NO; fi; if [ -f /root/.secrets/spaceweb-panel.env ]; then echo SPACEWEB_CREDS=YES; else echo SPACEWEB_CREDS=NO; fi; if command -v ss >/dev/null 2>&1; then ss -ltn 2>/dev/null | grep -E ':(80|443)[[:space:]]' | head -10 || true; fi''' + for name, raw in sorted(targets.items()): + if not isinstance(raw, dict): + continue + host = str(raw.get('host') or '').strip() + user = str(raw.get('user') or 'root').strip() + port = str(raw.get('port') or 22) + key = str(raw.get('key_path') or '').strip() + print(f'TARGET name={name} host={host} user={user} port={port} key_present={"YES" if key and pathlib.Path(key).exists() else "NO"} password_configured={"YES" if raw.get("password") else "NO"}') + if not host or not key or not pathlib.Path(key).exists(): + continue + cmd = ['ssh','-i',key,'-p',port,'-o','BatchMode=yes','-o','ConnectTimeout=8','-o','StrictHostKeyChecking=no','-o','UserKnownHostsFile=/dev/null',f'{user}@{host}',remote_probe] + try: + cp = subprocess.run(cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, timeout=25) + print(f'PROBE_BEGIN {name} rc={cp.returncode}') + print(cp.stdout[:12000]) + print(f'PROBE_END {name}') + except Exception as exc: + print(f'PROBE_ERROR {name} {type(exc).__name__}') + PY + echo "PUBLIC_DNS_BEGIN" + getent ahostsv4 globalsystem.cc 2>/dev/null | head -5 || true + getent ahostsv4 mlecovisuals.globalsystem.cc 2>/dev/null | head -5 || true + echo "PUBLIC_DNS_END" From 1fcdc6302de2873c1fa12bbb4d92346b8f491d51 Mon Sep 17 00:00:00 2001 From: STELS37 <138387422+STELS37@users.noreply.github.com> Date: Fri, 21 Aug 2026 19:37:37 +0300 Subject: [PATCH 2/4] Allow PR-visible Mleco Visuals discovery run --- .github/workflows/mlecovisuals-discovery.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/mlecovisuals-discovery.yml b/.github/workflows/mlecovisuals-discovery.yml index d9a1353..6939c66 100644 --- a/.github/workflows/mlecovisuals-discovery.yml +++ b/.github/workflows/mlecovisuals-discovery.yml @@ -3,6 +3,8 @@ name: Mleco Visuals Production Discovery on: push: branches: [mlecovisuals-release] + pull_request: + branches: [main] workflow_dispatch: permissions: @@ -38,7 +40,7 @@ jobs: echo "MANAGEMENT_HOST=$(hostname)" if [ -f /root/.secrets/spaceweb-panel.env ]; then echo "MGMT_SPACEWEB_CREDS=YES"; else echo "MGMT_SPACEWEB_CREDS=NO"; fi python3 - <<'PY' - import json, os, pathlib, subprocess + import json, pathlib, subprocess cfg = pathlib.Path('/a0/usr/projects/mcp_server/.runtime/ssh_targets.json') if not cfg.exists(): print('TARGET_CATALOG=NOT_FOUND') From 9bb0e12420b90a1434b93dc8719eab1fc010c3d8 Mon Sep 17 00:00:00 2001 From: STELS37 <138387422+STELS37@users.noreply.github.com> Date: Fri, 21 Aug 2026 19:41:34 +0300 Subject: [PATCH 3/4] Return sanitized discovery through PR comment --- .github/workflows/mlecovisuals-discovery.yml | 46 +++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/.github/workflows/mlecovisuals-discovery.yml b/.github/workflows/mlecovisuals-discovery.yml index 6939c66..7aa177a 100644 --- a/.github/workflows/mlecovisuals-discovery.yml +++ b/.github/workflows/mlecovisuals-discovery.yml @@ -3,12 +3,12 @@ name: Mleco Visuals Production Discovery on: push: branches: [mlecovisuals-release] - pull_request: - branches: [main] workflow_dispatch: permissions: contents: read + issues: write + pull-requests: write jobs: discover: @@ -18,6 +18,9 @@ jobs: SERVER_HOST: ${{ secrets.SERVER_HOST }} SERVER_USER: ${{ secrets.SERVER_USER }} SERVER_SSH_KEY: ${{ secrets.SERVER_SSH_KEY }} + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + PR_NUMBER: '1' steps: - name: Validate management connection configuration run: | @@ -26,20 +29,27 @@ jobs: test -n "$SERVER_SSH_KEY" || { echo "SERVER_SSH_KEY_MISSING"; exit 2; } echo "MANAGEMENT_CONFIG=OK" - - name: Read-only infrastructure discovery through MCP management VPS + - name: Read-only discovery and publish sanitized report uses: appleboy/ssh-action@v1.0.3 + env: + GH_TOKEN: ${{ env.GH_TOKEN }} + GH_REPO: ${{ env.GH_REPO }} + PR_NUMBER: ${{ env.PR_NUMBER }} with: host: ${{ env.SERVER_HOST }} username: ${{ env.SERVER_USER }} key: ${{ env.SERVER_SSH_KEY }} port: ${{ secrets.SERVER_PORT || 22 }} command_timeout: 5m + envs: GH_TOKEN,GH_REPO,PR_NUMBER script: | set -u - echo "DISCOVERY_VERSION=1" - echo "MANAGEMENT_HOST=$(hostname)" - if [ -f /root/.secrets/spaceweb-panel.env ]; then echo "MGMT_SPACEWEB_CREDS=YES"; else echo "MGMT_SPACEWEB_CREDS=NO"; fi - python3 - <<'PY' + OUT=$(mktemp) + { + echo "DISCOVERY_VERSION=2" + echo "MANAGEMENT_HOST=$(hostname)" + if [ -f /root/.secrets/spaceweb-panel.env ]; then echo "MGMT_SPACEWEB_CREDS=YES"; else echo "MGMT_SPACEWEB_CREDS=NO"; fi + python3 - <<'PY' import json, pathlib, subprocess cfg = pathlib.Path('/a0/usr/projects/mcp_server/.runtime/ssh_targets.json') if not cfg.exists(): @@ -71,7 +81,21 @@ jobs: except Exception as exc: print(f'PROBE_ERROR {name} {type(exc).__name__}') PY - echo "PUBLIC_DNS_BEGIN" - getent ahostsv4 globalsystem.cc 2>/dev/null | head -5 || true - getent ahostsv4 mlecovisuals.globalsystem.cc 2>/dev/null | head -5 || true - echo "PUBLIC_DNS_END" + echo "PUBLIC_DNS_BEGIN" + getent ahostsv4 globalsystem.cc 2>/dev/null | head -5 || true + getent ahostsv4 mlecovisuals.globalsystem.cc 2>/dev/null | head -5 || true + echo "PUBLIC_DNS_END" + } >"$OUT" 2>&1 + cat "$OUT" + python3 - "$OUT" <<'PY' | curl -fsS -X POST \ + -H "Authorization: Bearer $GH_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + -H "Content-Type: application/json" \ + "https://api.github.com/repos/$GH_REPO/issues/$PR_NUMBER/comments" \ + --data-binary @- + import json, pathlib, sys + text = pathlib.Path(sys.argv[1]).read_text(errors='replace')[:50000] + print(json.dumps({'body': '### Mleco Visuals production discovery\n```text\n' + text + '\n```'})) + PY + rm -f "$OUT" From f8af99f4493dcfab112eca7885dd07d8e06b2ae1 Mon Sep 17 00:00:00 2001 From: STELS37 <138387422+STELS37@users.noreply.github.com> Date: Fri, 21 Aug 2026 19:42:46 +0300 Subject: [PATCH 4/4] Instrument MCP discovery workflow start --- .github/workflows/mlecovisuals-discovery.yml | 29 +++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/.github/workflows/mlecovisuals-discovery.yml b/.github/workflows/mlecovisuals-discovery.yml index 7aa177a..6342d2a 100644 --- a/.github/workflows/mlecovisuals-discovery.yml +++ b/.github/workflows/mlecovisuals-discovery.yml @@ -11,7 +11,23 @@ permissions: pull-requests: write jobs: + signal: + runs-on: ubuntu-latest + steps: + - name: Signal that Actions runner started + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + run: | + curl -fsS -X POST \ + -H "Authorization: Bearer $GH_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/repos/$GH_REPO/issues/1/comments" \ + -d '{"body":"MCP_DISCOVERY_RUNNER_STARTED commit=${{ github.sha }}"}' + discover: + needs: signal runs-on: ubuntu-latest environment: production env: @@ -24,9 +40,14 @@ jobs: steps: - name: Validate management connection configuration run: | - test -n "$SERVER_HOST" || { echo "SERVER_HOST_MISSING"; exit 2; } - test -n "$SERVER_USER" || { echo "SERVER_USER_MISSING"; exit 2; } - test -n "$SERVER_SSH_KEY" || { echo "SERVER_SSH_KEY_MISSING"; exit 2; } + if [ -z "$SERVER_HOST" ] || [ -z "$SERVER_USER" ] || [ -z "$SERVER_SSH_KEY" ]; then + curl -fsS -X POST \ + -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/repos/$GH_REPO/issues/$PR_NUMBER/comments" \ + -d '{"body":"MCP_DISCOVERY_SECRETS_MISSING_OR_UNAVAILABLE"}' + exit 2 + fi echo "MANAGEMENT_CONFIG=OK" - name: Read-only discovery and publish sanitized report @@ -46,7 +67,7 @@ jobs: set -u OUT=$(mktemp) { - echo "DISCOVERY_VERSION=2" + echo "DISCOVERY_VERSION=3" echo "MANAGEMENT_HOST=$(hostname)" if [ -f /root/.secrets/spaceweb-panel.env ]; then echo "MGMT_SPACEWEB_CREDS=YES"; else echo "MGMT_SPACEWEB_CREDS=NO"; fi python3 - <<'PY'