tests fixes and some product advisories tunes ups
This commit is contained in:
@@ -739,54 +739,213 @@ sequenceDiagram
|
||||
- Health endpoints: `/health/liveness`, `/health/readiness`, `/status`; verification probe `/api/attestations/verify` once demo bundle is available (see runbook).
|
||||
- Alert hints: signing latency > 1s p99, verification failure spikes, tlog submission lag >10s, key rotation age over policy threshold, backlog above configured threshold.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 17) Rekor Entry Events
|
||||
|
||||
> Sprint: SPRINT_20260112_007_ATTESTOR_rekor_entry_events
|
||||
|
||||
Attestor emits deterministic events when DSSE bundles are logged to Rekor and inclusion proofs become available. These events drive policy reanalysis.
|
||||
|
||||
### Event Types
|
||||
|
||||
| Event Type | Constant | Description |
|
||||
|------------|----------|-------------|
|
||||
| `rekor.entry.logged` | `RekorEventTypes.EntryLogged` | Bundle successfully logged with inclusion proof |
|
||||
| `rekor.entry.queued` | `RekorEventTypes.EntryQueued` | Bundle queued for logging (async mode) |
|
||||
| `rekor.entry.inclusion_verified` | `RekorEventTypes.InclusionVerified` | Inclusion proof independently verified |
|
||||
| `rekor.entry.failed` | `RekorEventTypes.EntryFailed` | Logging or verification failed |
|
||||
|
||||
### RekorEntryEvent Schema
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"eventId": "rekor-evt-sha256:...",
|
||||
"eventType": "rekor.entry.logged",
|
||||
"tenant": "default",
|
||||
"bundleDigest": "sha256:abc123...",
|
||||
"artifactDigest": "sha256:def456...",
|
||||
"predicateType": "StellaOps.ScanResults@1",
|
||||
"rekorEntry": {
|
||||
"uuid": "24296fb24b8ad77a...",
|
||||
"logIndex": 123456789,
|
||||
"logUrl": "https://rekor.sigstore.dev",
|
||||
"integratedTime": "2026-01-15T10:30:02Z"
|
||||
},
|
||||
"reanalysisHints": {
|
||||
"cveIds": ["CVE-2026-1234"],
|
||||
"productKeys": ["pkg:npm/lodash@4.17.21"],
|
||||
"mayAffectDecision": true,
|
||||
"reanalysisScope": "immediate"
|
||||
},
|
||||
"occurredAtUtc": "2026-01-15T10:30:05Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Offline Mode Behavior
|
||||
|
||||
When operating in offline/air-gapped mode:
|
||||
1. Events are not emitted when Rekor is unreachable
|
||||
2. Bundles are queued locally for later submission
|
||||
3. Verification uses bundled checkpoints
|
||||
|
||||
---
|
||||
|
||||
## 17) Rekor Entry Events
|
||||
|
||||
> Sprint: SPRINT_20260112_007_ATTESTOR_rekor_entry_events
|
||||
|
||||
Attestor emits deterministic events when DSSE bundles are logged to Rekor and inclusion proofs become available. These events drive policy reanalysis.
|
||||
|
||||
### Event Types
|
||||
|
||||
| Event Type | Constant | Description |
|
||||
|------------|----------|-------------|
|
||||
| `rekor.entry.logged` | `RekorEventTypes.EntryLogged` | Bundle successfully logged with inclusion proof |
|
||||
| `rekor.entry.queued` | `RekorEventTypes.EntryQueued` | Bundle queued for logging (async mode) |
|
||||
| `rekor.entry.inclusion_verified` | `RekorEventTypes.InclusionVerified` | Inclusion proof independently verified |
|
||||
| `rekor.entry.failed` | `RekorEventTypes.EntryFailed` | Logging or verification failed |
|
||||
|
||||
### RekorEntryEvent Schema
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"eventId": "rekor-evt-sha256:...",
|
||||
"eventType": "rekor.entry.logged",
|
||||
"tenant": "default",
|
||||
"bundleDigest": "sha256:abc123...",
|
||||
"artifactDigest": "sha256:def456...",
|
||||
"predicateType": "StellaOps.ScanResults@1",
|
||||
"rekorEntry": {
|
||||
"uuid": "24296fb24b8ad77a...",
|
||||
"logIndex": 123456789,
|
||||
"logUrl": "https://rekor.sigstore.dev",
|
||||
"integratedTime": "2026-01-15T10:30:02Z"
|
||||
},
|
||||
"reanalysisHints": {
|
||||
"cveIds": ["CVE-2026-1234"],
|
||||
"productKeys": ["pkg:npm/lodash@4.17.21"],
|
||||
"mayAffectDecision": true,
|
||||
"reanalysisScope": "immediate"
|
||||
},
|
||||
"occurredAtUtc": "2026-01-15T10:30:05Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Offline Mode Behavior
|
||||
|
||||
When operating in offline/air-gapped mode:
|
||||
1. Events are not emitted when Rekor is unreachable
|
||||
2. Bundles are queued locally for later submission
|
||||
3. Verification uses bundled checkpoints
|
||||
4. Events are generated when connectivity is restored
|
||||
|
||||
---
|
||||
|
||||
## 18) Identity Watchlist & Monitoring
|
||||
|
||||
> Sprint: SPRINT_0129_001_ATTESTOR_identity_watchlist_alerting
|
||||
|
||||
The Attestor provides proactive monitoring for signing identities appearing in transparency logs. Organizations can define watchlists to receive alerts when specific identities sign artifacts.
|
||||
|
||||
### Purpose
|
||||
|
||||
- **Credential compromise detection**: Alert when your signing identity appears unexpectedly
|
||||
- **Third-party monitoring**: Watch for specific vendors or dependencies signing artifacts
|
||||
- **Compliance auditing**: Track all signing activity for specific issuers
|
||||
|
||||
### Watchlist Entry Model
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"id": "uuid",
|
||||
"tenantId": "tenant-123",
|
||||
"scope": "tenant", // tenant | global | system
|
||||
"displayName": "GitHub Actions Signer",
|
||||
"description": "Watch for GitHub Actions OIDC tokens",
|
||||
|
||||
// Identity fields (at least one required)
|
||||
"issuer": "https://token.actions.githubusercontent.com",
|
||||
"subjectAlternativeName": "repo:org/repo:*", // glob pattern
|
||||
"keyId": null,
|
||||
|
||||
"matchMode": "glob", // exact | prefix | glob | regex
|
||||
|
||||
// Alert configuration
|
||||
"severity": "warning", // info | warning | critical
|
||||
"enabled": true,
|
||||
"channelOverrides": ["slack-security"],
|
||||
"suppressDuplicatesMinutes": 60,
|
||||
|
||||
"tags": ["github", "ci-cd"],
|
||||
"createdAt": "2026-01-29T10:00:00Z",
|
||||
"createdBy": "admin@example.com"
|
||||
}
|
||||
```
|
||||
|
||||
### Matching Modes
|
||||
|
||||
| Mode | Behavior | Example Pattern | Matches |
|
||||
|------|----------|-----------------|---------|
|
||||
| `exact` | Case-insensitive equality | `alice@example.com` | `Alice@example.com` |
|
||||
| `prefix` | Starts-with match | `https://accounts.google.com/` | Any Google OIDC issuer |
|
||||
| `glob` | Glob pattern (`*`, `?`) | `*@example.com` | `alice@example.com`, `bob@example.com` |
|
||||
| `regex` | Full regex (with timeout) | `repo:org/(frontend\|backend):.*` | `repo:org/frontend:ref:main` |
|
||||
|
||||
### Scope Hierarchy
|
||||
|
||||
| Scope | Visibility | Who Can Create |
|
||||
|-------|------------|----------------|
|
||||
| `tenant` | Owning tenant only | Tenant admins |
|
||||
| `global` | All tenants | Platform admins |
|
||||
| `system` | All tenants (read-only) | System bootstrap |
|
||||
|
||||
### Event Flow
|
||||
|
||||
```
|
||||
New AttestorEntry persisted
|
||||
→ SignerIdentityDescriptor extracted
|
||||
→ IIdentityMatcher.MatchAsync()
|
||||
→ For each match:
|
||||
→ Check dedup window (default 60 min)
|
||||
→ Emit attestor.identity.matched event
|
||||
→ Route via Notifier rules → Slack/Email/Webhook
|
||||
```
|
||||
|
||||
### Event Schema (IdentityAlertEvent)
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"eventId": "uuid",
|
||||
"eventKind": "attestor.identity.matched",
|
||||
"tenantId": "tenant-123",
|
||||
"watchlistEntryId": "uuid",
|
||||
"watchlistEntryName": "GitHub Actions Signer",
|
||||
"matchedIdentity": {
|
||||
"issuer": "https://token.actions.githubusercontent.com",
|
||||
"subjectAlternativeName": "repo:org/repo:ref:refs/heads/main",
|
||||
"keyId": null
|
||||
},
|
||||
"rekorEntry": {
|
||||
"uuid": "24296fb24b8ad77a...",
|
||||
"logIndex": 123456789,
|
||||
"artifactSha256": "sha256:abc123...",
|
||||
"integratedTimeUtc": "2026-01-29T10:30:00Z"
|
||||
},
|
||||
"severity": "warning",
|
||||
"occurredAtUtc": "2026-01-29T10:30:05Z",
|
||||
"suppressedCount": 0
|
||||
}
|
||||
```
|
||||
|
||||
### API Endpoints
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `POST` | `/api/v1/watchlist` | Create watchlist entry |
|
||||
| `GET` | `/api/v1/watchlist` | List entries (tenant + optional global) |
|
||||
| `GET` | `/api/v1/watchlist/{id}` | Get single entry |
|
||||
| `PUT` | `/api/v1/watchlist/{id}` | Update entry |
|
||||
| `DELETE` | `/api/v1/watchlist/{id}` | Delete entry |
|
||||
| `POST` | `/api/v1/watchlist/{id}/test` | Test pattern against sample identity |
|
||||
| `GET` | `/api/v1/watchlist/alerts` | List recent alerts (paginated) |
|
||||
|
||||
### CLI Commands
|
||||
|
||||
```bash
|
||||
# Add a watchlist entry
|
||||
stella watchlist add --issuer "https://token.actions.githubusercontent.com" \
|
||||
--san "repo:org/*" --match-mode glob --severity warning
|
||||
|
||||
# List entries
|
||||
stella watchlist list --include-global
|
||||
|
||||
# Test a pattern
|
||||
stella watchlist test <id> --issuer "https://..." --san "repo:org/repo:ref:main"
|
||||
|
||||
# View recent alerts
|
||||
stella watchlist alerts --since 24h --severity warning
|
||||
```
|
||||
|
||||
### Metrics
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| `attestor.watchlist.entries_scanned_total` | Entries processed by monitor |
|
||||
| `attestor.watchlist.matches_total{severity}` | Pattern matches by severity |
|
||||
| `attestor.watchlist.alerts_emitted_total` | Alerts sent to notification system |
|
||||
| `attestor.watchlist.alerts_suppressed_total` | Alerts deduplicated |
|
||||
| `attestor.watchlist.scan_latency_seconds` | Per-entry scan duration |
|
||||
|
||||
### Configuration
|
||||
|
||||
```yaml
|
||||
attestor:
|
||||
watchlist:
|
||||
enabled: true
|
||||
monitorMode: "changefeed" # changefeed | polling
|
||||
pollingIntervalSeconds: 5 # only for polling mode
|
||||
maxEventsPerSecond: 100 # rate limit
|
||||
defaultDedupWindowMinutes: 60
|
||||
regexTimeoutMs: 100 # safety limit
|
||||
maxWatchlistEntriesPerTenant: 1000
|
||||
```
|
||||
|
||||
### Offline Mode
|
||||
|
||||
In air-gapped environments:
|
||||
- Polling mode used instead of Postgres NOTIFY
|
||||
- Alerts queued locally if notification channels unavailable
|
||||
- Alerts delivered when connectivity restored
|
||||
|
||||
|
||||
237
docs/modules/attestor/guides/identity-watchlist.md
Normal file
237
docs/modules/attestor/guides/identity-watchlist.md
Normal file
@@ -0,0 +1,237 @@
|
||||
# Identity Watchlist User Guide
|
||||
|
||||
This guide covers how to use the identity watchlist feature in Stella Ops to monitor signing activity in transparency logs.
|
||||
|
||||
## Overview
|
||||
|
||||
The identity watchlist enables proactive alerting when specific signing identities appear in Rekor transparency log entries. Use cases include:
|
||||
|
||||
- **Threat Detection**: Monitor for known malicious or compromised signing identities
|
||||
- **Compliance Monitoring**: Track when specific OIDC issuers sign artifacts
|
||||
- **Operational Awareness**: Get notified when CI/CD workflows from specific repositories sign releases
|
||||
- **Key Tracking**: Monitor usage of specific signing keys across your organization
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### Watchlist Entries
|
||||
|
||||
A watchlist entry defines an identity pattern to monitor and alert configuration:
|
||||
|
||||
| Field | Description | Required |
|
||||
|-------|-------------|----------|
|
||||
| `displayName` | Human-readable label | Yes |
|
||||
| `description` | Why this identity is watched | No |
|
||||
| `issuer` | OIDC issuer URL pattern | At least one |
|
||||
| `subjectAlternativeName` | Certificate SAN pattern | of these |
|
||||
| `keyId` | Key identifier for keyful signing | three |
|
||||
| `matchMode` | Pattern matching mode | No (default: `exact`) |
|
||||
| `severity` | Alert severity level | No (default: `warning`) |
|
||||
| `enabled` | Whether entry is active | No (default: `true`) |
|
||||
| `scope` | Visibility scope | No (default: `tenant`) |
|
||||
|
||||
### Match Modes
|
||||
|
||||
| Mode | Description | Example Pattern | Matches |
|
||||
|------|-------------|-----------------|---------|
|
||||
| `exact` | Case-insensitive equality | `https://accounts.google.com` | Only that exact URL |
|
||||
| `prefix` | Starts with pattern | `https://token.actions.` | Any GitHub Actions issuer |
|
||||
| `glob` | Wildcard matching | `*@example.com` | Any email at example.com |
|
||||
| `regex` | Full regex (advanced) | `user\d+@.*` | user123@domain.com |
|
||||
|
||||
> **Note**: Regex mode has a 100ms timeout and pattern validation. Use sparingly for performance-critical environments.
|
||||
|
||||
### Severity Levels
|
||||
|
||||
| Level | Use Case | Notification Priority |
|
||||
|-------|----------|----------------------|
|
||||
| `info` | Informational tracking | Low |
|
||||
| `warning` | Unexpected but not critical (default) | Medium |
|
||||
| `critical` | Immediate attention required | High |
|
||||
|
||||
### Scope Levels
|
||||
|
||||
| Scope | Description | Who Can Create |
|
||||
|-------|-------------|----------------|
|
||||
| `tenant` | Visible only to owning tenant | Any user with `watchlist:write` |
|
||||
| `global` | Shared across all tenants | Administrators only |
|
||||
| `system` | System-managed entries | System only |
|
||||
|
||||
## CLI Usage
|
||||
|
||||
### Adding a Watchlist Entry
|
||||
|
||||
Monitor a specific OIDC issuer:
|
||||
```bash
|
||||
stella watchlist add \
|
||||
--issuer "https://token.actions.githubusercontent.com" \
|
||||
--name "GitHub Actions" \
|
||||
--severity warning \
|
||||
--description "Track all GitHub Actions signatures"
|
||||
```
|
||||
|
||||
Monitor email patterns with glob matching:
|
||||
```bash
|
||||
stella watchlist add \
|
||||
--san "*@malicious-domain.com" \
|
||||
--match-mode glob \
|
||||
--severity critical \
|
||||
--name "Malicious Domain"
|
||||
```
|
||||
|
||||
### Listing Entries
|
||||
|
||||
List all entries including global ones:
|
||||
```bash
|
||||
stella watchlist list --include-global
|
||||
```
|
||||
|
||||
Output as JSON for scripting:
|
||||
```bash
|
||||
stella watchlist list --format json
|
||||
```
|
||||
|
||||
### Testing Patterns
|
||||
|
||||
Test if an identity would trigger an alert:
|
||||
```bash
|
||||
stella watchlist test <entry-id> \
|
||||
--issuer "https://token.actions.githubusercontent.com" \
|
||||
--san "repo:org/repo:ref:refs/heads/main"
|
||||
```
|
||||
|
||||
### Managing Entries
|
||||
|
||||
Update an entry:
|
||||
```bash
|
||||
stella watchlist update <entry-id> --enabled false
|
||||
stella watchlist update <entry-id> --severity critical
|
||||
```
|
||||
|
||||
Delete an entry:
|
||||
```bash
|
||||
stella watchlist remove <entry-id>
|
||||
stella watchlist remove <entry-id> --force # Skip confirmation
|
||||
```
|
||||
|
||||
### Viewing Alerts
|
||||
|
||||
List recent alerts:
|
||||
```bash
|
||||
stella watchlist alerts --since 24h
|
||||
stella watchlist alerts --severity critical --limit 50
|
||||
```
|
||||
|
||||
## API Usage
|
||||
|
||||
### Create Entry
|
||||
|
||||
```http
|
||||
POST /api/v1/watchlist
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"displayName": "GitHub Actions Monitor",
|
||||
"issuer": "https://token.actions.githubusercontent.com",
|
||||
"matchMode": "prefix",
|
||||
"severity": "warning",
|
||||
"description": "Monitor all GitHub Actions signatures",
|
||||
"enabled": true,
|
||||
"suppressDuplicatesMinutes": 60
|
||||
}
|
||||
```
|
||||
|
||||
### List Entries
|
||||
|
||||
```http
|
||||
GET /api/v1/watchlist?includeGlobal=true
|
||||
```
|
||||
|
||||
### Test Pattern
|
||||
|
||||
```http
|
||||
POST /api/v1/watchlist/{id}/test
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"issuer": "https://token.actions.githubusercontent.com",
|
||||
"subjectAlternativeName": "repo:org/repo:ref:refs/heads/main"
|
||||
}
|
||||
```
|
||||
|
||||
## Alert Deduplication
|
||||
|
||||
To prevent alert storms, the watchlist system deduplicates alerts based on:
|
||||
|
||||
1. **Watchlist Entry ID** - Which entry triggered the alert
|
||||
2. **Identity Hash** - SHA-256 of the matched identity fields
|
||||
|
||||
Configure the deduplication window per entry with `suppressDuplicatesMinutes` (default: 60 minutes).
|
||||
|
||||
When an alert is suppressed, subsequent alerts will include a `suppressedCount` indicating how many similar alerts were skipped.
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Pattern Design
|
||||
|
||||
1. **Start specific, broaden as needed**: Begin with exact matches before using wildcards
|
||||
2. **Test before deploying**: Use the test endpoint to validate patterns
|
||||
3. **Document why**: Always include a description explaining the monitoring purpose
|
||||
4. **Use appropriate match modes**:
|
||||
- `exact` for known bad actors
|
||||
- `prefix` for issuer families (e.g., all Google issuers)
|
||||
- `glob` for email/SAN patterns
|
||||
- `regex` only when simpler modes can't express the pattern
|
||||
|
||||
### Performance Considerations
|
||||
|
||||
- Limit regex patterns to < 256 characters
|
||||
- Avoid catastrophic backtracking patterns (e.g., `(a+)+`)
|
||||
- Monitor the `attestor.watchlist.scan_latency_seconds` metric
|
||||
- Keep watchlist size reasonable (< 1000 entries per tenant)
|
||||
|
||||
### Alert Management
|
||||
|
||||
1. **Set appropriate severity**: Reserve `critical` for genuine emergencies
|
||||
2. **Configure dedup windows**: Use shorter windows (5-15 min) for critical entries
|
||||
3. **Review suppressed counts**: High counts may indicate a pattern is too broad
|
||||
4. **Route appropriately**: Use channel overrides for sensitive entries
|
||||
|
||||
## Monitoring & Metrics
|
||||
|
||||
The following OpenTelemetry metrics are exposed:
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| `attestor.watchlist.entries_scanned_total` | Total Rekor entries processed |
|
||||
| `attestor.watchlist.matches_total{severity}` | Pattern matches by severity |
|
||||
| `attestor.watchlist.alerts_emitted_total` | Alerts sent to notification system |
|
||||
| `attestor.watchlist.alerts_suppressed_total` | Alerts suppressed by deduplication |
|
||||
| `attestor.watchlist.scan_latency_seconds` | Per-entry scan duration |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Entry Not Matching Expected Identity
|
||||
|
||||
1. Verify the match mode is appropriate for your pattern
|
||||
2. Use the test endpoint with verbose output
|
||||
3. Check if the entry is enabled
|
||||
4. Verify case sensitivity (all modes are case-insensitive)
|
||||
|
||||
### Too Many Alerts
|
||||
|
||||
1. Increase `suppressDuplicatesMinutes`
|
||||
2. Narrow the pattern (more specific issuer, SAN prefix)
|
||||
3. Consider if the pattern is too broad
|
||||
|
||||
### Missing Alerts
|
||||
|
||||
1. Verify the entry is enabled
|
||||
2. Check if alerts are being suppressed (view suppressed count)
|
||||
3. Verify notification routing is configured
|
||||
4. Check service logs for matching errors
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Attestor Architecture](../architecture.md)
|
||||
- [Notification Templates](../../notify/templates.md)
|
||||
- [Watchlist Monitoring Runbook](../../operations/watchlist-monitoring-runbook.md)
|
||||
@@ -1496,5 +1496,101 @@ A mismatch fails the blob replay verification step.
|
||||
|
||||
---
|
||||
|
||||
*Document Version: 1.2.0*
|
||||
*Last Updated: 2026-01-21*
|
||||
## 12. Binary Micro-Witnesses
|
||||
|
||||
Binary micro-witnesses provide cryptographic proof of patch status at the binary level. They formalize the output of BinaryIndex's semantic diffing capabilities into an auditor-friendly, portable format.
|
||||
|
||||
### 12.1 Overview
|
||||
|
||||
A micro-witness is a DSSE (Dead Simple Signing Envelope) predicate that captures:
|
||||
- Subject binary digest (SHA-256)
|
||||
- CVE/patch reference
|
||||
- Function-level evidence with confidence scores
|
||||
- Delta-Sig fingerprint hash
|
||||
- Tool versions and analysis metadata
|
||||
- Optional SBOM component mapping
|
||||
|
||||
### 12.2 Predicate Schema
|
||||
|
||||
**Predicate Type:** `https://stellaops.dev/predicates/binary-micro-witness@v1`
|
||||
|
||||
```json
|
||||
{
|
||||
"schemaVersion": "1.0.0",
|
||||
"binary": {
|
||||
"digest": "sha256:...",
|
||||
"purl": "pkg:deb/debian/openssl@3.0.11",
|
||||
"arch": "linux-amd64",
|
||||
"filename": "libssl.so.3"
|
||||
},
|
||||
"cve": {
|
||||
"id": "CVE-2024-0567",
|
||||
"advisory": "https://...",
|
||||
"patchCommit": "abc123"
|
||||
},
|
||||
"verdict": "patched",
|
||||
"confidence": 0.95,
|
||||
"evidence": [
|
||||
{
|
||||
"function": "SSL_CTX_new",
|
||||
"state": "patched",
|
||||
"score": 0.97,
|
||||
"method": "semantic_ksg",
|
||||
"hash": "sha256:..."
|
||||
}
|
||||
],
|
||||
"deltaSigDigest": "sha256:...",
|
||||
"sbomRef": {
|
||||
"sbomDigest": "sha256:...",
|
||||
"purl": "pkg:...",
|
||||
"bomRef": "component-ref"
|
||||
},
|
||||
"tooling": {
|
||||
"binaryIndexVersion": "2.1.0",
|
||||
"lifter": "b2r2",
|
||||
"matchAlgorithm": "semantic_ksg"
|
||||
},
|
||||
"computedAt": "2026-01-28T12:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### 12.3 Verdicts
|
||||
|
||||
| Verdict | Meaning |
|
||||
|---------|---------|
|
||||
| `patched` | Binary matches patched version signature |
|
||||
| `vulnerable` | Binary matches vulnerable version signature |
|
||||
| `inconclusive` | Unable to determine (insufficient evidence) |
|
||||
| `partial` | Some functions patched, others not |
|
||||
|
||||
### 12.4 CLI Commands
|
||||
|
||||
```bash
|
||||
# Generate a micro-witness
|
||||
stella witness generate /path/to/binary --cve CVE-2024-0567 --sbom sbom.json --output witness.json
|
||||
|
||||
# Verify a micro-witness
|
||||
stella witness verify witness.json --offline
|
||||
|
||||
# Create portable bundle for air-gapped verification
|
||||
stella witness bundle witness.json --output ./audit-bundle
|
||||
```
|
||||
|
||||
### 12.5 Integration with Rekor
|
||||
|
||||
When `--rekor` is specified during generation, witnesses are logged to the Rekor transparency log using v2 tile-based inclusion proofs. This provides tamper-evidence and enables auditors to verify witnesses weren't backdated.
|
||||
|
||||
Offline verification bundles include tile proofs for air-gapped environments.
|
||||
|
||||
### 12.6 Related Documentation
|
||||
|
||||
- **Auditor Guide:** `docs/guides/binary-micro-witness-verification.md`
|
||||
- **Predicate Schema:** `src/Attestor/StellaOps.Attestor.Types/schemas/stellaops-binary-micro-witness.v1.schema.json`
|
||||
- **CLI Commands:** `src/Cli/StellaOps.Cli/Commands/Witness/`
|
||||
- **Demo Bundle:** `demos/binary-micro-witness/`
|
||||
- **Sprint:** `docs-archived/implplan/SPRINT_0128_001_BinaryIndex_binary_micro_witness.md`
|
||||
|
||||
---
|
||||
|
||||
*Document Version: 1.3.0*
|
||||
*Last Updated: 2026-01-28*
|
||||
|
||||
@@ -995,6 +995,70 @@ Group: `/api/v1/policy/interop` with tag `PolicyInterop`
|
||||
| POST | `/evaluate` | `platform.policy.evaluate` | Evaluate policy against input |
|
||||
| GET | `/formats` | `platform.policy.read` | List supported formats |
|
||||
|
||||
### 13.9 · OPA Supply Chain Evidence Input
|
||||
|
||||
> **Sprint:** SPRINT_0129_001_Policy_supply_chain_evidence_input
|
||||
|
||||
OPA policies can optionally access comprehensive supply chain evidence beyond basic VEX merge results. When `PolicyGateContext.SupplyChainEvidence` is populated, the following fields become available in the OPA input:
|
||||
|
||||
| Input Field | Type | Description |
|
||||
|-------------|------|-------------|
|
||||
| `artifact.digest` | string | Artifact digest (e.g., `sha256:abc...`) |
|
||||
| `artifact.mediaType` | string | OCI media type |
|
||||
| `artifact.reference` | string | Full artifact reference |
|
||||
| `sbom.digest` | string | SBOM content hash |
|
||||
| `sbom.format` | string | Format identifier (e.g., `cyclonedx-1.7`, `spdx-3.0.1`) |
|
||||
| `sbom.componentCount` | int | Number of components |
|
||||
| `sbom.content` | object | Optional inline SBOM JSON |
|
||||
| `attestations[]` | array | Attestation references |
|
||||
| `attestations[].digest` | string | DSSE envelope digest |
|
||||
| `attestations[].predicateType` | string | in-toto predicate type URI |
|
||||
| `attestations[].signatureVerified` | bool | Signature verification status |
|
||||
| `attestations[].rekorLogIndex` | long | Transparency log index |
|
||||
| `transparency.rekor[]` | array | Rekor receipts |
|
||||
| `transparency.rekor[].logId` | string | Log identifier |
|
||||
| `transparency.rekor[].uuid` | string | Entry UUID |
|
||||
| `transparency.rekor[].logIndex` | long | Log position |
|
||||
| `transparency.rekor[].integratedTime` | long | Unix timestamp |
|
||||
| `transparency.rekor[].verified` | bool | Receipt verification status |
|
||||
| `vex.mergeDecision` | object | VEX merge decision |
|
||||
| `vex.mergeDecision.algorithm` | string | Merge algorithm (e.g., `trust-weighted-lattice-v1`) |
|
||||
| `vex.mergeDecision.inputs[]` | array | Source documents with trust weights |
|
||||
| `vex.mergeDecision.decisions[]` | array | Per-vulnerability decisions with provenance |
|
||||
|
||||
**Code locations:**
|
||||
- Evidence models: `src/Policy/__Libraries/StellaOps.Policy/Gates/Opa/OpaEvidenceModels.cs`
|
||||
- Context extension: `src/Policy/__Libraries/StellaOps.Policy/Gates/PolicyGateAbstractions.cs`
|
||||
- Input builder: `src/Policy/__Libraries/StellaOps.Policy/Gates/Opa/OpaGateAdapter.cs`
|
||||
|
||||
**Example Rego policy using evidence:**
|
||||
|
||||
```rego
|
||||
package stella.supply_chain
|
||||
|
||||
default allow = false
|
||||
|
||||
# Require SBOM presence
|
||||
allow {
|
||||
input.sbom.digest != ""
|
||||
input.sbom.componentCount > 0
|
||||
}
|
||||
|
||||
# Require verified attestation with SLSA provenance
|
||||
allow {
|
||||
some att in input.attestations
|
||||
att.predicateType == "https://slsa.dev/provenance/v1"
|
||||
att.signatureVerified == true
|
||||
}
|
||||
|
||||
# Require transparency log entry within 24 hours
|
||||
allow {
|
||||
some receipt in input.transparency.rekor
|
||||
receipt.verified == true
|
||||
time.now_ns() - (receipt.integratedTime * 1000000000) < 86400000000000
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 2026-01-23 (Sprint 041).*
|
||||
*Last updated: 2026-01-29 (Sprint 0129_001).*
|
||||
|
||||
Reference in New Issue
Block a user