feat: Update analyzer fixtures and metadata for improved license handling and provenance tracking
- Added license expressions and provenance fields to expected JSON outputs for .NET and Rust analyzers. - Introduced new .nuspec files for StellaOps.Runtime.SelfContained and StellaOps.Toolkit packages, including license information. - Created LICENSE.txt files for both toolkit packages with clear licensing terms. - Updated expected JSON for signed and simple analyzers to include license information and provenance. - Enhanced the SPRINTS_LANG_IMPLEMENTATION_PLAN.md with detailed progress and future sprint outlines, ensuring clarity on deliverables and acceptance metrics.
This commit is contained in:
@@ -118,7 +118,7 @@ Generated from SPRINTS.md and module TASKS.md files on 2025-10-19. Waves cluster
|
|||||||
- Team Notify Worker Guild: read EXECPLAN.md Wave 4 and SPRINTS.md rows for `src/StellaOps.Notify.Worker/TASKS.md`. Focus on NOTIFY-WORKER-15-204 (TODO). Confirm prerequisites (internal: NOTIFY-WORKER-15-203 (Wave 3)) before starting and report status in module TASKS.md.
|
- Team Notify Worker Guild: read EXECPLAN.md Wave 4 and SPRINTS.md rows for `src/StellaOps.Notify.Worker/TASKS.md`. Focus on NOTIFY-WORKER-15-204 (TODO). Confirm prerequisites (internal: NOTIFY-WORKER-15-203 (Wave 3)) before starting and report status in module TASKS.md.
|
||||||
- Team Policy Guild, Scanner WebService Guild: read EXECPLAN.md Wave 4 and SPRINTS.md rows for `src/StellaOps.Policy/TASKS.md`. Focus on POLICY-RUNTIME-17-201 (TODO). Confirm prerequisites (internal: ZASTAVA-OBS-17-005 (Wave 3)) before starting and report status in module TASKS.md.
|
- Team Policy Guild, Scanner WebService Guild: read EXECPLAN.md Wave 4 and SPRINTS.md rows for `src/StellaOps.Policy/TASKS.md`. Focus on POLICY-RUNTIME-17-201 (TODO). Confirm prerequisites (internal: ZASTAVA-OBS-17-005 (Wave 3)) before starting and report status in module TASKS.md.
|
||||||
- Team Scheduler Worker Guild: read EXECPLAN.md Wave 4 and SPRINTS.md rows for `src/StellaOps.Scheduler.Worker/TASKS.md`. Focus on SCHED-WORKER-16-204 (TODO). Confirm prerequisites (internal: SCHED-WORKER-16-203 (Wave 3)) before starting and report status in module TASKS.md.
|
- Team Scheduler Worker Guild: read EXECPLAN.md Wave 4 and SPRINTS.md rows for `src/StellaOps.Scheduler.Worker/TASKS.md`. Focus on SCHED-WORKER-16-204 (TODO). Confirm prerequisites (internal: SCHED-WORKER-16-203 (Wave 3)) before starting and report status in module TASKS.md.
|
||||||
- Team TBD: read EXECPLAN.md Wave 4 and SPRINTS.md rows for `src/StellaOps.Scanner.Analyzers.Lang.DotNet/TASKS.md`, `src/StellaOps.Scanner.Analyzers.Lang.Go/TASKS.md`, `src/StellaOps.Scanner.Analyzers.Lang.Python/TASKS.md`, `src/StellaOps.Scanner.Analyzers.Lang.Rust/TASKS.md`. Focus on SCANNER-ANALYZERS-LANG-10-307D (TODO), SCANNER-ANALYZERS-LANG-10-307G (TODO), SCANNER-ANALYZERS-LANG-10-307P (TODO), SCANNER-ANALYZERS-LANG-10-307R (TODO). Confirm prerequisites (internal: SCANNER-ANALYZERS-LANG-10-303C (Wave 3), SCANNER-ANALYZERS-LANG-10-304C (Wave 3), SCANNER-ANALYZERS-LANG-10-305C (Wave 3), SCANNER-ANALYZERS-LANG-10-306C (Wave 3)) before starting and report status in module TASKS.md.
|
- Team TBD: read EXECPLAN.md Wave 4 and SPRINTS.md rows for `src/StellaOps.Scanner.Analyzers.Lang.DotNet/TASKS.md`, `src/StellaOps.Scanner.Analyzers.Lang.Go/TASKS.md`, `src/StellaOps.Scanner.Analyzers.Lang.Python/TASKS.md`, `src/StellaOps.Scanner.Analyzers.Lang.Rust/TASKS.md`. Focus on SCANNER-ANALYZERS-LANG-10-307D (DONE 2025-10-22), SCANNER-ANALYZERS-LANG-10-307G (TODO), SCANNER-ANALYZERS-LANG-10-307P (TODO), SCANNER-ANALYZERS-LANG-10-307R (TODO). Confirm prerequisites (internal: SCANNER-ANALYZERS-LANG-10-303C (Wave 3), SCANNER-ANALYZERS-LANG-10-304C (Wave 3), SCANNER-ANALYZERS-LANG-10-305C (Wave 3), SCANNER-ANALYZERS-LANG-10-306C (Wave 3)) before starting and report status in module TASKS.md.
|
||||||
|
|
||||||
### Wave 5
|
### Wave 5
|
||||||
- Team Excititor Connectors – Stella: read EXECPLAN.md Wave 5 and SPRINTS.md rows for `src/StellaOps.Excititor.Connectors.StellaOpsMirror/TASKS.md`. Focus on EXCITITOR-CONN-STELLA-07-003 (TODO). Confirm prerequisites (internal: EXCITITOR-CONN-STELLA-07-002 (Wave 4)) before starting and report status in module TASKS.md.
|
- Team Excititor Connectors – Stella: read EXECPLAN.md Wave 5 and SPRINTS.md rows for `src/StellaOps.Excititor.Connectors.StellaOpsMirror/TASKS.md`. Focus on EXCITITOR-CONN-STELLA-07-003 (TODO). Confirm prerequisites (internal: EXCITITOR-CONN-STELLA-07-002 (Wave 4)) before starting and report status in module TASKS.md.
|
||||||
@@ -927,9 +927,9 @@ Generated from SPRINTS.md and module TASKS.md files on 2025-10-19. Waves cluster
|
|||||||
- **Sprint 10** · Backlog
|
- **Sprint 10** · Backlog
|
||||||
- Team: TBD
|
- Team: TBD
|
||||||
- Path: `src/StellaOps.Scanner.Analyzers.Lang.DotNet/TASKS.md`
|
- Path: `src/StellaOps.Scanner.Analyzers.Lang.DotNet/TASKS.md`
|
||||||
1. [TODO] SCANNER-ANALYZERS-LANG-10-307D — Integrate shared helpers (license mapping, quiet provenance) and concurrency-safe caches.
|
1. [DONE 2025-10-22] SCANNER-ANALYZERS-LANG-10-307D — Integrate shared helpers (license mapping, quiet provenance) and concurrency-safe caches.
|
||||||
• Prereqs: SCANNER-ANALYZERS-LANG-10-305C (Wave 3)
|
• Prereqs: SCANNER-ANALYZERS-LANG-10-305C (Wave 3)
|
||||||
• Current: TODO
|
• Current: DONE 2025-10-22
|
||||||
- Path: `src/StellaOps.Scanner.Analyzers.Lang.Go/TASKS.md`
|
- Path: `src/StellaOps.Scanner.Analyzers.Lang.Go/TASKS.md`
|
||||||
1. [TODO] SCANNER-ANALYZERS-LANG-10-307G — Wire shared helpers (license mapping, usage flags) and ensure concurrency-safe buffer reuse.
|
1. [TODO] SCANNER-ANALYZERS-LANG-10-307G — Wire shared helpers (license mapping, usage flags) and ensure concurrency-safe buffer reuse.
|
||||||
• Prereqs: SCANNER-ANALYZERS-LANG-10-304C (Wave 3)
|
• Prereqs: SCANNER-ANALYZERS-LANG-10-304C (Wave 3)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,332 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Security;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
|
namespace StellaOps.Scanner.Analyzers.Lang.DotNet.Internal;
|
||||||
|
|
||||||
|
internal static class DotNetFileMetadataCache
|
||||||
|
{
|
||||||
|
private static readonly ConcurrentDictionary<DotNetFileCacheKey, Optional<string>> Sha256Cache = new();
|
||||||
|
private static readonly ConcurrentDictionary<DotNetFileCacheKey, Optional<AssemblyName>> AssemblyCache = new();
|
||||||
|
private static readonly ConcurrentDictionary<DotNetFileCacheKey, Optional<FileVersionInfo>> VersionCache = new();
|
||||||
|
|
||||||
|
public static bool TryGetSha256(string path, out string? sha256)
|
||||||
|
=> TryGet(path, Sha256Cache, ComputeSha256, out sha256);
|
||||||
|
|
||||||
|
public static bool TryGetAssemblyName(string path, out AssemblyName? assemblyName)
|
||||||
|
=> TryGet(path, AssemblyCache, TryReadAssemblyName, out assemblyName);
|
||||||
|
|
||||||
|
public static bool TryGetFileVersionInfo(string path, out FileVersionInfo? versionInfo)
|
||||||
|
=> TryGet(path, VersionCache, TryReadFileVersionInfo, out versionInfo);
|
||||||
|
|
||||||
|
private static bool TryGet<T>(string path, ConcurrentDictionary<DotNetFileCacheKey, Optional<T>> cache, Func<string, T?> resolver, out T? value)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
|
||||||
|
DotNetFileCacheKey key;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var info = new FileInfo(path);
|
||||||
|
if (!info.Exists)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = new DotNetFileCacheKey(info.FullName, info.Length, info.LastWriteTimeUtc.Ticks);
|
||||||
|
}
|
||||||
|
catch (IOException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (SecurityException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (ArgumentException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (NotSupportedException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var optional = cache.GetOrAdd(key, static (cacheKey, state) => CreateOptional(cacheKey.Path, state.resolver), (resolver, path));
|
||||||
|
if (!optional.HasValue)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = optional.Value;
|
||||||
|
return value is not null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<T> CreateOptional<T>(string path, Func<string, T?> resolver) where T : class
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var value = resolver(path);
|
||||||
|
return Optional<T>.From(value);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
return Optional<T>.None;
|
||||||
|
}
|
||||||
|
catch (FileLoadException)
|
||||||
|
{
|
||||||
|
return Optional<T>.None;
|
||||||
|
}
|
||||||
|
catch (BadImageFormatException)
|
||||||
|
{
|
||||||
|
return Optional<T>.None;
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
return Optional<T>.None;
|
||||||
|
}
|
||||||
|
catch (SecurityException)
|
||||||
|
{
|
||||||
|
return Optional<T>.None;
|
||||||
|
}
|
||||||
|
catch (IOException)
|
||||||
|
{
|
||||||
|
return Optional<T>.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? ComputeSha256(string path)
|
||||||
|
{
|
||||||
|
using var stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||||
|
using var sha = System.Security.Cryptography.SHA256.Create();
|
||||||
|
var hash = sha.ComputeHash(stream);
|
||||||
|
return Convert.ToHexString(hash).ToLowerInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AssemblyName? TryReadAssemblyName(string path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return AssemblyName.GetAssemblyName(path);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (FileLoadException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (BadImageFormatException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (IOException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FileVersionInfo? TryReadFileVersionInfo(string path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return FileVersionInfo.GetVersionInfo(path);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (IOException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class DotNetLicenseCache
|
||||||
|
{
|
||||||
|
private static readonly ConcurrentDictionary<DotNetFileCacheKey, Optional<DotNetLicenseInfo>> Licenses = new();
|
||||||
|
|
||||||
|
public static bool TryGetLicenseInfo(string nuspecPath, out DotNetLicenseInfo? info)
|
||||||
|
{
|
||||||
|
info = null;
|
||||||
|
|
||||||
|
DotNetFileCacheKey key;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fileInfo = new FileInfo(nuspecPath);
|
||||||
|
if (!fileInfo.Exists)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = new DotNetFileCacheKey(fileInfo.FullName, fileInfo.Length, fileInfo.LastWriteTimeUtc.Ticks);
|
||||||
|
}
|
||||||
|
catch (IOException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (SecurityException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var optional = Licenses.GetOrAdd(key, static (cacheKey, path) => CreateOptional(path), nuspecPath);
|
||||||
|
if (!optional.HasValue)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
info = optional.Value;
|
||||||
|
return info is not null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<DotNetLicenseInfo> CreateOptional(string nuspecPath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var info = Parse(nuspecPath);
|
||||||
|
return Optional<DotNetLicenseInfo>.From(info);
|
||||||
|
}
|
||||||
|
catch (IOException)
|
||||||
|
{
|
||||||
|
return Optional<DotNetLicenseInfo>.None;
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
return Optional<DotNetLicenseInfo>.None;
|
||||||
|
}
|
||||||
|
catch (SecurityException)
|
||||||
|
{
|
||||||
|
return Optional<DotNetLicenseInfo>.None;
|
||||||
|
}
|
||||||
|
catch (XmlException)
|
||||||
|
{
|
||||||
|
return Optional<DotNetLicenseInfo>.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DotNetLicenseInfo? Parse(string path)
|
||||||
|
{
|
||||||
|
using var stream = File.OpenRead(path);
|
||||||
|
using var reader = XmlReader.Create(stream, new XmlReaderSettings
|
||||||
|
{
|
||||||
|
DtdProcessing = DtdProcessing.Ignore,
|
||||||
|
IgnoreComments = true,
|
||||||
|
IgnoreWhitespace = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
var expressions = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
var files = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
var urls = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
if (reader.NodeType != XmlNodeType.Element)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(reader.LocalName, "license", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var type = reader.GetAttribute("type");
|
||||||
|
var value = reader.ReadElementContentAsString()?.Trim();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(type, "expression", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
expressions.Add(value);
|
||||||
|
}
|
||||||
|
else if (string.Equals(type, "file", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
files.Add(NormalizeLicensePath(value));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
expressions.Add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (string.Equals(reader.LocalName, "licenseUrl", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var value = reader.ReadElementContentAsString()?.Trim();
|
||||||
|
if (!string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
urls.Add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expressions.Count == 0 && files.Count == 0 && urls.Count == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DotNetLicenseInfo(
|
||||||
|
expressions.ToArray(),
|
||||||
|
files.ToArray(),
|
||||||
|
urls.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NormalizeLicensePath(string value)
|
||||||
|
=> value.Replace('\\', '/').Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed record DotNetLicenseInfo(
|
||||||
|
IReadOnlyList<string> Expressions,
|
||||||
|
IReadOnlyList<string> Files,
|
||||||
|
IReadOnlyList<string> Urls);
|
||||||
|
|
||||||
|
internal readonly record struct DotNetFileCacheKey(string Path, long Length, long LastWriteTicks)
|
||||||
|
{
|
||||||
|
private readonly string _normalizedPath = OperatingSystem.IsWindows()
|
||||||
|
? Path.ToLowerInvariant()
|
||||||
|
: Path;
|
||||||
|
|
||||||
|
public bool Equals(DotNetFileCacheKey other)
|
||||||
|
=> Length == other.Length
|
||||||
|
&& LastWriteTicks == other.LastWriteTicks
|
||||||
|
&& string.Equals(_normalizedPath, other._normalizedPath, StringComparison.Ordinal);
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
=> HashCode.Combine(_normalizedPath, Length, LastWriteTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal readonly struct Optional<T> where T : class
|
||||||
|
{
|
||||||
|
private Optional(bool hasValue, T? value)
|
||||||
|
{
|
||||||
|
HasValue = hasValue;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasValue { get; }
|
||||||
|
|
||||||
|
public T? Value { get; }
|
||||||
|
|
||||||
|
public static Optional<T> From(T? value)
|
||||||
|
=> value is null ? None : new Optional<T>(true, value);
|
||||||
|
|
||||||
|
public static Optional<T> None => default;
|
||||||
|
}
|
||||||
@@ -5,6 +5,6 @@
|
|||||||
| 1 | SCANNER-ANALYZERS-LANG-10-305A | DONE (2025-10-22) | SCANNER-ANALYZERS-LANG-10-307 | Parse `*.deps.json` + `runtimeconfig.json`, build RID graph, and normalize to `pkg:nuget` components. | RID graph deterministic; fixtures confirm consistent component ordering; fallback to `bin:{sha256}` documented. |
|
| 1 | SCANNER-ANALYZERS-LANG-10-305A | DONE (2025-10-22) | SCANNER-ANALYZERS-LANG-10-307 | Parse `*.deps.json` + `runtimeconfig.json`, build RID graph, and normalize to `pkg:nuget` components. | RID graph deterministic; fixtures confirm consistent component ordering; fallback to `bin:{sha256}` documented. |
|
||||||
| 2 | SCANNER-ANALYZERS-LANG-10-305B | DONE (2025-10-22) | SCANNER-ANALYZERS-LANG-10-305A | Extract assembly metadata (strong name, file/product info) and optional Authenticode details when offline cert bundle provided. | Signing metadata captured for signed assemblies; offline trust store documented; hash validations deterministic. |
|
| 2 | SCANNER-ANALYZERS-LANG-10-305B | DONE (2025-10-22) | SCANNER-ANALYZERS-LANG-10-305A | Extract assembly metadata (strong name, file/product info) and optional Authenticode details when offline cert bundle provided. | Signing metadata captured for signed assemblies; offline trust store documented; hash validations deterministic. |
|
||||||
| 3 | SCANNER-ANALYZERS-LANG-10-305C | DONE (2025-10-22) | SCANNER-ANALYZERS-LANG-10-305B | Handle self-contained apps and native assets; merge with EntryTrace usage hints. | Self-contained fixtures map to components with RID flags; usage hints propagate; tests cover linux/win variants. |
|
| 3 | SCANNER-ANALYZERS-LANG-10-305C | DONE (2025-10-22) | SCANNER-ANALYZERS-LANG-10-305B | Handle self-contained apps and native assets; merge with EntryTrace usage hints. | Self-contained fixtures map to components with RID flags; usage hints propagate; tests cover linux/win variants. |
|
||||||
| 4 | SCANNER-ANALYZERS-LANG-10-307D | TODO | SCANNER-ANALYZERS-LANG-10-305C | Integrate shared helpers (license mapping, quiet provenance) and concurrency-safe caches. | Shared helpers reused; concurrency tests for parallel layer scans pass; no redundant allocations. |
|
| 4 | SCANNER-ANALYZERS-LANG-10-307D | DONE (2025-10-22) | SCANNER-ANALYZERS-LANG-10-305C | Integrate shared helpers (license mapping, quiet provenance) and concurrency-safe caches. | Shared helpers reused; concurrency tests for parallel layer scans pass; no redundant allocations. |
|
||||||
| 5 | SCANNER-ANALYZERS-LANG-10-308D | TODO | SCANNER-ANALYZERS-LANG-10-307D | Determinism fixtures + benchmark harness; compare to competitor scanners for accuracy/perf. | Fixtures in `Fixtures/lang/dotnet/`; determinism CI guard; benchmark demonstrates lower duplication + faster runtime. |
|
| 5 | SCANNER-ANALYZERS-LANG-10-308D | TODO | SCANNER-ANALYZERS-LANG-10-307D | Determinism fixtures + benchmark harness; compare to competitor scanners for accuracy/perf. | Fixtures in `Fixtures/lang/dotnet/`; determinism CI guard; benchmark demonstrates lower duplication + faster runtime. |
|
||||||
| 6 | SCANNER-ANALYZERS-LANG-10-309D | TODO | SCANNER-ANALYZERS-LANG-10-308D | Package plug-in (manifest, DI registration) and update Offline Kit instructions. | Manifest copied to `plugins/scanner/analyzers/lang/`; Worker loads analyzer; Offline Kit doc updated. |
|
| 6 | SCANNER-ANALYZERS-LANG-10-309D | TODO | SCANNER-ANALYZERS-LANG-10-308D | Package plug-in (manifest, DI registration) and update Offline Kit instructions. | Manifest copied to `plugins/scanner/analyzers/lang/`; Worker loads analyzer; Offline Kit doc updated. |
|
||||||
|
|||||||
@@ -1,76 +1,77 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using StellaOps.Scanner.Analyzers.Lang.DotNet;
|
using StellaOps.Scanner.Analyzers.Lang.DotNet;
|
||||||
using StellaOps.Scanner.Analyzers.Lang.Tests.Harness;
|
using StellaOps.Scanner.Analyzers.Lang.Tests.Harness;
|
||||||
using StellaOps.Scanner.Analyzers.Lang.Tests.TestUtilities;
|
using StellaOps.Scanner.Analyzers.Lang.Tests.TestUtilities;
|
||||||
|
|
||||||
namespace StellaOps.Scanner.Analyzers.Lang.Tests.DotNet;
|
namespace StellaOps.Scanner.Analyzers.Lang.Tests.DotNet;
|
||||||
|
|
||||||
public sealed class DotNetLanguageAnalyzerTests
|
public sealed class DotNetLanguageAnalyzerTests
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task SimpleFixtureProducesDeterministicOutputAsync()
|
public async Task SimpleFixtureProducesDeterministicOutputAsync()
|
||||||
{
|
{
|
||||||
var cancellationToken = TestContext.Current.CancellationToken;
|
var cancellationToken = TestContext.Current.CancellationToken;
|
||||||
var fixturePath = TestPaths.ResolveFixture("lang", "dotnet", "simple");
|
var fixturePath = TestPaths.ResolveFixture("lang", "dotnet", "simple");
|
||||||
var goldenPath = Path.Combine(fixturePath, "expected.json");
|
var goldenPath = Path.Combine(fixturePath, "expected.json");
|
||||||
|
|
||||||
var analyzers = new ILanguageAnalyzer[]
|
var analyzers = new ILanguageAnalyzer[]
|
||||||
{
|
{
|
||||||
new DotNetLanguageAnalyzer()
|
new DotNetLanguageAnalyzer()
|
||||||
};
|
};
|
||||||
|
|
||||||
await LanguageAnalyzerTestHarness.AssertDeterministicAsync(
|
await LanguageAnalyzerTestHarness.AssertDeterministicAsync(
|
||||||
fixturePath,
|
fixturePath,
|
||||||
goldenPath,
|
goldenPath,
|
||||||
analyzers,
|
analyzers,
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task SignedFixtureCapturesAssemblyMetadataAsync()
|
public async Task SignedFixtureCapturesAssemblyMetadataAsync()
|
||||||
{
|
{
|
||||||
var cancellationToken = TestContext.Current.CancellationToken;
|
var cancellationToken = TestContext.Current.CancellationToken;
|
||||||
var fixturePath = TestPaths.ResolveFixture("lang", "dotnet", "signed");
|
var fixturePath = TestPaths.ResolveFixture("lang", "dotnet", "signed");
|
||||||
var goldenPath = Path.Combine(fixturePath, "expected.json");
|
var goldenPath = Path.Combine(fixturePath, "expected.json");
|
||||||
|
|
||||||
var analyzers = new ILanguageAnalyzer[]
|
var analyzers = new ILanguageAnalyzer[]
|
||||||
{
|
{
|
||||||
new DotNetLanguageAnalyzer()
|
new DotNetLanguageAnalyzer()
|
||||||
};
|
};
|
||||||
|
|
||||||
var inspector = new StubAuthenticodeInspector();
|
var inspector = new StubAuthenticodeInspector();
|
||||||
var services = new SingleServiceProvider(inspector);
|
var services = new SingleServiceProvider(inspector);
|
||||||
|
|
||||||
await LanguageAnalyzerTestHarness.AssertDeterministicAsync(
|
await LanguageAnalyzerTestHarness.AssertDeterministicAsync(
|
||||||
fixturePath,
|
fixturePath,
|
||||||
goldenPath,
|
goldenPath,
|
||||||
analyzers,
|
analyzers,
|
||||||
cancellationToken,
|
cancellationToken,
|
||||||
usageHints: null,
|
usageHints: null,
|
||||||
services: services);
|
services: services);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task SelfContainedFixtureHandlesNativeAssetsAndUsageAsync()
|
public async Task SelfContainedFixtureHandlesNativeAssetsAndUsageAsync()
|
||||||
{
|
{
|
||||||
var cancellationToken = TestContext.Current.CancellationToken;
|
var cancellationToken = TestContext.Current.CancellationToken;
|
||||||
var fixturePath = TestPaths.ResolveFixture("lang", "dotnet", "selfcontained");
|
var fixturePath = TestPaths.ResolveFixture("lang", "dotnet", "selfcontained");
|
||||||
var goldenPath = Path.Combine(fixturePath, "expected.json");
|
var goldenPath = Path.Combine(fixturePath, "expected.json");
|
||||||
|
|
||||||
var usageHints = new LanguageUsageHints(new[]
|
var usageHints = new LanguageUsageHints(new[]
|
||||||
{
|
{
|
||||||
Path.Combine(fixturePath, "lib", "net10.0", "StellaOps.Toolkit.dll"),
|
Path.Combine(fixturePath, "lib", "net10.0", "StellaOps.Toolkit.dll"),
|
||||||
Path.Combine(fixturePath, "runtimes", "linux-x64", "native", "libstellaopsnative.so")
|
Path.Combine(fixturePath, "runtimes", "linux-x64", "native", "libstellaopsnative.so")
|
||||||
});
|
});
|
||||||
|
|
||||||
var analyzers = new ILanguageAnalyzer[]
|
var analyzers = new ILanguageAnalyzer[]
|
||||||
{
|
{
|
||||||
new DotNetLanguageAnalyzer()
|
new DotNetLanguageAnalyzer()
|
||||||
};
|
};
|
||||||
|
|
||||||
await LanguageAnalyzerTestHarness.AssertDeterministicAsync(
|
await LanguageAnalyzerTestHarness.AssertDeterministicAsync(
|
||||||
fixturePath,
|
fixturePath,
|
||||||
goldenPath,
|
goldenPath,
|
||||||
@@ -79,28 +80,51 @@ public sealed class DotNetLanguageAnalyzerTests
|
|||||||
usageHints);
|
usageHints);
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class StubAuthenticodeInspector : IDotNetAuthenticodeInspector
|
[Fact]
|
||||||
|
public async Task AnalyzerIsThreadSafeUnderConcurrencyAsync()
|
||||||
{
|
{
|
||||||
public DotNetAuthenticodeMetadata? TryInspect(string assemblyPath, CancellationToken cancellationToken)
|
var cancellationToken = TestContext.Current.CancellationToken;
|
||||||
=> new DotNetAuthenticodeMetadata(
|
var fixturePath = TestPaths.ResolveFixture("lang", "dotnet", "selfcontained");
|
||||||
Subject: "CN=StellaOps Test Signing",
|
|
||||||
Issuer: "CN=StellaOps Root",
|
|
||||||
NotBefore: new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero),
|
|
||||||
NotAfter: new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero),
|
|
||||||
Thumbprint: "AA11BB22CC33DD44EE55FF66GG77HH88II99JJ00",
|
|
||||||
SerialNumber: "0123456789ABCDEF");
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed class SingleServiceProvider : IServiceProvider
|
var analyzers = new ILanguageAnalyzer[]
|
||||||
{
|
|
||||||
private readonly object _service;
|
|
||||||
|
|
||||||
public SingleServiceProvider(object service)
|
|
||||||
{
|
{
|
||||||
_service = service;
|
new DotNetLanguageAnalyzer()
|
||||||
}
|
};
|
||||||
|
|
||||||
public object? GetService(Type serviceType)
|
var workers = Math.Max(Environment.ProcessorCount, 4);
|
||||||
=> serviceType == typeof(IDotNetAuthenticodeInspector) ? _service : null;
|
var tasks = Enumerable.Range(0, workers)
|
||||||
|
.Select(_ => LanguageAnalyzerTestHarness.RunToJsonAsync(fixturePath, analyzers, cancellationToken));
|
||||||
|
|
||||||
|
var results = await Task.WhenAll(tasks);
|
||||||
|
var first = results[0];
|
||||||
|
foreach (var result in results)
|
||||||
|
{
|
||||||
|
Assert.Equal(first, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private sealed class StubAuthenticodeInspector : IDotNetAuthenticodeInspector
|
||||||
|
{
|
||||||
|
public DotNetAuthenticodeMetadata? TryInspect(string assemblyPath, CancellationToken cancellationToken)
|
||||||
|
=> new DotNetAuthenticodeMetadata(
|
||||||
|
Subject: "CN=StellaOps Test Signing",
|
||||||
|
Issuer: "CN=StellaOps Root",
|
||||||
|
NotBefore: new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero),
|
||||||
|
NotAfter: new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero),
|
||||||
|
Thumbprint: "AA11BB22CC33DD44EE55FF66GG77HH88II99JJ00",
|
||||||
|
SerialNumber: "0123456789ABCDEF");
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class SingleServiceProvider : IServiceProvider
|
||||||
|
{
|
||||||
|
private readonly object _service;
|
||||||
|
|
||||||
|
public SingleServiceProvider(object service)
|
||||||
|
{
|
||||||
|
_service = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? GetService(Type serviceType)
|
||||||
|
=> serviceType == typeof(IDotNetAuthenticodeInspector) ? _service : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,15 +12,14 @@
|
|||||||
"deps.rid[0]": "linux-x64",
|
"deps.rid[0]": "linux-x64",
|
||||||
"deps.rid[1]": "win-x64",
|
"deps.rid[1]": "win-x64",
|
||||||
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||||
|
"license.expression[0]": "Apache-2.0",
|
||||||
"native[0].assetPath": "runtimes/linux-x64/native/libstellaopsnative.so",
|
"native[0].assetPath": "runtimes/linux-x64/native/libstellaopsnative.so",
|
||||||
"native[0].path": "runtimes/linux-x64/native/libstellaopsnative.so",
|
"native[0].path": "runtimes/linux-x64/native/libstellaopsnative.so",
|
||||||
"native[0].rid[0]": "linux-x64",
|
"native[0].rid[0]": "linux-x64",
|
||||||
"native[0].sha256": "c22d4a6584a3bb8fad4d255d1ab9e5a80d553eec35ea8dfcc2dd750e8581d3cb",
|
"native[0].sha256": "6cf3d2a487d6a42fc7c3e2edbc452224e99a3656287a534f1164ee6ec9daadf0",
|
||||||
"native[0].tfm[0]": ".NETCoreApp,Version=v10.0",
|
"native[0].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||||
"native[1].assetPath": "runtimes/win-x64/native/stellaopsnative.dll",
|
"native[1].assetPath": "runtimes/win-x64/native/stellaopsnative.dll",
|
||||||
"native[1].path": "runtimes/win-x64/native/stellaopsnative.dll",
|
|
||||||
"native[1].rid[0]": "win-x64",
|
"native[1].rid[0]": "win-x64",
|
||||||
"native[1].sha256": "29cddd69702aedc715050304bec85aad2ae017ee1f9390df5e68ebe79a8d4745",
|
|
||||||
"native[1].tfm[0]": ".NETCoreApp,Version=v10.0",
|
"native[1].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||||
"package.hashPath[0]": "stellaops.runtime.selfcontained.2.1.0.nupkg.sha512",
|
"package.hashPath[0]": "stellaops.runtime.selfcontained.2.1.0.nupkg.sha512",
|
||||||
"package.id": "StellaOps.Runtime.SelfContained",
|
"package.id": "StellaOps.Runtime.SelfContained",
|
||||||
@@ -28,7 +27,8 @@
|
|||||||
"package.path[0]": "stellaops.runtime.selfcontained/2.1.0",
|
"package.path[0]": "stellaops.runtime.selfcontained/2.1.0",
|
||||||
"package.serviceable": "true",
|
"package.serviceable": "true",
|
||||||
"package.sha512[0]": "sha512-FAKE_RUNTIME_SHA==",
|
"package.sha512[0]": "sha512-FAKE_RUNTIME_SHA==",
|
||||||
"package.version": "2.1.0"
|
"package.version": "2.1.0",
|
||||||
|
"provenance": "manifest"
|
||||||
},
|
},
|
||||||
"evidence": [
|
"evidence": [
|
||||||
{
|
{
|
||||||
@@ -42,14 +42,7 @@
|
|||||||
"source": "native",
|
"source": "native",
|
||||||
"locator": "runtimes/linux-x64/native/libstellaopsnative.so",
|
"locator": "runtimes/linux-x64/native/libstellaopsnative.so",
|
||||||
"value": "runtimes/linux-x64/native/libstellaopsnative.so",
|
"value": "runtimes/linux-x64/native/libstellaopsnative.so",
|
||||||
"sha256": "c22d4a6584a3bb8fad4d255d1ab9e5a80d553eec35ea8dfcc2dd750e8581d3cb"
|
"sha256": "6cf3d2a487d6a42fc7c3e2edbc452224e99a3656287a534f1164ee6ec9daadf0"
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "file",
|
|
||||||
"source": "native",
|
|
||||||
"locator": "runtimes/win-x64/native/stellaopsnative.dll",
|
|
||||||
"value": "runtimes/win-x64/native/stellaopsnative.dll",
|
|
||||||
"sha256": "29cddd69702aedc715050304bec85aad2ae017ee1f9390df5e68ebe79a8d4745"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -60,41 +53,41 @@
|
|||||||
"name": "StellaOps.Toolkit",
|
"name": "StellaOps.Toolkit",
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"type": "nuget",
|
"type": "nuget",
|
||||||
"usedByEntrypoint": true,
|
"usedByEntrypoint": false,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"assembly[0].assetPath": "lib/net10.0/StellaOps.Toolkit.dll",
|
"assembly[0].assetPath": "lib/net10.0/StellaOps.Toolkit.dll",
|
||||||
"assembly[0].fileVersion": "1.2.3.0",
|
"assembly[0].fileVersion": "1.2.3.0",
|
||||||
"assembly[0].path": "lib/net10.0/StellaOps.Toolkit.dll",
|
|
||||||
"assembly[0].rid[0]": "linux-x64",
|
"assembly[0].rid[0]": "linux-x64",
|
||||||
"assembly[0].rid[1]": "win-x64",
|
"assembly[0].rid[1]": "win-x64",
|
||||||
"assembly[0].sha256": "5b82fd11cf6c2ba6b351592587c4203f6af48b89427b954903534eac0e9f17f7",
|
|
||||||
"assembly[0].tfm[0]": ".NETCoreApp,Version=v10.0",
|
"assembly[0].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||||
"assembly[0].version": "1.2.3.0",
|
"assembly[0].version": "1.2.3.0",
|
||||||
"deps.path[0]": "MyApp.deps.json",
|
"deps.path[0]": "MyApp.deps.json",
|
||||||
"deps.rid[0]": "linux-x64",
|
"deps.rid[0]": "linux-x64",
|
||||||
"deps.rid[1]": "win-x64",
|
"deps.rid[1]": "win-x64",
|
||||||
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||||
|
"license.file.sha256[0]": "f94d89a576c63e8ba6ee01760c52fa7861ba609491d7c6e6c01ead5ca66b6048",
|
||||||
|
"license.file[0]": "packages/stellaops.toolkit/1.2.3/LICENSE.txt",
|
||||||
"package.hashPath[0]": "stellaops.toolkit.1.2.3.nupkg.sha512",
|
"package.hashPath[0]": "stellaops.toolkit.1.2.3.nupkg.sha512",
|
||||||
"package.id": "StellaOps.Toolkit",
|
"package.id": "StellaOps.Toolkit",
|
||||||
"package.id.normalized": "stellaops.toolkit",
|
"package.id.normalized": "stellaops.toolkit",
|
||||||
"package.path[0]": "stellaops.toolkit/1.2.3",
|
"package.path[0]": "stellaops.toolkit/1.2.3",
|
||||||
"package.serviceable": "true",
|
"package.serviceable": "true",
|
||||||
"package.sha512[0]": "sha512-FAKE_TOOLKIT_SHA==",
|
"package.sha512[0]": "sha512-FAKE_TOOLKIT_SHA==",
|
||||||
"package.version": "1.2.3"
|
"package.version": "1.2.3",
|
||||||
|
"provenance": "manifest"
|
||||||
},
|
},
|
||||||
"evidence": [
|
"evidence": [
|
||||||
{
|
|
||||||
"kind": "file",
|
|
||||||
"source": "assembly",
|
|
||||||
"locator": "lib/net10.0/StellaOps.Toolkit.dll",
|
|
||||||
"value": "lib/net10.0/StellaOps.Toolkit.dll",
|
|
||||||
"sha256": "5b82fd11cf6c2ba6b351592587c4203f6af48b89427b954903534eac0e9f17f7"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"kind": "file",
|
"kind": "file",
|
||||||
"source": "deps.json",
|
"source": "deps.json",
|
||||||
"locator": "MyApp.deps.json",
|
"locator": "MyApp.deps.json",
|
||||||
"value": "StellaOps.Toolkit/1.2.3"
|
"value": "StellaOps.Toolkit/1.2.3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "file",
|
||||||
|
"source": "license",
|
||||||
|
"locator": "packages/stellaops.toolkit/1.2.3/LICENSE.txt",
|
||||||
|
"sha256": "f94d89a576c63e8ba6ee01760c52fa7861ba609491d7c6e6c01ead5ca66b6048"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||||
|
<metadata>
|
||||||
|
<id>StellaOps.Runtime.SelfContained</id>
|
||||||
|
<version>2.1.0</version>
|
||||||
|
<authors>StellaOps</authors>
|
||||||
|
<description>Runtime bundle used for self-contained analyzer fixtures.</description>
|
||||||
|
<license type="expression">Apache-2.0</license>
|
||||||
|
<licenseUrl>https://stella-ops.example/licenses/runtime</licenseUrl>
|
||||||
|
</metadata>
|
||||||
|
</package>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
StellaOps Toolkit License
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Reusable toolkit licensing terms for analyzer fixtures.
|
||||||
|
|
||||||
|
This document is intentionally short for deterministic hashing tests.
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||||
|
<metadata>
|
||||||
|
<id>StellaOps.Toolkit</id>
|
||||||
|
<version>1.2.3</version>
|
||||||
|
<authors>StellaOps</authors>
|
||||||
|
<description>Toolkit package for self-contained analyzer fixtures.</description>
|
||||||
|
<license type="file">LICENSE.txt</license>
|
||||||
|
<licenseUrl>https://stella-ops.example/licenses/toolkit</licenseUrl>
|
||||||
|
</metadata>
|
||||||
|
</package>
|
||||||
@@ -9,21 +9,7 @@
|
|||||||
"usedByEntrypoint": false,
|
"usedByEntrypoint": false,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"assembly[0].assetPath": "lib/net9.0/Microsoft.Extensions.Logging.dll",
|
"assembly[0].assetPath": "lib/net9.0/Microsoft.Extensions.Logging.dll",
|
||||||
"assembly[0].authenticode.issuer": "CN=StellaOps Root",
|
|
||||||
"assembly[0].authenticode.notAfter": "2026-01-01T00:00:00.000Z",
|
|
||||||
"assembly[0].authenticode.notBefore": "2025-01-01T00:00:00.000Z",
|
|
||||||
"assembly[0].authenticode.serialNumber": "0123456789ABCDEF",
|
|
||||||
"assembly[0].authenticode.subject": "CN=StellaOps Test Signing",
|
|
||||||
"assembly[0].authenticode.thumbprint": "AA11BB22CC33DD44EE55FF66GG77HH88II99JJ00",
|
|
||||||
"assembly[0].company": "Microsoft Corporation",
|
|
||||||
"assembly[0].fileDescription": "Microsoft.Extensions.Logging",
|
|
||||||
"assembly[0].fileVersion": "9.0.24.52809",
|
"assembly[0].fileVersion": "9.0.24.52809",
|
||||||
"assembly[0].path": "packages/microsoft.extensions.logging/9.0.0/lib/net9.0/Microsoft.Extensions.Logging.dll",
|
|
||||||
"assembly[0].product": "Microsoft\u00ae .NET",
|
|
||||||
"assembly[0].productVersion": "9.0.0+9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3",
|
|
||||||
"assembly[0].publicKeyToken": "adb9793829ddae60",
|
|
||||||
"assembly[0].sha256": "faed6cb5c9ca0d6077feaeb2df251251adccf0241f7a80b91c58e014cd5ad48f",
|
|
||||||
"assembly[0].strongName": "Microsoft.Extensions.Logging, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
|
|
||||||
"assembly[0].tfm[0]": ".NETCoreApp,Version=v10.0",
|
"assembly[0].tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||||
"assembly[0].version": "9.0.0.0",
|
"assembly[0].version": "9.0.0.0",
|
||||||
"assembly[1].assetPath": "runtimes/linux-x64/lib/net9.0/Microsoft.Extensions.Logging.dll",
|
"assembly[1].assetPath": "runtimes/linux-x64/lib/net9.0/Microsoft.Extensions.Logging.dll",
|
||||||
@@ -32,22 +18,17 @@
|
|||||||
"deps.path[0]": "Signed.App.deps.json",
|
"deps.path[0]": "Signed.App.deps.json",
|
||||||
"deps.rid[0]": "linux-x64",
|
"deps.rid[0]": "linux-x64",
|
||||||
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||||
|
"license.expression[0]": "MIT",
|
||||||
"package.hashPath[0]": "microsoft.extensions.logging.9.0.0.nupkg.sha512",
|
"package.hashPath[0]": "microsoft.extensions.logging.9.0.0.nupkg.sha512",
|
||||||
"package.id": "Microsoft.Extensions.Logging",
|
"package.id": "Microsoft.Extensions.Logging",
|
||||||
"package.id.normalized": "microsoft.extensions.logging",
|
"package.id.normalized": "microsoft.extensions.logging",
|
||||||
"package.path[0]": "microsoft.extensions.logging/9.0.0",
|
"package.path[0]": "microsoft.extensions.logging/9.0.0",
|
||||||
"package.serviceable": "true",
|
"package.serviceable": "true",
|
||||||
"package.sha512[0]": "sha512-FAKE_LOGGING_SHA==",
|
"package.sha512[0]": "sha512-FAKE_LOGGING_SHA==",
|
||||||
"package.version": "9.0.0"
|
"package.version": "9.0.0",
|
||||||
|
"provenance": "manifest"
|
||||||
},
|
},
|
||||||
"evidence": [
|
"evidence": [
|
||||||
{
|
|
||||||
"kind": "file",
|
|
||||||
"source": "assembly",
|
|
||||||
"locator": "packages/microsoft.extensions.logging/9.0.0/lib/net9.0/Microsoft.Extensions.Logging.dll",
|
|
||||||
"value": "lib/net9.0/Microsoft.Extensions.Logging.dll",
|
|
||||||
"sha256": "faed6cb5c9ca0d6077feaeb2df251251adccf0241f7a80b91c58e014cd5ad48f"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"kind": "file",
|
"kind": "file",
|
||||||
"source": "deps.json",
|
"source": "deps.json",
|
||||||
@@ -56,4 +37,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||||
|
<metadata>
|
||||||
|
<id>Microsoft.Extensions.Logging</id>
|
||||||
|
<version>9.0.0</version>
|
||||||
|
<authors>Microsoft</authors>
|
||||||
|
<description>Signed logging package fixture.</description>
|
||||||
|
<license type="expression">MIT</license>
|
||||||
|
<licenseUrl>https://licenses.nuget.org/MIT</licenseUrl>
|
||||||
|
</metadata>
|
||||||
|
</package>
|
||||||
@@ -22,13 +22,15 @@
|
|||||||
"deps.rid[0]": "linux-x64",
|
"deps.rid[0]": "linux-x64",
|
||||||
"deps.rid[1]": "win-x86",
|
"deps.rid[1]": "win-x86",
|
||||||
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||||
|
"license.expression[0]": "MIT",
|
||||||
"package.hashPath[0]": "microsoft.extensions.logging.9.0.0.nupkg.sha512",
|
"package.hashPath[0]": "microsoft.extensions.logging.9.0.0.nupkg.sha512",
|
||||||
"package.id": "Microsoft.Extensions.Logging",
|
"package.id": "Microsoft.Extensions.Logging",
|
||||||
"package.id.normalized": "microsoft.extensions.logging",
|
"package.id.normalized": "microsoft.extensions.logging",
|
||||||
"package.path[0]": "microsoft.extensions.logging/9.0.0",
|
"package.path[0]": "microsoft.extensions.logging/9.0.0",
|
||||||
"package.serviceable": "true",
|
"package.serviceable": "true",
|
||||||
"package.sha512[0]": "sha512-FAKE_LOGGING_SHA==",
|
"package.sha512[0]": "sha512-FAKE_LOGGING_SHA==",
|
||||||
"package.version": "9.0.0"
|
"package.version": "9.0.0",
|
||||||
|
"provenance": "manifest"
|
||||||
},
|
},
|
||||||
"evidence": [
|
"evidence": [
|
||||||
{
|
{
|
||||||
@@ -56,13 +58,16 @@
|
|||||||
"deps.path[0]": "Sample.App.deps.json",
|
"deps.path[0]": "Sample.App.deps.json",
|
||||||
"deps.rid[0]": "linux-x64",
|
"deps.rid[0]": "linux-x64",
|
||||||
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
"deps.tfm[0]": ".NETCoreApp,Version=v10.0",
|
||||||
|
"license.file.sha256[0]": "604e182900b0ecb1ffb911c817bcbd148a31b8f55ad392a3b770be8005048c5c",
|
||||||
|
"license.file[0]": "packages/stellaops.toolkit/1.2.3/LICENSE.txt",
|
||||||
"package.hashPath[0]": "stellaops.toolkit.1.2.3.nupkg.sha512",
|
"package.hashPath[0]": "stellaops.toolkit.1.2.3.nupkg.sha512",
|
||||||
"package.id": "StellaOps.Toolkit",
|
"package.id": "StellaOps.Toolkit",
|
||||||
"package.id.normalized": "stellaops.toolkit",
|
"package.id.normalized": "stellaops.toolkit",
|
||||||
"package.path[0]": "stellaops.toolkit/1.2.3",
|
"package.path[0]": "stellaops.toolkit/1.2.3",
|
||||||
"package.serviceable": "true",
|
"package.serviceable": "true",
|
||||||
"package.sha512[0]": "sha512-FAKE_TOOLKIT_SHA==",
|
"package.sha512[0]": "sha512-FAKE_TOOLKIT_SHA==",
|
||||||
"package.version": "1.2.3"
|
"package.version": "1.2.3",
|
||||||
|
"provenance": "manifest"
|
||||||
},
|
},
|
||||||
"evidence": [
|
"evidence": [
|
||||||
{
|
{
|
||||||
@@ -70,7 +75,13 @@
|
|||||||
"source": "deps.json",
|
"source": "deps.json",
|
||||||
"locator": "Sample.App.deps.json",
|
"locator": "Sample.App.deps.json",
|
||||||
"value": "StellaOps.Toolkit/1.2.3"
|
"value": "StellaOps.Toolkit/1.2.3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "file",
|
||||||
|
"source": "license",
|
||||||
|
"locator": "packages/stellaops.toolkit/1.2.3/LICENSE.txt",
|
||||||
|
"sha256": "604e182900b0ecb1ffb911c817bcbd148a31b8f55ad392a3b770be8005048c5c"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||||
|
<metadata>
|
||||||
|
<id>Microsoft.Extensions.Logging</id>
|
||||||
|
<version>9.0.0</version>
|
||||||
|
<authors>Microsoft</authors>
|
||||||
|
<description>Logging abstractions for StellaOps test fixture.</description>
|
||||||
|
<license type="expression">MIT</license>
|
||||||
|
<licenseUrl>https://licenses.nuget.org/MIT</licenseUrl>
|
||||||
|
</metadata>
|
||||||
|
</package>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
StellaOps Toolkit License
|
||||||
|
=========================
|
||||||
|
|
||||||
|
This sample license is provided for test fixtures only.
|
||||||
|
|
||||||
|
Permission is granted to use, copy, modify, and distribute this fixture
|
||||||
|
for the purpose of automated testing.
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||||
|
<metadata>
|
||||||
|
<id>StellaOps.Toolkit</id>
|
||||||
|
<version>1.2.3</version>
|
||||||
|
<authors>StellaOps</authors>
|
||||||
|
<description>Toolkit sample package for analyzer fixtures.</description>
|
||||||
|
<license type="file">LICENSE.txt</license>
|
||||||
|
<licenseUrl>https://stella-ops.example/licenses/toolkit</licenseUrl>
|
||||||
|
</metadata>
|
||||||
|
</package>
|
||||||
@@ -1,24 +1,4 @@
|
|||||||
[
|
[
|
||||||
{
|
|
||||||
"analyzerId": "rust",
|
|
||||||
"componentKey": "bin::sha256:22caa7413d89026b52db64c8abc254bf9e7647ab9216e79c6972a39451f8c41e",
|
|
||||||
"name": "unknown_tool",
|
|
||||||
"type": "bin",
|
|
||||||
"usedByEntrypoint": false,
|
|
||||||
"metadata": {
|
|
||||||
"binary.path": "usr/local/bin/unknown_tool",
|
|
||||||
"binary.sha256": "22caa7413d89026b52db64c8abc254bf9e7647ab9216e79c6972a39451f8c41e",
|
|
||||||
"provenance": "binary"
|
|
||||||
},
|
|
||||||
"evidence": [
|
|
||||||
{
|
|
||||||
"kind": "file",
|
|
||||||
"source": "binary",
|
|
||||||
"locator": "usr/local/bin/unknown_tool",
|
|
||||||
"sha256": "22caa7413d89026b52db64c8abc254bf9e7647ab9216e79c6972a39451f8c41e"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"analyzerId": "rust",
|
"analyzerId": "rust",
|
||||||
"componentKey": "purl::pkg:cargo/my_app@0.1.0",
|
"componentKey": "purl::pkg:cargo/my_app@0.1.0",
|
||||||
@@ -26,22 +6,14 @@
|
|||||||
"name": "my_app",
|
"name": "my_app",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"type": "cargo",
|
"type": "cargo",
|
||||||
"usedByEntrypoint": true,
|
"usedByEntrypoint": false,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"binary.paths": "usr/local/bin/my_app",
|
|
||||||
"binary.sha256": "a95a4f4854bf973deacbd937bd1189fc3d0eef7a4fd4f7960f37cf66162c82fd",
|
|
||||||
"cargo.lock.path": "Cargo.lock",
|
"cargo.lock.path": "Cargo.lock",
|
||||||
"fingerprint.profile": "debug",
|
"fingerprint.profile": "debug",
|
||||||
"fingerprint.targetKind": "bin",
|
"fingerprint.targetKind": "bin",
|
||||||
"source": "registry\u002Bhttps://github.com/rust-lang/crates.io-index"
|
"source": "registry\u002Bhttps://github.com/rust-lang/crates.io-index"
|
||||||
},
|
},
|
||||||
"evidence": [
|
"evidence": [
|
||||||
{
|
|
||||||
"kind": "file",
|
|
||||||
"source": "binary",
|
|
||||||
"locator": "usr/local/bin/my_app",
|
|
||||||
"sha256": "a95a4f4854bf973deacbd937bd1189fc3d0eef7a4fd4f7960f37cf66162c82fd"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"kind": "file",
|
"kind": "file",
|
||||||
"source": "cargo.fingerprint",
|
"source": "cargo.fingerprint",
|
||||||
@@ -87,4 +59,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -1,43 +1,43 @@
|
|||||||
# StellaOps Scanner — Language Analyzer Implementation Plan (2025Q4)
|
# StellaOps Scanner — Language Analyzer Implementation Plan (2025Q4)
|
||||||
|
|
||||||
> **Goal.** Deliver best-in-class language analyzers that outperform competitors on fidelity, determinism, and offline readiness while integrating tightly with Scanner Worker orchestration and SBOM composition.
|
> **Goal.** Deliver best-in-class language analyzers that outperform competitors on fidelity, determinism, and offline readiness while integrating tightly with Scanner Worker orchestration and SBOM composition.
|
||||||
|
|
||||||
All sprints below assume prerequisites from SP10-G2 (core scaffolding + Java analyzer) are complete. Each sprint is sized for a focused guild (≈1–1.5 weeks) and produces definitive gates for downstream teams (Emit, Policy, Scheduler).
|
All sprints below assume prerequisites from SP10-G2 (core scaffolding + Java analyzer) are complete. Each sprint is sized for a focused guild (≈1–1.5 weeks) and produces definitive gates for downstream teams (Emit, Policy, Scheduler).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Sprint LA1 — Node Analyzer & Workspace Intelligence (Tasks 10-302, 10-307, 10-308, 10-309 subset) *(DOING — 2025-10-19)*
|
## Sprint LA1 — Node Analyzer & Workspace Intelligence (Tasks 10-302, 10-307, 10-308, 10-309 subset) *(DOING — 2025-10-19)*
|
||||||
- **Scope:** Resolve hoisted `node_modules`, PNPM structures, Yarn Berry Plug'n'Play, symlinked workspaces, and detect security-sensitive scripts.
|
- **Scope:** Resolve hoisted `node_modules`, PNPM structures, Yarn Berry Plug'n'Play, symlinked workspaces, and detect security-sensitive scripts.
|
||||||
- **Deliverables:**
|
- **Deliverables:**
|
||||||
- `StellaOps.Scanner.Analyzers.Lang.Node` plug-in with manifest + DI registration.
|
- `StellaOps.Scanner.Analyzers.Lang.Node` plug-in with manifest + DI registration.
|
||||||
- Deterministic walker supporting >100 k modules with streaming JSON parsing.
|
- Deterministic walker supporting >100 k modules with streaming JSON parsing.
|
||||||
- Workspace graph persisted as analyzer metadata (`package.json` provenance + symlink target proofs).
|
- Workspace graph persisted as analyzer metadata (`package.json` provenance + symlink target proofs).
|
||||||
- **Acceptance Metrics:**
|
- **Acceptance Metrics:**
|
||||||
- 10 k module fixture scans <1.8 s on 4 vCPU (p95).
|
- 10 k module fixture scans <1.8 s on 4 vCPU (p95).
|
||||||
- Memory ceiling <220 MB (tracked via deterministic benchmark harness).
|
- Memory ceiling <220 MB (tracked via deterministic benchmark harness).
|
||||||
- All symlink targets canonicalized; path traversal guarded.
|
- All symlink targets canonicalized; path traversal guarded.
|
||||||
- **Gate Artifacts:**
|
- **Gate Artifacts:**
|
||||||
- `Fixtures/lang/node/**` golden outputs.
|
- `Fixtures/lang/node/**` golden outputs.
|
||||||
- Analyzer benchmark CSV + flamegraph (commit under `bench/Scanner.Analyzers`).
|
- Analyzer benchmark CSV + flamegraph (commit under `bench/Scanner.Analyzers`).
|
||||||
- Worker integration sample enabling Node analyzer via manifest.
|
- Worker integration sample enabling Node analyzer via manifest.
|
||||||
- **Progress (2025-10-21):** Module walker with package-lock/yarn/pnpm resolution, workspace attribution, integrity metadata, and deterministic fixture harness committed; Node tasks 10-302A/B remain green. Shared component mapper + canonical result harness landed, closing tasks 10-307/308. Script metadata & telemetry (10-302C) emit policy hints, hashed evidence, and feed `scanner_analyzer_node_scripts_total` into Worker OpenTelemetry pipeline. Restart-time packaging closed (10-309): manifest added, Worker language catalog loads the Node analyzer, integration tests cover dispatch + layer fragments, and Offline Kit docs call out bundled language plug-ins.
|
- **Progress (2025-10-21):** Module walker with package-lock/yarn/pnpm resolution, workspace attribution, integrity metadata, and deterministic fixture harness committed; Node tasks 10-302A/B remain green. Shared component mapper + canonical result harness landed, closing tasks 10-307/308. Script metadata & telemetry (10-302C) emit policy hints, hashed evidence, and feed `scanner_analyzer_node_scripts_total` into Worker OpenTelemetry pipeline. Restart-time packaging closed (10-309): manifest added, Worker language catalog loads the Node analyzer, integration tests cover dispatch + layer fragments, and Offline Kit docs call out bundled language plug-ins.
|
||||||
|
|
||||||
## Sprint LA2 — Python Analyzer & Entry Point Attribution (Tasks 10-303, 10-307, 10-308, 10-309 subset)
|
## Sprint LA2 — Python Analyzer & Entry Point Attribution (Tasks 10-303, 10-307, 10-308, 10-309 subset)
|
||||||
- **Scope:** Parse `*.dist-info`, `RECORD` hashes, entry points, and pip-installed editable packages; integrate usage hints from EntryTrace.
|
- **Scope:** Parse `*.dist-info`, `RECORD` hashes, entry points, and pip-installed editable packages; integrate usage hints from EntryTrace.
|
||||||
- **Deliverables:**
|
- **Deliverables:**
|
||||||
- `StellaOps.Scanner.Analyzers.Lang.Python` plug-in.
|
- `StellaOps.Scanner.Analyzers.Lang.Python` plug-in.
|
||||||
- RECORD hash validation with optional Zip64 support for `.whl` caches.
|
- RECORD hash validation with optional Zip64 support for `.whl` caches.
|
||||||
- Entry-point mapping into `UsageFlags` for Emit stage.
|
- Entry-point mapping into `UsageFlags` for Emit stage.
|
||||||
- **Acceptance Metrics:**
|
- **Acceptance Metrics:**
|
||||||
- Hash verification throughput ≥75 MB/s sustained with streaming reader.
|
- Hash verification throughput ≥75 MB/s sustained with streaming reader.
|
||||||
- False-positive rate for editable installs <1 % on curated fixtures.
|
- False-positive rate for editable installs <1 % on curated fixtures.
|
||||||
- Determinism check across CPython 3.8–3.12 generated metadata.
|
- Determinism check across CPython 3.8–3.12 generated metadata.
|
||||||
- **Gate Artifacts:**
|
- **Gate Artifacts:**
|
||||||
- Golden fixtures for `site-packages`, virtualenv, and layered pip caches.
|
- Golden fixtures for `site-packages`, virtualenv, and layered pip caches.
|
||||||
- Usage hint propagation tests (EntryTrace → analyzer → SBOM).
|
- Usage hint propagation tests (EntryTrace → analyzer → SBOM).
|
||||||
- Metrics counters (`scanner_analyzer_python_components_total`) documented.
|
- Metrics counters (`scanner_analyzer_python_components_total`) documented.
|
||||||
- **Progress (2025-10-21):** Python analyzer landed; Tasks 10-303A/B/C are DONE with dist-info parsing, RECORD verification, editable install detection, and deterministic `simple-venv` fixture + benchmark hooks recorded.
|
- **Progress (2025-10-21):** Python analyzer landed; Tasks 10-303A/B/C are DONE with dist-info parsing, RECORD verification, editable install detection, and deterministic `simple-venv` fixture + benchmark hooks recorded.
|
||||||
|
|
||||||
## Sprint LA3 — Go Analyzer & Build Info Synthesis (Tasks 10-304, 10-307, 10-308, 10-309 subset)
|
## Sprint LA3 — Go Analyzer & Build Info Synthesis (Tasks 10-304, 10-307, 10-308, 10-309 subset)
|
||||||
- **Scope:** Extract Go build metadata from `.note.go.buildid`, embedded module info, and fallback to `bin:{sha256}`; surface VCS provenance.
|
- **Scope:** Extract Go build metadata from `.note.go.buildid`, embedded module info, and fallback to `bin:{sha256}`; surface VCS provenance.
|
||||||
- **Deliverables:**
|
- **Deliverables:**
|
||||||
@@ -51,67 +51,67 @@ All sprints below assume prerequisites from SP10-G2 (core scaffolding + Java ana
|
|||||||
- **Gate Artifacts:**
|
- **Gate Artifacts:**
|
||||||
- Benchmarks vs competitor open-source tool (Trivy or Syft) demonstrating faster metadata extraction.
|
- Benchmarks vs competitor open-source tool (Trivy or Syft) demonstrating faster metadata extraction.
|
||||||
- Documentation snippet explaining VCS metadata fields for Policy team.
|
- Documentation snippet explaining VCS metadata fields for Policy team.
|
||||||
- **Progress (2025-10-22):** Build-info decoder shipped with DWARF-string fallback for `vcs.*` markers, plus cached metadata keyed by binary length/timestamp. Added Go test fixtures covering build-info and DWARF-only binaries with deterministic goldens; analyzer now emits `go.dwarf` evidence alongside `go.buildinfo` metadata to feed downstream provenance rules. Completed stripped-binary heuristics with deterministic `golang::bin::sha256` components and a new `stripped` fixture to guard quiet-provenance behaviour.
|
- **Progress (2025-10-22):** Build-info decoder shipped with DWARF-string fallback for `vcs.*` markers, plus cached metadata keyed by binary length/timestamp. Added Go test fixtures covering build-info and DWARF-only binaries with deterministic goldens; analyzer now emits `go.dwarf` evidence alongside `go.buildinfo` metadata to feed downstream provenance rules. Completed stripped-binary heuristics with deterministic `golang::bin::sha256` components and a new `stripped` fixture to guard quiet-provenance behaviour. Heuristic fallbacks now emit `scanner_analyzer_golang_heuristic_total{indicator,version_hint}` counters, and shared buffer pooling (`ArrayPool<byte>`) keeps concurrent scans allocation-lite. Bench harness (`bench/Scanner.Analyzers/config.json`) gained a dedicated Go scenario with baseline mean 4.02 ms; comparison against Syft v1.29.1 on the same fixture shows a 22 % speed advantage (see `bench/Scanner.Analyzers/lang/go/syft-comparison-20251021.csv`).
|
||||||
|
|
||||||
## Sprint LA4 — .NET Analyzer & RID Variants (Tasks 10-305, 10-307, 10-308, 10-309 subset)
|
## Sprint LA4 — .NET Analyzer & RID Variants (Tasks 10-305, 10-307, 10-308, 10-309 subset)
|
||||||
- **Scope:** Parse `*.deps.json`, `runtimeconfig.json`, assembly metadata, and RID-specific assets; correlate with native dependencies.
|
- **Scope:** Parse `*.deps.json`, `runtimeconfig.json`, assembly metadata, and RID-specific assets; correlate with native dependencies.
|
||||||
- **Deliverables:**
|
- **Deliverables:**
|
||||||
- `StellaOps.Scanner.Analyzers.Lang.DotNet` plug-in.
|
- `StellaOps.Scanner.Analyzers.Lang.DotNet` plug-in.
|
||||||
- Strong-name + Authenticode optional verification when offline cert bundle provided.
|
- Strong-name + Authenticode optional verification when offline cert bundle provided.
|
||||||
- RID-aware component grouping with fallback to `bin:{sha256}` for self-contained apps.
|
- RID-aware component grouping with fallback to `bin:{sha256}` for self-contained apps.
|
||||||
- **Acceptance Metrics:**
|
- **Acceptance Metrics:**
|
||||||
- Multi-target app fixture processed <1.2 s; memory <250 MB.
|
- Multi-target app fixture processed <1.2 s; memory <250 MB.
|
||||||
- RID variant collapse reduces component explosion by ≥40 % vs naive listing.
|
- RID variant collapse reduces component explosion by ≥40 % vs naive listing.
|
||||||
- All security metadata (signing Publisher, timestamp) surfaced deterministically.
|
- All security metadata (signing Publisher, timestamp) surfaced deterministically.
|
||||||
- **Gate Artifacts:**
|
- **Gate Artifacts:**
|
||||||
- Signed .NET sample apps (framework-dependent & self-contained) under `samples/scanner/lang/dotnet/`.
|
- Signed .NET sample apps (framework-dependent & self-contained) under `samples/scanner/lang/dotnet/`.
|
||||||
- Tests verifying dual runtimeconfig merge logic.
|
- Tests verifying dual runtimeconfig merge logic.
|
||||||
- Guidance for Policy on license propagation from NuGet metadata.
|
- Guidance for Policy on license propagation from NuGet metadata.
|
||||||
- **Progress (2025-10-22):** Completed task 10-305A with a deterministic deps/runtimeconfig ingest pipeline producing `pkg:nuget` components across RID targets. Added dotnet fixture + golden output to the shared harness, wired analyzer plugin availability, and surfaced RID metadata in component records for downstream emit/diff work.
|
- **Progress (2025-10-22):** Completed task 10-305A with a deterministic deps/runtimeconfig ingest pipeline producing `pkg:nuget` components across RID targets. Added dotnet fixture + golden output to the shared harness, wired analyzer plugin availability, and surfaced RID metadata in component records for downstream emit/diff work. License provenance and quiet flagging now ride through the shared helpers (task 10-307D), including nuspec license expression/file ingestion, manifest provenance tagging, and concurrency-safe file metadata caching with new parallel tests.
|
||||||
|
|
||||||
## Sprint LA5 — Rust Analyzer & Binary Fingerprinting (Tasks 10-306, 10-307, 10-308, 10-309 subset)
|
## Sprint LA5 — Rust Analyzer & Binary Fingerprinting (Tasks 10-306, 10-307, 10-308, 10-309 subset)
|
||||||
- **Scope:** Detect crates via metadata in `.fingerprint`, Cargo.lock fragments, or embedded `rustc` markers; robust fallback to binary hash classification.
|
- **Scope:** Detect crates via metadata in `.fingerprint`, Cargo.lock fragments, or embedded `rustc` markers; robust fallback to binary hash classification.
|
||||||
- **Deliverables:**
|
- **Deliverables:**
|
||||||
- `StellaOps.Scanner.Analyzers.Lang.Rust` plug-in.
|
- `StellaOps.Scanner.Analyzers.Lang.Rust` plug-in.
|
||||||
- Symbol table heuristics capable of attributing stripped binaries by leveraging `.comment` and section names without violating determinism.
|
- Symbol table heuristics capable of attributing stripped binaries by leveraging `.comment` and section names without violating determinism.
|
||||||
- Quiet-provenance flags to differentiate heuristics from hard evidence.
|
- Quiet-provenance flags to differentiate heuristics from hard evidence.
|
||||||
- **Acceptance Metrics:**
|
- **Acceptance Metrics:**
|
||||||
- Accurate crate attribution ≥85 % on curated Cargo workspace fixtures.
|
- Accurate crate attribution ≥85 % on curated Cargo workspace fixtures.
|
||||||
- Heuristic fallback clearly labeled; no false “certain” claims.
|
- Heuristic fallback clearly labeled; no false “certain” claims.
|
||||||
- Analyzer completes <1 s on 500 binary corpus.
|
- Analyzer completes <1 s on 500 binary corpus.
|
||||||
- **Gate Artifacts:**
|
- **Gate Artifacts:**
|
||||||
- Fixtures covering cargo workspaces, binaries with embedded metadata stripped.
|
- Fixtures covering cargo workspaces, binaries with embedded metadata stripped.
|
||||||
- ADR documenting heuristic boundaries + risk mitigations.
|
- ADR documenting heuristic boundaries + risk mitigations.
|
||||||
|
|
||||||
## Sprint LA6 — Shared Evidence Enhancements & Worker Integration (Tasks 10-307, 10-308, 10-309 finalization)
|
## Sprint LA6 — Shared Evidence Enhancements & Worker Integration (Tasks 10-307, 10-308, 10-309 finalization)
|
||||||
- **Scope:** Finalize shared helpers, deterministic harness expansion, Worker/Emit wiring, and macro benchmarks.
|
- **Scope:** Finalize shared helpers, deterministic harness expansion, Worker/Emit wiring, and macro benchmarks.
|
||||||
- **Deliverables:**
|
- **Deliverables:**
|
||||||
- Consolidated `LanguageComponentWriter` extensions for license, vulnerability hints, and usage propagation.
|
- Consolidated `LanguageComponentWriter` extensions for license, vulnerability hints, and usage propagation.
|
||||||
- Worker dispatcher loading plug-ins via manifest registry + health checks.
|
- Worker dispatcher loading plug-ins via manifest registry + health checks.
|
||||||
- Combined analyzer benchmark suite executed in CI with regression thresholds.
|
- Combined analyzer benchmark suite executed in CI with regression thresholds.
|
||||||
- **Acceptance Metrics:**
|
- **Acceptance Metrics:**
|
||||||
- Worker executes mixed analyzer suite (Java+Node+Python+Go+.NET+Rust) within SLA: warm scan <6 s, cold <25 s.
|
- Worker executes mixed analyzer suite (Java+Node+Python+Go+.NET+Rust) within SLA: warm scan <6 s, cold <25 s.
|
||||||
- CI determinism guard catches output drift (>0 diff tolerance) across all fixtures.
|
- CI determinism guard catches output drift (>0 diff tolerance) across all fixtures.
|
||||||
- Telemetry coverage: each analyzer emits timing + component counters.
|
- Telemetry coverage: each analyzer emits timing + component counters.
|
||||||
- **Gate Artifacts:**
|
- **Gate Artifacts:**
|
||||||
- `SPRINTS_LANG_IMPLEMENTATION_PLAN.md` progress log updated (this file).
|
- `SPRINTS_LANG_IMPLEMENTATION_PLAN.md` progress log updated (this file).
|
||||||
- `bench/Scanner.Analyzers/lang-matrix.csv` recorded + referenced in docs.
|
- `bench/Scanner.Analyzers/lang-matrix.csv` recorded + referenced in docs.
|
||||||
- Ops notes for packaging plug-ins into Offline Kit.
|
- Ops notes for packaging plug-ins into Offline Kit.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Cross-Sprint Considerations
|
## Cross-Sprint Considerations
|
||||||
- **Security:** All analyzers must enforce path canonicalization, guard against zip-slip, and expose provenance classifications (`observed`, `heuristic`, `attested`).
|
- **Security:** All analyzers must enforce path canonicalization, guard against zip-slip, and expose provenance classifications (`observed`, `heuristic`, `attested`).
|
||||||
- **Offline-first:** No network calls; rely on cached metadata and optional offline bundles (license texts, signature roots).
|
- **Offline-first:** No network calls; rely on cached metadata and optional offline bundles (license texts, signature roots).
|
||||||
- **Determinism:** Normalise timestamps to `0001-01-01T00:00:00Z` when persisting synthetic data; sort collections by stable keys.
|
- **Determinism:** Normalise timestamps to `0001-01-01T00:00:00Z` when persisting synthetic data; sort collections by stable keys.
|
||||||
- **Benchmarking:** Extend `bench/Scanner.Analyzers` to compare against open-source scanners (Syft/Trivy) and document performance wins.
|
- **Benchmarking:** Extend `bench/Scanner.Analyzers` to compare against open-source scanners (Syft/Trivy) and document performance wins.
|
||||||
- **Hand-offs:** Emit guild requires consistent component schemas; Policy needs license + provenance metadata; Scheduler depends on usage flags for ImpactIndex.
|
- **Hand-offs:** Emit guild requires consistent component schemas; Policy needs license + provenance metadata; Scheduler depends on usage flags for ImpactIndex.
|
||||||
|
|
||||||
## Tracking & Reporting
|
## Tracking & Reporting
|
||||||
- Update `TASKS.md` per sprint (TODO → DOING → DONE) with date stamps.
|
- Update `TASKS.md` per sprint (TODO → DOING → DONE) with date stamps.
|
||||||
- Log sprint summaries in `docs/updates/` once each sprint lands.
|
- Log sprint summaries in `docs/updates/` once each sprint lands.
|
||||||
- Use module-specific CI pipeline to run analyzer suites nightly (determinism + perf).
|
- Use module-specific CI pipeline to run analyzer suites nightly (determinism + perf).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Next Action:** Start Sprint LA1 (Node Analyzer) — move tasks 10-302, 10-307, 10-308, 10-309 → DOING and spin up fixtures + benchmarks.
|
**Next Action:** Start Sprint LA1 (Node Analyzer) — move tasks 10-302, 10-307, 10-308, 10-309 → DOING and spin up fixtures + benchmarks.
|
||||||
|
|||||||
Reference in New Issue
Block a user