4040 python scripts/mock_sf_server.py # listens on port 8888
4141 MOCK_SF_PORT=9000 python scripts/mock_sf_server.py
4242 python scripts/mock_sf_server.py 9000
43+
44+ Serves TLS with a throwaway self-signed cert (the deploy path requires an HTTPS
45+ upload URL). Set ``MOCK_SF_CERT_FILE`` to a path the clients can trust via
46+ ``NODE_EXTRA_CA_CERTS`` (CLI) and ``REQUESTS_CA_BUNDLE`` (SDK).
4347"""
4448
4549from __future__ import annotations
4650
47- from http .server import BaseHTTPRequestHandler , HTTPServer
4851import json
4952import os
53+ import ssl
54+ import subprocess
5055import sys
56+ import tempfile
57+ from http .server import BaseHTTPRequestHandler , HTTPServer
5158
5259PORT = (
5360 int (sys .argv [1 ])
5461 if len (sys .argv ) > 1
5562 else int (os .environ .get ("MOCK_SF_PORT" , "8888" ))
5663)
5764
65+
66+ def _self_signed_cert (dirpath : str ) -> tuple [str , str ]:
67+ """Generate a throwaway self-signed cert for localhost via openssl.
68+
69+ The plugin's deploy path requires an HTTPS upload URL, so the server must
70+ speak TLS. Set ``MOCK_SF_CERT_FILE`` to write the cert to a known path so
71+ clients can trust it (``REQUESTS_CA_BUNDLE`` / ``NODE_EXTRA_CA_CERTS``).
72+ """
73+ cert_path = os .environ .get ("MOCK_SF_CERT_FILE" ) or os .path .join (dirpath , "cert.pem" )
74+ key_path = os .path .join (dirpath , "key.pem" )
75+ subprocess .run (
76+ [
77+ "openssl" , "req" , "-x509" , "-newkey" , "rsa:2048" , "-nodes" ,
78+ "-keyout" , key_path , "-out" , cert_path , "-days" , "1" ,
79+ "-subj" , "/CN=localhost" ,
80+ "-addext" , "subjectAltName=DNS:localhost,IP:127.0.0.1" ,
81+ ],
82+ check = True ,
83+ capture_output = True ,
84+ )
85+ return cert_path , key_path
86+
5887_USERINFO = {
5988 "sub" : "https://test.salesforce.com/id/00D000000000001AAA/005000000000001AAA" ,
6089 "user_id" : "005000000000001AAA" ,
6897
6998_TOKEN_RESPONSE = {
7099 "access_token" : "00D000000000001AAA!fakeAccessTokenForCITesting" ,
71- "instance_url" : f"http ://localhost:{ PORT } " ,
100+ "instance_url" : f"https ://localhost:{ PORT } " ,
72101 "token_type" : "Bearer" ,
73102 "scope" : "api" ,
74103}
@@ -135,7 +164,7 @@ def do_POST(self) -> None:
135164 elif path == _DATA_CUSTOM_CODE_PATH :
136165 # create_deployment() — return a presigned upload URL
137166 self ._send_json (
138- {"fileUploadUrl" : f"http ://localhost:{ PORT } /upload/fake-deployment.zip" }
167+ {"fileUploadUrl" : f"https ://localhost:{ PORT } /upload/fake-deployment.zip" }
139168 )
140169 elif path == _DATA_TRANSFORMS_PATH :
141170 # create_data_transform() — script packages only
@@ -152,5 +181,10 @@ def do_PUT(self) -> None:
152181if __name__ == "__main__" :
153182 server = HTTPServer (("localhost" , PORT ), MockSFHandler )
154183 server .allow_reuse_address = True
155- print (f"[MOCK SF] Listening on http://localhost:{ PORT } " , flush = True )
156- server .serve_forever ()
184+ with tempfile .TemporaryDirectory () as certdir :
185+ cert_path , key_path = _self_signed_cert (certdir )
186+ ctx = ssl .SSLContext (ssl .PROTOCOL_TLS_SERVER )
187+ ctx .load_cert_chain (cert_path , key_path )
188+ server .socket = ctx .wrap_socket (server .socket , server_side = True )
189+ print (f"[MOCK SF] Listening on https://localhost:{ PORT } " , flush = True )
190+ server .serve_forever ()
0 commit comments