448 lines
11 KiB
Markdown
448 lines
11 KiB
Markdown
# Change-Trace JSON Schema Contract
|
|
|
|
> **Version:** 1.0.0
|
|
> **Status:** Draft
|
|
> **Last Updated:** 2026-01-12
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
This document defines the JSON schema for Change-Trace artifacts (`trace.cdxchange.json`). All implementations must conform to this schema for interoperability.
|
|
|
|
---
|
|
|
|
## Schema Identifier
|
|
|
|
```
|
|
Schema URI: stella.change-trace/1.0
|
|
File Extension: .cdxchange.json
|
|
MIME Type: application/vnd.stella.change-trace+json
|
|
```
|
|
|
|
---
|
|
|
|
## Root Object
|
|
|
|
```json
|
|
{
|
|
"$schema": "https://stella-ops.org/schemas/change-trace/1.0/schema.json",
|
|
"schema": "stella.change-trace/1.0",
|
|
"subject": { ... },
|
|
"deltas": [ ... ],
|
|
"summary": { ... },
|
|
"analyzedAt": "2026-01-12T14:30:00.000Z",
|
|
"algorithmVersion": "1.0"
|
|
}
|
|
```
|
|
|
|
### Properties
|
|
|
|
| Property | Type | Required | Description |
|
|
|----------|------|----------|-------------|
|
|
| `schema` | string | Yes | Schema version identifier. Must be `stella.change-trace/1.0` |
|
|
| `subject` | object | Yes | Subject of the comparison |
|
|
| `deltas` | array | Yes | Array of package deltas (may be empty) |
|
|
| `summary` | object | Yes | Aggregated summary metrics |
|
|
| `analyzedAt` | string | Yes | ISO 8601 timestamp (UTC) |
|
|
| `algorithmVersion` | string | No | Algorithm version used (default: "1.0") |
|
|
|
|
---
|
|
|
|
## Subject Object
|
|
|
|
```json
|
|
{
|
|
"imageRef": "docker.io/library/nginx:1.25.3",
|
|
"fromDigest": "sha256:abc123...",
|
|
"toDigest": "sha256:def456...",
|
|
"fromScanId": "scan-12345",
|
|
"toScanId": "scan-67890"
|
|
}
|
|
```
|
|
|
|
### Properties
|
|
|
|
| Property | Type | Required | Description |
|
|
|----------|------|----------|-------------|
|
|
| `imageRef` | string | Yes | Container image reference |
|
|
| `fromDigest` | string | Yes | SHA-256 digest of source image |
|
|
| `toDigest` | string | Yes | SHA-256 digest of target image |
|
|
| `fromScanId` | string | No | Source scan identifier |
|
|
| `toScanId` | string | No | Target scan identifier |
|
|
|
|
---
|
|
|
|
## PackageDelta Object
|
|
|
|
```json
|
|
{
|
|
"purl": "pkg:deb/debian/libssl3@3.0.9-1",
|
|
"fromVersion": "3.0.9-1",
|
|
"toVersion": "3.0.9-1+deb12u3",
|
|
"changeType": "patched",
|
|
"symbols": [ ... ],
|
|
"bytes": [ ... ],
|
|
"trustDelta": { ... }
|
|
}
|
|
```
|
|
|
|
### Properties
|
|
|
|
| Property | Type | Required | Description |
|
|
|----------|------|----------|-------------|
|
|
| `purl` | string | Yes | Package URL (RFC 3986 compliant) |
|
|
| `fromVersion` | string | No | Source version (null if added) |
|
|
| `toVersion` | string | No | Target version (null if removed) |
|
|
| `changeType` | enum | Yes | Type of change |
|
|
| `symbols` | array | No | Symbol-level deltas (if available) |
|
|
| `bytes` | array | No | Byte-level deltas (if enabled) |
|
|
| `trustDelta` | object | Yes | Trust impact calculation |
|
|
|
|
### ChangeType Enum
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `unchanged` | No change detected |
|
|
| `added` | Package added in target |
|
|
| `removed` | Package removed in target |
|
|
| `upgraded` | Version increased |
|
|
| `downgraded` | Version decreased |
|
|
| `patched` | Security patch applied (same base version) |
|
|
| `rebuilt` | Same version, different build |
|
|
|
|
---
|
|
|
|
## SymbolDelta Object
|
|
|
|
```json
|
|
{
|
|
"symbolName": "ssl3_get_record",
|
|
"changeType": "patched",
|
|
"sizeDelta": -24,
|
|
"cfgBlockDelta": 2,
|
|
"confidence": 0.97,
|
|
"matchMethod": "CFGHash+ChunkMatch",
|
|
"explanation": "Function patched: 2 basic blocks changed"
|
|
}
|
|
```
|
|
|
|
### Properties
|
|
|
|
| Property | Type | Required | Description |
|
|
|----------|------|----------|-------------|
|
|
| `symbolName` | string | Yes | Symbol/function name |
|
|
| `changeType` | enum | Yes | Type of symbol change |
|
|
| `sizeDelta` | integer | No | Size change in bytes |
|
|
| `cfgBlockDelta` | integer | No | CFG basic block count change |
|
|
| `confidence` | number | No | Match confidence (0.0-1.0) |
|
|
| `matchMethod` | string | No | Method used for matching |
|
|
| `explanation` | string | No | Human-readable explanation |
|
|
|
|
### SymbolChangeType Enum
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `unchanged` | No change detected |
|
|
| `added` | Symbol added in target |
|
|
| `removed` | Symbol removed in target |
|
|
| `modified` | Symbol modified (general) |
|
|
| `patched` | Security patch detected |
|
|
|
|
---
|
|
|
|
## ByteDelta Object
|
|
|
|
```json
|
|
{
|
|
"offset": 4096,
|
|
"size": 2048,
|
|
"fromHash": "sha256:abc123...",
|
|
"toHash": "sha256:def456...",
|
|
"section": ".text",
|
|
"context": "Function: ssl3_get_record"
|
|
}
|
|
```
|
|
|
|
### Properties
|
|
|
|
| Property | Type | Required | Description |
|
|
|----------|------|----------|-------------|
|
|
| `offset` | integer | Yes | Byte offset in binary |
|
|
| `size` | integer | Yes | Size of changed region |
|
|
| `fromHash` | string | Yes | SHA-256 hash of source bytes |
|
|
| `toHash` | string | Yes | SHA-256 hash of target bytes |
|
|
| `section` | string | No | Binary section name |
|
|
| `context` | string | No | Context hint (e.g., function name) |
|
|
|
|
**Privacy Note:** Raw byte content is never included; only hashes are stored.
|
|
|
|
---
|
|
|
|
## TrustDelta Object
|
|
|
|
```json
|
|
{
|
|
"score": -0.27,
|
|
"beforeScore": 0.65,
|
|
"afterScore": 0.92,
|
|
"reachabilityImpact": "reduced",
|
|
"exploitabilityImpact": "down",
|
|
"proofSteps": [
|
|
"CVE-2026-12345 affects ssl3_get_record",
|
|
"Version changed: 3.0.9-1 -> 3.0.9-1+deb12u3",
|
|
"Patch verified via CFG match: 97% confidence",
|
|
"Reachable call paths: 3 -> 0 after patch",
|
|
"DSSE attestation present",
|
|
"Verdict: risk_down (-0.27)"
|
|
]
|
|
}
|
|
```
|
|
|
|
### Properties
|
|
|
|
| Property | Type | Required | Description |
|
|
|----------|------|----------|-------------|
|
|
| `score` | number | Yes | Trust delta value (-1.0 to +1.0) |
|
|
| `beforeScore` | number | Yes | Trust score before change |
|
|
| `afterScore` | number | Yes | Trust score after change |
|
|
| `reachabilityImpact` | enum | Yes | Impact on code reachability |
|
|
| `exploitabilityImpact` | enum | Yes | Impact on exploitability |
|
|
| `proofSteps` | array | Yes | Human-readable proof steps |
|
|
|
|
### ReachabilityImpact Enum
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `unchanged` | No change in reachability |
|
|
| `introduced` | Path now reachable |
|
|
| `eliminated` | Path no longer reachable |
|
|
| `reduced` | Fewer reachable paths |
|
|
| `increased` | More reachable paths |
|
|
|
|
### ExploitabilityImpact Enum
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `unchanged` | No change in exploitability |
|
|
| `introduced` | New exploitability concern |
|
|
| `eliminated` | Exploitability eliminated |
|
|
| `up` | Increased exploitability |
|
|
| `down` | Decreased exploitability |
|
|
|
|
---
|
|
|
|
## Summary Object
|
|
|
|
```json
|
|
{
|
|
"packagesChanged": 5,
|
|
"packagesAdded": 1,
|
|
"packagesRemoved": 0,
|
|
"symbolsChanged": 23,
|
|
"bytesChanged": 8192,
|
|
"trustDelta": -0.15,
|
|
"overallVerdict": "risk_down"
|
|
}
|
|
```
|
|
|
|
### Properties
|
|
|
|
| Property | Type | Required | Description |
|
|
|----------|------|----------|-------------|
|
|
| `packagesChanged` | integer | Yes | Total packages with changes |
|
|
| `packagesAdded` | integer | Yes | Packages added |
|
|
| `packagesRemoved` | integer | Yes | Packages removed |
|
|
| `symbolsChanged` | integer | Yes | Total symbols with changes |
|
|
| `bytesChanged` | integer | Yes | Total bytes changed |
|
|
| `trustDelta` | number | Yes | Aggregate trust delta |
|
|
| `overallVerdict` | string | Yes | Overall verdict |
|
|
|
|
### Verdict Values
|
|
|
|
| Value | Trust Delta Range | Description |
|
|
|-------|-------------------|-------------|
|
|
| `risk_down` | < -0.3 | Risk decreased significantly |
|
|
| `neutral` | -0.3 to +0.3 | No significant risk change |
|
|
| `risk_up` | > +0.3 | Risk increased significantly |
|
|
| `inconclusive` | N/A | Unable to determine |
|
|
|
|
---
|
|
|
|
## Full Example
|
|
|
|
```json
|
|
{
|
|
"$schema": "https://stella-ops.org/schemas/change-trace/1.0/schema.json",
|
|
"schema": "stella.change-trace/1.0",
|
|
"subject": {
|
|
"imageRef": "docker.io/library/nginx:1.25.3",
|
|
"fromDigest": "sha256:abc123def456...",
|
|
"toDigest": "sha256:789ghi012jkl...",
|
|
"fromScanId": "scan-20260112-001",
|
|
"toScanId": "scan-20260112-002"
|
|
},
|
|
"deltas": [
|
|
{
|
|
"purl": "pkg:deb/debian/libssl3@3.0.9-1",
|
|
"fromVersion": "3.0.9-1",
|
|
"toVersion": "3.0.9-1+deb12u3",
|
|
"changeType": "patched",
|
|
"symbols": [
|
|
{
|
|
"symbolName": "ssl3_get_record",
|
|
"changeType": "patched",
|
|
"sizeDelta": -24,
|
|
"cfgBlockDelta": 2,
|
|
"confidence": 0.97,
|
|
"matchMethod": "CFGHash+ChunkMatch",
|
|
"explanation": "Function patched: 2 basic blocks changed"
|
|
}
|
|
],
|
|
"bytes": [
|
|
{
|
|
"offset": 4096,
|
|
"size": 2048,
|
|
"fromHash": "sha256:abc...",
|
|
"toHash": "sha256:def...",
|
|
"section": ".text"
|
|
}
|
|
],
|
|
"trustDelta": {
|
|
"score": -0.27,
|
|
"beforeScore": 0.65,
|
|
"afterScore": 0.92,
|
|
"reachabilityImpact": "reduced",
|
|
"exploitabilityImpact": "down",
|
|
"proofSteps": [
|
|
"CVE-2026-12345 affects ssl3_get_record",
|
|
"Version changed: 3.0.9-1 -> 3.0.9-1+deb12u3",
|
|
"Patch verified via CFG match: 97% confidence",
|
|
"Reachable call paths: 3 -> 0 after patch",
|
|
"DSSE attestation present",
|
|
"Verdict: risk_down (-0.27)"
|
|
]
|
|
}
|
|
}
|
|
],
|
|
"summary": {
|
|
"packagesChanged": 1,
|
|
"packagesAdded": 0,
|
|
"packagesRemoved": 0,
|
|
"symbolsChanged": 1,
|
|
"bytesChanged": 2048,
|
|
"trustDelta": -0.27,
|
|
"overallVerdict": "risk_down"
|
|
},
|
|
"analyzedAt": "2026-01-12T14:30:00.000Z",
|
|
"algorithmVersion": "1.0"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Serialization Rules
|
|
|
|
### Determinism Requirements
|
|
|
|
1. **Key ordering**: Object keys must be sorted alphabetically
|
|
2. **Array ordering**:
|
|
- `deltas`: Sorted by `purl` (lexicographic)
|
|
- `symbols`: Sorted by `symbolName` (lexicographic)
|
|
- `bytes`: Sorted by `offset` (numeric ascending)
|
|
- `proofSteps`: Preserve generation order
|
|
3. **Number formatting**: No trailing zeros, no exponent notation
|
|
4. **String escaping**: Minimal escaping per RFC 8785
|
|
5. **Timestamps**: ISO 8601 with milliseconds, UTC (`Z` suffix)
|
|
|
|
### RFC 8785 Compliance
|
|
|
|
All JSON output must conform to [RFC 8785](https://datatracker.ietf.org/doc/html/rfc8785) (JSON Canonicalization Scheme) for digest computation.
|
|
|
|
---
|
|
|
|
## Validation
|
|
|
|
### JSON Schema
|
|
|
|
The formal JSON Schema is available at:
|
|
```
|
|
https://stella-ops.org/schemas/change-trace/1.0/schema.json
|
|
```
|
|
|
|
### Validation Command
|
|
|
|
```bash
|
|
stella change-trace verify trace.cdxchange.json
|
|
```
|
|
|
|
### Required Fields
|
|
|
|
The following fields are required for a valid trace:
|
|
- `schema`
|
|
- `subject.imageRef`
|
|
- `subject.fromDigest`
|
|
- `subject.toDigest`
|
|
- `deltas` (may be empty array)
|
|
- `summary.*` (all summary fields)
|
|
- `analyzedAt`
|
|
|
|
---
|
|
|
|
## CycloneDX Integration
|
|
|
|
### Embedded Mode
|
|
|
|
When embedded in CycloneDX, the change trace is attached as a `component-evidence` extension:
|
|
|
|
```json
|
|
{
|
|
"bomFormat": "CycloneDX",
|
|
"specVersion": "1.7",
|
|
"components": [
|
|
{
|
|
"purl": "pkg:deb/debian/libssl3@3.0.9-1+deb12u3",
|
|
"evidence": {
|
|
"extensions": [
|
|
{
|
|
"extensionType": "stella-change-trace",
|
|
"extension": {
|
|
"schema": "stella.change-trace/1.0",
|
|
"changeType": "patched",
|
|
"trustDelta": { ... },
|
|
"symbols": [ ... ]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Standalone Mode
|
|
|
|
Export as separate file: `<basename>.cdxchange.json`
|
|
|
|
---
|
|
|
|
## Version History
|
|
|
|
| Version | Date | Changes |
|
|
|---------|------|---------|
|
|
| 1.0.0 | 2026-01-12 | Initial release |
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
- [Architecture Document](../modules/scanner/design/change-trace-architecture.md)
|
|
- [Trust-Delta Contract](./change-trace-trust-delta.md)
|
|
- [RFC 8785 - JSON Canonicalization Scheme](https://datatracker.ietf.org/doc/html/rfc8785)
|
|
- [Package URL Specification](https://github.com/package-url/purl-spec)
|
|
|
|
---
|
|
|
|
*Document Version: 1.0.0*
|
|
*Last Updated: 2026-01-12*
|