# Function Map V1 Contract > **Predicate Type:** `https://stella.ops/predicates/function-map/v1` > **DSSE Payload Type:** `application/vnd.stellaops.function-map.v1+json` > **Schema Version:** `1.0.0` ## Overview A function map predicate declares the expected call paths for a service component, enabling verification of runtime behavior against static analysis. It follows the [in-toto attestation](https://github.com/in-toto/attestation) framework. --- ## Predicate Schema ```json { "type": "https://stella.ops/predicates/function-map/v1", "subject": { "purl": "pkg:oci/my-service@sha256:abc123...", "digest": { "sha256": "abc123..." } }, "predicate": { "service": "my-backend", "build_id": "build-456", "expected_paths": [...], "coverage": { "min_observation_rate": 0.95, "window_seconds": 1800, "fail_on_unexpected": false }, "generated_at": "2026-01-23T10:00:00Z", "generated_from": { "sbom_ref": "oci://registry/sbom@sha256:...", "static_analysis_ref": "oci://registry/analysis@sha256:..." }, "generator": { "name": "stella-cli", "version": "2.0.0", "commit": "abc123" } } } ``` --- ## Subject | Field | Type | Required | Description | |-------|------|----------|-------------| | `purl` | string | Yes | Package URL of the subject artifact | | `digest` | object | Yes | Content digest (sha256, sha512, etc.) | --- ## Predicate Fields | Field | Type | Required | Description | |-------|------|----------|-------------| | `service` | string | Yes | Service name for correlation | | `build_id` | string | No | Build identifier for provenance correlation | | `expected_paths` | array | Yes | List of expected call paths | | `coverage` | object | Yes | Coverage thresholds for verification | | `generated_at` | ISO 8601 | Yes | Generation timestamp | | `generated_from` | object | No | Source references (SBOM, static analysis) | | `generator` | object | No | Tool that generated the predicate | --- ## Expected Path Each expected path represents a call chain starting from an entrypoint: ```json { "path_id": "path-001", "entrypoint": { "symbol": "handleRequest", "node_hash": "sha256:..." }, "expected_calls": [ { "symbol": "crypto_sign", "purl": "pkg:deb/libcrypto3@3.0.0", "node_hash": "sha256:...", "probe_types": ["uprobe"], "optional": false, "function_address": null, "binary_path": "/usr/lib/libcrypto.so.3" } ], "path_hash": "sha256:...", "optional": false, "strict_ordering": false, "tags": ["crypto"] } ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `path_id` | string | Yes | Unique path identifier | | `entrypoint` | object | Yes | Path entry point (symbol + node_hash) | | `expected_calls` | array | Yes | List of expected function calls | | `path_hash` | string | Yes | SHA-256(entrypoint \|\| sorted calls) | | `optional` | boolean | No | Whether this path is optional (default false) | | `strict_ordering` | boolean | No | Ordered sequence vs unordered set (default false) | | `tags` | array | No | Categorization tags (crypto, auth, network, etc.) | --- ## Expected Call | Field | Type | Required | Description | |-------|------|----------|-------------| | `symbol` | string | Yes | Function name (demangled) | | `purl` | string | Yes | Package URL of the component containing this function | | `node_hash` | string | Yes | SHA-256(PURL + normalized symbol) | | `probe_types` | array | Yes | Acceptable probe types for observation | | `optional` | boolean | No | Whether this call is optional (default false) | | `function_address` | string | No | Address hint for probe attachment | | `binary_path` | string | No | Binary path for uprobe attachment | ### Probe Types | Type | Description | |------|-------------| | `kprobe` | Kernel function entry | | `kretprobe` | Kernel function return | | `uprobe` | User-space function entry | | `uretprobe` | User-space function return | | `tracepoint` | Kernel tracepoint | | `usdt` | User-space statically defined tracing | --- ## Coverage Thresholds | Field | Type | Default | Description | |-------|------|---------|-------------| | `min_observation_rate` | double | 0.95 | Minimum fraction of paths that must be observed | | `window_seconds` | integer | 1800 | Observation window duration | | `fail_on_unexpected` | boolean | false | Whether unexpected symbols cause verification failure | --- ## Node Hash Recipe Node hashes provide content-addressable identifiers for function calls, matching the [Witness V1](witness-v1.md) convention: ``` node_hash = SHA-256(PURL + ":" + normalize(symbol)) ``` Where `normalize(symbol)`: 1. Demangle C++/Rust symbols 2. Strip leading underscores (platform convention) 3. Lowercase the result 4. Remove whitespace ### Path Hash Recipe ``` path_hash = SHA-256(entrypoint.node_hash + ":" + sort(calls.map(c => c.node_hash)).join(":")) ``` The path hash is independent of call ordering (sorted) unless `strict_ordering` is true, in which case calls are not sorted before hashing. --- ## Coverage Calculation Algorithm ``` total_required = count(paths where optional == false) observed_required = count(paths where optional == false AND has_matching_observation) observation_rate = observed_required / total_required = 0.0 if total_required == 0 verified = observation_rate >= coverage.min_observation_rate ``` For each path, an observation "matches" when: - At least one observation has a `node_hash` matching any call in the path - The observation falls within the time window - The probe type is in the call's `probe_types` list --- ## Verification Algorithm ``` VERIFY(predicate, observations, options): 1. Filter observations to time window [now - window_seconds, now] 2. For each required expected_path: a. For each expected_call in path: - Find observations matching node_hash AND probe_type - Mark call as "observed" if any match found b. Mark path as "covered" if entrypoint OR any call observed 3. Compute observation_rate = covered_paths / required_paths 4. Collect unexpected = observations not matching any expected call 5. Collect missing = required calls with no matching observation 6. verified = observation_rate >= min_observation_rate AND (NOT fail_on_unexpected OR unexpected.count == 0) 7. Return result with breakdown, unexpected, missing ``` --- ## Media Types | Usage | Media Type | |-------|-----------| | Function map predicate | `application/vnd.stella.function-map+json` | | DSSE-signed predicate | `application/vnd.dsse+json` | | Observations | `application/x-ndjson` | | Verification report | `application/vnd.stella.verification-report+json` | --- ## Observation Record (NDJSON) Each line in an observations file: ```json { "observation_id": "obs-123", "node_hash": "sha256:...", "function_name": "crypto_sign", "probe_type": "uprobe", "observed_at": "2026-01-23T10:05:00Z", "observation_count": 42, "container_id": "abc123", "pod_name": "my-service-pod-xyz", "namespace": "production", "duration_microseconds": 150 } ```