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
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:
{
"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:
{
"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:
{
"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:
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:
minTrustScore: 0.8 # 80% trust required
Trust scores come from the source registry.
Signature Verification
If evidence includes a DSSE envelope, signature is verified:
{
"content": { ... },
"dsseEnvelope": "eyJwYXlsb2FkIjoi...",
"signatureVerified": true
}
Validation must fail closed when a verifier, trusted key, or transparency proof verifier is unavailable. Presence of a DSSE-shaped blob, base64 signature bytes, or a local placeholder signature is not accepted as proof of trust outside explicit dev/test harnesses.
For VEX proof gates, required proof metadata is part of the evidence contract. A proof cannot satisfy release-gate requirements by omitting confidence tier, input statement count, signed-statement status, proof timestamp, DSSE envelope digest, or Rekor log index. Missing values deny the gate when the corresponding policy requirement is active.
Schema Validation
Custom attestations can require schema validation:
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 |
Persistence
- Hook registry:
policy.evidence_hookswithmax_age_secondsandmin_trust_score. - Evidence submissions:
policy.submitted_evidencewithvalidation_status,reference, and optionaldsse_envelope.
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:
{
"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:
{
"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:
- File upload for attestations
- URL input for external references
- 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
- Mandatory = Critical: Only mark truly required evidence as mandatory
- Reasonable maxAge: Balance freshness with operational burden
- Trust Scores: Configure source trust appropriately
- Documentation: Document what each evidence type means
- Automation: Integrate with systems to auto-generate attestations
DSSE Attestation Format
Evidence can be wrapped in DSSE for integrity:
{
"payloadType": "application/vnd.stellaops.evidence+json",
"payload": "<base64-encoded-evidence>",
"signatures": [
{
"keyid": "key-123",
"sig": "<base64-signature>"
}
]
}
Example Hook Configurations
Critical CVE Policy
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
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
- Exception Workflow
- DSSE Attestations
