-
Notifications
You must be signed in to change notification settings - Fork 73
starknet_transaction_prover: add TLS integration tests #14050
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: avi/privacy/config-validation-tests-v2
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # Test TLS Material | ||
|
|
||
| **This directory contains a self-signed certificate and its private key used | ||
| exclusively by the unit tests in `src/server/tls_test.rs`.** | ||
|
|
||
| The key is intentionally checked into the repository — it is a test fixture, | ||
| not a secret. Do not reuse this material outside of test code. | ||
|
|
||
| ## Properties | ||
|
|
||
| - Subject: `CN=localhost` | ||
| - SAN: `DNS:localhost,IP:127.0.0.1` | ||
| - Validity: 100 years from generation | ||
| - Key: 2048-bit RSA, unencrypted | ||
|
|
||
| ## Regenerating | ||
|
|
||
| ```bash | ||
| openssl req -x509 -newkey rsa:2048 \ | ||
| -keyout crates/starknet_transaction_prover/resources/test_tls/key.pem \ | ||
| -out crates/starknet_transaction_prover/resources/test_tls/cert.pem \ | ||
| -sha256 -days 36500 -nodes \ | ||
| -subj "/CN=localhost" \ | ||
| -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| -----BEGIN CERTIFICATE----- | ||
| MIIDJzCCAg+gAwIBAgIUCfCD8/3lfYaThN2hDz8c4CIbTDowDQYJKoZIhvcNAQEL | ||
| BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTI2MDUxNzE1Mjk0N1oYDzIxMjYw | ||
| NDIzMTUyOTQ3WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB | ||
| AQUAA4IBDwAwggEKAoIBAQCcDEcAhUbdyBnUkIGykVCvNtXVg+sHYlvTTYnpasxM | ||
| iUyY9jyoLYJlBPZjmNPipDd67REL2fGa7q3hkkkHAy4BxdYIqE2l9fPkX2unY/nS | ||
| OWDemwPgOXEorcDWJC/kIVwNtVdqfLKG22d88QUvMe4rqUCA6J32dQv1/UAQ9OKw | ||
| 9kVQ3NAwGTMG2e61A3Ueur0DBmtap5YSn7IlT3HKQXSkTX08V7MCf8W9N3/Bg01h | ||
| a7yAtNiQX66Gs4y/8CsM7eTBnLt4e0MVyhSJ9Zj2Ibpatr/YyWAhaW8p7y4sGo50 | ||
| 3ovQ6isrOO8ayi6d7fYVCI27NDoiSmJ67okfQk0rf3DJAgMBAAGjbzBtMB0GA1Ud | ||
| DgQWBBQdz7tV14UJxD6RchjKEDz61wgN/zAfBgNVHSMEGDAWgBQdz7tV14UJxD6R | ||
| chjKEDz61wgN/zAPBgNVHRMBAf8EBTADAQH/MBoGA1UdEQQTMBGCCWxvY2FsaG9z | ||
| dIcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAIiAb1/7gA/NXMck/k3WGnYCp3Aut | ||
| rYDbfq1fwG/GJZ572qd9XREtuC198QPpQ04yjv7v2sspeWFqAS8e+Gr67h1cQ7q/ | ||
| mEnGPXQBKQ9r4TSamsFHnrh5x/J9Ec/hBXU9xd8OemZ+o00Itxn1FWwDBvudzfOA | ||
| 1IJ/7RNxmhUK2/dOOS9Jo5zGhRX/f6s8qmW6ZX2dRpvio3YqV30LpVSBZMsfQiWv | ||
| dRHcl5xVoxxtvSkKt1Ou8VE2SEl61c7+Gb3zPBxOdT59QDFGZvX9PC8fPsOq2dNh | ||
| ZhYJ4UJfWP5lMa372GATdPjVlZSf575xDpagUgSEKxEyCd7XC2k/p00u+w== | ||
| -----END CERTIFICATE----- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| -----BEGIN PRIVATE KEY----- | ||
| MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCcDEcAhUbdyBnU | ||
| kIGykVCvNtXVg+sHYlvTTYnpasxMiUyY9jyoLYJlBPZjmNPipDd67REL2fGa7q3h | ||
| kkkHAy4BxdYIqE2l9fPkX2unY/nSOWDemwPgOXEorcDWJC/kIVwNtVdqfLKG22d8 | ||
| 8QUvMe4rqUCA6J32dQv1/UAQ9OKw9kVQ3NAwGTMG2e61A3Ueur0DBmtap5YSn7Il | ||
| T3HKQXSkTX08V7MCf8W9N3/Bg01ha7yAtNiQX66Gs4y/8CsM7eTBnLt4e0MVyhSJ | ||
| 9Zj2Ibpatr/YyWAhaW8p7y4sGo503ovQ6isrOO8ayi6d7fYVCI27NDoiSmJ67okf | ||
| Qk0rf3DJAgMBAAECggEAQmpDSehvifMhc0Pxv4NzmK85AX/85w6o0F0fBlZrD2Qc | ||
| UrnyhQ2hgsdC6o7gF4UXC92cNLQUzYEqRmhRZoem7CA8gUDIk4sDu74U/pBhgmTj | ||
| YrsNQkCQdeTFvx51t52vJTJ6OxtJjHYTLK0ULMsOeEy35GWc3Ylhhte7jbv8Q55S | ||
| wSwmCqxnEj6+5HlAeOIC2LJnrerDEejlTpXH1HCEsTH0dd4EQ/sHixzNVt2MSHDU | ||
| fjhsmTl6kTO+RcIPoohuUSMrtrN9j/T4GxcrZqqwdzws/KMg1GYWvRxBJQHuO1yl | ||
| 5ivhA4sjE8cmN2SbcgrYa3R7aK3XzrCmxx4DKHNYlQKBgQDWeS4BIVEIKwzjjQOC | ||
| RPhPg4Zo+0xYzceq4Q7ERn6mBojsLxNF91Z0Yx32rDpQziV1FESe0xmWneRCIjP8 | ||
| Ua31MU5FeH1GI7q0RyWD7XoUTI8io8cFdMiQEbRrYqARVrHun6NpBHIUG5Z5az8L | ||
| JWRP/P0QN90cgkgLnqwxFicHywKBgQC6Qx7ej5cPBBf/m8Aijmd8cUDqrmk6A4Zc | ||
| df8IjsfMdkv7H29qBip4KgNuThREaTq5fuCqgKvVKUgmudEFousfuWjzJsICBE9h | ||
| 4DGFDUxPBYyUFf70PmlQ8e4avvNg1Cx5VgIt4M2IAsUmiAC/52y14R67u7MfQP7q | ||
| UWU3YitPOwKBgQCkq/A9n+YGnn9L68aI7Am3i2XVDzXEbWNj+V8MJpAxS40vwslK | ||
| jCjOPhgQgJZZ2p358fDp/W2FLn/Go1pE3jXxr8TIJEYTZ3V/26ybSefU1B+GWjeC | ||
| IfOoYl+jn9sE1QrTC7E8/dPVSoVTfpuuJCyMGdP38tyLeiB1A4R0P+0B1wKBgAtZ | ||
| 79Wsdo5Jt5SyT0FL4G6rEEO9IViRwmx8HHDPEsoZI4RIZCfX/FqaZN8iDwYkS5nm | ||
| a5a4hMBW5bjGdkCbryydxhGbeRNaY+QZH6t2JgJi2jBkLsd/zjdKpzImFPr/sz4p | ||
| ybQ2ERCK6qzweOs5FVz4PUE/rSjocyCgmUSIzQ7lAoGAE+Vc2EeHPxFRZgVSFS6m | ||
| SEl5p5h8Wfr39+HKBSVd1P7QMHAFN11yXrGhIrRnAkI37chSvNtwLbTLicHuY127 | ||
| zEVAVXATvTZosErLp8WuNCxnb/1PxBVv1RMxJHm0ibjfRuWpDF+Gstn6ESQYKyPU | ||
| Z84XK248kL9fShkmRNRujGI= | ||
| -----END PRIVATE KEY----- | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| //! Integration tests for the TLS server bootstrap. | ||
| //! | ||
| //! Uses a self-signed certificate checked into `resources/test_tls/` (CN=localhost, valid for | ||
| //! 100 years). See `resources/test_tls/README.md` for the openssl regeneration command. | ||
|
|
||
| use std::io::Write; | ||
| use std::net::SocketAddr; | ||
| use std::path::{Path, PathBuf}; | ||
|
|
||
| use rstest::rstest; | ||
| use serde_json::Value; | ||
| use tempfile::NamedTempFile; | ||
|
|
||
| use crate::server::mock_rpc::MockProvingRpc; | ||
| use crate::server::rpc_api::ProvingRpcServer; | ||
| use crate::server::rpc_impl::SPEC_VERSION; | ||
| use crate::server::tls::{load_tls_acceptor, start_tls_server}; | ||
|
|
||
| fn ensure_crypto_provider() { | ||
| let _ = tokio_rustls::rustls::crypto::aws_lc_rs::default_provider().install_default(); | ||
| } | ||
|
|
||
| fn test_cert_path() -> PathBuf { | ||
| Path::new(env!("CARGO_MANIFEST_DIR")).join("resources/test_tls/cert.pem") | ||
| } | ||
|
|
||
| fn test_key_path() -> PathBuf { | ||
| Path::new(env!("CARGO_MANIFEST_DIR")).join("resources/test_tls/key.pem") | ||
| } | ||
|
|
||
| fn write_pem_to_tempfile(pem_bytes: &[u8]) -> NamedTempFile { | ||
| let mut file = NamedTempFile::new().unwrap(); | ||
| file.write_all(pem_bytes).unwrap(); | ||
| file.flush().unwrap(); | ||
| file | ||
| } | ||
|
|
||
| fn spec_version_request() -> Value { | ||
| serde_json::json!({ | ||
| "jsonrpc": "2.0", | ||
| "id": "1", | ||
| "method": "starknet_specVersion" | ||
| }) | ||
| } | ||
|
|
||
| async fn start_test_tls_server() -> (SocketAddr, jsonrpsee::server::ServerHandle, Vec<u8>) { | ||
| let methods = MockProvingRpc::from_expected_json().into_rpc(); | ||
| let addr: SocketAddr = "127.0.0.1:0".parse().unwrap(); | ||
|
|
||
| let (local_addr, handle) = start_tls_server( | ||
| addr, | ||
| &test_cert_path(), | ||
| &test_key_path(), | ||
| methods, | ||
| 10, // max_connections | ||
| 5 * 1024 * 1024, // max_request_body_size | ||
| None, // cors_layer | ||
| None, // ohttp_layer | ||
| ) | ||
| .await | ||
| .expect("Failed to start TLS server"); | ||
|
|
||
| let cert_pem = std::fs::read(test_cert_path()).unwrap(); | ||
| (local_addr, handle, cert_pem) | ||
| } | ||
|
|
||
| #[tokio::test] | ||
| async fn test_https_spec_version_succeeds() { | ||
| ensure_crypto_provider(); | ||
| let (addr, handle, cert_pem) = start_test_tls_server().await; | ||
|
|
||
| let cert = reqwest::tls::Certificate::from_pem(&cert_pem).unwrap(); | ||
| let client = reqwest::Client::builder().add_root_certificate(cert).build().unwrap(); | ||
|
|
||
| let response = client | ||
| .post(format!("https://localhost:{}", addr.port())) | ||
| .json(&spec_version_request()) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Client URL mismatches bind addressMedium Severity The TLS server is bound to Additional Locations (1)Reviewed by Cursor Bugbot for commit 02903ed. Configure here. |
||
| .send() | ||
| .await | ||
| .expect("HTTPS request failed"); | ||
|
|
||
| assert_eq!(response.status(), 200); | ||
| let json: Value = response.json().await.unwrap(); | ||
| assert_eq!(json["result"].as_str().unwrap(), SPEC_VERSION); | ||
|
|
||
| handle.stop().unwrap(); | ||
| } | ||
|
|
||
| #[tokio::test] | ||
| async fn test_http_to_tls_server_fails() { | ||
| ensure_crypto_provider(); | ||
| let (addr, handle, _cert_pem) = start_test_tls_server().await; | ||
|
|
||
| // Plain HTTP to a TLS server should fail (connection or protocol error). | ||
| let result = reqwest::Client::new() | ||
| .post(format!("http://localhost:{}", addr.port())) | ||
| .json(&spec_version_request()) | ||
| .send() | ||
| .await; | ||
| assert!(result.is_err(), "Expected HTTP to TLS server to fail, got: {result:?}"); | ||
|
|
||
| handle.stop().unwrap(); | ||
| } | ||
|
cursor[bot] marked this conversation as resolved.
|
||
|
|
||
| /// How a given path argument is materialised for `load_tls_acceptor`. | ||
| enum PathMode { | ||
| /// Use the checked-in valid test fixture. | ||
| Valid, | ||
| /// Path to a file that does not exist. | ||
| Missing, | ||
| /// Path to a tempfile containing these bytes (returned alongside the path so the | ||
| /// `NamedTempFile` is kept alive for the call). | ||
| Junk(&'static [u8]), | ||
| } | ||
|
|
||
| /// `PathMode::Junk` returns `Some(tempfile)` so the tempfile is dropped after the test, not before. | ||
| fn materialise(mode: PathMode, missing: &str, valid: PathBuf) -> (PathBuf, Option<NamedTempFile>) { | ||
| match mode { | ||
| PathMode::Valid => (valid, None), | ||
| PathMode::Missing => (missing.into(), None), | ||
| PathMode::Junk(bytes) => { | ||
| let file = write_pem_to_tempfile(bytes); | ||
| (file.path().into(), Some(file)) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Each case isolates one specific failure path by holding the other input valid, so a green test | ||
| /// proves `load_tls_acceptor` actually rejected on the named reason and not on something earlier. | ||
| #[rstest] | ||
| #[case::missing_cert(PathMode::Missing, PathMode::Valid)] | ||
| #[case::missing_key(PathMode::Valid, PathMode::Missing)] | ||
| #[case::invalid_cert_pem(PathMode::Junk(b"not a valid PEM cert"), PathMode::Valid)] | ||
| #[case::invalid_key_pem(PathMode::Valid, PathMode::Junk(b"not a valid PEM key"))] | ||
| fn test_load_tls_acceptor_failure(#[case] cert: PathMode, #[case] key: PathMode) { | ||
| let (cert_path, _cert_tmp) = materialise(cert, "/nonexistent/cert.pem", test_cert_path()); | ||
| let (key_path, _key_tmp) = materialise(key, "/nonexistent/key.pem", test_key_path()); | ||
|
|
||
| assert!(load_tls_acceptor(&cert_path, &key_path).is_err()); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_load_tls_acceptor_succeeds_for_valid_files() { | ||
| // `load_tls_acceptor` builds a rustls `ServerConfig`, which requires a process-level crypto | ||
| // provider. nextest runs each test in a fresh process, so install the provider here. | ||
| ensure_crypto_provider(); | ||
| load_tls_acceptor(&test_cert_path(), &test_key_path()).unwrap(); | ||
| } | ||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Semgrep identified an issue in your code:
Hard-coded private key in source code allows attackers who gain repository access to impersonate your service or decrypt sensitive data.
More details about this
This code contains a hard-coded private key embedded directly in your source code. An attacker who gains access to your repository—whether through a compromised developer account, leaked source code, or cloned Git history—would immediately obtain this private key.
Here's a concrete attack scenario:
Attacker gains repository access: A developer's GitHub account is compromised, or the repo is accidentally made public, exposing the code containing the
-----BEGIN PRIVATE KEY-----block.Attacker extracts the key: The attacker copies the entire private key (the base64-encoded
$KEYcontent between the BEGIN/END markers).Attacker impersonates your service: Using this private key, the attacker can:
Lateral movement: If this key is used to authenticate to cloud services, databases, or internal APIs, the attacker now has a foothold into your infrastructure.
The danger is that this exposure is permanent—even if you delete the key from your repo now, it remains in Git history and anyone with repository access can retrieve it.
To resolve this comment:
✨ Commit fix suggestion
-----BEGIN PRIVATE KEY-----to-----END PRIVATE KEY-----.fs.readFileSync('/path/to/private.key')in Node.js, or reference an environment variable that points to the file path.*.keyor the specific key file) to your.gitignorefile to prevent accidental commits in the future.💬 Ignore this finding
Reply with Semgrep commands to ignore this finding.
/fp <comment>for false positive/ar <comment>for acceptable risk/other <comment>for all other reasonsAlternatively, triage in Semgrep AppSec Platform to ignore the finding created by detected-private-key.
You can view more details about this finding in the Semgrep AppSec Platform.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/fp Test fixture only. Cert subject is
CN=localhost(SAN:DNS:localhost,IP:127.0.0.1); used exclusively bysrc/server/tls_test.rsto exercisestart_tls_serverandload_tls_acceptor. Provenance and regeneration command documented inresources/test_tls/README.md. The key is not referenced from any production code path.