Skip to content

fix(certified-variables): update to certificate-verification 4 and fix broken examples - #407

Open
marc0olo wants to merge 8 commits into
mainfrom
fix/certified-variables-deps
Open

marc0olo wants to merge 8 commits into
mainfrom
fix/certified-variables-deps

Conversation

@marc0olo

@marc0olo marc0olo commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

The certified-variables skill is brought up to date with @dfinity/certificate-verification 4.0.0, which peers @icp-sdk/core ^6, and with the current Rust and Motoko libraries. Every code block was compiled, deployed to a local network (icp-cli 1.5.0) and exercised end to end, and several were broken on main.

Broken on main, now fixed:

  • Frontend verification did not type-check against certificate-verification 4 / core 6. The parameters are now Uint8Array, not ArrayBuffer. lookup_path returns a LookupResult, not bytes, so the old if (!leafData) check never fired. The new code switches on Found/Absent and rejects Unknown. Treating Unknown as absent would let a replica hide a real value behind a witness for a different key (new pitfall 9).
  • The Motoko CertTree example did not compile. let ct = CertTree.Ops(...) fails with M0131 in a persistent actor and needs transient. The deprecated postupgrade hook is dropped.
  • The Rust example failed icp deploy. It lacked ic_cdk::export_candid!(), so the Rust recipe failed with get_candid_pointer.
  • Every icp canister call … get was wrong. icp-cli sends an update call unless --query is passed, so the Rust getter trapped and the Motoko getters returned certificate = null.
  • The upgrade pitfall was wrong. Certified data survives upgrades (abstract-behavior.md:2690-2693, confirmed locally). What is lost is a heap tree, so Rust must rebuild it and re-set the hash, while Motoko's CertTree.Store needs nothing.
  • The HTTP certification snippet was incomplete. It had no http_request handler, no witness header, and no IC-CertificateExpression header in the certified response. The last one makes ic-http-certification 4 return CertificateExpressionHeaderMissing. It is replaced by a complete minimal canister, moved to references/http-certification.md.

Restructured for agents. The skill now opens with "Who Verifies What", which answers whether client-side verification is needed and with which library:

Response Verified by
HTTP via <id>.icp.net or a custom domain the gateway
HTTP via raw or your own client nobody; use @dfinity/response-verification
Update call through an actor the agent
Candid query only the answering node's signature; use certified data plus @dfinity/certificate-verification

The ICRC-3 tip certificate is covered as a use case.

The body shrinks from 482 to about 370 lines, and the size warning is gone:

  • Overlapping pitfalls are merged.
  • The conceptual diagram is dropped.
  • The deploy walkthrough and "Verify It Works" become a two-command check.
  • The HTTP material moves to a reference.

Updated:

  • Rust: ic-cdk 0.20, ic-certification 4 (same RbTree API as ic-certified-map, and what the official examples use), ic-http-certification 4.
  • New no-witness frontend path (Certificate.create + certified_data) for the single-value Motoko example, linking motoko/cert-var.
  • Root key guidance now follows the ic_env cookie, or icp network status --json in Node, with the same serving-network caveat as fix(icp-cli): drop false claim that createActor ignores { agent } #405.
  • Certified assets point to the static-site skill instead.
Verification (local network)
Check Result
Rust KV (ic-certification 4 / ic-cdk 0.20), Motoko CertTree present → value; missing → proof of absence; tampered value → throws; other key's witness → Unknown, throws
Motoko single value, verifySingleValue fresh install and after a set both verify; tampered value throws
HTTP canister through the local gateway 200 hello, and a certified 404 for other paths. A variant serving an uncertified body is rejected with backend_response_verification; certifying without IC-CertificateExpression returns CertificateExpressionHeaderMissing
Upgrade without re-setting Motoko single value still verifies; Rust verifies with a proof of absence after post_upgrade
Local gateway, tampered response rejected on <id>.localhost, served on <id>.raw.localhost
Mainnet ckBTC ledger icrc3_get_tip_certificate verifyCertification passes; last_block_index and last_block_hash are Found
Eval results (new file, all cases with baseline, rerun on the restructured skill)
  • Case 1, "Adversarial: certified getter traps when called from icp-cli": WITH 3/3 | WITHOUT 3/3. This is a regression guard for the --query pitfall.
  • Case 2, "Frontend witness verification with certificate-verification 4": WITH 4/4 (twice) | WITHOUT 3/4. The baseline returns null regardless of lookup status; a later baseline run timed out.
  • Case 3, "Adversarial: certified queries fail after a Rust canister upgrade": WITH 3/3 (three runs) | WITHOUT 1/3, 2/3, 1/3. The baseline claims certified data is reset on upgrade.
  • Case 4 (new), "Adversarial: gateway assumed to verify Candid query calls": WITH 3/3 | WITHOUT 3/3. This is a regression guard for the decision table.
  • Case 5, "Adversarial: CertTree declarations in a persistent Motoko actor": WITH 3/3 (twice) | WITHOUT 2/3. The baseline insists on a postupgrade hook.
  • Case 6, "Adversarial: ic-http-certification header and fallback errors": WITH 4/4 (three runs) | WITHOUT 4/4, 4/4, 3/4. This is a regression guard for pitfall 9 and the certified 404.
  • Case 7, "Adversarial: certify the initial value of a Motoko certified variable": WITH 4/4 (twice) | WITHOUT 3/4 (twice). The baseline never certifies the initial value.
  • Triggers: should-trigger 4/4, should-not-trigger 2/2.

Refs #406 (its certified-variables row: the rootKey type fix is done here). The developer-docs guides with the same errors are fixed in dfinity/developer-docs#408.

…x broken examples

Frontend code moves to @dfinity/certificate-verification 4 and @icp-sdk/core 6
(Uint8Array, LookupResult statuses) and gains a no-witness path. Rust moves to
ic-cdk 0.20 and ic-certification 4 with export_candid; the Motoko CertTree
example compiles again. The HTTP certification example is complete and moves
to a reference. Certified getters are tested with icp canister call --query,
and the upgrade pitfall now matches the spec. Adds the first eval file.
@github-actions

github-actions Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Skill Validation Report

Validating skill: /home/runner/work/icskills/icskills/skills/certified-variables

Structure

  • Pass: SKILL.md found
  • Pass: all files in references/ are referenced

Frontmatter

  • Pass: name: "certified-variables" (valid)
  • Pass: description: (570 chars)
  • Pass: license: "Apache-2.0"
  • Pass: compatibility: (16 chars)
  • Pass: metadata: (2 entries)

Markdown

  • Pass: no unclosed code fences found

Tokens

File Tokens
SKILL.md body 4,628
references/http-certification.md 1,219
Total 5,847

Content Analysis

Metric Value
Word count 2,498
Code block ratio 0.41
Imperative ratio 0.04
Information density 0.23
Instruction specificity 1.00
Sections 13
List items 12
Code blocks 7

References Content Analysis

Metric Value
Word count 526
Code block ratio 0.62
Imperative ratio 0.00
Information density 0.31
Instruction specificity 1.00
Sections 1
List items 0
Code blocks 3

Contamination Analysis

Metric Value
Contamination level medium
Contamination score 0.42
Primary language category javascript
Scope breadth 5
  • Warning: Language mismatch: config, shell, systems (3 categories differ from primary)

References Contamination Analysis

Metric Value
Contamination level medium
Contamination score 0.27
Primary language category config
Scope breadth 5
  • Warning: Language mismatch: shell, systems (2 categories differ from primary)

Result: passed

Project Checks


✓ Project checks passed for 1 skills (0 warnings)

Adds a verified decision table (HTTP gateway, update calls, Candid queries,
raw hosts) and the ICRC-3 tip certificate case, merges overlapping pitfalls,
and replaces the deploy walkthrough with a two-command check.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Initial-value verification, nullable certificate handling, and HTTP fallback certification remain incorrect, with additional eval coverage gaps.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 Medium severity · 1 Low severity

Open (3)
What changed in this PR

Updates the certified-variables skill for current IC certification libraries and correct verification patterns.

Changes:

  • Modernizes Rust, Motoko, and TypeScript examples.
  • Adds complete HTTP certification guidance.
  • Adds regression and trigger evaluations.
File Description
skills/​certified-variables/​SKILL.md Updates certification guidance and examples.
skills/​certified-variables/​references/​http-certification.md Adds a custom HTTP canister example.
evaluations/​certified-variables.json Adds skill evaluation cases.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread skills/certified-variables/SKILL.md
Comment thread skills/certified-variables/references/http-certification.md Outdated
Comment thread evaluations/certified-variables.json Outdated
The Motoko single-value actor now certifies its initial value, since
certified data starts empty. The HTTP reference certifies a wildcard 404 so
other paths do not fail gateway verification. Restores the CertTree eval.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The new certificate-expression pitfall lacks an output regression evaluation.

Review effort: Balanced
Findings: None

Resolved since last review (3)
Previously missed (1)

In code that hasn't changed since last review

Low severity Missing output eval for IC-CertificateExpression requirement

skills/​certified-variables/​SKILL.md:72

Pitfall 9 is newly introduced, but none of the five output evals checks that an agent includes IC-CertificateExpression in the response before certification (or recognizes CertificateExpressionHeaderMissing). The HTTP trigger case only tests skill activation, so this easy-to-regress requirement has no content-level regression coverage. Add a focused output eval for this pitfall.

@marc0olo

Copy link
Copy Markdown
Member Author

Re the latest Copilot review: added in 048a780 as case 6 ("Adversarial: ic-http-certification header and fallback errors"). It covers pitfall 9 (CertificateExpressionHeaderMissing → the IC-CertificateExpression header must be in the certified response) and the certified wildcard 404 from the reference. Results: WITH 4/4 in three runs | WITHOUT 4/4, 4/4, 3/4, so it is a regression guard. A first draft expected details the prompt did not ask for (the prompt says /hello already works); the expectations were rescoped to the question.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The new witness-free single-value verification flow lacks corresponding regression coverage.

Review effort: Balanced
Findings: None

Previously missed (1)

In code that hasn't changed since last review

Low severity Add output evaluation for single-value verification path

evaluations/​certified-variables.json:60

The new “single value without a witness” verification path has no output eval, while the parallel witness flow does. Add a scoped case so regressions in Certificate.create, the certified_data lookup, or the SHA-256 comparison are caught.

@marc0olo
marc0olo marked this pull request as ready for review September 25, 2026 13:40
@marc0olo
marc0olo requested review from a team and JoshDFN as code owners September 25, 2026 13:40
Also states that the Rust example keeps its tree on the heap only.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The examples and evaluations are consistent, with only a minor non-blocking grammar correction noted.

Review effort: Balanced
Findings: None

Previously missed (1)

In code that hasn't changed since last review

Low severity Clarify that the following code is the complete example

skills/​certified-variables/​references/​http-certification.md:3

This sentence is a fragment. Make it explicit that the code below is the complete example so the introduction reads grammatically.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The fresh-install certification fix needs a regression evaluation before approval.

Review effort: Balanced
Findings: None

Previously missed (2)

In code that hasn't changed since last review

Low severity Add regression coverage for install-time certification behavior

evaluations/​certified-variables.json:60

The newly added install-time certification behavior has no regression eval, even though omitting it already caused the fresh-install example to fail earlier in this PR. Add a focused output case requiring the initial value to be certified in the actor body and the same helper to run after mutations.

Low severity Rewrite sentence fragment as a complete explanation

skills/​certified-variables/​references/​http-certification.md:3

This sentence is a fragment, so the reference introduction does not read as a complete explanation.

…tall-time certification

The verification helpers take the ?blob certificate the Motoko getters return
and fail clearly when it is null. Adds an eval case for certifying the
initial value at install, and fixes a sentence fragment in the HTTP reference.
@marc0olo

Copy link
Copy Markdown
Member Author

Re the latest Copilot review, addressed in 4f577cb:

  • Install-time certification now has regression coverage in case 7, "Adversarial: certify the initial value of a Motoko certified variable". WITH 4/4 in both runs | WITHOUT 3/4 in both runs; the baseline fails exactly the install-time item, never certifying the initial value until the first set.
  • The HTTP reference's introduction fragment is now a complete sentence.
  • Also from the parallel developer-docs#408 review: both verification helpers now accept the ?blob certificate that the Motoko getters return, and fail with a clear message when it is null. That was verified against live canisters: the Rust and Motoko witness paths and the single-value path still verify, and null throws.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The dynamic gateway command and no-witness verification eval coverage need correction.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
Previously missed (1)

In code that hasn't changed since last review

Low severity Hardcoded port breaks gateway connectivity on alternate ports

skills/​certified-variables/​references/​http-certification.md:109

The local check says to use gateway_url, but the command still hardcodes port 8000, so it fails for networks configured with gateway.port: 0 or any alternate port. Use the URL returned by icp network status --json; this matches the explicit guidance in skills/icp-cli/SKILL.md:310-320.

Comment thread skills/certified-variables/SKILL.md
@marc0olo

Copy link
Copy Markdown
Member Author

Re the latest Copilot review, addressed in 785291e:

  • The HTTP reference's local check now takes the gateway URL from icp network status --json instead of hardcoding port 8000. It was verified on a gateway.port: 0 network: /hello returned 200 with both certification headers, and /missing a certified 404.
  • Also from developer-docs#408: the witness helper accepts the Motoko CertTree getter's ?Blob value (Uint8Array | null, decoded as UTF-8) as well as the Rust opt text value. It was verified with the raw responses of both getters, including an absent key and a tampered value.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The documentation, examples, and evaluations are internally consistent with the stated fixes, with no unresolved issues found.

Review effort: Balanced
Findings: None

Resolved since last review (1)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants