chore: ignore dokploy shots and add chat/traefik ops smokes
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
89
scripts/dokploy_dump_traefik_harden.py
Normal file
89
scripts/dokploy_dump_traefik_harden.py
Normal file
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Dump Traefik gitea.yml + n8n-hardened.yml + middlewares for harden prep."""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
BPS = Path("/Users/4ventures/Projects/bps-facturacion")
|
||||
OUT = Path("/Users/4ventures/4ventures-client-portal/.ops/traefik-dumps")
|
||||
SHOT = Path("/Users/4ventures/4ventures-client-portal/scripts/dokploy-shots")
|
||||
BASE = "https://dokploy.4ventures.es"
|
||||
FILES = ("middlewares.yml", "middleware-hardening.yml", "gitea.yml", "n8n-hardened.yml")
|
||||
|
||||
|
||||
def env(key: str) -> str:
|
||||
import os
|
||||
|
||||
v = os.environ.get(key, "").strip()
|
||||
if v:
|
||||
return v
|
||||
p = BPS / ".env"
|
||||
if not p.is_file():
|
||||
return ""
|
||||
for line in p.read_text(encoding="utf-8").splitlines():
|
||||
if line.startswith(f"{key}="):
|
||||
return line.split("=", 1)[1].strip().strip('"').strip("'")
|
||||
return ""
|
||||
|
||||
|
||||
def main() -> int:
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
email = env("DOKPLOY_EMAIL") or "marketing@4ventures.es"
|
||||
password = env("DOKPLOY_PASSWORD")
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=True)
|
||||
page = browser.new_page(viewport={"width": 1600, "height": 1200})
|
||||
page.goto(BASE + "/", wait_until="domcontentloaded", timeout=90000)
|
||||
page.wait_for_timeout(700)
|
||||
if "/dashboard" not in page.url:
|
||||
page.locator('input[type="email"], input[name="email"]').first.fill(email)
|
||||
page.locator('input[type="password"]').first.fill(password)
|
||||
page.locator('button[type="submit"]').first.click()
|
||||
page.wait_for_url(re.compile(r"/dashboard"), timeout=90000)
|
||||
print("login ok", flush=True)
|
||||
|
||||
page.goto(f"{BASE}/dashboard/traefik", wait_until="networkidle", timeout=120000)
|
||||
page.wait_for_timeout(1000)
|
||||
page.get_by_text(re.compile(r"^dynamic$", re.I)).first.click()
|
||||
page.wait_for_timeout(800)
|
||||
|
||||
for name in FILES:
|
||||
page.locator(f"text={name}").first.dblclick()
|
||||
page.wait_for_timeout(1500)
|
||||
# Unlock not needed for read; try extract from body line numbers area
|
||||
body = page.inner_text("body")
|
||||
# Heuristic: capture from 'http:' or 'http\n' yaml start
|
||||
m = re.search(r"(?ms)^(http:|tcp:|udp:|tls:).*(?=Unlock|Skip YAML|Update\n|$)", body)
|
||||
# Better: get cm content
|
||||
text = page.evaluate(
|
||||
"""() => {
|
||||
const rows = document.querySelector('.cm-content');
|
||||
return rows ? rows.innerText : '';
|
||||
}"""
|
||||
)
|
||||
if not text or len(text) < 20:
|
||||
# fallback strip UI chrome
|
||||
lines = []
|
||||
capture = False
|
||||
for ln in body.splitlines():
|
||||
if ln.strip() in ("http:", "tcp:", "tls:") or ln.startswith("http:"):
|
||||
capture = True
|
||||
if capture:
|
||||
if ln.strip() in ("Unlock", "Update", "Skip YAML validation (for Go templating)"):
|
||||
break
|
||||
lines.append(ln)
|
||||
text = "\n".join(lines)
|
||||
(OUT / name).write_text(text + "\n", encoding="utf-8")
|
||||
print("dumped", name, "chars", len(text), flush=True)
|
||||
page.screenshot(path=str(SHOT / f"dump_{name.replace('.','_')}.png"), full_page=True)
|
||||
|
||||
browser.close()
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
77
scripts/smoke_chat_auth.py
Normal file
77
scripts/smoke_chat_auth.py
Normal file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Authenticated chat smoke on app.4ventures.es."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
ROOT = Path("/Users/4ventures/4ventures-client-portal")
|
||||
APP = "https://app.4ventures.es"
|
||||
CREDS = ROOT / ".ops" / "marketing-credentials.txt"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
email, password = "marketing@4ventures.es", ""
|
||||
for line in CREDS.read_text().splitlines():
|
||||
if line.startswith("email="):
|
||||
email = line.split("=", 1)[1].strip()
|
||||
if line.startswith("password="):
|
||||
password = line.split("=", 1)[1].strip()
|
||||
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=True)
|
||||
page = browser.new_page(viewport={"width": 1400, "height": 1000})
|
||||
page.goto(f"{APP}/login", wait_until="networkidle", timeout=90000)
|
||||
page.locator('input[type="email"], input[name="email"]').first.fill(email)
|
||||
page.locator('input[type="password"]').first.fill(password)
|
||||
page.locator('button[type="submit"]').first.click()
|
||||
page.wait_for_timeout(3500)
|
||||
if "/login" in page.url:
|
||||
print("LOGIN_FAILED", flush=True)
|
||||
browser.close()
|
||||
return 2
|
||||
|
||||
# unauth baseline via fresh context later; here authenticated
|
||||
res = page.evaluate(
|
||||
"""async () => {
|
||||
const r = await fetch('/api/chat', {
|
||||
method: 'POST',
|
||||
headers: {'content-type':'application/json'},
|
||||
body: JSON.stringify({ message: 'hola' })
|
||||
});
|
||||
const text = await r.text();
|
||||
let json = null;
|
||||
try { json = JSON.parse(text); } catch {}
|
||||
return { status: r.status, text: text.slice(0, 300), json };
|
||||
}"""
|
||||
)
|
||||
print("auth_chat", json.dumps(res, ensure_ascii=False)[:500], flush=True)
|
||||
browser.close()
|
||||
|
||||
# unauth
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
req = urllib.request.Request(
|
||||
f"{APP}/api/chat",
|
||||
data=b'{"message":"hola"}',
|
||||
method="POST",
|
||||
headers={"Content-Type": "application/json"},
|
||||
)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=15) as r:
|
||||
print("unauth_chat", r.status, r.read()[:80], flush=True)
|
||||
except urllib.error.HTTPError as e:
|
||||
print("unauth_chat", e.code, e.read()[:80], flush=True)
|
||||
|
||||
ok = res.get("status") == 200 and isinstance(res.get("json"), list)
|
||||
print("SUCCESS" if ok else "PARTIAL", flush=True)
|
||||
return 0 if ok else 5
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user