tests fixes and some product advisories tunes ups

This commit is contained in:
master
2026-01-30 07:57:43 +02:00
parent 644887997c
commit 55744f6a39
345 changed files with 26290 additions and 2267 deletions

View File

@@ -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

View 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)

View File

@@ -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*

View File

@@ -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).*