test
This commit is contained in:
336
docs/modules/policy/evidence-hooks.md
Normal file
336
docs/modules/policy/evidence-hooks.md
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
# Evidence Hooks Reference
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
**Evidence Hooks** require specific attestations before an exception can be approved. This ensures exceptions are backed by verifiable proof, not just assertions.
|
||||||
|
|
||||||
|
## Hook Model
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
evidenceHooks:
|
||||||
|
- hookId: "feature-flag-off"
|
||||||
|
type: FeatureFlagDisabled
|
||||||
|
description: "Feature flag must be disabled in production"
|
||||||
|
isMandatory: true
|
||||||
|
maxAge: PT24H # ISO 8601 duration
|
||||||
|
minTrustScore: 0.8
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hook Types
|
||||||
|
|
||||||
|
### FeatureFlagDisabled
|
||||||
|
|
||||||
|
Requires attestation that a feature flag is disabled.
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| flagName | string | Name of the feature flag |
|
||||||
|
| environment | string | Target environment |
|
||||||
|
| attestedAt | timestamp | When flag state was verified |
|
||||||
|
|
||||||
|
**Evidence Example:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "FeatureFlagDisabled",
|
||||||
|
"flagName": "EXPERIMENTAL_TEMPLATE_ENGINE",
|
||||||
|
"environment": "production",
|
||||||
|
"attestedAt": "2024-12-22T10:00:00Z",
|
||||||
|
"source": "launchdarkly"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### BackportMerged
|
||||||
|
|
||||||
|
Requires attestation that a security backport was merged.
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| prUrl | string | Pull request URL |
|
||||||
|
| commitHash | string | Merged commit hash |
|
||||||
|
| mergedAt | timestamp | When PR was merged |
|
||||||
|
|
||||||
|
**Evidence Example:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "BackportMerged",
|
||||||
|
"prUrl": "https://github.com/org/repo/pull/123",
|
||||||
|
"commitHash": "abc123...",
|
||||||
|
"mergedAt": "2024-12-22T09:30:00Z",
|
||||||
|
"mergedBy": "security-team"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### CompensatingControl
|
||||||
|
|
||||||
|
Requires attestation of a compensating security control.
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| controlType | string | Type of control (WAF, RASP, etc.) |
|
||||||
|
| controlId | string | Control identifier |
|
||||||
|
| description | string | How control mitigates risk |
|
||||||
|
|
||||||
|
**Evidence Example:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "CompensatingControl",
|
||||||
|
"controlType": "WAF",
|
||||||
|
"controlId": "rule-block-template-injection",
|
||||||
|
"description": "WAF rule blocks template injection patterns",
|
||||||
|
"deployedAt": "2024-12-22T08:00:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### SecurityReview
|
||||||
|
|
||||||
|
Requires attestation of completed security review.
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| reviewId | string | Review identifier |
|
||||||
|
| reviewer | string | Who performed review |
|
||||||
|
| outcome | string | Review outcome |
|
||||||
|
|
||||||
|
### RuntimeMitigation
|
||||||
|
|
||||||
|
Requires attestation of runtime mitigation in place.
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| mitigationType | string | Type of mitigation |
|
||||||
|
| configuration | object | Mitigation configuration |
|
||||||
|
|
||||||
|
### WAFRuleDeployed
|
||||||
|
|
||||||
|
Requires attestation of WAF rule deployment.
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| ruleId | string | WAF rule identifier |
|
||||||
|
| provider | string | WAF provider |
|
||||||
|
| deployedAt | timestamp | Deployment time |
|
||||||
|
|
||||||
|
### CustomAttestation
|
||||||
|
|
||||||
|
Generic attestation for custom evidence types.
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| predicateType | string | Custom predicate type URI |
|
||||||
|
| payload | object | Custom payload |
|
||||||
|
|
||||||
|
## Validation Rules
|
||||||
|
|
||||||
|
### Freshness (maxAge)
|
||||||
|
|
||||||
|
Evidence must be recent enough:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
maxAge: PT24H # 24 hours
|
||||||
|
maxAge: P7D # 7 days
|
||||||
|
maxAge: PT1H # 1 hour
|
||||||
|
```
|
||||||
|
|
||||||
|
If evidence is older than maxAge, it's marked as **Expired**.
|
||||||
|
|
||||||
|
### Trust Score (minTrustScore)
|
||||||
|
|
||||||
|
Evidence source must meet minimum trust:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
minTrustScore: 0.8 # 80% trust required
|
||||||
|
```
|
||||||
|
|
||||||
|
Trust scores come from the source registry.
|
||||||
|
|
||||||
|
### Signature Verification
|
||||||
|
|
||||||
|
If evidence includes a DSSE envelope, signature is verified:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"content": { ... },
|
||||||
|
"dsseEnvelope": "eyJwYXlsb2FkIjoi...",
|
||||||
|
"signatureVerified": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Schema Validation
|
||||||
|
|
||||||
|
Custom attestations can require schema validation:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
validationSchema: "https://stellaops.io/schemas/evidence/feature-flag/v1"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validation States
|
||||||
|
|
||||||
|
| State | Description |
|
||||||
|
|-------|-------------|
|
||||||
|
| `Pending` | Evidence submitted, not yet validated |
|
||||||
|
| `Valid` | Evidence passes all validation |
|
||||||
|
| `Invalid` | Evidence fails validation |
|
||||||
|
| `Expired` | Evidence older than maxAge |
|
||||||
|
| `InsufficientTrust` | Source trust score too low |
|
||||||
|
|
||||||
|
## Submission Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
1. User selects exception to approve
|
||||||
|
2. System shows required evidence hooks
|
||||||
|
3. User submits evidence for each hook:
|
||||||
|
a. Upload attestation file
|
||||||
|
b. Link to external system
|
||||||
|
c. Generate attestation in-place
|
||||||
|
4. System validates each submission
|
||||||
|
5. If all mandatory hooks satisfied:
|
||||||
|
a. Exception can be approved
|
||||||
|
6. If any mandatory hooks unsatisfied:
|
||||||
|
a. Approval blocked
|
||||||
|
b. Missing evidence highlighted
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Endpoints
|
||||||
|
|
||||||
|
### POST /exceptions/{id}/evidence
|
||||||
|
|
||||||
|
Submit evidence for a hook.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"hookId": "feature-flag-off",
|
||||||
|
"type": "FeatureFlagDisabled",
|
||||||
|
"reference": "launchdarkly://flags/EXPERIMENTAL_TEMPLATE_ENGINE",
|
||||||
|
"content": {
|
||||||
|
"flagName": "EXPERIMENTAL_TEMPLATE_ENGINE",
|
||||||
|
"environment": "production",
|
||||||
|
"state": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET /exceptions/{id}/evidence
|
||||||
|
|
||||||
|
Get all submitted evidence for an exception.
|
||||||
|
|
||||||
|
### GET /exceptions/{id}/evidence/status
|
||||||
|
|
||||||
|
Get evidence satisfaction status.
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"isSatisfied": false,
|
||||||
|
"missingEvidence": [
|
||||||
|
{
|
||||||
|
"hookId": "backport-merged",
|
||||||
|
"type": "BackportMerged",
|
||||||
|
"description": "Security backport must be merged"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validEvidence": [
|
||||||
|
{
|
||||||
|
"hookId": "feature-flag-off",
|
||||||
|
"type": "FeatureFlagDisabled",
|
||||||
|
"validatedAt": "2024-12-22T10:00:00Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## UI Integration
|
||||||
|
|
||||||
|
### Evidence Requirements Panel
|
||||||
|
|
||||||
|
Shows required evidence with status:
|
||||||
|
|
||||||
|
```
|
||||||
|
Evidence Requirements
|
||||||
|
---------------------
|
||||||
|
[x] Feature flag disabled (Verified 2h ago)
|
||||||
|
[ ] Backport PR merged (Missing)
|
||||||
|
[x] WAF rule deployed (Verified 1d ago)
|
||||||
|
|
||||||
|
[Submit Missing Evidence]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Evidence Upload Modal
|
||||||
|
|
||||||
|
For each hook type:
|
||||||
|
1. File upload for attestations
|
||||||
|
2. URL input for external references
|
||||||
|
3. Form for in-place attestation
|
||||||
|
|
||||||
|
### Blocking Indicator
|
||||||
|
|
||||||
|
When evidence is missing:
|
||||||
|
- Approve button disabled
|
||||||
|
- Clear message: "Cannot approve: missing evidence"
|
||||||
|
- Link to evidence requirements
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Mandatory = Critical**: Only mark truly required evidence as mandatory
|
||||||
|
2. **Reasonable maxAge**: Balance freshness with operational burden
|
||||||
|
3. **Trust Scores**: Configure source trust appropriately
|
||||||
|
4. **Documentation**: Document what each evidence type means
|
||||||
|
5. **Automation**: Integrate with systems to auto-generate attestations
|
||||||
|
|
||||||
|
## DSSE Attestation Format
|
||||||
|
|
||||||
|
Evidence can be wrapped in DSSE for integrity:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"payloadType": "application/vnd.stellaops.evidence+json",
|
||||||
|
"payload": "<base64-encoded-evidence>",
|
||||||
|
"signatures": [
|
||||||
|
{
|
||||||
|
"keyid": "key-123",
|
||||||
|
"sig": "<base64-signature>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example Hook Configurations
|
||||||
|
|
||||||
|
### Critical CVE Policy
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
evidenceHooks:
|
||||||
|
- hookId: "security-review"
|
||||||
|
type: SecurityReview
|
||||||
|
description: "Security team review required"
|
||||||
|
isMandatory: true
|
||||||
|
- hookId: "compensating-control"
|
||||||
|
type: CompensatingControl
|
||||||
|
description: "Compensating control must be in place"
|
||||||
|
isMandatory: true
|
||||||
|
- hookId: "stakeholder-approval"
|
||||||
|
type: CustomAttestation
|
||||||
|
description: "Business stakeholder approval"
|
||||||
|
isMandatory: true
|
||||||
|
validationSchema: "https://stellaops.io/schemas/evidence/stakeholder-approval/v1"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Standard Policy
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
evidenceHooks:
|
||||||
|
- hookId: "justification"
|
||||||
|
type: CustomAttestation
|
||||||
|
description: "Written justification required"
|
||||||
|
isMandatory: true
|
||||||
|
- hookId: "compensating-control"
|
||||||
|
type: CompensatingControl
|
||||||
|
description: "Compensating control recommended"
|
||||||
|
isMandatory: false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- [Recheck Policy](./recheck-policy.md)
|
||||||
|
- [Exception Workflow](../../api/exceptions.md)
|
||||||
|
- [DSSE Attestations](../attestor/dsse.md)
|
||||||
251
docs/modules/policy/recheck-policy.md
Normal file
251
docs/modules/policy/recheck-policy.md
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
# Recheck Policy Reference
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
A **Recheck Policy** defines conditions that trigger automatic re-evaluation of an exception. When conditions are met, the exception may be flagged for review, require re-approval, or be automatically revoked.
|
||||||
|
|
||||||
|
## Policy Model
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
recheckPolicy:
|
||||||
|
policyId: "policy-critical-cves"
|
||||||
|
name: "Critical CVE Recheck"
|
||||||
|
conditions:
|
||||||
|
- type: EPSSAbove
|
||||||
|
threshold: 0.5
|
||||||
|
action: RequireReapproval
|
||||||
|
- type: ReachGraphChange
|
||||||
|
action: Block
|
||||||
|
- type: KEVFlagged
|
||||||
|
action: Block
|
||||||
|
- type: ExpiryWithin
|
||||||
|
threshold: 7 # days
|
||||||
|
action: Warn
|
||||||
|
defaultAction: Warn
|
||||||
|
isActive: true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Condition Types
|
||||||
|
|
||||||
|
### EPSSAbove
|
||||||
|
|
||||||
|
Triggers when EPSS score exceeds threshold.
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-----------|------|-------------|
|
||||||
|
| threshold | decimal | EPSS score threshold (0.0-1.0) |
|
||||||
|
| action | RecheckAction | Action when triggered |
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```yaml
|
||||||
|
- type: EPSSAbove
|
||||||
|
threshold: 0.5
|
||||||
|
action: RequireReapproval
|
||||||
|
```
|
||||||
|
|
||||||
|
### CVSSAbove
|
||||||
|
|
||||||
|
Triggers when CVSS score exceeds threshold.
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-----------|------|-------------|
|
||||||
|
| threshold | decimal | CVSS score threshold (0.0-10.0) |
|
||||||
|
| action | RecheckAction | Action when triggered |
|
||||||
|
|
||||||
|
### ReachGraphChange
|
||||||
|
|
||||||
|
Triggers when reachability graph changes (new paths discovered).
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-----------|------|-------------|
|
||||||
|
| action | RecheckAction | Action when triggered |
|
||||||
|
|
||||||
|
**Use case:** Exception was based on "unreachable" status; new analysis shows reachability.
|
||||||
|
|
||||||
|
### UnknownsAbove
|
||||||
|
|
||||||
|
Triggers when unknown budget exceeds threshold.
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-----------|------|-------------|
|
||||||
|
| threshold | integer | Maximum allowed unknowns |
|
||||||
|
| action | RecheckAction | Action when triggered |
|
||||||
|
|
||||||
|
### KEVFlagged
|
||||||
|
|
||||||
|
Triggers when CVE is added to CISA KEV catalog.
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-----------|------|-------------|
|
||||||
|
| action | RecheckAction | Action when triggered |
|
||||||
|
|
||||||
|
**Best practice:** Always use `Block` action for KEV additions.
|
||||||
|
|
||||||
|
### VEXStatusChange
|
||||||
|
|
||||||
|
Triggers when VEX status changes (e.g., NotAffected → Affected).
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-----------|------|-------------|
|
||||||
|
| action | RecheckAction | Action when triggered |
|
||||||
|
|
||||||
|
### NewCVEInPackage
|
||||||
|
|
||||||
|
Triggers when new CVE is discovered in the same package.
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-----------|------|-------------|
|
||||||
|
| action | RecheckAction | Action when triggered |
|
||||||
|
|
||||||
|
### ExpiryWithin
|
||||||
|
|
||||||
|
Triggers when exception nears expiry.
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-----------|------|-------------|
|
||||||
|
| threshold | integer | Days before expiry |
|
||||||
|
| action | RecheckAction | Action when triggered |
|
||||||
|
|
||||||
|
### PackageVersionChange
|
||||||
|
|
||||||
|
Triggers when package version changes in artifact.
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-----------|------|-------------|
|
||||||
|
| action | RecheckAction | Action when triggered |
|
||||||
|
|
||||||
|
## Actions
|
||||||
|
|
||||||
|
### Warn
|
||||||
|
|
||||||
|
Log warning but allow exception to remain active.
|
||||||
|
|
||||||
|
- Appears in audit log
|
||||||
|
- Visible in exception details
|
||||||
|
- Does not block deployment
|
||||||
|
|
||||||
|
### RequireReapproval
|
||||||
|
|
||||||
|
Move exception back to "pending" status requiring re-approval.
|
||||||
|
|
||||||
|
- Notifies original approvers
|
||||||
|
- Exception inactive until re-approved
|
||||||
|
- Evidence may need updating
|
||||||
|
|
||||||
|
### Revoke
|
||||||
|
|
||||||
|
Automatically revoke the exception.
|
||||||
|
|
||||||
|
- Exception becomes inactive immediately
|
||||||
|
- Audit log entry created
|
||||||
|
- Notification sent
|
||||||
|
|
||||||
|
### Block
|
||||||
|
|
||||||
|
Fail build/deployment pipeline.
|
||||||
|
|
||||||
|
- CI/CD gate returns failure
|
||||||
|
- Requires manual intervention
|
||||||
|
- Most severe action
|
||||||
|
|
||||||
|
## Environment Scoping
|
||||||
|
|
||||||
|
Conditions can be scoped to specific environments:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- type: EPSSAbove
|
||||||
|
threshold: 0.3
|
||||||
|
environmentScope:
|
||||||
|
- prod
|
||||||
|
- staging
|
||||||
|
action: Block
|
||||||
|
- type: EPSSAbove
|
||||||
|
threshold: 0.7
|
||||||
|
environmentScope:
|
||||||
|
- dev
|
||||||
|
action: Warn
|
||||||
|
```
|
||||||
|
|
||||||
|
## Evaluation Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Scan triggered
|
||||||
|
2. Get active exceptions for artifact
|
||||||
|
3. For each exception with recheck policy:
|
||||||
|
a. Evaluate each condition
|
||||||
|
b. Check environment scope
|
||||||
|
c. Record triggered conditions
|
||||||
|
4. Determine highest-priority action
|
||||||
|
5. Apply action (warn/reapproval/revoke/block)
|
||||||
|
6. Update exception with recheck result
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build Gate Integration
|
||||||
|
|
||||||
|
Recheck policies integrate with build gates:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# In CI/CD pipeline
|
||||||
|
- name: check-exceptions
|
||||||
|
uses: stellaops/exception-gate@v1
|
||||||
|
with:
|
||||||
|
artifact: ${{ env.IMAGE_DIGEST }}
|
||||||
|
environment: production
|
||||||
|
fail-on: block
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Start with Warn**: Begin with warning actions, escalate based on data
|
||||||
|
2. **KEV = Block**: Always block on KEV additions
|
||||||
|
3. **Environment Tiers**: Stricter policies for production
|
||||||
|
4. **Regular Review**: Review triggered conditions monthly
|
||||||
|
5. **Document Rationale**: Explain threshold choices
|
||||||
|
|
||||||
|
## Example Policies
|
||||||
|
|
||||||
|
### High-Security Policy
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
recheckPolicy:
|
||||||
|
policyId: "high-security"
|
||||||
|
name: "High Security Recheck"
|
||||||
|
conditions:
|
||||||
|
- type: EPSSAbove
|
||||||
|
threshold: 0.3
|
||||||
|
action: Block
|
||||||
|
- type: CVSSAbove
|
||||||
|
threshold: 7.0
|
||||||
|
action: RequireReapproval
|
||||||
|
- type: KEVFlagged
|
||||||
|
action: Block
|
||||||
|
- type: ReachGraphChange
|
||||||
|
action: Block
|
||||||
|
- type: VEXStatusChange
|
||||||
|
action: RequireReapproval
|
||||||
|
defaultAction: Warn
|
||||||
|
```
|
||||||
|
|
||||||
|
### Standard Policy
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
recheckPolicy:
|
||||||
|
policyId: "standard"
|
||||||
|
name: "Standard Recheck"
|
||||||
|
conditions:
|
||||||
|
- type: EPSSAbove
|
||||||
|
threshold: 0.7
|
||||||
|
action: RequireReapproval
|
||||||
|
- type: KEVFlagged
|
||||||
|
action: Block
|
||||||
|
- type: ExpiryWithin
|
||||||
|
threshold: 14
|
||||||
|
action: Warn
|
||||||
|
defaultAction: Warn
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- [Evidence Hooks](./evidence-hooks.md)
|
||||||
|
- [Exception API](../../api/exceptions.md)
|
||||||
|
- [Build Gates](../ci/recipes.md)
|
||||||
250
docs/modules/snapshot/merge-preview.md
Normal file
250
docs/modules/snapshot/merge-preview.md
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
# Policy Merge Preview
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The **Policy Merge Preview** shows how VEX statements from different sources combine using lattice logic. This visualization helps analysts understand:
|
||||||
|
|
||||||
|
1. What each source contributes
|
||||||
|
2. How conflicts are resolved
|
||||||
|
3. What evidence is missing
|
||||||
|
4. The final merged status
|
||||||
|
|
||||||
|
## Merge Semantics
|
||||||
|
|
||||||
|
StellaOps uses a three-layer merge model:
|
||||||
|
|
||||||
|
```
|
||||||
|
vendor ⊕ distro ⊕ internal = final
|
||||||
|
```
|
||||||
|
|
||||||
|
Where ⊕ represents the lattice join operation.
|
||||||
|
|
||||||
|
### Layer Hierarchy
|
||||||
|
|
||||||
|
| Layer | Description | Typical Trust |
|
||||||
|
|-------|-------------|---------------|
|
||||||
|
| **Vendor** | Software vendor's VEX statements | 0.95-1.0 |
|
||||||
|
| **Distro** | Distribution maintainer's assessments | 0.85-0.95 |
|
||||||
|
| **Internal** | Organization's own assessments | 0.70-0.90 |
|
||||||
|
|
||||||
|
### Lattice Operations
|
||||||
|
|
||||||
|
Using K4 (Kleene's 4-valued logic):
|
||||||
|
|
||||||
|
| Status | Lattice Position |
|
||||||
|
|--------|-----------------|
|
||||||
|
| Affected | Top (Both) |
|
||||||
|
| UnderInvestigation | Unknown (Neither) |
|
||||||
|
| Fixed | True |
|
||||||
|
| NotAffected | False |
|
||||||
|
|
||||||
|
Join table (⊕):
|
||||||
|
```
|
||||||
|
| Affected | Under... | Fixed | NotAffected
|
||||||
|
---------+----------+----------+-------+------------
|
||||||
|
Affected | A | A | A | A
|
||||||
|
Under... | A | U | U | U
|
||||||
|
Fixed | A | U | F | F
|
||||||
|
NotAff | A | U | F | N
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Endpoint
|
||||||
|
|
||||||
|
### GET /policy/merge-preview/{cveId}
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `cveId`: CVE identifier
|
||||||
|
- `artifact`: Artifact digest (query param)
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"cveId": "CVE-2024-1234",
|
||||||
|
"artifactDigest": "sha256:abc...",
|
||||||
|
"contributions": [
|
||||||
|
{
|
||||||
|
"layer": "vendor",
|
||||||
|
"sources": ["lodash-security"],
|
||||||
|
"status": "NotAffected",
|
||||||
|
"trustScore": 0.95,
|
||||||
|
"statements": [...],
|
||||||
|
"mergeTrace": {
|
||||||
|
"explanation": "Vendor states not affected due to version"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer": "distro",
|
||||||
|
"sources": ["redhat-csaf"],
|
||||||
|
"status": "Affected",
|
||||||
|
"trustScore": 0.90,
|
||||||
|
"statements": [...],
|
||||||
|
"mergeTrace": {
|
||||||
|
"explanation": "Distro states affected without context"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer": "internal",
|
||||||
|
"sources": [],
|
||||||
|
"status": null,
|
||||||
|
"trustScore": 0,
|
||||||
|
"statements": [],
|
||||||
|
"mergeTrace": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"finalStatus": "NotAffected",
|
||||||
|
"finalConfidence": 0.925,
|
||||||
|
"missingEvidence": [
|
||||||
|
{
|
||||||
|
"type": "internal-assessment",
|
||||||
|
"description": "Add internal security assessment",
|
||||||
|
"priority": "medium"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"latticeType": "K4",
|
||||||
|
"generatedAt": "2024-12-22T12:00:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conflict Resolution
|
||||||
|
|
||||||
|
When sources disagree, resolution follows:
|
||||||
|
|
||||||
|
1. **Trust Weight**: Higher trust wins
|
||||||
|
2. **Lattice Position**: If trust equal, higher lattice position wins
|
||||||
|
3. **Freshness**: If still tied, more recent statement wins
|
||||||
|
4. **Tie**: First statement wins
|
||||||
|
|
||||||
|
### Resolution Trace
|
||||||
|
|
||||||
|
Each merge includes explanation:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"leftSource": "vendor:lodash",
|
||||||
|
"rightSource": "distro:redhat",
|
||||||
|
"leftStatus": "NotAffected",
|
||||||
|
"rightStatus": "Affected",
|
||||||
|
"leftTrust": 0.95,
|
||||||
|
"rightTrust": 0.90,
|
||||||
|
"resultStatus": "NotAffected",
|
||||||
|
"explanation": "'vendor:lodash' has higher trust weight than 'distro:redhat'"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## UI Components
|
||||||
|
|
||||||
|
### Layer Cards
|
||||||
|
|
||||||
|
Each layer shows:
|
||||||
|
- Source names
|
||||||
|
- Current status badge
|
||||||
|
- Trust score bar
|
||||||
|
- Statement count
|
||||||
|
|
||||||
|
### Merge Flow Diagram
|
||||||
|
|
||||||
|
Visual representation:
|
||||||
|
```
|
||||||
|
┌─────────┐ ┌─────────┐ ┌──────────┐ ┌─────────┐
|
||||||
|
│ Vendor │ ──⊕─│ Distro │ ──⊕─│ Internal │ ──=─│ Final │
|
||||||
|
│ NotAff. │ │ Affected│ │ — │ │ NotAff. │
|
||||||
|
│ (0.95) │ │ (0.90) │ │ │ │ (0.925) │
|
||||||
|
└─────────┘ └─────────┘ └──────────┘ └─────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Missing Evidence CTA
|
||||||
|
|
||||||
|
Prominent call-to-action for missing evidence:
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ ⚠ Improve Confidence │
|
||||||
|
│ │
|
||||||
|
│ [+] Add internal security assessment │
|
||||||
|
│ Increases confidence by ~5% │
|
||||||
|
│ │
|
||||||
|
│ [+] Add reachability analysis │
|
||||||
|
│ Determines if code is called │
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Merge Traces (Expandable)
|
||||||
|
|
||||||
|
Detailed explanation of each merge:
|
||||||
|
```
|
||||||
|
▼ Merge Details
|
||||||
|
|
||||||
|
Vendor layer:
|
||||||
|
Sources: lodash-security
|
||||||
|
Status: NotAffected (trust: 95%)
|
||||||
|
|
||||||
|
Distro layer:
|
||||||
|
Sources: redhat-csaf
|
||||||
|
Status: Affected (trust: 90%)
|
||||||
|
Merge: 'lodash-security' has higher trust weight
|
||||||
|
|
||||||
|
Internal layer:
|
||||||
|
No statements
|
||||||
|
|
||||||
|
Final: NotAffected (confidence: 92.5%)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Trust Weights
|
||||||
|
|
||||||
|
Configure in `trust.yaml`:
|
||||||
|
```yaml
|
||||||
|
sources:
|
||||||
|
vendor: 1.0
|
||||||
|
distro: 0.9
|
||||||
|
nvd: 0.8
|
||||||
|
internal: 0.85
|
||||||
|
community: 0.5
|
||||||
|
unknown: 0.3
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lattice Type
|
||||||
|
|
||||||
|
Configure lattice in `policy.yaml`:
|
||||||
|
```yaml
|
||||||
|
lattice:
|
||||||
|
type: K4 # or Boolean, 8-state
|
||||||
|
joinStrategy: trust-weighted
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use Cases
|
||||||
|
|
||||||
|
### 1. Understanding Disagreement
|
||||||
|
|
||||||
|
When vendor says "not affected" but NVD says "affected":
|
||||||
|
- View merge preview
|
||||||
|
- See trust scores
|
||||||
|
- Understand why vendor wins
|
||||||
|
- Decide if internal assessment needed
|
||||||
|
|
||||||
|
### 2. Adding Internal Context
|
||||||
|
|
||||||
|
When external sources lack context:
|
||||||
|
- View missing evidence
|
||||||
|
- Click "Add evidence"
|
||||||
|
- Submit internal VEX statement
|
||||||
|
- See confidence increase
|
||||||
|
|
||||||
|
### 3. Audit Documentation
|
||||||
|
|
||||||
|
For compliance:
|
||||||
|
- Export merge preview
|
||||||
|
- Include in audit report
|
||||||
|
- Document decision rationale
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Review Conflicts**: When layers disagree, investigate why
|
||||||
|
2. **Add Internal Context**: Your reachability data often resolves conflicts
|
||||||
|
3. **Trust Calibration**: Adjust trust weights based on source accuracy
|
||||||
|
4. **Document Decisions**: Use merge preview in exception justifications
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- [VEX Trust Scoring](../excititor/scoring.md)
|
||||||
|
- [Lattice Configuration](../policy/implementation_plan.md)
|
||||||
|
- [REPLAY.yaml Specification](./replay-yaml.md)
|
||||||
295
docs/modules/snapshot/replay-yaml.md
Normal file
295
docs/modules/snapshot/replay-yaml.md
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
# REPLAY.yaml Manifest Specification
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The **REPLAY.yaml** manifest defines the complete set of inputs required to reproduce a StellaOps evaluation. It is the root document in a `.stella-replay.tgz` bundle.
|
||||||
|
|
||||||
|
## File Location
|
||||||
|
|
||||||
|
```
|
||||||
|
.stella-replay.tgz
|
||||||
|
├── REPLAY.yaml # This manifest
|
||||||
|
├── sboms/
|
||||||
|
├── vex/
|
||||||
|
├── reach/
|
||||||
|
├── exceptions/
|
||||||
|
├── policies/
|
||||||
|
├── feeds/
|
||||||
|
├── config/
|
||||||
|
└── SIGNATURE.sig # Optional DSSE signature
|
||||||
|
```
|
||||||
|
|
||||||
|
## Schema Version
|
||||||
|
|
||||||
|
Current schema version: `1.0.0`
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "1.0.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Complete Example
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "1.0.0"
|
||||||
|
|
||||||
|
snapshot:
|
||||||
|
id: "snap-20241222-abc123"
|
||||||
|
createdAt: "2024-12-22T12:00:00Z"
|
||||||
|
artifact: "sha256:abc123..."
|
||||||
|
previousId: "snap-20241221-xyz789"
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
sboms:
|
||||||
|
- path: "sboms/cyclonedx.json"
|
||||||
|
format: "cyclonedx-1.6"
|
||||||
|
digest: "sha256:def456..."
|
||||||
|
- path: "sboms/spdx.json"
|
||||||
|
format: "spdx-3.0.1"
|
||||||
|
digest: "sha256:ghi789..."
|
||||||
|
|
||||||
|
vex:
|
||||||
|
- path: "vex/vendor-lodash.json"
|
||||||
|
source: "vendor:lodash"
|
||||||
|
format: "openvex"
|
||||||
|
digest: "sha256:jkl012..."
|
||||||
|
trustScore: 0.95
|
||||||
|
- path: "vex/redhat-csaf.json"
|
||||||
|
source: "distro:redhat"
|
||||||
|
format: "csaf"
|
||||||
|
digest: "sha256:mno345..."
|
||||||
|
trustScore: 0.90
|
||||||
|
|
||||||
|
reachability:
|
||||||
|
- path: "reach/api-handler.json"
|
||||||
|
entryPoint: "/api/handler"
|
||||||
|
digest: "sha256:pqr678..."
|
||||||
|
nodeCount: 42
|
||||||
|
edgeCount: 57
|
||||||
|
|
||||||
|
exceptions:
|
||||||
|
- path: "exceptions/exc-001.json"
|
||||||
|
exceptionId: "exc-001"
|
||||||
|
digest: "sha256:stu901..."
|
||||||
|
|
||||||
|
policies:
|
||||||
|
bundlePath: "policies/bundle.tar.gz"
|
||||||
|
digest: "sha256:vwx234..."
|
||||||
|
version: "2.1.0"
|
||||||
|
rulesHash: "sha256:yza567..."
|
||||||
|
|
||||||
|
feeds:
|
||||||
|
- feedId: "nvd"
|
||||||
|
name: "National Vulnerability Database"
|
||||||
|
version: "2024-12-22T00:00:00Z"
|
||||||
|
digest: "sha256:bcd890..."
|
||||||
|
fetchedAt: "2024-12-22T06:00:00Z"
|
||||||
|
- feedId: "ghsa"
|
||||||
|
name: "GitHub Security Advisories"
|
||||||
|
version: "2024-12-22T01:00:00Z"
|
||||||
|
digest: "sha256:efg123..."
|
||||||
|
fetchedAt: "2024-12-22T06:15:00Z"
|
||||||
|
|
||||||
|
lattice:
|
||||||
|
type: "K4"
|
||||||
|
configDigest: "sha256:hij456..."
|
||||||
|
|
||||||
|
trust:
|
||||||
|
configDigest: "sha256:klm789..."
|
||||||
|
defaultWeight: 0.5
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
verdictPath: "verdict.json"
|
||||||
|
verdictDigest: "sha256:nop012..."
|
||||||
|
findingsPath: "findings.ndjson"
|
||||||
|
findingsDigest: "sha256:qrs345..."
|
||||||
|
|
||||||
|
seeds:
|
||||||
|
rng: 12345678
|
||||||
|
sampling: 87654321
|
||||||
|
|
||||||
|
environment:
|
||||||
|
STELLAOPS_POLICY_VERSION: "2.1.0"
|
||||||
|
STELLAOPS_LATTICE_TYPE: "K4"
|
||||||
|
|
||||||
|
signature:
|
||||||
|
algorithm: "ecdsa-p256"
|
||||||
|
keyId: "signing-key-prod-2024"
|
||||||
|
value: "MEUCIQDx..."
|
||||||
|
```
|
||||||
|
|
||||||
|
## Field Reference
|
||||||
|
|
||||||
|
### snapshot
|
||||||
|
|
||||||
|
Metadata about the snapshot itself.
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| id | string | Yes | Unique snapshot identifier |
|
||||||
|
| createdAt | datetime | Yes | ISO 8601 timestamp |
|
||||||
|
| artifact | string | Yes | Artifact digest being evaluated |
|
||||||
|
| previousId | string | No | Previous snapshot for diff |
|
||||||
|
|
||||||
|
### inputs.sboms
|
||||||
|
|
||||||
|
SBOM documents included in bundle.
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| path | string | Yes | Path within bundle |
|
||||||
|
| format | string | Yes | `cyclonedx-1.6` or `spdx-3.0.1` |
|
||||||
|
| digest | string | Yes | Content digest |
|
||||||
|
|
||||||
|
### inputs.vex
|
||||||
|
|
||||||
|
VEX documents from various sources.
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| path | string | Yes | Path within bundle |
|
||||||
|
| source | string | Yes | Source identifier (vendor:*, distro:*, etc.) |
|
||||||
|
| format | string | Yes | `openvex`, `csaf`, `cyclonedx-vex` |
|
||||||
|
| digest | string | Yes | Content digest |
|
||||||
|
| trustScore | number | Yes | Trust weight (0.0-1.0) |
|
||||||
|
|
||||||
|
### inputs.reachability
|
||||||
|
|
||||||
|
Reachability subgraph data.
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| path | string | Yes | Path within bundle |
|
||||||
|
| entryPoint | string | Yes | Entry point identifier |
|
||||||
|
| digest | string | Yes | Content digest |
|
||||||
|
| nodeCount | integer | No | Number of nodes |
|
||||||
|
| edgeCount | integer | No | Number of edges |
|
||||||
|
|
||||||
|
### inputs.exceptions
|
||||||
|
|
||||||
|
Active exceptions at snapshot time.
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| path | string | Yes | Path within bundle |
|
||||||
|
| exceptionId | string | Yes | Exception identifier |
|
||||||
|
| digest | string | Yes | Content digest |
|
||||||
|
|
||||||
|
### inputs.policies
|
||||||
|
|
||||||
|
Policy bundle reference.
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| bundlePath | string | Yes | Path to policy bundle |
|
||||||
|
| digest | string | Yes | Bundle digest |
|
||||||
|
| version | string | No | Policy version |
|
||||||
|
| rulesHash | string | Yes | Hash of compiled rules |
|
||||||
|
|
||||||
|
### inputs.feeds
|
||||||
|
|
||||||
|
Advisory feed versions at snapshot time.
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| feedId | string | Yes | Feed identifier |
|
||||||
|
| name | string | No | Human-readable name |
|
||||||
|
| version | string | Yes | Feed version/timestamp |
|
||||||
|
| digest | string | Yes | Feed content digest |
|
||||||
|
| fetchedAt | datetime | Yes | When feed was fetched |
|
||||||
|
|
||||||
|
### inputs.lattice
|
||||||
|
|
||||||
|
Lattice configuration for merge semantics.
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| type | string | Yes | `K4`, `Boolean`, `8-state` |
|
||||||
|
| configDigest | string | Yes | Configuration hash |
|
||||||
|
|
||||||
|
### inputs.trust
|
||||||
|
|
||||||
|
Trust weight configuration.
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| configDigest | string | Yes | Configuration hash |
|
||||||
|
| defaultWeight | number | No | Default trust weight |
|
||||||
|
|
||||||
|
### outputs
|
||||||
|
|
||||||
|
Evaluation outputs for verification.
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| verdictPath | string | Yes | Path to verdict file |
|
||||||
|
| verdictDigest | string | Yes | Verdict content digest |
|
||||||
|
| findingsPath | string | No | Path to findings file |
|
||||||
|
| findingsDigest | string | No | Findings content digest |
|
||||||
|
|
||||||
|
### seeds
|
||||||
|
|
||||||
|
Random seeds for deterministic evaluation.
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| rng | integer | No | Random number generator seed |
|
||||||
|
| sampling | integer | No | Sampling algorithm seed |
|
||||||
|
|
||||||
|
### environment
|
||||||
|
|
||||||
|
Environment variables captured (non-sensitive).
|
||||||
|
|
||||||
|
Key-value pairs of environment configuration.
|
||||||
|
|
||||||
|
### signature
|
||||||
|
|
||||||
|
DSSE signature over manifest.
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| algorithm | string | Yes | Signing algorithm |
|
||||||
|
| keyId | string | Yes | Signing key identifier |
|
||||||
|
| value | string | Yes | Base64-encoded signature |
|
||||||
|
|
||||||
|
## Digest Format
|
||||||
|
|
||||||
|
All digests use the format:
|
||||||
|
```
|
||||||
|
sha256:<64-char-hex>
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
sha256:a1b2c3d4e5f6...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
Bundle validation checks:
|
||||||
|
1. REPLAY.yaml exists at bundle root
|
||||||
|
2. All referenced files exist
|
||||||
|
3. All digests match content
|
||||||
|
4. Schema validates against JSON Schema
|
||||||
|
5. Signature verifies (if present)
|
||||||
|
|
||||||
|
## CLI Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create bundle
|
||||||
|
stella snapshot export --output snapshot.stella-replay.tgz
|
||||||
|
|
||||||
|
# Verify bundle
|
||||||
|
stella snapshot verify snapshot.stella-replay.tgz
|
||||||
|
|
||||||
|
# Replay from bundle
|
||||||
|
stella replay --bundle snapshot.stella-replay.tgz
|
||||||
|
|
||||||
|
# View manifest
|
||||||
|
stella snapshot manifest snapshot.stella-replay.tgz
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- [Knowledge Snapshot Model](./knowledge-snapshot.md)
|
||||||
|
- [Merge Preview](./merge-preview.md)
|
||||||
|
- [Replay Engine](../../modules/policy/implementation_plan.md)
|
||||||
176
docs/modules/triage/exploit-path-inbox.md
Normal file
176
docs/modules/triage/exploit-path-inbox.md
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
# Exploit Path Inbox Architecture
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The Exploit Path Inbox provides a triage workflow that groups vulnerabilities by their complete attack chain rather than individual CVEs. This enables analysts to assess and remediate entire exploit paths at once, improving efficiency and ensuring comprehensive coverage.
|
||||||
|
|
||||||
|
## Key Concepts
|
||||||
|
|
||||||
|
### Exploit Path
|
||||||
|
|
||||||
|
An **Exploit Path** represents the complete chain from an entry point to a vulnerable symbol:
|
||||||
|
|
||||||
|
```
|
||||||
|
Artifact → Package → Vulnerable Symbol → Entry Point
|
||||||
|
```
|
||||||
|
|
||||||
|
For example:
|
||||||
|
```
|
||||||
|
sha256:abc... → pkg:npm/lodash@4.17.19 → _.template() → /api/render
|
||||||
|
```
|
||||||
|
|
||||||
|
### Path ID Generation
|
||||||
|
|
||||||
|
Path IDs are deterministic hashes ensuring stable references:
|
||||||
|
|
||||||
|
```
|
||||||
|
PathId = SHA256(artifactDigest | packagePurl | symbolName | entryPointName)
|
||||||
|
```
|
||||||
|
|
||||||
|
This allows:
|
||||||
|
- Consistent tracking across scans
|
||||||
|
- Stable exception targeting
|
||||||
|
- Reproducible audits
|
||||||
|
|
||||||
|
### Grouping Logic
|
||||||
|
|
||||||
|
Findings are grouped into exploit paths based on:
|
||||||
|
|
||||||
|
1. **Reachability Graph**: If reachability data exists, group by actual call paths
|
||||||
|
2. **Fallback**: If no reachability, group by package only
|
||||||
|
|
||||||
|
## Data Model
|
||||||
|
|
||||||
|
### ExploitPath
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `pathId` | string | Stable deterministic identifier |
|
||||||
|
| `artifactDigest` | string | Container image digest |
|
||||||
|
| `package` | PackageRef | Package containing vulnerability |
|
||||||
|
| `symbol` | VulnerableSymbol | Vulnerable function/method |
|
||||||
|
| `entryPoint` | EntryPoint | Entry point exposing the path |
|
||||||
|
| `cveIds` | string[] | All CVEs affecting this path |
|
||||||
|
| `reachability` | ReachabilityStatus | Reachability lattice state |
|
||||||
|
| `riskScore` | PathRiskScore | Aggregated risk metrics |
|
||||||
|
| `evidence` | PathEvidence | Supporting evidence |
|
||||||
|
| `activeExceptions` | ExceptionRef[] | Active suppressions |
|
||||||
|
| `isQuiet` | boolean | Whether path is suppressed |
|
||||||
|
|
||||||
|
### ReachabilityStatus
|
||||||
|
|
||||||
|
| State | Description |
|
||||||
|
|-------|-------------|
|
||||||
|
| `Unknown` | No reachability analysis performed |
|
||||||
|
| `StaticallyReachable` | Static analysis found a path |
|
||||||
|
| `RuntimeConfirmed` | Runtime observation confirmed reachability |
|
||||||
|
| `Unreachable` | Confirmed not reachable |
|
||||||
|
| `Contested` | Conflicting evidence |
|
||||||
|
|
||||||
|
## API Endpoints
|
||||||
|
|
||||||
|
### GET /triage/inbox
|
||||||
|
|
||||||
|
Returns exploit paths for a given scope.
|
||||||
|
|
||||||
|
**Query Parameters:**
|
||||||
|
- `artifactDigest` (string): Filter by artifact
|
||||||
|
- `environment` (string): Filter by environment
|
||||||
|
- `quiet` (boolean): Filter by suppression status
|
||||||
|
- `minCvss` (number): Minimum CVSS score
|
||||||
|
- `reachability` (string): Filter by reachability status
|
||||||
|
- `offset` (number): Pagination offset
|
||||||
|
- `limit` (number): Page size (default 50)
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"paths": [...],
|
||||||
|
"totalCount": 42,
|
||||||
|
"quietCount": 12,
|
||||||
|
"activeCount": 30,
|
||||||
|
"offset": 0,
|
||||||
|
"limit": 50
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET /triage/paths/{pathId}
|
||||||
|
|
||||||
|
Returns detailed exploit path information.
|
||||||
|
|
||||||
|
### GET /triage/paths/{pathId}/proof
|
||||||
|
|
||||||
|
Returns proof bundle (see proof-bundle-spec.md).
|
||||||
|
|
||||||
|
## UI Components
|
||||||
|
|
||||||
|
### Three-Pane Layout
|
||||||
|
|
||||||
|
1. **Left Pane (Path List)**
|
||||||
|
- Exploit paths sorted by risk
|
||||||
|
- Quiet/Active toggle
|
||||||
|
- Search by CVE, package, symbol
|
||||||
|
- Risk score badges
|
||||||
|
|
||||||
|
2. **Center Pane (Path Detail)**
|
||||||
|
- CVE list with scores
|
||||||
|
- Package and symbol info
|
||||||
|
- Entry point context
|
||||||
|
- Active exceptions
|
||||||
|
- "Create Exception" button
|
||||||
|
|
||||||
|
3. **Right Pane (Proof Viewer)**
|
||||||
|
- Reach subgraph visualization
|
||||||
|
- Symbol map with source links
|
||||||
|
- VEX claims with trust badges
|
||||||
|
- "Export Proof" button
|
||||||
|
|
||||||
|
## Integration Points
|
||||||
|
|
||||||
|
### Exception System
|
||||||
|
|
||||||
|
Exceptions can target exploit paths via `pathId`:
|
||||||
|
```yaml
|
||||||
|
scope:
|
||||||
|
pathId: "path:abc123..."
|
||||||
|
```
|
||||||
|
|
||||||
|
This suppresses all CVEs in the path at once.
|
||||||
|
|
||||||
|
### Build Gates
|
||||||
|
|
||||||
|
Build gates can query by exploit path reachability:
|
||||||
|
```yaml
|
||||||
|
gates:
|
||||||
|
- name: block-reachable-critical
|
||||||
|
condition: reachability == "RuntimeConfirmed" && severity == "Critical"
|
||||||
|
action: block
|
||||||
|
```
|
||||||
|
|
||||||
|
### VEX Generation
|
||||||
|
|
||||||
|
VEX statements can reference exploit paths for context:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"vulnerability": "CVE-2024-1234",
|
||||||
|
"product": "sha256:abc...",
|
||||||
|
"status": "not_affected",
|
||||||
|
"justification": "vulnerable_code_not_in_execute_path",
|
||||||
|
"context": {
|
||||||
|
"exploitPathId": "path:abc123..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Triage by Path**: Address entire exploit paths, not individual CVEs
|
||||||
|
2. **Use Reachability**: Prioritize runtime-confirmed paths
|
||||||
|
3. **Document Evidence**: Attach proof bundles to exceptions
|
||||||
|
4. **Regular Review**: Re-evaluate paths when reachability changes
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- [Proof Bundle Specification](./proof-bundle-spec.md)
|
||||||
|
- [Recheck Policy](../policy/recheck-policy.md)
|
||||||
|
- [Evidence Hooks](../policy/evidence-hooks.md)
|
||||||
235
docs/modules/triage/proof-bundle-spec.md
Normal file
235
docs/modules/triage/proof-bundle-spec.md
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
# Proof Bundle Specification
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
A **Proof Bundle** aggregates all evidence supporting an exploit path assessment. It provides a complete, self-contained package for audit, compliance, and decision-making.
|
||||||
|
|
||||||
|
## Bundle Contents
|
||||||
|
|
||||||
|
### 1. Reach Subgraph
|
||||||
|
|
||||||
|
The reachability subgraph shows the call path from entry point to vulnerable symbol.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"id": "node-001",
|
||||||
|
"label": "handleRequest",
|
||||||
|
"type": "entryPoint",
|
||||||
|
"depth": 0,
|
||||||
|
"isVulnerable": false,
|
||||||
|
"isEntryPoint": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "node-002",
|
||||||
|
"label": "renderTemplate",
|
||||||
|
"type": "function",
|
||||||
|
"depth": 1,
|
||||||
|
"isVulnerable": false,
|
||||||
|
"isEntryPoint": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "node-003",
|
||||||
|
"label": "_.template",
|
||||||
|
"type": "vulnerableSymbol",
|
||||||
|
"depth": 2,
|
||||||
|
"isVulnerable": true,
|
||||||
|
"isEntryPoint": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"sourceId": "node-001",
|
||||||
|
"targetId": "node-002",
|
||||||
|
"label": "calls",
|
||||||
|
"weight": 0.95
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceId": "node-002",
|
||||||
|
"targetId": "node-003",
|
||||||
|
"label": "calls",
|
||||||
|
"weight": 0.90
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"entryPointId": "node-001",
|
||||||
|
"vulnerableSymbolId": "node-003",
|
||||||
|
"totalNodes": 3,
|
||||||
|
"totalEdges": 2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Symbol Map
|
||||||
|
|
||||||
|
Maps symbol identifiers to source code locations.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"symbols": [
|
||||||
|
{
|
||||||
|
"id": "node-001",
|
||||||
|
"fullyQualifiedName": "src.api.handleRequest",
|
||||||
|
"sourceFile": "src/api/handler.js",
|
||||||
|
"lineNumber": 42,
|
||||||
|
"language": "javascript",
|
||||||
|
"signature": "function handleRequest(req, res)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "node-003",
|
||||||
|
"fullyQualifiedName": "lodash.template",
|
||||||
|
"sourceFile": "node_modules/lodash/template.js",
|
||||||
|
"lineNumber": 156,
|
||||||
|
"language": "javascript",
|
||||||
|
"signature": "function template(string, options)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sourceFiles": [
|
||||||
|
"src/api/handler.js",
|
||||||
|
"node_modules/lodash/template.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. VEX Claims
|
||||||
|
|
||||||
|
VEX statements from various sources with trust scores.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"vexClaims": [
|
||||||
|
{
|
||||||
|
"cveId": "CVE-2024-1234",
|
||||||
|
"status": "not_affected",
|
||||||
|
"justification": "vulnerable_code_not_in_execute_path",
|
||||||
|
"source": "vendor:lodash",
|
||||||
|
"trustScore": 0.95,
|
||||||
|
"timestamp": "2024-12-22T10:00:00Z",
|
||||||
|
"signatureValid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cveId": "CVE-2024-1234",
|
||||||
|
"status": "affected",
|
||||||
|
"justification": null,
|
||||||
|
"source": "nvd",
|
||||||
|
"trustScore": 0.80,
|
||||||
|
"timestamp": "2024-12-20T08:00:00Z",
|
||||||
|
"signatureValid": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Trust Scores
|
||||||
|
|
||||||
|
Aggregated confidence metrics.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"trustScores": {
|
||||||
|
"reachabilityConfidence": 0.90,
|
||||||
|
"vexConfidence": 0.85,
|
||||||
|
"overallConfidence": 0.875,
|
||||||
|
"evidenceCount": 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Endpoint
|
||||||
|
|
||||||
|
### GET /triage/paths/{pathId}/proof
|
||||||
|
|
||||||
|
Returns the complete proof bundle.
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"pathId": "path:abc123...",
|
||||||
|
"generatedAt": "2024-12-22T12:00:00Z",
|
||||||
|
"reachSubgraph": { ... },
|
||||||
|
"symbolMap": { ... },
|
||||||
|
"vexClaims": [ ... ],
|
||||||
|
"trustScores": { ... },
|
||||||
|
"bundleDigest": "sha256:def456..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET /triage/paths/{pathId}/proof/export
|
||||||
|
|
||||||
|
Returns proof bundle as downloadable JSON file.
|
||||||
|
|
||||||
|
## Bundle Integrity
|
||||||
|
|
||||||
|
Each bundle includes a digest for integrity verification:
|
||||||
|
|
||||||
|
```
|
||||||
|
bundleDigest = SHA256(canonical_json(bundle_without_digest))
|
||||||
|
```
|
||||||
|
|
||||||
|
This allows:
|
||||||
|
- Tamper detection
|
||||||
|
- Audit trail verification
|
||||||
|
- Reproducible exports
|
||||||
|
|
||||||
|
## Visualization
|
||||||
|
|
||||||
|
### Reach Graph Rendering
|
||||||
|
|
||||||
|
Use Cytoscape.js or similar for interactive visualization:
|
||||||
|
- Nodes colored by type (entry point, intermediate, vulnerable)
|
||||||
|
- Edge width indicates confidence weight
|
||||||
|
- Collapsible for large graphs
|
||||||
|
|
||||||
|
### Symbol Navigation
|
||||||
|
|
||||||
|
Click-through from symbols to source code:
|
||||||
|
- IDE integration (VS Code, JetBrains)
|
||||||
|
- GitHub/GitLab links
|
||||||
|
- Line number highlighting
|
||||||
|
|
||||||
|
### VEX Claim Comparison
|
||||||
|
|
||||||
|
Side-by-side view of conflicting VEX statements:
|
||||||
|
- Trust score comparison
|
||||||
|
- Timestamp ordering
|
||||||
|
- Signature verification badges
|
||||||
|
|
||||||
|
## Use Cases
|
||||||
|
|
||||||
|
### Exception Creation
|
||||||
|
|
||||||
|
When creating an exception, attach proof bundle:
|
||||||
|
```yaml
|
||||||
|
exception:
|
||||||
|
pathId: "path:abc123..."
|
||||||
|
proofBundleDigest: "sha256:def456..."
|
||||||
|
evidence:
|
||||||
|
- type: proof-bundle
|
||||||
|
reference: "/triage/paths/path:abc123.../proof"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compliance Audit
|
||||||
|
|
||||||
|
Export proof bundles for compliance documentation:
|
||||||
|
1. Query all active exceptions
|
||||||
|
2. Export proof bundle for each
|
||||||
|
3. Generate PDF report with embedded evidence
|
||||||
|
|
||||||
|
### Dispute Resolution
|
||||||
|
|
||||||
|
When VEX claims conflict:
|
||||||
|
1. View all claims in proof bundle
|
||||||
|
2. Compare trust scores and timestamps
|
||||||
|
3. Document resolution rationale
|
||||||
|
|
||||||
|
## Schema Validation
|
||||||
|
|
||||||
|
Proof bundles must validate against JSON Schema:
|
||||||
|
```
|
||||||
|
$id: https://stellaops.io/schemas/proof-bundle/v1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- [Exploit Path Inbox](./exploit-path-inbox.md)
|
||||||
|
- [VEX Trust Scoring](../excititor/scoring.md)
|
||||||
|
- [Reachability Analysis](../scanner/operations/entrypoint.md)
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
Here’s a tight, first‑time‑friendly blueprint for two Stella Ops UX pillars—**Triage & Exceptions** and **Knowledge Snapshots & Merge Semantics**—with just enough background plus concrete specs your PMs/devs can ship.
|
Here's a tight, first‑time‑friendly blueprint for two Stella Ops UX pillars—**Triage & Exceptions** and **Knowledge Snapshots & Merge Semantics**—with just enough background plus concrete specs your PMs/devs can ship.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Triage & Exceptions (quiet‑by‑design)
|
# Triage & Exceptions (quiet‑by‑design)
|
||||||
|
|
||||||
**Why it matters (plain English):** Most scanners drown users in alerts. “Quiet‑by‑design” shows only *provable, reachable* risks and lets you create **auditable exceptions** (temporary waivers) that auto‑feed compliance packs.
|
**Why it matters (plain English):** Most scanners drown users in alerts. "Quiet‑by‑design" shows only *provable, reachable* risks and lets you create **auditable exceptions** (temporary waivers) that auto‑feed compliance packs.
|
||||||
|
|
||||||
**User flow**
|
**User flow**
|
||||||
|
|
||||||
1. **Inbox grouped by exploit path**
|
1. **Inbox grouped by exploit path**
|
||||||
|
|
||||||
* Group key = `(artifact → package → vulnerable symbol → runtime path)`.
|
* Group key = `(artifact → package → vulnerable symbol → runtime path)`.
|
||||||
* Each group shows: risk score, blast radius (count of dependents), EPSS/CVSS, and a “Proof” button.
|
* Each group shows: risk score, blast radius (count of dependents), EPSS/CVSS, and a "Proof" button.
|
||||||
2. **Open a path → Proof bundle**
|
2. **Open a path → Proof bundle**
|
||||||
|
|
||||||
* **Reach subgraph** (who calls what).
|
* **Reach subgraph** (who calls what).
|
||||||
@@ -19,7 +19,7 @@ Here’s a tight, first‑time‑friendly blueprint for two Stella Ops UX pill
|
|||||||
* **VEX claims** (vendor/distro/internal) with trust score + signatures.
|
* **VEX claims** (vendor/distro/internal) with trust score + signatures.
|
||||||
3. **Raise Exception** (time‑boxed)
|
3. **Raise Exception** (time‑boxed)
|
||||||
|
|
||||||
* **Required fields:** attested reason (dropdown + free text), expiry date, recheck policy (e.g., “fail build if new reachable path appears”, “fail if EPSS > X”).
|
* **Required fields:** attested reason (dropdown + free text), expiry date, recheck policy (e.g., "fail build if new reachable path appears", "fail if EPSS > X").
|
||||||
* **Attestation:** DSSE‑signed exception object, OCI‑attached to artifact digest.
|
* **Attestation:** DSSE‑signed exception object, OCI‑attached to artifact digest.
|
||||||
* Auto‑lands in **Audit Pack** (PDF/JSON bundle) and **Timeline**.
|
* Auto‑lands in **Audit Pack** (PDF/JSON bundle) and **Timeline**.
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ record ExceptionObj(
|
|||||||
|
|
||||||
# Knowledge Snapshots & Merge Semantics
|
# Knowledge Snapshots & Merge Semantics
|
||||||
|
|
||||||
**Plain English:** Take a sealed “photo” of everything you *know* at a point in time—SBOM, VEX, attestations, policies—so audits and incident reviews can be replayed exactly.
|
**Plain English:** Take a sealed "photo" of everything you *know* at a point in time—SBOM, VEX, attestations, policies—so audits and incident reviews can be replayed exactly.
|
||||||
|
|
||||||
**Lifecycle: Snapshot → Seal → Export**
|
**Lifecycle: Snapshot → Seal → Export**
|
||||||
|
|
||||||
@@ -82,19 +82,19 @@ record ExceptionObj(
|
|||||||
|
|
||||||
**Policy pane with merge semantics**
|
**Policy pane with merge semantics**
|
||||||
|
|
||||||
* Default preview: **vendor ⊕ distro ⊕ internal** (not “vendor > distro > internal”).
|
* Default preview: **vendor ⊕ distro ⊕ internal** (not "vendor > distro > internal").
|
||||||
* **Lattice rules** define resolution (e.g., `NOT_AFFECTED ⊕ AFFECTED → AFFECTED unless Evidence(feature_flag_off)`).
|
* **Lattice rules** define resolution (e.g., `NOT_AFFECTED ⊕ AFFECTED → AFFECTED unless Evidence(feature_flag_off)`).
|
||||||
* **Evidence hooks (required):**
|
* **Evidence hooks (required):**
|
||||||
|
|
||||||
* “Not affected because feature X off” → must include **feature‑flag attestation** (env‑scoped, signed).
|
* "Not affected because feature X off" → must include **feature‑flag attestation** (env‑scoped, signed).
|
||||||
* “Backported patch” → must include **patch‑index** mapping (`fixed‑symbols`, commit OIDs).
|
* "Backported patch" → must include **patch‑index** mapping (`fixed‑symbols`, commit OIDs).
|
||||||
* “Compensating control” → must include **control attestation** (control ID, monitoring link, SLO).
|
* "Compensating control" → must include **control attestation** (control ID, monitoring link, SLO).
|
||||||
|
|
||||||
**UI essentials**
|
**UI essentials**
|
||||||
|
|
||||||
* **Snapshot panel:** shows inputs (feed versions, rules hash), diff vs last snapshot, “Seal & Export” button.
|
* **Snapshot panel:** shows inputs (feed versions, rules hash), diff vs last snapshot, "Seal & Export" button.
|
||||||
* **Policy pane:** interactive merge preview; failed hooks highlighted with “Add evidence” CTA.
|
* **Policy pane:** interactive merge preview; failed hooks highlighted with "Add evidence" CTA.
|
||||||
* **Replay check:** “Verify determinism” runs local re‑eval; shows PASS/FAIL badge.
|
* **Replay check:** "Verify determinism" runs local re‑eval; shows PASS/FAIL badge.
|
||||||
|
|
||||||
**APIs**
|
**APIs**
|
||||||
|
|
||||||
@@ -138,3 +138,22 @@ record ExceptionObj(
|
|||||||
---
|
---
|
||||||
|
|
||||||
If you want, I can turn this into: (a) Swagger stubs, (b) EF Core schema + migrations, or (c) a Figma‑ready UI spec with screen flows and copy.
|
If you want, I can turn this into: (a) Swagger stubs, (b) EF Core schema + migrations, or (c) a Figma‑ready UI spec with screen flows and copy.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Archive Note
|
||||||
|
|
||||||
|
**Archived:** 2025-12-22
|
||||||
|
|
||||||
|
**Disposition:** Converted to implementation sprints:
|
||||||
|
- `SPRINT_3900_0003_0001_exploit_path_inbox_proof_bundles.md`
|
||||||
|
- `SPRINT_3900_0003_0002_recheck_policy_evidence_hooks.md`
|
||||||
|
- `SPRINT_4100_0003_0001_snapshot_merge_preview_replay_ui.md`
|
||||||
|
|
||||||
|
**Documentation created:**
|
||||||
|
- `docs/modules/triage/exploit-path-inbox.md`
|
||||||
|
- `docs/modules/triage/proof-bundle-spec.md`
|
||||||
|
- `docs/modules/policy/recheck-policy.md`
|
||||||
|
- `docs/modules/policy/evidence-hooks.md`
|
||||||
|
- `docs/modules/snapshot/replay-yaml.md`
|
||||||
|
- `docs/modules/snapshot/merge-preview.md`
|
||||||
Reference in New Issue
Block a user