From 3b738c949475ec0b801ed0ec51f51630314eea79 Mon Sep 17 00:00:00 2001 From: Piotr Roslaniec Date: Thu, 13 Mar 2025 16:04:35 +0100 Subject: [PATCH 1/4] fix: fix broken fixtures --- fixture/client.html.tee.json | 84 +++++++++++++++++ fixture/client.html.tee_tcp_local.json | 92 ------------------- ...ient.proxy.json => client.json.proxy.json} | 88 +++++++----------- notary/src/proxy.rs | 28 ++++-- tests/src/lib.rs | 2 +- 5 files changed, 138 insertions(+), 156 deletions(-) create mode 100644 fixture/client.html.tee.json delete mode 100644 fixture/client.html.tee_tcp_local.json rename fixture/{client.proxy.json => client.json.proxy.json} (54%) diff --git a/fixture/client.html.tee.json b/fixture/client.html.tee.json new file mode 100644 index 000000000..29f9e0118 --- /dev/null +++ b/fixture/client.html.tee.json @@ -0,0 +1,84 @@ +{ + "mode": "TEE", + "notary_host": "localhost", + "notary_port": 7443, + "notary_ca_cert": "MIIFszCCA5ugAwIBAgIUeXLQmnjeXsHpGji7xA8oJjjw7WwwDQYJKoZIhvcNAQELBQAwaTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCVBhbG8gQWx0bzEVMBMGA1UECgwMT3JnYW5pemF0aW9uMRowGAYDVQQDDBFMb2NhbGhvc3QgUm9vdCBDQTAeFw0yNDA2MDcyMjUyNDBaFw0yOTA2MDYyMjUyNDBaMGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlQYWxvIEFsdG8xFTATBgNVBAoMDE9yZ2FuaXphdGlvbjEaMBgGA1UEAwwRTG9jYWxob3N0IFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDIHMEL9gVSxT/J0qS4xDkDZs1d1UG0+z6NFLLsGdV7gu0ZJbDPlNd0kpjWsisVNB7TcqWoq5ROK5CR+6lZxXC8nbqr2YAJ2O8mHIXcYv7msAN3UYxtM6v1M7K+vNMJdDjZVAxcOKq5R7uUDUPw1weePz6eVEjntAW8mUjqkfnCqYml943Ud3724SkI5wyUT9rKS3bk6hvneq1ah/b1zRGDF2gp+T/oNe4ieS/LGoIUluE2csGRXtt542gpJnw5L54JASmGgt6hunUSWtoaht7Qxv6hYpieu4iHqZY1kfcFDjDH2WI16g1YqrWHzk1l7vWNLVDEcK3kdSQ1GmYAij8ZjAi0LJizLwtN//EkfxiOPlV435itK3uugY+etxrk77BeA6PmVcpZeLLXYuKSrzfaBh0ifP2p0uRlShURi5Rz4IE0I7wHkZ44x9MKYv8YzXK7O29HD158tgorxqwwKmkHqSxWpp7SRKvNnMulHN/el+IKDrPeBhVXsSSkd6U+/H61q7i0SY9TqqhdiMQLW/efK9LkVRen5myhwqogwiF/42Jp2nrCeuzv5YDsAFSrQ0lukW+Hz7FXV+0axnKeXZ08Nd+IS1BhGyMgHo6PWMP1fWyfO0DJVUfIqrHqvBy8bW0yNOuhiyU2oeyDRKv75OMxpIrUeX3qvmrVcYUPvfXsVQIDAQABo1MwUTAdBgNVHQ4EFgQUlro6UuKRY+lHZ3T4FQMhoQAJ2a8wHwYDVR0jBBgwFoAUlro6UuKRY+lHZ3T4FQMhoQAJ2a8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEARliSCLdjNI5fFkNwXDK6k6jN5hITrY07XIawUIEwinjQqgLkYFvzXbMtfLwsWmxMPjDVYYDa5Y2NAGcH08b//2z9EuHxMOTOFTKr59BEcVxV1cxV+lspAunH8DLSlLJhf/EeR+MhIIHAfhlE8V7lvlE1EbM+Uj5JYIeefV/4omsGrphyHD3oSJAQDae0su200I/i2yAaTrwXLZ4HtaXsnxKZ4PMPFWaLvMQ8DsLgx2VB3/vQJn74Xepau6mYEWlRnUu90mj79gJOnwBKPlLojF6dJOMIJ2YHr9fI8sUfkVwPFVlkDKJcr0ll5RL3O/naNlLQZuOgijOM5YF5iTrefliVodEHpBPID2mhtq/E+ZIQWLpik8ulsJ8ufN9YfrbjbsiC/KeoMqoFCImRSyMGQDMADo4EV3DNfDFvfrHx0qBMmJ0nkhuGobphegMPCjZ3axvQwQulKuHXmFpAvGYcpK/twBMC1MJkV04tIwVEDZG6id5oKYtrIXHdSFshf6r3z4bbgq6kJnOxZ8Vo4cEw/dgc3hRivr+HnxOJcEk2CTQlCVOiCQAg64OqDEOoswVg6nzoO3RJhFatu+abO22MIXPNGma02zBoQZLYpGzL9z6pMnPKjL15G9H1SYVSTGhmq+GVtdRibg8rLBciSm3ERd7gNRqvYP5GrjCtUIbOTEc=", + "target_method": "GET", + "target_url": "https://en.wikipedia.org/wiki/Claude_Shannon", + "target_headers": {}, + "target_body": "", + "max_sent_data": 10000, + "max_recv_data": 10000, + "manifest": { + "manifestVersion": "1", + "id": "wikipedia-claude-shannon", + "title": "Wikipedia Claude Shannon", + "description": "Generate a proof that you have visited the Claude Shannon Wikipedia page", + "prepareUrl": "https://en.wikipedia.org/wiki/Claude_Shannon", + "request": { + "method": "GET", + "version": "HTTP/1.1", + "url": "https://en.wikipedia.org/wiki/Claude_Shannon", + "headers": {} + }, + "response": { + "status": "200", + "version": "HTTP/1.1", + "message": "OK", + "headers": { + "Content-Type": "text/html; charset=UTF-8" + }, + "body": { + "format": "html", + "extractors": [ + { + "id": "pageTitle", + "description": "Extract the page title", + "selector": [ + "title" + ], + "type": "string", + "predicates": [ + { + "type": "value", + "comparison": "contains", + "value": "Claude Shannon" + } + ] + }, + { + "id": "roles", + "description": "Extract his professional roles", + "selector": [ + "div#mw-content-text", + "div.mw-parser-output", + "p", + "a" + ], + "type": "array", + "predicates": [ + { + "type": "value", + "comparison": "contains", + "value": "mathematician", + "case_sensitive": false + }, + { + "type": "value", + "comparison": "contains", + "value": "electrical engineer", + "case_sensitive": false + }, + { + "type": "value", + "comparison": "contains", + "value": "cryptographer", + "case_sensitive": false + } + ] + } + ] + } + } + } +} \ No newline at end of file diff --git a/fixture/client.html.tee_tcp_local.json b/fixture/client.html.tee_tcp_local.json deleted file mode 100644 index 41555a9da..000000000 --- a/fixture/client.html.tee_tcp_local.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "mode": "TEE", - "notary_host": "localhost", - "notary_port": 7443, - "notary_ca_cert": "MIIFszCCA5ugAwIBAgIUeXLQmnjeXsHpGji7xA8oJjjw7WwwDQYJKoZIhvcNAQELBQAwaTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCVBhbG8gQWx0bzEVMBMGA1UECgwMT3JnYW5pemF0aW9uMRowGAYDVQQDDBFMb2NhbGhvc3QgUm9vdCBDQTAeFw0yNDA2MDcyMjUyNDBaFw0yOTA2MDYyMjUyNDBaMGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlQYWxvIEFsdG8xFTATBgNVBAoMDE9yZ2FuaXphdGlvbjEaMBgGA1UEAwwRTG9jYWxob3N0IFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDIHMEL9gVSxT/J0qS4xDkDZs1d1UG0+z6NFLLsGdV7gu0ZJbDPlNd0kpjWsisVNB7TcqWoq5ROK5CR+6lZxXC8nbqr2YAJ2O8mHIXcYv7msAN3UYxtM6v1M7K+vNMJdDjZVAxcOKq5R7uUDUPw1weePz6eVEjntAW8mUjqkfnCqYml943Ud3724SkI5wyUT9rKS3bk6hvneq1ah/b1zRGDF2gp+T/oNe4ieS/LGoIUluE2csGRXtt542gpJnw5L54JASmGgt6hunUSWtoaht7Qxv6hYpieu4iHqZY1kfcFDjDH2WI16g1YqrWHzk1l7vWNLVDEcK3kdSQ1GmYAij8ZjAi0LJizLwtN//EkfxiOPlV435itK3uugY+etxrk77BeA6PmVcpZeLLXYuKSrzfaBh0ifP2p0uRlShURi5Rz4IE0I7wHkZ44x9MKYv8YzXK7O29HD158tgorxqwwKmkHqSxWpp7SRKvNnMulHN/el+IKDrPeBhVXsSSkd6U+/H61q7i0SY9TqqhdiMQLW/efK9LkVRen5myhwqogwiF/42Jp2nrCeuzv5YDsAFSrQ0lukW+Hz7FXV+0axnKeXZ08Nd+IS1BhGyMgHo6PWMP1fWyfO0DJVUfIqrHqvBy8bW0yNOuhiyU2oeyDRKv75OMxpIrUeX3qvmrVcYUPvfXsVQIDAQABo1MwUTAdBgNVHQ4EFgQUlro6UuKRY+lHZ3T4FQMhoQAJ2a8wHwYDVR0jBBgwFoAUlro6UuKRY+lHZ3T4FQMhoQAJ2a8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEARliSCLdjNI5fFkNwXDK6k6jN5hITrY07XIawUIEwinjQqgLkYFvzXbMtfLwsWmxMPjDVYYDa5Y2NAGcH08b//2z9EuHxMOTOFTKr59BEcVxV1cxV+lspAunH8DLSlLJhf/EeR+MhIIHAfhlE8V7lvlE1EbM+Uj5JYIeefV/4omsGrphyHD3oSJAQDae0su200I/i2yAaTrwXLZ4HtaXsnxKZ4PMPFWaLvMQ8DsLgx2VB3/vQJn74Xepau6mYEWlRnUu90mj79gJOnwBKPlLojF6dJOMIJ2YHr9fI8sUfkVwPFVlkDKJcr0ll5RL3O/naNlLQZuOgijOM5YF5iTrefliVodEHpBPID2mhtq/E+ZIQWLpik8ulsJ8ufN9YfrbjbsiC/KeoMqoFCImRSyMGQDMADo4EV3DNfDFvfrHx0qBMmJ0nkhuGobphegMPCjZ3axvQwQulKuHXmFpAvGYcpK/twBMC1MJkV04tIwVEDZG6id5oKYtrIXHdSFshf6r3z4bbgq6kJnOxZ8Vo4cEw/dgc3hRivr+HnxOJcEk2CTQlCVOiCQAg64OqDEOoswVg6nzoO3RJhFatu+abO22MIXPNGma02zBoQZLYpGzL9z6pMnPKjL15G9H1SYVSTGhmq+GVtdRibg8rLBciSm3ERd7gNRqvYP5GrjCtUIbOTEc=", - "target_method": "GET", - "target_url": "https://en.wikipedia.org/wiki/Claude_Shannon", - "target_headers": {}, - "target_body": "", - "max_sent_data": 10000, - "max_recv_data": 10000, - "proving": { - "manifest": { - "manifestVersion": "2", - "id": "wikipedia-claude-shannon", - "title": "Wikipedia Claude Shannon", - "description": "Generate a proof that you have visited the Claude Shannon Wikipedia page", - "prepareUrl": "https://en.wikipedia.org/wiki/Claude_Shannon", - "request": { - "method": "GET", - "version": "HTTP/1.1", - "url": "https://en.wikipedia.org/wiki/Claude_Shannon", - "headers": { - "accept-encoding": "identity", - "host": "en.wikipedia.org", - "connection": "close", - "accept": "*/*", - "authorization": "Bearer <% accessToken %>" - }, - "vars": { - "accessToken": { - "description": "Spotify access token", - "required": true, - "pattern": "^[A-Za-z0-9_-]+$" - } - } - }, - "response": { - "status": "200", - "version": "HTTP/1.1", - "message": "OK", - "headers": { - "Content-Type": "text/html; charset=UTF-8" - }, - "body": { - "format": "html", - "extractors": [ - { - "id": "pageTitle", - "description": "Extract the page title", - "selector": ["title"], - "type": "string", - "predicates": [ - { - "type": "value", - "comparison": "contains", - "value": "Claude Shannon" - } - ] - }, - { - "id": "roles", - "description": "Extract his professional roles", - "selector": ["div#mw-content-text", "div.mw-parser-output", "p", "a"], - "type": "array", - "predicates": [ - { - "type": "value", - "comparison": "contains", - "value": "mathematician", - "case_sensitive": false - }, - { - "type": "value", - "comparison": "contains", - "value": "electrical engineer", - "case_sensitive": false - }, - { - "type": "value", - "comparison": "contains", - "value": "cryptographer", - "case_sensitive": false - } - ] - } - ] - } - } - } - } -} \ No newline at end of file diff --git a/fixture/client.proxy.json b/fixture/client.json.proxy.json similarity index 54% rename from fixture/client.proxy.json rename to fixture/client.json.proxy.json index 4b387f458..b5803d462 100644 --- a/fixture/client.proxy.json +++ b/fixture/client.json.proxy.json @@ -3,62 +3,40 @@ "notary_port": 7443, "notary_ca_cert": "MIIFszCCA5ugAwIBAgIUeXLQmnjeXsHpGji7xA8oJjjw7WwwDQYJKoZIhvcNAQELBQAwaTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCVBhbG8gQWx0bzEVMBMGA1UECgwMT3JnYW5pemF0aW9uMRowGAYDVQQDDBFMb2NhbGhvc3QgUm9vdCBDQTAeFw0yNDA2MDcyMjUyNDBaFw0yOTA2MDYyMjUyNDBaMGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlQYWxvIEFsdG8xFTATBgNVBAoMDE9yZ2FuaXphdGlvbjEaMBgGA1UEAwwRTG9jYWxob3N0IFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDIHMEL9gVSxT/J0qS4xDkDZs1d1UG0+z6NFLLsGdV7gu0ZJbDPlNd0kpjWsisVNB7TcqWoq5ROK5CR+6lZxXC8nbqr2YAJ2O8mHIXcYv7msAN3UYxtM6v1M7K+vNMJdDjZVAxcOKq5R7uUDUPw1weePz6eVEjntAW8mUjqkfnCqYml943Ud3724SkI5wyUT9rKS3bk6hvneq1ah/b1zRGDF2gp+T/oNe4ieS/LGoIUluE2csGRXtt542gpJnw5L54JASmGgt6hunUSWtoaht7Qxv6hYpieu4iHqZY1kfcFDjDH2WI16g1YqrWHzk1l7vWNLVDEcK3kdSQ1GmYAij8ZjAi0LJizLwtN//EkfxiOPlV435itK3uugY+etxrk77BeA6PmVcpZeLLXYuKSrzfaBh0ifP2p0uRlShURi5Rz4IE0I7wHkZ44x9MKYv8YzXK7O29HD158tgorxqwwKmkHqSxWpp7SRKvNnMulHN/el+IKDrPeBhVXsSSkd6U+/H61q7i0SY9TqqhdiMQLW/efK9LkVRen5myhwqogwiF/42Jp2nrCeuzv5YDsAFSrQ0lukW+Hz7FXV+0axnKeXZ08Nd+IS1BhGyMgHo6PWMP1fWyfO0DJVUfIqrHqvBy8bW0yNOuhiyU2oeyDRKv75OMxpIrUeX3qvmrVcYUPvfXsVQIDAQABo1MwUTAdBgNVHQ4EFgQUlro6UuKRY+lHZ3T4FQMhoQAJ2a8wHwYDVR0jBBgwFoAUlro6UuKRY+lHZ3T4FQMhoQAJ2a8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEARliSCLdjNI5fFkNwXDK6k6jN5hITrY07XIawUIEwinjQqgLkYFvzXbMtfLwsWmxMPjDVYYDa5Y2NAGcH08b//2z9EuHxMOTOFTKr59BEcVxV1cxV+lspAunH8DLSlLJhf/EeR+MhIIHAfhlE8V7lvlE1EbM+Uj5JYIeefV/4omsGrphyHD3oSJAQDae0su200I/i2yAaTrwXLZ4HtaXsnxKZ4PMPFWaLvMQ8DsLgx2VB3/vQJn74Xepau6mYEWlRnUu90mj79gJOnwBKPlLojF6dJOMIJ2YHr9fI8sUfkVwPFVlkDKJcr0ll5RL3O/naNlLQZuOgijOM5YF5iTrefliVodEHpBPID2mhtq/E+ZIQWLpik8ulsJ8ufN9YfrbjbsiC/KeoMqoFCImRSyMGQDMADo4EV3DNfDFvfrHx0qBMmJ0nkhuGobphegMPCjZ3axvQwQulKuHXmFpAvGYcpK/twBMC1MJkV04tIwVEDZG6id5oKYtrIXHdSFshf6r3z4bbgq6kJnOxZ8Vo4cEw/dgc3hRivr+HnxOJcEk2CTQlCVOiCQAg64OqDEOoswVg6nzoO3RJhFatu+abO22MIXPNGma02zBoQZLYpGzL9z6pMnPKjL15G9H1SYVSTGhmq+GVtdRibg8rLBciSm3ERd7gNRqvYP5GrjCtUIbOTEc=", "target_body": "", - "proving": { - "manifest": { - "manifestVersion": "1", - "id": "reddit-user-karma", - "title": "Total Reddit Karma", - "description": "Generate a proof that you have a certain amount of karma", - "prepareUrl": "https://www.reddit.com/login/", - "request": { - "method": "GET", - "version": "HTTP/1.1", - "url": "https://gist.githubusercontent.com/mattes/23e64faadb5fd4b5112f379903d2572e/raw/74e517a60c21a5c11d94fec8b572f68addfade39/example.json", - "headers": { - }, - "body": { - "userId": "<% userId %>" - }, - "vars": { - "userId": { - "description": "Reddit username", - "required": true, - "pattern": "^[A-Za-z0-9_-]{3,20}$" - }, - "authToken": { - "description": "Authentication token", - "required": false, - "default": "abcdef1234567890abcdef1234567890", - "pattern": "^[A-Za-z0-9]{32}$" - } - }, - "extra": { - "headers": { - "User-Agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36", - "Content-Type": "application/json" - } - } + "target_method": "GET", + "target_url": "https://gist.githubusercontent.com/mattes/23e64faadb5fd4b5112f379903d2572e/raw/74e517a60c21a5c11d94fec8b572f68addfade39/example.json", + "target_headers": {}, + "manifest": { + "manifestVersion": "1", + "id": "hello-world", + "title": "Hello World example", + "description": "Prove that a gist contains a hello world message", + "prepareUrl": "https://gist.githubusercontent.com/mattes/23e64faadb5fd4b5112f379903d2572e/raw/74e517a60c21a5c11d94fec8b572f68addfade39/example.json", + "request": { + "method": "GET", + "version": "HTTP/1.1", + "url": "https://gist.githubusercontent.com/mattes/23e64faadb5fd4b5112f379903d2572e/raw/74e517a60c21a5c11d94fec8b572f68addfade39/example.json", + "headers": {} + }, + "response": { + "status": "200", + "version": "HTTP/1.1", + "message": "OK", + "headers": { + "Content-Type": "text/plain; charset=utf-8" }, - "response": { - "status": "200", - "version": "HTTP/1.1", - "message": "OK", - "headers": { - "Content-Type": "text/plain; charset=utf-8" - }, - "body": { - "format": "json", - "extractors": [ - { - "id": "helloValue", - "description": "Extract the hello value", - "selector": [ - "hello" - ], - "type": "string" - } - ] - } + "body": { + "format": "json", + "extractors": [ + { + "id": "helloValue", + "description": "Extract the hello value", + "selector": [ + "hello" + ], + "type": "string" + } + ] } } } diff --git a/notary/src/proxy.rs b/notary/src/proxy.rs index 3f24c2847..76a0c8a98 100644 --- a/notary/src/proxy.rs +++ b/notary/src/proxy.rs @@ -7,7 +7,7 @@ use axum::{ use reqwest::{Request, Response}; use serde::Deserialize; use serde_json::Value; -use tracing::info; +use tracing::{debug, info}; use uuid::Uuid; use web_prover_core::{ hash::keccak_digest, @@ -19,10 +19,11 @@ use web_prover_core::{ }; use crate::{ - error::NotaryServerError, + error::{NotaryServerError, ProxyError}, verifier::{sign_verification, VerifyOutput}, SharedState, }; + #[derive(Deserialize)] pub struct NotarizeQuery { session_id: Uuid, @@ -54,7 +55,7 @@ pub async fn proxy( let request = from_reqwest_request(&reqwest_request); // debug!("{:?}", request); - let response = from_reqwest_response(reqwest_response).await; + let response = from_reqwest_response(reqwest_response).await?; // debug!("{:?}", response); let tee_proof = create_tee_proof(&payload.manifest, &request, &response, State(state))?; @@ -64,7 +65,7 @@ pub async fn proxy( // TODO: This, similarly to other from_* methods, should be a trait // Requires adding reqwest to proofs crate -async fn from_reqwest_response(response: Response) -> NotaryResponse { +async fn from_reqwest_response(response: Response) -> Result { let status = response.status().as_u16().to_string(); let version = format!("{:?}", response.version()); let message = response.status().canonical_reason().unwrap_or("").to_string(); @@ -73,8 +74,17 @@ async fn from_reqwest_response(response: Response) -> NotaryResponse { .iter() .map(|(k, v)| (capitalize_header(k.as_ref()), v.to_str().unwrap_or("").to_string())) .collect(); - let json = response.json().await.ok(); - NotaryResponse { + let body = response + .bytes() + .await + .map_err(|_| { + NotaryServerError::ProxyError(ProxyError::Io(std::io::Error::new( + std::io::ErrorKind::Other, + "Failed to read response body", + ))) + })? + .to_vec(); + Ok(NotaryResponse { response: ManifestResponse { status, version, @@ -83,8 +93,9 @@ async fn from_reqwest_response(response: Response) -> NotaryResponse { // TODO: This makes me think that perhaps this should be an optional field or something else body: ManifestResponseBody::default(), }, - notary_response_body: NotaryResponseBody { body: json }, - } + // TODO: Should we remove Option<_> on body? + notary_response_body: NotaryResponseBody { body: Some(body) }, + }) } fn from_reqwest_request(request: &Request) -> ManifestRequest { @@ -142,6 +153,7 @@ fn validate_notarization_legal( request: &ManifestRequest, response: &NotaryResponse, ) -> Result { + debug!("Validating manifest"); let result = manifest.validate_with(request, response)?; if !result.is_success() { info!("Manifest validation failed: {:?}", result.errors()); diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 6af5fced7..3df20d2fb 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -146,7 +146,7 @@ impl TestSetup { Command::new("cargo") .args(["run", "-p", "client", "--"]) .arg("--config") - .arg(workspace_root.join("fixture/client.proxy.json")) + .arg(workspace_root.join("../../fixture/client.json.proxy.json")) .env("RUST_LOG", "DEBUG") .current_dir(&workspace_root) .stdout(Stdio::piped()) From 8c3ee5cfad9322a10f3c5d5e5b13300e4c70ab6d Mon Sep 17 00:00:00 2001 From: Piotr Roslaniec Date: Thu, 13 Mar 2025 22:12:33 +0100 Subject: [PATCH 2/4] (wip): refactor into consts --- tests/src/lib.rs | 75 +++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 3df20d2fb..71fbc2618 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -12,6 +12,25 @@ use std::{ use tokio::time::{sleep, timeout}; +// File paths +const NOTARY_CONFIG_PATH: &str = "fixture/notary-config.toml"; +const CLIENT_CONFIG_PATH: &str = "fixture/client.proxy.json"; +const RELEASE_DIR: &str = "target/release"; + +// Binary names +const NOTARY_BIN: &str = "web-prover-notary"; +const CLIENT_BIN: &str = "web-prover-client"; + +// Timeouts and delays +const NOTARY_READY_TIMEOUT: Duration = Duration::from_secs(60); +const PROVING_TIMEOUT: Duration = Duration::from_secs(60); +const NOTARY_STARTUP_DELAY: Duration = Duration::from_secs(5); +const POLL_INTERVAL: Duration = Duration::from_millis(100); + +// Log messages +const NOTARY_READY_MSG: &str = "Listening on https://0.0.0.0:7443"; +const PROVING_SUCCESS_MSG: &str = "Proving Successful"; + struct TestSetup { notary: Child, client: Child, @@ -37,14 +56,14 @@ impl TestSetup { println!("Workspace root: {:?}", workspace_root); // Check for pre-built binaries in target/release - let notary_bin = workspace_root.join("target/release/notary"); - let client_bin = workspace_root.join("target/release/client"); + let notary_bin = workspace_root.join(RELEASE_DIR).join(NOTARY_BIN); + let client_bin = workspace_root.join(RELEASE_DIR).join(CLIENT_BIN); let use_prebuilt = notary_bin.exists() && client_bin.exists(); println!("Using pre-built binaries: {}", use_prebuilt); // Print the config file content for debugging - let notary_config_path = workspace_root.join("fixture/notary-config.toml"); + let notary_config_path = workspace_root.join(NOTARY_CONFIG_PATH); if notary_config_path.exists() { match std::fs::read_to_string(¬ary_config_path) { Ok(content) => println!("Notary config content:\n{}", content), @@ -54,15 +73,14 @@ impl TestSetup { println!("Notary config file not found at {:?}", notary_config_path); } - // This matches exactly what worked in your shell script + // Start notary let mut notary = if use_prebuilt { - // Change directory to workspace root first std::env::set_current_dir(&workspace_root).unwrap(); println!("Current directory: {:?}", std::env::current_dir().unwrap()); - let cmd = Command::new("./target/release/notary") + let cmd = Command::new(format!("./{}/{}", RELEASE_DIR, NOTARY_BIN)) .arg("--config") - .arg("./fixture/notary-config.toml") + .arg(format!("./{}", NOTARY_CONFIG_PATH)) .env("RUST_LOG", "DEBUG") .stdout(Stdio::piped()) .stderr(Stdio::piped()) @@ -73,7 +91,7 @@ impl TestSetup { cmd } else { Command::new("cargo") - .args(["run", "-p", "notary", "--release", "--"]) + .args(["run", "-p", NOTARY_BIN, "--release", "--"]) .arg("--config") .arg(notary_config_path) .env("RUST_LOG", "DEBUG") @@ -100,7 +118,7 @@ impl TestSetup { for line in stdout_reader.lines().chain(stderr_reader.lines()) { if let Ok(line) = line { println!("Notary: {}", line); - if line.contains("Listening on https://0.0.0.0:7443") { + if line.contains(NOTARY_READY_MSG) { ready_flag_clone.store(true, Ordering::SeqCst); break; } @@ -109,13 +127,11 @@ impl TestSetup { }); // Wait for notary to be ready with a timeout, or sleep 10 seconds like the original workflow - match timeout(Duration::from_secs(60), async { + match timeout(NOTARY_READY_TIMEOUT, async { while !ready_flag.load(Ordering::SeqCst) { - sleep(Duration::from_millis(100)).await; + sleep(POLL_INTERVAL).await; } - - // Add extra delay to match original workflow - sleep(Duration::from_secs(5)).await; + sleep(NOTARY_STARTUP_DELAY).await; }) .await { @@ -126,14 +142,13 @@ impl TestSetup { }, } - // Start client with exact same pattern as the working workflow + // Start client let client = if use_prebuilt { - // We're already in workspace_root directory println!("Current directory before client: {:?}", std::env::current_dir().unwrap()); - let cmd = Command::new("./target/release/client") + let cmd = Command::new(format!("./{}/{}", RELEASE_DIR, CLIENT_BIN)) .arg("--config") - .arg("./fixture/client.proxy.json") + .arg(format!("./{}", CLIENT_CONFIG_PATH)) .env("RUST_LOG", "DEBUG") .stdout(Stdio::piped()) .stderr(Stdio::piped()) @@ -144,9 +159,9 @@ impl TestSetup { cmd } else { Command::new("cargo") - .args(["run", "-p", "client", "--"]) + .args(["run", "-p", CLIENT_BIN, "--"]) .arg("--config") - .arg(workspace_root.join("../../fixture/client.json.proxy.json")) + .arg(workspace_root.join(CLIENT_CONFIG_PATH)) .env("RUST_LOG", "DEBUG") .current_dir(&workspace_root) .stdout(Stdio::piped()) @@ -173,35 +188,35 @@ async fn test_proving_successful() { let stdout = BufReader::new(setup.client.stdout.take().unwrap()); let stderr = BufReader::new(setup.client.stderr.take().unwrap()); - // Wait for proving successful with timeout - let result = timeout(Duration::from_secs(60), async { + let result = timeout(PROVING_TIMEOUT, async { let mut stdout_lines = stdout.lines(); let mut stderr_lines = stderr.lines(); loop { - // Check stdout if let Some(Ok(line)) = stdout_lines.next() { println!("Client stdout: {}", line); - if line.contains("Proving Successful") { + if line.contains(PROVING_SUCCESS_MSG) { return true; } } - // Check stderr if let Some(Ok(line)) = stderr_lines.next() { println!("Client stderr: {}", line); - if line.contains("Proving Successful") { + if line.contains(PROVING_SUCCESS_MSG) { return true; } } - // Small sleep to avoid busy waiting - sleep(Duration::from_millis(10)).await; + sleep(POLL_INTERVAL).await; } }) .await; match result { - Ok(found) => assert!(found, "Did not find 'Proving Successful' in output"), - Err(_) => panic!("Timed out waiting for 'Proving Successful' after 60 seconds"), + Ok(found) => assert!(found, "Did not find '{}' in output", PROVING_SUCCESS_MSG), + Err(_) => panic!( + "Timed out waiting for '{}' after {} seconds", + PROVING_SUCCESS_MSG, + PROVING_TIMEOUT.as_secs() + ), } } From ee12dfd227fcec10e1467cfa23c4bdeeab961ab1 Mon Sep 17 00:00:00 2001 From: Piotr Roslaniec Date: Fri, 14 Mar 2025 08:50:22 +0100 Subject: [PATCH 3/4] (wip): test works --- tests/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 71fbc2618..1b541e60c 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -14,7 +14,7 @@ use tokio::time::{sleep, timeout}; // File paths const NOTARY_CONFIG_PATH: &str = "fixture/notary-config.toml"; -const CLIENT_CONFIG_PATH: &str = "fixture/client.proxy.json"; +const CLIENT_CONFIG_PATH: &str = "fixture/client.json.proxy.json"; const RELEASE_DIR: &str = "target/release"; // Binary names From d349e6fbfc23bec2fa9a53f2f3301778097890b9 Mon Sep 17 00:00:00 2001 From: Piotr Roslaniec Date: Fri, 14 Mar 2025 09:55:41 +0100 Subject: [PATCH 4/4] feat!: return notary errors to client --- client/src/lib.rs | 10 +++++----- client/src/main.rs | 10 ++++++++-- core/src/proof.rs | 6 ++++++ notary/src/proxy.rs | 44 ++++++++++++++++++++------------------------ tests/src/lib.rs | 15 +++++++++++---- 5 files changed, 50 insertions(+), 35 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 69ec1cb45..7700822fd 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use tracing::debug; use web_prover_core::{ manifest::Manifest, - proof::{SignedVerificationReply, TeeProof}, + proof::{NotarizationResult, SignedVerificationReply}, }; use crate::error::WebProverClientError; @@ -21,7 +21,7 @@ pub struct ProxyConfig { pub manifest: Manifest, } -pub async fn proxy(config: config::Config) -> Result { +pub async fn proxy(config: config::Config) -> Result { let session_id = config.session_id.clone(); let url = format!( @@ -50,8 +50,8 @@ pub async fn proxy(config: config::Config) -> Result().await?; - Ok(tee_proof) + let notarization_result = response.json::().await?; + Ok(notarization_result) } pub async fn verify( @@ -75,7 +75,7 @@ pub async fn verify( }; let response = client.post(url).json(&verify_body).send().await?; - assert!(response.status() == hyper::StatusCode::OK, "response={:?}", response); + assert_eq!(response.status(), hyper::StatusCode::OK, "response={:?}", response); let verify_response = response.json::().await?; debug!("\n{:?}\n\n", verify_response.clone()); diff --git a/client/src/main.rs b/client/src/main.rs index 9c828f96b..5155b023e 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -32,8 +32,14 @@ async fn main() -> Result<(), WebProverClientError> { let mut config: Config = serde_json::from_str(&config_json)?; config.set_session_id(); - let proof = web_prover_client::proxy(config).await?; - let proof_json = serde_json::to_string_pretty(&proof)?; + let result = web_prover_client::proxy(config).await?; + + if result.errors.is_some() { + println!("Proving Failed: {:?}", result.errors); + return Ok(()); + } + + let proof_json = serde_json::to_string_pretty(&result.tee_proof)?; println!("Proving Successful: proof_len={:?}", proof_json.len()); Ok(()) } diff --git a/core/src/proof.rs b/core/src/proof.rs index 33d8b5986..4fe12a475 100644 --- a/core/src/proof.rs +++ b/core/src/proof.rs @@ -35,3 +35,9 @@ impl TryFrom for Vec { pub struct TeeProofData { pub manifest_hash: Vec, } + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct NotarizationResult { + pub tee_proof: Option, + pub errors: Option>, +} diff --git a/notary/src/proxy.rs b/notary/src/proxy.rs index 76a0c8a98..77f43ee1a 100644 --- a/notary/src/proxy.rs +++ b/notary/src/proxy.rs @@ -14,8 +14,8 @@ use web_prover_core::{ http::{ ManifestRequest, ManifestResponse, ManifestResponseBody, NotaryResponse, NotaryResponseBody, }, - manifest::{Manifest, ManifestValidationResult}, - proof::{TeeProof, TeeProofData}, + manifest::Manifest, + proof::{NotarizationResult, TeeProof, TeeProofData}, }; use crate::{ @@ -33,7 +33,7 @@ pub async fn proxy( query: Query, State(state): State>, extract::Json(payload): extract::Json, -) -> Result, NotaryServerError> { +) -> Result, NotaryServerError> { let session_id = query.session_id; info!("Starting proxy with ID: {}", session_id); @@ -58,9 +58,9 @@ pub async fn proxy( let response = from_reqwest_response(reqwest_response).await?; // debug!("{:?}", response); - let tee_proof = create_tee_proof(&payload.manifest, &request, &response, State(state))?; + let notarization_result = create_tee_proof(&payload.manifest, &request, &response, State(state))?; - Ok(Json(tee_proof)) + Ok(Json(notarization_result)) } // TODO: This, similarly to other from_* methods, should be a trait @@ -124,13 +124,21 @@ fn capitalize_header(header: &str) -> String { .join("-") } +/// Check if `manifest`, `request`, and `response` all fulfill requirements necessary for +/// a proof to be created. pub fn create_tee_proof( manifest: &Manifest, request: &ManifestRequest, response: &NotaryResponse, State(state): State>, -) -> Result { - let validation_result = validate_notarization_legal(manifest, request, response)?; +) -> Result { + debug!("Validating manifest"); + let validation_result = manifest.validate_with(request, response)?; + if !validation_result.is_success() { + info!("Manifest validation failed: {:?}", validation_result.errors()); + return Ok(NotarizationResult { tee_proof: None, errors: Some(validation_result.errors()) }); + } + info!("Manifest returned values: {:?}", validation_result.values()); let manifest_hash = manifest.to_keccak_digest()?; let extraction_hash = validation_result.extraction_keccak_digest()?; @@ -142,22 +150,10 @@ pub fn create_tee_proof( }; let signature = sign_verification(to_sign, State(state))?; let data = TeeProofData { manifest_hash: manifest_hash.to_vec() }; + let proof = TeeProof { data, signature }; + debug!("Created proof: {:?}", proof); - Ok(TeeProof { data, signature }) -} - -/// Check if `manifest`, `request`, and `response` all fulfill requirements necessary for -/// a proof to be created -fn validate_notarization_legal( - manifest: &Manifest, - request: &ManifestRequest, - response: &NotaryResponse, -) -> Result { - debug!("Validating manifest"); - let result = manifest.validate_with(request, response)?; - if !result.is_success() { - info!("Manifest validation failed: {:?}", result.errors()); - } - info!("Manifest returned values: {:?}", result.values()); - Ok(result) + let notarization_result = + NotarizationResult { tee_proof: Some(proof), errors: Some(validation_result.errors()) }; + Ok(notarization_result) } diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 1b541e60c..d6c1e74f2 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -195,14 +195,20 @@ async fn test_proving_successful() { if let Some(Ok(line)) = stdout_lines.next() { println!("Client stdout: {}", line); if line.contains(PROVING_SUCCESS_MSG) { - return true; + return Ok(()); + } + if line.contains("Proving Failed") { + return Err(line); } } if let Some(Ok(line)) = stderr_lines.next() { println!("Client stderr: {}", line); if line.contains(PROVING_SUCCESS_MSG) { - return true; + return Ok(()); + } + if line.contains("Proving Failed") { + return Err(line); } } @@ -212,9 +218,10 @@ async fn test_proving_successful() { .await; match result { - Ok(found) => assert!(found, "Did not find '{}' in output", PROVING_SUCCESS_MSG), + Ok(Ok(())) => (), + Ok(Err(failed_msg)) => panic!("Proving failed: {}", failed_msg), Err(_) => panic!( - "Timed out waiting for '{}' after {} seconds", + "Timed out waiting for '{}' or 'Proving Failed' after {} seconds", PROVING_SUCCESS_MSG, PROVING_TIMEOUT.as_secs() ),