Repository navigation
docs: tell a client that pins its own CA how to trust keploy's - #931
Draft
slayerjain wants to merge 1 commit into
Draft
slayerjain wants to merge 1 commit into
slayerjain wants to merge 1 commit into
Conversation
A client that trusts only a CA file it names itself (Python requests with verify=<file>, a Go client with its own RootCAs) rejects the certificate keploy answers its HTTPS calls with, and keploy record does not record the call. keploy record now warns of it at the end of a recording, naming the test cases, and its next_step links here (keploy/keploy#4853). Nothing in the docs said what to do: the TLS page covers keploy's automatic trust injection and OS-trust-store libraries only. The new section "A client that pins its own CA" shows the warning and how to point such a client at a file that holds keploy's per-run CA as well as its own: - in Docker and Docker Compose, from /tmp/keploy-tls/keploy-ca.crt, which keploy mounts in the app container; - natively, from the file SSL_CERT_FILE names in the app's environment. Checked against keploy main in a lane container. The compose example as written makes both pinned calls answer 200 and be recorded, with no warning. Natively, SSL_CERT_FILE names a file holding one certificate, "Keploy MITM CA <run id>". Signed-off-by: slayerjain <shubhamkjain@outlook.com>
slayerjain
added a commit
to keploy/keploy
that referenced
this pull request
Oct 19, 2026
…e switch off A client that does not trust keploy's CA rejects the certificate keploy's proxy answers its TLS handshake with. Examples are a client that pins its own CA file (Python requests with verify=<file>, a Go client with its own RootCAs) and a library that reads only the OS trust store. Its call fails, and keploy neither records nor can replay it. With the proven switch on, such a handshake (tls_handshake_failed) fails the recording. With it off, keploy said nothing. The recording ended green, its test cases held the app's error response for those calls, and a replay of them passed by replaying that error: a silent false pass. With the switch off, keploy record now says so once, at WARN, when the recording ends: N TLS handshake(s) with keploy's proxy failed while this recording ran (a client that does not trust keploy's CA rejects keploy's certificate); those calls are not recorded It names the test cases recorded while those handshakes failed, how many failed after the last test case, and the last one's destination. Its next_step points at how a client that pins its own CA trusts keploy's, natively and in Docker (https://keploy.io/docs/running-keploy/docker-tls/ #a-client-that-pins-its-own-ca, added by keploy/docs#931). The agent already counts these handshakes with the switch off. The watch the record path already drives (caRejectWatch, in captureWatch) now reads that count: - as capture begins; - as each test case is saved (a handshake's failure is the test case's it was made in, models.PerTest); - once more after the last. The reads are made as the switch-on watch's are. A stop ends record's context before the drain saves its last test cases and before the final read, so the reads use a context the stop does not end; only the second interrupt, which gives the stop's waits up, ends them. They are made one at a time, each applied before the next is made, so a late answer is never taken for an agent that was started again. A read that fails leaves its count to the next read, at Debug. It changes nothing else. No test case, recording, verdict, status or exit code differs, and with the switch on, captureWatch is as it was. It counts only failed handshakes. A client that hung up on its handshake (tls_handshake_abandoned) cannot be told from one that gave up, so that is left to the proven switch. A count it cannot read is left unsaid. Replicated in a lane container on 192.168.116.142 with keploy main, in compose. A Flask app calls an HTTPS upstream two ways: /pinned with verify=/certs/ca.pem (its own CA), and /env with REQUESTS_CA_BUNDLE, which keploy's injected trust covers. Calls made: /pinned, /env, /pinned. - Before: the record exits 0 with nothing said. The /pinned test cases hold the app's 500, and the app logged CERTIFICATE_VERIFY_FAILED. - After: the record still exits 0, and says once: "2 TLS handshake(s) with keploy's proxy failed while this recording ran (...); those calls are not recorded", testCases [get-pinned-1, get-pinned-2], last "to 172.19.0.2:8443", next_step the CA docs. get-env-1 is not named. - A pinned call the app makes 1.5 s after its last test case's response, before the stop (SIGINT): the WARN says 3, with afterTheLastTestCase 1. - Following the docs (the app's CA file combined with /tmp/keploy-tls/keploy-ca.crt at container start): both /pinned calls answer 200, are recorded, and nothing is said. Tests (pkg/service/record/ca_reject_warn_test.go): - with the switch off, failed handshakes during two of three test cases and one after the last give one WARN: 4, those two test cases, 1 after the last, its destination, and the docs. The recording is not failed; - none failed: nothing said; - a start that cannot be read: nothing said, nothing read after; - a check that cannot be read: the next read counts what it missed, and a failed read is no count of 0; - an agent started again (its count from nothing): counted; - around the stop, with a reader that ends with its context as the agent client's does: a failure in a test case the drain saves, and two after the last, are said; - a test case's read and the final read asked at once: the final one is not asked until the other is counted; - abandoned handshakes: nothing said; - the fields: a test case's destination, no afterTheLastTestCase with none after it, and with every failure after the last, no test cases named and "record again"; - with the switch on, the WARN is not said, and the failed handshake fails the recording as before. TestTheCaptureWatchIsOffWithoutTheSwitchOrACount now expects the switch-off watch to read the count for this WARN and to say nothing of other losses. Signed-off-by: slayerjain <shubhamkjain@outlook.com>
slayerjain
added a commit
to keploy/keploy
that referenced
this pull request
Oct 19, 2026
…e switch off A client that does not trust keploy's CA rejects the certificate keploy's proxy answers its TLS handshake with. Examples are a client that pins its own CA file (Python requests with verify=<file>, a Go client with its own RootCAs) and a library that reads only the OS trust store. Its call fails, and keploy neither records nor can replay it. With the proven switch on, such a handshake (tls_handshake_failed) fails the recording. With it off, keploy said nothing. The recording ended green, its test cases held the app's error response for those calls, and a replay of them passed by replaying that error: a silent false pass. With the switch off, keploy record now says so once, at WARN, when the recording ends: N TLS handshake(s) with keploy's proxy failed while this recording ran (a client that does not trust keploy's CA rejects keploy's certificate); those calls are not recorded It names the test cases recorded while those handshakes failed, how many failed after the last test case, and the last one's destination. Its next_step points at how a client that pins its own CA trusts keploy's, natively and in Docker (https://keploy.io/docs/running-keploy/docker-tls/ #a-client-that-pins-its-own-ca, added by keploy/docs#931). The agent already counts these handshakes with the switch off. The watch the record path already drives (caRejectWatch, in captureWatch) now reads that count: - as capture begins; - as each test case is saved (a handshake's failure is the test case's it was made in, models.PerTest); - once more after the last. The base read is made as capture begins, on record's context, and waited for: a stop before capture began ends it, as does the bound below, and nothing is then watched. Every later read is asked for and not waited for: a test case's as the consumer saves it, and the final one once the app has stopped, at the three places the switch-on watch makes its own final read. They are made on one goroutine of the watch's, one at a time and in the order asked, so an answer is never applied after a later one, and a read that lags counts every test case saved since the last together. finish, after every drain, waits for those still out, saying at Info that it does. No read holds the recording or the stop's drains up; finish's wait is as long as the reads still out, each bounded below. The watch stands no offer of the stop's (utils.OfferStopNow): the final read is asked before the drain in a native or docker stop, and an offer it stood there would have the user's press give that drain up. A read is not ended by the stop, which ends record's context before the drain saves its last test cases and before the final read. It is ended by the interrupt that gave the stop's waits up (utils.StopNow, a drain's own offer answered), and given up once keploy had stall.HangBudget of its own runnable time to run without an answer, so a stop no one presses Ctrl+C at (CI's pkill -INT) ends too, and a starved keploy is not taken for a silent agent. A read given up, or that failed, leaves its test cases to the next read; an answer that comes after is not counted. What failed after the last test case is what the final read saw beyond the last read that counted test cases, when no such read came after it: in a native or docker stop the final read comes before the drain saves its last test cases, and a handshake that failed in one of those is that test case's, and named. A count lower than the last (an agent started again) is taken whole. It changes nothing else: no test case, verdict, status, exit code or hook differs, and with the switch on, captureWatch is as it was. It counts only failed handshakes. A client that hung up on its handshake (tls_handshake_abandoned) cannot be told from one that gave up, so that is left to the proven switch. A count it cannot read is left unsaid (Debug). Replicated in a lane container on 192.168.116.142 with keploy main, in compose. A Flask app calls an HTTPS upstream two ways: /pinned with verify=/certs/ca.pem (its own CA), and /env with REQUESTS_CA_BUNDLE, which keploy's injected trust covers. Calls made: /pinned, /env, /pinned. - Before: the record exits 0 with nothing said. The /pinned test cases hold the app's 500, and the app logged CERTIFICATE_VERIFY_FAILED. - After: the record still exits 0, and says once: "2 TLS handshake(s) with keploy's proxy failed while this recording ran (...); those calls are not recorded", testCases [get-pinned-1, get-pinned-2], last "to 172.19.0.2:8443", next_step the CA docs. get-env-1 is not named. - A pinned call the app makes 1.5 s after its last test case's response, before the stop (SIGINT): the WARN says 3, with afterTheLastTestCase 1. - Following the docs (the app's CA file combined with /tmp/keploy-tls/keploy-ca.crt at container start): both /pinned calls answer 200, are recorded, and nothing is said. Tests (pkg/service/record/ca_reject_warn_test.go): - with the switch off, failed handshakes during two of three test cases and one after the last give one WARN: 4, those two test cases, 1 after the last, its destination, and the docs. The recording is not failed; - none failed: nothing said; a start that cannot be read: nothing said, nothing read after; a read that fails: the next read counts its test cases, and it is no count of 0; an agent started again, during the recording or before the final read: counted whole; - around the stop, with a reader that ends with its context as the agent client's does: a failure in a test case the drain saves, and two after the last, are said (compose's order); in the native and docker order, the test case the drain saves after the final read is named, and nothing is after the last; a stop before capture began: no watch; - the drain: with the final read out (never answered) in the native order, the ask returns at once, a press while the drain saves answers no offer, and the drain saves all 50 mocks the agent held; finish says it waits and stands no offer either. Against the previous version of this change, the same test saved 0 of 50, 3 runs of 3; - a read the agent never answers: the ask returns at once, wall time that keploy could not run gives nothing up, and keploy's own HangBudget does, the test case then counted by the next read; a press that answers a drain's offer (utils.StopNow) ends a read at once; a read that does not end with its context is given up all the same, and its later answer not counted; - reads asked while one is out: made after it, in order, the final one not asked until then; a lagging read names every test case it counts; - no goroutine of the watch's outlives its reads (20 recordings); - abandoned handshakes: nothing said; the fields: a test case's destination, no afterTheLastTestCase with none after, and with every failure after the last, no test cases named and "record again"; - with the switch on, the WARN is not said, and the failed handshake fails the recording as before. TestTheCaptureWatchIsOffWithoutTheSwitchOrACount now expects the switch-off watch to read the count for this WARN and to say nothing of other losses. All 23 compile-safe mutants fail a test. The switch-on watch (captureWatch) has the same unbounded reads: its base and final reads with no offer standing, and its test cases' reads with no escape at all. That is left to its own change, before the switch flips. Signed-off-by: slayerjain <shubhamkjain@outlook.com>
slayerjain
added a commit
to keploy/keploy
that referenced
this pull request
Oct 19, 2026
…e switch off A client that does not trust keploy's CA rejects the certificate keploy's proxy answers its TLS handshake with. Examples are a client that pins its own CA file (Python requests with verify=<file>, a Go client with its own RootCAs) and a library that reads only the OS trust store. Its call fails, and keploy neither records nor can replay it. With the proven switch on, such a handshake (tls_handshake_failed) fails the recording. With it off, keploy said nothing. The recording ended green, its test cases held the app's error response for those calls, and a replay of them passed by replaying that error: a silent false pass. With the switch off, keploy record now says so once, at WARN, when the recording ends: N TLS handshake(s) with keploy's proxy failed while this recording ran (a client that does not trust keploy's CA rejects keploy's certificate); those calls are not recorded It names the test cases recorded while those handshakes failed, how many failed after the last test case, and the last one's destination. Its next_step points at how a client that pins its own CA trusts keploy's, natively and in Docker (https://keploy.io/docs/running-keploy/docker-tls/ #a-client-that-pins-its-own-ca, added by keploy/docs#931). The agent already counts these handshakes with the switch off. The watch the record path already drives (caRejectWatch, in captureWatch) now reads that count: - as capture begins; - as each test case is saved (a handshake's failure is the test case's it was made in, models.PerTest); - once more after the last. The base read is made as capture begins, on record's context, and waited for: a stop before capture began ends it, as does the bound below, and nothing is then watched. Every later read is asked for and not waited for: a test case's as the consumer saves it, and the final one once the app has stopped, at the three places the switch-on watch makes its own final read. They are made on one goroutine of the watch's, one at a time and in the order asked, so an answer is never applied after a later one, and a read that lags counts every test case saved since the last together. finish, after every drain, waits for those still out, saying at Info that it does. No read holds the recording or the stop's drains up; finish's wait is as long as the reads still out, each bounded below. The watch stands no offer of the stop's (utils.OfferStopNow): the final read is asked before the drain in a native or docker stop, and an offer it stood there would have the user's press give that drain up. A read is not ended by the stop, which ends record's context before the drain saves its last test cases and before the final read. It is ended by the interrupt that gave the stop's waits up (utils.StopNow, a drain's own offer answered), and given up once keploy had stall.HangBudget of its own runnable time to run without an answer, so a stop no one presses Ctrl+C at (CI's pkill -INT) ends too, and a starved keploy is not taken for a silent agent. A read given up, or that failed, leaves its test cases to the next read; an answer that comes after is not counted. What failed after the last test case is what the final read saw beyond the last read that counted test cases, when no such read came after it: in a native or docker stop the final read comes before the drain saves its last test cases, and a handshake that failed in one of those is that test case's, and named. A count lower than the last (an agent started again) is taken whole. It changes nothing else: no test case, verdict, status, exit code or hook differs, and with the switch on, captureWatch is as it was. It counts only failed handshakes. A client that hung up on its handshake (tls_handshake_abandoned) cannot be told from one that gave up, so that is left to the proven switch. A count it cannot read is left unsaid (Debug). Replicated in a lane container on 192.168.116.142 with keploy main, in compose. A Flask app calls an HTTPS upstream two ways: /pinned with verify=/certs/ca.pem (its own CA), and /env with REQUESTS_CA_BUNDLE, which keploy's injected trust covers. Calls made: /pinned, /env, /pinned. - Before: the record exits 0 with nothing said. The /pinned test cases hold the app's 500, and the app logged CERTIFICATE_VERIFY_FAILED. - After: the record still exits 0, and says once: "2 TLS handshake(s) with keploy's proxy failed while this recording ran (...); those calls are not recorded", testCases [get-pinned-1, get-pinned-2], last "to 172.19.0.2:8443", next_step the CA docs. get-env-1 is not named. - A pinned call the app makes 1.5 s after its last test case's response, before the stop (SIGINT): the WARN says 3, with afterTheLastTestCase 1. - Following the docs (the app's CA file combined with /tmp/keploy-tls/keploy-ca.crt at container start): both /pinned calls answer 200, are recorded, and nothing is said. Tests (pkg/service/record/ca_reject_warn_test.go): - with the switch off, failed handshakes during two of three test cases and one after the last give one WARN: 4, those two test cases, 1 after the last, its destination, and the docs. The recording is not failed; - none failed: nothing said; a start that cannot be read: nothing said, nothing read after; a read that fails: the next read counts its test cases, and it is no count of 0; an agent started again, during the recording or before the final read: counted whole; - around the stop, with a reader that ends with its context as the agent client's does: a failure in a test case the drain saves, and two after the last, are said (compose's order); in the native and docker order, the test case the drain saves after the final read is named, and nothing is after the last; a stop before capture began: no watch; - the drain: with the final read out (never answered) in the native order, the ask returns at once, a press while the drain saves answers no offer, and the drain saves all 50 mocks the agent held; finish says it waits and stands no offer either. Against the previous version of this change, the same test saved 0 of 50, 3 runs of 3; - a read the agent never answers: the ask returns at once, wall time that keploy could not run gives nothing up, and keploy's own HangBudget does, the test case then counted by the next read; a press that answers a drain's offer (utils.StopNow) ends a read at once; a read that does not end with its context is given up all the same, and its later answer not counted; - reads asked while one is out: made after it, in order, the final one not asked until then; a lagging read names every test case it counts; - no goroutine of the watch's outlives its reads (20 recordings); - abandoned handshakes: nothing said; the fields: a test case's destination, no afterTheLastTestCase with none after, and with every failure after the last, no test cases named and "record again"; - with the switch on, the WARN is not said, and the failed handshake fails the recording as before. TestTheCaptureWatchIsOffWithoutTheSwitchOrACount now expects the switch-off watch to read the count for this WARN and to say nothing of other losses. All 23 compile-safe mutants fail a test. The switch-on watch (captureWatch) has the same unbounded reads: its base and final reads with no offer standing, and its test cases' reads with no escape at all. That is left to its own change, before the switch flips. Signed-off-by: slayerjain <shubhamkjain@outlook.com>
slayerjain
added a commit
to keploy/keploy
that referenced
this pull request
Oct 19, 2026
…e switch off A client that does not trust keploy's CA rejects the certificate keploy's proxy answers its TLS handshake with. Examples are a client that pins its own CA file (Python requests with verify=<file>, a Go client with its own RootCAs) and a library that reads only the OS trust store. Its call fails, and keploy neither records nor can replay it. With the proven switch on, such a handshake (tls_handshake_failed) fails the recording. With it off, keploy said nothing. The recording ended green, its test cases held the app's error response for those calls, and a replay of them passed by replaying that error: a silent false pass. With the switch off, keploy record now says so once, at WARN, when the recording ends: N TLS handshake(s) with keploy's proxy failed while this recording ran (a client that does not trust keploy's CA rejects keploy's certificate); those calls are not recorded It names the test cases recorded while those handshakes failed, how many failed after the last test case, and the last one's destination. Its next_step points at how a client that pins its own CA trusts keploy's, natively and in Docker (https://keploy.io/docs/running-keploy/docker-tls/ #a-client-that-pins-its-own-ca, added by keploy/docs#931). The agent already counts these handshakes with the switch off. The watch the record path already drives (caRejectWatch, in captureWatch) now reads that count: - as capture begins; - as each test case is saved (a handshake's failure is the test case's it was made in, models.PerTest); - once more after the last. The base read is made as capture begins, on record's context, and waited for (bounded as below): a stop during it ends it, and the watch is then off for the recording. Every later read is asked for and not waited for: a test case's as the consumer saves it, and the final one once the app has stopped, at the three places the switch-on watch makes its own final read. They are made on one goroutine of the watch's, one at a time and in the order asked, so an answer is never applied after a later one, and a read that lags counts every test case saved since the last together. Those reads are not ended by the stop, which ends record's context before the drain saves its last test cases and before the final read; the interrupt that gave the stop's waits up (utils.StopNow, a drain's own offer answered) ends them. Every read is given up once keploy had stall.HangBudget of its own runnable time to run without an answer, so a stop no one presses Ctrl+C at (CI's pkill -INT) ends too, and a starved keploy is not taken for a silent agent. A read given up, or that failed, leaves its test cases to the next read; an answer that comes after is not counted. While a drain may still save what the agent held, the watch stands no offer of the stop's (utils.OfferStopNow): the final read is asked before the drain in a native or docker stop, and an offer it stood there would have the user's press give that drain up. Once the frame drains are over, the stop waits for the reads still out while the agent is up (after drainFrames natively, before compose takes the stack down, before the agent is told to go), saying so at Info and offering nothing, since a record drain may still select on utils.StopNow; each read is bounded, so that wait is too, up to HangBudget of runnable time for each read still out. finish, after every drain, waits for any left, and there, once it has said so, one more Ctrl+C stops the wait now. What failed after the last test case is what the final read saw beyond the last read that counted test cases, when no such read came after it: in a native or docker stop the final read comes before the drain saves its last test cases, and a handshake that failed in one of those is that test case's, and named, once its read comes. A test case whose read never came (the agent went first) is named as not checked, and what the final read saw beyond the last counted read is said to be in it or after the last test case. A count lower than the last (an agent started again) is taken whole; one started again whose count has passed the last by the next read is not told from one that was not. It changes nothing else: no test case, verdict, status, exit code or hook differs, and with the switch on, captureWatch is as it was. It counts only failed handshakes. A client that hung up on its handshake (tls_handshake_abandoned) cannot be told from one that gave up, so that is left to the proven switch. A count it cannot read is left unsaid (Debug). Replicated in a lane container on 192.168.116.142 with keploy main, in compose. A Flask app calls an HTTPS upstream two ways: /pinned with verify=/certs/ca.pem (its own CA), and /env with REQUESTS_CA_BUNDLE, which keploy's injected trust covers. Calls made: /pinned, /env, /pinned. - Before: the record exits 0 with nothing said. The /pinned test cases hold the app's 500, and the app logged CERTIFICATE_VERIFY_FAILED. - With an earlier, synchronous version of this watch (the same WARN): the record still exits 0, and says once: "2 TLS handshake(s) with keploy's proxy failed while this recording ran (...); those calls are not recorded", testCases [get-pinned-1, get-pinned-2], last "to 172.19.0.2:8443", next_step the CA docs; get-env-1 is not named. A pinned call 1.5 s after the last test case's response, before the stop (SIGINT): 3, with afterTheLastTestCase 1. Following the docs (the app's CA file combined with /tmp/keploy-tls/keploy-ca.crt at container start): both /pinned calls answer 200, are recorded, and nothing is said. This version's reads are the unit tests' below; the lane is to be run again on it. Tests (pkg/service/record/ca_reject_warn_test.go): - with the switch off, failed handshakes during two of three test cases and one after the last give one WARN: 4, those two test cases, 1 after the last, its destination, and the docs. The recording is not failed; - none failed: nothing said; a start that cannot be read: nothing said, nothing read after; a read that fails: the next read counts its test cases, and it is no count of 0; an agent started again, during the recording or before the final read: counted whole; - around the stop, with a reader that ends with its context as the agent client's does: a failure in a test case the drain saves, and two after the last, are said (compose's order); in the native and docker order, the test case the drain saves after the final read is named, and nothing is after the last; one whose read never came is named as not checked, and what the final read saw beyond is said to be in it or after the last (and it is not named when the final read saw nothing beyond); a stop before capture began: no watch; a base read the agent never answers is given up on its stall; - the drain: with the final read out (never answered) in the native order, the ask returns at once, a press while the drain saves answers no offer, and the drain saves all 50 mocks the agent held; the stop's wait for the read after the drains says it waits and stands no offer either. Against the previous version of this change, the same test saved 0 of 50, 3 runs of 3; finish, after every drain, offers one more Ctrl+C, which ends it and the read, and withdraws the offer as it ends; - a read the agent never answers: the ask returns at once, wall time that keploy could not run gives nothing up, and keploy's own HangBudget does, the test case then counted by the next read; a press that answers a drain's offer (utils.StopNow) ends a read at once; a read that does not end with its context is given up all the same, and its later answer not counted; - reads asked while one is out: made after it, in order, the final one not asked until then; a lagging read names every test case it counts; - no goroutine of the watch's outlives its reads (20 recordings); an ask after finish reads nothing; - abandoned handshakes: nothing said; the fields: a test case's destination, no afterTheLastTestCase with none after, and with every failure after the last, no test cases named and "record again"; - with the switch on, the WARN is not said, and the failed handshake fails the recording as before. TestTheCaptureWatchIsOffWithoutTheSwitchOrACount now expects the switch-off watch to read the count for this WARN and to say nothing of other losses. Of 28 compile-safe mutants, 27 fail a test; the one left drops the check in an ask after finish, which the read goroutine's own check makes redundant (it then ends without a read). The three calls in record.go that wait for the reads after the frame drains have no test of their own. The switch-on watch (captureWatch) has the same unbounded reads: its base and final reads with no offer standing, and its test cases' reads with no escape at all. That is left to its own change, before the switch flips. Signed-off-by: slayerjain <shubhamkjain@outlook.com>
slayerjain
added a commit
to keploy/keploy
that referenced
this pull request
Oct 19, 2026
…e switch off A client that does not trust keploy's CA rejects the certificate keploy's proxy answers its TLS handshake with. Examples are a client that pins its own CA file (Python requests with verify=<file>, a Go client with its own RootCAs) and a library that reads only the OS trust store. Its call fails, and keploy neither records nor can replay it. With the proven switch on, such a handshake (tls_handshake_failed) fails the recording. With it off, keploy said nothing. The recording ended green, its test cases held the app's error response for those calls, and a replay of them passed by replaying that error: a silent false pass. With the switch off, keploy record now says so once, at WARN, when the recording ends: N TLS handshake(s) with keploy's proxy failed while this recording ran (a client that does not trust keploy's CA rejects keploy's certificate); those calls are not recorded It names the test cases recorded while those handshakes failed, how many failed after the last test case, and the last one's destination. Its next_step points at how a client that pins its own CA trusts keploy's, natively and in Docker (https://keploy.io/docs/running-keploy/docker-tls/ #a-client-that-pins-its-own-ca, added by keploy/docs#931). The agent already counts these handshakes with the switch off. The watch the record path already drives (caRejectWatch, in captureWatch) now reads that count: - as capture begins; - as each test case is saved (a handshake's failure is the test case's it was made in, models.PerTest); - once more after the last. The base read is made as capture begins, on record's context, and waited for (bounded as below): a stop during it ends it, and the watch is then off for the recording. Every later read is asked for and not waited for: a test case's as the consumer saves it, and the final one at the three places the switch-on watch makes its own final read (once the app has stopped, but in a docker compose stop with the switch off, where the app still runs, once the drain is over). They are made on one goroutine of the watch's, one at a time and in the order asked, so an answer is never applied after a later one, and a read that lags counts every test case saved since the last together. Those reads are not ended by the stop, which ends record's context before the drain saves its last test cases and before the final read; the interrupt that gave the stop's waits up (utils.StopNow, a drain's own offer answered) ends them. Every read is given up once keploy had stall.HangBudget of its own runnable time to run without an answer, so a stop no one presses Ctrl+C at (CI's pkill -INT) ends too, and a starved keploy is not taken for a silent agent. A read given up, or that failed, leaves its test cases to the next read; an answer that comes after is not counted. While a drain may still save what the agent held, the watch stands no offer of the stop's (utils.OfferStopNow): the final read is asked before the drain in a native or docker stop, and an offer it stood there would have the user's press give that drain up. Once the frame drains are over, the stop waits for the reads still out before it lets the agent go (after drainFrames natively, before compose takes the stack down, before the agent is told to go: an agent that goes as its streams close may be gone already, and its reads then fail), saying so at Info. That wait stands no offer, since a record drain may still select on utils.StopNow: the user's next Ctrl+C after it began (utils.InterruptedAfter) stops it, and ends the watch's reads alone. Each read is bounded, so the wait is too: up to HangBudget of runnable time for each read still out or asked while it waits. finish, after every drain, waits for any left, and there, once it has said so, one more Ctrl+C stops the wait now. A read a press ended, or one still out as finish ends, leaves its test cases not checked. What failed after the last test case is what the final read saw beyond the last read that counted test cases, when no such read came after it: in a native or docker stop the final read comes before the drain saves its last test cases, and a handshake that failed in one of those is that test case's, and named, once its read comes. A test case whose read never came (the agent went first, or the user stopped the wait) is named as not checked, and what the final read saw beyond the last counted read is said to be in it or after the last test case. In compose's order a read that failed leaves its test cases to the final read, which then names them for what failed after the last too: an extra test case to re-record, never one left out. A count lower than the last (an agent started again) is taken whole; one started again whose count has passed the last by the next read is not told from one that was not. It changes nothing else: no test case, verdict, status, exit code or hook differs, and with the switch on, captureWatch is as it was. It counts only failed handshakes. A client that hung up on its handshake (tls_handshake_abandoned) cannot be told from one that gave up, so that is left to the proven switch. A count it cannot read is left unsaid (Debug). Replicated in a lane container on 192.168.116.142 with keploy main, in compose. A Flask app calls an HTTPS upstream two ways: /pinned with verify=/certs/ca.pem (its own CA), and /env with REQUESTS_CA_BUNDLE, which keploy's injected trust covers. Calls made: /pinned, /env, /pinned. - Before: the record exits 0 with nothing said. The /pinned test cases hold the app's 500, and the app logged CERTIFICATE_VERIFY_FAILED. - After (run on this commit's code): the record still exits 0, and says once: "2 TLS handshake(s) with keploy's proxy failed while this recording ran (...); those calls are not recorded", testCases [get-pinned-1, get-pinned-2], last "to 172.19.0.2:8443", next_step the CA docs; get-env-1 is not named. - A pinned call the app makes after its last test case's response, before the stop (SIGINT): the WARN says 3, with afterTheLastTestCase 1. - Following the docs (the app's CA file combined with /tmp/keploy-tls/keploy-ca.crt at container start): both /pinned calls answer 200, are recorded, and nothing is said. - Native: SSL_CERT_FILE in the app's environment names a file holding keploy's per-run CA (the docs' native recipe). Tests (pkg/service/record/ca_reject_warn_test.go): - with the switch off, failed handshakes during two of three test cases and one after the last give one WARN: 4, those two test cases, 1 after the last, its destination, and the docs. The recording is not failed; - none failed: nothing said; a start that cannot be read: nothing said, nothing read after; a read that fails: the next read counts its test cases, and it is no count of 0; an agent started again, during the recording or before the final read: counted whole; - around the stop, with a reader that ends with its context as the agent client's does: a failure in a test case the drain saves, and two after the last, are said (compose's order); in the native and docker order, the test case the drain saves after the final read is named, and nothing is after the last; one whose read never came is named as not checked, and what the final read saw beyond is said to be in it or after the last (and it is not named when the final read saw nothing beyond); a stop before capture began: no watch; a base read the agent never answers is given up on its stall; - the drain: with the final read out (never answered) in the native order, the ask returns at once, a press while the drain saves answers no offer, and the drain saves all 50 mocks the agent held; the stop's wait for the read after the drains says it waits and stands no offer either. Against the previous version of this change, the same test saved 0 of 50, 3 runs of 3; finish, after every drain, offers one more Ctrl+C, which ends it and the read, and withdraws the offer as it ends; - a press at finish's offer while a test case's read is out: it is named not checked, not dropped; the stop's wait after the frame drains stands no offer, and the next Ctrl+C stops it and ends even a read that does not end with its context; with the final read failed, unread test cases are named not checked beside those counted, and with nothing counted nothing is said; - a read the agent never answers: the ask returns at once, wall time that keploy could not run gives nothing up, and keploy's own HangBudget does, the test case then counted by the next read; a press that answers a drain's offer (utils.StopNow) ends a read at once; a read that does not end with its context is given up all the same, and its later answer not counted; - reads asked while one is out: made after it, in order, the final one not asked until then; a lagging read names every test case it counts; - no goroutine of the watch's outlives its reads (20 recordings); an ask after finish reads nothing; - abandoned handshakes: nothing said; the fields: a test case's destination, no afterTheLastTestCase with none after, and with every failure after the last, no test cases named and "record again"; - with the switch on, the WARN is not said, and the failed handshake fails the recording as before. TestTheCaptureWatchIsOffWithoutTheSwitchOrACount now expects the switch-off watch to read the count for this WARN and to say nothing of other losses. Of 33 compile-safe mutants, 32 fail a test; the one left drops the check in an ask after finish, which the read goroutine's own check makes redundant (it then ends without a read). The three calls in record.go that wait for the reads after the frame drains have no test of their own. The switch-on watch (captureWatch) has the same unbounded reads: its base and final reads with no offer standing, and its test cases' reads with no escape at all. That is left to its own change, before the switch flips. Signed-off-by: slayerjain <shubhamkjain@outlook.com>
slayerjain
added a commit
to keploy/keploy
that referenced
this pull request
Oct 19, 2026
…e switch off A client that does not trust keploy's CA rejects the certificate keploy's proxy answers its TLS handshake with. Examples are a client that pins its own CA file (Python requests with verify=<file>, a Go client with its own RootCAs) and a library that reads only the OS trust store. Its call fails, and keploy neither records nor can replay it. With the proven switch on, such a handshake (tls_handshake_failed) fails the recording. With it off, keploy said nothing. The recording ended green, its test cases held the app's error response for those calls, and a replay of them passed by replaying that error: a silent false pass. With the switch off, keploy record now says so once, at WARN, when the recording ends: N TLS handshake(s) with keploy's proxy failed while this recording ran (a client that does not trust keploy's CA rejects keploy's certificate); those calls are not recorded It names the test cases recorded while those handshakes failed, how many failed after the last test case, and the last one's destination. Its next_step points at how a client that pins its own CA trusts keploy's, natively and in Docker (https://keploy.io/docs/running-keploy/docker-tls/ #a-client-that-pins-its-own-ca, added by keploy/docs#931). The agent already counts these handshakes with the switch off. The watch the record path already drives (caRejectWatch, in captureWatch) now reads that count: - as capture begins; - as each test case is saved (a handshake's failure is the test case's it was made in, models.PerTest); - once more after the last. The base read is made as capture begins, on record's context, and waited for (bounded as below): a stop during it ends it, and the watch is then off for the recording. Every later read is asked for and not waited for: a test case's as the consumer saves it, and the final one at the three places the switch-on watch makes its own final read (once the app has stopped, but in a docker compose stop with the switch off, where the app still runs, once the drain is over). They are made on one goroutine of the watch's, one at a time and in the order asked, so an answer is never applied after a later one, and a read that lags counts every test case saved since the last together. Those reads are not ended by the stop, which ends record's context before the drain saves its last test cases and before the final read; the interrupt that gave the stop's waits up (utils.StopNow, a drain's own offer answered) ends them. Every read is given up once keploy had stall.HangBudget of its own runnable time to run without an answer, so a stop no one presses Ctrl+C at (CI's pkill -INT) ends too, and a starved keploy is not taken for a silent agent. A read given up, or that failed, leaves its test cases to the next read; an answer that comes after is not counted. While a drain may still save what the agent held, the watch stands no offer of the stop's (utils.OfferStopNow): the final read is asked before the drain in a native or docker stop, and an offer it stood there would have the user's press give that drain up. Once the frame drains are over, the stop waits for the reads still out before it lets the agent go (after drainFrames natively, before compose takes the stack down, before the agent is told to go: an agent that goes as its streams close may be gone already, and its reads then fail), saying so at Info. That wait stands no offer, since a record drain may still select on utils.StopNow: the user's next Ctrl+C once the run has been interrupted (utils.InterruptedAfter) stops it, and ends the watch's reads alone; the wait says so only once it holds (a stop no signal began, the record timer or an app that exited, has the user's first Ctrl+C as the run's first signal, which only marks it interrupted). Each read is bounded, so the wait is too: up to HangBudget of runnable time for each read still out or asked while it waits. finish, after every drain, waits for any left, and there, once it has said so, one more Ctrl+C stops the wait now. A read a press ended, or one still out as finish ends, leaves its test cases not checked. What failed after the last test case is what the final read saw beyond the last read that counted test cases, when no such read came after it: in a native or docker stop the final read comes before the drain saves its last test cases, and a handshake that failed in one of those is that test case's, and named, once its read comes. A test case whose read never came (the agent went first, or the user stopped the wait) is named as not checked, and what the final read saw beyond the last counted read is said to be in it or after the last test case. In compose's order a read that failed leaves its test cases to the final read, which then names them for what failed after the last too: an extra test case to re-record, never one left out. A count lower than the last (an agent started again) is taken whole; one started again whose count has passed the last by the next read is not told from one that was not. It changes nothing else: no test case, verdict, status, exit code or hook differs, and with the switch on, captureWatch is as it was. It counts only failed handshakes. A client that hung up on its handshake (tls_handshake_abandoned) cannot be told from one that gave up, so that is left to the proven switch. A count it cannot read is left unsaid (Debug). Replicated in a lane container on 192.168.116.142 with keploy main, in compose. A Flask app calls an HTTPS upstream two ways: /pinned with verify=/certs/ca.pem (its own CA), and /env with REQUESTS_CA_BUNDLE, which keploy's injected trust covers. Calls made: /pinned, /env, /pinned. - Before: the record exits 0 with nothing said. The /pinned test cases hold the app's 500, and the app logged CERTIFICATE_VERIFY_FAILED. - After (run on this commit's code): the record still exits 0, and says once: "2 TLS handshake(s) with keploy's proxy failed while this recording ran (...); those calls are not recorded", testCases [get-pinned-1, get-pinned-2], last "to 172.19.0.2:8443", next_step the CA docs; get-env-1 is not named. - A pinned call the app makes after its last test case's response, before the stop (SIGINT): the WARN says 3, with afterTheLastTestCase 1. - Following the docs (the app's CA file combined with /tmp/keploy-tls/keploy-ca.crt at container start): both /pinned calls answer 200, are recorded, and nothing is said. - Native (the docs' native recipe's premise, not the WARN): SSL_CERT_FILE in the app's environment names a file holding keploy's per-run CA. Tests (pkg/service/record/ca_reject_warn_test.go): - with the switch off, failed handshakes during two of three test cases and one after the last give one WARN: 4, those two test cases, 1 after the last, its destination, and the docs. The recording is not failed; - none failed: nothing said; a start that cannot be read: nothing said, nothing read after; a read that fails: the next read counts its test cases, and it is no count of 0; an agent started again, during the recording or before the final read: counted whole; - around the stop, with a reader that ends with its context as the agent client's does: a failure in a test case the drain saves, and two after the last, are said (compose's order); in the native and docker order, the test case the drain saves after the final read is named, and nothing is after the last; one whose read never came is named as not checked, and what the final read saw beyond is said to be in it or after the last (and it is not named when the final read saw nothing beyond); a stop before capture began: no watch; a base read the agent never answers is given up on its stall; - the drain: with the final read out (never answered) in the native order, the ask returns at once, a press while the drain saves answers no offer, and the drain saves all 50 mocks the agent held; the stop's wait for the read after the drains says it waits and stands no offer either. Against the previous version of this change, the same test saved 0 of 50, 3 runs of 3; finish, after every drain, offers one more Ctrl+C, which ends it and the read, and withdraws the offer as it ends; - a press at finish's offer while a test case's read is out: it is named not checked, not dropped; the stop's wait after the frame drains stands no offer, and the next Ctrl+C stops it and ends even a read that does not end with its context, with no read after; a stop no signal began says how to stop that wait only once the run has been interrupted, and the next press then does; with the final read failed, unread test cases are named not checked beside those counted, and with nothing counted nothing is said; - a read the agent never answers: the ask returns at once, wall time that keploy could not run gives nothing up, and keploy's own HangBudget does, the test case then counted by the next read; a press that answers a drain's offer (utils.StopNow) ends a read at once; a read that does not end with its context is given up all the same, and its later answer not counted; - reads asked while one is out: made after it, in order, the final one not asked until then; a lagging read names every test case it counts; - no goroutine of the watch's outlives its reads (20 recordings); an ask after finish reads nothing; - abandoned handshakes: nothing said; the fields: a test case's destination, no afterTheLastTestCase with none after, and with every failure after the last, no test cases named and "record again"; - with the switch on, the WARN is not said, and the failed handshake fails the recording as before. TestTheCaptureWatchIsOffWithoutTheSwitchOrACount now expects the switch-off watch to read the count for this WARN and to say nothing of other losses. Of 35 compile-safe mutants, 34 fail a test; the one left drops the check in an ask after finish, which the read goroutine's own check makes redundant (it then ends without a read). The three calls in record.go that wait for the reads after the frame drains have no test of their own. The switch-on watch (captureWatch) has the same unbounded reads: its base and final reads with no offer standing, and its test cases' reads with no escape at all. That is left to its own change, before the switch flips. Signed-off-by: slayerjain <shubhamkjain@outlook.com>
slayerjain
added a commit
to keploy/keploy
that referenced
this pull request
Oct 19, 2026
…e switch off A client that does not trust keploy's CA rejects the certificate keploy's proxy answers its TLS handshake with. Examples are a client that pins its own CA file (Python requests with verify=<file>, a Go client with its own RootCAs) and a library that reads only the OS trust store. Its call fails, and keploy neither records nor can replay it. With the proven switch on, such a handshake (tls_handshake_failed) fails the recording. With it off, keploy said nothing. The recording ended green, its test cases held the app's error response for those calls, and a replay of them passed by replaying that error: a silent false pass. With the switch off, keploy record now says so once, at WARN, when the recording ends: N TLS handshake(s) with keploy's proxy failed while this recording ran (a client that does not trust keploy's CA rejects keploy's certificate); those calls are not recorded It names the test cases recorded while those handshakes failed, how many failed after the last test case, and the last one's destination. Its next_step points at how a client that pins its own CA trusts keploy's, natively and in Docker (https://keploy.io/docs/running-keploy/docker-tls/ #a-client-that-pins-its-own-ca, added by keploy/docs#931). The agent already counts these handshakes with the switch off. The watch the record path already drives (caRejectWatch, in captureWatch) now reads that count: - as capture begins; - as each test case is saved (a handshake's failure is the test case's it was made in, models.PerTest); - once more after the last. The base read is made as capture begins, on record's context, and waited for (bounded as below): a stop during it ends it, and the watch is then off for the recording. Every later read is asked for and not waited for: a test case's as the consumer saves it, and the final one at the three places the switch-on watch makes its own final read (once the app has stopped, but in a docker compose stop with the switch off, where the app still runs, once the drain is over). They are made on one goroutine of the watch's, one at a time and in the order asked, so an answer is never applied after a later one, and a read that lags counts every test case saved since the last together. Those reads are not ended by the stop, which ends record's context before the drain saves its last test cases and before the final read; the interrupt that gave the stop's waits up (utils.StopNow, a drain's own offer answered) ends them. Every read is given up once keploy had stall.HangBudget of its own runnable time to run without an answer, so a stop no one presses Ctrl+C at (CI's pkill -INT) ends too, and a starved keploy is not taken for a silent agent. A read given up, or that failed, leaves its test cases to the next read; an answer that comes after is not counted. While a drain may still save what the agent held, the watch stands no offer of the stop's (utils.OfferStopNow): the final read is asked before the drain in a native or docker stop, and an offer it stood there would have the user's press give that drain up. Once the frame drains are over, the stop waits for the reads still out before it lets the agent go (after drainFrames natively, before compose takes the stack down, before the agent is told to go: an agent that goes as its streams close may be gone already, and its reads then fail), saying so at Info. That wait stands no offer, since a record drain may still select on utils.StopNow, but a whole notice period after it saw the run interrupted (as utils.StopNowNotice paces its offer, so the copy of the stop's signal that sudo hands on is not taken for a press) it hears the next Ctrl+C (utils.InterruptedAfter), which stops it and ends the watch's reads alone. It says so from then on, and not before; a press before then is not heard. A stop no signal began (the record timer, an app that exited) has the user's first Ctrl+C as the run's first signal, which begins keploy's own stop rather than ending this wait. Each read is bounded, so the wait is too: up to HangBudget of runnable time for each read still out or asked while it waits. finish, after every drain, waits for any left, and there, once it has said so, one more Ctrl+C stops the wait now. A read a press ended, or one still out as finish ends, leaves its test cases not checked. What failed after the last test case is what the final read saw beyond the last read that counted test cases, when no such read came after it: in a native or docker stop the final read comes before the drain saves its last test cases, and a handshake that failed in one of those is that test case's, and named, once its read comes. A test case whose read never came (the agent went first, or the user stopped the wait) is named as not checked, and what the final read saw beyond the last counted read is said to be in it or after the last test case. In compose's order a read that failed leaves its test cases to the final read, which then names them for what failed after the last too: an extra test case to re-record, never one left out. A count lower than the last (an agent started again) is taken whole; one started again whose count has passed the last by the next read is not told from one that was not. It changes nothing else: no test case, verdict, status, exit code or hook differs, and with the switch on, captureWatch is as it was. It counts only failed handshakes. A client that hung up on its handshake (tls_handshake_abandoned) cannot be told from one that gave up, so that is left to the proven switch. A count it cannot read is left unsaid (Debug). Replicated in a lane container on 192.168.116.142 with keploy main, in compose. A Flask app calls an HTTPS upstream two ways: /pinned with verify=/certs/ca.pem (its own CA), and /env with REQUESTS_CA_BUNDLE, which keploy's injected trust covers. Calls made: /pinned, /env, /pinned. - Before: the record exits 0 with nothing said. The /pinned test cases hold the app's 500, and the app logged CERTIFICATE_VERIFY_FAILED. - After (run on this commit's code): the record still exits 0, and says once: "2 TLS handshake(s) with keploy's proxy failed while this recording ran (...); those calls are not recorded", testCases [get-pinned-1, get-pinned-2], last "to 172.19.0.2:8443", next_step the CA docs; get-env-1 is not named. - A pinned call the app makes after its last test case's response, before the stop (SIGINT): the WARN says 3, with afterTheLastTestCase 1. - Following the docs (the app's CA file combined with /tmp/keploy-tls/keploy-ca.crt at container start): both /pinned calls answer 200, are recorded, and nothing is said. - Native (the docs' native recipe's premise, not the WARN): SSL_CERT_FILE in the app's environment names a file holding keploy's per-run CA. Tests (pkg/service/record/ca_reject_warn_test.go): - with the switch off, failed handshakes during two of three test cases and one after the last give one WARN: 4, those two test cases, 1 after the last, its destination, and the docs. The recording is not failed; - none failed: nothing said; a start that cannot be read: nothing said, nothing read after; a read that fails: the next read counts its test cases, and it is no count of 0; an agent started again, during the recording or before the final read: counted whole; - around the stop, with a reader that ends with its context as the agent client's does: a failure in a test case the drain saves, and two after the last, are said (compose's order); in the native and docker order, the test case the drain saves after the final read is named, and nothing is after the last; one whose read never came is named as not checked, and what the final read saw beyond is said to be in it or after the last (and it is not named when the final read saw nothing beyond); a stop before capture began: no watch; a base read the agent never answers is given up on its stall; - the drain: with the final read out (never answered) in the native order, the ask returns at once, a press while the drain saves answers no offer, and the drain saves all 50 mocks the agent held; the stop's wait for the read after the drains says it waits and stands no offer either. Against the previous version of this change, the same test saved 0 of 50, 3 runs of 3; finish, after every drain, offers one more Ctrl+C, which ends it and the read, and withdraws the offer as it ends; - a press at finish's offer while a test case's read is out: it is named not checked, not dropped; the stop's wait after the frame drains stands no offer, and the next Ctrl+C stops it and ends even a read that does not end with its context, with no read after; a stop no signal began says how to stop that wait only once the run has been interrupted, and the next press then does; a copy of the stop's signal, coming with it, does not stop that wait, which hears presses only a notice period on; with the final read failed, unread test cases are named not checked beside those counted, and with nothing counted nothing is said; - a read the agent never answers: the ask returns at once, wall time that keploy could not run gives nothing up, and keploy's own HangBudget does, the test case then counted by the next read; a press that answers a drain's offer (utils.StopNow) ends a read at once; a read that does not end with its context is given up all the same, and its later answer not counted; - reads asked while one is out: made after it, in order, the final one not asked until then; a lagging read names every test case it counts; - no goroutine of the watch's outlives its reads (20 recordings); an ask after finish reads nothing; - abandoned handshakes: nothing said; the fields: a test case's destination, no afterTheLastTestCase with none after, and with every failure after the last, no test cases named and "record again"; - with the switch on, the WARN is not said, and the failed handshake fails the recording as before. TestTheCaptureWatchIsOffWithoutTheSwitchOrACount now expects the switch-off watch to read the count for this WARN and to say nothing of other losses. Of 36 compile-safe mutants, 35 fail a test; the one left drops the check in an ask after finish, which the read goroutine's own check makes redundant (it then ends without a read). The three calls in record.go that wait for the reads after the frame drains have no test of their own. The switch-on watch (captureWatch) has the same unbounded reads: its base and final reads with no offer standing, and its test cases' reads with no escape at all. That is left to its own change, before the switch flips. Signed-off-by: slayerjain <shubhamkjain@outlook.com>
slayerjain
added a commit
to keploy/keploy
that referenced
this pull request
Oct 19, 2026
…e switch off A client that does not trust keploy's CA rejects the certificate keploy's proxy answers its TLS handshake with. Examples are a client that pins its own CA file (Python requests with verify=<file>, a Go client with its own RootCAs) and a library that reads only the OS trust store. Its call fails, and keploy neither records nor can replay it. With the proven switch on, such a handshake (tls_handshake_failed) fails the recording. With it off, keploy said nothing. The recording ended green, its test cases held the app's error response for those calls, and a replay of them passed by replaying that error: a silent false pass. With the switch off, keploy record now says so once, at WARN, when the recording ends: N TLS handshake(s) with keploy's proxy failed while this recording ran (a client that does not trust keploy's CA rejects keploy's certificate); those calls are not recorded It names the test cases recorded while those handshakes failed, how many failed after the last test case, and the last one's destination. Its next_step points at how a client that pins its own CA trusts keploy's, natively and in Docker (https://keploy.io/docs/running-keploy/docker-tls/ #a-client-that-pins-its-own-ca, added by keploy/docs#931). The agent already counts these handshakes with the switch off. The watch the record path already drives (caRejectWatch, in captureWatch) now reads that count: - as capture begins; - as each test case is saved (a handshake's failure is the test case's it was made in, models.PerTest); - once more after the last. The base read is made as capture begins, on record's context, and waited for (bounded as below): a stop during it ends it, and the watch is then off for the recording. Every later read is asked for and not waited for: a test case's as the consumer saves it, and the final one at the three places the switch-on watch makes its own final read (once the app has stopped, but in a docker compose stop with the switch off, where the app still runs, once the drain is over). They are made on one goroutine of the watch's, one at a time and in the order asked, so an answer is never applied after a later one, and a read that lags counts every test case saved since the last together. Those reads are not ended by the stop, which ends record's context before the drain saves its last test cases and before the final read (but a compose agent that goes on its own has its drain and final read run with no stop at all); the interrupt that gave the stop's waits up (utils.StopNow, a drain's own offer answered) ends them. Every read is given up once keploy had stall.HangBudget of its own runnable time to run without an answer, so a stop no one presses Ctrl+C at (CI's pkill -INT) ends too, and a starved keploy is not taken for a silent agent. A read given up, or that failed, leaves its test cases to the next read; an answer that comes after is not counted. While a drain may still save what the agent held, the watch stands no offer of the stop's (utils.OfferStopNow): the final read is asked before the drain in a native or docker stop, and an offer it stood there would have the user's press give that drain up. Once the frame drains are over, the stop waits for the reads still out before it lets the agent go (after drainFrames natively, before compose takes the stack down, before the agent is told to go: an agent that goes as its streams close may be gone already, and its reads then fail), saying so at Info, with how long it can take. No interrupt ends that wait. It stands no offer, since a record drain may still select on utils.StopNow; and it hears no press of its own, since nothing keploy can see tells the user's Ctrl+C from the copy of the stop's own signal that sudo hands on: a signal a user process sends (CI's `sudo pkill -INT -f keploy`) reaches keploy directly and again through sudo, which relays it (sudo(8): SIGINT is relayed when sent by a user process, or under a new pty), Go's os/signal gives no signal's sender (and signalfd cannot hold SIGINT, which the runtime unblocks on every thread), and only time could tell them apart, which a loaded host does not keep. (An escape on a signal no stop sends, Ctrl+\, or the sender read off a kernel tracepoint, would tell them apart; neither is worth its cost for a diagnostic.) So its line says that Ctrl+C does not cut it short, and each read's bound ends it: up to HangBudget of runnable time for each read still out or asked while it waits. finish, after every drain, waits for any left, and there, once it has said so, one more Ctrl+C stops the wait now (a copy of the stop's signal taken for that press costs no more than the count, as every offer of the stop's must). A read a press ended, or one still out as finish ends, leaves its test cases not checked, and they are named at WARN even when nothing was counted: unknown is not none. What failed after the last test case is what the final read saw beyond the last read that counted test cases, when no such read came after it: in a native or docker stop the final read comes before the drain saves its last test cases, and a handshake that failed in one of those is that test case's, and named, once its read comes. A test case whose read never came (the agent went first, or the user stopped the wait) is named as not checked, and what the final read saw beyond the last counted read is said to be in it or after the last test case. In compose's order a read that failed leaves its test cases to the final read, which then names them for what failed after the last too: an extra test case to re-record, never one left out. A count lower than the last (an agent started again) is taken whole; one started again whose count has passed the last by the next read is not told from one that was not. It changes nothing else: no test case, verdict, status, exit code or hook differs, and with the switch on, captureWatch is as it was. It counts only failed handshakes. A client that hung up on its handshake (tls_handshake_abandoned) cannot be told from one that gave up, so that is left to the proven switch. A count it cannot read is left unsaid (Debug). Replicated in a lane container on 192.168.116.142 with keploy main, in compose. A Flask app calls an HTTPS upstream two ways: /pinned with verify=/certs/ca.pem (its own CA), and /env with REQUESTS_CA_BUNDLE, which keploy's injected trust covers. Calls made: /pinned, /env, /pinned. - Before: the record exits 0 with nothing said. The /pinned test cases hold the app's 500, and the app logged CERTIFICATE_VERIFY_FAILED. - After (run on this commit's code): the record still exits 0, and says once: "2 TLS handshake(s) with keploy's proxy failed while this recording ran (...); those calls are not recorded", testCases [get-pinned-1, get-pinned-2], last "to 172.19.0.2:8443", next_step the CA docs; get-env-1 is not named. - A pinned call the app makes after its last test case's response, before the stop (SIGINT): the WARN says 3, with afterTheLastTestCase 1. - Following the docs (the app's CA file combined with /tmp/keploy-tls/keploy-ca.crt at container start): both /pinned calls answer 200, are recorded, and nothing is said. - Native (the docs' native recipe's premise, not the WARN): SSL_CERT_FILE in the app's environment names a file holding keploy's per-run CA. Tests (pkg/service/record/ca_reject_warn_test.go): - with the switch off, failed handshakes during two of three test cases and one after the last give one WARN: 4, those two test cases, 1 after the last, its destination, and the docs. The recording is not failed; - none failed: nothing said; a start that cannot be read: nothing said, nothing read after; a read that fails: the next read counts its test cases, and it is no count of 0; an agent started again, during the recording or before the final read: counted whole; - around the stop, with a reader that ends with its context as the agent client's does: a failure in a test case the drain saves, and two after the last, are said (compose's order); in the native and docker order, the test case the drain saves after the final read is named, and nothing is after the last; one whose read never came is named as not checked, and what the final read saw beyond is said to be in it or after the last (and it is not named when the final read saw nothing beyond); a stop before capture began: no watch; a base read the agent never answers is given up on its stall; - the drain: with the final read out (never answered) in the native order, the ask returns at once, a press while the drain saves answers no offer, and the drain saves all 50 mocks the agent held; the stop's wait for the read after the drains says it waits and stands no offer either. Against the previous version of this change, the same test saved 0 of 50, 3 runs of 3; finish, after every drain, offers one more Ctrl+C, which ends it and the read, and withdraws the offer as it ends; - a press at finish's offer while a test case's read is out: it is named not checked, not dropped, also when nothing was counted; the stop's wait after the frame drains stands no offer, says Ctrl+C does not cut it short, and no interrupt does (the read ends on its own bound); with the final read failed, unread test cases are named not checked beside those counted, and with nothing counted they are named all the same; - a read the agent never answers: the ask returns at once, wall time that keploy could not run gives nothing up, and keploy's own HangBudget does, the test case then counted by the next read; a press that answers a drain's offer (utils.StopNow) ends a read at once; a read that does not end with its context is given up all the same, and its later answer not counted; - reads asked while one is out: made after it, in order, the final one not asked until then; a lagging read names every test case it counts; - no goroutine of the watch's outlives its reads (20 recordings); an ask after finish reads nothing; - abandoned handshakes: nothing said; the fields: a test case's destination, no afterTheLastTestCase with none after, and with every failure after the last, no test cases named and "record again"; - with the switch on, the WARN is not said, and the failed handshake fails the recording as before. TestTheCaptureWatchIsOffWithoutTheSwitchOrACount now expects the switch-off watch to read the count for this WARN and to say nothing of other losses. Of 32 compile-safe mutants, 31 fail a test; the one left drops the check in an ask after finish, which the read goroutine's own check makes redundant (it then ends without a read). The three calls in record.go that wait for the reads after the frame drains have no test of their own. The switch-on watch (captureWatch) has the same unbounded reads: its base and final reads with no offer standing, and its test cases' reads with no escape at all. That is left to its own change, before the switch flips. Signed-off-by: slayerjain <shubhamkjain@outlook.com>
slayerjain
added a commit
to keploy/keploy
that referenced
this pull request
Oct 19, 2026
…e switch off A client that does not trust keploy's CA rejects the certificate keploy's proxy answers its TLS handshake with. Examples are a client that pins its own CA file (Python requests with verify=<file>, a Go client with its own RootCAs) and a library that reads only the OS trust store. Its call fails, and keploy neither records nor can replay it. With the proven switch on, such a handshake (tls_handshake_failed) fails the recording. With it off, keploy said nothing. The recording ended green, its test cases held the app's error response for those calls, and a replay of them passed by replaying that error: a silent false pass. With the switch off, keploy record now says so once, at WARN, when the recording ends: N TLS handshake(s) with keploy's proxy failed while this recording ran (a client that does not trust keploy's CA rejects keploy's certificate); those calls are not recorded It names the test cases recorded while those handshakes failed, how many failed after the last test case, and the last one's destination. Its next_step points at how a client that pins its own CA trusts keploy's, natively and in Docker (https://keploy.io/docs/running-keploy/docker-tls/ #a-client-that-pins-its-own-ca, added by keploy/docs#931). The agent already counts these handshakes with the switch off. The watch the record path already drives (caRejectWatch, in captureWatch) now reads that count: - as capture begins; - as each test case is saved (a handshake's failure is the test case's it was made in, models.PerTest); - once more after the last. The base read is made as capture begins, on record's context, and waited for (bounded as below): a stop during it ends it, and the watch is then off for the recording. Every later read is asked for and not waited for: a test case's as the consumer saves it, and the final one at the three places the switch-on watch makes its own final read (once the app has stopped, but in a docker compose stop with the switch off, where the app still runs, once the drain is over). They are made on one goroutine of the watch's, one at a time and in the order asked, so an answer is never applied after a later one, and a read that lags counts every test case saved since the last together. Those reads are not ended by the stop, which ends record's context before the drain saves its last test cases and before the final read (but a compose agent that goes on its own has its drain and final read run with no stop at all); the interrupt that gave the stop's waits up (utils.StopNow, a drain's own offer answered) ends them. Every read is given up once keploy had stall.HangBudget of its own runnable time to run without an answer, so a stop no one presses Ctrl+C at (CI's pkill -INT) ends too, and a starved keploy is not taken for a silent agent. A read given up, or that failed, leaves its test cases to the next read; an answer that comes after is not counted. While a drain may still save what the agent held, the watch stands no offer of the stop's (utils.OfferStopNow): the final read is asked before the drain in a native or docker stop, and an offer it stood there would have the user's press give that drain up. Once the frame drains are over, the stop waits for the reads still out before it lets the agent go (after drainFrames natively, before compose takes the stack down, before the agent is told to go: an agent that goes as its streams close may be gone already, and its reads then fail), saying so at Info, with how long it can take. No interrupt ends that wait. It stands no offer, since a record drain may still select on utils.StopNow; and it hears no press of its own, since nothing keploy can see tells the user's Ctrl+C from the copy of the stop's own signal that sudo hands on: a signal a user process sends (CI's `sudo pkill -INT -f keploy`) reaches keploy directly and again through sudo, which relays it (sudo(8): SIGINT is relayed when sent by a user process, or under a new pty), Go's os/signal gives no signal's sender (and signalfd cannot hold SIGINT, which the runtime unblocks on every thread), and only time could tell them apart, which a loaded host does not keep. (An escape on a signal no stop sends, Ctrl+\, or the sender read off a kernel tracepoint, would tell them apart; neither is worth its cost for a diagnostic.) So its line says that Ctrl+C does not cut it short, and each read's bound ends it: up to HangBudget of runnable time for each read still out or asked while it waits. finish, after every drain, waits for any left, and there, once it has said so, one more Ctrl+C stops the wait now (a copy of the stop's signal taken for that press costs no more than the count, as every offer of the stop's must). A read a press ended, or one still out as finish ends, leaves its test cases not checked, and they are named at WARN even when nothing was counted: unknown is not none. A read that answered after the final read was asked, with nothing beyond the last counted, covers them (their calls came before the stop), and they are not named. What failed after the last test case is what the final read saw beyond the last read that counted test cases, when no such read came after it: in a native or docker stop the final read comes before the drain saves its last test cases, and a handshake that failed in one of those is that test case's, and named, once its read comes. A test case whose read never came (the agent went first, or the user stopped the wait) is named as not checked, and what the final read saw beyond the last counted read is said to be in it or after the last test case. In compose's order a read that failed leaves its test cases to the final read, which then names them for what failed after the last too: an extra test case to re-record, never one left out. A count lower than the last (an agent started again) is taken whole; one started again whose count has passed the last by the next read is not told from one that was not. It changes nothing else: no test case, verdict, status, exit code or hook differs, and with the switch on, captureWatch is as it was. It counts only failed handshakes. A client that hung up on its handshake (tls_handshake_abandoned) cannot be told from one that gave up, so that is left to the proven switch. A count it cannot read is left unsaid (Debug). Replicated in a lane container on 192.168.116.142 with keploy main, in compose. A Flask app calls an HTTPS upstream two ways: /pinned with verify=/certs/ca.pem (its own CA), and /env with REQUESTS_CA_BUNDLE, which keploy's injected trust covers. Calls made: /pinned, /env, /pinned. - Before: the record exits 0 with nothing said. The /pinned test cases hold the app's 500, and the app logged CERTIFICATE_VERIFY_FAILED. - After (run on this commit's code): the record still exits 0, and says once: "2 TLS handshake(s) with keploy's proxy failed while this recording ran (...); those calls are not recorded", testCases [get-pinned-1, get-pinned-2], last "to 172.19.0.2:8443", next_step the CA docs; get-env-1 is not named. - A pinned call the app makes after its last test case's response, before the stop (SIGINT): the WARN says 3, with afterTheLastTestCase 1. - Following the docs (the app's CA file combined with /tmp/keploy-tls/keploy-ca.crt at container start): both /pinned calls answer 200, are recorded, and nothing is said. - Native (the docs' native recipe's premise, not the WARN): SSL_CERT_FILE in the app's environment names a file holding keploy's per-run CA. Tests (pkg/service/record/ca_reject_warn_test.go): - with the switch off, failed handshakes during two of three test cases and one after the last give one WARN: 4, those two test cases, 1 after the last, its destination, and the docs. The recording is not failed; - none failed: nothing said; a start that cannot be read: nothing said, nothing read after; a read that fails: the next read counts its test cases, and it is no count of 0; an agent started again, during the recording or before the final read: counted whole; - around the stop, with a reader that ends with its context as the agent client's does: a failure in a test case the drain saves, and two after the last, are said (compose's order); in the native and docker order, the test case the drain saves after the final read is named, and nothing is after the last; one whose read never came is named as not checked, and what the final read saw beyond is said to be in it or after the last (and it is not named when the final read saw nothing beyond); a stop before capture began: no watch; a base read the agent never answers is given up on its stall; - the drain: with the final read out (never answered) in the native order, the ask returns at once, a press while the drain saves answers no offer, and the drain saves all 50 mocks the agent held; the stop's wait for the read after the drains says it waits and stands no offer either. Against the previous version of this change, the same test saved 0 of 50, 3 runs of 3; finish, after every drain, offers one more Ctrl+C, which ends it and the read, and withdraws the offer as it ends; - a press at finish's offer while a test case's read is out: it is named not checked, not dropped, also when nothing was counted; the stop's wait after the frame drains stands no offer, says Ctrl+C does not cut it short and how long it can take, and no interrupt does (it waits for the read, which ends on its own bound); with the final read failed, unread test cases are named not checked beside those counted, and with nothing counted they are named all the same; a read after the final one, which saw nothing more, covers a test case whose own read never came; - a read the agent never answers: the ask returns at once, wall time that keploy could not run gives nothing up, and keploy's own HangBudget does, the test case then counted by the next read; a press that answers a drain's offer (utils.StopNow) ends a read at once; a read that does not end with its context is given up all the same, and its later answer not counted; - reads asked while one is out: made after it, in order, the final one not asked until then; a lagging read names every test case it counts; - no goroutine of the watch's outlives its reads (20 recordings); an ask after finish reads nothing; - abandoned handshakes: nothing said; the fields: a test case's destination, no afterTheLastTestCase with none after, and with every failure after the last, no test cases named and "record again"; - with the switch on, the WARN is not said, and the failed handshake fails the recording as before. TestTheCaptureWatchIsOffWithoutTheSwitchOrACount now expects the switch-off watch to read the count for this WARN and to say nothing of other losses. Of 35 compile-safe mutants, 34 fail a test; the one left drops the check in an ask after finish, which the read goroutine's own check makes redundant (it then ends without a read). The three calls in record.go that wait for the reads after the frame drains have no test of their own. The switch-on watch (captureWatch) has the same unbounded reads: its base and final reads with no offer standing, and its test cases' reads with no escape at all. That is left to its own change, before the switch flips. Signed-off-by: slayerjain <shubhamkjain@outlook.com>
slayerjain
added a commit
to keploy/keploy
that referenced
this pull request
Oct 19, 2026
…e switch off A client that does not trust keploy's CA rejects the certificate keploy's proxy answers its TLS handshake with. Examples are a client that pins its own CA file (Python requests with verify=<file>, a Go client with its own RootCAs) and a library that reads only the OS trust store. Its call fails, and keploy neither records nor can replay it. With the proven switch on, such a handshake (tls_handshake_failed) fails the recording. With it off, keploy said nothing. The recording ended green, its test cases held the app's error response for those calls, and a replay of them passed by replaying that error: a silent false pass. With the switch off, keploy record now says so once, at WARN, when the recording ends: N TLS handshake(s) with keploy's proxy failed while this recording ran (a client that does not trust keploy's CA rejects keploy's certificate); those calls are not recorded It names the test cases recorded while those handshakes failed, how many failed after the last test case, and the last one's destination. Its next_step points at how a client that pins its own CA trusts keploy's, natively and in Docker (https://keploy.io/docs/running-keploy/docker-tls/ #a-client-that-pins-its-own-ca, added by keploy/docs#931). The agent already counts these handshakes with the switch off. The watch the record path already drives (caRejectWatch, in captureWatch) now reads that count: - as capture begins; - as each test case is saved (a handshake's failure is the test case's it was made in, models.PerTest); - once more after the last. The base read is made as capture begins, on record's context, and waited for (bounded as below): a stop during it ends it, and the watch is then off for the recording. Every later read is asked for and not waited for: a test case's as the consumer saves it, and the final one at the three places the switch-on watch makes its own final read (once the app has stopped, but in a docker compose stop with the switch off, where the app still runs, once the drain is over). They are made on one goroutine of the watch's, one at a time and in the order asked, so an answer is never applied after a later one, and a read that lags counts every test case saved since the last together. Those reads are not ended by the stop, which ends record's context before the drain saves its last test cases and before the final read (but a compose agent that goes on its own has its drain and final read run with no stop at all); the interrupt that gave the stop's waits up (utils.StopNow, a drain's own offer answered) ends them. Every read is given up once keploy had stall.HangBudget of its own runnable time to run without an answer, so a stop no one presses Ctrl+C at (CI's pkill -INT) ends too, and a starved keploy is not taken for a silent agent. A read given up, or that failed, leaves its test cases to the next read; an answer that comes after is not counted. While a drain may still save what the agent held, the watch stands no offer of the stop's (utils.OfferStopNow): the final read is asked before the drain in a native or docker stop, and an offer it stood there would have the user's press give that drain up. Once the frame drains are over, the stop waits for the reads still out before it lets the agent go (after drainFrames natively, before compose takes the stack down, before the agent is told to go: an agent that goes as its streams close may be gone already, and its reads then fail), saying so at Info, with each read's bound. No interrupt ends that wait. It stands no offer, since a record drain may still select on utils.StopNow; and it hears no press of its own, since nothing keploy can see tells the user's Ctrl+C from the copy of the stop's own signal that sudo hands on: a signal a user process sends (CI's `sudo pkill -INT -f keploy`) reaches keploy directly and again through sudo, which relays it (sudo(8): SIGINT is relayed when sent by a user process, or under a new pty), Go's os/signal gives no signal's sender (and signalfd cannot hold SIGINT, which the runtime unblocks on every thread), and only time could tell them apart, which a loaded host does not keep. (An escape on a signal no stop sends, Ctrl+\, or the sender read off a kernel tracepoint, would tell them apart; neither is worth its cost for a diagnostic.) So its line says that Ctrl+C does not cut it short, and each read's bound ends it: up to HangBudget of runnable time for each read still out or asked while it waits. finish, after every drain, waits for any left, and there, once it has said so, one more Ctrl+C stops the wait now (a copy of the stop's signal taken for that press costs no more than the count, as every offer of the stop's must). A read a press ended, or one still out as finish ends, leaves its test cases not checked, and they are named at WARN even when nothing was counted: unknown is not none. A read made after the final read was asked (taken after it, not merely answered after it), with nothing beyond the last counted, covers them (their calls came before the stop), and they are not named. What failed after the last test case is what the final read saw beyond the last read that counted test cases, when no such read came after it: in a native or docker stop the final read comes before the drain saves its last test cases, and a handshake that failed in one of those is that test case's, and named, once its read comes. A test case whose read never came (the agent went first, or the user stopped the wait) is named as not checked, and what the final read saw beyond the last counted read is said to be in it or after the last test case. In compose's order a read that failed leaves its test cases to the final read, which then names them for what failed after the last too: an extra test case to re-record, never one left out. A count lower than the last (an agent started again) is taken whole; one started again whose count has passed the last by the next read is not told from one that was not. It changes nothing else: no test case, verdict, status, exit code or hook differs, and with the switch on, captureWatch is as it was. It counts only failed handshakes. A client that hung up on its handshake (tls_handshake_abandoned) cannot be told from one that gave up, so that is left to the proven switch. A count it cannot read is left unsaid (Debug). Replicated in a lane container on 192.168.116.142 with keploy main, in compose. A Flask app calls an HTTPS upstream two ways: /pinned with verify=/certs/ca.pem (its own CA), and /env with REQUESTS_CA_BUNDLE, which keploy's injected trust covers. Calls made: /pinned, /env, /pinned. - Before: the record exits 0 with nothing said. The /pinned test cases hold the app's 500, and the app logged CERTIFICATE_VERIFY_FAILED. - After (run on this commit's code): the record still exits 0, and says once: "2 TLS handshake(s) with keploy's proxy failed while this recording ran (...); those calls are not recorded", testCases [get-pinned-1, get-pinned-2], last "to 172.19.0.2:8443", next_step the CA docs; get-env-1 is not named. - A pinned call the app makes after its last test case's response, before the stop (SIGINT): the WARN says 3, with afterTheLastTestCase 1. - Following the docs (the app's CA file combined with /tmp/keploy-tls/keploy-ca.crt at container start): both /pinned calls answer 200, are recorded, and nothing is said. - Native (the docs' native recipe's premise, not the WARN): SSL_CERT_FILE in the app's environment names a file holding keploy's per-run CA. Tests (pkg/service/record/ca_reject_warn_test.go): - with the switch off, failed handshakes during two of three test cases and one after the last give one WARN: 4, those two test cases, 1 after the last, its destination, and the docs. The recording is not failed; - none failed: nothing said; a start that cannot be read: nothing said, nothing read after; a read that fails: the next read counts its test cases, and it is no count of 0; an agent started again, during the recording or before the final read: counted whole; - around the stop, with a reader that ends with its context as the agent client's does: a failure in a test case the drain saves, and two after the last, are said (compose's order); in the native and docker order, the test case the drain saves after the final read is named, and nothing is after the last; one whose read never came is named as not checked, and what the final read saw beyond is said to be in it or after the last (and it is not named when the final read saw nothing beyond); a stop before capture began: no watch; a base read the agent never answers is given up on its stall; - the drain: with the final read out (never answered) in the native order, the ask returns at once, a press while the drain saves answers no offer, and the drain saves all 50 mocks the agent held; the stop's wait for the read after the drains says it waits and stands no offer either. Against the previous version of this change, the same test saved 0 of 50, 3 runs of 3; finish, after every drain, offers one more Ctrl+C, which ends it and the read, and withdraws the offer as it ends; - a press at finish's offer while a test case's read is out: it is named not checked, not dropped, also when nothing was counted; the stop's wait after the frame drains stands no offer, says Ctrl+C does not cut it short and each read's bound, and no interrupt does (it waits for the read, which ends on its own bound); with the final read failed, unread test cases are named not checked beside those counted, and with nothing counted they are named all the same; a read made after the final one, which saw nothing more, covers a test case whose own read never came, and one taken before it, answered after, covers nothing; - a read the agent never answers: the ask returns at once, wall time that keploy could not run gives nothing up, and keploy's own HangBudget does, the test case then counted by the next read; a press that answers a drain's offer (utils.StopNow) ends a read at once; a read that does not end with its context is given up all the same, and its later answer not counted; - reads asked while one is out: made after it, in order, the final one not asked until then; a lagging read names every test case it counts; - no goroutine of the watch's outlives its reads (20 recordings); an ask after finish reads nothing; - abandoned handshakes: nothing said; the fields: a test case's destination, no afterTheLastTestCase with none after, and with every failure after the last, no test cases named and "record again"; - with the switch on, the WARN is not said, and the failed handshake fails the recording as before. TestTheCaptureWatchIsOffWithoutTheSwitchOrACount now expects the switch-off watch to read the count for this WARN and to say nothing of other losses. Of 36 compile-safe mutants, 35 fail a test; the one left drops the check in an ask after finish, which the read goroutine's own check makes redundant (it then ends without a read). The three calls in record.go that wait for the reads after the frame drains have no test of their own. The switch-on watch (captureWatch) has the same unbounded reads: its base and final reads with no offer standing, and its test cases' reads with no escape at all. That is left to its own change, before the switch flips. Signed-off-by: slayerjain <shubhamkjain@outlook.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What has changed?
versioned_docs/version-4.0.0/running-keploy/docker-tls.md). It covers clients that trust only a CA file they name themselves, such as Pythonrequestswithverify=<file>or a Go client with its ownRootCAs.keploy recordnow gives when such a client rejects Keploy's certificate./tmp/keploy-tls/keploy-ca.crt, and natively from the fileSSL_CERT_FILEnames.next_steplinks to this section (fix(record): say when a client rejected keploy's certificate, with the switch off keploy#4853). Until now the page covered only automatic trust injection and libraries that read the OS trust store.Type of change
How Has This Been Tested?
SSL_CERT_FILEnames a file holding one certificate, "Keploy MITM CA".Checklist: