docs consolidation and others
This commit is contained in:
283
docs/cicd/dsse-build-flow.md
Normal file
283
docs/cicd/dsse-build-flow.md
Normal file
@@ -0,0 +1,283 @@
|
||||
# Build-Time DSSE Attestation Walkthrough
|
||||
|
||||
> **Status:** Complete — implements the November 2025 advisory "Embed in-toto attestations (DSSE-wrapped) into .NET 10/C# builds." Updated 2025-11-27 with CLI verification commands (`DSSE-CLI-401-021`).
|
||||
> **Owners:** Attestor Guild · DevOps Guild · Docs Guild.
|
||||
|
||||
This guide shows how to emit signed, in-toto compliant DSSE envelopes for every container build step (scan → package → push) using Stella Ops Authority keys. The same primitives power our Signer/Attestor services, but this walkthrough targets developer pipelines (GitHub/GitLab, dotnet builds, container scanners).
|
||||
|
||||
---
|
||||
|
||||
## 1. Concepts refresher
|
||||
|
||||
| Term | Meaning |
|
||||
|------|---------|
|
||||
| **In-toto Statement** | JSON document describing what happened (predicate) to which artifact (subject). |
|
||||
| **DSSE** | Dead Simple Signing Envelope: wraps the statement, base64 payload, and signatures. |
|
||||
| **Authority Signer** | Stella Ops client that signs data via file-based keys, HSM/KMS, or keyless Fulcio certs. |
|
||||
| **PAE** | Pre-Authentication Encoding: canonical “DSSEv1 <len> <payloadType> <len> <payload>” byte layout that is signed. |
|
||||
|
||||
Requirements:
|
||||
|
||||
1. .NET 10 SDK (preview) for C# helper code.
|
||||
2. Authority key material (dev: file-based Ed25519; prod: Authority/KMS signer).
|
||||
3. Artifact digest (e.g., `pkg:docker/registry/app@sha256:...`) per step.
|
||||
|
||||
---
|
||||
|
||||
## 2. Helpers (drop-in library)
|
||||
|
||||
Create `src/StellaOps.Attestation` with:
|
||||
|
||||
```csharp
|
||||
public sealed record InTotoStatement(
|
||||
string _type,
|
||||
IReadOnlyList<Subject> subject,
|
||||
string predicateType,
|
||||
object predicate);
|
||||
|
||||
public sealed record Subject(string name, IReadOnlyDictionary<string,string> digest);
|
||||
|
||||
public sealed record DsseEnvelope(
|
||||
string payloadType,
|
||||
string payload,
|
||||
IReadOnlyList<Signature> signatures);
|
||||
|
||||
public sealed record Signature(string keyid, string sig);
|
||||
|
||||
public interface IAuthoritySigner
|
||||
{
|
||||
Task<string> GetKeyIdAsync(CancellationToken ct = default);
|
||||
Task<byte[]> SignAsync(ReadOnlyMemory<byte> pae, CancellationToken ct = default);
|
||||
}
|
||||
```
|
||||
|
||||
DSSE helper:
|
||||
|
||||
```csharp
|
||||
public static class DsseHelper
|
||||
{
|
||||
public static async Task<DsseEnvelope> WrapAsync(
|
||||
InTotoStatement statement,
|
||||
IAuthoritySigner signer,
|
||||
string payloadType = "application/vnd.in-toto+json",
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
var payloadBytes = JsonSerializer.SerializeToUtf8Bytes(statement,
|
||||
new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull });
|
||||
var pae = PreAuthEncode(payloadType, payloadBytes);
|
||||
|
||||
var signature = await signer.SignAsync(pae, ct).ConfigureAwait(false);
|
||||
var keyId = await signer.GetKeyIdAsync(ct).ConfigureAwait(false);
|
||||
|
||||
return new DsseEnvelope(
|
||||
payloadType,
|
||||
Convert.ToBase64String(payloadBytes),
|
||||
new[] { new Signature(keyId, Convert.ToBase64String(signature)) });
|
||||
}
|
||||
|
||||
private static byte[] PreAuthEncode(string payloadType, byte[] payload)
|
||||
{
|
||||
static byte[] Cat(params byte[][] parts)
|
||||
{
|
||||
var len = parts.Sum(p => p.Length);
|
||||
var buf = new byte[len];
|
||||
var offset = 0;
|
||||
foreach (var part in parts)
|
||||
{
|
||||
Buffer.BlockCopy(part, 0, buf, offset, part.Length);
|
||||
offset += part.Length;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
var header = Encoding.UTF8.GetBytes("DSSEv1");
|
||||
var pt = Encoding.UTF8.GetBytes(payloadType);
|
||||
var lenPt = Encoding.UTF8.GetBytes(pt.Length.ToString(CultureInfo.InvariantCulture));
|
||||
var lenPayload = Encoding.UTF8.GetBytes(payload.Length.ToString(CultureInfo.InvariantCulture));
|
||||
var space = Encoding.UTF8.GetBytes(" ");
|
||||
|
||||
return Cat(header, space, lenPt, space, pt, space, lenPayload, space, payload);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Authority signer examples:
|
||||
|
||||
/dev (file Ed25519):
|
||||
```csharp
|
||||
public sealed class FileEd25519Signer : IAuthoritySigner, IDisposable
|
||||
{
|
||||
private readonly Ed25519 _ed;
|
||||
private readonly string _keyId;
|
||||
|
||||
public FileEd25519Signer(byte[] privateKeySeed, string keyId)
|
||||
{
|
||||
_ed = new Ed25519(privateKeySeed);
|
||||
_keyId = keyId;
|
||||
}
|
||||
|
||||
public Task<string> GetKeyIdAsync(CancellationToken ct) => Task.FromResult(_keyId);
|
||||
|
||||
public Task<byte[]> SignAsync(ReadOnlyMemory<byte> pae, CancellationToken ct)
|
||||
=> Task.FromResult(_ed.Sign(pae.Span.ToArray()));
|
||||
|
||||
public void Dispose() => _ed.Dispose();
|
||||
}
|
||||
```
|
||||
|
||||
Prod (Authority KMS):
|
||||
|
||||
Reuse the existing `StellaOps.Signer.KmsSigner` adapter—wrap it behind `IAuthoritySigner`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Emitting attestations per step
|
||||
|
||||
Subject helper:
|
||||
```csharp
|
||||
static Subject ImageSubject(string imageDigest) => new(
|
||||
name: imageDigest,
|
||||
digest: new Dictionary<string,string>{{"sha256", imageDigest.Replace("sha256:", "", StringComparison.Ordinal)}});
|
||||
```
|
||||
|
||||
### 3.1 Scan
|
||||
|
||||
```csharp
|
||||
var scanStmt = new InTotoStatement(
|
||||
_type: "https://in-toto.io/Statement/v1",
|
||||
subject: new[]{ ImageSubject(imageDigest) },
|
||||
predicateType: "https://stella.ops/predicates/scanner-evidence/v1",
|
||||
predicate: new {
|
||||
scanner = "StellaOps.Scanner 0.9.0",
|
||||
findingsSha256 = scanResultsHash,
|
||||
startedAt = startedIso,
|
||||
finishedAt = finishedIso,
|
||||
rulePack = "lattice:default@2025-11-01"
|
||||
});
|
||||
|
||||
var scanEnvelope = await DsseHelper.WrapAsync(scanStmt, signer);
|
||||
await File.WriteAllTextAsync("artifacts/attest-scan.dsse.json", JsonSerializer.Serialize(scanEnvelope));
|
||||
```
|
||||
|
||||
### 3.2 Package (SLSA provenance)
|
||||
|
||||
```csharp
|
||||
var pkgStmt = new InTotoStatement(
|
||||
"https://in-toto.io/Statement/v1",
|
||||
new[]{ ImageSubject(imageDigest) },
|
||||
"https://slsa.dev/provenance/v1",
|
||||
new {
|
||||
builder = new { id = "stella://builder/dockerfile" },
|
||||
buildType = "dockerfile/v1",
|
||||
invocation = new { configSource = repoUrl, entryPoint = dockerfilePath },
|
||||
materials = new[] { new { uri = repoUrl, digest = new { git = gitSha } } }
|
||||
});
|
||||
|
||||
var pkgEnvelope = await DsseHelper.WrapAsync(pkgStmt, signer);
|
||||
await File.WriteAllTextAsync("artifacts/attest-package.dsse.json", JsonSerializer.Serialize(pkgEnvelope));
|
||||
```
|
||||
|
||||
### 3.3 Push
|
||||
|
||||
```csharp
|
||||
var pushStmt = new InTotoStatement(
|
||||
"https://in-toto.io/Statement/v1",
|
||||
new[]{ ImageSubject(imageDigest) },
|
||||
"https://stella.ops/predicates/push/v1",
|
||||
new { registry = registryUrl, repository = repoName, tags, pushedAt = DateTimeOffset.UtcNow });
|
||||
|
||||
var pushEnvelope = await DsseHelper.WrapAsync(pushStmt, signer);
|
||||
await File.WriteAllTextAsync("artifacts/attest-push.dsse.json", JsonSerializer.Serialize(pushEnvelope));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. CI integration
|
||||
|
||||
### 4.1 GitLab example
|
||||
|
||||
```yaml
|
||||
.attest-template: &attest
|
||||
image: mcr.microsoft.com/dotnet/sdk:10.0-preview
|
||||
before_script:
|
||||
- dotnet build src/StellaOps.Attestation/StellaOps.Attestation.csproj
|
||||
variables:
|
||||
AUTHORITY_KEY_FILE: "$CI_PROJECT_DIR/secrets/ed25519.key"
|
||||
IMAGE_DIGEST: "$CI_REGISTRY_IMAGE@${CI_COMMIT_SHA}"
|
||||
|
||||
attest:scan:
|
||||
stage: scan
|
||||
script:
|
||||
- dotnet run --project tools/StellaOps.Attestor.Tool -- step scan --subject "$IMAGE_DIGEST" --out artifacts/attest-scan.dsse.json
|
||||
artifacts:
|
||||
paths: [artifacts/attest-scan.dsse.json]
|
||||
|
||||
attest:package:
|
||||
stage: package
|
||||
script:
|
||||
- dotnet run --project tools/StellaOps.Attestor.Tool -- step package --subject "$IMAGE_DIGEST" --out artifacts/attest-package.dsse.json
|
||||
|
||||
attest:push:
|
||||
stage: push
|
||||
script:
|
||||
- dotnet run --project tools/StellaOps.Attestor.Tool -- step push --subject "$IMAGE_DIGEST" --registry "$CI_REGISTRY" --tags "$CI_COMMIT_REF_NAME"
|
||||
```
|
||||
|
||||
### 4.2 GitHub Actions snippet
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
attest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-dotnet@v4
|
||||
with: { dotnet-version: '10.0.x' }
|
||||
- name: Build attestor helpers
|
||||
run: dotnet build src/StellaOps.Attestation/StellaOps.Attestation.csproj
|
||||
- name: Emit scan attestation
|
||||
run: dotnet run --project tools/StellaOps.Attestor.Tool -- step scan --subject "${{ env.IMAGE_DIGEST }}" --out artifacts/attest-scan.dsse.json
|
||||
env:
|
||||
AUTHORITY_KEY_REF: ${{ secrets.AUTHORITY_KEY_REF }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Verification
|
||||
|
||||
* `stella attest verify --envelope artifacts/attest-scan.dsse.json` — offline verification using the CLI.
|
||||
* Additional verification options:
|
||||
* `--policy policy.json` — apply custom verification policy
|
||||
* `--root keys/root.pem` — specify trusted root certificate
|
||||
* `--transparency-checkpoint checkpoint.json` — verify against Rekor checkpoint
|
||||
* Manual validation:
|
||||
1. Base64 decode payload → ensure `_type` = `https://in-toto.io/Statement/v1`, `subject[].digest.sha256` matches artifact.
|
||||
2. Recompute PAE and verify signature with the Authority public key.
|
||||
3. Attach envelope to Rekor (optional) via existing Attestor API.
|
||||
|
||||
---
|
||||
|
||||
## 6. Storage conventions
|
||||
|
||||
Store DSSE files next to build outputs:
|
||||
|
||||
```
|
||||
artifacts/
|
||||
attest-scan.dsse.json
|
||||
attest-package.dsse.json
|
||||
attest-push.dsse.json
|
||||
```
|
||||
|
||||
Include the SHA-256 digest of each envelope in promotion manifests (`docs/release/promotion-attestations.md`) so downstream verifiers can trace chain of custody.
|
||||
|
||||
---
|
||||
|
||||
## 7. References
|
||||
|
||||
- [In-toto Statement v1](https://in-toto.io/spec/v1)
|
||||
- [DSSE specification](https://github.com/secure-systems-lab/dsse)
|
||||
- `docs/modules/signer/architecture.md`
|
||||
- `docs/modules/attestor/architecture.md`
|
||||
- `docs/release/promotion-attestations.md`
|
||||
|
||||
This file was updated as part of `DSSE-LIB-401-020` and `DSSE-CLI-401-021` (completed 2025-11-27). See `docs/modules/cli/guides/attest.md` for CI/CD workflow snippets.
|
||||
250
docs/cicd/sarif-integration.md
Normal file
250
docs/cicd/sarif-integration.md
Normal file
@@ -0,0 +1,250 @@
|
||||
# SARIF Integration Guide
|
||||
|
||||
**Sprint:** SPRINT_3500_0004_0001
|
||||
**Task:** SDIFF-BIN-032 - Documentation for SARIF integration
|
||||
|
||||
## Overview
|
||||
|
||||
StellaOps Scanner supports SARIF (Static Analysis Results Interchange Format) 2.1.0 output for seamless integration with CI/CD platforms including GitHub, GitLab, and Azure DevOps.
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
| Platform | Integration Method | Native Support |
|
||||
|----------|-------------------|----------------|
|
||||
| GitHub Actions | Code Scanning API | ✅ Yes |
|
||||
| GitLab CI | SAST Reports | ✅ Yes |
|
||||
| Azure DevOps | SARIF Viewer Extension | ✅ Yes |
|
||||
| Jenkins | SARIF Plugin | ✅ Yes |
|
||||
| Other | File upload | ✅ Yes |
|
||||
|
||||
## Quick Start
|
||||
|
||||
### API Endpoint
|
||||
|
||||
```bash
|
||||
# Get SARIF output for a scan
|
||||
curl -H "Authorization: Bearer $TOKEN" \
|
||||
"https://scanner.example.com/api/v1/smart-diff/scans/{scanId}/sarif"
|
||||
|
||||
# With pretty printing
|
||||
curl -H "Authorization: Bearer $TOKEN" \
|
||||
"https://scanner.example.com/api/v1/smart-diff/scans/{scanId}/sarif?pretty=true"
|
||||
```
|
||||
|
||||
### CLI Usage
|
||||
|
||||
```bash
|
||||
# Scan with SARIF output
|
||||
stellaops scan image:tag --output-format sarif > results.sarif
|
||||
|
||||
# Smart-diff with SARIF output
|
||||
stellaops smart-diff --base image:v1 --target image:v2 --output-format sarif
|
||||
```
|
||||
|
||||
## SARIF Rule Definitions
|
||||
|
||||
StellaOps emits the following rule categories in SARIF output:
|
||||
|
||||
| Rule ID | Name | Description |
|
||||
|---------|------|-------------|
|
||||
| SDIFF001 | ReachabilityChange | Vulnerability reachability status changed |
|
||||
| SDIFF002 | VexStatusFlip | VEX status changed (affected/not_affected/fixed) |
|
||||
| SDIFF003 | HardeningRegression | Binary hardening flag regressed |
|
||||
| SDIFF004 | IntelligenceSignal | EPSS/KEV status changed |
|
||||
|
||||
## GitHub Actions Integration
|
||||
|
||||
```yaml
|
||||
name: Security Scan
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run StellaOps Scanner
|
||||
run: |
|
||||
stellaops scan ${{ github.repository }} \
|
||||
--output-format sarif \
|
||||
--output results.sarif
|
||||
|
||||
- name: Upload SARIF
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
category: stellaops
|
||||
```
|
||||
|
||||
## GitLab CI Integration
|
||||
|
||||
```yaml
|
||||
security_scan:
|
||||
stage: test
|
||||
image: stellaops/cli:latest
|
||||
script:
|
||||
- stellaops scan $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --output-format sarif > gl-sast-report.sarif
|
||||
artifacts:
|
||||
reports:
|
||||
sast: gl-sast-report.sarif
|
||||
```
|
||||
|
||||
## Azure DevOps Integration
|
||||
|
||||
```yaml
|
||||
trigger:
|
||||
- main
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
- task: Bash@3
|
||||
displayName: 'Run StellaOps Scanner'
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
script: |
|
||||
stellaops scan $(containerImage) --output-format sarif > $(Build.ArtifactStagingDirectory)/results.sarif
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs:
|
||||
pathToPublish: '$(Build.ArtifactStagingDirectory)/results.sarif'
|
||||
artifactName: 'security-results'
|
||||
```
|
||||
|
||||
## SARIF Schema Details
|
||||
|
||||
### Result Levels
|
||||
|
||||
| SARIF Level | StellaOps Severity | Description |
|
||||
|-------------|-------------------|-------------|
|
||||
| `error` | Critical, High | Requires immediate attention |
|
||||
| `warning` | Medium | Should be reviewed |
|
||||
| `note` | Low, Info | For awareness |
|
||||
|
||||
### Result Kinds
|
||||
|
||||
| Kind | Meaning |
|
||||
|------|---------|
|
||||
| `fail` | Finding indicates a problem |
|
||||
| `pass` | Check passed (for VEX suppressed) |
|
||||
| `notApplicable` | Finding does not apply |
|
||||
| `informational` | Advisory information |
|
||||
|
||||
### Location Information
|
||||
|
||||
SARIF results include:
|
||||
- **Physical location**: File path and line numbers (when available)
|
||||
- **Logical location**: Component PURL, function name
|
||||
- **URI**: OCI artifact digest or SBOM reference
|
||||
|
||||
## Example SARIF Output
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json",
|
||||
"version": "2.1.0",
|
||||
"runs": [
|
||||
{
|
||||
"tool": {
|
||||
"driver": {
|
||||
"name": "StellaOps Scanner",
|
||||
"version": "1.0.0",
|
||||
"informationUri": "https://stellaops.io",
|
||||
"rules": [
|
||||
{
|
||||
"id": "SDIFF001",
|
||||
"name": "ReachabilityChange",
|
||||
"shortDescription": {
|
||||
"text": "Vulnerability reachability changed"
|
||||
},
|
||||
"defaultConfiguration": {
|
||||
"level": "warning"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"ruleId": "SDIFF001",
|
||||
"level": "warning",
|
||||
"message": {
|
||||
"text": "CVE-2024-1234 became reachable in pkg:npm/lodash@4.17.20"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "package-lock.json"
|
||||
}
|
||||
},
|
||||
"logicalLocations": [
|
||||
{
|
||||
"name": "pkg:npm/lodash@4.17.20",
|
||||
"kind": "package"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"vulnerability": "CVE-2024-1234",
|
||||
"tier": "executed",
|
||||
"direction": "increased"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Filtering Results
|
||||
|
||||
### By Tier
|
||||
|
||||
```bash
|
||||
# Only tainted_sink findings
|
||||
stellaops scan image:tag --output-format sarif --tier tainted_sink
|
||||
|
||||
# Executed and tainted_sink
|
||||
stellaops scan image:tag --output-format sarif --tier executed,tainted_sink
|
||||
```
|
||||
|
||||
### By Priority
|
||||
|
||||
```bash
|
||||
# Only high priority changes
|
||||
stellaops smart-diff --output-format sarif --min-priority 0.7
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### SARIF Validation Errors
|
||||
|
||||
If your CI platform rejects the SARIF output:
|
||||
|
||||
1. Validate against schema:
|
||||
```bash
|
||||
stellaops validate-sarif results.sarif
|
||||
```
|
||||
|
||||
2. Check for required fields:
|
||||
- `$schema` must be present
|
||||
- `version` must be `"2.1.0"`
|
||||
- Each result must have `ruleId` and `message`
|
||||
|
||||
### Empty Results
|
||||
|
||||
If SARIF contains no results:
|
||||
- Check scan completed successfully
|
||||
- Verify image has vulnerability data
|
||||
- Ensure feed snapshots are current
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Smart-Diff Detection Rules](../modules/scanner/smart-diff-rules.md)
|
||||
- [Scanner API Reference](../api/scanner-api.md)
|
||||
- [CLI Reference](../API_CLI_REFERENCE.md)
|
||||
- [Scoring Configuration](./scoring-configuration.md)
|
||||
292
docs/cicd/scoring-configuration.md
Normal file
292
docs/cicd/scoring-configuration.md
Normal file
@@ -0,0 +1,292 @@
|
||||
# Smart-Diff Scoring Configuration Guide
|
||||
|
||||
**Sprint:** SPRINT_3500_0004_0001
|
||||
**Task:** SDIFF-BIN-031 - Documentation for scoring configuration
|
||||
|
||||
## Overview
|
||||
|
||||
Smart-Diff uses configurable scoring weights to prioritize material risk changes. This guide explains how to customize scoring for your organization's risk appetite.
|
||||
|
||||
## Configuration Location
|
||||
|
||||
Smart-Diff scoring can be configured via:
|
||||
1. **PolicyScoringConfig** - Integrated with policy engine
|
||||
2. **SmartDiffScoringConfig** - Standalone configuration
|
||||
3. **Environment variables** - Runtime overrides
|
||||
4. **API** - Dynamic configuration
|
||||
|
||||
## Default Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "default",
|
||||
"version": "1.0",
|
||||
"reachabilityFlipUpWeight": 1.0,
|
||||
"reachabilityFlipDownWeight": 0.8,
|
||||
"vexFlipToAffectedWeight": 0.9,
|
||||
"vexFlipToNotAffectedWeight": 0.7,
|
||||
"vexFlipToFixedWeight": 0.6,
|
||||
"vexFlipToUnderInvestigationWeight": 0.3,
|
||||
"rangeEntryWeight": 0.8,
|
||||
"rangeExitWeight": 0.6,
|
||||
"kevAddedWeight": 1.0,
|
||||
"epssThreshold": 0.1,
|
||||
"epssThresholdCrossWeight": 0.5,
|
||||
"hardeningRegressionWeight": 0.7,
|
||||
"hardeningImprovementWeight": 0.3,
|
||||
"hardeningRegressionThreshold": 0.1
|
||||
}
|
||||
```
|
||||
|
||||
## Weight Categories
|
||||
|
||||
### Reachability Weights (R1)
|
||||
|
||||
Controls scoring for reachability status changes.
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `reachabilityFlipUpWeight` | 1.0 | Unreachable → Reachable (risk increase) |
|
||||
| `reachabilityFlipDownWeight` | 0.8 | Reachable → Unreachable (risk decrease) |
|
||||
| `useLatticeConfidence` | true | Factor in reachability confidence |
|
||||
|
||||
**Example scenarios:**
|
||||
- Vulnerability becomes reachable after code refactoring → weight = 1.0
|
||||
- Dependency removed, vulnerability no longer reachable → weight = 0.8
|
||||
|
||||
### VEX Status Weights (R2)
|
||||
|
||||
Controls scoring for VEX statement changes.
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `vexFlipToAffectedWeight` | 0.9 | Status changed to "affected" |
|
||||
| `vexFlipToNotAffectedWeight` | 0.7 | Status changed to "not_affected" |
|
||||
| `vexFlipToFixedWeight` | 0.6 | Status changed to "fixed" |
|
||||
| `vexFlipToUnderInvestigationWeight` | 0.3 | Status changed to "under_investigation" |
|
||||
|
||||
**Rationale:**
|
||||
- "affected" is highest weight as it confirms exploitability
|
||||
- "fixed" is lower as it indicates remediation
|
||||
- "under_investigation" is lowest as status is uncertain
|
||||
|
||||
### Version Range Weights (R3)
|
||||
|
||||
Controls scoring for affected version range changes.
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `rangeEntryWeight` | 0.8 | Version entered affected range |
|
||||
| `rangeExitWeight` | 0.6 | Version exited affected range |
|
||||
|
||||
### Intelligence Signal Weights (R4)
|
||||
|
||||
Controls scoring for external intelligence changes.
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `kevAddedWeight` | 1.0 | Vulnerability added to CISA KEV |
|
||||
| `epssThreshold` | 0.1 | EPSS score threshold for significance |
|
||||
| `epssThresholdCrossWeight` | 0.5 | Weight when EPSS crosses threshold |
|
||||
|
||||
### Binary Hardening Weights (R5)
|
||||
|
||||
Controls scoring for binary hardening flag changes.
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `hardeningRegressionWeight` | 0.7 | Security flag disabled (e.g., NX removed) |
|
||||
| `hardeningImprovementWeight` | 0.3 | Security flag enabled (e.g., PIE added) |
|
||||
| `hardeningRegressionThreshold` | 0.1 | Minimum score drop to flag regression |
|
||||
|
||||
## Presets
|
||||
|
||||
### Default Preset
|
||||
|
||||
Balanced configuration suitable for most organizations.
|
||||
|
||||
```csharp
|
||||
SmartDiffScoringConfig.Default
|
||||
```
|
||||
|
||||
### Strict Preset
|
||||
|
||||
Higher weights for regressions, recommended for security-critical applications.
|
||||
|
||||
```csharp
|
||||
SmartDiffScoringConfig.Strict
|
||||
```
|
||||
|
||||
Configuration:
|
||||
```json
|
||||
{
|
||||
"name": "strict",
|
||||
"reachabilityFlipUpWeight": 1.2,
|
||||
"vexFlipToAffectedWeight": 1.1,
|
||||
"kevAddedWeight": 1.5,
|
||||
"hardeningRegressionWeight": 1.0,
|
||||
"hardeningRegressionThreshold": 0.05
|
||||
}
|
||||
```
|
||||
|
||||
### Lenient Preset
|
||||
|
||||
Lower weights for alerts, suitable for development/staging environments.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "lenient",
|
||||
"reachabilityFlipUpWeight": 0.7,
|
||||
"vexFlipToAffectedWeight": 0.6,
|
||||
"kevAddedWeight": 0.8,
|
||||
"hardeningRegressionWeight": 0.4,
|
||||
"epssThreshold": 0.2
|
||||
}
|
||||
```
|
||||
|
||||
## Policy Integration
|
||||
|
||||
Smart-Diff scoring integrates with `PolicyScoringConfig`:
|
||||
|
||||
```csharp
|
||||
var config = new PolicyScoringConfig(
|
||||
Version: "1.0",
|
||||
SeverityWeights: severityWeights,
|
||||
QuietPenalty: 0.1,
|
||||
WarnPenalty: 0.5,
|
||||
IgnorePenalty: 0.0,
|
||||
TrustOverrides: trustOverrides,
|
||||
ReachabilityBuckets: reachabilityBuckets,
|
||||
UnknownConfidence: unknownConfig,
|
||||
SmartDiff: new SmartDiffPolicyScoringConfig(
|
||||
ReachabilityFlipUpWeight: 1.0,
|
||||
VexFlipToAffectedWeight: 0.9,
|
||||
KevAddedWeight: 1.2
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
## Environment Variable Overrides
|
||||
|
||||
```bash
|
||||
# Override reachability weights
|
||||
export STELLAOPS_SMARTDIFF_REACHABILITY_FLIP_UP_WEIGHT=1.2
|
||||
export STELLAOPS_SMARTDIFF_REACHABILITY_FLIP_DOWN_WEIGHT=0.7
|
||||
|
||||
# Override KEV weight
|
||||
export STELLAOPS_SMARTDIFF_KEV_ADDED_WEIGHT=1.5
|
||||
|
||||
# Override hardening threshold
|
||||
export STELLAOPS_SMARTDIFF_HARDENING_REGRESSION_THRESHOLD=0.05
|
||||
```
|
||||
|
||||
## API Configuration
|
||||
|
||||
### Get Current Configuration
|
||||
|
||||
```bash
|
||||
GET /api/v1/config/smart-diff/scoring
|
||||
|
||||
Response:
|
||||
{
|
||||
"name": "default",
|
||||
"version": "1.0",
|
||||
"weights": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
### Update Configuration
|
||||
|
||||
```bash
|
||||
PUT /api/v1/config/smart-diff/scoring
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"reachabilityFlipUpWeight": 1.2,
|
||||
"kevAddedWeight": 1.5
|
||||
}
|
||||
```
|
||||
|
||||
## Score Calculation Formula
|
||||
|
||||
The final priority score is calculated as:
|
||||
|
||||
```
|
||||
priority_score = base_severity × Σ(change_weight × rule_match)
|
||||
```
|
||||
|
||||
Where:
|
||||
- `base_severity` is the CVSS/severity normalized to 0-1
|
||||
- `change_weight` is the configured weight for the change type
|
||||
- `rule_match` is 1 if the rule triggered, 0 otherwise
|
||||
|
||||
### Example Calculation
|
||||
|
||||
Given:
|
||||
- CVE-2024-1234 with CVSS 7.5 (base_severity = 0.75)
|
||||
- Became reachable (reachabilityFlipUpWeight = 1.0)
|
||||
- Added to KEV (kevAddedWeight = 1.0)
|
||||
|
||||
```
|
||||
priority_score = 0.75 × (1.0 + 1.0) = 1.5 → capped at 1.0
|
||||
```
|
||||
|
||||
## Tuning Recommendations
|
||||
|
||||
### For CI/CD Pipelines
|
||||
|
||||
```json
|
||||
{
|
||||
"kevAddedWeight": 1.5,
|
||||
"hardeningRegressionWeight": 1.2,
|
||||
"epssThreshold": 0.05
|
||||
}
|
||||
```
|
||||
|
||||
Focus on blocking builds for known exploited vulnerabilities and hardening regressions.
|
||||
|
||||
### For Alert Fatigue Reduction
|
||||
|
||||
```json
|
||||
{
|
||||
"reachabilityFlipDownWeight": 0.3,
|
||||
"vexFlipToNotAffectedWeight": 0.2,
|
||||
"rangeExitWeight": 0.2
|
||||
}
|
||||
```
|
||||
|
||||
Lower weights for positive changes to reduce noise.
|
||||
|
||||
### For Compliance Focus
|
||||
|
||||
```json
|
||||
{
|
||||
"kevAddedWeight": 2.0,
|
||||
"vexFlipToAffectedWeight": 1.2,
|
||||
"hardeningRegressionThreshold": 0.02
|
||||
}
|
||||
```
|
||||
|
||||
Higher weights for regulatory-relevant changes.
|
||||
|
||||
## Monitoring and Metrics
|
||||
|
||||
Track scoring effectiveness with:
|
||||
|
||||
```sql
|
||||
-- Average priority score by rule type
|
||||
SELECT
|
||||
change_type,
|
||||
AVG(priority_score) as avg_score,
|
||||
COUNT(*) as count
|
||||
FROM smart_diff_changes
|
||||
WHERE created_at > now() - interval '30 days'
|
||||
GROUP BY change_type
|
||||
ORDER BY avg_score DESC;
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Smart-Diff Detection Rules](../modules/scanner/smart-diff-rules.md)
|
||||
- [Policy Engine Configuration](../modules/policy/architecture.md)
|
||||
- [SARIF Integration](./sarif-integration.md)
|
||||
@@ -154,7 +154,7 @@ Create `.gitleaksignore` or `.secretsignore` for false positives:
|
||||
```
|
||||
# Ignore test fixtures
|
||||
src/__Tests/**/*
|
||||
docs/examples/**/*
|
||||
docs/samples/**/*
|
||||
|
||||
# Ignore specific files
|
||||
path/to/test-credentials.json
|
||||
|
||||
Reference in New Issue
Block a user