Conversation
Safari silently blocks ws:// connections on HTTPS pages without firing the close event, leaving the plugin stuck in "loading". Hardcode the protocol to wss:// so failures increment failureCount normally and the disconnected InfoPanel appears after 2 failures.
Generate self-signed certs via mkcert so the CLI serves WSS, matching the plugin's wss:// protocol. Falls back to plain WS with a warning if cert generation fails.
Remove ws:// fallback entirely — the CLI now requires TLS certs and fails with a clear error message instead of silently downgrading. When a new CA is generated (e.g. after the user deletes ca.key/ca.crt), the old server cert and install marker are cleaned up so they get regenerated against the new CA.
On Linux and Windows, tryInstallCA silently returned without warning, leaving users with no explanation for why WSS connections fail. Now shows platform-specific manual installation instructions.
|
@Nick-Lucas I've opened a new pull request, #588, to work on those changes. Once the pull request is ready, I'll request review from you. |
There was a problem hiding this comment.
Pull request overview
Adds TLS certificate generation/management to enable secure WebSocket (WSS) connections between the Framer plugin and the Code Link CLI, making TLS mandatory for local connections.
Changes:
- Plugin switches client connections from
ws://towss://. - CLI WebSocket server is now hosted over an HTTPS (TLS) server using locally generated certificates.
- New CLI helper to download/run
mkcert, cache certs, and (on macOS) install the CA into the system trust store.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| plugins/code-link/src/utils/sockets.ts | Forces plugin WebSocket client to use wss:// and logs protocol on close. |
| packages/code-link-cli/src/helpers/connection.ts | Wraps ws server with an HTTPS server to provide WSS-only connections. |
| packages/code-link-cli/src/helpers/certs.ts | New mkcert-based certificate download/generation/cache helper for localhost TLS. |
| packages/code-link-cli/src/controller.ts | Generates/loads certs before starting the WSS server; improves failure messaging. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@cursor review |
- Verify mkcert binary integrity via hardcoded SHA-256 checksums before execution - Sync root CA from mkcert default CAROOT and invalidate stale server certs on change - Split cert generation into separate install + generate steps with better error messages - Export CERT_DIR (overridable via FRAMER_CODE_LINK_CERT_DIR env var) - Add WSS server error handler in connection helper - Trim file header comment
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: HTTPS runtime errors not forwarded to error handler
- Added
handlers.onError?.(err)to the HTTPS server runtime error path so connection-level error listeners now receive those errors.
- Added
- ✅ Fixed: Test certificates already expired before PR merge
- Replaced the embedded test key/certificate pair with a newly generated localhost certificate valid for ten years to avoid immediate expiration fragility.
Or push these changes by commenting:
@cursor push 2987219ba8
Preview (2987219ba8)
diff --git a/packages/code-link-cli/src/helpers/connection.test.ts b/packages/code-link-cli/src/helpers/connection.test.ts
--- a/packages/code-link-cli/src/helpers/connection.test.ts
+++ b/packages/code-link-cli/src/helpers/connection.test.ts
@@ -4,53 +4,53 @@
import { initConnection, sendMessage } from "./connection.ts"
const TEST_KEY = `-----BEGIN PRIVATE KEY-----
-MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDrogGoQi38Qtul
-IzKaeMHoV9jJeyp3+hmQn7O5cQTxdjzYecqhMtUBvr3gklvSJgprDrGJ8tJSluHv
-g83lKVPTo0EVIHxvkxX886yQddyo4048tOBZCGkz2LXwZE3LKCRWQZeNUoSJn19L
-UPbavBoAM0/iosl+NAsAKL8dwT87i1m4jlojjRNLCzrpqt7VhKURaK85RJN8/Gv3
-CpZWhTIeSu8LyQNjA1PjxuntGTNLbnjoFLAzJ6pxX2MGuCppvuwzByY0XkChEaJ7
-P5nvWBVkr0wEVfYpXRgt4G9z2wuVAQsivjuo9jK6wtsJoOSp+05Js3cXdm5nJUij
-uo2vzUA9AgMBAAECggEADBjGlgFDxBoYlZs/e0+swMVVw0436W3lBxgzzVbghpbn
-28Mw5GKsLclBjThmT10VltZrxeW553SIh9fP565d99T/P9rpmH7IF7LYzpfGasM0
-nog4pkl4wSkkegFkPwRCDU2TvrUYScptRXwUGDmk6hK4TK3Hw1tfnzP4T8o+eUt+
-Za8MG8AeAMzBqumFQiAop6V0hdPhPLVeFGB2KMSXPzNt7HRgmIJtnLCi+lt0XaPR
-5j/fn6ZZKHsZBdsueNjqKrKBKgUyXdEPOruxHEfBnI7e9Uvmua0/IHUV51/41+D+
-Vp07I1YKsmhMvL5Id7GRoA54IPpnXy8amsmhZnkW0QKBgQD+Ezs9KYW7xJmT77IT
-2MIryNzepNZmQooyzNQ7+80eBGtL6INlnFqeexiP9jcSIqwomR/H95NAO68sSrxs
-yJnLMfHp5GN8X+htOZExlTHjFEEP8BIR4Pi1BhQR8oevFt3W/NqStx+obrkboxCk
-Yj+7uX3+Ss7i3ADt2op8GHlbCQKBgQDtawHKUmNthWWh+tUh6ExTLYa99GKur7DS
-gLjN1uBngo7cGVHJYiTp+iS7gqnE20ln7buVhc5os3F6fqPylb2Ig6NNsl9nAcjq
-GMonX+dug612il2IK+/pIcVp6R6xABv1cV0neZD+JU8q31pADcAdErGO6Dvt4Z5X
-N817Tu4klQKBgQD2gfAqwjuHVxLublPnX5ncY1CwD1wY8Rwmd4a+/+od4om7p0a8
-8jsVojbNjkQWK1+/L/meyPysCHxHy+cO4H4eoEGm/Tjs9hyKxJyzb55sRD1v2iud
-/xkugUw9sYKlhNkNelwSlut3Pp4IS2idJNnTKAAvFaOuhWe9XhiYmCI+CQKBgQDR
-odmL1uF6E/5gXwWQEfhKvXkrAr2btv/vbr8+6UttukcAKs8ffSxQ+JE0jDPw4RtY
-y/4FEYfmxQMfAPEsQnF/N5SbBzPb1SSdJ1RgHftQhq5Ea/oYQYttk2cnlDKIYStO
-tlFliJ6w+SqFFYAv7LREN3xWTdKUwdG4+0nRZik6XQKBgQDNFBL/NNy8f4jP2LNe
-Rr9yXnm7p7+ptHbIEaA6TmAqmBIgDWaxIyOgetPAs0VABtqeNk7CKSJyCDO3OGqe
-g2XehSba4rjQEs5W2z1/8zvVPn20856uVhFOMMV5a3Sr7tQ9iFQ19JiW8ACKll2L
-ThCKIGWM1NQFPq3sN0ooz4dKJA==
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDNdQNneJoOxRcf
+Pc8J1bv+S98RaiEtkMjvWYN8sn94sEvc03zZ1IGRryWAMfcirZPB8W3htHGAbrZW
+Bln/aFvrF/jBxzARPyejaB51EY1uDAjAlrz8aS6SsXs8xExVCMws8rWLxfAqp/+t
+qiPw9At7+iZs8uqKPuXF6qFCd0Am2CTtzjnQuvc9vI2RoaoHF/Hi0/VFqgUCWx8S
+HxO0VVHzPiVPqwWLlsLZnrU6swG1AVdIqxunbTY8GTyw2hUWwMNjkg/pxnsQWsbF
+QvOJ3SU0nW9ubKeDKjo3IARFGlFs+GstwZS9zfFGQ8Qq9w3NunTBghxpsVa8x3O4
+61r22r0zAgMBAAECggEAFKWfs/RAtx9DVZZmifx6qfGB90QNFYEpUDRUrGFbwgsl
+dImkUFe0tak+QYXD6i47XRAgFMCHb3qwxDBbNvmL0zJTg1W7FOCd4SQDe4xKBDcd
+Yg1D7LG9Rmyjj9XCPgFmU1YIvIUlv4OmhBNHDV3ZEZpv5h77Ru1PNfaAQietwLll
+0+wFA46bTEb4VrVyxCo5HL1h6ubjzOqhjRizFGVbVv5d5dz7rr7eWBRQ5vUeTb7v
+sWz8S6T1HA7IcKzsab3wt7CAu7NQ10Cy/iYw0GxPa1HuuBgKF/XXQfam23s0OI58
+17c4pkTjudrNl3BpqpwXP5z2OFL6QKoTmjisaYKbIQKBgQDnXQIGh0Dv+San14Mm
+sgPyTrdnfW3CFQbspAAGX1AK4+8ZczFp1+nsKVEolzOcfkDSusfuxCDmuw39uMqT
+7sQ9wSMj1n8MaK+8pVJ9lkIgHYSGArtaRmBOt0Qpo6CDk08UFhJTJbVxFE83Hv7J
+6EUzOTkom6c1rf7Y6RMUN04yWwKBgQDjVcxlre6vE12C7l6DlKGrgOPu3oP9H5w+
+kXvKMwfuWBXfTpBnZJdq5z1rPQjenHdiuRW3tU391kB6nfvfHmkbnFJz4V4cielM
+3vrXLmlZh+yZHRE59TEwnlYvmJxpB6gKvkfE6vw0Dt+pBiOZ/kRI7eJDcGSssaMz
+e6QWdtJoCQKBgQClowGbOOO1qfMRwInFfzayF8bYEYUtqK4fZr4Z0czVLx/zYXPj
+6c8v4tiWrcEmbYDtHQmcF8/SP+KhXdWyGQNnjskglCS69ouyC83F2XgX0+oXowcM
+d0vlrvDeuqVk7WZ04+RUoK+IeFjKBqe0V1SLepFAUEdid+H22s5s77dM9wKBgDhQ
+6diKdOVkC7dCq6E28bHVtSFYeCP9b6xESAE4EQ/nPEvcX4NtdOEjtaBaN1dGNYD8
+Trf6rv5h1AlMF7gXBXy0hex0+OZi96t2VXd25NwsAt2PSNQtvGjJ4Jnb2WtfXS6E
+Iq1SdPXEdX2eqrUcOvhCDdoc/qOVQdOgHm7+MnNZAoGAOwjsvqiOaJhP9bz/tC0b
+472giPzFxba1L19iSMfGeIJd/GDJKzW129sZEwUEfWkYVd0e1vhneKPBxtE1Z7+y
+35E71Q2ijmFPfd47y3pVgcWj1lPWCg9DAsrD/cqiJ/fIy0l90rSZYmUvG9G7qJQq
+/vDRn3clgb7L/ZEjeUeIEvY=
-----END PRIVATE KEY-----
`
const TEST_CERT = `-----BEGIN CERTIFICATE-----
-MIIDCTCCAfGgAwIBAgIUZYxUt7lbGkNAA92GzPD0s5wFbvQwDQYJKoZIhvcNAQEL
-BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI2MDMwNjE0MTY1N1oXDTI2MDMw
-NzE0MTY1N1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEA66IBqEIt/ELbpSMymnjB6FfYyXsqd/oZkJ+zuXEE8XY8
-2HnKoTLVAb694JJb0iYKaw6xifLSUpbh74PN5SlT06NBFSB8b5MV/POskHXcqONO
-PLTgWQhpM9i18GRNyygkVkGXjVKEiZ9fS1D22rwaADNP4qLJfjQLACi/HcE/O4tZ
-uI5aI40TSws66are1YSlEWivOUSTfPxr9wqWVoUyHkrvC8kDYwNT48bp7RkzS254
-6BSwMyeqcV9jBrgqab7sMwcmNF5AoRGiez+Z71gVZK9MBFX2KV0YLeBvc9sLlQEL
-Ir47qPYyusLbCaDkqftOSbN3F3ZuZyVIo7qNr81APQIDAQABo1MwUTAdBgNVHQ4E
-FgQUOsJWop04UtmQdQVbThKWqiLU3eIwHwYDVR0jBBgwFoAUOsJWop04UtmQdQVb
-ThKWqiLU3eIwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAiphn
-7KISByG40QtIPSLltzQmkv2RPfpSq+LcNkdXmYEBbRh53a3L4JodHkl9Tmd98NI8
-wDPtqmA5A+L4Gc47v2O+b33IZ69g81JqYbjl2zNwYzCNEppirIfcyvalhFlly47A
-Z8HbtXQgF19BnBQ+DOTc0Xcbaxg7o5JoCSAs+t7e9kS9pdQ6Ak4vWZ6w75IgeVYp
-iaejAga8nqAw5JE4ORjnvJY5tNivOYRvslpYysLD4AW8twI52ZUqaRISZ4l+bYFI
-WvpV0rjmehRqHvyb06B91jDCy8oOb4WKnpBVHiSho5jLAEmuZn0GKrO7FpqQmUEW
-q3dVP+H9IROOHQsRwA==
+MIIDCTCCAfGgAwIBAgIUEm+yEgY9YJWp4K0j410Qi9Wyqe8wDQYJKoZIhvcNAQEL
+BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI2MDMwOTE0MjUzNVoXDTM2MDMw
+NjE0MjUzNVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAzXUDZ3iaDsUXHz3PCdW7/kvfEWohLZDI71mDfLJ/eLBL
+3NN82dSBka8lgDH3Iq2TwfFt4bRxgG62VgZZ/2hb6xf4wccwET8no2gedRGNbgwI
+wJa8/GkukrF7PMRMVQjMLPK1i8XwKqf/raoj8PQLe/ombPLqij7lxeqhQndAJtgk
+7c450Lr3PbyNkaGqBxfx4tP1RaoFAlsfEh8TtFVR8z4lT6sFi5bC2Z61OrMBtQFX
+SKsbp202PBk8sNoVFsDDY5IP6cZ7EFrGxULzid0lNJ1vbmyngyo6NyAERRpRbPhr
+LcGUvc3xRkPEKvcNzbp0wYIcabFWvMdzuOta9tq9MwIDAQABo1MwUTAdBgNVHQ4E
+FgQULsidnLW2mOw3K4jNhopHvXW+6bQwHwYDVR0jBBgwFoAULsidnLW2mOw3K4jN
+hopHvXW+6bQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAxmdG
+8RAHknfODzksEHK3iivJ/LqWMEh6bOsQqayD76ZaHSxRd56Y7kbxzPvjJkEkPDDM
+PcBpzr1IaEjd4Djq2AuwfCdelIqIWZNnkrwxf7dgxCCXczVuHQn3kjjNMo195wNH
+963DAtW++L5lpym27LSFP+Lh1YpR6Ft0ABUCO8j+hswnLG9kSm5WUyUkqbbVSlIS
+r42tr8yPxoypYLUz8MTLjphB+M3RAba/Wp4Qj/IaV25T3wM9yJAt5o/Dr/vnCDVx
+Ybg5PtiuknQYyq6Qn9nEAtewDC9CBV1BFbEOgR/sCsXWAm65cHbaBVdKSrH4rJOI
+AQ0TthT5VowpqXJdSw==
-----END CERTIFICATE-----
`
diff --git a/packages/code-link-cli/src/helpers/connection.ts b/packages/code-link-cli/src/helpers/connection.ts
--- a/packages/code-link-cli/src/helpers/connection.ts
+++ b/packages/code-link-cli/src/helpers/connection.ts
@@ -61,6 +61,7 @@
return
}
error(`WebSocket server error: ${err.message}`)
+ handlers.onError?.(err)
}
const handleListening = () => {mkcert creates rootCA-key.pem with 0o400 (read-only) permissions, so fs.writeFile fails with EACCES when syncRootCA tries to update it. Fix by removing the existing files before writing new ones. Also switch help/recovery text from error() to info() and simplify the port-in-use message.

Description
This PR adds TLS certificate generation and management to the Code Link CLI, enabling secure WebSocket (WSS) connections. Certificates are automatically generated on first run and cached locally in
~/.framer/code-link/. The CA is automatically installed to the system keychain on macOS with a one-time password prompt.The certificate setup message has been improved for clarity and styled consistently with other status messages.
Changelog
Testing