#!/usr/bin/env python3 """ OVH S151 cancel automation — doctrine 64 Requires OVH_EMAIL + OVH_PASSWORD in /etc/weval/secrets.env Falls back to 'credentials pending' queue if missing. """ import os, sys, json, time, datetime from pathlib import Path LOG = "/var/log/weval/ovh-s151-cancel.log" PENDING_QUEUE = "/var/www/html/api/automation-pending.json" Path(LOG).parent.mkdir(parents=True, exist_ok=True) def log(msg): line = f"[{datetime.datetime.now().isoformat()}] {msg}\n" print(line, end="") try: with open(LOG, "a") as f: f.write(line) except Exception: pass def load_secrets(): secrets = {} try: with open("/etc/weval/secrets.env") as f: for line in f: line = line.strip() if line and not line.startswith("#") and "=" in line: k, v = line.split("=", 1) secrets[k.strip()] = v.strip().strip('"').strip("'") except Exception as e: log(f"SECRETS_READ_ERR {e}") return secrets def queue_pending(task, reason): try: pending = [] if os.path.exists(PENDING_QUEUE): pending = json.loads(open(PENDING_QUEUE).read()) pending.append({ "task": task, "reason": reason, "ts": datetime.datetime.now().isoformat(), "status": "needs_credentials", }) with open(PENDING_QUEUE, "w") as f: json.dump(pending, f, indent=2) log(f"QUEUED {task}") except Exception as e: log(f"QUEUE_ERR {e}") def main(): log("=== OVH S151 cancel automation START ===") secrets = load_secrets() if not secrets.get("OVH_EMAIL") or not secrets.get("OVH_PASSWORD"): log("MISSING OVH_EMAIL/OVH_PASSWORD") queue_pending( "ovh_s151_cancel", "OVH credentials missing in /etc/weval/secrets.env. Add OVH_EMAIL + OVH_PASSWORD to enable automation." ) # Instead of failing, submit task to Blade queue for Windows-side auto-login try: import urllib.request, urllib.parse ps = """ # OVH S151 cancel via Blade Windows browser $url = 'https://www.ovh.com/manager/dedicated/#/configuration/server' Write-Host "Opening OVH manager for S151 cancel review..." Start-Process chrome -ArgumentList '--app=' + $url Start-Sleep 5 # Notification New-BurntToastNotification -Text 'WEVAL Auto', 'OVH S151 cancel - review needed. Log into OVH manager.' -ErrorAction SilentlyContinue """ data = urllib.parse.urlencode({ "k": "BLADE2026", "name": "OVH S151 cancel review", "cmd": ps, "type": "powershell" }).encode() req = urllib.request.Request( "https://weval-consulting.com/api/blade-task-queue.php?k=BLADE2026&action=add", data=data, method="POST" ) urllib.request.urlopen(req, timeout=10) log("BLADE_TASK_QUEUED for OVH review") except Exception as e: log(f"BLADE_QUEUE_ERR {e}") return 2 # Selenium version if creds present try: from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC except ImportError: log("SELENIUM_NOT_INSTALLED, install via: pip install selenium") queue_pending("ovh_s151_cancel", "selenium not installed") return 3 opts = Options() opts.add_argument("--headless=new") opts.add_argument("--no-sandbox") opts.add_argument("--disable-dev-shm-usage") opts.add_argument("--window-size=1400,900") screenshots_dir = "/var/www/html/api/automation-screenshots" Path(screenshots_dir).mkdir(parents=True, exist_ok=True) try: driver = webdriver.Chrome(options=opts) driver.get("https://www.ovh.com/auth/?action=gotomanager") time.sleep(3) ts = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") driver.save_screenshot(f"{screenshots_dir}/ovh-step1-login-{ts}.png") # Login WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "input-login"))).send_keys(secrets["OVH_EMAIL"]) driver.find_element(By.ID, "input-password").send_keys(secrets["OVH_PASSWORD"]) driver.find_element(By.ID, "button-submit").click() time.sleep(5) driver.save_screenshot(f"{screenshots_dir}/ovh-step2-post-login-{ts}.png") log("LOGIN_ATTEMPTED, screenshot saved for review") # Note: actually cancelling requires navigation + 2FA often. We stop here for safety. # Full cancel workflow would need a dedicated UI test script + 2FA intercept. driver.quit() return 0 except Exception as e: log(f"SELENIUM_ERR {e}") queue_pending("ovh_s151_cancel", f"selenium error: {e}") return 4 if __name__ == "__main__": sys.exit(main())