From 7b5271a69aa66dbda5ab1bee15396116abd9f74f Mon Sep 17 00:00:00 2001 From: cred-driver Date: Sun, 4 Oct 2026 18:07:48 +0000 Subject: [PATCH] muse-signin: mask secrets in progress output at the source Identifier, OTP code, and account-name values replaced with [redacted] in all progress prints. Line structure and markers preserved (APPROVAL_NEEDED/NEEDS_HUMAN/SUCCESS prefixes intact); exit codes 0/2/3/4 unchanged, no consumer parses stdout. Defense in depth: onboard-driver already scrubs its passthrough; this covers manual operator flows too. --- bin/muse-signin.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/bin/muse-signin.py b/bin/muse-signin.py index 22c3a48..2980d30 100755 --- a/bin/muse-signin.py +++ b/bin/muse-signin.py @@ -7,7 +7,7 @@ Usage: If --otp is not provided, the script will: 1. Navigate through login flow up to OTP prompt -2. Print "APPROVAL_NEEDED: OTP required for " +2. Print "APPROVAL_NEEDED: OTP required for [redacted]" 3. Exit with code 2 The operator then obtains the OTP (via chat with user) and re-runs: @@ -83,7 +83,7 @@ def main(): args = p.parse_args() if is_registered_in_accounts(args.email): - print(f"Registry check: {args.email} is registered in ACCOUNTS.md") + print("Registry check: [redacted] is registered in ACCOUNTS.md") if args.cdp_port: port = args.cdp_port @@ -113,7 +113,7 @@ def main(): time.sleep(3) # Step 3: Enter email - print(f"Entering email: {args.email}") + print("Entering email: [redacted]") result = ev(ws, f"""(async()=>{{ const inp=[...document.querySelectorAll('input')].find(i=> (i.placeholder&&i.placeholder.toLowerCase().includes('email'))|| @@ -125,7 +125,7 @@ def main(): await new Promise(r=>setTimeout(r,500)); return 'entered:'+inp.value; }})()""", True) - print(f"Email: {result}") + print("Email: [redacted]") if result == 'NOINPUT': print("ERROR: Email input not found", file=sys.stderr) ws.close() @@ -143,10 +143,10 @@ def main(): # Step 5: Check for OTP prompt body = ev(ws, "document.body.innerText.slice(0,500)") if "Enter your code" in body or "code we sent" in body or "To log in" in body or "To confirm your account" in body: - print(f"OTP prompt detected for {args.email}") + print("OTP prompt detected for [redacted]") if not args.otp: - print(f"APPROVAL_NEEDED: OTP required for {args.email}") - print("Re-run with: signin.py --email {} --otp ".format(args.email)) + print("APPROVAL_NEEDED: OTP required for [redacted]") + print("Re-run with: signin.py --email [redacted] --otp ") ws.close() sys.exit(2) # Approval needed @@ -160,7 +160,7 @@ def main(): await new Promise(r=>setTimeout(r,500)); return 'entered:'+inp.value; }})()""", True) - print(f"OTP: {result}") + print("OTP: [redacted]") time.sleep(1) # Click Next/Verify/Confirm @@ -177,7 +177,7 @@ def main(): body = ev(ws, "document.body.innerText.slice(0,500)") title = ev(ws, "document.title") or "" if "Connected" in body or "Chats" in body or "Muse" in title or "Chat" in title: - print(f"SUCCESS: Logged in as {args.email} (title: {title})") + print(f"SUCCESS: Logged in as [redacted] (title: {title})") ws.close() return 0 # Multi-account selection: Meta shows one button per matching @@ -200,16 +200,16 @@ def main(): })()""" % json.dumps(args.account_name), True) if not picked: print(f"NEEDS_HUMAN: no account button matched " - f"'{args.account_name}'", file=sys.stderr) + f"'[redacted]'", file=sys.stderr) ws.close() sys.exit(3) - print(f"Selected account '{args.account_name}', waiting...") + print(f"Selected account '[redacted]', waiting...") time.sleep(5) body = ev(ws, "document.body.innerText.slice(0,500)") title = ev(ws, "document.title") or "" if "Connected" in body or "Chats" in body or "Muse" in title or "Chat" in title: - print(f"SUCCESS: Logged in as {args.email} " - f"(account: {args.account_name})") + print("SUCCESS: Logged in as [redacted] " + "(account: [redacted])") ws.close() return 0 print("WARNING: account selection did not land in chat",