Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions evaluations/certified-variables.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"skill": "certified-variables",
"description": "Evaluation cases for the certified-variables skill. Tests whether agents fetch certificates with query calls, verify witnesses with the current @dfinity/certificate-verification and @icp-sdk/core APIs, know that certified data survives upgrades while heap trees do not, know what the HTTP gateway does and does not verify, certify http_request responses (including fallbacks) so the gateway accepts them, and write CertTree-backed Motoko actors that compile.",
"output_evals": [
{
"name": "Adversarial: certified getter traps when called from icp-cli",
"prompt": "My Rust canister has a `#[query] fn get(key: String)` that calls `ic_cdk::api::data_certificate().expect(\"data_certificate only available in query calls\")`. Running `icp canister call backend get '(\"greeting\")'` traps with that message. Why, and what is the fix? Just the cause and the corrected command.",
"expected_behaviors": [
"Explains that `icp canister call` sends an update call by default, even for a query method, and that data_certificate() returns None outside a query call",
"Gives the corrected command with the `--query` flag (e.g. `icp canister call --query backend get '(\"greeting\")'`)",
"Does NOT tell the user to move certified_data_set into the query or to change the method to an update"
]
},
{
"name": "Frontend witness verification with certificate-verification 4",
"prompt": "Write a TypeScript function that verifies a certified key-value response `{ value: string | null; certificate: Uint8Array; witness: Uint8Array }` from my canister (keys are inserted as UTF-8 bytes) using @dfinity/certificate-verification 4 and @icp-sdk/core 6, and returns the verified value or null. Just the function.",
"expected_behaviors": [
"Calls verifyCertification with Uint8Array certificate, witness and rootKey (no ArrayBuffer conversions) and a maxCertificateTimeOffsetMs",
"Checks the status of the lookup_path result (LookupPathStatus.Found / Absent) instead of treating lookup_path's return value as the raw bytes",
"Returns null only for Absent and treats Unknown (or Error) as a failure, not as an absent key",
"Compares the canister-returned value with the value proven by the witness"
]
},
{
"name": "Adversarial: certified queries fail after a Rust canister upgrade",
"prompt": "My Rust canister keeps an ic_certification RbTree in a thread_local and certifies its root hash in every update. After an upgrade, clients report 'Tree root hash did not match the certified data'. Someone says certified data is cleared on upgrade. Is that the cause, and what is the fix? Short answer, no code beyond the post_upgrade hook.",
"expected_behaviors": [
"States that certified data is NOT cleared on upgrade (it survives; only install/reinstall start it empty)",
"Identifies the real cause: the thread_local RbTree is wiped on upgrade, so the kept hash no longer matches the tree",
"Fix: rebuild the tree (from stable storage) in #[post_upgrade] and call certified_data_set with the new root hash"
]
},
{
"name": "Adversarial: gateway assumed to verify Candid query calls",
"prompt": "My React app is served from https://<id>.icp.net, and it reads the user's balance with a `get_balance` query through the actor generated by @icp-sdk/bindgen. The HTTP gateway already verifies certificates, so the balance is trustworthy, right? Short answer: what verifies what, and what should I do if the balance must be trustworthy?",
"expected_behaviors": [
"States that the HTTP gateway verifies only HTTP responses (the frontend assets), not the Candid API query call the actor makes",
"Explains that a query response is answered by a single replica (only a node signature), so it is not consensus-verified",
"Recommends either certifying the balance (certified data + witness, verified with @dfinity/certificate-verification) or calling it as an update call"
]
},
{
"name": "Adversarial: CertTree declarations in a persistent Motoko actor",
"prompt": "Show just the declarations for a Motoko persistent actor that keeps a certified map with the mops ic-certification package's CertTree: the store, the ops object, and the init-time certification call. No methods. Do I also need a postupgrade hook to re-set the certified data?",
"expected_behaviors": [
"Declares the store as `CertTree.newStore()` and the ops object with `transient` (e.g. `transient let ct = CertTree.Ops(certStore)`), not as a plain stable `let`",
"Calls ct.setCertifiedData() at init (in the actor body)",
"Says no postupgrade hook is needed: the CertTree.Store persists and the certified data survives upgrades"
]
},
{
"name": "Adversarial: ic-http-certification header and fallback errors",
"prompt": "My Rust canister serves `/hello` from `http_request` using ic-http-certification 4. First, `HttpCertification::response_only(&cel, &response, None)` returned `CertificateExpressionHeaderMissing`. After fixing that, `/hello` works through `https://<id>.icp.net`, but every other path returns `backend_response_verification` instead of a 404. Explain both errors and the fix for each. Short answer, no full canister code.",
"expected_behaviors": [
"Explains that the `IC-CertificateExpression` header (carrying the CEL expression) must be in the response before it is certified",
"Explains that the 404 for other paths is uncertified, so the gateway rejects it",
"Fixes it by certifying a response for those paths under a wildcard path (e.g. `HttpCertificationPath::wildcard(\"/\")`) and serving it with its witness",
"Does NOT suggest using the raw domain (`<id>.raw.icp.net`) as the fix"
]
},
{
"name": "Adversarial: certify the initial value of a Motoko certified variable",
"prompt": "Write a minimal Motoko persistent actor that certifies a single Text value with mo:core/CertifiedData (hash it with the mops sha2 package): a setter and a query getter returning { value; certificate }. Just the actor, no deploy steps.",
"expected_behaviors": [
"Certifies the initial value at install (a CertifiedData.set call in the actor body or init), not only inside the setter",
"Uses the same hashing/certification step after every change in the setter",
"The getter is a query that returns CertifiedData.getCertificate() as the certificate",
"Hashes the value to 32 bytes (e.g. SHA-256) before calling CertifiedData.set"
]
}
],
"trigger_evals": {
"description": "Queries to test whether the skill activates correctly. 'should_trigger' queries should cause the skill to load; 'should_not_trigger' queries should NOT activate this skill.",
"should_trigger": [
"How do I make my canister's query responses verifiable on the client?",
"verifyCertification throws 'Tree root hash did not match the certified data in the certificate'",
"Certify the responses of my Rust canister's http_request so the HTTP gateway accepts them",
"Do I need to verify query responses from my canister in the frontend, or does the gateway do that?"
],
"should_not_trigger": [
"Deploy my React frontend to the IC with the static-site recipe",
"How do I keep a StableBTreeMap across canister upgrades?"
]
}
}
Loading
Loading