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)
|
||||
Reference in New Issue
Block a user