Cookwala / حزمة التطوير والسيناريوهات / 004

Hash a recipe and see that the same document always gives the same hash

An executor cooks exactly one revision of a recipe and refuses any other. The hash is SHA-256 over RFC 8785 canonical JSON, without the hash and signature fields, so the hub, the CLI and every SDK agree on it.

الفئة: developer · الهدف: روبوتات في خدمة الناس · المستوى: beginner

اقرأ أولًا: /docs/CORE/ /docs/QUICKSTART/

الخطوات

  1. Fetch the shakshuka example from the hub. getRecipe

  2. Hash the fetched document. hash

  3. Hash the same recipe read from the repository checkout: the same bytes in a different order still give the same hash. hash

  4. Another recipe gives another hash; a changed byte anywhere would too. hash

  5. The two shakshuka hashes are identical and equal the recipeHash in the ExecuteRequest example.

النتيجة

You can compute the hash an ExecuteRequest must carry. Next: scenario 018 sends a request with the wrong hash and reads the refusal.

سطر الأوامر

cookwala hash examples/shakshuka.cookwala.json
cookwala hash examples/kofta-oven.cookwala.json
curl -s -X POST http://localhost:7878/v1/tools/hash -H 'Content-Type: application/json' -d "{\"doc\": $(cat examples/shakshuka.cookwala.json)}"

المخرجات المسجلة

الحالة: ok

[1] getRecipe: {"$schema": "https://cookwala.ai/v1/schemas/recipe.schema.json", "cookwala": "0.1.0", "id": "example-shakshuka", "revision": 2, "updated": "2026-10-03", "hash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "verification": {"level": "V2", "evidence": {"simulatorRuns": 1, "humanReviews": 1, "fieldReports": 0}, "reviewedBy": "fifi.cooking editorial", "notes": "Illustrative example for the spec; values are realistic but not field-verified."}, "dish": {"names": {"en": "Shakshuka", "ar": "شكشوكة", "fr": "Chakchouka"}, "cuisine": ["TN", "MA", "DZ", "LY"], "course": "main…
[2] hash: {"hash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841"}
[3] hash: {"hash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841"}
[4] hash: {"hash": "sha256:932c364ad759aa2d27905c30c198be08ea9a7ac80ac3b60068895818cbdb4720"}

الكود

التشغيل: python scenarios/out/004-hash-a-recipe/python.py

# Scenario 004: Hash a recipe and see that the same document always gives the same hash
# An executor cooks exactly one revision of a recipe and refuses any other. The hash is SHA-256 over RFC 8785 canonical JSON, without the hash and signature fields, so the hub, the CLI and every SDK agree on it.
# Run a hub first: python hub/cookwala_hub.py --recipes examples
import json, os
from cookwala.client import CookwalaClient, CookwalaProblem

def load(path):
    with open(path, encoding="utf-8") as f:
        return json.load(f)

def pick(obj, path):
    for part in path.replace("]", "").replace("[", ".").split("."):
        obj = obj[int(part)] if part.isdigit() else (len(obj) if part == "length" else obj.get(part))
    return obj

c = CookwalaClient(os.environ.get("COOKWALA_HUB", "http://localhost:7878"))


# Step 1: Fetch the shakshuka example from the hub.
recipe = c.get_recipe("shakshuka")
assert pick(recipe, "id") == "example-shakshuka", pick(recipe, "id")
print("ok", "id", "=", "example-shakshuka")
assert pick(recipe, "revision") == 2, pick(recipe, "revision")
print("ok", "revision", "=", 2)

# Step 2: Hash the fetched document.
fromHub = c.hash(recipe)
assert pick(fromHub, "hash") == "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", pick(fromHub, "hash")
print("ok", "hash", "=", "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841")

# Step 3: Hash the same recipe read from the repository checkout: the same bytes in a different order still give the same hash.
fromFile = c.hash(load("examples/shakshuka.cookwala.json"))
assert pick(fromFile, "hash") == "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", pick(fromFile, "hash")
print("ok", "hash", "=", "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841")

# Step 4: Another recipe gives another hash; a changed byte anywhere would too.
kofta = c.hash(load("examples/kofta-oven.cookwala.json"))
assert pick(kofta, "hash") == "sha256:932c364ad759aa2d27905c30c198be08ea9a7ac80ac3b60068895818cbdb4720", pick(kofta, "hash")
print("ok", "hash", "=", "sha256:932c364ad759aa2d27905c30c198be08ea9a7ac80ac3b60068895818cbdb4720")

# Step 5: The two shakshuka hashes are identical and equal the recipeHash in the ExecuteRequest example.
assert pick(fromHub, "hash") == "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", pick(fromHub, "hash")
print("ok", "hash", "=", "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841")
assert pick(fromFile, "hash") == "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", pick(fromFile, "hash")
print("ok", "hash", "=", "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841")

print("scenario complete")

scenarios/004-hash-a-recipe.json

السابق: 003 التالي: 005