diff --git a/notebooks/enclave/double-blind-eval-w-receipts/1. DO-benchmark-owner-dbe.ipynb b/notebooks/enclave/double-blind-eval-w-receipts/1. DO-benchmark-owner-dbe.ipynb index 6f78df95a6f..2d6973ebcfa 100644 --- a/notebooks/enclave/double-blind-eval-w-receipts/1. DO-benchmark-owner-dbe.ipynb +++ b/notebooks/enclave/double-blind-eval-w-receipts/1. DO-benchmark-owner-dbe.ipynb @@ -163,6 +163,19 @@ "benchmark_owner.peers" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Fail on a wrong email, or if the peer has not approved yet. Warn if the peer\n", + "# was already there before this notebook logged in.\n", + "# attest_peer() below checks the enclave.\n", + "benchmark_owner.validate_peer(MODEL_OWNER_EMAIL)\n", + "print(f\" Connected to {MODEL_OWNER_EMAIL}\")" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/notebooks/enclave/double-blind-eval-w-receipts/2. DO-model-owner-dbe.ipynb b/notebooks/enclave/double-blind-eval-w-receipts/2. DO-model-owner-dbe.ipynb index aa09e7f9fb0..2be6b118872 100644 --- a/notebooks/enclave/double-blind-eval-w-receipts/2. DO-model-owner-dbe.ipynb +++ b/notebooks/enclave/double-blind-eval-w-receipts/2. DO-model-owner-dbe.ipynb @@ -170,6 +170,19 @@ "print(\" Benchmark owner approved\")" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Fail on a wrong email, or if the peer has not approved yet. Warn if the peer\n", + "# was already there before this notebook logged in.\n", + "# attest_peer() below checks the enclave.\n", + "model_owner.validate_peer(BENCHMARK_OWNER_EMAIL)\n", + "print(f\" Connected to {BENCHMARK_OWNER_EMAIL}\")" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/notebooks/enclave/gemma/colab-3-persona/1. DO-model-owner-gemma-restrict.ipynb b/notebooks/enclave/gemma/colab-3-persona/1. DO-model-owner-gemma-restrict.ipynb index 3c14adfeaff..c0363f3b148 100644 --- a/notebooks/enclave/gemma/colab-3-persona/1. DO-model-owner-gemma-restrict.ipynb +++ b/notebooks/enclave/gemma/colab-3-persona/1. DO-model-owner-gemma-restrict.ipynb @@ -192,9 +192,23 @@ ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "id": "15", "metadata": {}, + "outputs": [], + "source": [ + "# Fail on a wrong email, or if the peer has not approved yet. Warn if the peer\n", + "# was already there before this notebook logged in.\n", + "# attest_peer() below checks the enclave.\n", + "model_owner.validate_peer(RESEARCHER_EMAIL)\n", + "print(f\" Connected to {RESEARCHER_EMAIL}\")" + ] + }, + { + "cell_type": "markdown", + "id": "16", + "metadata": {}, "source": [ "### Step 1.2 — Attest the enclave's identity\n", "\n", @@ -204,7 +218,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -214,7 +228,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ "## Step 2 — Get the Gemma 3 model\n", @@ -225,7 +239,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -236,7 +250,7 @@ { "cell_type": "code", "execution_count": null, - "id": "19", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -252,7 +266,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -261,7 +275,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "## Step 3 — Prepare the files for upload\n", @@ -272,7 +286,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -322,7 +336,7 @@ { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -338,7 +352,7 @@ }, { "cell_type": "markdown", - "id": "24", + "id": "25", "metadata": {}, "source": [ "## Step 4 — Upload the private model\n", @@ -349,7 +363,7 @@ { "cell_type": "code", "execution_count": null, - "id": "25", + "id": "26", "metadata": {}, "outputs": [], "source": [ @@ -368,7 +382,7 @@ }, { "cell_type": "markdown", - "id": "26", + "id": "27", "metadata": {}, "source": [ "## Step 5 — Run `syft-restrict` on the inference code\n", @@ -382,7 +396,7 @@ { "cell_type": "code", "execution_count": null, - "id": "27", + "id": "28", "metadata": {}, "outputs": [], "source": [ @@ -442,7 +456,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -463,7 +477,7 @@ }, { "cell_type": "markdown", - "id": "29", + "id": "30", "metadata": {}, "source": [ "### Step 5.1 — Approve the job\n", @@ -474,7 +488,7 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "31", "metadata": {}, "outputs": [], "source": [ @@ -486,7 +500,7 @@ { "cell_type": "code", "execution_count": null, - "id": "31", + "id": "32", "metadata": {}, "outputs": [], "source": [ @@ -496,7 +510,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32", + "id": "33", "metadata": {}, "outputs": [], "source": [ @@ -507,7 +521,7 @@ }, { "cell_type": "markdown", - "id": "33", + "id": "34", "metadata": {}, "source": [ "## Step 6 — Approve the final inference job\n", @@ -518,7 +532,7 @@ { "cell_type": "code", "execution_count": null, - "id": "34", + "id": "35", "metadata": {}, "outputs": [], "source": [ @@ -531,7 +545,7 @@ { "cell_type": "code", "execution_count": null, - "id": "35", + "id": "36", "metadata": {}, "outputs": [], "source": [ @@ -541,7 +555,7 @@ { "cell_type": "code", "execution_count": null, - "id": "36", + "id": "37", "metadata": {}, "outputs": [], "source": [ diff --git a/notebooks/enclave/gemma/colab-3-persona/2. DO-benchmark-owner-gemma-restrict.ipynb b/notebooks/enclave/gemma/colab-3-persona/2. DO-benchmark-owner-gemma-restrict.ipynb index 57e114c91b7..94d51734ef7 100644 --- a/notebooks/enclave/gemma/colab-3-persona/2. DO-benchmark-owner-gemma-restrict.ipynb +++ b/notebooks/enclave/gemma/colab-3-persona/2. DO-benchmark-owner-gemma-restrict.ipynb @@ -165,9 +165,23 @@ ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "id": "14", "metadata": {}, + "outputs": [], + "source": [ + "# Fail on a wrong email, or if the peer has not approved yet. Warn if the peer\n", + "# was already there before this notebook logged in.\n", + "# attest_peer() below checks the enclave.\n", + "benchmark_owner.validate_peer(RESEARCHER_EMAIL)\n", + "print(f\" Connected to {RESEARCHER_EMAIL}\")" + ] + }, + { + "cell_type": "markdown", + "id": "15", + "metadata": {}, "source": [ "### Step 1.2 — Attest the enclave's identity\n", "\n", @@ -177,7 +191,7 @@ { "cell_type": "code", "execution_count": null, - "id": "15", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -187,7 +201,7 @@ }, { "cell_type": "markdown", - "id": "16", + "id": "17", "metadata": {}, "source": [ "## Step 2 — Prepare the benchmark\n", @@ -198,7 +212,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17", + "id": "18", "metadata": {}, "outputs": [], "source": [ @@ -232,7 +246,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -245,7 +259,7 @@ }, { "cell_type": "markdown", - "id": "19", + "id": "20", "metadata": {}, "source": [ "## Step 3 — Upload the benchmark\n", @@ -256,7 +270,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -275,7 +289,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "## Step 4 — Review the `syft-restrict` job\n", @@ -291,7 +305,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -304,7 +318,7 @@ { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -314,7 +328,7 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -325,7 +339,7 @@ }, { "cell_type": "markdown", - "id": "25", + "id": "26", "metadata": {}, "source": [ "### Step 4.1 — Read the certificate\n", @@ -336,7 +350,7 @@ { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -353,7 +367,7 @@ }, { "cell_type": "markdown", - "id": "27", + "id": "28", "metadata": {}, "source": [ "## Step 5 — Approve the inference job\n", @@ -364,7 +378,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -377,7 +391,7 @@ { "cell_type": "code", "execution_count": null, - "id": "29", + "id": "30", "metadata": {}, "outputs": [], "source": [ @@ -387,7 +401,7 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "31", "metadata": {}, "outputs": [], "source": [ diff --git a/notebooks/enclave/gemma/colab-3-persona/3. DS-researcher-gemma-restrict.ipynb b/notebooks/enclave/gemma/colab-3-persona/3. DS-researcher-gemma-restrict.ipynb index a6e5ec797da..30505d2a4ab 100644 --- a/notebooks/enclave/gemma/colab-3-persona/3. DS-researcher-gemma-restrict.ipynb +++ b/notebooks/enclave/gemma/colab-3-persona/3. DS-researcher-gemma-restrict.ipynb @@ -152,9 +152,24 @@ ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "id": "13", "metadata": {}, + "outputs": [], + "source": [ + "# Fail on a wrong email, or if the peer has not approved yet. Warn if the peer\n", + "# was already there before this notebook logged in.\n", + "# attest_peer() below checks the enclave.\n", + "for peer_email in [MODEL_OWNER_EMAIL, BENCHMARK_OWNER_EMAIL]:\n", + " researcher.validate_peer(peer_email)\n", + " print(f\" Connected to {peer_email}\")" + ] + }, + { + "cell_type": "markdown", + "id": "14", + "metadata": {}, "source": [ "### Step 1.2 — Attest enclave's identity" ] @@ -162,7 +177,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -172,7 +187,7 @@ }, { "cell_type": "markdown", - "id": "15", + "id": "16", "metadata": {}, "source": [ "## Step 2 — Browse the mock datasets" @@ -181,7 +196,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -191,7 +206,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ "## Step 3 — Job helpers" @@ -200,7 +215,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -214,7 +229,7 @@ }, { "cell_type": "markdown", - "id": "19", + "id": "20", "metadata": {}, "source": [ "## Step 4 — Define the inference job\n", @@ -225,7 +240,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -289,7 +304,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "## Step 5 — Submit the job to the enclave" @@ -298,7 +313,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -321,7 +336,7 @@ }, { "cell_type": "markdown", - "id": "23", + "id": "24", "metadata": {}, "source": [ "## Step 6 — Wait for both DOs to approve and the enclave to run\n", @@ -332,7 +347,7 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -347,7 +362,7 @@ }, { "cell_type": "markdown", - "id": "25", + "id": "26", "metadata": {}, "source": [ "## Step 7 — View the results" @@ -356,7 +371,7 @@ { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "27", "metadata": {}, "outputs": [], "source": [ diff --git a/notebooks/enclave/gemma/colab-shield/1. DO-model-owner-gemma-shield.ipynb b/notebooks/enclave/gemma/colab-shield/1. DO-model-owner-gemma-shield.ipynb index 2d0fd7f3e81..9819051ae03 100644 --- a/notebooks/enclave/gemma/colab-shield/1. DO-model-owner-gemma-shield.ipynb +++ b/notebooks/enclave/gemma/colab-shield/1. DO-model-owner-gemma-shield.ipynb @@ -243,9 +243,23 @@ ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "id": "17", "metadata": {}, + "outputs": [], + "source": [ + "# Fail on a wrong email, or if the peer has not approved yet. Warn if the peer\n", + "# was already there before this notebook logged in.\n", + "# attest_peer() below checks the enclave.\n", + "model_owner.validate_peer(BENCHMARK_OWNER_EMAIL)\n", + "print(f\" Connected to {BENCHMARK_OWNER_EMAIL}\")" + ] + }, + { + "cell_type": "markdown", + "id": "18", + "metadata": {}, "source": [ "### Step 1.2 — Attest the enclave's identity\n", "\n", @@ -255,7 +269,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -265,7 +279,7 @@ }, { "cell_type": "markdown", - "id": "19", + "id": "20", "metadata": {}, "source": [ "## Step 2 — Get the two models\n", @@ -282,7 +296,7 @@ }, { "cell_type": "markdown", - "id": "20", + "id": "21", "metadata": {}, "source": [ "### Step 2.1 — Gemma 3 from Kaggle\n" @@ -291,7 +305,7 @@ { "cell_type": "code", "execution_count": null, - "id": "21", + "id": "22", "metadata": {}, "outputs": [], "source": [ @@ -310,7 +324,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -325,7 +339,7 @@ }, { "cell_type": "markdown", - "id": "23", + "id": "24", "metadata": {}, "source": [ "### Step 2.2 — ShieldGemma 2B from Hugging Face\n", @@ -338,7 +352,7 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -363,7 +377,7 @@ }, { "cell_type": "markdown", - "id": "25", + "id": "26", "metadata": {}, "source": [ "## Step 3 — Prepare the files for upload\n", @@ -377,7 +391,7 @@ { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -455,7 +469,7 @@ { "cell_type": "code", "execution_count": null, - "id": "27", + "id": "28", "metadata": {}, "outputs": [], "source": [ @@ -474,7 +488,7 @@ }, { "cell_type": "markdown", - "id": "28", + "id": "29", "metadata": {}, "source": [ "## Step 4 — Upload the two private models\n", @@ -485,7 +499,7 @@ { "cell_type": "code", "execution_count": null, - "id": "29", + "id": "30", "metadata": {}, "outputs": [], "source": [ @@ -511,7 +525,7 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "31", "metadata": {}, "outputs": [], "source": [ @@ -522,7 +536,7 @@ }, { "cell_type": "markdown", - "id": "31", + "id": "32", "metadata": {}, "source": [ "## Step 5 — Run `syft-restrict` on the inference code\n", @@ -536,7 +550,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32", + "id": "33", "metadata": {}, "outputs": [], "source": [ @@ -596,7 +610,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33", + "id": "34", "metadata": {}, "outputs": [], "source": [ @@ -616,7 +630,7 @@ }, { "cell_type": "markdown", - "id": "34", + "id": "35", "metadata": {}, "source": [ "### Step 5.1 — Approve the job\n", @@ -627,7 +641,7 @@ { "cell_type": "code", "execution_count": null, - "id": "35", + "id": "36", "metadata": {}, "outputs": [], "source": [ @@ -642,7 +656,7 @@ { "cell_type": "code", "execution_count": null, - "id": "36", + "id": "37", "metadata": {}, "outputs": [], "source": [ @@ -652,7 +666,7 @@ { "cell_type": "code", "execution_count": null, - "id": "37", + "id": "38", "metadata": {}, "outputs": [], "source": [ @@ -662,7 +676,7 @@ }, { "cell_type": "markdown", - "id": "38", + "id": "39", "metadata": {}, "source": [ "\"Wait\n" @@ -670,7 +684,7 @@ }, { "cell_type": "markdown", - "id": "39", + "id": "40", "metadata": {}, "source": [ "## Step 6 — Approve the final inference job\n", @@ -681,7 +695,7 @@ { "cell_type": "code", "execution_count": null, - "id": "40", + "id": "41", "metadata": {}, "outputs": [], "source": [ @@ -697,7 +711,7 @@ { "cell_type": "code", "execution_count": null, - "id": "41", + "id": "42", "metadata": {}, "outputs": [], "source": [ @@ -707,7 +721,7 @@ { "cell_type": "code", "execution_count": null, - "id": "42", + "id": "43", "metadata": {}, "outputs": [], "source": [ diff --git a/notebooks/enclave/gemma/colab-shield/2. DO-benchmark-owner-gemma-shield.ipynb b/notebooks/enclave/gemma/colab-shield/2. DO-benchmark-owner-gemma-shield.ipynb index 9b2a0ba83df..c6f01bdf378 100644 --- a/notebooks/enclave/gemma/colab-shield/2. DO-benchmark-owner-gemma-shield.ipynb +++ b/notebooks/enclave/gemma/colab-shield/2. DO-benchmark-owner-gemma-shield.ipynb @@ -185,9 +185,23 @@ ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "id": "14", "metadata": {}, + "outputs": [], + "source": [ + "# Fail on a wrong email, or if the peer has not approved yet. Warn if the peer\n", + "# was already there before this notebook logged in.\n", + "# attest_peer() below checks the enclave.\n", + "benchmark_owner.validate_peer(MODEL_OWNER_EMAIL)\n", + "print(f\" Connected to {MODEL_OWNER_EMAIL}\")" + ] + }, + { + "cell_type": "markdown", + "id": "15", + "metadata": {}, "source": [ "### Step 1.2 — Attest the enclave's identity\n", "\n", @@ -197,7 +211,7 @@ { "cell_type": "code", "execution_count": null, - "id": "15", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -207,7 +221,7 @@ }, { "cell_type": "markdown", - "id": "16", + "id": "17", "metadata": {}, "source": [ "## Step 2 — Prepare the benchmark\n", @@ -222,7 +236,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17", + "id": "18", "metadata": {}, "outputs": [], "source": [ @@ -288,7 +302,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -299,7 +313,7 @@ { "cell_type": "code", "execution_count": null, - "id": "19", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -312,7 +326,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -330,7 +344,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "## Step 3 — Upload the benchmark\n", @@ -341,7 +355,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -358,7 +372,7 @@ { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -368,7 +382,7 @@ }, { "cell_type": "markdown", - "id": "24", + "id": "25", "metadata": {}, "source": [ "\"Wait\n" @@ -376,7 +390,7 @@ }, { "cell_type": "markdown", - "id": "25", + "id": "26", "metadata": {}, "source": [ "## Step 4 — Review the `syft-restrict` job\n", @@ -392,7 +406,7 @@ { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -408,7 +422,7 @@ { "cell_type": "code", "execution_count": null, - "id": "27", + "id": "28", "metadata": {}, "outputs": [], "source": [ @@ -418,7 +432,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -428,7 +442,7 @@ }, { "cell_type": "markdown", - "id": "29", + "id": "30", "metadata": {}, "source": [ "### Step 4.1 — Read the certificate\n", @@ -439,7 +453,7 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "31", "metadata": {}, "outputs": [], "source": [ @@ -459,7 +473,7 @@ }, { "cell_type": "markdown", - "id": "31", + "id": "32", "metadata": {}, "source": [ "## Step 5 — Submit the inference job\n", @@ -476,7 +490,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32", + "id": "33", "metadata": {}, "outputs": [], "source": [ @@ -485,7 +499,7 @@ }, { "cell_type": "markdown", - "id": "33", + "id": "34", "metadata": {}, "source": [ "### Step 5.1 — Read the model owner's guardrail\n", @@ -496,7 +510,7 @@ { "cell_type": "code", "execution_count": null, - "id": "34", + "id": "35", "metadata": {}, "outputs": [], "source": [ @@ -514,7 +528,7 @@ { "cell_type": "code", "execution_count": null, - "id": "35", + "id": "36", "metadata": {}, "outputs": [], "source": [ @@ -646,7 +660,7 @@ { "cell_type": "code", "execution_count": null, - "id": "36", + "id": "37", "metadata": {}, "outputs": [], "source": [ @@ -674,7 +688,7 @@ }, { "cell_type": "markdown", - "id": "37", + "id": "38", "metadata": {}, "source": [ "## Step 6 — Approve the inference job\n", @@ -685,7 +699,7 @@ { "cell_type": "code", "execution_count": null, - "id": "38", + "id": "39", "metadata": {}, "outputs": [], "source": [ @@ -697,7 +711,7 @@ { "cell_type": "code", "execution_count": null, - "id": "39", + "id": "40", "metadata": {}, "outputs": [], "source": [ @@ -707,7 +721,7 @@ { "cell_type": "code", "execution_count": null, - "id": "40", + "id": "41", "metadata": {}, "outputs": [], "source": [ @@ -717,7 +731,7 @@ }, { "cell_type": "markdown", - "id": "41", + "id": "42", "metadata": {}, "source": [ "\"Wait\n" @@ -725,7 +739,7 @@ }, { "cell_type": "markdown", - "id": "42", + "id": "43", "metadata": {}, "source": [ "## Step 7 — View the results\n", @@ -738,7 +752,7 @@ { "cell_type": "code", "execution_count": null, - "id": "43", + "id": "44", "metadata": {}, "outputs": [], "source": [ @@ -754,7 +768,7 @@ { "cell_type": "code", "execution_count": null, - "id": "44", + "id": "45", "metadata": {}, "outputs": [], "source": [ diff --git a/notebooks/enclave/gemma/colab/1. DO-model-owner-gemma-restrict.ipynb b/notebooks/enclave/gemma/colab/1. DO-model-owner-gemma-restrict.ipynb index 578aad52171..57a995e8551 100644 --- a/notebooks/enclave/gemma/colab/1. DO-model-owner-gemma-restrict.ipynb +++ b/notebooks/enclave/gemma/colab/1. DO-model-owner-gemma-restrict.ipynb @@ -195,9 +195,23 @@ ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "id": "15", "metadata": {}, + "outputs": [], + "source": [ + "# Fail on a wrong email, or if the peer has not approved yet. Warn if the peer\n", + "# was already there before this notebook logged in.\n", + "# attest_peer() below checks the enclave.\n", + "model_owner.validate_peer(BENCHMARK_OWNER_EMAIL)\n", + "print(f\" Connected to {BENCHMARK_OWNER_EMAIL}\")" + ] + }, + { + "cell_type": "markdown", + "id": "16", + "metadata": {}, "source": [ "### Step 1.2 — Attest the enclave's identity\n", "\n", @@ -207,7 +221,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -217,7 +231,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ "## Step 2 — Get the Gemma 3 model\n", @@ -227,7 +241,7 @@ }, { "cell_type": "markdown", - "id": "18", + "id": "19", "metadata": {}, "source": [ "The Notebooks assumes, that gemma-3 model is present in your Google Drive, kindly upload the model to your Google Drive. You could use the kaggle API to download the model from Kaggle and upload it to your Google Drive. The command to download the model from Kaggle is below.\n", @@ -238,7 +252,7 @@ { "cell_type": "code", "execution_count": null, - "id": "19", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -257,7 +271,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -274,7 +288,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "## Step 3 — Prepare the files for upload\n", @@ -285,7 +299,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -327,7 +341,7 @@ { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -343,7 +357,7 @@ }, { "cell_type": "markdown", - "id": "24", + "id": "25", "metadata": {}, "source": [ "## Step 4 — Upload the private model\n", @@ -354,7 +368,7 @@ { "cell_type": "code", "execution_count": null, - "id": "25", + "id": "26", "metadata": {}, "outputs": [], "source": [ @@ -371,7 +385,7 @@ { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -381,7 +395,7 @@ }, { "cell_type": "markdown", - "id": "27", + "id": "28", "metadata": {}, "source": [ "## Step 5 — Run `syft-restrict` on the inference code\n", @@ -395,7 +409,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -455,7 +469,7 @@ { "cell_type": "code", "execution_count": null, - "id": "29", + "id": "30", "metadata": {}, "outputs": [], "source": [ @@ -475,7 +489,7 @@ }, { "cell_type": "markdown", - "id": "30", + "id": "31", "metadata": {}, "source": [ "### Step 5.1 — Approve the job\n", @@ -486,7 +500,7 @@ { "cell_type": "code", "execution_count": null, - "id": "31", + "id": "32", "metadata": {}, "outputs": [], "source": [ @@ -501,7 +515,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32", + "id": "33", "metadata": {}, "outputs": [], "source": [ @@ -511,7 +525,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33", + "id": "34", "metadata": {}, "outputs": [], "source": [ @@ -521,7 +535,7 @@ }, { "cell_type": "markdown", - "id": "34", + "id": "35", "metadata": {}, "source": [ "\"Wait\n" @@ -529,7 +543,7 @@ }, { "cell_type": "markdown", - "id": "35", + "id": "36", "metadata": {}, "source": [ "## Step 6 — Approve the final inference job\n", @@ -540,7 +554,7 @@ { "cell_type": "code", "execution_count": null, - "id": "36", + "id": "37", "metadata": {}, "outputs": [], "source": [ @@ -556,7 +570,7 @@ { "cell_type": "code", "execution_count": null, - "id": "37", + "id": "38", "metadata": {}, "outputs": [], "source": [ @@ -566,7 +580,7 @@ { "cell_type": "code", "execution_count": null, - "id": "38", + "id": "39", "metadata": {}, "outputs": [], "source": [ diff --git a/notebooks/enclave/gemma/colab/2. DO-benchmark-owner-gemma-restrict.ipynb b/notebooks/enclave/gemma/colab/2. DO-benchmark-owner-gemma-restrict.ipynb index e644f9f9a6b..25a1c9f0737 100644 --- a/notebooks/enclave/gemma/colab/2. DO-benchmark-owner-gemma-restrict.ipynb +++ b/notebooks/enclave/gemma/colab/2. DO-benchmark-owner-gemma-restrict.ipynb @@ -174,9 +174,23 @@ ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "id": "14", "metadata": {}, + "outputs": [], + "source": [ + "# Fail on a wrong email, or if the peer has not approved yet. Warn if the peer\n", + "# was already there before this notebook logged in.\n", + "# attest_peer() below checks the enclave.\n", + "benchmark_owner.validate_peer(MODEL_OWNER_EMAIL)\n", + "print(f\" Connected to {MODEL_OWNER_EMAIL}\")" + ] + }, + { + "cell_type": "markdown", + "id": "15", + "metadata": {}, "source": [ "### Step 1.2 — Attest the enclave's identity\n", "\n", @@ -186,7 +200,7 @@ { "cell_type": "code", "execution_count": null, - "id": "15", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -196,7 +210,7 @@ }, { "cell_type": "markdown", - "id": "16", + "id": "17", "metadata": {}, "source": [ "## Step 2 — Prepare the benchmark\n", @@ -211,7 +225,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17", + "id": "18", "metadata": {}, "outputs": [], "source": [ @@ -277,7 +291,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -288,7 +302,7 @@ { "cell_type": "code", "execution_count": null, - "id": "19", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -301,7 +315,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -319,7 +333,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "## Step 3 — Upload the benchmark\n", @@ -330,7 +344,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -347,7 +361,7 @@ { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -357,7 +371,7 @@ }, { "cell_type": "markdown", - "id": "24", + "id": "25", "metadata": {}, "source": [ "\"Wait\n" @@ -365,7 +379,7 @@ }, { "cell_type": "markdown", - "id": "25", + "id": "26", "metadata": {}, "source": [ "## Step 4 — Review the `syft-restrict` job\n", @@ -381,7 +395,7 @@ { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -397,7 +411,7 @@ { "cell_type": "code", "execution_count": null, - "id": "27", + "id": "28", "metadata": {}, "outputs": [], "source": [ @@ -407,7 +421,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -417,7 +431,7 @@ }, { "cell_type": "markdown", - "id": "29", + "id": "30", "metadata": {}, "source": [ "### Step 4.1 — Read the certificate\n", @@ -428,7 +442,7 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "31", "metadata": {}, "outputs": [], "source": [ @@ -448,7 +462,7 @@ }, { "cell_type": "markdown", - "id": "31", + "id": "32", "metadata": {}, "source": [ "## Step 5 — Submit the inference job\n", @@ -462,7 +476,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32", + "id": "33", "metadata": {}, "outputs": [], "source": [ @@ -472,7 +486,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33", + "id": "34", "metadata": {}, "outputs": [], "source": [ @@ -550,7 +564,7 @@ { "cell_type": "code", "execution_count": null, - "id": "34", + "id": "35", "metadata": {}, "outputs": [], "source": [ @@ -575,7 +589,7 @@ }, { "cell_type": "markdown", - "id": "35", + "id": "36", "metadata": {}, "source": [ "## Step 6 — Approve the inference job\n", @@ -586,7 +600,7 @@ { "cell_type": "code", "execution_count": null, - "id": "36", + "id": "37", "metadata": {}, "outputs": [], "source": [ @@ -598,7 +612,7 @@ { "cell_type": "code", "execution_count": null, - "id": "37", + "id": "38", "metadata": {}, "outputs": [], "source": [ @@ -608,7 +622,7 @@ { "cell_type": "code", "execution_count": null, - "id": "38", + "id": "39", "metadata": {}, "outputs": [], "source": [ @@ -618,7 +632,7 @@ }, { "cell_type": "markdown", - "id": "39", + "id": "40", "metadata": {}, "source": [ "\"Wait\n" @@ -626,7 +640,7 @@ }, { "cell_type": "markdown", - "id": "40", + "id": "41", "metadata": {}, "source": [ "## Step 7 — View the results\n", @@ -637,7 +651,7 @@ { "cell_type": "code", "execution_count": null, - "id": "41", + "id": "42", "metadata": {}, "outputs": [], "source": [ @@ -653,7 +667,7 @@ { "cell_type": "code", "execution_count": null, - "id": "42", + "id": "43", "metadata": {}, "outputs": [], "source": [ diff --git a/notebooks/enclave/nanolm/2. enclave_eval_localenc.ipynb b/notebooks/enclave/nanolm/2. enclave_eval_localenc.ipynb index 0291dfdf8e7..ed211eca3ab 100644 --- a/notebooks/enclave/nanolm/2. enclave_eval_localenc.ipynb +++ b/notebooks/enclave/nanolm/2. enclave_eval_localenc.ipynb @@ -346,9 +346,26 @@ ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "id": "16", "metadata": {}, + "outputs": [], + "source": [ + "# Fail on a wrong email, or if the peer has not approved yet. Warn if the peer\n", + "# was already there before this notebook logged in.\n", + "# Nothing in this notebook checks the enclave address.\n", + "researcher.validate_peer(MODEL_OWNER_EMAIL)\n", + "researcher.validate_peer(BENCHMARK_OWNER_EMAIL)\n", + "model_owner.validate_peer(RESEARCHER_EMAIL)\n", + "benchmark_owner.validate_peer(RESEARCHER_EMAIL)\n", + "print(\" Peers validated\")" + ] + }, + { + "cell_type": "markdown", + "id": "17", + "metadata": {}, "source": [ "## Step 3 — Model owner uploads the Gemma model\n", "\n", @@ -359,7 +376,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17", + "id": "18", "metadata": {}, "outputs": [], "source": [ @@ -379,7 +396,7 @@ }, { "cell_type": "markdown", - "id": "18", + "id": "19", "metadata": {}, "source": [ "## Step 4 — Benchmark owner uploads the evaluation benchmark" @@ -388,7 +405,7 @@ { "cell_type": "code", "execution_count": null, - "id": "19", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -408,7 +425,7 @@ }, { "cell_type": "markdown", - "id": "20", + "id": "21", "metadata": {}, "source": [ "## Step 5 — Researcher browses the mock datasets" @@ -417,7 +434,7 @@ { "cell_type": "code", "execution_count": null, - "id": "21", + "id": "22", "metadata": {}, "outputs": [], "source": [ @@ -427,7 +444,7 @@ }, { "cell_type": "markdown", - "id": "22", + "id": "23", "metadata": {}, "source": [ "## Step 6 — Researcher writes and submits the inference job\n", @@ -440,7 +457,7 @@ { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -496,7 +513,7 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -515,7 +532,7 @@ }, { "cell_type": "markdown", - "id": "25", + "id": "26", "metadata": {}, "source": [ "## Step 7 — Enclave receives and distributes the job\n", @@ -527,7 +544,7 @@ { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -544,7 +561,7 @@ }, { "cell_type": "markdown", - "id": "27", + "id": "28", "metadata": {}, "source": [ "## Step 8 — Model owner and Benchmark owner approve\n", @@ -556,7 +573,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -567,7 +584,7 @@ }, { "cell_type": "markdown", - "id": "29", + "id": "30", "metadata": {}, "source": [ "## Step 9 — Enclave runs the job and distributes results\n", @@ -579,7 +596,7 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "31", "metadata": {}, "outputs": [], "source": [ @@ -596,7 +613,7 @@ }, { "cell_type": "markdown", - "id": "31", + "id": "32", "metadata": {}, "source": [ "## Step 10 — Researcher retrieves the result" @@ -605,7 +622,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32", + "id": "33", "metadata": {}, "outputs": [], "source": [ @@ -624,7 +641,7 @@ }, { "cell_type": "markdown", - "id": "33", + "id": "34", "metadata": {}, "source": [ "## Step 11 — Model owner and Benchmark owner also receive the result\n", @@ -635,7 +652,7 @@ { "cell_type": "code", "execution_count": null, - "id": "34", + "id": "35", "metadata": {}, "outputs": [], "source": [ diff --git a/notebooks/enclave/nanolm/3. enclave_eval_e2e.ipynb b/notebooks/enclave/nanolm/3. enclave_eval_e2e.ipynb index e44b0dc72a5..2c3e521fc53 100644 --- a/notebooks/enclave/nanolm/3. enclave_eval_e2e.ipynb +++ b/notebooks/enclave/nanolm/3. enclave_eval_e2e.ipynb @@ -218,9 +218,26 @@ ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "id": "12", "metadata": {}, + "outputs": [], + "source": [ + "# Fail on a wrong email, or if the peer has not approved yet. Warn if the peer\n", + "# was already there before this notebook logged in.\n", + "# Nothing in this notebook checks the enclave address.\n", + "researcher.validate_peer(MODEL_OWNER_EMAIL)\n", + "researcher.validate_peer(BENCHMARK_OWNER_EMAIL)\n", + "model_owner.validate_peer(RESEARCHER_EMAIL)\n", + "benchmark_owner.validate_peer(RESEARCHER_EMAIL)\n", + "print(\" Peers validated\")" + ] + }, + { + "cell_type": "markdown", + "id": "13", + "metadata": {}, "source": [ "## Step 2.1 Dataset Helpers " ] @@ -228,7 +245,7 @@ { "cell_type": "code", "execution_count": null, - "id": "13", + "id": "14", "metadata": {}, "outputs": [], "source": [ @@ -296,7 +313,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -330,7 +347,7 @@ }, { "cell_type": "markdown", - "id": "15", + "id": "16", "metadata": {}, "source": [ "## Step 2.2 — Model owner uploads the model weights\n", @@ -342,7 +359,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -362,7 +379,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ "## Step 3 — Benchmark owner uploads the evaluation benchmark" @@ -371,7 +388,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -391,7 +408,7 @@ }, { "cell_type": "markdown", - "id": "19", + "id": "20", "metadata": {}, "source": [ "## Step 4 — Researcher browses the mock datasets" @@ -400,7 +417,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -410,7 +427,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "## Step 5 — Researcher writes and submits the inference job\n", @@ -422,7 +439,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -479,7 +496,7 @@ { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -498,7 +515,7 @@ }, { "cell_type": "markdown", - "id": "24", + "id": "25", "metadata": {}, "source": [ "## Step 6 — Enclave receives and distributes the job\n", @@ -510,7 +527,7 @@ { "cell_type": "code", "execution_count": null, - "id": "25", + "id": "26", "metadata": {}, "outputs": [], "source": [ @@ -525,7 +542,7 @@ }, { "cell_type": "markdown", - "id": "26", + "id": "27", "metadata": {}, "source": [ "## Step 7 — Model owner and Benchmark owner approve\n", @@ -537,7 +554,7 @@ { "cell_type": "code", "execution_count": null, - "id": "27", + "id": "28", "metadata": {}, "outputs": [], "source": [ @@ -548,7 +565,7 @@ }, { "cell_type": "markdown", - "id": "28", + "id": "29", "metadata": {}, "source": [ "## Step 8 — Enclave runs the job and distributes results\n", @@ -560,7 +577,7 @@ { "cell_type": "code", "execution_count": null, - "id": "29", + "id": "30", "metadata": {}, "outputs": [], "source": [ @@ -575,7 +592,7 @@ }, { "cell_type": "markdown", - "id": "30", + "id": "31", "metadata": {}, "source": [ "## Step 9 — Researcher retrieves the result" @@ -584,7 +601,7 @@ { "cell_type": "code", "execution_count": null, - "id": "31", + "id": "32", "metadata": {}, "outputs": [], "source": [ @@ -603,7 +620,7 @@ }, { "cell_type": "markdown", - "id": "32", + "id": "33", "metadata": {}, "source": [ "## Step 10 — Model owner and Benchmark owner also receive the result\n", @@ -614,7 +631,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33", + "id": "34", "metadata": {}, "outputs": [], "source": [ diff --git a/notebooks/enclave/nanolm/nbsplit/1. DO-model-owner-nanolm.ipynb b/notebooks/enclave/nanolm/nbsplit/1. DO-model-owner-nanolm.ipynb index 20fa803b7e9..d3042fc417e 100644 --- a/notebooks/enclave/nanolm/nbsplit/1. DO-model-owner-nanolm.ipynb +++ b/notebooks/enclave/nanolm/nbsplit/1. DO-model-owner-nanolm.ipynb @@ -160,9 +160,23 @@ ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "id": "14", "metadata": {}, + "outputs": [], + "source": [ + "# Fail on a wrong email, or if the peer has not approved yet. Warn if the peer\n", + "# was already there before this notebook logged in.\n", + "# attest_peer() below checks the enclave.\n", + "model_owner.validate_peer(RESEARCHER_EMAIL)\n", + "print(f\" Connected to {RESEARCHER_EMAIL}\")" + ] + }, + { + "cell_type": "markdown", + "id": "15", + "metadata": {}, "source": [ "### Step 1.2 — Attest enclave's identity" ] @@ -170,7 +184,7 @@ { "cell_type": "code", "execution_count": null, - "id": "15", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -180,7 +194,7 @@ }, { "cell_type": "markdown", - "id": "16", + "id": "17", "metadata": {}, "source": [ "## Step 2.1 — Dataset helpers" @@ -189,7 +203,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17", + "id": "18", "metadata": {}, "outputs": [], "source": [ @@ -238,7 +252,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -253,7 +267,7 @@ }, { "cell_type": "markdown", - "id": "19", + "id": "20", "metadata": {}, "source": [ "## Step 2.2 — Upload the model weights\n", @@ -265,7 +279,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -285,7 +299,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "## Step 3 — Wait for the Researcher to submit the job, then approve\n", @@ -296,7 +310,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -309,7 +323,7 @@ { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -320,7 +334,7 @@ }, { "cell_type": "markdown", - "id": "24", + "id": "25", "metadata": {}, "source": [ "## Step 4 — Receive results\n", @@ -331,7 +345,7 @@ { "cell_type": "code", "execution_count": null, - "id": "25", + "id": "26", "metadata": {}, "outputs": [], "source": [ diff --git a/notebooks/enclave/nanolm/nbsplit/2. DO-benchmark-owner-nanolm.ipynb b/notebooks/enclave/nanolm/nbsplit/2. DO-benchmark-owner-nanolm.ipynb index dd8ead10fee..490d9841f6a 100644 --- a/notebooks/enclave/nanolm/nbsplit/2. DO-benchmark-owner-nanolm.ipynb +++ b/notebooks/enclave/nanolm/nbsplit/2. DO-benchmark-owner-nanolm.ipynb @@ -160,9 +160,23 @@ ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "id": "14", "metadata": {}, + "outputs": [], + "source": [ + "# Fail on a wrong email, or if the peer has not approved yet. Warn if the peer\n", + "# was already there before this notebook logged in.\n", + "# attest_peer() below checks the enclave.\n", + "benchmark_owner.validate_peer(RESEARCHER_EMAIL)\n", + "print(f\" Connected to {RESEARCHER_EMAIL}\")" + ] + }, + { + "cell_type": "markdown", + "id": "15", + "metadata": {}, "source": [ "### Step 1.2 — Attest enclave's identity" ] @@ -170,7 +184,7 @@ { "cell_type": "code", "execution_count": null, - "id": "15", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -180,7 +194,7 @@ }, { "cell_type": "markdown", - "id": "16", + "id": "17", "metadata": {}, "source": [ "## Step 2.1 — Dataset helpers" @@ -189,7 +203,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17", + "id": "18", "metadata": {}, "outputs": [], "source": [ @@ -216,7 +230,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -233,7 +247,7 @@ }, { "cell_type": "markdown", - "id": "19", + "id": "20", "metadata": {}, "source": [ "## Step 2.2 — Upload the evaluation benchmark\n", @@ -244,7 +258,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -264,7 +278,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "## Step 3 — Wait for the Researcher to submit the job, then approve\n", @@ -275,7 +289,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -288,7 +302,7 @@ { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -299,7 +313,7 @@ }, { "cell_type": "markdown", - "id": "24", + "id": "25", "metadata": {}, "source": [ "## Step 4 — Receive results\n", @@ -310,7 +324,7 @@ { "cell_type": "code", "execution_count": null, - "id": "25", + "id": "26", "metadata": {}, "outputs": [], "source": [ diff --git a/notebooks/enclave/nanolm/nbsplit/3. DS-researcher-nanolm.ipynb b/notebooks/enclave/nanolm/nbsplit/3. DS-researcher-nanolm.ipynb index 392d41beec7..3314f5eec98 100644 --- a/notebooks/enclave/nanolm/nbsplit/3. DS-researcher-nanolm.ipynb +++ b/notebooks/enclave/nanolm/nbsplit/3. DS-researcher-nanolm.ipynb @@ -152,9 +152,24 @@ ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "id": "13", "metadata": {}, + "outputs": [], + "source": [ + "# Fail on a wrong email, or if the peer has not approved yet. Warn if the peer\n", + "# was already there before this notebook logged in.\n", + "# attest_peer() below checks the enclave.\n", + "for peer_email in [MODEL_OWNER_EMAIL, BENCHMARK_OWNER_EMAIL]:\n", + " researcher.validate_peer(peer_email)\n", + " print(f\" Connected to {peer_email}\")" + ] + }, + { + "cell_type": "markdown", + "id": "14", + "metadata": {}, "source": [ "### Step 1.2 — Attest enclave's identity" ] @@ -162,7 +177,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -172,7 +187,7 @@ }, { "cell_type": "markdown", - "id": "15", + "id": "16", "metadata": {}, "source": [ "## Step 2 — Browse the mock datasets" @@ -181,7 +196,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -191,7 +206,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "18", "metadata": {}, "source": [ "## Step 3 — Job helpers" @@ -200,7 +215,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -214,7 +229,7 @@ }, { "cell_type": "markdown", - "id": "19", + "id": "20", "metadata": {}, "source": [ "## Step 4 — Define the inference job\n", @@ -225,7 +240,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -281,7 +296,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "22", "metadata": {}, "source": [ "## Step 5 — Submit the job to the enclave" @@ -290,7 +305,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -310,7 +325,7 @@ }, { "cell_type": "markdown", - "id": "23", + "id": "24", "metadata": {}, "source": [ "## Step 6 — Wait for both DOs to approve and the enclave to run\n", @@ -321,7 +336,7 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -336,7 +351,7 @@ }, { "cell_type": "markdown", - "id": "25", + "id": "26", "metadata": {}, "source": [ "## Step 7 — View the results" @@ -345,7 +360,7 @@ { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "27", "metadata": {}, "outputs": [], "source": [ diff --git a/packages/syft-enclave/src/syft_enclaves/client.py b/packages/syft-enclave/src/syft_enclaves/client.py index 4d08d5bf9c3..5a7b6b39e6c 100644 --- a/packages/syft-enclave/src/syft_enclaves/client.py +++ b/packages/syft-enclave/src/syft_enclaves/client.py @@ -110,6 +110,9 @@ def approve_peer_request( def reject_peer_request(self, email_or_peer: str | Peer): self._rds.reject_peer_request(email_or_peer) + def validate_peer(self, peer_email: str) -> Peer: + return self._rds.validate_peer(peer_email) + def attest_peer( self, peer_email: str, diff --git a/packages/syft-enclave/tests/test_enclave_client.py b/packages/syft-enclave/tests/test_enclave_client.py index 909630906df..24ec47bc34f 100644 --- a/packages/syft-enclave/tests/test_enclave_client.py +++ b/packages/syft-enclave/tests/test_enclave_client.py @@ -3,6 +3,9 @@ os.environ["PRE_SYNC"] = "false" +import pytest + +from syft.sync.peers.peer import PeerSetupError from syft_enclaves import SyftEnclaveClient @@ -42,3 +45,11 @@ def approved_emails(client): # DS: all peers are accepted (both sides created folders) assert approved_emails(ds) == {do1.email, do2.email, enclave.email} + + +def test_validate_peer_accepts_live_peer_and_rejects_wrong_email(): + _, do1, _, ds = SyftEnclaveClient.quad_with_mock_drive_service_connection() + + assert ds.validate_peer(do1.email).email == do1.email + with pytest.raises(PeerSetupError, match="not a peer"): + ds.validate_peer("wrong@test.com") diff --git a/packages/syft-rds/src/syft_rds/client.py b/packages/syft-rds/src/syft_rds/client.py index c53a4f90cc9..30983ae49bb 100644 --- a/packages/syft-rds/src/syft_rds/client.py +++ b/packages/syft-rds/src/syft_rds/client.py @@ -265,6 +265,9 @@ def reject_peer_request(self, *args: Any, **kwargs: Any) -> Any: def load_peers(self, *args: Any, **kwargs: Any) -> Any: return self.sync_engine.load_peers(*args, **kwargs) + def validate_peer(self, *args: Any, **kwargs: Any) -> Any: + return self.sync_engine.validate_peer(*args, **kwargs) + def delete_syftbox(self, *args: Any, **kwargs: Any) -> Any: return self.sync_engine.delete_syftbox(*args, **kwargs) diff --git a/syft/sync/peers/peer.py b/syft/sync/peers/peer.py index 3b53e1a6163..82201a9c3e8 100644 --- a/syft/sync/peers/peer.py +++ b/syft/sync/peers/peer.py @@ -6,6 +6,14 @@ from syft.sync.version.version_info import VersionInfo +class PeerSetupError(ValueError): + """A peer is unknown, not approved, or not shown to be a live connection.""" + + +class PeerNotReadyError(PeerSetupError): + """The peer can still become valid: it did not approve yet, or log in recently.""" + + class PeerState(str, Enum): ACCEPTED = "accepted" REQUESTED_BY_PEER = "requested_by_peer" diff --git a/syft/sync/syftbox_manager.py b/syft/sync/syftbox_manager.py index 2fe36d09378..61ad24d8ced 100644 --- a/syft/sync/syftbox_manager.py +++ b/syft/sync/syftbox_manager.py @@ -462,6 +462,7 @@ class SyftboxManager(BaseModelCallbackMixin): "load_peers", "approve_peer_request", "reject_peer_request", + "validate_peer", "sync", "create_checkpoint", "should_create_checkpoint", @@ -1009,6 +1010,18 @@ def reject_peer_request(self, email_or_peer: str | Peer): """Reject a pending peer request. Delegates to PeerManager.""" self.peer_manager.reject_peer_request(email_or_peer) + def validate_peer(self, peer_email: str) -> Peer: + """Load the peers, then return ``peer_email`` if it is approved. + + Use it after peering, before the rest of a notebook runs. The rules are + in ``PeerManager.validate_peer``. + + Raises: + PeerSetupError: ``peer_email`` is not approved. + """ + self.load_peers() + return self.peer_manager.validate_peer(peer_email) + # ========== Encryption key fingerprints ========== @property @@ -1193,6 +1206,7 @@ def delete_syftbox( # Clear in-memory caches and filesystem cache contents self._clear_caches() + self.peer_manager.forget_states_at_start() self.reset_all_connection_caches() # Delete local syftbox folder and cache directories diff --git a/syft/sync/version/peer_manager.py b/syft/sync/version/peer_manager.py index f14dbd1c9ca..9df67c11fa3 100644 --- a/syft/sync/version/peer_manager.py +++ b/syft/sync/version/peer_manager.py @@ -25,7 +25,7 @@ format_fingerprint, normalize_fingerprint, ) -from syft.sync.peers.peer import Peer, PeerState +from syft.sync.peers.peer import Peer, PeerNotReadyError, PeerSetupError, PeerState from syft.sync.peers.peer_store import PeerStore, datasite_crypto_keys_path from syft.sync.utils.print_utils import ( print_peer_already_connected, @@ -43,6 +43,7 @@ logger = logging.getLogger(__name__) + # Key wrapping the DID document inside a published encryption bundle file. BUNDLE_FILE_KEY = "public_encryption_bundle" @@ -173,6 +174,9 @@ class PeerManager(BaseModel): _loaded_peer_versions: Dict[str, Optional[VersionInfo]] = PrivateAttr( default_factory=dict ) + # Peer email -> state at the first load_peers(), for accepted peers and + # waiting requests. None until that load. + _states_at_start: Optional[Dict[str, PeerState]] = PrivateAttr(default=None) # ========== Peer List Properties ========== @@ -843,6 +847,13 @@ def load_peers(self, force_download: bool = False): email, PeerState.ACCEPTED.value ) + if self._states_at_start is None: + self._states_at_start = { + p.email: p.state + for p in peers + if p.state in (PeerState.ACCEPTED, PeerState.REQUESTED_BY_PEER) + } + # set_peers keeps the locally pinned bundle over whatever the Drive # copy of SYFT_peers.json holds, and validates any bundle it adopts. self.peer_store.set_peers(peers) @@ -873,6 +884,65 @@ def _pin_missing_peer_bundles(self, peers: List[Peer]) -> None: peer.email, peer.state.value, public_encryption_bundle=adopted ) + def validate_peer(self, peer_email: str) -> Peer: + """Return the peer ``peer_email`` if it is approved, else raise. + + If the peer was already approved, or already waiting for our approval, + at the first ``load_peers()`` of this client, warn: the connection can + be left over from an earlier run, with an account that is not in use + now. This is a setup check for demos, not authentication. + + Raises: + PeerNotReadyError: the peer did not approve the request yet. + PeerSetupError: the peer is unknown or rejected, or waits for + this client to approve its request. + """ + peer = self.get_cached_peer(peer_email) + if peer is None: + raise PeerSetupError( + f"{peer_email} is not a peer. Check the email, or add it with " + f"client.add_peer({peer_email!r})." + ) + if peer.is_requested_by_peer: + raise PeerSetupError( + f"{peer_email} is not approved yet: approve it with " + f"client.approve_peer_request({peer_email!r})." + ) + if peer.is_requested_by_me: + raise PeerNotReadyError( + f"{peer_email} has not approved the request yet. Check the email, " + "and make sure that the peer approved the request." + ) + if not peer.is_approved: + raise PeerSetupError( + f"{peer_email} is not approved (state: {peer.state.value})." + ) + self._warn_if_known_at_start(peer_email) + return peer + + def _warn_if_known_at_start(self, peer_email: str) -> None: + """Warn if ``peer_email`` was connected, or waiting, at the first load.""" + state = (self._states_at_start or {}).get(peer_email) + if state is None: + return + found = ( + "was already connected" + if state == PeerState.ACCEPTED + else "sent its request" + ) + warnings.warn( + f"{peer_email} {found} before this client started. If this email " + "is wrong, the connection can be left over from an earlier run." + ) + + def forget_states_at_start(self) -> None: + """Count no peer as there at start, for the rest of this session. + + Call it after this client deletes its state. Its peers then connect + again from nothing, so ``validate_peer`` does not warn about them. + """ + self._states_at_start = {} + def check_peer_request_exists(self, email: str) -> bool: """Check if a peer request exists for the given email.""" return any(p.email == email for p in self.requested_by_peer_peers) diff --git a/tests/unit/test_validate_peer.py b/tests/unit/test_validate_peer.py new file mode 100644 index 00000000000..1610cdababc --- /dev/null +++ b/tests/unit/test_validate_peer.py @@ -0,0 +1,82 @@ +import pytest + +from syft.sync.peers.peer import PeerNotReadyError, PeerSetupError +from syft.sync.syftbox_manager import SyftboxManager + + +def _pair(add_peers: bool): + return SyftboxManager.pair_with_mock_drive_service_connection( + email1="do@test.com", email2="ds@test.com", add_peers=add_peers + ) + + +def _start_both_then_request(ds_manager, do_manager): + """Both clients load their peers, then the DS sends its request.""" + do_manager.load_peers() + ds_manager.add_peer(do_manager.email) + + +def test_peer_connected_in_this_session_is_valid(): + ds_manager, do_manager = _pair(add_peers=False) + _start_both_then_request(ds_manager, do_manager) + do_manager.approve_peer_request(ds_manager.email) + + assert ds_manager.validate_peer(do_manager.email).email == do_manager.email + assert do_manager.validate_peer(ds_manager.email).email == ds_manager.email + + +def test_unapproved_peer_is_invalid(): + ds_manager, do_manager = _pair(add_peers=False) + ds_manager.add_peer(do_manager.email) + + with pytest.raises(PeerNotReadyError, match="not approved"): + ds_manager.validate_peer(do_manager.email) + + +def test_peer_approved_without_request_is_invalid_until_peer_connects(): + # approve_peer_request(..., peer_must_exist=False) with a wrong email only + # sends a request; the peer is not connected. + ds_manager, do_manager = _pair(add_peers=False) + do_manager.approve_peer_request(ds_manager.email, peer_must_exist=False) + + with pytest.raises(PeerNotReadyError, match="not approved"): + do_manager.validate_peer(ds_manager.email) + + ds_manager.add_peer(do_manager.email) + assert do_manager.validate_peer(ds_manager.email).is_approved + + +def test_leftover_connection_warns_and_passes(): + ds_manager, do_manager = _pair(add_peers=True) + # The DS loaded peers first after the DO approved: the connection was + # already there when the DS client started. + + with pytest.warns(UserWarning, match="already connected before this client"): + peer = ds_manager.validate_peer(do_manager.email) + assert peer.is_approved + + +def test_request_waiting_at_start_warns_once_approved(): + # The DS request was already there when the DO client started. + ds_manager, do_manager = _pair(add_peers=False) + ds_manager.add_peer(do_manager.email) + + with pytest.raises(PeerSetupError, match="approve_peer_request"): + do_manager.validate_peer(ds_manager.email) + do_manager.approve_peer_request(ds_manager.email) + with pytest.warns(UserWarning, match="sent its request before this client"): + assert do_manager.validate_peer(ds_manager.email).is_approved + + +def test_reset_then_re_peer_in_the_same_session_is_valid(recwarn): + ds_manager, do_manager = _pair(add_peers=True) # connected at start + for manager in (ds_manager, do_manager): + manager.delete_syftbox(verbose=False, broadcast_delete_events=False) + manager.peer_manager.write_own_version() + + ds_manager.add_peer(do_manager.email) + do_manager.approve_peer_request(ds_manager.email, peer_must_exist=False) + + assert ds_manager.validate_peer(do_manager.email).is_approved + assert do_manager.validate_peer(ds_manager.email).is_approved + assert not [w for w in recwarn if "before this client started" in str(w.message)]