audit, advisories and doctors/setup work
This commit is contained in:
@@ -25,27 +25,27 @@ Bulk task definitions (applies to every project row below):
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 1 | AUDIT-0001-M | DONE | Revalidated 2026-01-08 | Guild | devops/services/crypto/sim-crypto-service/SimCryptoService.csproj - MAINT |
|
||||
| 2 | AUDIT-0001-T | DONE | Revalidated 2026-01-08 | Guild | devops/services/crypto/sim-crypto-service/SimCryptoService.csproj - TEST |
|
||||
| 3 | AUDIT-0001-A | TODO | Approved 2026-01-12 | Guild | devops/services/crypto/sim-crypto-service/SimCryptoService.csproj - APPLY |
|
||||
| 3 | AUDIT-0001-A | DONE | Applied 2026-01-13 | Guild | devops/services/crypto/sim-crypto-service/SimCryptoService.csproj - APPLY |
|
||||
| 4 | AUDIT-0002-M | DONE | Revalidated 2026-01-08 | Guild | devops/services/crypto/sim-crypto-smoke/SimCryptoSmoke.csproj - MAINT |
|
||||
| 5 | AUDIT-0002-T | DONE | Revalidated 2026-01-08 | Guild | devops/services/crypto/sim-crypto-smoke/SimCryptoSmoke.csproj - TEST |
|
||||
| 6 | AUDIT-0002-A | TODO | Approved 2026-01-12 | Guild | devops/services/crypto/sim-crypto-smoke/SimCryptoSmoke.csproj - APPLY |
|
||||
| 6 | AUDIT-0002-A | DONE | Applied 2026-01-13 | Guild | devops/services/crypto/sim-crypto-smoke/SimCryptoSmoke.csproj - APPLY |
|
||||
| 7 | AUDIT-0003-M | DONE | Revalidated 2026-01-08 | Guild | devops/services/cryptopro/linux-csp-service/CryptoProLinuxApi.csproj - MAINT |
|
||||
| 8 | AUDIT-0003-T | DONE | Revalidated 2026-01-08 | Guild | devops/services/cryptopro/linux-csp-service/CryptoProLinuxApi.csproj - TEST |
|
||||
| 9 | AUDIT-0003-A | TODO | Approved 2026-01-12 | Guild | devops/services/cryptopro/linux-csp-service/CryptoProLinuxApi.csproj - APPLY |
|
||||
| 9 | AUDIT-0003-A | DONE | Applied 2026-01-13 | Guild | devops/services/cryptopro/linux-csp-service/CryptoProLinuxApi.csproj - APPLY |
|
||||
| 10 | AUDIT-0004-M | DONE | Revalidated 2026-01-08 | Guild | devops/tools/nuget-prime/nuget-prime.csproj - MAINT |
|
||||
| 11 | AUDIT-0004-T | DONE | Revalidated 2026-01-08 | Guild | devops/tools/nuget-prime/nuget-prime.csproj - TEST |
|
||||
| 12 | AUDIT-0004-A | TODO | Approved 2026-01-12 | Guild | devops/tools/nuget-prime/nuget-prime.csproj - APPLY |
|
||||
| 12 | AUDIT-0004-A | DONE | Applied 2026-01-13 | Guild | devops/tools/nuget-prime/nuget-prime.csproj - APPLY |
|
||||
| 13 | AUDIT-0005-M | DONE | Revalidated 2026-01-08 | Guild | devops/tools/nuget-prime/nuget-prime-v9.csproj - MAINT |
|
||||
| 14 | AUDIT-0005-T | DONE | Revalidated 2026-01-08 | Guild | devops/tools/nuget-prime/nuget-prime-v9.csproj - TEST |
|
||||
| 15 | AUDIT-0005-A | TODO | Approved 2026-01-12 | Guild | devops/tools/nuget-prime/nuget-prime-v9.csproj - APPLY |
|
||||
| 15 | AUDIT-0005-A | DONE | Applied 2026-01-13 | Guild | devops/tools/nuget-prime/nuget-prime-v9.csproj - APPLY |
|
||||
| 16 | AUDIT-0006-M | DONE | Revalidated 2026-01-08 (doc template) | Guild | docs/dev/sdks/plugin-templates/StellaOps.Templates.csproj - MAINT |
|
||||
| 17 | AUDIT-0006-T | DONE | Revalidated 2026-01-08 (doc template) | Guild | docs/dev/sdks/plugin-templates/StellaOps.Templates.csproj - TEST |
|
||||
| 17 | AUDIT-0006-T | DONE | Waived 2026-01-13 (template package; content-only) | Guild | docs/dev/sdks/plugin-templates/StellaOps.Templates.csproj - TEST |
|
||||
| 18 | AUDIT-0006-A | DONE | Waived (doc template) | Guild | docs/dev/sdks/plugin-templates/StellaOps.Templates.csproj - APPLY |
|
||||
| 19 | AUDIT-0007-M | DONE | Revalidated 2026-01-08 (doc template) | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-connector/StellaOps.Plugin.MyConnector.csproj - MAINT |
|
||||
| 20 | AUDIT-0007-T | DONE | Revalidated 2026-01-08 (doc template) | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-connector/StellaOps.Plugin.MyConnector.csproj - TEST |
|
||||
| 20 | AUDIT-0007-T | DONE | Applied 2026-01-13; test scaffolding added | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-connector/StellaOps.Plugin.MyConnector.csproj - TEST |
|
||||
| 21 | AUDIT-0007-A | DONE | Waived (doc template) | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-connector/StellaOps.Plugin.MyConnector.csproj - APPLY |
|
||||
| 22 | AUDIT-0008-M | DONE | Revalidated 2026-01-08 (doc template) | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-scheduler/StellaOps.Plugin.MyJob.csproj - MAINT |
|
||||
| 23 | AUDIT-0008-T | DONE | Revalidated 2026-01-08 (doc template) | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-scheduler/StellaOps.Plugin.MyJob.csproj - TEST |
|
||||
| 23 | AUDIT-0008-T | DONE | Applied 2026-01-13; test scaffolding added | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-scheduler/StellaOps.Plugin.MyJob.csproj - TEST |
|
||||
| 24 | AUDIT-0008-A | DONE | Waived (doc template) | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-scheduler/StellaOps.Plugin.MyJob.csproj - APPLY |
|
||||
| 25 | AUDIT-0009-M | DONE | Revalidated 2026-01-08 (doc template) | Guild | docs/dev/templates/excititor-connector/src/Excititor.MyConnector.csproj - MAINT |
|
||||
| 26 | AUDIT-0009-T | DONE | Revalidated 2026-01-08 (doc template) | Guild | docs/dev/templates/excititor-connector/src/Excititor.MyConnector.csproj - TEST |
|
||||
@@ -118,7 +118,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 93 | AUDIT-0031-A | DONE | Waived (test project) | Guild | src/__Libraries/__Tests/StellaOps.Plugin.Tests/StellaOps.Plugin.Tests.csproj - APPLY |
|
||||
| 94 | AUDIT-0032-M | DONE | Revalidated 2026-01-08 (test project) | Guild | src/__Libraries/__Tests/StellaOps.Provcache.Tests/StellaOps.Provcache.Tests.csproj - MAINT |
|
||||
| 95 | AUDIT-0032-T | DONE | Revalidated 2026-01-08 (test project) | Guild | src/__Libraries/__Tests/StellaOps.Provcache.Tests/StellaOps.Provcache.Tests.csproj - TEST |
|
||||
| 96 | AUDIT-0032-A | DONE | Waived (test project) | Guild | src/__Libraries/__Tests/StellaOps.Provcache.Tests/StellaOps.Provcache.Tests.csproj - APPLY |
|
||||
| 96 | AUDIT-0032-A | DONE | Applied 2026-01-13 (deterministic fixtures, Integration tagging, warnings-as-errors) | Guild | src/__Libraries/__Tests/StellaOps.Provcache.Tests/StellaOps.Provcache.Tests.csproj - APPLY |
|
||||
| 97 | AUDIT-0033-M | DONE | Revalidated 2026-01-08 (test project) | Guild | src/__Libraries/__Tests/StellaOps.Provenance.Tests/StellaOps.Provenance.Tests.csproj - MAINT |
|
||||
| 98 | AUDIT-0033-T | DONE | Revalidated 2026-01-08 (test project) | Guild | src/__Libraries/__Tests/StellaOps.Provenance.Tests/StellaOps.Provenance.Tests.csproj - TEST |
|
||||
| 99 | AUDIT-0033-A | DONE | Waived (test project) | Guild | src/__Libraries/__Tests/StellaOps.Provenance.Tests/StellaOps.Provenance.Tests.csproj - APPLY |
|
||||
@@ -310,22 +310,22 @@ Bulk task definitions (applies to every project row below):
|
||||
| 285 | AUDIT-0095-A | TODO | Approved 2026-01-12 (revalidated 2026-01-08) | Guild | src/__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj - APPLY |
|
||||
| 286 | AUDIT-0096-M | DONE | Revalidated 2026-01-08 | Guild | src/__Libraries/StellaOps.Policy.Tools/StellaOps.Policy.Tools.csproj - MAINT |
|
||||
| 287 | AUDIT-0096-T | DONE | Revalidated 2026-01-08 | Guild | src/__Libraries/StellaOps.Policy.Tools/StellaOps.Policy.Tools.csproj - TEST |
|
||||
| 288 | AUDIT-0096-A | TODO | Approved 2026-01-12 (revalidated 2026-01-08) | Guild | src/__Libraries/StellaOps.Policy.Tools/StellaOps.Policy.Tools.csproj - APPLY |
|
||||
| 288 | AUDIT-0096-A | DONE | Applied 2026-01-14 (determinism, parsing guards, tests) | Guild | src/__Libraries/StellaOps.Policy.Tools/StellaOps.Policy.Tools.csproj - APPLY |
|
||||
| 289 | AUDIT-0097-M | DONE | Revalidated 2026-01-08 | Guild | src/__Libraries/StellaOps.PolicyAuthoritySignals.Contracts/StellaOps.PolicyAuthoritySignals.Contracts.csproj - MAINT |
|
||||
| 290 | AUDIT-0097-T | DONE | Revalidated 2026-01-08 | Guild | src/__Libraries/StellaOps.PolicyAuthoritySignals.Contracts/StellaOps.PolicyAuthoritySignals.Contracts.csproj - TEST |
|
||||
| 291 | AUDIT-0097-A | TODO | Approved 2026-01-12 (revalidated 2026-01-08) | Guild | src/__Libraries/StellaOps.PolicyAuthoritySignals.Contracts/StellaOps.PolicyAuthoritySignals.Contracts.csproj - APPLY |
|
||||
| 292 | AUDIT-0098-M | DONE | Revalidated 2026-01-08 | Guild | src/__Libraries/StellaOps.Provcache.Api/StellaOps.Provcache.Api.csproj - MAINT |
|
||||
| 293 | AUDIT-0098-T | DONE | Revalidated 2026-01-08 | Guild | src/__Libraries/StellaOps.Provcache.Api/StellaOps.Provcache.Api.csproj - TEST |
|
||||
| 294 | AUDIT-0098-A | TODO | Approved 2026-01-12 (revalidated 2026-01-08) | Guild | src/__Libraries/StellaOps.Provcache.Api/StellaOps.Provcache.Api.csproj - APPLY |
|
||||
| 294 | AUDIT-0098-A | DONE | Applied 2026-01-13 (error redaction, ordering, pagination validation, tests) | Guild | src/__Libraries/StellaOps.Provcache.Api/StellaOps.Provcache.Api.csproj - APPLY |
|
||||
| 295 | AUDIT-0099-M | DONE | Revalidated 2026-01-08 | Guild | src/__Libraries/StellaOps.Provcache.Postgres/StellaOps.Provcache.Postgres.csproj - MAINT |
|
||||
| 296 | AUDIT-0099-T | DONE | Revalidated 2026-01-08 | Guild | src/__Libraries/StellaOps.Provcache.Postgres/StellaOps.Provcache.Postgres.csproj - TEST |
|
||||
| 297 | AUDIT-0099-A | TODO | Approved 2026-01-12 (revalidated 2026-01-08) | Guild | src/__Libraries/StellaOps.Provcache.Postgres/StellaOps.Provcache.Postgres.csproj - APPLY |
|
||||
| 297 | AUDIT-0099-A | DONE | Applied 2026-01-13 (canonical replay seed serialization; test gaps tracked) | Guild | src/__Libraries/StellaOps.Provcache.Postgres/StellaOps.Provcache.Postgres.csproj - APPLY |
|
||||
| 298 | AUDIT-0100-M | DONE | Revalidated 2026-01-08 | Guild | src/__Libraries/StellaOps.Provcache.Valkey/StellaOps.Provcache.Valkey.csproj - MAINT |
|
||||
| 299 | AUDIT-0100-T | DONE | Revalidated 2026-01-08 | Guild | src/__Libraries/StellaOps.Provcache.Valkey/StellaOps.Provcache.Valkey.csproj - TEST |
|
||||
| 300 | AUDIT-0100-A | TODO | Approved 2026-01-12 (revalidated 2026-01-08) | Guild | src/__Libraries/StellaOps.Provcache.Valkey/StellaOps.Provcache.Valkey.csproj - APPLY |
|
||||
| 300 | AUDIT-0100-A | DONE | Applied 2026-01-13 (SCAN invalidation, cancellation propagation; test gaps tracked) | Guild | src/__Libraries/StellaOps.Provcache.Valkey/StellaOps.Provcache.Valkey.csproj - APPLY |
|
||||
| 301 | AUDIT-0101-M | DONE | Revalidated 2026-01-08 | Guild | src/__Libraries/StellaOps.Provcache/StellaOps.Provcache.csproj - MAINT |
|
||||
| 302 | AUDIT-0101-T | DONE | Revalidated 2026-01-08 | Guild | src/__Libraries/StellaOps.Provcache/StellaOps.Provcache.csproj - TEST |
|
||||
| 303 | AUDIT-0101-A | TODO | Approved 2026-01-12 (revalidated 2026-01-08) | Guild | src/__Libraries/StellaOps.Provcache/StellaOps.Provcache.csproj - APPLY |
|
||||
| 303 | AUDIT-0101-A | DONE | Applied 2026-01-13 | Guild | src/__Libraries/StellaOps.Provcache/StellaOps.Provcache.csproj - APPLY |
|
||||
| 304 | AUDIT-0102-M | DONE | Revalidated 2026-01-08 | Guild | src/__Libraries/StellaOps.Provenance/StellaOps.Provenance.csproj - MAINT |
|
||||
| 305 | AUDIT-0102-T | DONE | Revalidated 2026-01-08 | Guild | src/__Libraries/StellaOps.Provenance/StellaOps.Provenance.csproj - TEST |
|
||||
| 306 | AUDIT-0102-A | TODO | Approved 2026-01-12 (revalidated 2026-01-08) | Guild | src/__Libraries/StellaOps.Provenance/StellaOps.Provenance.csproj - APPLY |
|
||||
@@ -361,7 +361,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 336 | AUDIT-0112-A | TODO | Approved 2026-01-12 (revalidated 2026-01-08) | Guild | src/__Libraries/StellaOps.Spdx3/StellaOps.Spdx3.csproj - APPLY |
|
||||
| 337 | AUDIT-0113-M | DONE | Revalidated 2026-01-12 | Guild | src/__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj - MAINT |
|
||||
| 338 | AUDIT-0113-T | DONE | Revalidated 2026-01-12 | Guild | src/__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj - TEST |
|
||||
| 339 | AUDIT-0113-A | TODO | Approved 2026-01-12 | Guild | src/__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj - APPLY |
|
||||
| 339 | AUDIT-0113-A | DONE | Applied 2026-01-13 | Guild | src/__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj - APPLY |
|
||||
| 340 | AUDIT-0114-M | DONE | Revalidated 2026-01-12 | Guild | src/__Libraries/StellaOps.Verdict/StellaOps.Verdict.csproj - MAINT |
|
||||
| 341 | AUDIT-0114-T | DONE | Revalidated 2026-01-12 | Guild | src/__Libraries/StellaOps.Verdict/StellaOps.Verdict.csproj - TEST |
|
||||
| 342 | AUDIT-0114-A | TODO | Approved 2026-01-12 | Guild | src/__Libraries/StellaOps.Verdict/StellaOps.Verdict.csproj - APPLY |
|
||||
@@ -529,7 +529,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 504 | AUDIT-0168-A | TODO | Approved 2026-01-12 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI.WebService/StellaOps.AdvisoryAI.WebService.csproj - APPLY |
|
||||
| 505 | AUDIT-0169-M | DONE | Revalidated 2026-01-12 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI.Worker/StellaOps.AdvisoryAI.Worker.csproj - MAINT |
|
||||
| 506 | AUDIT-0169-T | DONE | Revalidated 2026-01-12 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI.Worker/StellaOps.AdvisoryAI.Worker.csproj - TEST |
|
||||
| 507 | AUDIT-0169-A | TODO | Approved 2026-01-12 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI.Worker/StellaOps.AdvisoryAI.Worker.csproj - APPLY |
|
||||
| 507 | AUDIT-0169-A | DONE | Applied 2026-01-14 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI.Worker/StellaOps.AdvisoryAI.Worker.csproj - APPLY |
|
||||
| 508 | AUDIT-0170-M | DONE | Revalidated 2026-01-12 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI/StellaOps.AdvisoryAI.csproj - MAINT |
|
||||
| 509 | AUDIT-0170-T | DONE | Revalidated 2026-01-12 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI/StellaOps.AdvisoryAI.csproj - TEST |
|
||||
| 510 | AUDIT-0170-A | TODO | Approved 2026-01-12 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI/StellaOps.AdvisoryAI.csproj - APPLY |
|
||||
@@ -1072,7 +1072,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 1047 | AUDIT-0349-A | TODO | Approved 2026-01-12 | Guild | src/Concelier/__Libraries/StellaOps.Concelier.Connector.Vndr.Vmware/StellaOps.Concelier.Connector.Vndr.Vmware.csproj - APPLY |
|
||||
| 1048 | AUDIT-0350-M | DONE | Revalidated 2026-01-12 | Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core/StellaOps.Concelier.Core.csproj - MAINT |
|
||||
| 1049 | AUDIT-0350-T | DONE | Revalidated 2026-01-12 | Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core/StellaOps.Concelier.Core.csproj - TEST |
|
||||
| 1050 | AUDIT-0350-A | TODO | Approved 2026-01-12 | Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core/StellaOps.Concelier.Core.csproj - APPLY |
|
||||
| 1050 | AUDIT-0350-A | DONE | Applied 2026-01-13 | Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core/StellaOps.Concelier.Core.csproj - APPLY |
|
||||
| 1051 | AUDIT-0351-M | DONE | Revalidated 2026-01-12 | Guild | src/Concelier/__Libraries/StellaOps.Concelier.Exporter.Json/StellaOps.Concelier.Exporter.Json.csproj - MAINT |
|
||||
| 1052 | AUDIT-0351-T | DONE | Revalidated 2026-01-12 | Guild | src/Concelier/__Libraries/StellaOps.Concelier.Exporter.Json/StellaOps.Concelier.Exporter.Json.csproj - TEST |
|
||||
| 1053 | AUDIT-0351-A | TODO | Approved 2026-01-12 | Guild | src/Concelier/__Libraries/StellaOps.Concelier.Exporter.Json/StellaOps.Concelier.Exporter.Json.csproj - APPLY |
|
||||
@@ -1273,7 +1273,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 1248 | AUDIT-0416-A | TODO | Approved 2026-01-12 | Guild | src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/StellaOps.Concelier.WebService.Tests.csproj - APPLY |
|
||||
| 1249 | AUDIT-0417-M | DONE | Revalidated 2026-01-12 | Guild | src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj - MAINT |
|
||||
| 1250 | AUDIT-0417-T | DONE | Revalidated 2026-01-12 | Guild | src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj - TEST |
|
||||
| 1251 | AUDIT-0417-A | TODO | Approved 2026-01-12 | Guild | src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj - APPLY |
|
||||
| 1251 | AUDIT-0417-A | DONE | Applied 2026-01-13; TimeProvider defaults, ASCII cleanup, federation tests | Guild | src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj - APPLY |
|
||||
| 1252 | AUDIT-0418-M | DONE | Revalidated 2026-01-12 | Guild | src/Cryptography/StellaOps.Cryptography.Profiles.Ecdsa/StellaOps.Cryptography.Profiles.Ecdsa.csproj - MAINT |
|
||||
| 1253 | AUDIT-0418-T | DONE | Revalidated 2026-01-12 | Guild | src/Cryptography/StellaOps.Cryptography.Profiles.Ecdsa/StellaOps.Cryptography.Profiles.Ecdsa.csproj - TEST |
|
||||
| 1254 | AUDIT-0418-A | TODO | Approved 2026-01-12 | Guild | src/Cryptography/StellaOps.Cryptography.Profiles.Ecdsa/StellaOps.Cryptography.Profiles.Ecdsa.csproj - APPLY |
|
||||
@@ -1426,7 +1426,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 1401 | AUDIT-0467-A | TODO | Approved 2026-01-12 | Guild | src/Excititor/StellaOps.Excititor.WebService/StellaOps.Excititor.WebService.csproj - APPLY |
|
||||
| 1402 | AUDIT-0468-M | DONE | Revalidated 2026-01-12 | Guild | src/Excititor/StellaOps.Excititor.Worker/StellaOps.Excititor.Worker.csproj - MAINT |
|
||||
| 1403 | AUDIT-0468-T | DONE | Revalidated 2026-01-12 | Guild | src/Excititor/StellaOps.Excititor.Worker/StellaOps.Excititor.Worker.csproj - TEST |
|
||||
| 1404 | AUDIT-0468-A | TODO | Approved 2026-01-12 | Guild | src/Excititor/StellaOps.Excititor.Worker/StellaOps.Excititor.Worker.csproj - APPLY |
|
||||
| 1404 | AUDIT-0468-A | DONE | Applied 2026-01-13; determinism, DI, tests | Guild | src/Excititor/StellaOps.Excititor.Worker/StellaOps.Excititor.Worker.csproj - APPLY |
|
||||
| 1405 | AUDIT-0469-M | DONE | Revalidated 2026-01-12 | Guild | src/ExportCenter/StellaOps.ExportCenter.RiskBundles/StellaOps.ExportCenter.RiskBundles.csproj - MAINT |
|
||||
| 1406 | AUDIT-0469-T | DONE | Revalidated 2026-01-12 | Guild | src/ExportCenter/StellaOps.ExportCenter.RiskBundles/StellaOps.ExportCenter.RiskBundles.csproj - TEST |
|
||||
| 1407 | AUDIT-0469-A | TODO | Approved 2026-01-12 | Guild | src/ExportCenter/StellaOps.ExportCenter.RiskBundles/StellaOps.ExportCenter.RiskBundles.csproj - APPLY |
|
||||
@@ -1816,7 +1816,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 1791 | AUDIT-0597-A | TODO | Approved 2026-01-12 | Guild | src/Router/__Libraries/StellaOps.Microservice.SourceGen/StellaOps.Microservice.SourceGen.csproj - APPLY |
|
||||
| 1792 | AUDIT-0598-M | DONE | Revalidated 2026-01-12 | Guild | src/Router/__Libraries/StellaOps.Microservice/StellaOps.Microservice.csproj - MAINT |
|
||||
| 1793 | AUDIT-0598-T | DONE | Revalidated 2026-01-12 | Guild | src/Router/__Libraries/StellaOps.Microservice/StellaOps.Microservice.csproj - TEST |
|
||||
| 1794 | AUDIT-0598-A | TODO | Approved 2026-01-12 | Guild | src/Router/__Libraries/StellaOps.Microservice/StellaOps.Microservice.csproj - APPLY |
|
||||
| 1794 | AUDIT-0598-A | DONE | Applied 2026-01-13; hotlist fixes and tests | Guild | src/Router/__Libraries/StellaOps.Microservice/StellaOps.Microservice.csproj - APPLY |
|
||||
| 1795 | AUDIT-0599-M | DONE | Revalidated 2026-01-12 | Guild | src/Router/__Libraries/StellaOps.Router.AspNet/StellaOps.Router.AspNet.csproj - MAINT |
|
||||
| 1796 | AUDIT-0599-T | DONE | Revalidated 2026-01-12 | Guild | src/Router/__Libraries/StellaOps.Router.AspNet/StellaOps.Router.AspNet.csproj - TEST |
|
||||
| 1797 | AUDIT-0599-A | TODO | Approved 2026-01-12 | Guild | src/Router/__Libraries/StellaOps.Router.AspNet/StellaOps.Router.AspNet.csproj - APPLY |
|
||||
@@ -2074,7 +2074,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 2049 | AUDIT-0683-A | TODO | Approved 2026-01-12 | Guild | src/Scanner/__Libraries/StellaOps.Scanner.SmartDiff/StellaOps.Scanner.SmartDiff.csproj - APPLY |
|
||||
| 2050 | AUDIT-0684-M | DONE | Revalidated 2026-01-12 | Guild | src/Scanner/__Libraries/StellaOps.Scanner.Sources/StellaOps.Scanner.Sources.csproj - MAINT |
|
||||
| 2051 | AUDIT-0684-T | DONE | Revalidated 2026-01-12 | Guild | src/Scanner/__Libraries/StellaOps.Scanner.Sources/StellaOps.Scanner.Sources.csproj - TEST |
|
||||
| 2052 | AUDIT-0684-A | TODO | Approved 2026-01-12 | Guild | src/Scanner/__Libraries/StellaOps.Scanner.Sources/StellaOps.Scanner.Sources.csproj - APPLY |
|
||||
| 2052 | AUDIT-0684-A | DONE | Applied 2026-01-14 | Guild | src/Scanner/__Libraries/StellaOps.Scanner.Sources/StellaOps.Scanner.Sources.csproj - APPLY |
|
||||
| 2053 | AUDIT-0685-M | DONE | Revalidated 2026-01-12 | Guild | src/Scanner/__Libraries/StellaOps.Scanner.Storage.Oci/StellaOps.Scanner.Storage.Oci.csproj - MAINT |
|
||||
| 2054 | AUDIT-0685-T | DONE | Revalidated 2026-01-12 | Guild | src/Scanner/__Libraries/StellaOps.Scanner.Storage.Oci/StellaOps.Scanner.Storage.Oci.csproj - TEST |
|
||||
| 2055 | AUDIT-0685-A | TODO | Approved 2026-01-12 | Guild | src/Scanner/__Libraries/StellaOps.Scanner.Storage.Oci/StellaOps.Scanner.Storage.Oci.csproj - APPLY |
|
||||
@@ -2236,7 +2236,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 2211 | AUDIT-0737-A | TODO | Approved 2026-01-12 | Guild | src/Scanner/__Tests/StellaOps.Scanner.SmartDiff.Tests/StellaOps.Scanner.SmartDiff.Tests.csproj - APPLY |
|
||||
| 2212 | AUDIT-0738-M | DONE | Revalidated 2026-01-12 | Guild | src/Scanner/__Tests/StellaOps.Scanner.Sources.Tests/StellaOps.Scanner.Sources.Tests.csproj - MAINT |
|
||||
| 2213 | AUDIT-0738-T | DONE | Revalidated 2026-01-12 | Guild | src/Scanner/__Tests/StellaOps.Scanner.Sources.Tests/StellaOps.Scanner.Sources.Tests.csproj - TEST |
|
||||
| 2214 | AUDIT-0738-A | TODO | Approved 2026-01-12 | Guild | src/Scanner/__Tests/StellaOps.Scanner.Sources.Tests/StellaOps.Scanner.Sources.Tests.csproj - APPLY |
|
||||
| 2214 | AUDIT-0738-A | DONE | Applied 2026-01-14 | Guild | src/Scanner/__Tests/StellaOps.Scanner.Sources.Tests/StellaOps.Scanner.Sources.Tests.csproj - APPLY |
|
||||
| 2215 | AUDIT-0739-M | DONE | Revalidated 2026-01-12 | Guild | src/Scanner/__Tests/StellaOps.Scanner.Storage.Oci.Tests/StellaOps.Scanner.Storage.Oci.Tests.csproj - MAINT |
|
||||
| 2216 | AUDIT-0739-T | DONE | Revalidated 2026-01-12 | Guild | src/Scanner/__Tests/StellaOps.Scanner.Storage.Oci.Tests/StellaOps.Scanner.Storage.Oci.Tests.csproj - TEST |
|
||||
| 2217 | AUDIT-0739-A | TODO | Approved 2026-01-12 | Guild | src/Scanner/__Tests/StellaOps.Scanner.Storage.Oci.Tests/StellaOps.Scanner.Storage.Oci.Tests.csproj - APPLY |
|
||||
@@ -2266,7 +2266,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 2241 | AUDIT-0747-A | DONE | Applied 2026-01-13 | Guild | src/Scanner/__Tests/StellaOps.Scanner.WebService.Tests/StellaOps.Scanner.WebService.Tests.csproj - APPLY |
|
||||
| 2242 | AUDIT-0748-M | DONE | Revalidated 2026-01-12 | Guild | src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/StellaOps.Scanner.Worker.Tests.csproj - MAINT |
|
||||
| 2243 | AUDIT-0748-T | DONE | Revalidated 2026-01-12 | Guild | src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/StellaOps.Scanner.Worker.Tests.csproj - TEST |
|
||||
| 2244 | AUDIT-0748-A | TODO | Approved 2026-01-12 | Guild | src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/StellaOps.Scanner.Worker.Tests.csproj - APPLY |
|
||||
| 2244 | AUDIT-0748-A | DONE | Applied 2026-01-13 | Guild | src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/StellaOps.Scanner.Worker.Tests.csproj - APPLY |
|
||||
| 2245 | AUDIT-0749-M | DONE | Revalidated 2026-01-12 | Guild | src/Scanner/StellaOps.Scanner.Analyzers.Native/StellaOps.Scanner.Analyzers.Native.csproj - MAINT |
|
||||
| 2246 | AUDIT-0749-T | DONE | Revalidated 2026-01-12 | Guild | src/Scanner/StellaOps.Scanner.Analyzers.Native/StellaOps.Scanner.Analyzers.Native.csproj - TEST |
|
||||
| 2247 | AUDIT-0749-A | DONE | Applied 2026-01-13 | Guild | src/Scanner/StellaOps.Scanner.Analyzers.Native/StellaOps.Scanner.Analyzers.Native.csproj - APPLY |
|
||||
@@ -2278,7 +2278,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 2253 | AUDIT-0751-A | DONE | Applied 2026-01-13 | Guild | src/Scanner/StellaOps.Scanner.WebService/StellaOps.Scanner.WebService.csproj - APPLY |
|
||||
| 2254 | AUDIT-0752-M | DONE | Revalidated 2026-01-12 | Guild | src/Scanner/StellaOps.Scanner.Worker/StellaOps.Scanner.Worker.csproj - MAINT |
|
||||
| 2255 | AUDIT-0752-T | DONE | Revalidated 2026-01-12 | Guild | src/Scanner/StellaOps.Scanner.Worker/StellaOps.Scanner.Worker.csproj - TEST |
|
||||
| 2256 | AUDIT-0752-A | TODO | Approved 2026-01-12 | Guild | src/Scanner/StellaOps.Scanner.Worker/StellaOps.Scanner.Worker.csproj - APPLY |
|
||||
| 2256 | AUDIT-0752-A | DONE | Applied 2026-01-13 | Guild | src/Scanner/StellaOps.Scanner.Worker/StellaOps.Scanner.Worker.csproj - APPLY |
|
||||
| 2257 | AUDIT-0753-M | DONE | Revalidated 2026-01-12 | Guild | src/Scheduler/__Libraries/StellaOps.Scheduler.ImpactIndex/StellaOps.Scheduler.ImpactIndex.csproj - MAINT |
|
||||
| 2258 | AUDIT-0753-T | DONE | Revalidated 2026-01-12 | Guild | src/Scheduler/__Libraries/StellaOps.Scheduler.ImpactIndex/StellaOps.Scheduler.ImpactIndex.csproj - TEST |
|
||||
| 2259 | AUDIT-0753-A | TODO | Approved 2026-01-12 | Guild | src/Scheduler/__Libraries/StellaOps.Scheduler.ImpactIndex/StellaOps.Scheduler.ImpactIndex.csproj - APPLY |
|
||||
@@ -2344,7 +2344,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 2319 | AUDIT-0773-A | TODO | Approved 2026-01-12 | Guild | src/Signals/StellaOps.Signals.Scheduler/StellaOps.Signals.Scheduler.csproj - APPLY |
|
||||
| 2320 | AUDIT-0774-M | DONE | Revalidated 2026-01-12 | Guild | src/Signals/StellaOps.Signals/StellaOps.Signals.csproj - MAINT |
|
||||
| 2321 | AUDIT-0774-T | DONE | Revalidated 2026-01-12 | Guild | src/Signals/StellaOps.Signals/StellaOps.Signals.csproj - TEST |
|
||||
| 2322 | AUDIT-0774-A | TODO | Approved 2026-01-12 | Guild | src/Signals/StellaOps.Signals/StellaOps.Signals.csproj - APPLY |
|
||||
| 2322 | AUDIT-0774-A | DONE | Applied 2026-01-13 | Guild | src/Signals/StellaOps.Signals/StellaOps.Signals.csproj - APPLY |
|
||||
| 2323 | AUDIT-0775-M | DONE | Revalidated 2026-01-12 | Guild | src/Signer/__Libraries/StellaOps.Signer.Keyless/StellaOps.Signer.Keyless.csproj - MAINT |
|
||||
| 2324 | AUDIT-0775-T | DONE | Revalidated 2026-01-12 | Guild | src/Signer/__Libraries/StellaOps.Signer.Keyless/StellaOps.Signer.Keyless.csproj - TEST |
|
||||
| 2325 | AUDIT-0775-A | TODO | Approved 2026-01-12 | Guild | src/Signer/__Libraries/StellaOps.Signer.Keyless/StellaOps.Signer.Keyless.csproj - APPLY |
|
||||
@@ -2548,7 +2548,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 2523 | AUDIT-0841-A | TODO | Approved 2026-01-12 | Guild | src/VexLens/StellaOps.VexLens/StellaOps.VexLens.Core/StellaOps.VexLens.Core.csproj - APPLY |
|
||||
| 2524 | AUDIT-0842-M | DONE | Revalidated 2026-01-12 | Guild | src/VexLens/StellaOps.VexLens/StellaOps.VexLens.csproj - MAINT |
|
||||
| 2525 | AUDIT-0842-T | DONE | Revalidated 2026-01-12 | Guild | src/VexLens/StellaOps.VexLens/StellaOps.VexLens.csproj - TEST |
|
||||
| 2526 | AUDIT-0842-A | TODO | Approved 2026-01-12 | Guild | src/VexLens/StellaOps.VexLens/StellaOps.VexLens.csproj - APPLY |
|
||||
| 2526 | AUDIT-0842-A | DONE | Applied 2026-01-13 | Guild | src/VexLens/StellaOps.VexLens/StellaOps.VexLens.csproj - APPLY |
|
||||
| 2527 | AUDIT-0843-M | DONE | Revalidated 2026-01-12 | Guild | src/VulnExplorer/StellaOps.VulnExplorer.Api/StellaOps.VulnExplorer.Api.csproj - MAINT |
|
||||
| 2528 | AUDIT-0843-T | DONE | Revalidated 2026-01-12 | Guild | src/VulnExplorer/StellaOps.VulnExplorer.Api/StellaOps.VulnExplorer.Api.csproj - TEST |
|
||||
| 2529 | AUDIT-0843-A | TODO | Approved 2026-01-12 | Guild | src/VulnExplorer/StellaOps.VulnExplorer.Api/StellaOps.VulnExplorer.Api.csproj - APPLY |
|
||||
@@ -2569,7 +2569,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 2544 | AUDIT-0848-A | TODO | Approved 2026-01-12 | Guild | src/Zastava/StellaOps.Zastava.Agent/StellaOps.Zastava.Agent.csproj - APPLY |
|
||||
| 2545 | AUDIT-0849-M | DONE | Revalidated 2026-01-12 | Guild | src/Zastava/StellaOps.Zastava.Observer/StellaOps.Zastava.Observer.csproj - MAINT |
|
||||
| 2546 | AUDIT-0849-T | DONE | Revalidated 2026-01-12 | Guild | src/Zastava/StellaOps.Zastava.Observer/StellaOps.Zastava.Observer.csproj - TEST |
|
||||
| 2547 | AUDIT-0849-A | TODO | Approved 2026-01-12 | Guild | src/Zastava/StellaOps.Zastava.Observer/StellaOps.Zastava.Observer.csproj - APPLY |
|
||||
| 2547 | AUDIT-0849-A | DONE | Applied 2026-01-13 | Guild | src/Zastava/StellaOps.Zastava.Observer/StellaOps.Zastava.Observer.csproj - APPLY |
|
||||
| 2548 | AUDIT-0850-M | DONE | Revalidated 2026-01-12 | Guild | src/Zastava/StellaOps.Zastava.Webhook/StellaOps.Zastava.Webhook.csproj - MAINT |
|
||||
| 2549 | AUDIT-0850-T | DONE | Revalidated 2026-01-12 | Guild | src/Zastava/StellaOps.Zastava.Webhook/StellaOps.Zastava.Webhook.csproj - TEST |
|
||||
| 2550 | AUDIT-0850-A | TODO | Approved 2026-01-12 | Guild | src/Zastava/StellaOps.Zastava.Webhook/StellaOps.Zastava.Webhook.csproj - APPLY |
|
||||
@@ -2626,10 +2626,10 @@ Bulk task definitions (applies to every project row below):
|
||||
| 2601 | AUDIT-0866-A | DONE | Waived (test project; revalidated 2026-01-12) | Guild | src/__Tests/Integration/StellaOps.Integration.Immutability/StellaOps.Integration.Immutability.csproj - APPLY |
|
||||
| 2602 | AUDIT-0867-M | DONE | Revalidated 2026-01-12 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI.Plugin.Unified/StellaOps.AdvisoryAI.Plugin.Unified.csproj - MAINT |
|
||||
| 2603 | AUDIT-0867-T | DONE | Revalidated 2026-01-12 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI.Plugin.Unified/StellaOps.AdvisoryAI.Plugin.Unified.csproj - TEST |
|
||||
| 2604 | AUDIT-0867-A | TODO | Approved 2026-01-12 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI.Plugin.Unified/StellaOps.AdvisoryAI.Plugin.Unified.csproj - APPLY |
|
||||
| 2604 | AUDIT-0867-A | DONE | Applied 2026-01-14 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI.Plugin.Unified/StellaOps.AdvisoryAI.Plugin.Unified.csproj - APPLY |
|
||||
| 2605 | AUDIT-0868-M | DONE | Revalidated 2026-01-12 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI.Scm.Plugin.Unified/StellaOps.AdvisoryAI.Scm.Plugin.Unified.csproj - MAINT |
|
||||
| 2606 | AUDIT-0868-T | DONE | Revalidated 2026-01-12 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI.Scm.Plugin.Unified/StellaOps.AdvisoryAI.Scm.Plugin.Unified.csproj - TEST |
|
||||
| 2607 | AUDIT-0868-A | TODO | Approved 2026-01-12 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI.Scm.Plugin.Unified/StellaOps.AdvisoryAI.Scm.Plugin.Unified.csproj - APPLY |
|
||||
| 2607 | AUDIT-0868-A | DONE | Applied 2026-01-14 | Guild | src/AdvisoryAI/StellaOps.AdvisoryAI.Scm.Plugin.Unified/StellaOps.AdvisoryAI.Scm.Plugin.Unified.csproj - APPLY |
|
||||
| 2608 | AUDIT-0869-M | DONE | Revalidated 2026-01-12 (test project) | Guild | src/Attestor/__Libraries/__Tests/StellaOps.Attestor.FixChain.Tests/StellaOps.Attestor.FixChain.Tests.csproj - MAINT |
|
||||
| 2609 | AUDIT-0869-T | DONE | Revalidated 2026-01-12 (test project) | Guild | src/Attestor/__Libraries/__Tests/StellaOps.Attestor.FixChain.Tests/StellaOps.Attestor.FixChain.Tests.csproj - TEST |
|
||||
| 2610 | AUDIT-0869-A | DONE | Waived (test project; revalidated 2026-01-12) | Guild | src/Attestor/__Libraries/__Tests/StellaOps.Attestor.FixChain.Tests/StellaOps.Attestor.FixChain.Tests.csproj - APPLY |
|
||||
@@ -2650,7 +2650,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 2625 | AUDIT-0874-A | TODO | Approved 2026-01-12 | Guild | src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.Diff/StellaOps.BinaryIndex.Diff.csproj - APPLY |
|
||||
| 2626 | AUDIT-0875-M | DONE | Revalidated 2026-01-12 | Guild | src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.GoldenSet/StellaOps.BinaryIndex.GoldenSet.csproj - MAINT |
|
||||
| 2627 | AUDIT-0875-T | DONE | Revalidated 2026-01-12 | Guild | src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.GoldenSet/StellaOps.BinaryIndex.GoldenSet.csproj - TEST |
|
||||
| 2628 | AUDIT-0875-A | TODO | Approved 2026-01-12 | Guild | src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.GoldenSet/StellaOps.BinaryIndex.GoldenSet.csproj - APPLY |
|
||||
| 2628 | AUDIT-0875-A | DONE | Applied 2026-01-13; deterministic newlines, cleanup note, tests | Guild | src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.GoldenSet/StellaOps.BinaryIndex.GoldenSet.csproj - APPLY |
|
||||
| 2629 | AUDIT-0876-M | DONE | Revalidated 2026-01-12 (test project) | Guild | src/BinaryIndex/__Tests/StellaOps.BinaryIndex.Analysis.Tests/StellaOps.BinaryIndex.Analysis.Tests.csproj - MAINT |
|
||||
| 2630 | AUDIT-0876-T | DONE | Revalidated 2026-01-12 (test project) | Guild | src/BinaryIndex/__Tests/StellaOps.BinaryIndex.Analysis.Tests/StellaOps.BinaryIndex.Analysis.Tests.csproj - TEST |
|
||||
| 2631 | AUDIT-0876-A | DONE | Waived (test project; revalidated 2026-01-12) | Guild | src/BinaryIndex/__Tests/StellaOps.BinaryIndex.Analysis.Tests/StellaOps.BinaryIndex.Analysis.Tests.csproj - APPLY |
|
||||
@@ -3083,7 +3083,13 @@ Bulk task definitions (applies to every project row below):
|
||||
| 2026-01-12 | Archived audit report and maint/test sprint to docs-archived/implplan/2025-12-29-csproj-audit; updated references and created pending apply sprint SPRINT_20260112_003_BE_csproj_audit_pending_apply.md. | Project Mgmt |
|
||||
| 2026-01-13 | Applied ExportCenter.WebService hotlist (AUDIT-0337-A/AUDIT-0475-A): determinism, DI guards, retention/TLS gating, tests. | Project Mgmt |
|
||||
| 2026-01-13 | Applied Scanner.Reachability hotlist (AUDIT-0681-A): DSSE PAE/canon, deterministic IDs, cancellation propagation, invariant formatting, tests. | Project Mgmt |
|
||||
| 2026-01-13 | Applied Concelier.WebService hotlist (AUDIT-0242-A/AUDIT-0417-A): TimeProvider timestamps, ASCII cleanup, federation tests. | Project Mgmt |
|
||||
| 2026-01-13 | Applied Evidence hotlist (AUDIT-0082-A/AUDIT-0279-A): determinism, schema validation, budgets, retention, tests. | Project Mgmt |
|
||||
| 2026-01-13 | Applied Scanner.Worker hotlist (AUDIT-0622-A/AUDIT-0748-A/AUDIT-0752-A): determinism, cancellation, DSSE canon, test fixes. | Project Mgmt |
|
||||
| 2026-01-13 | Applied Provcache hotlist (AUDIT-0101-A): HttpClientFactory/allowlist/timeouts, canonical JSON signing, signature verification, options validation, tests. | Project Mgmt |
|
||||
| 2026-01-13 | Applied Provcache.Api/Postgres/Valkey/test audit items (error redaction, ordering/pagination, CanonJson replay seeds, SCAN invalidation, deterministic fixtures); audit report and TASKS.md updated. | Project Mgmt |
|
||||
| 2026-01-13 | Applied Attestor.WebService hotlist (AUDIT-0072-A): feature gating removes disabled controllers, correlation ID provider, proof chain/verification summary fixes, tests updated. | Project Mgmt |
|
||||
| 2026-01-14 | Applied Policy.Tools hotlist (AUDIT-0096-A): LF schema output, fixed-time defaults, parsing guards, deterministic summary output, cancellation propagation, tests added. | Project Mgmt |
|
||||
| 2026-01-12 | Approved all pending APPLY tasks; updated tracker entries to Approved 2026-01-12. | Project Mgmt |
|
||||
| 2026-01-12 | Added Apply Status Summary to the audit report and created sprint `docs-archived/implplan/2026-01-12-csproj-audit-apply-backlog/SPRINT_20260112_002_BE_csproj_audit_apply_backlog.md` for pending APPLY backlog. | Project Mgmt |
|
||||
| 2026-01-12 | Added production test and reuse gap inventories to the audit report to complete per-project audit coverage. | Project Mgmt |
|
||||
@@ -4239,6 +4245,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 2026-01-07 | Added AGENTS.md and TASKS.md for Router transport plugin tests. | Planning |
|
||||
| 2026-01-07 | Revalidated AUDIT-0764 (SbomService.Lineage); report and task trackers updated. | Planning |
|
||||
| 2026-01-07 | Added AGENTS.md and TASKS.md for SbomService Lineage library. | Planning |
|
||||
| 2026-01-13 | Applied devops test gap fixes for sim-crypto-service, sim-crypto-smoke, CryptoProLinuxApi, and nuget-prime (v10/v9); added tests and devops package versions. | Implementer |
|
||||
|
||||
## Decisions & Risks
|
||||
- **APPROVED 2026-01-12**: All pending APPLY tasks approved; remediation can proceed under module review gates.
|
||||
@@ -4573,7 +4580,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 213 | AUDIT-0071-A | TODO | Reopened after revalidation 2026-01-06 | Guild | src/Attestor/StellaOps.Attestor.Verify/StellaOps.Attestor.Verify.csproj - APPLY |
|
||||
| 214 | AUDIT-0072-M | DONE | Revalidation 2026-01-06 | Guild | src/Attestor/StellaOps.Attestor/StellaOps.Attestor.WebService/StellaOps.Attestor.WebService.csproj - MAINT |
|
||||
| 215 | AUDIT-0072-T | DONE | Revalidation 2026-01-06 | Guild | src/Attestor/StellaOps.Attestor/StellaOps.Attestor.WebService/StellaOps.Attestor.WebService.csproj - TEST |
|
||||
| 216 | AUDIT-0072-A | TODO | Reopened after revalidation 2026-01-06 | Guild | src/Attestor/StellaOps.Attestor/StellaOps.Attestor.WebService/StellaOps.Attestor.WebService.csproj - APPLY |
|
||||
| 216 | AUDIT-0072-A | DONE | Applied 2026-01-13 | Guild | src/Attestor/StellaOps.Attestor/StellaOps.Attestor.WebService/StellaOps.Attestor.WebService.csproj - APPLY |
|
||||
| 217 | AUDIT-0073-M | DONE | Revalidation 2026-01-06 | Guild | src/__Libraries/StellaOps.Audit.ReplayToken/StellaOps.Audit.ReplayToken.csproj - MAINT |
|
||||
| 218 | AUDIT-0073-T | DONE | Revalidation 2026-01-06 | Guild | src/__Libraries/StellaOps.Audit.ReplayToken/StellaOps.Audit.ReplayToken.csproj - TEST |
|
||||
| 219 | AUDIT-0073-A | TODO | Reopened after revalidation 2026-01-06 | Guild | src/__Libraries/StellaOps.Audit.ReplayToken/StellaOps.Audit.ReplayToken.csproj - APPLY |
|
||||
@@ -5083,7 +5090,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 723 | AUDIT-0241-A | DONE | Waived (test-support library; revalidated 2026-01-07) | Guild | src/__Tests/__Libraries/StellaOps.Concelier.Testing/StellaOps.Concelier.Testing.csproj - APPLY |
|
||||
| 724 | AUDIT-0242-M | DONE | Revalidated 2026-01-07 | Guild | src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj - MAINT |
|
||||
| 725 | AUDIT-0242-T | DONE | Revalidated 2026-01-07 | Guild | src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj - TEST |
|
||||
| 726 | AUDIT-0242-A | TODO | Revalidated 2026-01-07 (open findings) | Guild | src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj - APPLY |
|
||||
| 726 | AUDIT-0242-A | DONE | Applied 2026-01-13; TimeProvider defaults, ASCII cleanup, federation tests | Guild | src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj - APPLY |
|
||||
| 727 | AUDIT-0243-M | DONE | Revalidated 2026-01-07 | Guild | src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/StellaOps.Concelier.WebService.Tests.csproj - MAINT |
|
||||
| 728 | AUDIT-0243-T | DONE | Revalidated 2026-01-07 | Guild | src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/StellaOps.Concelier.WebService.Tests.csproj - TEST |
|
||||
| 729 | AUDIT-0243-A | DONE | Waived (test project; revalidated 2026-01-07) | Guild | src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/StellaOps.Concelier.WebService.Tests.csproj - APPLY |
|
||||
@@ -5518,7 +5525,7 @@ Bulk task definitions (applies to every project row below):
|
||||
| 1158 | AUDIT-0386-A | DONE | Waived (test project; revalidated 2026-01-07) | Guild | src/__Libraries/__Tests/StellaOps.Metrics.Tests/StellaOps.Metrics.Tests.csproj - APPLY |
|
||||
| 1159 | AUDIT-0387-M | DONE | Revalidated 2026-01-07 | Guild | src/Router/__Libraries/StellaOps.Microservice/StellaOps.Microservice.csproj - MAINT |
|
||||
| 1160 | AUDIT-0387-T | DONE | Revalidated 2026-01-07 | Guild | src/Router/__Libraries/StellaOps.Microservice/StellaOps.Microservice.csproj - TEST |
|
||||
| 1161 | AUDIT-0387-A | TODO | Revalidated 2026-01-07 (open findings) | Guild | src/Router/__Libraries/StellaOps.Microservice/StellaOps.Microservice.csproj - APPLY |
|
||||
| 1161 | AUDIT-0387-A | DONE | Applied 2026-01-13; superseded by AUDIT-0598-A | Guild | src/Router/__Libraries/StellaOps.Microservice/StellaOps.Microservice.csproj - APPLY |
|
||||
| 1162 | AUDIT-0388-M | DONE | Revalidated 2026-01-07 | Guild | src/Router/__Libraries/StellaOps.Microservice.AspNetCore/StellaOps.Microservice.AspNetCore.csproj - MAINT |
|
||||
| 1163 | AUDIT-0388-T | DONE | Revalidated 2026-01-07 | Guild | src/Router/__Libraries/StellaOps.Microservice.AspNetCore/StellaOps.Microservice.AspNetCore.csproj - TEST |
|
||||
| 1164 | AUDIT-0388-A | TODO | Revalidated 2026-01-07 (open findings) | Guild | src/Router/__Libraries/StellaOps.Microservice.AspNetCore/StellaOps.Microservice.AspNetCore.csproj - APPLY |
|
||||
@@ -6226,10 +6233,10 @@ Bulk task definitions (applies to every project row below):
|
||||
| 1863 | AUDIT-0621-A | DONE | Waived (test project; revalidated 2026-01-08) | Guild | src/Scanner/__Tests/StellaOps.Scanner.WebService.Tests/StellaOps.Scanner.WebService.Tests.csproj - APPLY |
|
||||
| 1864 | AUDIT-0622-M | DONE | Revalidated 2026-01-08 | Guild | src/Scanner/StellaOps.Scanner.Worker/StellaOps.Scanner.Worker.csproj - MAINT |
|
||||
| 1865 | AUDIT-0622-T | DONE | Revalidated 2026-01-08 | Guild | src/Scanner/StellaOps.Scanner.Worker/StellaOps.Scanner.Worker.csproj - TEST |
|
||||
| 1866 | AUDIT-0622-A | TODO | Revalidated 2026-01-08 (open findings) | Guild | src/Scanner/StellaOps.Scanner.Worker/StellaOps.Scanner.Worker.csproj - APPLY |
|
||||
| 1866 | AUDIT-0622-A | DONE | Applied 2026-01-13 | Guild | src/Scanner/StellaOps.Scanner.Worker/StellaOps.Scanner.Worker.csproj - APPLY |
|
||||
| 1867 | AUDIT-0623-M | DONE | Revalidated 2026-01-08 | Guild | src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/StellaOps.Scanner.Worker.Tests.csproj - MAINT |
|
||||
| 1868 | AUDIT-0623-T | DONE | Revalidated 2026-01-08 | Guild | src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/StellaOps.Scanner.Worker.Tests.csproj - TEST |
|
||||
| 1869 | AUDIT-0623-A | DONE | Waived (test project; revalidated 2026-01-08) | Guild | src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/StellaOps.Scanner.Worker.Tests.csproj - APPLY |
|
||||
| 1869 | AUDIT-0623-A | DONE | Applied 2026-01-13 | Guild | src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/StellaOps.Scanner.Worker.Tests.csproj - APPLY |
|
||||
| 1870 | AUDIT-0624-M | DONE | Revalidated 2026-01-08 | Guild | src/__Tests/reachability/StellaOps.ScannerSignals.IntegrationTests/StellaOps.ScannerSignals.IntegrationTests.csproj - MAINT |
|
||||
| 1871 | AUDIT-0624-T | DONE | Revalidated 2026-01-08 | Guild | src/__Tests/reachability/StellaOps.ScannerSignals.IntegrationTests/StellaOps.ScannerSignals.IntegrationTests.csproj - TEST |
|
||||
| 1872 | AUDIT-0624-A | DONE | Waived (test project; revalidated 2026-01-08) | Guild | src/__Tests/reachability/StellaOps.ScannerSignals.IntegrationTests/StellaOps.ScannerSignals.IntegrationTests.csproj - APPLY |
|
||||
@@ -6546,13 +6553,13 @@ Bulk task definitions (applies to every project row below):
|
||||
| 2177 | AUDIT-0725-T | DONE | Waived (docs/template project) | Guild | docs/modules/router/samples/tests/Examples.Integration.Tests/Examples.Integration.Tests.csproj - TEST |
|
||||
| 2178 | AUDIT-0725-A | DONE | Waived (docs/template project) | Guild | docs/modules/router/samples/tests/Examples.Integration.Tests/Examples.Integration.Tests.csproj - APPLY |
|
||||
| 2179 | AUDIT-0726-M | DONE | Waived (docs/template project) | Guild | docs/dev/sdks/plugin-templates/StellaOps.Templates.csproj - MAINT |
|
||||
| 2180 | AUDIT-0726-T | DONE | Waived (docs/template project) | Guild | docs/dev/sdks/plugin-templates/StellaOps.Templates.csproj - TEST |
|
||||
| 2180 | AUDIT-0726-T | DONE | Waived 2026-01-13 (template package; content-only) | Guild | docs/dev/sdks/plugin-templates/StellaOps.Templates.csproj - TEST |
|
||||
| 2181 | AUDIT-0726-A | DONE | Waived (docs/template project) | Guild | docs/dev/sdks/plugin-templates/StellaOps.Templates.csproj - APPLY |
|
||||
| 2182 | AUDIT-0727-M | DONE | Waived (docs/template project) | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-connector/StellaOps.Plugin.MyConnector.csproj - MAINT |
|
||||
| 2183 | AUDIT-0727-T | DONE | Waived (docs/template project) | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-connector/StellaOps.Plugin.MyConnector.csproj - TEST |
|
||||
| 2183 | AUDIT-0727-T | DONE | Applied 2026-01-13; test scaffolding added | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-connector/StellaOps.Plugin.MyConnector.csproj - TEST |
|
||||
| 2184 | AUDIT-0727-A | DONE | Waived (docs/template project) | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-connector/StellaOps.Plugin.MyConnector.csproj - APPLY |
|
||||
| 2185 | AUDIT-0728-M | DONE | Waived (docs/template project) | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-scheduler/StellaOps.Plugin.MyJob.csproj - MAINT |
|
||||
| 2186 | AUDIT-0728-T | DONE | Waived (docs/template project) | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-scheduler/StellaOps.Plugin.MyJob.csproj - TEST |
|
||||
| 2186 | AUDIT-0728-T | DONE | Applied 2026-01-13; test scaffolding added | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-scheduler/StellaOps.Plugin.MyJob.csproj - TEST |
|
||||
| 2187 | AUDIT-0728-A | DONE | Waived (docs/template project) | Guild | docs/dev/sdks/plugin-templates/stellaops-plugin-scheduler/StellaOps.Plugin.MyJob.csproj - APPLY |
|
||||
| 2188 | AUDIT-0729-M | DONE | Revalidated 2026-01-07 | Guild | src/Attestor/__Tests/StellaOps.Attestor.Infrastructure.Tests/StellaOps.Attestor.Infrastructure.Tests.csproj - MAINT |
|
||||
| 2189 | AUDIT-0729-T | DONE | Revalidated 2026-01-07 | Guild | src/Attestor/__Tests/StellaOps.Attestor.Infrastructure.Tests/StellaOps.Attestor.Infrastructure.Tests.csproj - TEST |
|
||||
@@ -6980,6 +6987,7 @@ Bulk task definitions (applies to every project row below):
|
||||
## Execution Log
|
||||
| Date (UTC) | Update | Owner |
|
||||
| --- | --- | --- |
|
||||
| 2026-01-13 | Applied Concelier.WebService hotlist (AUDIT-0242-A/AUDIT-0417-A): TimeProvider timestamps, ASCII cleanup, federation tests. | Project Mgmt |
|
||||
| 2026-01-07 | Revalidated AUDIT-0774 (PolicySchemaExporter.Tests); added AGENTS/TASKS; updated audit report. | Codex |
|
||||
| 2026-01-07 | Revalidated AUDIT-0773 (PolicyDslValidator.Tests); added AGENTS/TASKS; updated audit report. | Codex |
|
||||
| 2026-01-07 | Revalidated AUDIT-0772 (NotifySmokeCheck.Tests); added AGENTS/TASKS; updated audit report. | Codex |
|
||||
|
||||
@@ -570,7 +570,8 @@
|
||||
- MAINT: AdvisoryTaskWorker uses Random.Shared for jitter in retry backoff; violates determinism rules and makes retries nondeterministic. `src/AdvisoryAI/StellaOps.AdvisoryAI.Worker/Services/AdvisoryTaskWorker.cs`
|
||||
- TEST: No tests for worker behavior (cache miss handling, retry loop, cancellation). `src/AdvisoryAI/StellaOps.AdvisoryAI.Worker/Services/AdvisoryTaskWorker.cs`
|
||||
- Applied changes (prior): added plan-cache aliasing on cache miss, added bounded backoff with jitter, and improved cancellation handling.
|
||||
- Disposition: revalidated 2026-01-06; apply recommendations remain open.
|
||||
- Applied changes (2026-01-14): replaced Random.Shared jitter with injected IAdvisoryJitterSource and added worker tests for cache hit/miss handling.
|
||||
- Disposition: applied 2026-01-14; apply recommendations closed.
|
||||
### src/AirGap/__Libraries/StellaOps.AirGap.Bundle/StellaOps.AirGap.Bundle.csproj
|
||||
- MAINT: BundleManifestSerializer uses UnsafeRelaxedJsonEscaping and camelCase before canonicalization; canonical outputs should use the shared RFC 8785 serializer without relaxed escaping. `src/AirGap/__Libraries/StellaOps.AirGap.Bundle/Serialization/BundleManifestSerializer.cs`
|
||||
- SECURITY: SnapshotManifestSigner hand-rolls DSSE PAE and formats lengths with culture-sensitive ToString; use the shared DsseHelper and invariant formatting to avoid spec drift. `src/AirGap/__Libraries/StellaOps.AirGap.Bundle/Services/SnapshotManifestSigner.cs`
|
||||
@@ -916,7 +917,8 @@
|
||||
- MAINT: Feature-gated controllers (AnchorsController, ProofsController, VerifyController) still expose routes but return 501 Not Implemented, leaving dead endpoints in the surface area. `src/Attestor/StellaOps.Attestor/StellaOps.Attestor.WebService/Controllers/AnchorsController.cs` `src/Attestor/StellaOps.Attestor/StellaOps.Attestor.WebService/Controllers/ProofsController.cs` `src/Attestor/StellaOps.Attestor/StellaOps.Attestor.WebService/Controllers/VerifyController.cs`
|
||||
- MAINT: Correlation ID middleware generates Guid.NewGuid directly instead of using an injected IGuidGenerator, reducing determinism and testability. `src/Attestor/StellaOps.Attestor/StellaOps.Attestor.WebService/AttestorWebServiceComposition.cs`
|
||||
- MAINT: VerdictController formats CreatedAt via ToString("O") without CultureInfo.InvariantCulture, which violates invariant formatting guidance for deterministic outputs. `src/Attestor/StellaOps.Attestor/StellaOps.Attestor.WebService/Controllers/VerdictController.cs`
|
||||
- Disposition: revalidated 2026-01-06 (apply reopened).
|
||||
- Applied changes: removed disabled controller routes via feature provider, standardized proof chain error responses on ProblemDetails, injected IGuidProvider for correlation IDs, resolved subject type/signature summaries, and updated tests for feature gating and verification summaries.
|
||||
- Disposition: applied 2026-01-13.
|
||||
### src/__Libraries/StellaOps.Audit.ReplayToken/StellaOps.Audit.ReplayToken.csproj
|
||||
- MAINT: ReplayToken.IsExpired/GetTimeToExpiration default to DateTimeOffset.UtcNow instead of a provided time source, violating deterministic time injection guidance. `src/__Libraries/StellaOps.Audit.ReplayToken/ReplayToken.cs`
|
||||
- MAINT: ReplayToken.Canonical and ReplayToken.Parse format/parse Unix seconds using the current culture (string interpolation + long.TryParse without InvariantCulture), risking locale-dependent or non-ASCII token strings. `src/__Libraries/StellaOps.Audit.ReplayToken/ReplayToken.cs`
|
||||
@@ -1995,7 +1997,7 @@
|
||||
- MAINT: Non-ASCII characters in comments violate ASCII-only guidance. src/Concelier/__Libraries/StellaOps.Concelier.Core/Events/AdvisoryDsseMetadataResolver.cs, src/Concelier/__Libraries/StellaOps.Concelier.Core/Linksets/AdvisoryLinksetUpdatedEvent.cs
|
||||
- TEST: Coverage exists for canonical merge decisions, canonical advisory service/cache behavior, job scheduler/coordinator flows, linkset determinism/normalization, observation query/aggregation, event log replay, noise prior service, and unknown state ledger.
|
||||
- TEST: Missing tests for deterministic ordering of credits/references/affected packages and consideredSources in CanonicalMerger output, replay cursor culture invariance, AdvisoryObservationUpdatedEvent relationship ordering, AdvisoryLinksetUpdatedEvent conflict ordering/ConflictsChanged behavior and provenance ordering, LinksetCorrelation conflict value stability, VendorRiskSignalExtractor KEV date parsing, AdvisoryLinksetQueryService cursor roundtrip/invalid formats, BundleCatalogService cursor parsing/sourceId ordering, and AdvisoryFieldChangeEmitter score formatting.
|
||||
- Disposition: revalidated 2026-01-06 (open findings)
|
||||
- Disposition: applied 2026-01-13; apply recommendations closed.
|
||||
### src/Concelier/__Tests/StellaOps.Concelier.Core.Tests/StellaOps.Concelier.Core.Tests.csproj
|
||||
- MAINT: IsTestProject is not set; discovery relies on defaults rather than explicit test metadata.
|
||||
- MAINT: Test project lacks explicit Microsoft.NET.Test.Sdk/xunit runner references; discovery depends on shared props/packages.
|
||||
@@ -2284,8 +2286,8 @@
|
||||
- MAINT: Non-ASCII box-drawing characters and an en dash appear in comments and OpenAPI metadata, violating ASCII-only output rules. `src/Concelier/StellaOps.Concelier.WebService/Diagnostics/ErrorCodes.cs` `src/Concelier/StellaOps.Concelier.WebService/Results/ConcelierProblemResultFactory.cs` `src/Concelier/StellaOps.Concelier.WebService/openapi/concelier-lnm.yaml`
|
||||
- TEST: Coverage exists in StellaOps.Concelier.WebService.Tests for health/readiness, options post-configure, canonical advisories, interest scoring, orchestrator/timeline endpoints, observations, cache/linkset, mirror exports, telemetry, and plugin loading.
|
||||
- TEST: Missing tests for federation endpoints (export/import/validate/preview/status/sites) and the FederationDisabled path.
|
||||
- Proposed changes (pending approval): thread TimeProvider through endpoint timestamp defaults; replace TimeProvider.System usage with injected provider; remove non-ASCII comment glyphs; add federation endpoint tests for enabled/disabled flows.
|
||||
- Disposition: revalidated 2026-01-07 (open findings)
|
||||
- Applied changes (2026-01-13): thread TimeProvider through endpoint timestamp defaults and guard mapping; remove non-ASCII comment glyphs; add federation endpoint tests for enabled/disabled flows.
|
||||
- Disposition: applied 2026-01-13; apply recommendations closed.
|
||||
### src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/StellaOps.Concelier.WebService.Tests.csproj
|
||||
- MAINT: IsTestProject is not set and explicit Microsoft.NET.Test.Sdk/xUnit references are absent; discovery relies on centralized props. `src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/StellaOps.Concelier.WebService.Tests.csproj`
|
||||
- MAINT: RunAnalyzers and CollectCoverage are disabled; analyzer and coverage feedback are reduced. `src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/StellaOps.Concelier.WebService.Tests.csproj`
|
||||
@@ -2976,7 +2978,7 @@
|
||||
- TEST: Coverage exists for append-only linkset store, observation store, provider store, attestation store, timeline event store, and migration/idempotency/determinism checks.
|
||||
- TEST: Missing tests for VEX delta repository CRUD/ordering, VEX statement repository CRUD/precedence, raw document canonicalization/inline vs blob paths, connector state serialization, and append-only checkpoint store behavior.
|
||||
- Proposed changes (pending approval): require explicit ID/timestamp inputs (or inject providers); validate tenant consistency in batch inserts; normalize created_at to DateTimeOffset UTC; make timeline event attribute JSON deterministic with logged parse failures; add tests for deltas/raw store/connector state/checkpoint store and statement ordering.
|
||||
- Disposition: pending implementation (non-test project; revalidated 2026-01-07; apply recommendations remain open).
|
||||
- Disposition: applied 2026-01-13.
|
||||
### src/Excititor/__Tests/StellaOps.Excititor.Persistence.Tests/StellaOps.Excititor.Persistence.Tests.csproj
|
||||
- MAINT: TreatWarningsAsErrors is not set in the project file; warning discipline is relaxed.
|
||||
- MAINT: Multiple tests use Guid.NewGuid/Random.Shared/DateTimeOffset.UtcNow in fixtures (VexQueryDeterminismTests, VexStatementIdempotencyTests, PostgresVexAttestationStoreTests, PostgresVexObservationStoreTests, PostgresVexTimelineEventStoreTests), reducing deterministic replay.
|
||||
@@ -3016,17 +3018,14 @@
|
||||
- TEST: Missing tests for ingest run/resume/reconcile endpoints, mirror endpoints, VEX raw endpoints, observation projection/list endpoints, linkset list endpoints, evidence chunk service/endpoint, status/resolve/risk feed endpoints, observability endpoints, and OpenAPI contract snapshots.
|
||||
- Disposition: waived (test project; revalidated 2026-01-07).
|
||||
### src/Excititor/StellaOps.Excititor.Worker/StellaOps.Excititor.Worker.csproj
|
||||
- MAINT: Program registers in-memory provider/claim stores after AddExcititorPersistence, which overrides any persistent implementations and can mask configuration errors (`src/Excititor/StellaOps.Excititor.Worker/Program.cs`).
|
||||
- MAINT: Program hardcodes plugin catalog fallback paths, but no metrics or health output for missing plugin directories (`src/Excititor/StellaOps.Excititor.Worker/Program.cs`).
|
||||
- MAINT: WorkerSignatureVerifier parses timestamp metadata with DateTimeOffset.TryParse without invariant culture; parsing is locale-sensitive and can accept ambiguous inputs (`src/Excititor/StellaOps.Excititor.Worker/Signature/WorkerSignatureVerifier.cs`).
|
||||
- MAINT: WorkerSignatureVerifier falls back to _timeProvider.GetUtcNow when signedAt metadata is missing; signature metadata becomes nondeterministic (`src/Excititor/StellaOps.Excititor.Worker/Signature/WorkerSignatureVerifier.cs`).
|
||||
- MAINT: VexWorkerOrchestratorClient fallback job context uses Guid.NewGuid; local job IDs vary run-to-run and make deterministic replay harder (`src/Excititor/StellaOps.Excititor.Worker/Orchestration/VexWorkerOrchestratorClient.cs`).
|
||||
- MAINT: VexWorkerOrchestratorClient.ParseCheckpoint uses DateTimeOffset.TryParse with default culture; prefer invariant/roundtrip handling for stable parsing (`src/Excititor/StellaOps.Excititor.Worker/Orchestration/VexWorkerOrchestratorClient.cs`).
|
||||
- MAINT: DefaultVexProviderRunner uses RandomNumberGenerator jitter for backoff; NextEligibleRun becomes nondeterministic and harder to test (`src/Excititor/StellaOps.Excititor.Worker/Scheduling/DefaultVexProviderRunner.cs`).
|
||||
- TEST: Coverage exists for worker options validation, tenant authority validation/client factory, worker signature verification, retry policy, orchestrator client behavior, provider runner behavior, end-to-end ingest jobs, and OTel correlation.
|
||||
- TEST: Missing tests for consensus refresh scheduler (VexConsensusRefreshService), hosted service scheduling behavior, plugin catalog fallback path handling, and signature metadata culture parsing edge cases.
|
||||
- Proposed changes (pending approval): register in-memory stores via TryAdd or guard with config; emit health/telemetry for missing plugin directories; parse timestamps with invariant culture; require explicit signature timestamps or use document timestamps; inject a deterministic run-id provider for local jobs; inject jitter provider for backoff; add tests for consensus refresh, hosted service scheduling, plugin loading fallback, and timestamp parsing.
|
||||
- Disposition: pending implementation (non-test project; revalidated 2026-01-07; apply recommendations remain open).
|
||||
- MAINT: Program uses TryAdd for in-memory provider/claim stores to avoid overriding persistence (`src/Excititor/StellaOps.Excititor.Worker/Program.cs`).
|
||||
- MAINT: Plugin catalog loader emits diagnostics for missing plugin directories and fallback usage (`src/Excititor/StellaOps.Excititor.Worker/Plugins/VexWorkerPluginCatalogDiagnostics.cs` `src/Excititor/StellaOps.Excititor.Worker/Plugins/VexWorkerPluginCatalogLoader.cs`).
|
||||
- MAINT: WorkerSignatureVerifier parses timestamp metadata with invariant culture and falls back to document timestamps when missing (`src/Excititor/StellaOps.Excititor.Worker/Signature/WorkerSignatureVerifier.cs`).
|
||||
- MAINT: VexWorkerOrchestratorClient uses injected GUID generation for local job IDs (`src/Excititor/StellaOps.Excititor.Worker/Orchestration/VexWorkerOrchestratorClient.cs`).
|
||||
- MAINT: VexWorkerOrchestratorClient.ParseCheckpoint uses invariant culture for roundtrip parsing (`src/Excititor/StellaOps.Excititor.Worker/Orchestration/VexWorkerOrchestratorClient.cs`).
|
||||
- MAINT: DefaultVexProviderRunner uses deterministic backoff jitter keyed by connector ID (`src/Excititor/StellaOps.Excititor.Worker/Scheduling/DefaultVexProviderRunner.cs`).
|
||||
- TEST: Coverage exists for worker options validation, tenant authority validation/client factory, worker signature verification, retry policy, orchestrator client behavior, provider runner behavior, end-to-end ingest jobs, OTel correlation, consensus refresh scheduling, hosted service scheduling behavior, plugin catalog fallback handling, and signature metadata culture parsing.
|
||||
- Disposition: applied 2026-01-13; apply recommendations closed.
|
||||
### src/Excititor/__Tests/StellaOps.Excititor.Worker.Tests/StellaOps.Excititor.Worker.Tests.csproj
|
||||
- MAINT: TreatWarningsAsErrors is not set in the project file; warning discipline is relaxed.
|
||||
- MAINT: Multiple tests use Guid.NewGuid/DateTimeOffset.UtcNow for job context, document timestamps, or database names (DefaultVexProviderRunnerIntegrationTests.cs, EndToEndIngestJobTests.cs, VexWorkerOrchestratorClientTests.cs, WorkerSignatureVerifierTests.cs), reducing deterministic replay.
|
||||
@@ -3331,7 +3330,7 @@
|
||||
- QUALITY: Build artifacts are checked in under bin/obj. `src/__Libraries/StellaOps.Infrastructure.EfCore/bin` `src/__Libraries/StellaOps.Infrastructure.EfCore/obj`
|
||||
- TEST: No tests for tenant session configuration, schema wiring, or tenant accessors. `src/__Libraries/StellaOps.Infrastructure.EfCore/Extensions/DbContextServiceExtensions.cs` `src/__Libraries/StellaOps.Infrastructure.EfCore/Interceptors/TenantConnectionInterceptor.cs` `src/__Libraries/StellaOps.Infrastructure.EfCore/Tenancy/AsyncLocalTenantContextAccessor.cs`
|
||||
- Proposed changes (pending approval): gate EnableDetailedErrors behind environment/options; validate schema names (or quote identifiers) before building search_path; use a sync-safe session configuration path (or avoid blocking on async) and propagate cancellation; refactor shared DbContext configuration into a single helper; add tests for tenant session setup, interceptor behavior, and AsyncLocal scope behavior in a new infrastructure test project.
|
||||
- Disposition: pending implementation (non-test project; revalidated 2026-01-08; apply recommendations remain open).
|
||||
- Disposition: applied 2026-01-13 (bin/obj cleanup still pending).
|
||||
### src/__Libraries/StellaOps.Infrastructure.Postgres/StellaOps.Infrastructure.Postgres.csproj
|
||||
- MAINT: PostgresOptions are configured without validation or ValidateOnStart; required ConnectionString and option bounds are not enforced. `src/__Libraries/StellaOps.Infrastructure.Postgres/ServiceCollectionExtensions.cs` `src/__Libraries/StellaOps.Infrastructure.Postgres/Options/PostgresOptions.cs`
|
||||
- MAINT: ConnectionIdleLifetimeSeconds is never applied to the Npgsql connection string, so configured values are ignored. `src/__Libraries/StellaOps.Infrastructure.Postgres/Connections/DataSourceBase.cs` `src/__Libraries/StellaOps.Infrastructure.Postgres/Options/PostgresOptions.cs`
|
||||
@@ -4176,8 +4175,8 @@
|
||||
- MAINT/SECURITY: MinimalProofExporter and ProvcacheOciAttestationBuilder serialize signed payloads with JsonSerializer options instead of RFC 8785 canonical JSON, risking signature drift across implementations. `src/__Libraries/StellaOps.Provcache/Export/MinimalProofExporter.cs` `src/__Libraries/StellaOps.Provcache/Oci/ProvcacheOciAttestationBuilder.cs`
|
||||
- QUALITY: Build artifacts are checked in under bin/obj. `src/__Libraries/StellaOps.Provcache/bin` `src/__Libraries/StellaOps.Provcache/obj`
|
||||
- TEST: No tests cover HTTP fetcher allowlists/timeouts, canonicalized bundle/attestation signing, or signature verification failure paths. `src/__Libraries/__Tests/StellaOps.Provcache.Tests/LazyFetchTests.cs` `src/__Libraries/__Tests/StellaOps.Provcache.Tests/MinimalProofExporterTests.cs`
|
||||
- Proposed changes (pending approval): use IHttpClientFactory with timeouts/allowlists, inject ID/time providers into event factories, propagate cancellation for shutdown drains, enforce invariant formatting and ValidateOnStart for options, switch signing/attestation payloads to RFC 8785 canonical JSON, implement real signature verification, add coverage for lazy fetcher safeguards and bundle signing failures, and remove bin/obj artifacts.
|
||||
- Disposition: pending implementation (non-test project; revalidated 2026-01-08; apply recommendations remain open).
|
||||
- Applied changes (2026-01-13): switched HttpChunkFetcher to IHttpClientFactory with allowlist/scheme/timeout enforcement, injected TimeProvider/IGuidProvider for events, propagated shutdown cancellation, enforced invariant formatting and ValidateOnStart, moved bundle/attestation signing to CanonJson with real HMAC verification, and added tests for lazy fetcher guards/signature failure paths.
|
||||
- Disposition: apply completed 2026-01-13.
|
||||
### src/__Libraries/StellaOps.Provcache.Api/StellaOps.Provcache.Api.csproj
|
||||
- SECURITY: Endpoint error handlers return ex.Message to callers, leaking internal details. `src/__Libraries/StellaOps.Provcache.Api/ProvcacheEndpointExtensions.cs`
|
||||
- MAINT: Proof verification computes Merkle roots from unsorted chunk lists, so ordering can invalidate proofs or hide corruption; sort by ChunkIndex before hashing. `src/__Libraries/StellaOps.Provcache.Api/ProvcacheEndpointExtensions.cs`
|
||||
@@ -4185,31 +4184,31 @@
|
||||
- QUALITY: Input manifest builds placeholder hashes using fixed VeriKey slicing without length checks; short or malformed VeriKeys can throw. `src/__Libraries/StellaOps.Provcache.Api/ProvcacheEndpointExtensions.cs`
|
||||
- QUALITY: Build artifacts are checked in under bin/obj. `src/__Libraries/StellaOps.Provcache.Api/bin` `src/__Libraries/StellaOps.Provcache.Api/obj`
|
||||
- TEST: No tests cover out-of-order chunk lists, error detail redaction, or manifest hash placeholder behavior. `src/__Libraries/__Tests/StellaOps.Provcache.Tests/EvidenceApiTests.cs`
|
||||
- Proposed changes (pending approval): sanitize exception details, enforce chunk ordering, validate offsets, and add tests for ordering and error responses.
|
||||
- Disposition: pending implementation (non-test project; revalidated 2026-01-08; apply recommendations remain open).
|
||||
- Applied changes (2026-01-13): redacted error details, enforced chunk ordering and pagination validation, guarded placeholder hashes, and added tests for ordering/placeholder/error redaction.
|
||||
- Disposition: apply completed 2026-01-13.
|
||||
### src/__Libraries/StellaOps.Provcache.Postgres/StellaOps.Provcache.Postgres.csproj
|
||||
- MAINT: PostgresProvcacheRepository serializes replay seeds with JsonNamingPolicy.CamelCase, which can diverge from canonical JSON expectations for hashes. `src/__Libraries/StellaOps.Provcache.Postgres/PostgresProvcacheRepository.cs`
|
||||
- MAINT: Evidence chunk manifest generation uses TimeProvider.System when no provider is supplied, making manifests nondeterministic in tests. `src/__Libraries/StellaOps.Provcache.Postgres/PostgresEvidenceChunkRepository.cs`
|
||||
- QUALITY: Build artifacts are checked in under bin/obj. `src/__Libraries/StellaOps.Provcache.Postgres/bin` `src/__Libraries/StellaOps.Provcache.Postgres/obj`
|
||||
- TEST: No tests cover Postgres repository behavior or DbContext mappings (provcache items, evidence chunks, revocations). `src/__Libraries/StellaOps.Provcache.Postgres/PostgresProvcacheRepository.cs` `src/__Libraries/StellaOps.Provcache.Postgres/PostgresEvidenceChunkRepository.cs` `src/__Libraries/StellaOps.Provcache.Postgres/ProvcacheDbContext.cs`
|
||||
- Proposed changes (pending approval): use canonical JSON serializer for stored replay seeds, inject deterministic TimeProvider in tests, and add repository/DbContext mapping tests.
|
||||
- Disposition: pending implementation (non-test project; revalidated 2026-01-08; apply recommendations remain open).
|
||||
- Proposed changes (pending approval): add repository/DbContext tests with deterministic fixtures and ordering checks.
|
||||
- Disposition: pending implementation (non-test project; revalidated 2026-01-07; apply recommendations remain open).
|
||||
- Applied changes (2026-01-13): replay seed serialization now uses CanonJson for deterministic hashes.
|
||||
- Remaining changes: inject deterministic TimeProvider in Postgres evidence tests and add repository/DbContext mapping coverage (tracked under AUDIT-TESTGAP-CORELIB-0001).
|
||||
- Disposition: apply completed 2026-01-13; remaining test gaps tracked.
|
||||
### src/__Libraries/__Tests/StellaOps.Provcache.Tests/StellaOps.Provcache.Tests.csproj
|
||||
- MAINT: Test project does not enable warnings-as-errors. `src/__Libraries/__Tests/StellaOps.Provcache.Tests/StellaOps.Provcache.Tests.csproj`
|
||||
- MAINT: Tests use Random.Shared, Guid.NewGuid, and DateTimeOffset.UtcNow for fixtures and assertions, making results nondeterministic. `src/__Libraries/__Tests/StellaOps.Provcache.Tests/EvidenceChunkerTests.cs` `src/__Libraries/__Tests/StellaOps.Provcache.Tests/EvidenceApiTests.cs` `src/__Libraries/__Tests/StellaOps.Provcache.Tests/StorageIntegrationTests.cs`
|
||||
- MAINT: Tests create temp directories with Guid.NewGuid without deterministic cleanup. `src/__Libraries/__Tests/StellaOps.Provcache.Tests/LazyFetchTests.cs`
|
||||
- Proposed changes (optional): enable warnings-as-errors, use deterministic seeds/timestamps, and centralize temp path helpers.
|
||||
- Disposition: waived (test project; revalidated 2026-01-07).
|
||||
- Applied changes (2026-01-13): enabled warnings-as-errors, tagged API/storage tests as Integration, replaced nondeterministic fixtures with FixedTimeProvider/DeterministicRandom, and centralized deterministic temp path helpers.
|
||||
- Disposition: apply completed 2026-01-13 (test project).
|
||||
|
||||
### src/__Libraries/StellaOps.Provcache.Valkey/StellaOps.Provcache.Valkey.csproj
|
||||
- MAINT: InvalidateByPattern uses `server.Keys`, which performs a full keyspace scan and can block or time out on large caches; it also targets only the first endpoint, which is unsafe for clustered or replica setups. `src/__Libraries/StellaOps.Provcache.Valkey/ValkeyProvcacheStore.cs`
|
||||
- MAINT: CancellationToken parameters are accepted but not honored by Redis calls, so long-running operations cannot be canceled. `src/__Libraries/StellaOps.Provcache.Valkey/ValkeyProvcacheStore.cs`
|
||||
- QUALITY: Build artifacts are checked in under bin/obj. `src/__Libraries/StellaOps.Provcache.Valkey/bin` `src/__Libraries/StellaOps.Provcache.Valkey/obj`
|
||||
- TEST: No tests cover valkey read/write behavior, sliding expiration, or invalidation flows. `src/__Libraries/StellaOps.Provcache.Valkey/ValkeyProvcacheStore.cs`
|
||||
- Proposed changes (pending approval): replace KEYS with SCAN/paged invalidation and endpoint selection, add timeouts or cancellation strategy, and add valkey store tests.
|
||||
- Disposition: pending implementation (non-test project; revalidated 2026-01-08; apply recommendations remain open).
|
||||
- Applied changes (2026-01-13): replaced KEYS with SCAN-based invalidation across endpoints and propagated cancellation through Valkey operations.
|
||||
- Remaining changes: add valkey store tests (tracked under AUDIT-TESTGAP-CORELIB-0001).
|
||||
- Disposition: apply completed 2026-01-13; remaining test gaps tracked.
|
||||
### src/__Libraries/StellaOps.Provenance/StellaOps.Provenance.csproj
|
||||
- MAINT: ProjectReference to StellaOps.Concelier.Models is unused in the library, increasing coupling without usage. `src/__Libraries/StellaOps.Provenance/StellaOps.Provenance.csproj`
|
||||
- MAINT: ProvenanceJsonParser parses numeric fields with long.TryParse without invariant culture, so locale-specific digits or separators can break parsing. `src/__Libraries/StellaOps.Provenance/ProvenanceJsonParser.cs`
|
||||
@@ -4825,7 +4824,7 @@
|
||||
- QUALITY: Confidence mapping is duplicated with different thresholds; filtering can diverge from emitted confidence. `src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Secrets/SecretsAnalyzer.cs` `src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Secrets/Evidence/SecretLeakEvidence.cs`
|
||||
- QUALITY: Custom glob matching for include/exclude patterns is partial and OS-sensitive; patterns like `**/node_modules/**` and file patterns can mis-match. `src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Secrets/SecretsAnalyzer.cs` `src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Secrets/Rules/SecretRule.cs`
|
||||
- TEST: No coverage for SecretsAnalyzerHost startup/verification paths, AnalyzeAsync file traversal/exclusions/size limits, or analysis-store integration. `src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Secrets/SecretsAnalyzerHost.cs` `src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Secrets/SecretsAnalyzer.cs`
|
||||
- Disposition: revalidated 2026-01-07; apply recommendations remain open.
|
||||
- Disposition: applied 2026-01-13; TimeProvider retry-after, explicit timestamps, ASCII truncation, HttpClient injection, and tests updated.
|
||||
### src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Secrets.Tests/StellaOps.Scanner.Analyzers.Secrets.Tests.csproj
|
||||
- MAINT: Tests use Guid.NewGuid for temp directories and DateTimeOffset.UtcNow for ruleset timestamps, making runs nondeterministic. `src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Secrets.Tests/RulesetLoaderTests.cs` `src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Secrets.Tests/Bundles/BundleBuilderTests.cs` `src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Secrets.Tests/Bundles/BundleVerifierTests.cs` `src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Secrets.Tests/Bundles/BundleSignerTests.cs` `src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Secrets.Tests/SecretRulesetTests.cs`
|
||||
- TEST: No tests exercise SecretsAnalyzerHost startup/verification behavior or AnalyzeAsync file enumeration/exclusion handling. `src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Secrets/SecretsAnalyzerHost.cs` `src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Secrets/SecretsAnalyzer.cs`
|
||||
@@ -5034,7 +5033,7 @@
|
||||
- QUALITY: Docker reference parsing drops registry ports and can mis-handle `registry:5000/repo` by treating the port as a tag; BuildFullReference uses Uri.Host so ports are lost. `src/Scanner/__Libraries/StellaOps.Scanner.Sources/Handlers/Docker/DockerSourceHandler.cs`
|
||||
- QUALITY: GitConnectionTester returns success for SSH configurations without validating connectivity, yielding false positives. `src/Scanner/__Libraries/StellaOps.Scanner.Sources/ConnectionTesters/GitConnectionTester.cs`
|
||||
- TEST: Coverage is limited to config validation and domain models; handlers, connection testers, trigger dispatch/scheduling, and persistence are untested. `src/Scanner/__Tests/StellaOps.Scanner.Sources.Tests/Configuration/SourceConfigValidatorTests.cs` `src/Scanner/__Tests/StellaOps.Scanner.Sources.Tests/Domain/SbomSourceTests.cs` `src/Scanner/__Tests/StellaOps.Scanner.Sources.Tests/Domain/SbomSourceRunTests.cs`
|
||||
- Disposition: revalidated 2026-01-07; apply recommendations remain open.
|
||||
- Disposition: applied 2026-01-13; HttpClientFactory fixtures, TimeProvider request timestamps, ASCII comments, deterministic random, Task.Run removal, sync-over-async removal, tests added.
|
||||
### src/Scanner/__Tests/StellaOps.Scanner.Sources.Tests/StellaOps.Scanner.Sources.Tests.csproj
|
||||
- MAINT: TreatWarningsAsErrors is not set for the test project. `src/Scanner/__Tests/StellaOps.Scanner.Sources.Tests/StellaOps.Scanner.Sources.Tests.csproj`
|
||||
- MAINT: Tests use Guid.NewGuid and DateTimeOffset.Parse without InvariantCulture, making runs nondeterministic. `src/Scanner/__Tests/StellaOps.Scanner.Sources.Tests/Domain/SbomSourceRunTests.cs`
|
||||
@@ -5144,12 +5143,12 @@
|
||||
- MAINT: DeterministicRandomProvider falls back to Random.Shared when no seed is configured. `src/Scanner/StellaOps.Scanner.Worker/Determinism/DeterministicRandomProvider.cs`
|
||||
- QUALITY: Non-ASCII glyphs appear in strings/comments. `src/Scanner/StellaOps.Scanner.Worker/Determinism/Calculators/PolicyFidelityCalculator.cs` `src/Scanner/StellaOps.Scanner.Worker/Orchestration/PoEOrchestrator.cs` `src/Scanner/StellaOps.Scanner.Worker/Processing/BinaryFindingMapper.cs` `src/Scanner/StellaOps.Scanner.Worker/Processing/BinaryLookupStageExecutor.cs`
|
||||
- TEST: Coverage review continues in AUDIT-0623 (Scanner.Worker.Tests).
|
||||
- Disposition: revalidated 2026-01-08; apply recommendations remain open.
|
||||
- Disposition: applied 2026-01-13; apply recommendations closed.
|
||||
### src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/StellaOps.Scanner.Worker.Tests.csproj
|
||||
- MAINT: TreatWarningsAsErrors is not set in the test project. `src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/StellaOps.Scanner.Worker.Tests.csproj`
|
||||
- MAINT: Tests use Guid.NewGuid, DateTimeOffset.UtcNow, Random.Shared, TimeProvider.System, and CancellationToken.None; nondeterministic. `src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/CompositeScanAnalyzerDispatcherTests.cs` `src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/EntryTraceExecutionServiceTests.cs` `src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/PoE/PoEGenerationStageExecutorTests.cs`
|
||||
- QUALITY: Non-ASCII glyphs appear in comments and expected strings. `src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/Integration/WorkerEndToEndJobTests.cs` `src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/Determinism/PolicyFidelityCalculatorTests.cs`
|
||||
- Disposition: waived (test project; revalidated 2026-01-08).
|
||||
- Disposition: applied 2026-01-13; determinism fixes and warnings set.
|
||||
### src/__Tests/reachability/StellaOps.ScannerSignals.IntegrationTests/StellaOps.ScannerSignals.IntegrationTests.csproj
|
||||
- MAINT: TreatWarningsAsErrors is not set in the test project. `src/__Tests/reachability/StellaOps.ScannerSignals.IntegrationTests/StellaOps.ScannerSignals.IntegrationTests.csproj`
|
||||
- MAINT: Tests use CancellationToken.None; cancellation handling is not exercised. `src/__Tests/reachability/StellaOps.ScannerSignals.IntegrationTests/ScannerToSignalsReachabilityTests.cs`
|
||||
@@ -5227,7 +5226,7 @@
|
||||
- QUALITY: ReachabilityFactDigestCalculator hashes JsonSerializerDefaults.Web output instead of canonical JSON; use the shared canonical serializer for digest inputs. `src/Signals/StellaOps.Signals/Services/ReachabilityFactDigestCalculator.cs`
|
||||
- QUALITY: RuntimeSignalNormalizer uses DateTimeOffset.UtcNow for recency and emits non-ASCII glyphs in explanations; use TimeProvider and ASCII-only output. `src/Signals/StellaOps.Signals/EvidenceWeightedScore/Normalizers/RuntimeSignalNormalizer.cs`
|
||||
- QUALITY: Non-ASCII glyphs appear in comments and output strings. `src/Signals/StellaOps.Signals/EvidenceWeightedScore/EvidenceWeightPolicy.cs` `src/Signals/StellaOps.Signals/EvidenceWeightedScore/Normalizers/SourceTrustNormalizer.cs` `src/Signals/StellaOps.Signals/EvidenceWeightedScore/Normalizers/MitigationNormalizer.cs` `src/Signals/StellaOps.Signals/Services/UnknownsScoringService.cs`
|
||||
- Disposition: revalidated 2026-01-08; apply recommendations remain open.
|
||||
- Disposition: applied 2026-01-13; apply recommendations closed.
|
||||
### src/__Libraries/StellaOps.Signals.Contracts/StellaOps.Signals.Contracts.csproj
|
||||
- MAINT: SignalEnvelope.Value uses object, which weakens type safety and can complicate cross-module serialization; prefer a typed envelope or JsonElement plus explicit type metadata. `src/__Libraries/StellaOps.Signals.Contracts/Models/SignalEnvelope.cs`
|
||||
- QUALITY: SignalType enum relies on implicit numeric values; if serialized as numbers, adding/reordering values risks breaking compatibility. `src/__Libraries/StellaOps.Signals.Contracts/Models/SignalType.cs`
|
||||
@@ -5820,7 +5819,7 @@
|
||||
- QUALITY: PostgresConsensusProjectionStoreProxy reads timestamptz with GetDateTime instead of GetFieldValue<DateTimeOffset>, losing offset accuracy. `src/VexLens/StellaOps.VexLens/Storage/PostgresConsensusProjectionStoreProxy.cs`
|
||||
- TEST: Coverage exists for determinism/pipeline, proof builder, propagation, and golden corpus regression runs, but no tests cover rationale caching, dual-write discrepancy handling, or Postgres proxy mappings. `src/VexLens/StellaOps.VexLens/__Tests/StellaOps.VexLens.Tests/E2E/VexLensPipelineDeterminismTests.cs` `src/VexLens/StellaOps.VexLens/__Tests/StellaOps.VexLens.Tests/Proof/VexProofBuilderTests.cs` `src/VexLens/StellaOps.VexLens/__Tests/StellaOps.VexLens.Tests/GoldenCorpus/GoldenCorpusTests.cs`
|
||||
- Proposed changes (pending approval): inject TimeProvider/IGuidProvider into rationale + test harnesses, use InvariantCulture parsing, honor cancellation in dual-write checks, and switch timestamptz reads to DateTimeOffset.
|
||||
- Disposition: pending implementation (non-test project; revalidated 2026-01-07; apply recommendations remain open).
|
||||
- Disposition: applied 2026-01-13; apply recommendations closed.
|
||||
### src/VexLens/StellaOps.VexLens/StellaOps.VexLens.Core/StellaOps.VexLens.Core.csproj
|
||||
- SECURITY: SignatureVerifier does not verify signatures cryptographically; it validates structure and returns Valid=true for DSSE/JWS/Ed25519/ECDSA. `src/VexLens/StellaOps.VexLens/StellaOps.VexLens.Core/Signature/SignatureVerifier.cs`
|
||||
- MAINT: DSSE PAE is reimplemented locally (with culture-dependent length formatting) instead of using the shared DSSE helper. `src/VexLens/StellaOps.VexLens/StellaOps.VexLens.Core/Signature/SignatureVerifier.cs`
|
||||
@@ -5914,7 +5913,8 @@
|
||||
- MAINT: CLI apps invoke command handlers with CancellationToken.None, preventing cancellation from propagating. `src/__Libraries/StellaOps.Policy.Tools/PolicyDslValidatorApp.cs` `src/__Libraries/StellaOps.Policy.Tools/PolicySchemaExporterApp.cs` `src/__Libraries/StellaOps.Policy.Tools/PolicySimulationSmokeApp.cs`
|
||||
- QUALITY: Build artifacts are checked in under bin/obj. `src/__Libraries/StellaOps.Policy.Tools/bin` `src/__Libraries/StellaOps.Policy.Tools/obj`
|
||||
- TEST: Existing tool tests do not cover schema output line endings or invalid severity/status parsing. `src/Tools/__Tests/PolicySchemaExporter.Tests` `src/Tools/__Tests/PolicySimulationSmoke.Tests`
|
||||
- Disposition: revalidated 2026-01-08; apply recommendations remain open.
|
||||
- Applied changes: schema export now appends LF, simulation defaults to fixed time with deterministic summary output ordering, severity/status parsing reports scenario-specific failures, CLI apps propagate cancellation, and new Policy.Tools tests cover line endings, parsing failures, and summary ordering. Bin/obj entries are not tracked in git.
|
||||
- Disposition: applied 2026-01-14.
|
||||
### src/__Libraries/__Tests/StellaOps.Auth.Security.Tests/StellaOps.Auth.Security.Tests.csproj
|
||||
- MAINT: TreatWarningsAsErrors is not set in the test project. `src/__Libraries/__Tests/StellaOps.Auth.Security.Tests/StellaOps.Auth.Security.Tests.csproj`
|
||||
- MAINT: Tests generate random keys and JWT IDs via ECDsa.Create and Guid.NewGuid, making runs nondeterministic. `src/__Libraries/__Tests/StellaOps.Auth.Security.Tests/DpopProofValidatorTests.cs`
|
||||
@@ -6163,7 +6163,7 @@
|
||||
|
||||
### src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.GoldenSet/StellaOps.BinaryIndex.GoldenSet.csproj
|
||||
- QUALITY: Environment.NewLine introduces OS-specific output; prefer \\n. `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.GoldenSet/Authoring/GoldenSetReviewService.cs`
|
||||
- Disposition: revalidated 2026-01-12; apply recommendations remain open.
|
||||
- Disposition: applied 2026-01-13.
|
||||
|
||||
### src/BinaryIndex/__Tests/StellaOps.BinaryIndex.Analysis.Tests/StellaOps.BinaryIndex.Analysis.Tests.csproj
|
||||
- MAINT: Uses DateTime.UtcNow/DateTimeOffset.UtcNow/Guid.NewGuid/Random.Shared; inject TimeProvider/IGuidProvider and deterministic random sources. `src/BinaryIndex/__Tests/StellaOps.BinaryIndex.Analysis.Tests/Integration/GoldenSetAnalysisPipelineIntegrationTests.cs`
|
||||
@@ -7858,18 +7858,20 @@
|
||||
- QUALITY: No quality patterns detected in automated scan.
|
||||
|
||||
### src/AdvisoryAI/StellaOps.AdvisoryAI.Plugin.Unified/StellaOps.AdvisoryAI.Plugin.Unified.csproj
|
||||
- TEST: No test project ProjectReference found; coverage gap likely.
|
||||
- TEST: Covered by 1 test project(s): `src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj`.
|
||||
- MAINT: No maintainability issues detected in automated scan.
|
||||
- SECURITY: No high-risk patterns detected in automated scan.
|
||||
- REUSE: No internal ProjectReference usage found; verify intended packaging or consolidation.
|
||||
- QUALITY: No quality patterns detected in automated scan.
|
||||
- Applied changes (2026-01-14): added adapter and factory coverage in AdvisoryAI.Tests.
|
||||
|
||||
### src/AdvisoryAI/StellaOps.AdvisoryAI.Scm.Plugin.Unified/StellaOps.AdvisoryAI.Scm.Plugin.Unified.csproj
|
||||
- TEST: No test project ProjectReference found; coverage gap likely.
|
||||
- TEST: Covered by 1 test project(s): `src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj`.
|
||||
- MAINT: No maintainability issues detected in automated scan.
|
||||
- SECURITY: No high-risk patterns detected in automated scan.
|
||||
- REUSE: No internal ProjectReference usage found; verify intended packaging or consolidation.
|
||||
- QUALITY: No quality patterns detected in automated scan.
|
||||
- Applied changes (2026-01-14): added connector adapter and factory coverage in AdvisoryAI.Tests.
|
||||
|
||||
### src/AdvisoryAI/StellaOps.AdvisoryAI.WebService/StellaOps.AdvisoryAI.WebService.csproj
|
||||
- TEST: Covered by 1 test project(s): `src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj`.
|
||||
@@ -7879,11 +7881,12 @@
|
||||
- QUALITY: No quality patterns detected in automated scan.
|
||||
|
||||
### src/AdvisoryAI/StellaOps.AdvisoryAI.Worker/StellaOps.AdvisoryAI.Worker.csproj
|
||||
- TEST: No test project ProjectReference found; coverage gap likely.
|
||||
- MAINT: Non-deterministic time or random usage; inject TimeProvider/IGuidProvider and deterministic random sources. `src/AdvisoryAI/StellaOps.AdvisoryAI.Worker/Services/AdvisoryTaskWorker.cs`
|
||||
- TEST: Covered by 1 test project(s): `src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj`.
|
||||
- MAINT: Resolved - jitter source injected for retry backoff; Random.Shared removed from AdvisoryTaskWorker.
|
||||
- SECURITY: No high-risk patterns detected in automated scan.
|
||||
- REUSE: No internal ProjectReference usage found; verify intended packaging or consolidation.
|
||||
- QUALITY: No quality patterns detected in automated scan.
|
||||
- Applied changes (2026-01-14): added worker cache hit/miss tests with deterministic jitter source.
|
||||
|
||||
### src/AdvisoryAI/StellaOps.AdvisoryAI/StellaOps.AdvisoryAI.csproj
|
||||
- TEST: Covered by 1 test project(s): `src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj`.
|
||||
@@ -9811,8 +9814,6 @@
|
||||
|
||||
### src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj
|
||||
- TEST: Covered by 1 test project(s): `src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/StellaOps.Concelier.WebService.Tests.csproj`.
|
||||
- MAINT: Non-deterministic time or random usage; inject TimeProvider/IGuidProvider and deterministic random sources. `src/Concelier/StellaOps.Concelier.WebService/Program.cs` `src/Concelier/StellaOps.Concelier.WebService/Extensions/InterestScoreEndpointExtensions.cs` `src/Concelier/StellaOps.Concelier.WebService/Extensions/FederationEndpointExtensions.cs`
|
||||
- MAINT: CancellationToken.None used; propagate cancellation. `src/Concelier/StellaOps.Concelier.WebService/Program.cs`
|
||||
- MAINT: Sync-over-async detected (.Result/.Wait/GetResult); use await. `src/Concelier/StellaOps.Concelier.WebService/Services/MessagingAdvisoryChunkCache.cs` `src/Concelier/StellaOps.Concelier.WebService/Services/AdvisoryAiTelemetry.cs` `src/Concelier/StellaOps.Concelier.WebService/Program.cs`
|
||||
- SECURITY: No high-risk patterns detected in automated scan.
|
||||
- REUSE: No production references; referenced by 1 non-production project(s): `src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/StellaOps.Concelier.WebService.Tests.csproj`.
|
||||
@@ -10269,10 +10270,7 @@
|
||||
|
||||
### src/Excititor/StellaOps.Excititor.Worker/StellaOps.Excititor.Worker.csproj
|
||||
- TEST: Covered by 1 test project(s): `src/Excititor/__Tests/StellaOps.Excititor.Worker.Tests/StellaOps.Excititor.Worker.Tests.csproj`.
|
||||
- MAINT: Non-deterministic time or random usage; inject TimeProvider/IGuidProvider and deterministic random sources. `src/Excititor/StellaOps.Excititor.Worker/Orchestration/VexWorkerOrchestratorClient.cs`
|
||||
- MAINT: CancellationToken.None used; propagate cancellation. `src/Excititor/StellaOps.Excititor.Worker/Scheduling/DefaultVexProviderRunner.cs`
|
||||
- MAINT: Direct HttpClient construction; use IHttpClientFactory. `src/Excititor/StellaOps.Excititor.Worker/Auth/TenantAuthorityClientFactory.cs`
|
||||
- MAINT: Sync-over-async detected (.Result/.Wait/GetResult); use await. `src/Excititor/StellaOps.Excititor.Worker/Signature/WorkerSignatureVerifier.cs`
|
||||
- MAINT: No maintainability issues detected in automated scan.
|
||||
- SECURITY: No high-risk patterns detected in automated scan.
|
||||
- REUSE: No production references; referenced by 1 non-production project(s): `src/Excititor/__Tests/StellaOps.Excititor.Worker.Tests/StellaOps.Excititor.Worker.Tests.csproj`.
|
||||
- QUALITY: Warnings disabled via pragma; document and minimize. `src/Excititor/StellaOps.Excititor.Worker/Scheduling/VexConsensusRefreshService.cs`
|
||||
@@ -12922,10 +12920,10 @@
|
||||
|
||||
### src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/StellaOps.Scanner.Worker.Tests.csproj
|
||||
- TEST: test project.
|
||||
- MAINT: Non-deterministic time or random usage; inject TimeProvider/IGuidProvider and deterministic random sources. `src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/WorkerBasicScanScenarioTests.cs` `src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/VexGateStageExecutorTests.cs` `src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/SurfaceManifestStoreOptionsConfiguratorTests.cs`
|
||||
- MAINT: No maintainability issues detected in automated scan.
|
||||
- SECURITY: No high-risk patterns detected in automated scan.
|
||||
- REUSE: Not applicable (non-production project).
|
||||
- QUALITY: Environment.NewLine used; prefer \n for deterministic output. `src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/WorkerBasicScanScenarioTests.cs`
|
||||
- QUALITY: No quality patterns detected in automated scan.
|
||||
|
||||
### src/Scanner/StellaOps.Scanner.Analyzers.Native/StellaOps.Scanner.Analyzers.Native.csproj
|
||||
- TEST: Covered by 1 test project(s): `src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Native.Tests/StellaOps.Scanner.Analyzers.Native.Tests.csproj`.
|
||||
@@ -12965,13 +12963,10 @@
|
||||
|
||||
### src/Scanner/StellaOps.Scanner.Worker/StellaOps.Scanner.Worker.csproj
|
||||
- TEST: Covered by 2 test project(s): `src/Scanner/__Tests/StellaOps.Scanner.Integration.Tests/StellaOps.Scanner.Integration.Tests.csproj` `src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/StellaOps.Scanner.Worker.Tests.csproj`.
|
||||
- MAINT: Non-deterministic time or random usage; inject TimeProvider/IGuidProvider and deterministic random sources. `src/Scanner/StellaOps.Scanner.Worker/Determinism/DeterministicRandomProvider.cs`
|
||||
- MAINT: CancellationToken.None used; propagate cancellation. `src/Scanner/StellaOps.Scanner.Worker/Processing/Surface/SurfaceManifestStageExecutor.cs` `src/Scanner/StellaOps.Scanner.Worker/Processing/Surface/HmacDsseEnvelopeSigner.cs` `src/Scanner/StellaOps.Scanner.Worker/Hosting/ScannerWorkerHostedService.cs`
|
||||
- MAINT: Sync-over-async detected (.Result/.Wait/GetResult); use await. `src/Scanner/StellaOps.Scanner.Worker/Options/ScannerStorageSurfaceSecretConfigurator.cs` `src/Scanner/StellaOps.Scanner.Worker/Processing/Surface/SurfaceManifestStageExecutor.cs` `src/Scanner/StellaOps.Scanner.Worker/Processing/CompositeScanAnalyzerDispatcher.cs`
|
||||
- MAINT: Task.Run usage; ensure not used to offload request-path work. `src/Scanner/StellaOps.Scanner.Worker/Processing/NativeBinaryDiscovery.cs` `src/Scanner/StellaOps.Scanner.Worker/Processing/NativeAnalyzerExecutor.cs`
|
||||
- MAINT: No maintainability issues detected in automated scan.
|
||||
- SECURITY: No high-risk patterns detected in automated scan.
|
||||
- REUSE: No production references; referenced by 2 non-production project(s): `src/Scanner/__Tests/StellaOps.Scanner.Integration.Tests/StellaOps.Scanner.Integration.Tests.csproj` `src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/StellaOps.Scanner.Worker.Tests.csproj`.
|
||||
- QUALITY: TODO/FIXME/HACK markers present; track cleanup. `src/Scanner/StellaOps.Scanner.Worker/Processing/PoE/PoEGenerationStageExecutor.cs`
|
||||
- QUALITY: No quality patterns detected in automated scan.
|
||||
|
||||
### src/Scheduler/__Libraries/StellaOps.Scheduler.ImpactIndex/StellaOps.Scheduler.ImpactIndex.csproj
|
||||
- TEST: Covered by 1 test project(s): `src/Scheduler/__Tests/StellaOps.Scheduler.ImpactIndex.Tests/StellaOps.Scheduler.ImpactIndex.Tests.csproj`.
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
# Sprint 20260113_001_000 - Index - Binary Diff Attestation
|
||||
|
||||
## Topic & Scope
|
||||
- Deliver ELF section hash extraction and binary diff attestations to close the genuine gaps from the OCI layer-level integrity advisory.
|
||||
- Coordinate Scanner, Attestor, CLI, and Docs sprints for deterministic evidence and DSSE-signed outputs.
|
||||
- Keep scope ELF-only for the initial release; defer PE and Mach-O to a later milestone.
|
||||
- **Working directory:** `docs/implplan`.
|
||||
|
||||
### Executive Summary
|
||||
This sprint batch implements **targeted enhancements** for binary-level image integrity verification, focusing on ELF section-level hashing for vendor backport detection and DSSE-signed attestations for binary diffs. This addresses the genuine gaps identified in the OCI Layer-Level Image Integrity advisory analysis while avoiding redundant work on already-implemented capabilities.
|
||||
|
||||
**Scope:** ELF-only (PE/Mach-O deferred to M2+)
|
||||
**Effort Estimate:** 5-7 story points across 4 sprints
|
||||
**Priority:** Medium (enhancement, not blocking)
|
||||
|
||||
### Background
|
||||
#### Advisory Analysis Summary
|
||||
|
||||
| Category | Coverage |
|
||||
|----------|----------|
|
||||
| **Already Implemented** | ~80% (OCI manifest parsing, layer SBOM fragmentation, DSSE pipeline, VEX emission) |
|
||||
| **Partial Overlap** | ~15% (ELF symbols exist, section hashes missing) |
|
||||
| **Genuine Gaps** | ~5% (section hashes, BinaryDiffV1 predicate, CLI diff verb) |
|
||||
|
||||
This batch addresses only the genuine gaps to maximize value while avoiding redundant effort.
|
||||
|
||||
#### Existing Capabilities (No Work Needed)
|
||||
- OCI manifest/index parsing with Docker and OCI media types
|
||||
- Per-layer SBOM fragmentation with three-way diff
|
||||
- DSSE envelope creation -> Attestor -> Rekor pipeline
|
||||
- VEX emission with trust scoring and evidence links
|
||||
- ELF Build-ID, symbol table parsing, link graph analysis
|
||||
|
||||
#### New Capabilities (This Batch)
|
||||
1. **ELF Section Hash Extractor** - SHA-256 per `.text`, `.rodata`, `.data`, `.symtab` sections
|
||||
2. **BinaryDiffV1 In-Toto Predicate** - Schema for binary-level diff attestations
|
||||
3. **CLI `stella scan diff --mode=elf`** - Binary-section-level diff with DSSE output
|
||||
4. **Documentation** - Architecture docs and CLI reference updates
|
||||
|
||||
### Sprint Index
|
||||
|
||||
| Sprint | ID | Module | Topic | Status | Owner |
|
||||
|--------|-----|--------|-------|--------|-------|
|
||||
| 1 | SPRINT_20260113_001_001 | SCANNER | ELF Section Hash Extractor | DONE | Guild - Scanner |
|
||||
| 2 | SPRINT_20260113_001_002 | ATTESTOR | BinaryDiffV1 In-Toto Predicate | DONE | Guild - Attestor |
|
||||
| 3 | SPRINT_20260113_001_003 | CLI | Binary Diff Command Enhancement | DONE | Guild - CLI |
|
||||
| 4 | SPRINT_20260113_001_004 | DOCS | Documentation and Architecture | DONE | Guild - Docs |
|
||||
|
||||
### Acceptance Criteria (Batch-Level)
|
||||
|
||||
#### Must Have
|
||||
1. **Section Hash Extraction**
|
||||
- Compute SHA-256 for `.text`, `.rodata`, `.data`, `.symtab` ELF sections
|
||||
- Deterministic output (stable ordering, canonical JSON)
|
||||
- Evidence properties in SBOM components
|
||||
|
||||
2. **BinaryDiffV1 Predicate**
|
||||
- In-toto compliant predicate schema
|
||||
- Subjects: image@digest, platform
|
||||
- Inputs: base and target manifests
|
||||
- Findings: per-path section deltas
|
||||
|
||||
3. **CLI Integration**
|
||||
- `stella scan diff --mode=elf` produces binary-section-level diff
|
||||
- `--emit-dsse=<dir>` outputs signed attestations
|
||||
- Human-readable and JSON output formats
|
||||
|
||||
4. **Documentation**
|
||||
- Architecture doc under `docs/modules/scanner/`
|
||||
- CLI reference updates
|
||||
- Predicate schema specification
|
||||
|
||||
#### Should Have
|
||||
- Confidence scoring for section hash matches (0.0-1.0)
|
||||
- Integration with existing VEX evidence blocks
|
||||
|
||||
#### Deferred (Out of Scope)
|
||||
- PE and Mach-O section analysis (M2)
|
||||
- Vendor backport corpus and 95% precision target (follow-up sprint)
|
||||
- `ctr images export` integration (use existing OCI blob pull)
|
||||
- Multi-platform diff in single invocation
|
||||
|
||||
### Technical Context
|
||||
|
||||
#### Key Files to Extend
|
||||
|
||||
| Component | File | Purpose |
|
||||
|-----------|------|---------|
|
||||
| ELF Analysis | `src/Scanner/StellaOps.Scanner.Analyzers.Native/Hardening/ElfHardeningExtractor.cs` | Add section hash extraction |
|
||||
| Native Models | `src/Scanner/__Libraries/StellaOps.Scanner.Contracts/CallGraphModels.cs` | Section hash models |
|
||||
| DSSE Signing | `src/Scanner/__Libraries/StellaOps.Scanner.Reachability/Witnesses/WitnessDsseSigner.cs` | Pattern for BinaryDiffSigner |
|
||||
| Predicates | `src/Attestor/__Libraries/StellaOps.Attestor.StandardPredicates/` | Add BinaryDiffV1 |
|
||||
| CLI | `src/Cli/StellaOps.Cli/Commands/` | Add diff subcommand |
|
||||
|
||||
#### Determinism Requirements
|
||||
Per CLAUDE.md Section 8:
|
||||
|
||||
1. **TimeProvider injection** - No `DateTime.UtcNow` calls
|
||||
2. **Stable ordering** - Section hashes sorted by section name
|
||||
3. **Canonical JSON** - RFC 8785 for digest computation
|
||||
4. **InvariantCulture** - All formatting and parsing
|
||||
5. **DSSE PAE compliance** - Use shared `DsseHelper`
|
||||
|
||||
### Risk Assessment
|
||||
|
||||
| Risk | Likelihood | Impact | Mitigation |
|
||||
|------|------------|--------|------------|
|
||||
| Section hash instability across compilers | Medium | High | Document compiler and flag assumptions; use position-independent matching as fallback |
|
||||
| ELF parsing edge cases | Low | Medium | Comprehensive test fixtures; existing ELF library handles most cases |
|
||||
| CLI integration conflicts | Low | Low | CLI tests currently blocked by other agent work; coordinate ownership |
|
||||
|
||||
### Success Metrics
|
||||
- [ ] All unit tests pass (100% of new code covered)
|
||||
- [ ] Integration tests with synthetic ELF fixtures pass
|
||||
- [ ] CLI help and completions work
|
||||
- [ ] Documentation builds without warnings
|
||||
- [ ] No regressions in existing Scanner tests
|
||||
|
||||
## Dependencies & Concurrency
|
||||
- Sprint 1 is foundational with no dependencies.
|
||||
- Sprint 2 depends on Sprint 1 (uses section hash models).
|
||||
- Sprint 3 depends on Sprints 1 and 2 (consumes extractor and predicate).
|
||||
- Sprint 4 can proceed in parallel with Sprints 2 and 3.
|
||||
- Other 20260113_001_000 planning artifacts are index-only, so parallel edits remain safe.
|
||||
|
||||
```
|
||||
Sprint 1 (ELF Section Hashes)
|
||||
-> Sprint 2 (Predicate)
|
||||
-> Sprint 4 (Docs)
|
||||
Sprint 2 (Predicate)
|
||||
-> Sprint 3 (CLI)
|
||||
```
|
||||
|
||||
## Documentation Prerequisites
|
||||
Before starting implementation, reviewers must read:
|
||||
|
||||
- `docs/README.md`
|
||||
- `docs/ARCHITECTURE_REFERENCE.md`
|
||||
- `docs/modules/scanner/architecture.md` (if exists)
|
||||
- `CLAUDE.md` Section 8 (Code Quality and Determinism Rules)
|
||||
- `src/Scanner/StellaOps.Scanner.Analyzers.Native/AGENTS.md` (if exists)
|
||||
|
||||
## Delivery Tracker
|
||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 1 | INDEX-20260113-001-000-01 | DONE | None | Project Mgmt | Normalize sprint batch index to standard template and ASCII-only formatting. |
|
||||
| 2 | INDEX-20260113-001-000-02 | DONE | None | Project Mgmt | Clarify dependency flow and checkpoint wording without changing scope. |
|
||||
|
||||
## Execution Log
|
||||
| Date (UTC) | Update | Owner |
|
||||
|------------|--------|-------|
|
||||
| 2026-01-13 | Sprint batch created from advisory analysis; 4 sprints defined. | Project Mgmt |
|
||||
| 2026-01-13 | Normalized sprint file to standard template; ASCII-only cleanup; no semantic changes. | Project Mgmt |
|
||||
| 2026-01-13 | Sprints 001_003 (CLI) and 001_004 (Docs) completed; tests remain blocked. | CLI + Docs |
|
||||
| 2026-01-13 | Sprints 001_001 (Scanner) and 001_002 (Attestor) completed. | Scanner + Attestor |
|
||||
| 2026-01-13 | CLI binary diff unit and integration tests completed; batch ready for archive. | CLI |
|
||||
|
||||
## Decisions & Risks
|
||||
- **APPROVED 2026-01-13**: Scope limited to ELF-only; PE and Mach-O deferred to M2.
|
||||
- **APPROVED 2026-01-13**: 80% precision target for initial release; 95% deferred to corpus sprint.
|
||||
- **RESOLVED**: CLI tests completed after coordination.
|
||||
|
||||
## Next Checkpoints
|
||||
- Sprint 1 completion -> Sprint 2 and 4 can start
|
||||
- Sprint 2 completion -> Sprint 3 can start
|
||||
- All sprints complete -> Integration testing checkpoint
|
||||
@@ -0,0 +1,234 @@
|
||||
# Sprint 20260113_001_001_SCANNER - ELF Section Hash Extractor
|
||||
|
||||
## Topic & Scope
|
||||
|
||||
- Implement per-section SHA-256 hash extraction for ELF binaries
|
||||
- Target sections: `.text`, `.rodata`, `.data`, `.symtab`, `.dynsym`
|
||||
- Integrate with existing `ElfHardeningExtractor` infrastructure
|
||||
- Expose section hashes as SBOM component evidence properties
|
||||
- **Working directory:** `src/Scanner/StellaOps.Scanner.Analyzers.Native/`
|
||||
|
||||
## Dependencies & Concurrency
|
||||
|
||||
- No blocking dependencies (foundational sprint)
|
||||
- Parallel work safe within Scanner.Native module
|
||||
- Sprint 2 (BinaryDiffV1 predicate) depends on this sprint's models
|
||||
|
||||
## Documentation Prerequisites
|
||||
|
||||
- `docs/README.md`
|
||||
- `docs/ARCHITECTURE_REFERENCE.md`
|
||||
- `CLAUDE.md` Section 8 (Determinism Rules)
|
||||
- `src/Scanner/StellaOps.Scanner.Analyzers.Native/AGENTS.md` (if exists)
|
||||
- ELF specification reference (https://refspecs.linuxfoundation.org/elf/elf.pdf)
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||
|---|---------|--------|---------------------------|--------|-----------------|
|
||||
| 1 | ELF-SECTION-MODELS-0001 | DONE | None | Guild - Scanner | Define `ElfSectionHash` and `ElfSectionHashSet` models in `src/Scanner/__Libraries/StellaOps.Scanner.Contracts/`. Include section name, offset, size, SHA-256 hash, and optional BLAKE3 hash. |
|
||||
| 2 | ELF-SECTION-EXTRACTOR-0001 | DONE | Depends on ELF-SECTION-MODELS-0001 | Guild - Scanner | Implement `ElfSectionHashExtractor` class that reads ELF sections and computes per-section hashes. Integrate with existing ELF parsing in `ElfHardeningExtractor`. |
|
||||
| 3 | ELF-SECTION-CONFIG-0001 | DONE | Depends on ELF-SECTION-EXTRACTOR-0001 | Guild - Scanner | Add configuration options for section hash extraction: enabled/disabled, section allowlist, hash algorithms. Use `IOptions<T>` with `ValidateOnStart`. |
|
||||
| 4 | ELF-SECTION-EVIDENCE-0001 | DONE | Depends on ELF-SECTION-EXTRACTOR-0001 | Guild - Scanner | Emit section hashes as SBOM component `properties[]` with keys: `evidence:section:<name>:sha256`, `evidence:section:<name>:blake3`, `evidence:section:<name>:size`. |
|
||||
| 5 | ELF-SECTION-DI-0001 | DONE | Depends on all above | Guild - Scanner | Register `ElfSectionHashExtractor` in `ServiceCollectionExtensions.cs`. Ensure `TimeProvider` and `IGuidGenerator` are injected for determinism. |
|
||||
| 6 | ELF-SECTION-TESTS-0001 | DONE | Depends on all above | Guild - Scanner | Add unit tests in `src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Native.Tests/` covering: valid ELF with all sections, stripped ELF (missing symtab), malformed ELF, empty sections, large binaries. |
|
||||
| 7 | ELF-SECTION-FIXTURES-0001 | DONE | Depends on ELF-SECTION-TESTS-0001 | Guild - Scanner | Create synthetic ELF test fixtures under `src/Scanner/__Tests/__Datasets/elf-section-hashes/` with known section contents for golden hash verification. |
|
||||
| 8 | ELF-SECTION-DETERMINISM-0001 | DONE | Depends on all above | Guild - Scanner | Add determinism regression test: same ELF input produces identical section hashes across runs. Use `FakeTimeProvider` and fixed GUID generator. |
|
||||
|
||||
## Technical Specification
|
||||
|
||||
### ElfSectionHash Model
|
||||
|
||||
```csharp
|
||||
namespace StellaOps.Scanner.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a cryptographic hash of an ELF section.
|
||||
/// </summary>
|
||||
public sealed record ElfSectionHash
|
||||
{
|
||||
/// <summary>Section name (e.g., ".text", ".rodata").</summary>
|
||||
public required string Name { get; init; }
|
||||
|
||||
/// <summary>Section offset in file.</summary>
|
||||
public required long Offset { get; init; }
|
||||
|
||||
/// <summary>Section size in bytes.</summary>
|
||||
public required long Size { get; init; }
|
||||
|
||||
/// <summary>SHA-256 hash of section contents (lowercase hex).</summary>
|
||||
public required string Sha256 { get; init; }
|
||||
|
||||
/// <summary>Optional BLAKE3-256 hash of section contents (lowercase hex).</summary>
|
||||
public string? Blake3 { get; init; }
|
||||
|
||||
/// <summary>Section type from ELF header.</summary>
|
||||
public required ElfSectionType SectionType { get; init; }
|
||||
|
||||
/// <summary>Section flags from ELF header.</summary>
|
||||
public required ElfSectionFlags Flags { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collection of section hashes for a single ELF binary.
|
||||
/// </summary>
|
||||
public sealed record ElfSectionHashSet
|
||||
{
|
||||
/// <summary>Path to the ELF binary.</summary>
|
||||
public required string FilePath { get; init; }
|
||||
|
||||
/// <summary>SHA-256 hash of the entire file.</summary>
|
||||
public required string FileHash { get; init; }
|
||||
|
||||
/// <summary>Build-ID from .note.gnu.build-id if present.</summary>
|
||||
public string? BuildId { get; init; }
|
||||
|
||||
/// <summary>Section hashes, sorted by section name.</summary>
|
||||
public required ImmutableArray<ElfSectionHash> Sections { get; init; }
|
||||
|
||||
/// <summary>Extraction timestamp (UTC ISO-8601).</summary>
|
||||
public required DateTimeOffset ExtractedAt { get; init; }
|
||||
|
||||
/// <summary>Extractor version for reproducibility.</summary>
|
||||
public required string ExtractorVersion { get; init; }
|
||||
}
|
||||
```
|
||||
|
||||
### Extractor Interface
|
||||
|
||||
```csharp
|
||||
namespace StellaOps.Scanner.Analyzers.Native;
|
||||
|
||||
public interface IElfSectionHashExtractor
|
||||
{
|
||||
/// <summary>
|
||||
/// Extracts section hashes from an ELF binary.
|
||||
/// </summary>
|
||||
/// <param name="elfPath">Path to the ELF file.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Section hash set, or null if not a valid ELF.</returns>
|
||||
Task<ElfSectionHashSet?> ExtractAsync(
|
||||
string elfPath,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Extracts section hashes from ELF bytes in memory.
|
||||
/// </summary>
|
||||
Task<ElfSectionHashSet?> ExtractFromBytesAsync(
|
||||
ReadOnlyMemory<byte> elfBytes,
|
||||
string virtualPath,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
```
|
||||
|
||||
### Target Sections
|
||||
|
||||
| Section | Purpose | Backport Relevance |
|
||||
|---------|---------|-------------------|
|
||||
| `.text` | Executable code | **High** - patched functions change this |
|
||||
| `.rodata` | Read-only data | Medium - string constants may change |
|
||||
| `.data` | Initialized data | Low - rarely changes for patches |
|
||||
| `.symtab` | Symbol table | **High** - function signatures |
|
||||
| `.dynsym` | Dynamic symbols | **High** - exported API |
|
||||
| `.gnu.hash` | GNU hash table | Low - derived from symbols |
|
||||
|
||||
### SBOM Evidence Properties
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "library",
|
||||
"name": "libssl.so.3",
|
||||
"properties": [
|
||||
{"name": "evidence:build-id", "value": "abc123..."},
|
||||
{"name": "evidence:section:.text:sha256", "value": "e3b0c442..."},
|
||||
{"name": "evidence:section:.text:size", "value": "1048576"},
|
||||
{"name": "evidence:section:.rodata:sha256", "value": "d7a8fbb3..."},
|
||||
{"name": "evidence:section:.symtab:sha256", "value": "9f86d081..."},
|
||||
{"name": "evidence:section-set:sha256", "value": "combined_hash..."},
|
||||
{"name": "evidence:extractor-version", "value": "1.0.0"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Determinism Requirements
|
||||
|
||||
1. **Ordering**: Sections sorted lexicographically by name
|
||||
2. **Hash format**: Lowercase hexadecimal, no prefix
|
||||
3. **Timestamps**: From injected `TimeProvider.GetUtcNow()`
|
||||
4. **Version string**: Assembly version or build metadata
|
||||
5. **JSON serialization**: RFC 8785 canonical for any digest computation
|
||||
|
||||
### Configuration Schema
|
||||
|
||||
```yaml
|
||||
scanner:
|
||||
native:
|
||||
sectionHashes:
|
||||
enabled: true
|
||||
algorithms:
|
||||
- sha256
|
||||
- blake3 # optional
|
||||
sections:
|
||||
- .text
|
||||
- .rodata
|
||||
- .data
|
||||
- .symtab
|
||||
- .dynsym
|
||||
maxSectionSize: 104857600 # 100MB limit per section
|
||||
```
|
||||
|
||||
## Test Cases
|
||||
|
||||
### Unit Tests
|
||||
|
||||
| Test | Description | Expected |
|
||||
|------|-------------|----------|
|
||||
| `ExtractAsync_ValidElf_ReturnsAllSections` | Standard ELF with all target sections | All 5 sections extracted with valid hashes |
|
||||
| `ExtractAsync_StrippedElf_OmitsSymtab` | Stripped binary without .symtab | Only .text, .rodata, .data returned |
|
||||
| `ExtractAsync_InvalidElf_ReturnsNull` | Non-ELF file (PE, Mach-O, random) | Returns null, no exception |
|
||||
| `ExtractAsync_EmptySection_ReturnsEmptyHash` | ELF with zero-size .data | Hash of empty content (`e3b0c442...`) |
|
||||
| `ExtractAsync_LargeSection_RespectsLimit` | Section > maxSectionSize | Section skipped or truncated per config |
|
||||
| `ExtractAsync_Deterministic_SameOutput` | Same ELF, multiple runs | Identical `ElfSectionHashSet` |
|
||||
| `ExtractFromBytesAsync_SameAsFile` | Memory vs file extraction | Identical results |
|
||||
|
||||
### Integration Tests
|
||||
|
||||
| Test | Description | Expected |
|
||||
|------|-------------|----------|
|
||||
| `LayerAnalysis_ElfWithSections_EmitsEvidence` | Container layer with ELF binaries | SBOM components have section hash properties |
|
||||
| `Diff_SameBinaryDifferentPatch_DetectsSectionChange` | Two builds with backport | `.text` hash differs, other sections same |
|
||||
|
||||
### Fixtures
|
||||
|
||||
Create under `src/Scanner/__Tests/__Datasets/elf-section-hashes/`:
|
||||
|
||||
```
|
||||
elf-section-hashes/
|
||||
├── README.md # Fixture documentation
|
||||
├── standard-amd64.elf # Standard ELF with all sections
|
||||
├── standard-amd64.golden.json # Expected section hashes
|
||||
├── stripped-amd64.elf # Stripped binary
|
||||
├── stripped-amd64.golden.json
|
||||
├── minimal-arm64.elf # Minimal ELF (few sections)
|
||||
├── minimal-arm64.golden.json
|
||||
└── corrupt.bin # Invalid ELF magic
|
||||
```
|
||||
|
||||
## Execution Log
|
||||
|
||||
| Date (UTC) | Update | Owner |
|
||||
|------------|--------|-------|
|
||||
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
|
||||
|
||||
## Decisions & Risks
|
||||
|
||||
- **APPROVED**: SHA-256 as primary hash; BLAKE3 optional for performance.
|
||||
- **APPROVED**: 100MB per-section limit to prevent memory exhaustion.
|
||||
- **RISK**: Some ELF parsers may handle edge cases differently; use LibObjectFile or similar well-tested library.
|
||||
- **RISK**: Section ordering may vary by toolchain; normalize by sorting.
|
||||
|
||||
## Next Checkpoints
|
||||
|
||||
- Task 1-2 complete → Models and extractor ready for integration
|
||||
- Task 6-8 complete → Sprint can be marked DONE
|
||||
- Unblock Sprint 2 (BinaryDiffV1 predicate)
|
||||
@@ -0,0 +1,441 @@
|
||||
# Sprint 20260113_001_002_ATTESTOR - BinaryDiffV1 In-Toto Predicate
|
||||
|
||||
## Topic & Scope
|
||||
|
||||
- Define `BinaryDiffV1` in-toto predicate schema for binary-level diff attestations
|
||||
- Implement predicate builder and serializer
|
||||
- Integrate with existing DSSE signing infrastructure
|
||||
- Support both ELF section diffs and future PE/Mach-O extensions
|
||||
- **Working directory:** `src/Attestor/__Libraries/StellaOps.Attestor.StandardPredicates/`
|
||||
|
||||
## Dependencies & Concurrency
|
||||
|
||||
- **Depends on:** Sprint 001 (ELF Section Hash models)
|
||||
- Parallel work safe within Attestor module
|
||||
- Sprint 3 (CLI) depends on this sprint
|
||||
|
||||
## Documentation Prerequisites
|
||||
|
||||
- `docs/README.md`
|
||||
- `docs/ARCHITECTURE_REFERENCE.md`
|
||||
- `CLAUDE.md` Section 8 (Determinism Rules)
|
||||
- in-toto attestation specification (https://github.com/in-toto/attestation/blob/main/spec/v1/statement.md)
|
||||
- DSSE envelope specification (https://github.com/secure-systems-lab/dsse/blob/master/envelope.md)
|
||||
- Existing predicates: `src/Attestor/__Libraries/StellaOps.Attestor.StandardPredicates/`
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||
|---|---------|--------|---------------------------|--------|-----------------|
|
||||
| 1 | BINARYDIFF-SCHEMA-0001 | DONE | Sprint 001 models | Guild - Attestor | Define `BinaryDiffV1` predicate schema with JSON Schema and C# models. Include subjects, inputs, findings, and verification materials. |
|
||||
| 2 | BINARYDIFF-MODELS-0001 | DONE | Depends on BINARYDIFF-SCHEMA-0001 | Guild - Attestor | Implement C# record types for `BinaryDiffPredicate`, `BinaryDiffSubject`, `BinaryDiffInput`, `BinaryDiffFinding`, `SectionDelta`. |
|
||||
| 3 | BINARYDIFF-BUILDER-0001 | DONE | Depends on BINARYDIFF-MODELS-0001 | Guild - Attestor | Implement `BinaryDiffPredicateBuilder` with fluent API for constructing predicates from section hash comparisons. |
|
||||
| 4 | BINARYDIFF-SERIALIZER-0001 | DONE | Depends on BINARYDIFF-MODELS-0001 | Guild - Attestor | Implement canonical JSON serialization using RFC 8785. Register with existing `IPredicateSerializer` infrastructure. |
|
||||
| 5 | BINARYDIFF-SIGNER-0001 | DONE | Depends on all above | Guild - Attestor | Implement `BinaryDiffDsseSigner` following `WitnessDsseSigner` pattern. Payload type: `stellaops.binarydiff.v1`. |
|
||||
| 6 | BINARYDIFF-VERIFIER-0001 | DONE | Depends on BINARYDIFF-SIGNER-0001 | Guild - Attestor | Implement `BinaryDiffDsseVerifier` for signature and schema validation. |
|
||||
| 7 | BINARYDIFF-DI-0001 | DONE | Depends on all above | Guild - Attestor | Register all services in DI. Add `IOptions<BinaryDiffOptions>` for configuration. |
|
||||
| 8 | BINARYDIFF-TESTS-0001 | DONE | Depends on all above | Guild - Attestor | Add comprehensive unit tests covering: schema validation, serialization round-trip, signing/verification, edge cases (empty findings, large diffs). |
|
||||
| 9 | BINARYDIFF-JSONSCHEMA-0001 | DONE | Depends on BINARYDIFF-SCHEMA-0001 | Guild - Attestor | Publish JSON Schema to `docs/schemas/binarydiff-v1.schema.json` for external validation. |
|
||||
|
||||
## Technical Specification
|
||||
|
||||
### Predicate Type
|
||||
|
||||
```
|
||||
stellaops.binarydiff.v1
|
||||
```
|
||||
|
||||
### BinaryDiffV1 Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://stellaops.io/schemas/binarydiff-v1.schema.json",
|
||||
"title": "BinaryDiffV1",
|
||||
"description": "In-toto predicate for binary-level diff attestations",
|
||||
"type": "object",
|
||||
"required": ["predicateType", "subjects", "inputs", "findings", "metadata"],
|
||||
"properties": {
|
||||
"predicateType": {
|
||||
"const": "stellaops.binarydiff.v1"
|
||||
},
|
||||
"subjects": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/$defs/BinaryDiffSubject" },
|
||||
"minItems": 1
|
||||
},
|
||||
"inputs": {
|
||||
"$ref": "#/$defs/BinaryDiffInputs"
|
||||
},
|
||||
"findings": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/$defs/BinaryDiffFinding" }
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/$defs/BinaryDiffMetadata"
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"BinaryDiffSubject": {
|
||||
"type": "object",
|
||||
"required": ["name", "digest"],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Image reference (e.g., docker://repo/app@sha256:...)"
|
||||
},
|
||||
"digest": {
|
||||
"type": "object",
|
||||
"additionalProperties": { "type": "string" }
|
||||
},
|
||||
"platform": {
|
||||
"$ref": "#/$defs/Platform"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BinaryDiffInputs": {
|
||||
"type": "object",
|
||||
"required": ["base", "target"],
|
||||
"properties": {
|
||||
"base": { "$ref": "#/$defs/ImageReference" },
|
||||
"target": { "$ref": "#/$defs/ImageReference" }
|
||||
}
|
||||
},
|
||||
"ImageReference": {
|
||||
"type": "object",
|
||||
"required": ["digest"],
|
||||
"properties": {
|
||||
"reference": { "type": "string" },
|
||||
"digest": { "type": "string" },
|
||||
"manifestDigest": { "type": "string" },
|
||||
"platform": { "$ref": "#/$defs/Platform" }
|
||||
}
|
||||
},
|
||||
"Platform": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"os": { "type": "string" },
|
||||
"architecture": { "type": "string" },
|
||||
"variant": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"BinaryDiffFinding": {
|
||||
"type": "object",
|
||||
"required": ["path", "changeType", "binaryFormat"],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "File path within the image filesystem"
|
||||
},
|
||||
"changeType": {
|
||||
"enum": ["added", "removed", "modified", "unchanged"]
|
||||
},
|
||||
"binaryFormat": {
|
||||
"enum": ["elf", "pe", "macho", "unknown"]
|
||||
},
|
||||
"layerDigest": {
|
||||
"type": "string",
|
||||
"description": "Layer that introduced this change"
|
||||
},
|
||||
"baseHashes": {
|
||||
"$ref": "#/$defs/SectionHashSet"
|
||||
},
|
||||
"targetHashes": {
|
||||
"$ref": "#/$defs/SectionHashSet"
|
||||
},
|
||||
"sectionDeltas": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/$defs/SectionDelta" }
|
||||
},
|
||||
"confidence": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
"verdict": {
|
||||
"enum": ["patched", "vanilla", "unknown", "incompatible"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"SectionHashSet": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"buildId": { "type": "string" },
|
||||
"fileHash": { "type": "string" },
|
||||
"sections": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/$defs/SectionInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"SectionInfo": {
|
||||
"type": "object",
|
||||
"required": ["sha256", "size"],
|
||||
"properties": {
|
||||
"sha256": { "type": "string" },
|
||||
"blake3": { "type": "string" },
|
||||
"size": { "type": "integer" }
|
||||
}
|
||||
},
|
||||
"SectionDelta": {
|
||||
"type": "object",
|
||||
"required": ["section", "status"],
|
||||
"properties": {
|
||||
"section": {
|
||||
"type": "string",
|
||||
"description": "Section name (e.g., .text, .rodata)"
|
||||
},
|
||||
"status": {
|
||||
"enum": ["identical", "modified", "added", "removed"]
|
||||
},
|
||||
"baseSha256": { "type": "string" },
|
||||
"targetSha256": { "type": "string" },
|
||||
"sizeDelta": { "type": "integer" }
|
||||
}
|
||||
},
|
||||
"BinaryDiffMetadata": {
|
||||
"type": "object",
|
||||
"required": ["toolVersion", "analysisTimestamp"],
|
||||
"properties": {
|
||||
"toolVersion": { "type": "string" },
|
||||
"analysisTimestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"configDigest": { "type": "string" },
|
||||
"totalBinaries": { "type": "integer" },
|
||||
"modifiedBinaries": { "type": "integer" },
|
||||
"analyzedSections": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### C# Model Classes
|
||||
|
||||
```csharp
|
||||
namespace StellaOps.Attestor.StandardPredicates.BinaryDiff;
|
||||
|
||||
/// <summary>
|
||||
/// BinaryDiffV1 predicate for in-toto attestations.
|
||||
/// </summary>
|
||||
public sealed record BinaryDiffPredicate
|
||||
{
|
||||
public const string PredicateType = "stellaops.binarydiff.v1";
|
||||
|
||||
public required ImmutableArray<BinaryDiffSubject> Subjects { get; init; }
|
||||
public required BinaryDiffInputs Inputs { get; init; }
|
||||
public required ImmutableArray<BinaryDiffFinding> Findings { get; init; }
|
||||
public required BinaryDiffMetadata Metadata { get; init; }
|
||||
}
|
||||
|
||||
public sealed record BinaryDiffSubject
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
public required ImmutableDictionary<string, string> Digest { get; init; }
|
||||
public Platform? Platform { get; init; }
|
||||
}
|
||||
|
||||
public sealed record BinaryDiffInputs
|
||||
{
|
||||
public required ImageReference Base { get; init; }
|
||||
public required ImageReference Target { get; init; }
|
||||
}
|
||||
|
||||
public sealed record ImageReference
|
||||
{
|
||||
public string? Reference { get; init; }
|
||||
public required string Digest { get; init; }
|
||||
public string? ManifestDigest { get; init; }
|
||||
public Platform? Platform { get; init; }
|
||||
}
|
||||
|
||||
public sealed record Platform
|
||||
{
|
||||
public required string Os { get; init; }
|
||||
public required string Architecture { get; init; }
|
||||
public string? Variant { get; init; }
|
||||
}
|
||||
|
||||
public sealed record BinaryDiffFinding
|
||||
{
|
||||
public required string Path { get; init; }
|
||||
public required ChangeType ChangeType { get; init; }
|
||||
public required BinaryFormat BinaryFormat { get; init; }
|
||||
public string? LayerDigest { get; init; }
|
||||
public SectionHashSet? BaseHashes { get; init; }
|
||||
public SectionHashSet? TargetHashes { get; init; }
|
||||
public ImmutableArray<SectionDelta> SectionDeltas { get; init; }
|
||||
public double? Confidence { get; init; }
|
||||
public Verdict? Verdict { get; init; }
|
||||
}
|
||||
|
||||
public enum ChangeType { Added, Removed, Modified, Unchanged }
|
||||
public enum BinaryFormat { Elf, Pe, Macho, Unknown }
|
||||
public enum Verdict { Patched, Vanilla, Unknown, Incompatible }
|
||||
|
||||
public sealed record SectionHashSet
|
||||
{
|
||||
public string? BuildId { get; init; }
|
||||
public required string FileHash { get; init; }
|
||||
public required ImmutableDictionary<string, SectionInfo> Sections { get; init; }
|
||||
}
|
||||
|
||||
public sealed record SectionInfo
|
||||
{
|
||||
public required string Sha256 { get; init; }
|
||||
public string? Blake3 { get; init; }
|
||||
public required long Size { get; init; }
|
||||
}
|
||||
|
||||
public sealed record SectionDelta
|
||||
{
|
||||
public required string Section { get; init; }
|
||||
public required SectionStatus Status { get; init; }
|
||||
public string? BaseSha256 { get; init; }
|
||||
public string? TargetSha256 { get; init; }
|
||||
public long? SizeDelta { get; init; }
|
||||
}
|
||||
|
||||
public enum SectionStatus { Identical, Modified, Added, Removed }
|
||||
|
||||
public sealed record BinaryDiffMetadata
|
||||
{
|
||||
public required string ToolVersion { get; init; }
|
||||
public required DateTimeOffset AnalysisTimestamp { get; init; }
|
||||
public string? ConfigDigest { get; init; }
|
||||
public int TotalBinaries { get; init; }
|
||||
public int ModifiedBinaries { get; init; }
|
||||
public ImmutableArray<string> AnalyzedSections { get; init; }
|
||||
}
|
||||
```
|
||||
|
||||
### Builder API
|
||||
|
||||
```csharp
|
||||
public interface IBinaryDiffPredicateBuilder
|
||||
{
|
||||
IBinaryDiffPredicateBuilder WithSubject(string name, string digest, Platform? platform = null);
|
||||
IBinaryDiffPredicateBuilder WithInputs(ImageReference baseImage, ImageReference targetImage);
|
||||
IBinaryDiffPredicateBuilder AddFinding(BinaryDiffFinding finding);
|
||||
IBinaryDiffPredicateBuilder WithMetadata(Action<BinaryDiffMetadataBuilder> configure);
|
||||
BinaryDiffPredicate Build();
|
||||
}
|
||||
```
|
||||
|
||||
### DSSE Integration
|
||||
|
||||
```csharp
|
||||
public interface IBinaryDiffDsseSigner
|
||||
{
|
||||
Task<BinaryDiffDsseResult> SignAsync(
|
||||
BinaryDiffPredicate predicate,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public sealed record BinaryDiffDsseResult
|
||||
{
|
||||
public required string PayloadType { get; init; } // stellaops.binarydiff.v1
|
||||
public required byte[] Payload { get; init; }
|
||||
public required ImmutableArray<DsseSignature> Signatures { get; init; }
|
||||
public required string EnvelopeJson { get; init; }
|
||||
public string? RekorLogIndex { get; init; }
|
||||
public string? RekorEntryId { get; init; }
|
||||
}
|
||||
```
|
||||
|
||||
### In-Toto Statement Wrapper
|
||||
|
||||
```json
|
||||
{
|
||||
"_type": "https://in-toto.io/Statement/v1",
|
||||
"subject": [
|
||||
{
|
||||
"name": "docker://registry.example.com/app@sha256:abc123...",
|
||||
"digest": {
|
||||
"sha256": "abc123..."
|
||||
}
|
||||
}
|
||||
],
|
||||
"predicateType": "stellaops.binarydiff.v1",
|
||||
"predicate": {
|
||||
"inputs": {
|
||||
"base": { "digest": "sha256:old..." },
|
||||
"target": { "digest": "sha256:new..." }
|
||||
},
|
||||
"findings": [
|
||||
{
|
||||
"path": "/usr/lib/libssl.so.3",
|
||||
"changeType": "modified",
|
||||
"binaryFormat": "elf",
|
||||
"sectionDeltas": [
|
||||
{ "section": ".text", "status": "modified", "baseSha256": "...", "targetSha256": "..." }
|
||||
],
|
||||
"confidence": 0.95,
|
||||
"verdict": "patched"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"toolVersion": "1.0.0",
|
||||
"analysisTimestamp": "2026-01-13T12:00:00Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Determinism Requirements
|
||||
|
||||
1. **Canonical JSON**: RFC 8785 for all serialization before signing
|
||||
2. **Stable ordering**: Findings sorted by path; sections sorted by name
|
||||
3. **Timestamps**: From injected `TimeProvider`
|
||||
4. **Hash computation**: Use shared `CanonicalJsonSerializer`
|
||||
5. **DSSE PAE**: Use shared `DsseHelper.ComputePreAuthenticationEncoding`
|
||||
|
||||
## Test Cases
|
||||
|
||||
### Unit Tests
|
||||
|
||||
| Test | Description | Expected |
|
||||
|------|-------------|----------|
|
||||
| `Serialize_RoundTrip_Identical` | Serialize then deserialize | Identical predicate |
|
||||
| `Serialize_Canonical_DeterministicOutput` | Same predicate, multiple serializations | Byte-identical JSON |
|
||||
| `Build_ValidInputs_CreatesPredicate` | Builder with all required fields | Valid predicate |
|
||||
| `Build_MissingSubject_Throws` | Builder without subject | `ArgumentException` |
|
||||
| `Sign_ValidPredicate_ReturnsEnvelope` | Sign with test key | Valid DSSE envelope |
|
||||
| `Verify_ValidEnvelope_Succeeds` | Verify signed envelope | Verification passes |
|
||||
| `Verify_TamperedPayload_Fails` | Modified payload | Verification fails |
|
||||
| `Schema_ValidJson_Passes` | Valid JSON against schema | Schema validation passes |
|
||||
| `Schema_InvalidJson_Fails` | Missing required field | Schema validation fails |
|
||||
|
||||
### Integration Tests
|
||||
|
||||
| Test | Description | Expected |
|
||||
|------|-------------|----------|
|
||||
| `SignAndSubmit_RekorIntegration` | Sign and submit to Rekor (test instance) | Log entry created |
|
||||
| `EndToEnd_DiffToAttestation` | From image diff to signed attestation | Valid DSSE with findings |
|
||||
|
||||
## Execution Log
|
||||
|
||||
| Date (UTC) | Update | Owner |
|
||||
|------------|--------|-------|
|
||||
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
|
||||
|
||||
## Decisions & Risks
|
||||
|
||||
- **APPROVED**: Predicate type `stellaops.binarydiff.v1` follows StellaOps naming convention.
|
||||
- **APPROVED**: Support both ELF and future PE/Mach-O via `binaryFormat` discriminator.
|
||||
- **RISK**: Schema evolution requires versioning strategy; defer to v2 if breaking changes needed.
|
||||
- **RISK**: Large diffs may produce large attestations; consider summary mode for >1000 findings.
|
||||
|
||||
## Next Checkpoints
|
||||
|
||||
- Task 1-4 complete → Schema and models ready for integration
|
||||
- Task 5-6 complete → Signing/verification operational
|
||||
- Task 8 complete → Sprint can be marked DONE
|
||||
- Unblock Sprint 3 (CLI)
|
||||
@@ -0,0 +1,360 @@
|
||||
# Sprint 20260113_001_003_CLI - Binary Diff Command Enhancement
|
||||
|
||||
## Topic & Scope
|
||||
|
||||
- Implement `stella scan diff --mode=elf` for binary-section-level diff
|
||||
- Add `--emit-dsse=<dir>` option for DSSE attestation output
|
||||
- Support human-readable table and JSON output formats
|
||||
- Integrate with existing scan infrastructure and OCI registry client
|
||||
- **Working directory:** `src/Cli/StellaOps.Cli/Commands/`
|
||||
|
||||
## Dependencies & Concurrency
|
||||
|
||||
- **Depends on:** Sprint 001 (ELF Section Hash Extractor)
|
||||
- **Depends on:** Sprint 002 (BinaryDiffV1 Predicate)
|
||||
- **RESOLVED**: CLI test coordination complete; tests unblocked
|
||||
- Parallel work safe for command implementation; test coordination required
|
||||
|
||||
## Documentation Prerequisites
|
||||
|
||||
- `docs/README.md`
|
||||
- `docs/ARCHITECTURE_REFERENCE.md`
|
||||
- `CLAUDE.md` Section 8 (Determinism Rules)
|
||||
- `src/Cli/StellaOps.Cli/AGENTS.md` (if exists)
|
||||
- Existing CLI commands: `src/Cli/StellaOps.Cli/Commands/`
|
||||
- System.CommandLine documentation
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||
|---|---------|--------|---------------------------|--------|-----------------|
|
||||
| 1 | CLI-DIFF-COMMAND-0001 | DONE | Sprint 001 & 002 complete | Guild - CLI | Create `BinaryDiffCommand` class under `Commands/Scan/` implementing `stella scan diff` subcommand with required options. |
|
||||
| 2 | CLI-DIFF-OPTIONS-0001 | DONE | Depends on CLI-DIFF-COMMAND-0001 | Guild - CLI | Define command options: `--base` (base image ref), `--target` (target image ref), `--mode` (elf/pe/auto), `--emit-dsse` (output dir), `--format` (table/json), `--platform` (os/arch). |
|
||||
| 3 | CLI-DIFF-SERVICE-0001 | DONE | Depends on CLI-DIFF-OPTIONS-0001 | Guild - CLI | Implement `BinaryDiffService` that orchestrates: image pull, layer extraction, section hash computation, diff computation, predicate building. |
|
||||
| 4 | CLI-DIFF-RENDERER-0001 | DONE | Depends on CLI-DIFF-SERVICE-0001 | Guild - CLI | Implement `BinaryDiffRenderer` for table and JSON output formats. Table shows path, change type, verdict, confidence. JSON outputs full diff structure. |
|
||||
| 5 | CLI-DIFF-DSSE-OUTPUT-0001 | DONE | Depends on CLI-DIFF-SERVICE-0001 | Guild - CLI | Implement DSSE output: one envelope per platform manifest, written to `--emit-dsse` directory with naming convention `{platform}-binarydiff.dsse.json`. |
|
||||
| 6 | CLI-DIFF-PROGRESS-0001 | DONE | Depends on CLI-DIFF-SERVICE-0001 | Guild - CLI | Add progress reporting for long-running operations: layer download progress, binary analysis progress, section hash computation. |
|
||||
| 7 | CLI-DIFF-DI-0001 | DONE | Depends on all above | Guild - CLI | Register all services in `Program.cs` DI setup. Wire up `IHttpClientFactory`, `IElfSectionHashExtractor`, `IBinaryDiffDsseSigner`. |
|
||||
| 8 | CLI-DIFF-HELP-0001 | DONE | Depends on CLI-DIFF-COMMAND-0001 | Guild - CLI | Add comprehensive help text, examples, and shell completions for the new command. |
|
||||
| 9 | CLI-DIFF-TESTS-0001 | DONE | Depends on all above; CLI tests under active modification | Guild - CLI | Add unit tests for command parsing, service logic, and output rendering. Coordinate with other agent before modifying test files. |
|
||||
| 10 | CLI-DIFF-INTEGRATION-0001 | DONE | Depends on CLI-DIFF-TESTS-0001 | Guild - CLI | Add integration test with synthetic OCI images containing known ELF binaries. Verify end-to-end flow. |
|
||||
|
||||
## Technical Specification
|
||||
|
||||
### Command Syntax
|
||||
|
||||
```bash
|
||||
# Basic usage
|
||||
stella scan diff --base <image-ref> --target <image-ref>
|
||||
|
||||
# With binary mode
|
||||
stella scan diff --base docker://repo/app:1.0.0 --target docker://repo/app:1.0.1 --mode=elf
|
||||
|
||||
# With DSSE output
|
||||
stella scan diff --base @sha256:abc... --target @sha256:def... \
|
||||
--mode=elf --emit-dsse=./attestations/
|
||||
|
||||
# JSON output
|
||||
stella scan diff --base image1 --target image2 --format=json > diff.json
|
||||
|
||||
# Specific platform
|
||||
stella scan diff --base image1 --target image2 --platform=linux/amd64
|
||||
```
|
||||
|
||||
### Command Options
|
||||
|
||||
| Option | Short | Type | Required | Default | Description |
|
||||
|--------|-------|------|----------|---------|-------------|
|
||||
| `--base` | `-b` | string | Yes | - | Base image reference (tag or @digest) |
|
||||
| `--target` | `-t` | string | Yes | - | Target image reference (tag or @digest) |
|
||||
| `--mode` | `-m` | enum | No | `auto` | Analysis mode: `elf`, `pe`, `auto` |
|
||||
| `--emit-dsse` | `-d` | path | No | - | Directory for DSSE attestation output |
|
||||
| `--format` | `-f` | enum | No | `table` | Output format: `table`, `json`, `summary` |
|
||||
| `--platform` | `-p` | string | No | - | Platform filter (e.g., `linux/amd64`) |
|
||||
| `--include-unchanged` | - | bool | No | `false` | Include unchanged binaries in output |
|
||||
| `--sections` | - | string[] | No | all | Sections to analyze (e.g., `.text,.rodata`) |
|
||||
| `--registry-auth` | - | string | No | - | Path to Docker config for authentication |
|
||||
| `--timeout` | - | int | No | `300` | Timeout in seconds for operations |
|
||||
| `--verbose` | `-v` | bool | No | `false` | Enable verbose output |
|
||||
|
||||
### Output Formats
|
||||
|
||||
#### Table Format (Default)
|
||||
|
||||
```
|
||||
Binary Diff: docker://repo/app:1.0.0 → docker://repo/app:1.0.1
|
||||
Platform: linux/amd64
|
||||
Analysis Mode: ELF Section Hashes
|
||||
|
||||
PATH CHANGE VERDICT CONFIDENCE SECTIONS CHANGED
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
/usr/lib/libssl.so.3 modified patched 0.95 .text, .rodata
|
||||
/usr/lib/libcrypto.so.3 modified patched 0.92 .text
|
||||
/usr/bin/openssl modified unknown 0.75 .text, .data
|
||||
/usr/lib/libc.so.6 unchanged - - -
|
||||
|
||||
Summary: 4 binaries analyzed, 3 modified, 1 unchanged
|
||||
Patched: 2, Unknown: 1
|
||||
```
|
||||
|
||||
#### JSON Format
|
||||
|
||||
```json
|
||||
{
|
||||
"schemaVersion": "1.0.0",
|
||||
"base": {
|
||||
"reference": "docker://repo/app:1.0.0",
|
||||
"digest": "sha256:abc123..."
|
||||
},
|
||||
"target": {
|
||||
"reference": "docker://repo/app:1.0.1",
|
||||
"digest": "sha256:def456..."
|
||||
},
|
||||
"platform": {
|
||||
"os": "linux",
|
||||
"architecture": "amd64"
|
||||
},
|
||||
"analysisMode": "elf",
|
||||
"timestamp": "2026-01-13T12:00:00Z",
|
||||
"findings": [
|
||||
{
|
||||
"path": "/usr/lib/libssl.so.3",
|
||||
"changeType": "modified",
|
||||
"verdict": "patched",
|
||||
"confidence": 0.95,
|
||||
"sectionDeltas": [
|
||||
{ "section": ".text", "status": "modified" },
|
||||
{ "section": ".rodata", "status": "modified" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"summary": {
|
||||
"totalBinaries": 4,
|
||||
"modified": 3,
|
||||
"unchanged": 1,
|
||||
"verdicts": {
|
||||
"patched": 2,
|
||||
"unknown": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Summary Format
|
||||
|
||||
```
|
||||
Binary Diff Summary
|
||||
───────────────────
|
||||
Base: docker://repo/app:1.0.0 (sha256:abc123...)
|
||||
Target: docker://repo/app:1.0.1 (sha256:def456...)
|
||||
Platform: linux/amd64
|
||||
|
||||
Binaries: 4 total, 3 modified, 1 unchanged
|
||||
Verdicts: 2 patched, 1 unknown
|
||||
|
||||
DSSE Attestation: ./attestations/linux-amd64-binarydiff.dsse.json
|
||||
```
|
||||
|
||||
### DSSE Output Structure
|
||||
|
||||
```
|
||||
attestations/
|
||||
├── linux-amd64-binarydiff.dsse.json # DSSE envelope
|
||||
├── linux-amd64-binarydiff.payload.json # Raw predicate (for inspection)
|
||||
└── linux-arm64-binarydiff.dsse.json # (if multi-arch)
|
||||
```
|
||||
|
||||
### Service Architecture
|
||||
|
||||
```csharp
|
||||
namespace StellaOps.Cli.Services;
|
||||
|
||||
public interface IBinaryDiffService
|
||||
{
|
||||
Task<BinaryDiffResult> ComputeDiffAsync(
|
||||
BinaryDiffRequest request,
|
||||
IProgress<BinaryDiffProgress>? progress = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public sealed record BinaryDiffRequest
|
||||
{
|
||||
public required string BaseImageRef { get; init; }
|
||||
public required string TargetImageRef { get; init; }
|
||||
public required BinaryDiffMode Mode { get; init; }
|
||||
public Platform? Platform { get; init; }
|
||||
public ImmutableArray<string>? Sections { get; init; }
|
||||
public bool IncludeUnchanged { get; init; }
|
||||
public string? RegistryAuthPath { get; init; }
|
||||
}
|
||||
|
||||
public sealed record BinaryDiffResult
|
||||
{
|
||||
public required ImageReference Base { get; init; }
|
||||
public required ImageReference Target { get; init; }
|
||||
public required Platform Platform { get; init; }
|
||||
public required ImmutableArray<BinaryDiffFinding> Findings { get; init; }
|
||||
public required BinaryDiffSummary Summary { get; init; }
|
||||
public BinaryDiffPredicate? Predicate { get; init; }
|
||||
}
|
||||
|
||||
public sealed record BinaryDiffProgress
|
||||
{
|
||||
public required string Phase { get; init; } // "pulling", "extracting", "analyzing", "diffing"
|
||||
public required string CurrentItem { get; init; }
|
||||
public required int Current { get; init; }
|
||||
public required int Total { get; init; }
|
||||
}
|
||||
```
|
||||
|
||||
### Command Implementation Pattern
|
||||
|
||||
```csharp
|
||||
namespace StellaOps.Cli.Commands.Scan;
|
||||
|
||||
public class BinaryDiffCommand : Command
|
||||
{
|
||||
public BinaryDiffCommand() : base("diff", "Compare binaries between two images")
|
||||
{
|
||||
AddOption(BaseOption);
|
||||
AddOption(TargetOption);
|
||||
AddOption(ModeOption);
|
||||
AddOption(EmitDsseOption);
|
||||
AddOption(FormatOption);
|
||||
AddOption(PlatformOption);
|
||||
// ... other options
|
||||
}
|
||||
|
||||
public static Option<string> BaseOption { get; } = new(
|
||||
aliases: ["--base", "-b"],
|
||||
description: "Base image reference (tag or @digest)")
|
||||
{
|
||||
IsRequired = true
|
||||
};
|
||||
|
||||
// ... other options
|
||||
|
||||
public new class Handler : ICommandHandler
|
||||
{
|
||||
private readonly IBinaryDiffService _diffService;
|
||||
private readonly IBinaryDiffDsseSigner _signer;
|
||||
private readonly IBinaryDiffRenderer _renderer;
|
||||
private readonly IConsole _console;
|
||||
|
||||
public async Task<int> InvokeAsync(InvocationContext context)
|
||||
{
|
||||
var cancellationToken = context.GetCancellationToken();
|
||||
|
||||
// Parse options
|
||||
var baseRef = context.ParseResult.GetValueForOption(BaseOption)!;
|
||||
var targetRef = context.ParseResult.GetValueForOption(TargetOption)!;
|
||||
// ...
|
||||
|
||||
// Execute diff
|
||||
var progress = new Progress<BinaryDiffProgress>(p =>
|
||||
_console.WriteLine($"[{p.Phase}] {p.CurrentItem} ({p.Current}/{p.Total})"));
|
||||
|
||||
var result = await _diffService.ComputeDiffAsync(
|
||||
new BinaryDiffRequest { ... },
|
||||
progress,
|
||||
cancellationToken);
|
||||
|
||||
// Emit DSSE if requested
|
||||
if (!string.IsNullOrEmpty(emitDssePath))
|
||||
{
|
||||
var dsseResult = await _signer.SignAsync(result.Predicate!, cancellationToken);
|
||||
await WriteDsseAsync(emitDssePath, result.Platform, dsseResult, cancellationToken);
|
||||
}
|
||||
|
||||
// Render output
|
||||
await _renderer.RenderAsync(result, format, _console.Out, cancellationToken);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
| Error | Exit Code | Message |
|
||||
|-------|-----------|---------|
|
||||
| Invalid base image | 1 | `Error: Unable to resolve base image '{ref}': {reason}` |
|
||||
| Invalid target image | 1 | `Error: Unable to resolve target image '{ref}': {reason}` |
|
||||
| Authentication failed | 2 | `Error: Registry authentication failed for '{registry}'` |
|
||||
| Platform not found | 3 | `Error: Platform '{platform}' not found in image index` |
|
||||
| No ELF binaries | 0 | `Warning: No ELF binaries found in images` (success with warning) |
|
||||
| Timeout | 124 | `Error: Operation timed out after {timeout}s` |
|
||||
| Network error | 5 | `Error: Network error: {message}` |
|
||||
|
||||
### Progress Reporting
|
||||
|
||||
```
|
||||
[pulling] Fetching base manifest... (1/4)
|
||||
[pulling] Fetching target manifest... (2/4)
|
||||
[pulling] Downloading layers... (3/4)
|
||||
└─ sha256:abc123... 45.2 MB/128.5 MB (35%)
|
||||
[extracting] Extracting base layers... (1/8)
|
||||
[extracting] Extracting target layers... (5/8)
|
||||
[analyzing] Computing section hashes... (1/156)
|
||||
└─ /usr/lib/libssl.so.3
|
||||
[analyzing] Computing section hashes... (78/156)
|
||||
└─ /usr/bin/python3.11
|
||||
[diffing] Comparing binaries... (1/156)
|
||||
[complete] Analysis complete.
|
||||
```
|
||||
|
||||
## Determinism Requirements
|
||||
|
||||
1. **Output ordering**: Findings sorted by path
|
||||
2. **Timestamps**: From injected `TimeProvider`
|
||||
3. **Hash formats**: Lowercase hexadecimal
|
||||
4. **JSON output**: RFC 8785 canonical when `--format=json`
|
||||
5. **DSSE files**: Canonical JSON serialization
|
||||
|
||||
## Test Cases
|
||||
|
||||
### Unit Tests
|
||||
|
||||
| Test | Description | Expected |
|
||||
|------|-------------|----------|
|
||||
| `ParseOptions_ValidArgs_Succeeds` | All required options provided | Options parsed correctly |
|
||||
| `ParseOptions_MissingBase_Fails` | Missing --base | Parse error |
|
||||
| `ComputeDiff_IdenticalImages_NoChanges` | Same image for base and target | Empty findings, summary shows 0 modified |
|
||||
| `ComputeDiff_ModifiedBinary_DetectsChange` | Binary with .text change | Finding with modified status |
|
||||
| `ComputeDiff_AddedBinary_Detected` | Binary in target only | Finding with added status |
|
||||
| `ComputeDiff_RemovedBinary_Detected` | Binary in base only | Finding with removed status |
|
||||
| `RenderTable_ValidResult_FormatsCorrectly` | Result with findings | Properly formatted table |
|
||||
| `RenderJson_ValidResult_CanonicalOutput` | Same result, multiple renders | Byte-identical JSON |
|
||||
| `EmitDsse_ValidResult_CreatesFile` | With --emit-dsse | DSSE file created |
|
||||
|
||||
### Integration Tests
|
||||
|
||||
| Test | Description | Expected |
|
||||
|------|-------------|----------|
|
||||
| `EndToEnd_RealImages_ProducesOutput` | Two synthetic OCI images | Valid diff output |
|
||||
| `EndToEnd_WithDsse_ValidAttestation` | Diff with --emit-dsse | Verifiable DSSE |
|
||||
| `MultiArch_SpecificPlatform_FiltersCorrectly` | Multi-arch image with --platform | Only specified platform analyzed |
|
||||
|
||||
## Execution Log
|
||||
|
||||
| Date (UTC) | Update | Owner |
|
||||
|------------|--------|-------|
|
||||
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
|
||||
| 2026-01-13 | Task CLI-DIFF-TESTS-0001 marked BLOCKED: CLI tests under active modification. | Project Mgmt |
|
||||
| 2026-01-13 | Completed CLI diff command implementation, rendering, DSSE output, and DI wiring; tests remain blocked. | CLI |
|
||||
| 2026-01-13 | Completed binary diff unit and integration tests; tasks unblocked. | CLI |
|
||||
|
||||
## Decisions & Risks
|
||||
|
||||
- **APPROVED**: Command placed under `stella scan diff` (not separate `stella-scan image diff` as in advisory).
|
||||
- **APPROVED**: Support `--mode=elf` initially; `--mode=pe` and `--mode=auto` stubbed for future.
|
||||
- **RESOLVED**: CLI tests completed after coordination.
|
||||
- **RISK**: Long-running operations need robust timeout and cancellation handling.
|
||||
- **RISK**: Large images may cause memory pressure; consider streaming approach for layer extraction.
|
||||
|
||||
## Next Checkpoints
|
||||
|
||||
- Task 1-6 complete → Command implementation ready
|
||||
- Task 7-8 complete → Help and DI wired up
|
||||
- Task 9-10 complete (after unblock) → Sprint can be marked DONE
|
||||
@@ -0,0 +1,352 @@
|
||||
# Sprint 20260113_001_004_DOCS - Binary Diff Attestation Documentation
|
||||
|
||||
## Topic & Scope
|
||||
|
||||
- Create architecture documentation for binary diff attestation feature
|
||||
- Update CLI reference with new `stella scan diff` command
|
||||
- Publish BinaryDiffV1 predicate JSON Schema
|
||||
- Add developer guide for extending binary analysis
|
||||
- **Working directory:** `docs/`
|
||||
|
||||
## Dependencies & Concurrency
|
||||
|
||||
- Can proceed in parallel with Sprints 2-3 (after Sprint 1 models stabilize)
|
||||
- No blocking dependencies for initial documentation drafts
|
||||
- Final documentation review after all implementation sprints complete
|
||||
|
||||
## Documentation Prerequisites
|
||||
|
||||
- `docs/README.md`
|
||||
- `docs/ARCHITECTURE_REFERENCE.md`
|
||||
- `CLAUDE.md` (for documentation standards)
|
||||
- Existing module docs: `docs/modules/scanner/`
|
||||
- Existing CLI docs: `docs/API_CLI_REFERENCE.md`
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||
|---|---------|--------|---------------------------|--------|-----------------|
|
||||
| 1 | DOCS-ARCH-0001 | DONE | Sprint 001 models | Guild - Docs | Create `docs/modules/scanner/binary-diff-attestation.md` architecture document covering ELF section hashing, diff computation, and DSSE attestation flow. |
|
||||
| 2 | DOCS-CLI-0001 | DONE | Sprint 003 command spec | Guild - Docs | Update `docs/API_CLI_REFERENCE.md` with `stella scan diff` command documentation including all options, examples, and output formats. |
|
||||
| 3 | DOCS-SCHEMA-0001 | DONE | Sprint 002 schema | Guild - Docs | Publish `docs/schemas/binarydiff-v1.schema.json` with full JSON Schema definition and validation examples. |
|
||||
| 4 | DOCS-DEVGUIDE-0001 | DONE | All sprints | Guild - Docs | Create `docs/dev/extending-binary-analysis.md` developer guide for adding new binary formats (PE, Mach-O) and custom section extractors. |
|
||||
| 5 | DOCS-EXAMPLES-0001 | DONE | Sprint 003 complete | Guild - Docs | Add usage examples to `docs/examples/binary-diff/` with sample commands, expected outputs, and DSSE verification steps. |
|
||||
| 6 | DOCS-GLOSSARY-0001 | DONE | None | Guild - Docs | Update `docs/GLOSSARY.md` (if exists) or create glossary entries for: section hash, binary diff, vendor backport, DSSE envelope. |
|
||||
| 7 | DOCS-CHANGELOG-0001 | DONE | All sprints complete | Guild - Docs | Add changelog entry for binary diff attestation feature in `CHANGELOG.md`. |
|
||||
| 8 | DOCS-REVIEW-0001 | DONE | All above complete | Guild - Docs | Final documentation review: cross-link all docs, verify examples work, spell-check, ensure consistency with existing docs. |
|
||||
|
||||
## Documentation Deliverables
|
||||
|
||||
### 1. Architecture Document
|
||||
|
||||
**File:** `docs/modules/scanner/binary-diff-attestation.md`
|
||||
|
||||
**Outline:**
|
||||
|
||||
```markdown
|
||||
# Binary Diff Attestation
|
||||
|
||||
## Overview
|
||||
- Purpose and use cases
|
||||
- Relationship to SBOM and VEX
|
||||
|
||||
## Architecture
|
||||
|
||||
### Component Diagram
|
||||
- ElfSectionHashExtractor
|
||||
- BinaryDiffService
|
||||
- BinaryDiffPredicateBuilder
|
||||
- BinaryDiffDsseSigner
|
||||
|
||||
### Data Flow
|
||||
1. Image resolution
|
||||
2. Layer extraction
|
||||
3. Binary identification
|
||||
4. Section hash computation
|
||||
5. Diff computation
|
||||
6. Predicate construction
|
||||
7. DSSE signing
|
||||
|
||||
## ELF Section Hashing
|
||||
|
||||
### Target Sections
|
||||
- .text (executable code)
|
||||
- .rodata (read-only data)
|
||||
- .data (initialized data)
|
||||
- .symtab (symbol table)
|
||||
- .dynsym (dynamic symbols)
|
||||
|
||||
### Hash Algorithm
|
||||
- SHA-256 primary
|
||||
- BLAKE3 optional
|
||||
|
||||
### Determinism Guarantees
|
||||
- Stable ordering
|
||||
- Canonical serialization
|
||||
|
||||
## BinaryDiffV1 Predicate
|
||||
|
||||
### Schema Overview
|
||||
- Subjects (image references)
|
||||
- Inputs (base/target)
|
||||
- Findings (per-binary deltas)
|
||||
- Metadata
|
||||
|
||||
### Evidence Properties
|
||||
- Section hashes in SBOM
|
||||
- Confidence scoring
|
||||
- Verdict classification
|
||||
|
||||
## DSSE Attestation
|
||||
|
||||
### Envelope Structure
|
||||
- Payload type: stellaops.binarydiff.v1
|
||||
- Signature algorithm
|
||||
- Rekor submission
|
||||
|
||||
### Verification
|
||||
- cosign compatibility
|
||||
- Offline verification
|
||||
|
||||
## Integration Points
|
||||
|
||||
### VEX Mapping
|
||||
- Linking to vulnerability status
|
||||
- Backport evidence
|
||||
|
||||
### Policy Engine
|
||||
- Binary evidence rules
|
||||
- Trust thresholds
|
||||
|
||||
## Configuration
|
||||
|
||||
### Options
|
||||
- Section selection
|
||||
- Hash algorithms
|
||||
- Output formats
|
||||
|
||||
## Limitations and Future Work
|
||||
|
||||
### Current Limitations
|
||||
- ELF only (PE/Mach-O planned)
|
||||
- Single-platform per invocation
|
||||
|
||||
### Roadmap
|
||||
- PE section analysis (M2)
|
||||
- Mach-O section analysis (M2)
|
||||
- Vendor backport corpus (M3)
|
||||
```
|
||||
|
||||
### 2. CLI Reference Update
|
||||
|
||||
**File:** `docs/API_CLI_REFERENCE.md` (append to Scan section)
|
||||
|
||||
**Content:**
|
||||
|
||||
```markdown
|
||||
### stella scan diff
|
||||
|
||||
Compare binaries between two container images at the section level.
|
||||
|
||||
#### Synopsis
|
||||
|
||||
```bash
|
||||
stella scan diff --base <image-ref> --target <image-ref> [options]
|
||||
```
|
||||
|
||||
#### Description
|
||||
|
||||
The `diff` command performs binary-level comparison between two container images,
|
||||
analyzing ELF section hashes to detect changes and classify them as patches,
|
||||
vanilla updates, or unknown modifications.
|
||||
|
||||
#### Options
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--base`, `-b` | Base image reference (required) |
|
||||
| `--target`, `-t` | Target image reference (required) |
|
||||
| `--mode`, `-m` | Analysis mode: `elf`, `pe`, `auto` (default: `auto`) |
|
||||
| `--emit-dsse`, `-d` | Directory for DSSE attestation output |
|
||||
| `--format`, `-f` | Output format: `table`, `json`, `summary` (default: `table`) |
|
||||
| `--platform`, `-p` | Platform filter (e.g., `linux/amd64`) |
|
||||
| `--include-unchanged` | Include unchanged binaries in output |
|
||||
| `--sections` | Sections to analyze (comma-separated) |
|
||||
| `--registry-auth` | Path to Docker config for authentication |
|
||||
| `--timeout` | Timeout in seconds (default: 300) |
|
||||
| `--verbose`, `-v` | Enable verbose output |
|
||||
|
||||
#### Examples
|
||||
|
||||
**Basic comparison:**
|
||||
```bash
|
||||
stella scan diff --base myapp:1.0.0 --target myapp:1.0.1
|
||||
```
|
||||
|
||||
**With DSSE attestation output:**
|
||||
```bash
|
||||
stella scan diff -b myapp:1.0.0 -t myapp:1.0.1 \
|
||||
--mode=elf --emit-dsse=./attestations/
|
||||
```
|
||||
|
||||
**JSON output for automation:**
|
||||
```bash
|
||||
stella scan diff -b myapp:1.0.0 -t myapp:1.0.1 --format=json > diff.json
|
||||
```
|
||||
|
||||
**Specific platform:**
|
||||
```bash
|
||||
stella scan diff -b myapp:1.0.0 -t myapp:1.0.1 --platform=linux/arm64
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
**Table format** shows a summary of changes:
|
||||
```
|
||||
PATH CHANGE VERDICT CONFIDENCE
|
||||
/usr/lib/libssl.so.3 modified patched 0.95
|
||||
/usr/lib/libcrypto.so.3 modified patched 0.92
|
||||
```
|
||||
|
||||
**JSON format** provides full diff details for programmatic consumption.
|
||||
|
||||
#### Exit Codes
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 0 | Success |
|
||||
| 1 | Invalid image reference |
|
||||
| 2 | Authentication failed |
|
||||
| 3 | Platform not found |
|
||||
| 124 | Timeout |
|
||||
| 5 | Network error |
|
||||
|
||||
#### See Also
|
||||
|
||||
- `stella scan layers` - List layers in an image
|
||||
- `stella scan sbom` - Generate SBOM for an image
|
||||
- [Binary Diff Attestation Architecture](../modules/scanner/binary-diff-attestation.md)
|
||||
```
|
||||
|
||||
### 3. JSON Schema
|
||||
|
||||
**File:** `docs/schemas/binarydiff-v1.schema.json`
|
||||
|
||||
(Full schema as defined in Sprint 002)
|
||||
|
||||
### 4. Developer Guide
|
||||
|
||||
**File:** `docs/dev/extending-binary-analysis.md`
|
||||
|
||||
**Outline:**
|
||||
|
||||
```markdown
|
||||
# Extending Binary Analysis
|
||||
|
||||
## Overview
|
||||
|
||||
This guide explains how to add support for new binary formats (PE, Mach-O)
|
||||
or custom section extractors to the binary diff attestation system.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Extractor Interface
|
||||
- ISectionHashExtractor<TConfig>
|
||||
- Registration pattern
|
||||
- Configuration binding
|
||||
|
||||
### Adding a New Format
|
||||
|
||||
#### Step 1: Define Models
|
||||
- Section hash models
|
||||
- Format-specific metadata
|
||||
|
||||
#### Step 2: Implement Extractor
|
||||
- Parse binary format
|
||||
- Extract sections
|
||||
- Compute hashes
|
||||
|
||||
#### Step 3: Register Services
|
||||
- DI registration
|
||||
- Configuration binding
|
||||
- Format detection
|
||||
|
||||
#### Step 4: Add Tests
|
||||
- Unit test fixtures
|
||||
- Golden file comparisons
|
||||
- Edge cases
|
||||
|
||||
### Example: PE Section Extractor
|
||||
|
||||
```csharp
|
||||
public class PeSectionHashExtractor : ISectionHashExtractor<PeConfig>
|
||||
{
|
||||
// Implementation example
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Determinism
|
||||
- Stable ordering
|
||||
- Canonical hashing
|
||||
- Injected dependencies
|
||||
|
||||
### Performance
|
||||
- Streaming large binaries
|
||||
- Caching strategies
|
||||
- Parallel extraction
|
||||
|
||||
### Security
|
||||
- Input validation
|
||||
- Memory limits
|
||||
- Malformed input handling
|
||||
```
|
||||
|
||||
### 5. Usage Examples
|
||||
|
||||
**Directory:** `docs/examples/binary-diff/`
|
||||
|
||||
**Files:**
|
||||
|
||||
```
|
||||
binary-diff/
|
||||
├── README.md # Overview and prerequisites
|
||||
├── basic-comparison.md # Simple diff example
|
||||
├── dsse-attestation.md # DSSE output and verification
|
||||
├── policy-integration.md # Using diffs in policy rules
|
||||
├── ci-cd-integration.md # GitHub Actions / GitLab CI examples
|
||||
└── sample-outputs/
|
||||
├── diff-table.txt # Sample table output
|
||||
├── diff.json # Sample JSON output
|
||||
└── attestation.dsse.json # Sample DSSE envelope
|
||||
```
|
||||
|
||||
## Quality Checklist
|
||||
|
||||
- [ ] All code examples compile/run
|
||||
- [ ] All links are valid
|
||||
- [ ] Consistent terminology with existing docs
|
||||
- [ ] No spelling/grammar errors
|
||||
- [ ] Screenshots/diagrams where helpful
|
||||
- [ ] Cross-references to related docs
|
||||
- [ ] Version compatibility noted
|
||||
|
||||
## Execution Log
|
||||
|
||||
| Date (UTC) | Update | Owner |
|
||||
|------------|--------|-------|
|
||||
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
|
||||
| 2026-01-13 | Completed binary diff docs, examples, glossary entries, and changelog update; refreshed verification guidance. | Docs |
|
||||
|
||||
## Decisions & Risks
|
||||
|
||||
- **APPROVED**: Documentation follows existing StellaOps documentation patterns.
|
||||
- **APPROVED**: JSON Schema published under `docs/schemas/` for external consumption.
|
||||
- **RISK**: Documentation may need updates if implementation details change; defer final review until code complete.
|
||||
|
||||
## Next Checkpoints
|
||||
|
||||
- Task 1-3 complete → Core documentation in place
|
||||
- Task 4-5 complete → Developer and user resources ready
|
||||
- Task 8 complete → Sprint can be marked DONE
|
||||
@@ -0,0 +1,191 @@
|
||||
# Sprint 20260113_002_000 - Index - Image Index Resolution CLI
|
||||
|
||||
## Topic & Scope
|
||||
- Deliver OCI multi-arch image inspection with index and layer enumeration for CLI consumers.
|
||||
- Build an inspector service and CLI command that resolve image indices, manifests, and layers deterministically.
|
||||
- Complete the advisory request for index -> manifest -> layer traversal with Docker and OCI media types.
|
||||
- **Working directory:** `docs/implplan`.
|
||||
|
||||
### Executive Summary
|
||||
This sprint batch implements **OCI multi-arch image inspection** capabilities, enabling users to enumerate image indices, platform manifests, and layer digests through CLI commands. This completes the index -> manifests -> layers flow requested in the OCI Layer-Level Image Integrity advisory.
|
||||
|
||||
**Scope:** OCI image index resolution with Docker and OCI media type support
|
||||
**Effort Estimate:** 4-5 story points across 3 sprints
|
||||
**Priority:** Medium (usability enhancement)
|
||||
|
||||
### Background
|
||||
#### Advisory Requirements
|
||||
The original advisory specified:
|
||||
|
||||
> Resolve an image index (if present), list all platform manifests, then for each manifest list ordered layer digests and sizes. Accept Docker and OCI media types.
|
||||
|
||||
#### Existing Capabilities
|
||||
|
||||
| Component | Status | Location |
|
||||
|-----------|--------|----------|
|
||||
| `OciIndex` record | EXISTS | `src/Concelier/__Libraries/.../OciIndex.cs` |
|
||||
| `OciManifest` record | EXISTS | `src/Concelier/__Libraries/.../OciManifest.cs` |
|
||||
| `OciRegistryClient` | EXISTS | `src/Excititor/__Libraries/.../Fetch/OciRegistryClient.cs` |
|
||||
| `OciImageReferenceParser` | EXISTS | `src/Cli/StellaOps.Cli/Services/OciImageReferenceParser.cs` |
|
||||
| `LayeredRootFileSystem` | EXISTS | `src/Scanner/__Libraries/.../FileSystem/LayeredRootFileSystem.cs` |
|
||||
|
||||
#### Gap Analysis
|
||||
|
||||
| Capability | Status |
|
||||
|------------|--------|
|
||||
| Parse OCI image index from registry | Partial (records exist, no handler) |
|
||||
| Walk index -> platform manifests | MISSING |
|
||||
| CLI `image inspect` verb | MISSING |
|
||||
| JSON output with canonical digests | MISSING |
|
||||
|
||||
### Sprint Index
|
||||
|
||||
| Sprint | ID | Module | Topic | Status | Owner |
|
||||
|--------|-----|--------|-------|--------|-------|
|
||||
| 1 | SPRINT_20260113_002_001 | SCANNER | OCI Image Index Inspector Service | DONE | Guild - Scanner |
|
||||
| 2 | SPRINT_20260113_002_002 | CLI | Image Inspect Command | DONE | Guild - CLI |
|
||||
| 3 | SPRINT_20260113_002_003 | DOCS | Image Inspection Documentation | DONE | Guild - Docs |
|
||||
|
||||
### Acceptance Criteria (Batch-Level)
|
||||
|
||||
#### Must Have
|
||||
1. **Image Index Resolution**
|
||||
- Accept image reference (tag or digest)
|
||||
- Detect and parse image index (multi-arch) vs single manifest
|
||||
- Return platform manifest list with os, arch, and variant
|
||||
|
||||
2. **Layer Enumeration**
|
||||
- For each platform manifest: ordered layer digests
|
||||
- Include layer sizes and media types
|
||||
- Support both Docker and OCI media types
|
||||
|
||||
3. **CLI Command**
|
||||
- `stella image inspect <reference>` with output formats
|
||||
- `--resolve-index` flag to walk multi-arch structure
|
||||
- `--print-layers` flag to include layer details
|
||||
- JSON output with canonical ordering
|
||||
|
||||
4. **Documentation**
|
||||
- CLI reference for new commands
|
||||
- Architecture doc for inspector service
|
||||
|
||||
#### Should Have
|
||||
- Platform filtering (`--platform linux/amd64`)
|
||||
- Config blob inspection (`--config` flag)
|
||||
- Cache manifest responses (in-memory, session-scoped)
|
||||
|
||||
#### Deferred (Out of Scope)
|
||||
- `skopeo` or `ctr` CLI integration (use HTTP API)
|
||||
- Offline image tar inspection (handled by existing LayeredRootFileSystem)
|
||||
- Image pulling and export (out of scope)
|
||||
|
||||
### Technical Context
|
||||
|
||||
#### Key Files to Create or Extend
|
||||
|
||||
| Component | File | Purpose |
|
||||
|-----------|------|---------|
|
||||
| Inspector Service | `src/Scanner/__Libraries/StellaOps.Scanner.Storage.Oci/OciImageInspector.cs` | NEW: Unified index and manifest inspection |
|
||||
| Inspector Models | `src/Scanner/__Libraries/StellaOps.Scanner.Contracts/OciInspectionModels.cs` | NEW: Inspection result models |
|
||||
| CLI Command | `src/Cli/StellaOps.Cli/Commands/ImageCommandGroup.cs` | NEW: `stella image` command group |
|
||||
| CLI Handler | `src/Cli/StellaOps.Cli/Commands/CommandHandlers.Image.cs` | NEW: Image command handlers |
|
||||
|
||||
#### Output Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"reference": "docker.io/library/nginx:latest",
|
||||
"resolvedDigest": "sha256:abc123...",
|
||||
"mediaType": "application/vnd.oci.image.index.v1+json",
|
||||
"isMultiArch": true,
|
||||
"platforms": [
|
||||
{
|
||||
"os": "linux",
|
||||
"architecture": "amd64",
|
||||
"variant": null,
|
||||
"manifestDigest": "sha256:def456...",
|
||||
"configDigest": "sha256:ghi789...",
|
||||
"layers": [
|
||||
{
|
||||
"order": 0,
|
||||
"digest": "sha256:layer1...",
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"size": 31457280
|
||||
}
|
||||
],
|
||||
"totalSize": 157286400
|
||||
}
|
||||
],
|
||||
"inspectedAt": "2026-01-13T12:00:00Z",
|
||||
"inspectorVersion": "1.0.0"
|
||||
}
|
||||
```
|
||||
|
||||
#### Determinism Requirements
|
||||
Per CLAUDE.md Section 8:
|
||||
|
||||
1. **Ordering**: Platforms sorted by os, arch, and variant; layers by order
|
||||
2. **Timestamps**: From injected `TimeProvider`
|
||||
3. **JSON serialization**: Canonical key ordering
|
||||
4. **InvariantCulture**: All size and number formatting
|
||||
|
||||
### Risk Assessment
|
||||
|
||||
| Risk | Likelihood | Impact | Mitigation |
|
||||
|------|------------|--------|------------|
|
||||
| Registry auth complexity | Medium | Medium | Use existing `OciRegistryClient` auth handling |
|
||||
| Rate limiting on public registries | Low | Low | Implement retry with backoff |
|
||||
| Non-standard manifest schemas | Low | Medium | Graceful degradation with warnings |
|
||||
|
||||
### Success Metrics
|
||||
- [ ] All unit tests pass
|
||||
- [ ] Integration tests against Docker Hub, GHCR, and mock registry
|
||||
- [ ] CLI completions and help work correctly
|
||||
- [ ] JSON output is valid and deterministic
|
||||
|
||||
## Dependencies & Concurrency
|
||||
- Sprint 1 is foundational; Sprint 2 depends on the inspector service.
|
||||
- Sprint 3 can proceed in parallel with Sprint 2.
|
||||
- Cross-batch dependencies: none for this batch.
|
||||
- Other 20260113_002_000 planning artifacts are index-only, so parallel edits remain safe.
|
||||
|
||||
```
|
||||
Sprint 1 (Inspector Service)
|
||||
-> Sprint 2 (CLI)
|
||||
Sprint 1 (Inspector Service)
|
||||
-> Sprint 3 (Docs)
|
||||
```
|
||||
|
||||
## Documentation Prerequisites
|
||||
Before starting implementation, reviewers must read:
|
||||
|
||||
- `docs/README.md`
|
||||
- `docs/ARCHITECTURE_REFERENCE.md`
|
||||
- `CLAUDE.md` Section 8 (Code Quality and Determinism Rules)
|
||||
- OCI Image Index Spec: https://github.com/opencontainers/image-spec/blob/main/image-index.md
|
||||
- OCI Image Manifest Spec: https://specs.opencontainers.org/image-spec/manifest/
|
||||
|
||||
## Delivery Tracker
|
||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 1 | INDEX-20260113-002-000-01 | DONE | None | Project Mgmt | Normalize sprint batch index to standard template and ASCII-only formatting. |
|
||||
| 2 | INDEX-20260113-002-000-02 | DONE | None | Project Mgmt | Clarify dependency flow and checkpoint wording without changing scope. |
|
||||
|
||||
## Execution Log
|
||||
| Date (UTC) | Update | Owner |
|
||||
|------------|--------|-------|
|
||||
| 2026-01-13 | Sprint batch created from advisory analysis. | Project Mgmt |
|
||||
| 2026-01-13 | Normalized sprint file to standard template; ASCII-only cleanup; no semantic changes. | Project Mgmt |
|
||||
| 2026-01-13 | Marked Sprint 002_001 (image inspector service) as complete. | Scanner |
|
||||
| 2026-01-13 | Marked Sprint 002_002 (image inspect CLI) as complete. | CLI |
|
||||
| 2026-01-13 | Marked Sprint 002_003 (image inspection docs) as complete. | Docs |
|
||||
|
||||
## Decisions & Risks
|
||||
- **APPROVED 2026-01-13**: Use HTTP Registry API v2 only; no external CLI tool dependencies.
|
||||
- **APPROVED 2026-01-13**: Single-manifest images return as degenerate case (one-element platform list).
|
||||
- **RISK**: Some registries may not support OCI index; handle Docker manifest list as fallback.
|
||||
|
||||
## Next Checkpoints
|
||||
- Sprint 1 completion -> Sprint 2 can start
|
||||
- All sprints complete -> Integration testing checkpoint
|
||||
- Integrate with Batch 001 CLI commands post-completion
|
||||
@@ -0,0 +1,273 @@
|
||||
# Sprint 20260113_002_001_SCANNER - OCI Image Index Inspector Service
|
||||
|
||||
## Topic & Scope
|
||||
|
||||
- Implement unified OCI image inspection service
|
||||
- Support image index (multi-arch) and single manifest resolution
|
||||
- Walk index -> platform manifests -> ordered layers
|
||||
- Support both Docker and OCI media types
|
||||
- **Working directory:** `src/Scanner/__Libraries/StellaOps.Scanner.Storage.Oci/`
|
||||
|
||||
## Dependencies & Concurrency
|
||||
|
||||
- No blocking dependencies (foundational sprint)
|
||||
- Uses existing `OciRegistryClient` for HTTP operations
|
||||
- Sprint 2 (CLI) depends on this sprint
|
||||
|
||||
## Documentation Prerequisites
|
||||
|
||||
- `docs/README.md`
|
||||
- `docs/ARCHITECTURE_REFERENCE.md`
|
||||
- `CLAUDE.md` Section 8 (Determinism Rules)
|
||||
- OCI Image Index Spec: https://github.com/opencontainers/image-spec/blob/main/image-index.md
|
||||
- OCI Image Manifest Spec: https://specs.opencontainers.org/image-spec/manifest/
|
||||
- Docker Manifest List: https://docs.docker.com/registry/spec/manifest-v2-2/
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||
|---|---------|--------|---------------------------|--------|-----------------|
|
||||
| 1 | IMG-INSPECT-MODELS-0001 | DONE | None | Guild - Scanner | Define `ImageInspectionResult`, `PlatformManifest`, `LayerInfo` models in `src/Scanner/__Libraries/StellaOps.Scanner.Contracts/OciInspectionModels.cs`. Include all OCI/Docker discriminators. |
|
||||
| 2 | IMG-INSPECT-INTERFACE-0001 | DONE | Depends on MODELS-0001 | Guild - Scanner | Define `IOciImageInspector` interface with `InspectAsync(reference, options, ct)` signature. Options include: resolveIndex, includeLayers, platformFilter. |
|
||||
| 3 | IMG-INSPECT-IMPL-0001 | DONE | Depends on INTERFACE-0001 | Guild - Scanner | Implement `OciImageInspector` class. Handle HEAD request for manifest detection, then GET for content. Detect index vs manifest by media type. |
|
||||
| 4 | IMG-INSPECT-INDEX-0001 | DONE | Depends on IMPL-0001 | Guild - Scanner | Implement index resolution: parse `application/vnd.oci.image.index.v1+json` and `application/vnd.docker.distribution.manifest.list.v2+json`. Extract platform descriptors. |
|
||||
| 5 | IMG-INSPECT-MANIFEST-0001 | DONE | Depends on IMPL-0001 | Guild - Scanner | Implement manifest parsing: `application/vnd.oci.image.manifest.v1+json` and `application/vnd.docker.distribution.manifest.v2+json`. Extract config and layers. |
|
||||
| 6 | IMG-INSPECT-LAYERS-0001 | DONE | Depends on MANIFEST-0001 | Guild - Scanner | For each manifest, enumerate layers with: order (0-indexed), digest, mediaType, size. Support compressed and uncompressed variants. |
|
||||
| 7 | IMG-INSPECT-AUTH-0001 | DONE | Depends on IMPL-0001 | Guild - Scanner | Integrate with existing registry auth: token-based, basic, anonymous. Handle 401 -> token refresh flow. |
|
||||
| 8 | IMG-INSPECT-DI-0001 | DONE | Depends on all above | Guild - Scanner | Register `IOciImageInspector` in `ServiceCollectionExtensions.cs`. Inject `TimeProvider`, `IHttpClientFactory`, `ILogger`. |
|
||||
| 9 | IMG-INSPECT-TESTS-0001 | DONE | Depends on all above | Guild - Scanner | Unit tests covering: single manifest, multi-arch index, Docker manifest list, missing manifest, auth errors, malformed responses. |
|
||||
| 10 | IMG-INSPECT-INTEGRATION-0001 | DONE | Depends on TESTS-0001 | Guild - Scanner | Integration tests against mock OCI registry (testcontainers or in-memory). Test real Docker Hub and GHCR in CI. |
|
||||
|
||||
## Technical Specification
|
||||
|
||||
### Models
|
||||
|
||||
```csharp
|
||||
namespace StellaOps.Scanner.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Result of inspecting an OCI image reference.
|
||||
/// </summary>
|
||||
public sealed record ImageInspectionResult
|
||||
{
|
||||
/// <summary>Original image reference provided.</summary>
|
||||
public required string Reference { get; init; }
|
||||
|
||||
/// <summary>Resolved digest of the index or manifest.</summary>
|
||||
public required string ResolvedDigest { get; init; }
|
||||
|
||||
/// <summary>Media type of the resolved artifact.</summary>
|
||||
public required string MediaType { get; init; }
|
||||
|
||||
/// <summary>True if this is a multi-arch image index.</summary>
|
||||
public required bool IsMultiArch { get; init; }
|
||||
|
||||
/// <summary>Platform manifests (1 for single-arch, N for multi-arch).</summary>
|
||||
public required ImmutableArray<PlatformManifest> Platforms { get; init; }
|
||||
|
||||
/// <summary>Inspection timestamp (UTC).</summary>
|
||||
public required DateTimeOffset InspectedAt { get; init; }
|
||||
|
||||
/// <summary>Inspector version for reproducibility.</summary>
|
||||
public required string InspectorVersion { get; init; }
|
||||
|
||||
/// <summary>Registry that was queried.</summary>
|
||||
public required string Registry { get; init; }
|
||||
|
||||
/// <summary>Repository name.</summary>
|
||||
public required string Repository { get; init; }
|
||||
|
||||
/// <summary>Warnings encountered during inspection.</summary>
|
||||
public ImmutableArray<string> Warnings { get; init; } = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A platform-specific manifest within an image index.
|
||||
/// </summary>
|
||||
public sealed record PlatformManifest
|
||||
{
|
||||
/// <summary>Operating system (e.g., "linux", "windows").</summary>
|
||||
public required string Os { get; init; }
|
||||
|
||||
/// <summary>CPU architecture (e.g., "amd64", "arm64").</summary>
|
||||
public required string Architecture { get; init; }
|
||||
|
||||
/// <summary>Architecture variant (e.g., "v8" for arm64).</summary>
|
||||
public string? Variant { get; init; }
|
||||
|
||||
/// <summary>OS version (mainly for Windows).</summary>
|
||||
public string? OsVersion { get; init; }
|
||||
|
||||
/// <summary>Digest of this platform's manifest.</summary>
|
||||
public required string ManifestDigest { get; init; }
|
||||
|
||||
/// <summary>Media type of the manifest.</summary>
|
||||
public required string ManifestMediaType { get; init; }
|
||||
|
||||
/// <summary>Digest of the config blob.</summary>
|
||||
public required string ConfigDigest { get; init; }
|
||||
|
||||
/// <summary>Ordered list of layers.</summary>
|
||||
public required ImmutableArray<LayerInfo> Layers { get; init; }
|
||||
|
||||
/// <summary>Total size of all layers in bytes.</summary>
|
||||
public required long TotalSize { get; init; }
|
||||
|
||||
/// <summary>Platform string (os/arch/variant).</summary>
|
||||
public string PlatformString => Variant is null
|
||||
? $"{Os}/{Architecture}"
|
||||
: $"{Os}/{Architecture}/{Variant}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Information about a single layer.
|
||||
/// </summary>
|
||||
public sealed record LayerInfo
|
||||
{
|
||||
/// <summary>Layer order (0-indexed, application order).</summary>
|
||||
public required int Order { get; init; }
|
||||
|
||||
/// <summary>Layer digest (sha256:...).</summary>
|
||||
public required string Digest { get; init; }
|
||||
|
||||
/// <summary>Media type of the layer blob.</summary>
|
||||
public required string MediaType { get; init; }
|
||||
|
||||
/// <summary>Compressed size in bytes.</summary>
|
||||
public required long Size { get; init; }
|
||||
|
||||
/// <summary>Optional annotations from the manifest.</summary>
|
||||
public ImmutableDictionary<string, string>? Annotations { get; init; }
|
||||
}
|
||||
```
|
||||
|
||||
### Interface
|
||||
|
||||
```csharp
|
||||
namespace StellaOps.Scanner.Storage.Oci;
|
||||
|
||||
public interface IOciImageInspector
|
||||
{
|
||||
/// <summary>
|
||||
/// Inspects an OCI image reference.
|
||||
/// </summary>
|
||||
/// <param name="reference">Image reference (e.g., "nginx:latest", "ghcr.io/org/app@sha256:...").</param>
|
||||
/// <param name="options">Inspection options.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Inspection result or null if not found.</returns>
|
||||
Task<ImageInspectionResult?> InspectAsync(
|
||||
string reference,
|
||||
ImageInspectionOptions? options = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public sealed record ImageInspectionOptions
|
||||
{
|
||||
/// <summary>Resolve multi-arch index to platform manifests (default: true).</summary>
|
||||
public bool ResolveIndex { get; init; } = true;
|
||||
|
||||
/// <summary>Include layer details (default: true).</summary>
|
||||
public bool IncludeLayers { get; init; } = true;
|
||||
|
||||
/// <summary>Filter to specific platform (e.g., "linux/amd64").</summary>
|
||||
public string? PlatformFilter { get; init; }
|
||||
|
||||
/// <summary>Maximum platforms to inspect (default: unlimited).</summary>
|
||||
public int? MaxPlatforms { get; init; }
|
||||
|
||||
/// <summary>Request timeout.</summary>
|
||||
public TimeSpan? Timeout { get; init; }
|
||||
}
|
||||
```
|
||||
|
||||
### Media Type Handling
|
||||
|
||||
| Media Type | Type | Handling |
|
||||
|------------|------|----------|
|
||||
| `application/vnd.oci.image.index.v1+json` | OCI Index | Parse as index, enumerate manifests |
|
||||
| `application/vnd.docker.distribution.manifest.list.v2+json` | Docker List | Parse as index (compatible) |
|
||||
| `application/vnd.oci.image.manifest.v1+json` | OCI Manifest | Parse as manifest, extract layers |
|
||||
| `application/vnd.docker.distribution.manifest.v2+json` | Docker Manifest | Parse as manifest (compatible) |
|
||||
| Other | Unknown | Return warning, skip or fail per config |
|
||||
|
||||
### Algorithm
|
||||
|
||||
```pseudo
|
||||
function InspectAsync(reference, options):
|
||||
parsed = ParseReference(reference) // registry, repo, tag/digest
|
||||
|
||||
// Step 1: Resolve to digest
|
||||
digest = HEAD(registry, repo, parsed.tagOrDigest)
|
||||
mediaType = response.headers["Content-Type"]
|
||||
|
||||
// Step 2: Get manifest content
|
||||
body = GET(registry, repo, digest, Accept: mediaType)
|
||||
|
||||
// Step 3: Classify and parse
|
||||
if mediaType in [OCI_INDEX, DOCKER_MANIFEST_LIST]:
|
||||
index = ParseIndex(body)
|
||||
platforms = []
|
||||
for descriptor in index.manifests:
|
||||
if options.platformFilter and not matches(descriptor, filter):
|
||||
continue
|
||||
manifest = await InspectManifest(registry, repo, descriptor.digest)
|
||||
platforms.append(manifest)
|
||||
return Result(isMultiArch=true, platforms)
|
||||
else:
|
||||
manifest = ParseManifest(body)
|
||||
platform = ExtractPlatform(manifest.config)
|
||||
layers = ExtractLayers(manifest)
|
||||
return Result(isMultiArch=false, [platform])
|
||||
```
|
||||
|
||||
### Determinism Requirements
|
||||
|
||||
1. **Platform ordering**: Sort by os ASC, architecture ASC, variant ASC
|
||||
2. **Layer ordering**: Preserve manifest order (0-indexed)
|
||||
3. **Timestamps**: From injected `TimeProvider`
|
||||
4. **JSON**: Canonical serialization for any digest computation
|
||||
5. **Warnings**: Sorted lexicographically
|
||||
|
||||
## Test Cases
|
||||
|
||||
### Unit Tests
|
||||
|
||||
| Test | Description | Expected |
|
||||
|------|-------------|----------|
|
||||
| `Inspect_SingleManifest_ReturnsSinglePlatform` | Image without index | 1 platform, layers present |
|
||||
| `Inspect_MultiArchIndex_ReturnsAllPlatforms` | Image with 5 platforms | 5 platforms, each with layers |
|
||||
| `Inspect_DockerManifestList_Parses` | Legacy Docker format | Correctly parsed as index |
|
||||
| `Inspect_PlatformFilter_ReturnsFiltered` | Filter to linux/amd64 | Only matching platform returned |
|
||||
| `Inspect_NotFound_ReturnsNull` | 404 response | Returns null, no exception |
|
||||
| `Inspect_AuthRequired_RefreshesToken` | 401 -> token refresh | Successful after refresh |
|
||||
| `Inspect_Deterministic_SameOutput` | Same image, multiple calls | Identical result (ignoring timestamp) |
|
||||
|
||||
### Integration Tests
|
||||
|
||||
| Test | Description | Expected |
|
||||
|------|-------------|----------|
|
||||
| `Inspect_DockerHub_NginxLatest` | Public Docker Hub image | Multi-arch result with linux/amd64, linux/arm64 |
|
||||
| `Inspect_GHCR_PublicImage` | GitHub Container Registry | Valid result |
|
||||
| `Inspect_MockRegistry_AllScenarios` | Testcontainers registry | All edge cases covered |
|
||||
|
||||
## Execution Log
|
||||
|
||||
| Date (UTC) | Update | Owner |
|
||||
|------------|--------|-------|
|
||||
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
|
||||
| 2026-01-13 | Completed OCI image inspector models, service, DI, and tests. | Scanner |
|
||||
|
||||
## Decisions & Risks
|
||||
|
||||
- **APPROVED**: Single manifest images return as 1-element platforms array for API consistency.
|
||||
- **APPROVED**: Use existing `OciRegistryClient` for HTTP operations where compatible.
|
||||
- **RISK**: Some registries return incorrect Content-Type; handle by sniffing JSON structure.
|
||||
- **RISK**: Large multi-arch images (10+ platforms) may be slow; add max_platforms limit.
|
||||
- **RISK**: Live registry tests (Docker Hub/GHCR) are not included; local registry integration tests cover offline needs.
|
||||
|
||||
## Next Checkpoints
|
||||
|
||||
- Task 1-3 complete -> Basic inspection working
|
||||
- Task 4-6 complete -> Full index/manifest/layer resolution
|
||||
- Task 9-10 complete -> Sprint can be marked DONE
|
||||
- Unblock Sprint 2 (CLI)
|
||||
@@ -0,0 +1,284 @@
|
||||
# Sprint 20260113_002_002_CLI - Image Inspect Command
|
||||
|
||||
## Topic & Scope
|
||||
|
||||
- Implement `stella image inspect` CLI command
|
||||
- Support `--resolve-index`, `--print-layers`, `--platform` flags
|
||||
- JSON and human-readable output formats
|
||||
- Integrate with OCI Image Inspector service
|
||||
- **Working directory:** `src/Cli/StellaOps.Cli/Commands/`
|
||||
|
||||
## Dependencies & Concurrency
|
||||
|
||||
- **Depends on:** Sprint 002_001 (OCI Image Inspector Service)
|
||||
- Parallel work safe within CLI module
|
||||
- Sprint 3 (Docs) can proceed in parallel
|
||||
|
||||
## Documentation Prerequisites
|
||||
|
||||
- `docs/README.md`
|
||||
- `CLAUDE.md` Section 8 (Determinism Rules)
|
||||
- `src/Cli/StellaOps.Cli/AGENTS.md` (if exists)
|
||||
- Existing CLI patterns in `LayerSbomCommandGroup.cs`
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||
|---|---------|--------|---------------------------|--------|-----------------|
|
||||
| 1 | CLI-IMAGE-GROUP-0001 | DONE | None | Guild - CLI | Create `ImageCommandGroup.cs` with `stella image` root command and subcommand registration. |
|
||||
| 2 | CLI-IMAGE-INSPECT-0001 | DONE | Depends on GROUP-0001 | Guild - CLI | Implement `stella image inspect <reference>` command with options: `--resolve-index`, `--print-layers`, `--platform`, `--output`. |
|
||||
| 3 | CLI-IMAGE-HANDLER-0001 | DONE | Depends on INSPECT-0001, Sprint 001 service | Guild - CLI | Implement `CommandHandlers.Image.cs` with `HandleInspectImageAsync` that calls `IOciImageInspector`. |
|
||||
| 4 | CLI-IMAGE-OUTPUT-TABLE-0001 | DONE | Depends on HANDLER-0001 | Guild - CLI | Implement table output for human-readable display using Spectre.Console. Show platforms, layers, sizes. |
|
||||
| 5 | CLI-IMAGE-OUTPUT-JSON-0001 | DONE | Depends on HANDLER-0001 | Guild - CLI | Implement JSON output with canonical ordering. Match schema from Sprint 001 models. |
|
||||
| 6 | CLI-IMAGE-REGISTER-0001 | DONE | Depends on all above | Guild - CLI | Register `ImageCommandGroup` in `CommandFactory.cs`. Wire DI for `IOciImageInspector`. |
|
||||
| 7 | CLI-IMAGE-TESTS-0001 | DONE | Depends on all above | Guild - CLI | Unit tests covering: successful inspect, not found, auth error, invalid reference, output formats. |
|
||||
| 8 | CLI-IMAGE-GOLDEN-0001 | DONE | Depends on TESTS-0001 | Guild - CLI | Golden output tests for determinism: same input produces identical output across runs. |
|
||||
|
||||
## Technical Specification
|
||||
|
||||
### Command Structure
|
||||
|
||||
```
|
||||
stella image <subcommand>
|
||||
|
||||
Subcommands:
|
||||
inspect Inspect OCI image manifest and layers
|
||||
```
|
||||
|
||||
### `stella image inspect` Command
|
||||
|
||||
```
|
||||
stella image inspect <reference> [options]
|
||||
|
||||
Arguments:
|
||||
<reference> Image reference (e.g., nginx:latest, ghcr.io/org/app@sha256:...)
|
||||
|
||||
Options:
|
||||
--resolve-index, -r Resolve multi-arch index to platform manifests (default: true)
|
||||
--print-layers, -l Include layer details in output (default: true)
|
||||
--platform, -p Filter to specific platform (e.g., linux/amd64)
|
||||
--output, -o Output format: table (default), json
|
||||
--verbose, -v Show detailed information including warnings
|
||||
--timeout Request timeout in seconds (default: 60)
|
||||
|
||||
Examples:
|
||||
stella image inspect nginx:latest
|
||||
stella image inspect nginx:latest --output json
|
||||
stella image inspect nginx:latest --platform linux/arm64
|
||||
stella image inspect ghcr.io/org/app@sha256:abc123... --print-layers
|
||||
```
|
||||
|
||||
### Output Examples
|
||||
|
||||
#### Table Output (Default)
|
||||
|
||||
```
|
||||
Image: nginx:latest
|
||||
Resolved Digest: sha256:abc123...
|
||||
Media Type: application/vnd.oci.image.index.v1+json
|
||||
Multi-Arch: Yes (5 platforms)
|
||||
|
||||
Platforms:
|
||||
+-------+--------------+----------+---------+---------------+------------+
|
||||
| OS | Architecture | Variant | Layers | Total Size | Manifest |
|
||||
+-------+--------------+----------+---------+---------------+------------+
|
||||
| linux | amd64 | - | 7 | 142.3 MB | sha256:... |
|
||||
| linux | arm64 | v8 | 7 | 138.1 MB | sha256:... |
|
||||
| linux | arm | v7 | 7 | 135.2 MB | sha256:... |
|
||||
| linux | 386 | - | 7 | 145.8 MB | sha256:... |
|
||||
| linux | ppc64le | - | 7 | 148.5 MB | sha256:... |
|
||||
+-------+--------------+----------+---------+---------------+------------+
|
||||
|
||||
Layers (linux/amd64):
|
||||
+-------+------------------+------------------------------------------------+----------+
|
||||
| Order | Size | Digest | Type |
|
||||
+-------+------------------+------------------------------------------------+----------+
|
||||
| 0 | 31.4 MB | sha256:a803e7c4b030... | tar+gzip |
|
||||
| 1 | 62.5 MB | sha256:8a6e7b1c9d2e... | tar+gzip |
|
||||
| ... | ... | ... | ... |
|
||||
+-------+------------------+------------------------------------------------+----------+
|
||||
|
||||
Inspected at: 2026-01-13T12:00:00Z
|
||||
```
|
||||
|
||||
#### JSON Output
|
||||
|
||||
```json
|
||||
{
|
||||
"reference": "nginx:latest",
|
||||
"resolvedDigest": "sha256:abc123...",
|
||||
"mediaType": "application/vnd.oci.image.index.v1+json",
|
||||
"isMultiArch": true,
|
||||
"registry": "docker.io",
|
||||
"repository": "library/nginx",
|
||||
"platforms": [
|
||||
{
|
||||
"os": "linux",
|
||||
"architecture": "amd64",
|
||||
"variant": null,
|
||||
"manifestDigest": "sha256:def456...",
|
||||
"configDigest": "sha256:ghi789...",
|
||||
"layers": [
|
||||
{
|
||||
"order": 0,
|
||||
"digest": "sha256:layer1...",
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"size": 31457280
|
||||
}
|
||||
],
|
||||
"totalSize": 157286400
|
||||
}
|
||||
],
|
||||
"inspectedAt": "2026-01-13T12:00:00Z",
|
||||
"inspectorVersion": "1.0.0"
|
||||
}
|
||||
```
|
||||
|
||||
### Implementation
|
||||
|
||||
```csharp
|
||||
// ImageCommandGroup.cs
|
||||
namespace StellaOps.Cli.Commands;
|
||||
|
||||
public static class ImageCommandGroup
|
||||
{
|
||||
public static Command Build(
|
||||
IServiceProvider services,
|
||||
StellaOpsCliOptions options,
|
||||
Option<bool> verboseOption,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var imageCommand = new Command("image", "OCI image operations");
|
||||
|
||||
imageCommand.AddCommand(BuildInspectCommand(services, options, verboseOption, cancellationToken));
|
||||
|
||||
return imageCommand;
|
||||
}
|
||||
|
||||
private static Command BuildInspectCommand(
|
||||
IServiceProvider services,
|
||||
StellaOpsCliOptions options,
|
||||
Option<bool> verboseOption,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var referenceArg = new Argument<string>("reference")
|
||||
{
|
||||
Description = "Image reference (e.g., nginx:latest, ghcr.io/org/app@sha256:...)"
|
||||
};
|
||||
|
||||
var resolveIndexOption = new Option<bool>("--resolve-index", new[] { "-r" })
|
||||
{
|
||||
Description = "Resolve multi-arch index to platform manifests",
|
||||
DefaultValue = true
|
||||
};
|
||||
|
||||
var printLayersOption = new Option<bool>("--print-layers", new[] { "-l" })
|
||||
{
|
||||
Description = "Include layer details in output",
|
||||
DefaultValue = true
|
||||
};
|
||||
|
||||
var platformOption = new Option<string?>("--platform", new[] { "-p" })
|
||||
{
|
||||
Description = "Filter to specific platform (e.g., linux/amd64)"
|
||||
};
|
||||
|
||||
var outputOption = new Option<string>("--output", new[] { "-o" })
|
||||
{
|
||||
Description = "Output format: table (default), json"
|
||||
};
|
||||
|
||||
var timeoutOption = new Option<int>("--timeout")
|
||||
{
|
||||
Description = "Request timeout in seconds",
|
||||
DefaultValue = 60
|
||||
};
|
||||
|
||||
var inspect = new Command("inspect", "Inspect OCI image manifest and layers")
|
||||
{
|
||||
referenceArg,
|
||||
resolveIndexOption,
|
||||
printLayersOption,
|
||||
platformOption,
|
||||
outputOption,
|
||||
timeoutOption,
|
||||
verboseOption
|
||||
};
|
||||
|
||||
inspect.SetAction(async (parseResult, _) =>
|
||||
{
|
||||
var reference = parseResult.GetValue(referenceArg) ?? string.Empty;
|
||||
var resolveIndex = parseResult.GetValue(resolveIndexOption);
|
||||
var printLayers = parseResult.GetValue(printLayersOption);
|
||||
var platform = parseResult.GetValue(platformOption);
|
||||
var output = parseResult.GetValue(outputOption) ?? "table";
|
||||
var timeout = parseResult.GetValue(timeoutOption);
|
||||
var verbose = parseResult.GetValue(verboseOption);
|
||||
|
||||
return await CommandHandlers.HandleInspectImageAsync(
|
||||
services, reference, resolveIndex, printLayers,
|
||||
platform, output, timeout, verbose, cancellationToken);
|
||||
});
|
||||
|
||||
return inspect;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
| Scenario | Exit Code | Message |
|
||||
|----------|-----------|---------|
|
||||
| Success | 0 | (output) |
|
||||
| Image not found | 1 | `Error: Image not found: <reference>` |
|
||||
| Auth required | 2 | `Error: Authentication required for <registry>` |
|
||||
| Invalid reference | 2 | `Error: Invalid image reference: <reference>` |
|
||||
| Network error | 2 | `Error: Network error: <message>` |
|
||||
| Timeout | 2 | `Error: Request timed out` |
|
||||
|
||||
### Determinism Requirements
|
||||
|
||||
1. **Ordering**: JSON keys sorted; platforms sorted by os/arch/variant
|
||||
2. **Size formatting**: Use InvariantCulture for all numbers
|
||||
3. **Timestamps**: Display as UTC ISO-8601
|
||||
4. **Digest truncation**: Consistent truncation (e.g., first 12 chars for display)
|
||||
|
||||
## Test Cases
|
||||
|
||||
### Unit Tests
|
||||
|
||||
| Test | Description | Expected |
|
||||
|------|-------------|----------|
|
||||
| `Inspect_ValidReference_ReturnsSuccess` | Mock successful inspection | Exit code 0, valid output |
|
||||
| `Inspect_NotFound_ReturnsError` | 404 from registry | Exit code 1, error message |
|
||||
| `Inspect_InvalidReference_ReturnsError` | Malformed reference | Exit code 2, validation error |
|
||||
| `Inspect_JsonOutput_ValidJson` | Request JSON format | Parseable JSON output |
|
||||
| `Inspect_TableOutput_FormatsCorrectly` | Default table format | Table with headers and rows |
|
||||
| `Inspect_PlatformFilter_FiltersResults` | Filter to linux/amd64 | Only matching platform in output |
|
||||
|
||||
### Golden Output Tests
|
||||
|
||||
| Test | Description | Expected |
|
||||
|------|-------------|----------|
|
||||
| `Inspect_Json_Deterministic` | Same input, multiple runs | Byte-identical JSON |
|
||||
| `Inspect_Table_Deterministic` | Same input, multiple runs | Identical table output |
|
||||
|
||||
## Execution Log
|
||||
|
||||
| Date (UTC) | Update | Owner |
|
||||
|------------|--------|-------|
|
||||
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
|
||||
| 2026-01-13 | Implemented image inspect command, handlers, DI, and tests. | CLI |
|
||||
|
||||
## Decisions & Risks
|
||||
|
||||
- **APPROVED**: Table output as default (more user-friendly).
|
||||
- **APPROVED**: JSON output matches service model exactly (no transformation).
|
||||
- **RISK**: CLI tests may conflict with other agent work; coordinate ownership.
|
||||
- **RISK**: Table formatting may truncate long digests; use consistent truncation.
|
||||
|
||||
## Next Checkpoints
|
||||
|
||||
- Task 1-3 complete -> Basic command working
|
||||
- Task 4-5 complete -> Both output formats working
|
||||
- Task 7-8 complete -> Sprint can be marked DONE
|
||||
@@ -0,0 +1,103 @@
|
||||
# Sprint 20260113_002_003_DOCS - Image Inspection Documentation
|
||||
|
||||
## Topic & Scope
|
||||
|
||||
- Document OCI Image Inspector architecture
|
||||
- Create CLI reference for `stella image inspect`
|
||||
- Add usage examples and troubleshooting guide
|
||||
- **Working directory:** `docs/`
|
||||
|
||||
## Dependencies & Concurrency
|
||||
|
||||
- Can proceed in parallel with Sprint 002_002
|
||||
- Should finalize after Sprint 002_001 models are stable
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||
|---|---------|--------|---------------------------|--------|-----------------|
|
||||
| 1 | DOCS-IMAGE-ARCH-0001 | DONE | Sprint 001 complete | Guild - Docs | Create `docs/modules/scanner/image-inspection.md` documenting the OCI Image Inspector service architecture, supported media types, and integration points. |
|
||||
| 2 | DOCS-IMAGE-CLI-0001 | DONE | Sprint 002 complete | Guild - Docs | Add `stella image inspect` to CLI reference in `docs/API_CLI_REFERENCE.md`. Include all options, examples, and exit codes. |
|
||||
| 3 | DOCS-IMAGE-EXAMPLES-0001 | DONE | Depends on CLI-0001 | Guild - Docs | Create practical usage examples in `docs/guides/image-inspection-guide.md` covering Docker Hub, GHCR, private registries, and CI/CD integration. |
|
||||
| 4 | DOCS-IMAGE-TROUBLESHOOT-0001 | DONE | Depends on EXAMPLES-0001 | Guild - Docs | Add troubleshooting section for common issues: auth failures, rate limits, unsupported media types. |
|
||||
|
||||
## Technical Specification
|
||||
|
||||
### Architecture Documentation Outline
|
||||
|
||||
```markdown
|
||||
# OCI Image Inspection
|
||||
|
||||
## Overview
|
||||
- Purpose and use cases
|
||||
- Supported registries and media types
|
||||
|
||||
## Architecture
|
||||
- IOciImageInspector interface
|
||||
- Index vs manifest resolution flow
|
||||
- Platform enumeration algorithm
|
||||
|
||||
## Media Type Support
|
||||
| Media Type | Description | Support |
|
||||
|------------|-------------|---------|
|
||||
| ... | ... | ... |
|
||||
|
||||
## Integration Points
|
||||
- CLI integration
|
||||
- Programmatic usage
|
||||
- Webhook/CI integration
|
||||
|
||||
## Configuration
|
||||
- Registry authentication
|
||||
- Timeout and retry settings
|
||||
|
||||
## Determinism
|
||||
- Output ordering guarantees
|
||||
- Reproducibility considerations
|
||||
```
|
||||
|
||||
### CLI Reference Addition
|
||||
|
||||
```markdown
|
||||
## stella image inspect
|
||||
|
||||
Inspect OCI image manifest and layers.
|
||||
|
||||
### Synopsis
|
||||
stella image inspect <reference> [options]
|
||||
|
||||
### Arguments
|
||||
| Argument | Description |
|
||||
|----------|-------------|
|
||||
| reference | Image reference (tag or digest) |
|
||||
|
||||
### Options
|
||||
| Option | Description | Default |
|
||||
|--------|-------------|---------|
|
||||
| --resolve-index, -r | Resolve multi-arch index | true |
|
||||
| --print-layers, -l | Include layer details | true |
|
||||
| --platform, -p | Platform filter | (all) |
|
||||
| --output, -o | Output format (table, json) | table |
|
||||
|
||||
### Examples
|
||||
...
|
||||
|
||||
### Exit Codes
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 0 | Success |
|
||||
| 1 | Image not found |
|
||||
| 2 | Error (auth, network, invalid input) |
|
||||
```
|
||||
|
||||
## Execution Log
|
||||
|
||||
| Date (UTC) | Update | Owner |
|
||||
|------------|--------|-------|
|
||||
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
|
||||
| 2026-01-13 | Added image inspection architecture, CLI reference, and guide with troubleshooting. | Docs |
|
||||
|
||||
## Next Checkpoints
|
||||
|
||||
- All tasks complete -> Sprint can be marked DONE
|
||||
- Coordinate with Sprint 002_001/002 for accuracy
|
||||
@@ -0,0 +1,227 @@
|
||||
# Sprint 20260113_003_000 - Index - VEX Evidence Auto-Linking
|
||||
|
||||
## Topic & Scope
|
||||
- Implement automatic linking between VEX exploitability decisions and DSSE binary-diff evidence bundles.
|
||||
- Extend Excititor and CLI output to surface evidence URIs and metadata in CycloneDX VEX.
|
||||
- Complete the evidence chain from binary diff attestations to VEX analysis details.
|
||||
- **Working directory:** `docs/implplan`.
|
||||
|
||||
### Executive Summary
|
||||
This sprint batch implements **automatic linking** between VEX exploitability status and DSSE binary-diff evidence bundles. When a binary analysis determines a vulnerability is "not_affected" due to a vendor backport, the system automatically links the VEX assertion to the cryptographic evidence that proves the claim.
|
||||
|
||||
**Scope:** VEX-to-evidence linking for binary-diff attestations
|
||||
**Effort Estimate:** 3-4 story points across 2 sprints
|
||||
**Priority:** Medium (completes evidence chain)
|
||||
|
||||
### Background
|
||||
#### Advisory Requirements
|
||||
The original advisory specified:
|
||||
|
||||
> Surface exploitability conclusions via CycloneDX VEX (e.g., "CVE-X.Y not affected due to backported fix; evidence -> DSSE bundle link").
|
||||
|
||||
> For each CVE in SBOM components, attach exploitability status with `analysis.justification` ("component_not_present", "vulnerable_code_not_in_execute_path", "fixed", etc.) and `analysis.detail` linking the DSSE evidence URI.
|
||||
|
||||
#### Existing Capabilities
|
||||
|
||||
| Component | Status | Location |
|
||||
|-----------|--------|----------|
|
||||
| `VexPredicate` | EXISTS | `src/Attestor/__Libraries/.../Predicates/VexPredicate.cs` |
|
||||
| `VexDeltaEntity` | EXISTS | `src/Excititor/__Libraries/.../Observations/VexDeltaModels.cs` |
|
||||
| `CycloneDxExporter` | EXISTS | `src/Excititor/__Libraries/.../CycloneDxExporter.cs` |
|
||||
| `BinaryDiffV1 Predicate` | IN PROGRESS | Batch 001 Sprint 002 |
|
||||
| `BinaryDiffDsseSigner` | IN PROGRESS | Batch 001 Sprint 002 |
|
||||
|
||||
#### Gap Analysis
|
||||
|
||||
| Capability | Status |
|
||||
|------------|--------|
|
||||
| Store DSSE bundle URIs with VEX assertions | MISSING |
|
||||
| Auto-link binary-diff evidence to VEX | MISSING |
|
||||
| Emit `analysis.detail` with evidence URI in CycloneDX VEX | MISSING |
|
||||
| CLI `stella vex gen` with evidence links | PARTIAL |
|
||||
|
||||
### Sprint Index
|
||||
|
||||
| Sprint | ID | Module | Topic | Status | Owner |
|
||||
|--------|-----|--------|-------|--------|-------|
|
||||
| 1 | SPRINT_20260113_003_001 | EXCITITOR | VEX Evidence Linker Service | DONE | Guild - Excititor |
|
||||
| 2 | SPRINT_20260113_003_002 | CLI | VEX Generation with Evidence Links | DONE | Guild - CLI |
|
||||
|
||||
### Acceptance Criteria (Batch-Level)
|
||||
|
||||
#### Must Have
|
||||
1. **Evidence URI Storage**
|
||||
- Store DSSE bundle URIs alongside VEX assertions
|
||||
- Support multiple evidence sources per VEX entry
|
||||
- URIs point to OCI artifact digests or CAS addresses
|
||||
|
||||
2. **Auto-Link on Binary Diff**
|
||||
- When binary diff detects "patched" verdict, create VEX link
|
||||
- Link includes: DSSE envelope digest, predicate type, confidence score
|
||||
- Justification auto-set to "vulnerable_code_not_in_execute_path" or "code_not_reachable"
|
||||
|
||||
3. **CycloneDX VEX Output**
|
||||
- `analysis.detail` contains evidence URI
|
||||
- `analysis.response` includes evidence metadata
|
||||
- Compatible with CycloneDX VEX 1.5+ schema
|
||||
|
||||
4. **CLI Integration**
|
||||
- `stella vex gen` includes `--link-evidence` flag
|
||||
- JSON output contains evidence links
|
||||
- Human-readable output shows evidence summary
|
||||
|
||||
#### Should Have
|
||||
- Confidence threshold filtering (only link if confidence >= X)
|
||||
- Evidence chain validation (verify DSSE before linking)
|
||||
|
||||
#### Deferred (Out of Scope)
|
||||
- UI for evidence visualization (follow-up sprint)
|
||||
- Evidence refresh and update workflow
|
||||
- Third-party evidence import
|
||||
|
||||
### Technical Context
|
||||
|
||||
#### Key Files to Create or Extend
|
||||
|
||||
| Component | File | Purpose |
|
||||
|-----------|------|---------|
|
||||
| Evidence Linker | `src/Excititor/__Libraries/StellaOps.Excititor.Core/Evidence/VexEvidenceLinker.cs` | NEW: Service to link VEX -> DSSE |
|
||||
| Evidence Models | `src/Excititor/__Libraries/StellaOps.Excititor.Core/Evidence/VexEvidenceLinkModels.cs` | NEW: Link models |
|
||||
| CycloneDX Mapper | `src/Excititor/__Libraries/.../CycloneDxVexMapper.cs` | EXTEND: Add evidence links |
|
||||
| CLI Handler | `src/Cli/StellaOps.Cli/Commands/VexGenCommandGroup.cs` | EXTEND: Add evidence option |
|
||||
|
||||
#### VEX with Evidence Link Schema (CycloneDX)
|
||||
|
||||
```json
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.6",
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"id": "CVE-2023-12345",
|
||||
"source": { "name": "NVD" },
|
||||
"analysis": {
|
||||
"state": "not_affected",
|
||||
"justification": "code_not_reachable",
|
||||
"detail": "Binary analysis confirms vendor backport applied. Evidence: oci://registry.example.com/evidence@sha256:abc123",
|
||||
"response": ["update"],
|
||||
"firstIssued": "2026-01-13T12:00:00Z"
|
||||
},
|
||||
"affects": [
|
||||
{
|
||||
"ref": "urn:cdx:stellaops/app@1.0.0/libssl.so.3",
|
||||
"versions": [{ "version": "3.0.2", "status": "unaffected" }]
|
||||
}
|
||||
],
|
||||
"properties": [
|
||||
{
|
||||
"name": "stellaops:evidence:type",
|
||||
"value": "binary-diff"
|
||||
},
|
||||
{
|
||||
"name": "stellaops:evidence:uri",
|
||||
"value": "oci://registry.example.com/evidence@sha256:abc123..."
|
||||
},
|
||||
{
|
||||
"name": "stellaops:evidence:confidence",
|
||||
"value": "0.95"
|
||||
},
|
||||
{
|
||||
"name": "stellaops:evidence:predicate-type",
|
||||
"value": "stellaops.binarydiff.v1"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Evidence Link Model
|
||||
|
||||
```csharp
|
||||
public sealed record VexEvidenceLink
|
||||
{
|
||||
/// <summary>Type of evidence (binary-diff, reachability, runtime, etc.).</summary>
|
||||
public required string EvidenceType { get; init; }
|
||||
|
||||
/// <summary>URI to the DSSE bundle (oci://, cas://, file://).</summary>
|
||||
public required string EvidenceUri { get; init; }
|
||||
|
||||
/// <summary>Digest of the DSSE envelope.</summary>
|
||||
public required string EnvelopeDigest { get; init; }
|
||||
|
||||
/// <summary>Predicate type in the DSSE envelope.</summary>
|
||||
public required string PredicateType { get; init; }
|
||||
|
||||
/// <summary>Confidence score (0.0-1.0).</summary>
|
||||
public required double Confidence { get; init; }
|
||||
|
||||
/// <summary>When the evidence was created.</summary>
|
||||
public required DateTimeOffset CreatedAt { get; init; }
|
||||
|
||||
/// <summary>Signer identity (key ID or certificate subject).</summary>
|
||||
public string? SignerIdentity { get; init; }
|
||||
|
||||
/// <summary>Rekor log index if submitted to transparency log.</summary>
|
||||
public string? RekorLogIndex { get; init; }
|
||||
}
|
||||
```
|
||||
|
||||
### Risk Assessment
|
||||
|
||||
| Risk | Likelihood | Impact | Mitigation |
|
||||
|------|------------|--------|------------|
|
||||
| Evidence URI format inconsistency | Medium | Medium | Define URI schema spec; validate on link |
|
||||
| Stale evidence links | Medium | Low | Include evidence timestamp; optional refresh |
|
||||
| Large evidence bundles | Low | Medium | Link to bundle, do not embed content |
|
||||
|
||||
### Success Metrics
|
||||
- [ ] VEX output includes evidence links when available
|
||||
- [ ] Evidence URIs resolve to valid DSSE bundles
|
||||
- [ ] CLI shows evidence in human-readable format
|
||||
- [ ] CycloneDX VEX validates against schema
|
||||
|
||||
## Dependencies & Concurrency
|
||||
- Batch 001 Sprint 002 (BinaryDiffV1 predicate) must be complete.
|
||||
- Sprint 1 depends on Batch 001 Sprint 002 outputs (DSSE bundle URIs).
|
||||
- Sprint 2 depends on Sprint 1 (linker service).
|
||||
- Other 20260113_003_000 planning artifacts are index-only, so parallel edits remain safe.
|
||||
|
||||
```
|
||||
Batch 001 Sprint 002 (BinaryDiffV1)
|
||||
-> Sprint 1 (VEX Evidence Linker)
|
||||
-> Sprint 2 (CLI Integration)
|
||||
```
|
||||
|
||||
## Documentation Prerequisites
|
||||
Before starting implementation, reviewers must read:
|
||||
|
||||
- `docs/README.md`
|
||||
- `docs/ARCHITECTURE_REFERENCE.md`
|
||||
- `CLAUDE.md` Section 8 (Code Quality and Determinism Rules)
|
||||
- CycloneDX VEX specification: https://cyclonedx.org/capabilities/vex/
|
||||
- Batch 001 BinaryDiffV1 predicate schema
|
||||
|
||||
## Delivery Tracker
|
||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 1 | INDEX-20260113-003-000-01 | DONE | None | Project Mgmt | Normalize sprint batch index to standard template and ASCII-only formatting. |
|
||||
| 2 | INDEX-20260113-003-000-02 | DONE | None | Project Mgmt | Clarify dependency flow and checkpoint wording without changing scope. |
|
||||
|
||||
## Execution Log
|
||||
| Date (UTC) | Update | Owner |
|
||||
|------------|--------|-------|
|
||||
| 2026-01-13 | Sprint batch created from advisory analysis. | Project Mgmt |
|
||||
| 2026-01-13 | Normalized sprint file to standard template; ASCII-only cleanup; no semantic changes. | Project Mgmt |
|
||||
| 2026-01-13 | Updated sprint statuses (003_001 DONE, 003_002 DONE). | Excititor/CLI |
|
||||
| 2026-01-13 | Archived sprint file to docs-archived/implplan. | Project Mgmt |
|
||||
|
||||
## Decisions & Risks
|
||||
- **APPROVED 2026-01-13**: Evidence stored as URI references, not embedded content.
|
||||
- **APPROVED 2026-01-13**: Use CycloneDX `properties[]` for Stella-specific evidence metadata.
|
||||
- **RISK**: CycloneDX `analysis.detail` has length limits; use URI not full content.
|
||||
|
||||
## Next Checkpoints
|
||||
- Batch 001 Sprint 002 complete -> Sprint 1 can start
|
||||
- Sprint 1 complete -> Sprint 2 can start
|
||||
- All sprints complete -> Integration testing checkpoint
|
||||
@@ -0,0 +1,379 @@
|
||||
# Sprint 20260113_003_001_EXCITITOR - VEX Evidence Linker Service
|
||||
|
||||
## Topic & Scope
|
||||
|
||||
- Implement VEX-to-evidence linking service
|
||||
- Auto-link binary-diff attestations to VEX assertions
|
||||
- Store evidence URIs alongside VEX entries
|
||||
- Emit evidence metadata in CycloneDX VEX output
|
||||
- **Working directory:** `src/Excititor/__Libraries/StellaOps.Excititor.Core/`
|
||||
|
||||
## Dependencies & Concurrency
|
||||
|
||||
- **Depends on:** Batch 001 Sprint 002 (BinaryDiffV1 predicate)
|
||||
- Parallel work safe within Excititor module
|
||||
- Sprint 2 (CLI) depends on this sprint
|
||||
|
||||
## Documentation Prerequisites
|
||||
|
||||
- `docs/README.md`
|
||||
- `CLAUDE.md` Section 8 (Determinism Rules)
|
||||
- CycloneDX VEX specification: https://cyclonedx.org/capabilities/vex/
|
||||
- Batch 001 BinaryDiffV1 predicate schema
|
||||
- Existing VEX models in `src/Excititor/__Libraries/.../VexDeltaModels.cs`
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||
|---|---------|--------|---------------------------|--------|-----------------|
|
||||
| 1 | VEX-LINK-MODELS-0001 | DONE | None | Guild - Excititor | Define `VexEvidenceLink`, `VexEvidenceLinkSet`, and `EvidenceType` enum in `Evidence/VexEvidenceLinkModels.cs`. Include URI, digest, predicate type, confidence, timestamps. |
|
||||
| 2 | VEX-LINK-INTERFACE-0001 | DONE | Depends on MODELS-0001 | Guild - Excititor | Define `IVexEvidenceLinker` interface with `LinkAsync(vexEntry, evidenceSource, ct)` and `GetLinksAsync(vexEntryId, ct)` methods. |
|
||||
| 3 | VEX-LINK-BINARYDIFF-0001 | DONE | Depends on INTERFACE-0001, Batch 001 | Guild - Excititor | Implement `BinaryDiffEvidenceLinker` that extracts evidence from `BinaryDiffPredicate` findings and creates `VexEvidenceLink` entries. |
|
||||
| 4 | VEX-LINK-STORE-0001 | DONE | Depends on MODELS-0001 | Guild - Excititor | Implement `IVexEvidenceLinkStore` interface and in-memory implementation. Define PostgreSQL schema for persistent storage. |
|
||||
| 5 | VEX-LINK-AUTOLINK-0001 | DONE | Depends on BINARYDIFF-0001 | Guild - Excititor | Implement auto-linking pipeline: when binary-diff produces "patched" verdict, create VEX link with appropriate justification. |
|
||||
| 6 | VEX-LINK-CYCLONEDX-0001 | DONE | Depends on AUTOLINK-0001 | Guild - Excititor | Extend `CycloneDxVexMapper` to emit `analysis.detail` with evidence URI and `properties[]` with evidence metadata. |
|
||||
| 7 | VEX-LINK-VALIDATION-0001 | DONE | Depends on all above | Guild - Excititor | Implement evidence validation: verify DSSE signature before accepting link. Optional: verify Rekor inclusion. |
|
||||
| 8 | VEX-LINK-DI-0001 | DONE | Depends on all above | Guild - Excititor | Register all services in DI. Add `IOptions<VexEvidenceLinkOptions>` for configuration (confidence threshold, validation mode). |
|
||||
| 9 | VEX-LINK-TESTS-0001 | DONE | Depends on all above | Guild - Excititor | Unit tests covering: link creation, storage, auto-linking, CycloneDX output, validation success/failure. |
|
||||
|
||||
## Technical Specification
|
||||
|
||||
### Models
|
||||
|
||||
```csharp
|
||||
namespace StellaOps.Excititor.Core.Evidence;
|
||||
|
||||
/// <summary>
|
||||
/// Link between a VEX assertion and supporting evidence.
|
||||
/// </summary>
|
||||
public sealed record VexEvidenceLink
|
||||
{
|
||||
/// <summary>Unique link identifier.</summary>
|
||||
public required string LinkId { get; init; }
|
||||
|
||||
/// <summary>VEX entry this evidence supports.</summary>
|
||||
public required string VexEntryId { get; init; }
|
||||
|
||||
/// <summary>Type of evidence.</summary>
|
||||
public required EvidenceType EvidenceType { get; init; }
|
||||
|
||||
/// <summary>URI to the evidence artifact (oci://, cas://, https://).</summary>
|
||||
public required string EvidenceUri { get; init; }
|
||||
|
||||
/// <summary>Digest of the DSSE envelope (sha256:...).</summary>
|
||||
public required string EnvelopeDigest { get; init; }
|
||||
|
||||
/// <summary>Predicate type in the DSSE envelope.</summary>
|
||||
public required string PredicateType { get; init; }
|
||||
|
||||
/// <summary>Confidence score from the evidence (0.0-1.0).</summary>
|
||||
public required double Confidence { get; init; }
|
||||
|
||||
/// <summary>Justification derived from evidence.</summary>
|
||||
public required VexJustification Justification { get; init; }
|
||||
|
||||
/// <summary>When the evidence was created.</summary>
|
||||
public required DateTimeOffset EvidenceCreatedAt { get; init; }
|
||||
|
||||
/// <summary>When the link was created.</summary>
|
||||
public required DateTimeOffset LinkedAt { get; init; }
|
||||
|
||||
/// <summary>Signer identity (key ID or certificate subject).</summary>
|
||||
public string? SignerIdentity { get; init; }
|
||||
|
||||
/// <summary>Rekor log index if submitted to transparency log.</summary>
|
||||
public string? RekorLogIndex { get; init; }
|
||||
|
||||
/// <summary>Whether the evidence signature was validated.</summary>
|
||||
public bool SignatureValidated { get; init; }
|
||||
|
||||
/// <summary>Additional metadata as key-value pairs.</summary>
|
||||
public ImmutableDictionary<string, string> Metadata { get; init; }
|
||||
= ImmutableDictionary<string, string>.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Types of evidence that can support VEX assertions.
|
||||
/// </summary>
|
||||
public enum EvidenceType
|
||||
{
|
||||
/// <summary>Binary-level diff showing patch applied.</summary>
|
||||
BinaryDiff,
|
||||
|
||||
/// <summary>Call graph analysis showing code not reachable.</summary>
|
||||
ReachabilityAnalysis,
|
||||
|
||||
/// <summary>Runtime analysis showing code not executed.</summary>
|
||||
RuntimeAnalysis,
|
||||
|
||||
/// <summary>Human attestation (manual review).</summary>
|
||||
HumanAttestation,
|
||||
|
||||
/// <summary>Vendor advisory or statement.</summary>
|
||||
VendorAdvisory,
|
||||
|
||||
/// <summary>Other/custom evidence type.</summary>
|
||||
Other
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// VEX justification codes (CycloneDX compatible).
|
||||
/// </summary>
|
||||
public enum VexJustification
|
||||
{
|
||||
CodeNotPresent,
|
||||
CodeNotReachable,
|
||||
RequiresConfiguration,
|
||||
RequiresDependency,
|
||||
RequiresEnvironment,
|
||||
ProtectedByCompiler,
|
||||
ProtectedAtRuntime,
|
||||
ProtectedAtPerimeter,
|
||||
ProtectedByMitigatingControl
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collection of evidence links for a VEX entry.
|
||||
/// </summary>
|
||||
public sealed record VexEvidenceLinkSet
|
||||
{
|
||||
/// <summary>VEX entry ID.</summary>
|
||||
public required string VexEntryId { get; init; }
|
||||
|
||||
/// <summary>All evidence links, sorted by confidence descending.</summary>
|
||||
public required ImmutableArray<VexEvidenceLink> Links { get; init; }
|
||||
|
||||
/// <summary>Highest confidence among all links.</summary>
|
||||
public double MaxConfidence => Links.IsEmpty ? 0 : Links.Max(l => l.Confidence);
|
||||
|
||||
/// <summary>Primary link (highest confidence).</summary>
|
||||
public VexEvidenceLink? PrimaryLink => Links.IsEmpty ? null : Links[0];
|
||||
}
|
||||
```
|
||||
|
||||
### Interfaces
|
||||
|
||||
```csharp
|
||||
namespace StellaOps.Excititor.Core.Evidence;
|
||||
|
||||
/// <summary>
|
||||
/// Service for linking VEX assertions to supporting evidence.
|
||||
/// </summary>
|
||||
public interface IVexEvidenceLinker
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a link between a VEX entry and evidence.
|
||||
/// </summary>
|
||||
Task<VexEvidenceLink> LinkAsync(
|
||||
string vexEntryId,
|
||||
EvidenceSource source,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all evidence links for a VEX entry.
|
||||
/// </summary>
|
||||
Task<VexEvidenceLinkSet> GetLinksAsync(
|
||||
string vexEntryId,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Auto-links evidence from a binary diff result.
|
||||
/// </summary>
|
||||
Task<ImmutableArray<VexEvidenceLink>> AutoLinkFromBinaryDiffAsync(
|
||||
BinaryDiffPredicate diff,
|
||||
string dsseEnvelopeUri,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Source of evidence for linking.
|
||||
/// </summary>
|
||||
public sealed record EvidenceSource
|
||||
{
|
||||
/// <summary>Evidence type.</summary>
|
||||
public required EvidenceType Type { get; init; }
|
||||
|
||||
/// <summary>URI to the evidence artifact.</summary>
|
||||
public required string Uri { get; init; }
|
||||
|
||||
/// <summary>Digest of the artifact.</summary>
|
||||
public required string Digest { get; init; }
|
||||
|
||||
/// <summary>Predicate type if DSSE/in-toto.</summary>
|
||||
public string? PredicateType { get; init; }
|
||||
|
||||
/// <summary>Confidence score.</summary>
|
||||
public double Confidence { get; init; } = 1.0;
|
||||
|
||||
/// <summary>DSSE envelope bytes for validation.</summary>
|
||||
public byte[]? EnvelopeBytes { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Storage for evidence links.
|
||||
/// </summary>
|
||||
public interface IVexEvidenceLinkStore
|
||||
{
|
||||
Task SaveAsync(VexEvidenceLink link, CancellationToken ct = default);
|
||||
Task<VexEvidenceLink?> GetAsync(string linkId, CancellationToken ct = default);
|
||||
Task<ImmutableArray<VexEvidenceLink>> GetByVexEntryAsync(string vexEntryId, CancellationToken ct = default);
|
||||
Task DeleteAsync(string linkId, CancellationToken ct = default);
|
||||
}
|
||||
```
|
||||
|
||||
### Auto-Link Algorithm
|
||||
|
||||
```pseudo
|
||||
function AutoLinkFromBinaryDiff(diff, dsseUri):
|
||||
links = []
|
||||
|
||||
for finding in diff.findings where finding.verdict == Patched:
|
||||
// Determine affected VEX entry
|
||||
vexEntryId = LookupVexEntry(finding.path, diff.inputs.target)
|
||||
|
||||
if vexEntryId is null:
|
||||
continue // No matching VEX entry
|
||||
|
||||
// Determine justification from finding
|
||||
justification = DetermineJustification(finding)
|
||||
|
||||
// Create link
|
||||
link = VexEvidenceLink {
|
||||
linkId: GenerateId(vexEntryId, dsseUri),
|
||||
vexEntryId: vexEntryId,
|
||||
evidenceType: BinaryDiff,
|
||||
evidenceUri: dsseUri,
|
||||
envelopeDigest: ComputeDigest(diff),
|
||||
predicateType: "stellaops.binarydiff.v1",
|
||||
confidence: finding.confidence ?? 0.9,
|
||||
justification: justification,
|
||||
evidenceCreatedAt: diff.metadata.analysisTimestamp,
|
||||
linkedAt: timeProvider.GetUtcNow()
|
||||
}
|
||||
|
||||
links.append(link)
|
||||
|
||||
return links
|
||||
|
||||
function DetermineJustification(finding):
|
||||
// If .text section changed -> code was patched
|
||||
if finding.sectionDeltas.any(d => d.section == ".text" && d.status == Modified):
|
||||
return CodeNotPresent // Vulnerable code removed/replaced
|
||||
|
||||
// If only .rodata changed -> data patched
|
||||
if finding.sectionDeltas.all(d => d.section != ".text"):
|
||||
return ProtectedAtRuntime // Runtime behavior changed
|
||||
|
||||
return CodeNotReachable // Default for verified patches
|
||||
```
|
||||
|
||||
### CycloneDX Output Enhancement
|
||||
|
||||
```csharp
|
||||
// In CycloneDxVexMapper
|
||||
private void MapEvidenceLinks(VulnerabilityAnalysis analysis, VexEvidenceLinkSet links)
|
||||
{
|
||||
if (links.PrimaryLink is null) return;
|
||||
|
||||
var primary = links.PrimaryLink;
|
||||
|
||||
// Set analysis.detail with evidence URI
|
||||
analysis.Detail = $"Evidence: {primary.EvidenceUri}";
|
||||
|
||||
// Add evidence properties
|
||||
analysis.Properties ??= [];
|
||||
analysis.Properties.Add(new Property
|
||||
{
|
||||
Name = "stellaops:evidence:type",
|
||||
Value = primary.EvidenceType.ToString().ToLowerInvariant()
|
||||
});
|
||||
analysis.Properties.Add(new Property
|
||||
{
|
||||
Name = "stellaops:evidence:uri",
|
||||
Value = primary.EvidenceUri
|
||||
});
|
||||
analysis.Properties.Add(new Property
|
||||
{
|
||||
Name = "stellaops:evidence:confidence",
|
||||
Value = primary.Confidence.ToString("F2", CultureInfo.InvariantCulture)
|
||||
});
|
||||
analysis.Properties.Add(new Property
|
||||
{
|
||||
Name = "stellaops:evidence:predicate-type",
|
||||
Value = primary.PredicateType
|
||||
});
|
||||
|
||||
if (primary.RekorLogIndex is not null)
|
||||
{
|
||||
analysis.Properties.Add(new Property
|
||||
{
|
||||
Name = "stellaops:evidence:rekor-index",
|
||||
Value = primary.RekorLogIndex
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
```yaml
|
||||
excititor:
|
||||
evidence:
|
||||
linking:
|
||||
enabled: true
|
||||
autoLinkOnBinaryDiff: true
|
||||
confidenceThreshold: 0.8
|
||||
validateSignatures: true
|
||||
validateRekorInclusion: false
|
||||
maxLinksPerEntry: 10
|
||||
```
|
||||
|
||||
## Determinism Requirements
|
||||
|
||||
1. **Link ID generation**: Deterministic from vexEntryId + evidenceUri
|
||||
2. **Ordering**: Links sorted by confidence DESC, then by linkedAt ASC
|
||||
3. **Timestamps**: From injected `TimeProvider`
|
||||
4. **Confidence formatting**: Two decimal places, InvariantCulture
|
||||
|
||||
## Test Cases
|
||||
|
||||
### Unit Tests
|
||||
|
||||
| Test | Description | Expected |
|
||||
|------|-------------|----------|
|
||||
| `Link_ValidSource_CreatesLink` | Link with valid evidence | Link created with correct fields |
|
||||
| `Link_DuplicateSource_Deduplicates` | Same source linked twice | Single link returned |
|
||||
| `AutoLink_PatchedFinding_CreatesLinks` | Binary diff with patched verdict | Links created for affected entries |
|
||||
| `AutoLink_VanillaFinding_NoLinks` | Binary diff with vanilla verdict | No links created |
|
||||
| `GetLinks_ExistingEntry_ReturnsSet` | Query by VEX entry ID | All links returned, sorted |
|
||||
| `MapCycloneDx_WithLinks_IncludesEvidence` | CycloneDX export with links | Properties contain evidence metadata |
|
||||
| `Validate_ValidSignature_Succeeds` | DSSE with valid signature | Validation passes |
|
||||
| `Validate_InvalidSignature_Rejects` | DSSE with bad signature | Validation fails, link rejected |
|
||||
|
||||
### Integration Tests
|
||||
|
||||
| Test | Description | Expected |
|
||||
|------|-------------|----------|
|
||||
| `EndToEnd_BinaryDiffToVex_LinksEvidence` | Full pipeline from diff to VEX | VEX output contains evidence links |
|
||||
|
||||
## Execution Log
|
||||
|
||||
| Date (UTC) | Update | Owner |
|
||||
|------------|--------|-------|
|
||||
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
|
||||
| 2026-01-13 | Implemented evidence linker, storage, validation, and tests. | Excititor |
|
||||
| 2026-01-13 | Archived sprint file to docs-archived/implplan. | Project Mgmt |
|
||||
|
||||
## Decisions & Risks
|
||||
|
||||
- **APPROVED**: Evidence stored as URIs, not embedded content.
|
||||
- **APPROVED**: Auto-link only for high-confidence findings (>= threshold).
|
||||
- **RISK**: Signature validation may fail for offline evidence; add bypass option.
|
||||
- **RISK**: VEX entry lookup requires correlation logic; may need component PURL matching.
|
||||
|
||||
## Next Checkpoints
|
||||
|
||||
- Task 1-4 complete -> Core linking operational
|
||||
- Task 5-6 complete -> Auto-link and CycloneDX working
|
||||
- Task 9 complete -> Sprint can be marked DONE
|
||||
- Unblock Sprint 2 (CLI)
|
||||
@@ -0,0 +1,139 @@
|
||||
# Sprint 20260113_003_002_CLI - VEX Generation with Evidence Links
|
||||
|
||||
## Topic & Scope
|
||||
|
||||
- Extend `stella vex gen` command with evidence linking
|
||||
- Add `--link-evidence` flag to include binary-diff evidence
|
||||
- Display evidence summary in human-readable output
|
||||
- Emit evidence metadata in JSON output
|
||||
- **Working directory:** `src/Cli/StellaOps.Cli/Commands/`
|
||||
|
||||
## Dependencies & Concurrency
|
||||
|
||||
- **Depends on:** Sprint 003_001 (VEX Evidence Linker)
|
||||
- Extends existing `VexGenCommandGroup.cs`
|
||||
|
||||
## Documentation Prerequisites
|
||||
|
||||
- `docs/README.md`
|
||||
- `CLAUDE.md` Section 8 (Determinism Rules)
|
||||
- Existing VEX CLI in `src/Cli/StellaOps.Cli/Commands/VexGenCommandGroup.cs`
|
||||
- Sprint 003_001 models and interfaces
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||
|---|---------|--------|---------------------------|--------|-----------------|
|
||||
| 1 | CLI-VEX-EVIDENCE-OPT-0001 | DONE | None | Guild - CLI | Add `--link-evidence` option to `stella vex gen` command. Default: true if evidence available. |
|
||||
| 2 | CLI-VEX-EVIDENCE-HANDLER-0001 | DONE | Depends on OPT-0001, Sprint 001 | Guild - CLI | Extend VEX generation handler to call `IVexEvidenceLinker.GetLinksAsync()` and include in output. |
|
||||
| 3 | CLI-VEX-EVIDENCE-JSON-0001 | DONE | Depends on HANDLER-0001 | Guild - CLI | Emit evidence links in JSON output under `evidence` key per vulnerability. |
|
||||
| 4 | CLI-VEX-EVIDENCE-TABLE-0001 | DONE | Depends on HANDLER-0001 | Guild - CLI | Show evidence summary in table output: type, confidence, URI (truncated). |
|
||||
| 5 | CLI-VEX-EVIDENCE-TESTS-0001 | DONE | Depends on all above | Guild - CLI | Unit tests for evidence flag, output formats, missing evidence handling. |
|
||||
|
||||
## Technical Specification
|
||||
|
||||
### Command Enhancement
|
||||
|
||||
```
|
||||
stella vex gen <scan-id> [options]
|
||||
|
||||
Existing options:
|
||||
--output, -o Output format (json, table, cyclonedx)
|
||||
--format, -f VEX format (openvex, cyclonedx)
|
||||
|
||||
New options:
|
||||
--link-evidence Include evidence links in output (default: true)
|
||||
--evidence-threshold Minimum confidence for evidence (default: 0.8)
|
||||
--show-evidence-uri Show full evidence URIs (default: truncated)
|
||||
```
|
||||
|
||||
### Output Examples
|
||||
|
||||
#### Table Output with Evidence
|
||||
|
||||
```
|
||||
VEX Report for scan abc123
|
||||
|
||||
+----------------+-------------+----------------+------------+------------------+
|
||||
| CVE | Component | Status | Confidence | Evidence |
|
||||
+----------------+-------------+----------------+------------+------------------+
|
||||
| CVE-2023-12345 | libssl.so.3 | not_affected | 0.95 | binary-diff [OK] |
|
||||
| CVE-2023-67890 | libcrypto | affected | - | (none) |
|
||||
| CVE-2024-11111 | nginx | not_affected | 0.88 | reachability |
|
||||
+----------------+-------------+----------------+------------+------------------+
|
||||
|
||||
Evidence Details:
|
||||
CVE-2023-12345: oci://registry/evidence@sha256:abc123...
|
||||
Type: binary-diff, Predicate: stellaops.binarydiff.v1
|
||||
Signer: CN=StellaOps Signing Key
|
||||
```
|
||||
|
||||
#### JSON Output with Evidence
|
||||
|
||||
```json
|
||||
{
|
||||
"scanId": "abc123",
|
||||
"generatedAt": "2026-01-13T12:00:00Z",
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"id": "CVE-2023-12345",
|
||||
"component": "libssl.so.3",
|
||||
"status": "not_affected",
|
||||
"justification": "code_not_present",
|
||||
"evidence": {
|
||||
"type": "binary-diff",
|
||||
"uri": "oci://registry/evidence@sha256:abc123...",
|
||||
"confidence": 0.95,
|
||||
"predicateType": "stellaops.binarydiff.v1",
|
||||
"validatedSignature": true,
|
||||
"rekorIndex": "12345678"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Implementation Notes
|
||||
|
||||
```csharp
|
||||
// Extend HandleVexGenAsync
|
||||
if (linkEvidence)
|
||||
{
|
||||
var linker = services.GetRequiredService<IVexEvidenceLinker>();
|
||||
foreach (var entry in vexEntries)
|
||||
{
|
||||
var links = await linker.GetLinksAsync(entry.Id, ct);
|
||||
if (links.PrimaryLink is not null && links.MaxConfidence >= evidenceThreshold)
|
||||
{
|
||||
entry.Evidence = links.PrimaryLink;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Test Cases
|
||||
|
||||
| Test | Description | Expected |
|
||||
|------|-------------|----------|
|
||||
| `VexGen_WithEvidence_IncludesLinks` | Evidence available | Links in output |
|
||||
| `VexGen_NoEvidence_OmitsField` | No evidence | `evidence: null` |
|
||||
| `VexGen_BelowThreshold_Filtered` | Low confidence evidence | Evidence omitted |
|
||||
| `VexGen_TableFormat_ShowsSummary` | Table output | Evidence column populated |
|
||||
|
||||
## Execution Log
|
||||
|
||||
| Date (UTC) | Update | Owner |
|
||||
|------------|--------|-------|
|
||||
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
|
||||
| 2026-01-13 | Normalised sprint file to standard template; added Decisions & Risks section. | Docs |
|
||||
| 2026-01-13 | Implemented VEX evidence options, output mapping, and tests. | CLI |
|
||||
| 2026-01-13 | Archived sprint file to docs-archived/implplan. | Project Mgmt |
|
||||
|
||||
## Decisions & Risks
|
||||
|
||||
- None recorded.
|
||||
|
||||
## Next Checkpoints
|
||||
|
||||
- All tasks complete -> Sprint can be marked DONE
|
||||
- Batch 003 complete -> Evidence chain operational
|
||||
Reference in New Issue
Block a user