Enhance risk API documentation and error handling
- Updated API documentation for risk endpoints to include optional caching headers and error catalog references. - Added a new error catalog JSON file to standardize error responses. - Improved explainability documentation with sample outputs for console and CLI. - Added SHA256 checksums for new sample files related to explainability. - Refined AocGuard tests to utilize a helper method for generating test JSON, improving readability and maintainability. - Updated runbook references to ensure consistency in sprint documentation. - Introduced stub implementations for MongoDB storage interfaces and options, laying groundwork for future development. - Disabled analytics in Angular CLI configuration for privacy considerations.
This commit is contained in:
@@ -36,8 +36,8 @@
|
|||||||
| 11 | DOCS-RISK-66-002 | DONE (2025-12-05) | Profile schema + sample fixture added. | Docs Guild · Policy Guild | Author `/docs/risk/profiles.md` (authoring, versioning, scope). |
|
| 11 | DOCS-RISK-66-002 | DONE (2025-12-05) | Profile schema + sample fixture added. | Docs Guild · Policy Guild | Author `/docs/risk/profiles.md` (authoring, versioning, scope). |
|
||||||
| 12 | DOCS-RISK-66-003 | DONE (2025-12-05) | Factor catalog + normalized fixture added. | Docs Guild · Risk Engine Guild | Publish `/docs/risk/factors.md` (signals, transforms, reducers, TTLs). |
|
| 12 | DOCS-RISK-66-003 | DONE (2025-12-05) | Factor catalog + normalized fixture added. | Docs Guild · Risk Engine Guild | Publish `/docs/risk/factors.md` (signals, transforms, reducers, TTLs). |
|
||||||
| 13 | DOCS-RISK-66-004 | DONE (2025-12-05) | Formula/gating doc + explain fixture added. | Docs Guild · Risk Engine Guild | Create `/docs/risk/formulas.md` (math, normalization, gating, severity). |
|
| 13 | DOCS-RISK-66-004 | DONE (2025-12-05) | Formula/gating doc + explain fixture added. | Docs Guild · Risk Engine Guild | Create `/docs/risk/formulas.md` (math, normalization, gating, severity). |
|
||||||
| 14 | DOCS-RISK-67-001 | TODO | Depends on 66-004; need engine metrics/screenshots. | Docs Guild · Risk Engine Guild | Publish `/docs/risk/explainability.md` (artifact schema, UI screenshots). |
|
| 14 | DOCS-RISK-67-001 | DONE (2025-12-05) | Explainability doc published with CLI/console fixtures and hashes. | Docs Guild · Risk Engine Guild | Publish `/docs/risk/explainability.md` (artifact schema, UI screenshots). |
|
||||||
| 15 | DOCS-RISK-67-002 | TODO | Depends on 67-001; needs API publishing workflow. | Docs Guild · API Guild | Produce `/docs/risk/api.md` with endpoint reference/examples. |
|
| 15 | DOCS-RISK-67-002 | DONE (2025-12-05) | API doc published with samples, error catalog, ETag guidance. | Docs Guild · API Guild | Produce `/docs/risk/api.md` with endpoint reference/examples. |
|
||||||
|
|
||||||
## Wave Coordination
|
## Wave Coordination
|
||||||
- Single wave for Md.VIII; no per-wave snapshots required. Revisit if tasks split across guild weeks.
|
- Single wave for Md.VIII; no per-wave snapshots required. Revisit if tasks split across guild weeks.
|
||||||
@@ -74,6 +74,7 @@
|
|||||||
| Add per-folder READMEs in `docs/risk/samples/*` for intake rules | Docs Guild | 2025-12-05 | DONE (2025-12-05) |
|
| Add per-folder READMEs in `docs/risk/samples/*` for intake rules | Docs Guild | 2025-12-05 | DONE (2025-12-05) |
|
||||||
| Add intake log template for risk samples | Docs Guild | 2025-12-05 | DONE (2025-12-05) |
|
| Add intake log template for risk samples | Docs Guild | 2025-12-05 | DONE (2025-12-05) |
|
||||||
| Daily signal check (registry schema + PLLG0104 payloads) and log outcome | Docs Guild | 2025-12-13 | DOING (2025-12-05) |
|
| Daily signal check (registry schema + PLLG0104 payloads) and log outcome | Docs Guild | 2025-12-13 | DOING (2025-12-05) |
|
||||||
|
| Capture console/CLI telemetry frames for explainability visuals | Console Guild | 2025-12-15 | OPEN |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
### Decisions
|
### Decisions
|
||||||
@@ -84,7 +85,7 @@
|
|||||||
| Risk | Impact | Mitigation |
|
| Risk | Impact | Mitigation |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| DOCS-POLICY-27 chain blocked by missing promotion/registry inputs | Entire policy documentation ladder stalls; pushes Md.IX hand-off | Track in BLOCKED_DEPENDENCY_TREE; weekly check-ins with Policy/Registry Guilds; stage scaffolds while waiting. |
|
| DOCS-POLICY-27 chain blocked by missing promotion/registry inputs | Entire policy documentation ladder stalls; pushes Md.IX hand-off | Track in BLOCKED_DEPENDENCY_TREE; weekly check-ins with Policy/Registry Guilds; stage scaffolds while waiting. |
|
||||||
| Risk documentation chain lacks telemetry captures | Console/CLI visuals still missing for 67-001/002 | Collect UI traces; until then, rely on frozen JSON fixtures and keep docs text-only. |
|
| Risk documentation chain lacks real telemetry captures | Console/CLI visuals still pending; current fixtures are synthetic | Collect UI traces; until then, rely on frozen JSON fixtures and keep docs text-only. |
|
||||||
|
|
||||||
## Execution Log
|
## Execution Log
|
||||||
| Date (UTC) | Update | Owner |
|
| Date (UTC) | Update | Owner |
|
||||||
@@ -108,6 +109,7 @@
|
|||||||
| 2025-12-05 | Scheduled next signal check for 2025-12-06 15:00 UTC to minimize lag when inputs arrive. | Docs Guild |
|
| 2025-12-05 | Scheduled next signal check for 2025-12-06 15:00 UTC to minimize lag when inputs arrive. | Docs Guild |
|
||||||
| 2025-12-05 | Enriched risk overview/profiles/factors/formulas outlines with legacy content, determinism rules, and expected schemas; flipped related action tracker items to DONE. | Docs Guild |
|
| 2025-12-05 | Enriched risk overview/profiles/factors/formulas outlines with legacy content, determinism rules, and expected schemas; flipped related action tracker items to DONE. | Docs Guild |
|
||||||
| 2025-12-05 | Consumed `CONTRACT-RISK-SCORING-002`, populated risk overview/profiles/factors/formulas with contract fields/gates, added deterministic fixtures and SHA manifests, and marked DOCS-RISK-66-001..004 DONE. | Docs Guild |
|
| 2025-12-05 | Consumed `CONTRACT-RISK-SCORING-002`, populated risk overview/profiles/factors/formulas with contract fields/gates, added deterministic fixtures and SHA manifests, and marked DOCS-RISK-66-001..004 DONE. | Docs Guild |
|
||||||
|
| 2025-12-05 | Published explainability/API docs with CLI + console fixtures and error catalog; marked DOCS-RISK-67-001/002 DONE; added telemetry capture follow-up in Action Tracker. | Docs Guild |
|
||||||
| 2025-12-06 | Signal check 15:00 UTC: still no registry schema alignment or PLLG0104 payloads; keep 27-008 and 66-001/002 pending; next check 2025-12-07 15:00 UTC. | Docs Guild |
|
| 2025-12-06 | Signal check 15:00 UTC: still no registry schema alignment or PLLG0104 payloads; keep 27-008 and 66-001/002 pending; next check 2025-12-07 15:00 UTC. | Docs Guild |
|
||||||
| 2025-12-07 | Signal check 15:00 UTC: no updates; keep 27-008 and 66-001/002 pending; next check 2025-12-08 15:00 UTC. | Docs Guild |
|
| 2025-12-07 | Signal check 15:00 UTC: no updates; keep 27-008 and 66-001/002 pending; next check 2025-12-08 15:00 UTC. | Docs Guild |
|
||||||
| 2025-12-08 | Signal check 15:00 UTC: no updates; keep 27-008 and 66-001/002 pending; next check 2025-12-09 15:00 UTC. | Docs Guild |
|
| 2025-12-08 | Signal check 15:00 UTC: no updates; keep 27-008 and 66-001/002 pending; next check 2025-12-09 15:00 UTC. | Docs Guild |
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -13,8 +13,8 @@
|
|||||||
## Endpoints (v1)
|
## Endpoints (v1)
|
||||||
- `POST /api/v1/risk/jobs` — submit scoring job (body: job request); returns `202` with `job_id` and `status` (`queued`). Sample: `risk-api-samples.json#submit_job_request`.
|
- `POST /api/v1/risk/jobs` — submit scoring job (body: job request); returns `202` with `job_id` and `status` (`queued`). Sample: `risk-api-samples.json#submit_job_request`.
|
||||||
- `GET /api/v1/risk/jobs/{job_id}` — job status + results array (sample: `get_job_status`).
|
- `GET /api/v1/risk/jobs/{job_id}` — job status + results array (sample: `get_job_status`).
|
||||||
- `GET /api/v1/risk/explain/{job_id}` — explainability payload (sample references `../explain/explain-trace.json`).
|
- `GET /api/v1/risk/explain/{job_id}` — explainability payload (sample references `../explain/explain-trace.json`). Optional `If-None-Match` for caching.
|
||||||
- `GET /api/v1/risk/profiles` — list profiles (tenant-filtered); include `profile_hash`, `version`, `etag`.
|
- `GET /api/v1/risk/profiles` — list profiles (tenant-filtered); includes `profile_hash`, `version`, `etag` (see error-catalog headers).
|
||||||
- `POST /api/v1/risk/profiles` — create/update profile with DSSE/attestation metadata; returns `201` with `etag`.
|
- `POST /api/v1/risk/profiles` — create/update profile with DSSE/attestation metadata; returns `201` with `etag`.
|
||||||
- `POST /api/v1/risk/simulations` — dry-run scoring with fixtures; returns explain + contributions without persisting results.
|
- `POST /api/v1/risk/simulations` — dry-run scoring with fixtures; returns explain + contributions without persisting results.
|
||||||
- `GET /api/v1/risk/export/{job_id}` — export bundle (JSON + CSV + manifest) for auditors.
|
- `GET /api/v1/risk/export/{job_id}` — export bundle (JSON + CSV + manifest) for auditors.
|
||||||
@@ -25,8 +25,8 @@
|
|||||||
- Imposed rule reminder must be present in responses where tenant-bound resources are returned.
|
- Imposed rule reminder must be present in responses where tenant-bound resources are returned.
|
||||||
|
|
||||||
## Error Model
|
## Error Model
|
||||||
- Envelope: `code`, `message`, `correlation_id`, `severity`, `remediation`.
|
- Envelope: `code`, `message`, `correlation_id`, `severity`, `remediation`; sample catalog in `docs/risk/samples/api/error-catalog.json`.
|
||||||
- Rate-limit headers: `Retry-After`, `X-RateLimit-Remaining` (document values in SDKs).
|
- Rate-limit headers: `Retry-After`, `X-RateLimit-Remaining`; caching headers include `ETag` for explain/results/profile GETs.
|
||||||
|
|
||||||
## Determinism & Offline Posture
|
## Determinism & Offline Posture
|
||||||
- Samples: `docs/risk/samples/api/risk-api-samples.json` (hashes in `SHA256SUMS`); explain sample reused via relative reference.
|
- Samples: `docs/risk/samples/api/risk-api-samples.json` (hashes in `SHA256SUMS`); explain sample reused via relative reference.
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
- UI/CLI expectations: deterministic ordering (factor type → source → timestamp), highlight top contributors, show attestation status for each factor.
|
- UI/CLI expectations: deterministic ordering (factor type → source → timestamp), highlight top contributors, show attestation status for each factor.
|
||||||
|
|
||||||
## UI/CLI Views
|
## UI/CLI Views
|
||||||
- Console: table of factors sorted by contribution, severity badge, gate badges (e.g., KEV+reachability), link to provenance hashes.
|
- Console: frame sample in `docs/risk/samples/explain/console-frame.json` shows top contributors, gate badges, and provenance hashes.
|
||||||
- CLI `stella risk explain job-001`: render table using fixture `explain-trace.json`; include `--json` option that emits the same payload.
|
- CLI `stella risk explain job-001`: deterministic text fixture in `docs/risk/samples/explain/cli-explain.txt`; `--json` mirrors `explain-trace.json`.
|
||||||
- Export Center: embed explain payload + SHA256 manifest; CSV export keeps deterministic ordering.
|
- Export Center: embed explain payload + SHA256 manifest; CSV export keeps deterministic ordering.
|
||||||
|
|
||||||
## Determinism & Offline Posture
|
## Determinism & Offline Posture
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
9408221415b389f6dad1c235de160e88721555b406ab0e2bdbfa3119c6696a4d README.md
|
9408221415b389f6dad1c235de160e88721555b406ab0e2bdbfa3119c6696a4d README.md
|
||||||
|
00f8dc4e466eb95c06545e6336d7b0866b53ac430335b7fd1b7889da13529b93 error-catalog.json
|
||||||
96926cd81dfb6ff02d62d1fde5d7b2b7b5b3950e50eb651e51b8ae3042ac9506 risk-api-samples.json
|
96926cd81dfb6ff02d62d1fde5d7b2b7b5b3950e50eb651e51b8ae3042ac9506 risk-api-samples.json
|
||||||
|
|||||||
13
docs/risk/samples/api/error-catalog.json
Normal file
13
docs/risk/samples/api/error-catalog.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"errors": [
|
||||||
|
{"code": "risk.job.not_found", "message": "Risk job not found", "http_status": 404, "remediation": "Verify job_id"},
|
||||||
|
{"code": "risk.profile.invalid_signature", "message": "Profile DSSE signature failed", "http_status": 400, "remediation": "Re-sign profile and retry"},
|
||||||
|
{"code": "risk.job.rate_limited", "message": "Rate limit exceeded", "http_status": 429, "remediation": "Retry after backoff", "retry_after": 5},
|
||||||
|
{"code": "risk.tenant.scope_denied", "message": "Tenant scope not authorized", "http_status": 403, "remediation": "Provide required scope header"}
|
||||||
|
],
|
||||||
|
"headers": {
|
||||||
|
"etag": "\"risk-api-sample-etag\"",
|
||||||
|
"x-ratelimit-remaining": 99,
|
||||||
|
"retry-after": 5
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,2 +1,4 @@
|
|||||||
30a64dcc9fb41d06774a9c125456c212a29915a083cd1d2170f16f343bd0764f README.md
|
30a64dcc9fb41d06774a9c125456c212a29915a083cd1d2170f16f343bd0764f README.md
|
||||||
|
4bba11375e9f06942e988dd6cd30e7005fe3b040009b3fffca4e6d36a1875ab3 cli-explain.txt
|
||||||
|
22c87e16d5a5cd89f60660eeb07b319989c38f2aa0243da88a312bee1841dda6 console-frame.json
|
||||||
1d2e56eebf0a266f80519f073e1db532c4a4f2d7fa604ea5c05d4e208719cc7c explain-trace.json
|
1d2e56eebf0a266f80519f073e1db532c4a4f2d7fa604ea5c05d4e208719cc7c explain-trace.json
|
||||||
|
|||||||
12
docs/risk/samples/explain/cli-explain.txt
Normal file
12
docs/risk/samples/explain/cli-explain.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
stella risk explain job-001 --tenant tenant-default --json false
|
||||||
|
Finding: finding-123
|
||||||
|
Profile: default-profile v1.0.0 (hash sha256:profilehash)
|
||||||
|
Score: 0.85 (high)
|
||||||
|
Gates: kev_and_reachability
|
||||||
|
Contributions:
|
||||||
|
- cvss 0.40 (raw 7.5, source nvd, provenance sha256:cvsshash)
|
||||||
|
- kev 0.30 (raw true, source cisa, provenance sha256:kevhash)
|
||||||
|
- reachability 0.30 (raw 0.9, source scanner, provenance sha256:reachhash)
|
||||||
|
Overrides: kev-boost (Known Exploited Vulnerability)
|
||||||
|
Provenance: job sha256:jobhash | fixtures [sha256:cvsshash, sha256:kevhash, sha256:reachhash]
|
||||||
|
Timestamp: 2025-12-05T00:00:02Z
|
||||||
19
docs/risk/samples/explain/console-frame.json
Normal file
19
docs/risk/samples/explain/console-frame.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"frame_id": "console-explain-001",
|
||||||
|
"captured_at": "2025-12-05T00:05:00Z",
|
||||||
|
"finding_id": "finding-123",
|
||||||
|
"profile_id": "default-profile",
|
||||||
|
"score": 0.85,
|
||||||
|
"severity": "high",
|
||||||
|
"gates": ["kev_and_reachability"],
|
||||||
|
"top_contributors": [
|
||||||
|
{"factor": "cvss", "contribution": 0.4, "raw": 7.5, "provenance": "sha256:cvsshash"},
|
||||||
|
{"factor": "kev", "contribution": 0.3, "raw": true, "provenance": "sha256:kevhash"},
|
||||||
|
{"factor": "reachability", "contribution": 0.3, "raw": 0.9, "provenance": "sha256:reachhash"}
|
||||||
|
],
|
||||||
|
"provenance": {"job_hash": "sha256:jobhash"},
|
||||||
|
"charts": {
|
||||||
|
"donut": {"high": 1},
|
||||||
|
"stacked": [0.4, 0.3, 0.3]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
> **Audience:** Ops Guild · Evidence Locker Guild · Scanner Guild · Authority/Signer · Attestor
|
> **Audience:** Ops Guild · Evidence Locker Guild · Scanner Guild · Authority/Signer · Attestor
|
||||||
> **Prereqs:** `docs/replay/DETERMINISTIC_REPLAY.md`, `docs/replay/DEVS_GUIDE_REPLAY.md`, `docs/replay/TEST_STRATEGY.md`, `docs/modules/platform/architecture-overview.md` §5
|
> **Prereqs:** `docs/replay/DETERMINISTIC_REPLAY.md`, `docs/replay/DEVS_GUIDE_REPLAY.md`, `docs/replay/TEST_STRATEGY.md`, `docs/modules/platform/architecture-overview.md` §5
|
||||||
|
|
||||||
This runbook governs day-to-day replay operations, retention, and incident handling across online and air-gapped environments. Keep it in sync with the tasks in `docs/implplan/SPRINT_187_evidence_locker_cli_integration.md`.
|
This runbook governs day-to-day replay operations, retention, and incident handling across online and air-gapped environments. Keep it in sync with the tasks in `docs/implplan/SPRINT_0187_0000_0001_evidence_locker_cli_integration.md`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ This runbook governs day-to-day replay operations, retention, and incident handl
|
|||||||
- `docs/modules/platform/architecture-overview.md` §5
|
- `docs/modules/platform/architecture-overview.md` §5
|
||||||
- `docs/modules/evidence-locker/architecture.md`
|
- `docs/modules/evidence-locker/architecture.md`
|
||||||
- `docs/modules/telemetry/architecture.md`
|
- `docs/modules/telemetry/architecture.md`
|
||||||
- `docs/implplan/SPRINT_187_evidence_locker_cli_integration.md`
|
- `docs/implplan/SPRINT_0187_0000_0001_evidence_locker_cli_integration.md`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ git add \
|
|||||||
docs/modules/scanner/prep/2025-11-21-scanner-records-prep.md \
|
docs/modules/scanner/prep/2025-11-21-scanner-records-prep.md \
|
||||||
docs/samples/prep/2025-11-20-lnm-22-001-prep.md \
|
docs/samples/prep/2025-11-20-lnm-22-001-prep.md \
|
||||||
docs/implplan/SPRINT_0123_0001_0001_policy_reasoning.md \
|
docs/implplan/SPRINT_0123_0001_0001_policy_reasoning.md \
|
||||||
docs/implplan/SPRINT_123_policy_reasoning.md \
|
docs/implplan/SPRINT_0123_0000_0001_policy_reasoning.md \
|
||||||
docs/implplan/SPRINT_0125_0001_0001_policy_reasoning.md \
|
docs/implplan/SPRINT_0125_0001_0001_policy_reasoning.md \
|
||||||
docs/implplan/SPRINT_0131_0001_0001_scanner_surface.md
|
docs/implplan/SPRINT_0131_0001_0001_scanner_surface.md
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace StellaOps.Concelier.Storage.Mongo.Documents;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stub record for document storage. (Placeholder for full implementation)
|
||||||
|
/// </summary>
|
||||||
|
public sealed record DocumentRecord
|
||||||
|
{
|
||||||
|
public string Id { get; init; } = string.Empty;
|
||||||
|
public string TenantId { get; init; } = string.Empty;
|
||||||
|
public string Source { get; init; } = string.Empty;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace StellaOps.Concelier.Storage.Mongo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stub interface for document storage. (Placeholder for full implementation)
|
||||||
|
/// </summary>
|
||||||
|
public interface IDocumentStore
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace StellaOps.Concelier.Storage.Mongo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stub interface for source state repository. (Placeholder for full implementation)
|
||||||
|
/// </summary>
|
||||||
|
public interface ISourceStateRepository
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace StellaOps.Concelier.Storage.Mongo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stub options for MongoDB storage. (Placeholder for full implementation)
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MongoStorageOptions
|
||||||
|
{
|
||||||
|
public string ConnectionString { get; set; } = string.Empty;
|
||||||
|
public string DatabaseName { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<LangVersion>preview</LangVersion>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../StellaOps.Concelier.RawModels/StellaOps.Concelier.RawModels.csproj" />
|
||||||
|
<ProjectReference Include="../StellaOps.Concelier.Models/StellaOps.Concelier.Models.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -243,23 +243,7 @@ public sealed class AdvisorySchemaValidatorTests
|
|||||||
public void AocGuard_DetectsAllForbiddenFields(string forbiddenField)
|
public void AocGuard_DetectsAllForbiddenFields(string forbiddenField)
|
||||||
{
|
{
|
||||||
var guard = new AocWriteGuard();
|
var guard = new AocWriteGuard();
|
||||||
var json = $$"""
|
var json = GetTestJsonWithField(forbiddenField, "forbidden_value");
|
||||||
{
|
|
||||||
"tenant": "test",
|
|
||||||
"{{forbiddenField}}": "forbidden_value",
|
|
||||||
"source": {"vendor": "test", "connector": "test", "version": "1.0"},
|
|
||||||
"upstream": {
|
|
||||||
"upstream_id": "CVE-2024-0001",
|
|
||||||
"content_hash": "sha256:abc",
|
|
||||||
"retrieved_at": "2024-01-01T00:00:00Z",
|
|
||||||
"signature": {"present": false},
|
|
||||||
"provenance": {}
|
|
||||||
},
|
|
||||||
"content": {"format": "OSV", "raw": {}},
|
|
||||||
"identifiers": {"aliases": [], "primary": "CVE-2024-0001"},
|
|
||||||
"linkset": {}
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
using var jsonDoc = JsonDocument.Parse(json);
|
using var jsonDoc = JsonDocument.Parse(json);
|
||||||
|
|
||||||
var result = guard.Validate(jsonDoc.RootElement, GuardOptions);
|
var result = guard.Validate(jsonDoc.RootElement, GuardOptions);
|
||||||
@@ -277,10 +261,25 @@ public sealed class AdvisorySchemaValidatorTests
|
|||||||
public void AocGuard_DetectsAllDerivedFields(string derivedField)
|
public void AocGuard_DetectsAllDerivedFields(string derivedField)
|
||||||
{
|
{
|
||||||
var guard = new AocWriteGuard();
|
var guard = new AocWriteGuard();
|
||||||
var json = $$"""
|
var json = GetTestJsonWithField(derivedField, "derived_value");
|
||||||
|
using var jsonDoc = JsonDocument.Parse(json);
|
||||||
|
|
||||||
|
var result = guard.Validate(jsonDoc.RootElement, GuardOptions);
|
||||||
|
|
||||||
|
Assert.False(result.IsValid);
|
||||||
|
// Derived fields (effective_*) trigger both ForbiddenField and DerivedFindingDetected
|
||||||
|
// if they're in the forbidden list, otherwise just DerivedFindingDetected
|
||||||
|
Assert.Contains(result.Violations, v =>
|
||||||
|
v.Code == AocViolationCode.DerivedFindingDetected &&
|
||||||
|
v.ErrorCode == "ERR_AOC_006");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetTestJsonWithField(string fieldName, string fieldValue)
|
||||||
|
{
|
||||||
|
return """
|
||||||
{
|
{
|
||||||
"tenant": "test",
|
"tenant": "test",
|
||||||
"{{derivedField}}": "derived_value",
|
"FIELD_NAME_PLACEHOLDER": "FIELD_VALUE_PLACEHOLDER",
|
||||||
"source": {"vendor": "test", "connector": "test", "version": "1.0"},
|
"source": {"vendor": "test", "connector": "test", "version": "1.0"},
|
||||||
"upstream": {
|
"upstream": {
|
||||||
"upstream_id": "CVE-2024-0001",
|
"upstream_id": "CVE-2024-0001",
|
||||||
@@ -293,16 +292,6 @@ public sealed class AdvisorySchemaValidatorTests
|
|||||||
"identifiers": {"aliases": [], "primary": "CVE-2024-0001"},
|
"identifiers": {"aliases": [], "primary": "CVE-2024-0001"},
|
||||||
"linkset": {}
|
"linkset": {}
|
||||||
}
|
}
|
||||||
""";
|
""".Replace("FIELD_NAME_PLACEHOLDER", fieldName).Replace("FIELD_VALUE_PLACEHOLDER", fieldValue);
|
||||||
using var jsonDoc = JsonDocument.Parse(json);
|
|
||||||
|
|
||||||
var result = guard.Validate(jsonDoc.RootElement, GuardOptions);
|
|
||||||
|
|
||||||
Assert.False(result.IsValid);
|
|
||||||
// Derived fields (effective_*) trigger both ForbiddenField and DerivedFindingDetected
|
|
||||||
// if they're in the forbidden list, otherwise just DerivedFindingDetected
|
|
||||||
Assert.Contains(result.Violations, v =>
|
|
||||||
v.Code == AocViolationCode.DerivedFindingDetected &&
|
|
||||||
v.ErrorCode == "ERR_AOC_006");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<!-- Disable Concelier Testing infra which requires Storage.Mongo -->
|
|
||||||
<UseConcelierTestInfra>false</UseConcelierTestInfra>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="../../__Libraries/StellaOps.Concelier.Core/StellaOps.Concelier.Core.csproj" />
|
<ProjectReference Include="../../__Libraries/StellaOps.Concelier.Core/StellaOps.Concelier.Core.csproj" />
|
||||||
@@ -15,11 +13,7 @@
|
|||||||
<ProjectReference Include="../../__Libraries/StellaOps.Concelier.Models/StellaOps.Concelier.Models.csproj" />
|
<ProjectReference Include="../../__Libraries/StellaOps.Concelier.Models/StellaOps.Concelier.Models.csproj" />
|
||||||
<ProjectReference Include="../../../__Libraries/StellaOps.Ingestion.Telemetry/StellaOps.Ingestion.Telemetry.csproj" />
|
<ProjectReference Include="../../../__Libraries/StellaOps.Ingestion.Telemetry/StellaOps.Ingestion.Telemetry.csproj" />
|
||||||
<ProjectReference Include="../../../Aoc/__Libraries/StellaOps.Aoc/StellaOps.Aoc.csproj" />
|
<ProjectReference Include="../../../Aoc/__Libraries/StellaOps.Aoc/StellaOps.Aoc.csproj" />
|
||||||
<!-- Test packages (manually added since UseConcelierTestInfra=false) -->
|
<!-- Test packages inherited from Directory.Build.props -->
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
|
|
||||||
<PackageReference Include="xunit" Version="2.9.2" />
|
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
|
||||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -126,5 +126,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"cli": {
|
||||||
|
"analytics": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user