Skip to main content

calimero_node_primitives/bundle/
mod.rs

1mod signature;
2
3pub use signature::{
4    canonicalize_manifest, compute_bundle_hash, compute_signing_payload, decode_public_key,
5    decode_signature, derive_signer_id_did_key, format_bundle_hash, sign_manifest_json,
6    verify_ed25519, verify_manifest_signature, ManifestVerification,
7};
8
9use serde::{Deserialize, Serialize};
10
11/// Represents an artifact within a bundle (WASM, ABI, migration)
12#[derive(Clone, Debug, Deserialize, Serialize)]
13#[serde(rename_all = "camelCase")]
14pub struct BundleArtifact {
15    pub path: String,
16    pub hash: Option<String>,
17    pub size: u64,
18}
19
20/// Display metadata for the application
21#[derive(Clone, Debug, Deserialize, Serialize)]
22#[serde(rename_all = "camelCase")]
23pub struct BundleMetadata {
24    pub name: String,
25    pub description: Option<String>,
26    pub icon: Option<String>,
27    #[serde(default)]
28    pub tags: Vec<String>,
29    pub license: Option<String>,
30}
31
32/// Declarative interfaces (intents) implemented or required by the application
33#[derive(Clone, Debug, Default, Deserialize, Serialize)]
34#[serde(rename_all = "camelCase")]
35pub struct BundleInterfaces {
36    #[serde(default)]
37    pub exports: Vec<String>,
38    #[serde(default)]
39    pub uses: Vec<String>,
40}
41
42/// External links for the application
43#[derive(Clone, Debug, Default, Deserialize, Serialize)]
44#[serde(rename_all = "camelCase")]
45pub struct BundleLinks {
46    pub frontend: Option<String>,
47    pub github: Option<String>,
48    pub docs: Option<String>,
49}
50
51/// Cryptographic signature of the manifest
52///
53/// The signature is computed over the SHA-256 hash of the canonical manifest bytes (RFC 8785 JCS) with the `signature` field excluded.
54#[derive(Clone, Debug, Deserialize, Serialize)]
55#[serde(rename_all = "camelCase")]
56pub struct BundleSignature {
57    /// Signature algorithm identifier. MUST be "ed25519" in v0.
58    pub algorithm: String,
59    /// Ed25519 public key encoded as base64url (no padding).
60    pub public_key: String,
61    /// Signature over canonical manifest encoded as base64url (no padding).
62    pub signature: String,
63    /// Optional ISO 8601 timestamp of signing.
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub signed_at: Option<String>,
66}
67
68/// Bundle manifest describing the contents of a bundle archive
69#[derive(Clone, Debug, Deserialize, Serialize)]
70#[serde(rename_all = "camelCase")]
71pub struct BundleManifest {
72    pub version: String,
73    pub package: String,
74    pub app_version: String,
75
76    /// The signerId (did:key) derived from the signing public key.
77    ///
78    /// This field is **required** for all bundle manifests. Both `signer_id` and `signature`
79    /// must be present for bundle installation. The `signer_id` must match the signerId derived
80    /// from the signature's public key during verification.
81    ///
82    /// The field is `Option<String>` at the type level for deserialization flexibility, but
83    /// `verify_manifest_signature` will reject manifests where this field is `None`.
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub signer_id: Option<String>,
86
87    /// Minimum required runtime version (semver).
88    pub min_runtime_version: String,
89
90    #[serde(default)]
91    pub metadata: Option<BundleMetadata>,
92
93    #[serde(default)]
94    pub interfaces: Option<BundleInterfaces>,
95
96    pub wasm: Option<BundleArtifact>,
97    pub abi: Option<BundleArtifact>,
98
99    #[serde(default)]
100    pub migrations: Vec<BundleArtifact>,
101
102    #[serde(default)]
103    pub links: Option<BundleLinks>,
104
105    #[serde(default)]
106    pub signature: Option<BundleSignature>,
107}