release orchestrator v1 draft and build fixes
This commit is contained in:
447
docs/contracts/change-trace-schema.md
Normal file
447
docs/contracts/change-trace-schema.md
Normal file
@@ -0,0 +1,447 @@
|
||||
# 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*
|
||||
Reference in New Issue
Block a user