From b9cd74c5a9ce51af754a0607f8900423aaa785a2 Mon Sep 17 00:00:00 2001 From: Meik Date: Thu, 9 Jul 2026 23:30:07 +0200 Subject: [PATCH] Log LIAM assembly identities and cap traverse depth --- LiamNtfs/C4IT.LIAM.Ntfs.cs | 30 ++++++++++++++- .../C4IT.LIAM.WorkflowactivityBase.cs | 38 +++++++++++++++++++ README.md | 6 +-- 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/LiamNtfs/C4IT.LIAM.Ntfs.cs b/LiamNtfs/C4IT.LIAM.Ntfs.cs index 1b5a10e..3dd44a5 100644 --- a/LiamNtfs/C4IT.LIAM.Ntfs.cs +++ b/LiamNtfs/C4IT.LIAM.Ntfs.cs @@ -1521,10 +1521,33 @@ namespace C4IT.LIAM private cNtfsLevelRange GetTraverseLevelRange() { - return GetConfiguredLevelRange( + var range = GetConfiguredLevelRange( AdditionalConfigurationTraverseGroupsMinLevelKey, AdditionalConfigurationTraverseGroupsMaxLevelKey, "traverse group level range"); + if (range.IsValid + && !HasAdditionalConfigurationValue(AdditionalConfigurationTraverseGroupsMaxLevelKey) + && MaxDepth > 0) + { + var maxDepthLevel = MaxDepth - 1; + if (range.IsConfigured) + { + range.MaxLevel = Math.Min(range.MaxLevel, maxDepthLevel); + } + else + { + range.IsConfigured = true; + range.MaxLevel = maxDepthLevel; + } + + if (range.MinLevel > range.MaxLevel) + { + range.IsValid = false; + range.ErrorMessage = $"AdditionalConfiguration traverse group level range is invalid because min level {range.MinLevel} is greater than effective max level {range.MaxLevel}."; + } + } + + return range; } private cNtfsLevelRange GetConfiguredLevelRange(string minKey, string maxKey, string label) @@ -1572,6 +1595,11 @@ namespace C4IT.LIAM return range; } + private bool HasAdditionalConfigurationValue(string key) + { + return !string.IsNullOrWhiteSpace(GetAdditionalConfigurationValue(key)); + } + private static bool IsSupportedPermissionManagedPathKind(cNtfsPathClassification classification, params eNtfsPathKind[] supportedKinds) { if (classification == null || supportedKinds == null || supportedKinds.Length == 0) diff --git a/LiamWorkflowActivities/C4IT.LIAM.WorkflowactivityBase.cs b/LiamWorkflowActivities/C4IT.LIAM.WorkflowactivityBase.cs index a0a049b..e2d3d3f 100644 --- a/LiamWorkflowActivities/C4IT.LIAM.WorkflowactivityBase.cs +++ b/LiamWorkflowActivities/C4IT.LIAM.WorkflowactivityBase.cs @@ -2,7 +2,9 @@ using System; using System.Activities; using System.ComponentModel; +using System.Diagnostics; using System.Reflection; +using System.Security.Cryptography; using static C4IT.Logging.cLogManager; using Matrix42.Contracts.Platform.Data; using Matrix42.ServiceRepository.Contracts.Components; @@ -120,6 +122,9 @@ namespace LiamWorkflowActivities var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); cLogManager.DefaultLogger.LogAssemblyInfo(Ass); + LogAssemblyIdentity("WorkflowActivities", Ass); + LogAssemblyIdentity("LiamNtfs", typeof(cLiamProviderNtfs).Assembly); + LogAssemblyIdentity("LiamBaseClasses", typeof(cLiamProviderBase).Assembly); IsInitialized = true; LogMethodEnd(CM); } @@ -127,6 +132,39 @@ namespace LiamWorkflowActivities catch { }; } + private static void LogAssemblyIdentity(string label, Assembly assembly) + { + if (assembly == null) + return; + + var fileVersion = string.IsNullOrWhiteSpace(assembly.Location) + ? null + : FileVersionInfo.GetVersionInfo(assembly.Location); + var informationalVersion = assembly.GetCustomAttribute()?.InformationalVersion ?? string.Empty; + LogEntry( + $"LIAM assembly identity: Label='{label}', Name='{assembly.GetName().Name}', AssemblyVersion='{assembly.GetName().Version}', InformationalVersion='{informationalVersion}', FileVersion='{fileVersion?.FileVersion}', ProductVersion='{fileVersion?.ProductVersion}', Sha256='{GetAssemblySha256(assembly)}', Location='{assembly.Location}'", + LogLevels.Info); + } + + private static string GetAssemblySha256(Assembly assembly) + { + try + { + if (assembly == null || string.IsNullOrWhiteSpace(assembly.Location) || !File.Exists(assembly.Location)) + return string.Empty; + + using (var stream = File.OpenRead(assembly.Location)) + using (var sha256 = SHA256.Create()) + { + return BitConverter.ToString(sha256.ComputeHash(stream)).Replace("-", string.Empty); + } + } + catch + { + return string.Empty; + } + } + public bool LoadLicensingInformation(bool force = false) { if (cC4ITLicenseM42ESM.Instance == null || force) diff --git a/README.md b/README.md index eea5f16..af2692e 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,7 @@ Im Diagnose-JSON erscheinen diese Werte unter `AdditionalConfiguration`. Paramet | `NtfsExcludePaths` | Pfadliste, getrennt mit `;`, | oder Zeilenumbruechen | Schliesst passende Pfade von der NTFS-Verarbeitung aus. Excludes gewinnen gegen Includes. Unterstuetzt relative Pfade, absolute UNC-Pfade und einfache Wildcards mit `*`. | | `NtfsTraverseBoundaryPath` | Relativer oder absoluter Pfad | Setzt eine Traverse-Grenze fuer die Traverse-Gruppenverarbeitung. Damit koennen Traverse-Gruppen ueber den eigentlichen Einsprung hinaus bis zu einer definierten Ebene sichergestellt werden. Der Boundary-Pfad selbst darf ebenfalls als Traverse-Ziel verarbeitet werden. | | `NtfsPermissionGroupsMinLevel` / `NtfsPermissionGroupsMaxLevel` | Ganzzahl, z. B. `0`, `1`, `2` | Optionaler Levelbereich fuer Owner/Write/Read-Ensure. Ebene `0` ist der `RootPath`; Unterordner sind `1`, `2`, `3`, ... Wenn beide Parameter leer sind, bleibt das bisherige Verhalten unveraendert. | -| `NtfsTraverseGroupsMinLevel` / `NtfsTraverseGroupsMaxLevel` | Ganzzahl, z. B. `-1`, `0`, `2` | Optionaler Levelbereich fuer Traverse-Ensure. Ebene `0` ist der `RootPath`; Parent-Pfade oberhalb des `RootPath` sind `-1`, `-2`, ... Wenn beide Parameter leer sind, bleibt das bisherige Verhalten unveraendert. | +| `NtfsTraverseGroupsMinLevel` / `NtfsTraverseGroupsMaxLevel` | Ganzzahl, z. B. `-1`, `0`, `2` | Optionaler Levelbereich fuer Traverse-Ensure. Ebene `0` ist der `RootPath`; Parent-Pfade oberhalb des `RootPath` sind `-1`, `-2`, ... Wenn `NtfsTraverseGroupsMaxLevel` nicht gesetzt ist, wird fuer Traverse implizit `MaxDepth - 1` verwendet. | | `NtfsGroupNameSanitizeReplacement` | Zeichenfolge, z. B. `_`, `.`, leer, `none`, `remove`, `` | Legt fest, womit ungueltige Zeichen in dynamischen gruppennamenrelevanten Pfadbestandteilen ersetzt werden. Standard ist `_`. Mit leerem Wert oder `none`/`remove`/`` werden ungueltige Zeichen entfernt und Pfadsegmente ohne Trennzeichen verbunden. | | `PreserveNtfsAdGroupNameCase` | `true`, `1`, `yes` | Unterbindet das automatische Uppercase fuer generierte NTFS-AD-Gruppennamen. Ohne diesen Parameter werden generierte Gruppennamen wie bisher in Grossbuchstaben erzeugt. | | `ForceStrictAdGroupNames` | `true`, `1`, `yes` | Erzwingt strikte AD-Gruppennamen. Wildcard-/ACL-basierte Wiederverwendung abweichender bestehender Gruppen wird damit eingeschraenkt; es werden nur exakt passende konfigurierte oder generierte Namen verwendet. | @@ -269,7 +269,7 @@ In diesem Beispiel koennen Traverse-Gruppen fuer `...\Projekte` selbst und fuer #### Levelbereiche fuer Ensure und Ordneranlage -Die optionalen Levelbereiche schraenken ein, auf welchen Ebenen Gruppen und ACLs automatisch sichergestellt werden. Wenn keiner der Level-Parameter gesetzt ist, bleibt das bisherige Verhalten unveraendert. +Die optionalen Levelbereiche schraenken ein, auf welchen Ebenen Gruppen und ACLs automatisch sichergestellt werden. Wenn keine Permission-Level-Parameter gesetzt sind, bleibt Owner/Write/Read unveraendert. Fuer Traverse wird ohne explizites `NtfsTraverseGroupsMaxLevel` automatisch `MaxDepth - 1` als maximale Verarbeitungsebene verwendet. Ebene `0` ist immer der konfigurierte `RootPath`. Unterordner unterhalb des `RootPath` haben positive Level (`1`, `2`, `3`, ...). Parent-Pfade oberhalb des `RootPath` haben negative Level (`-1`, `-2`, ...). Negative Level sind vor allem fuer Traverse relevant, wenn `NtfsTraverseBoundaryPath` oberhalb des `RootPath` liegt. @@ -288,7 +288,7 @@ Damit werden Owner/Write/Read-Gruppen nur fuer `\\server\share\Bereich\...` auf Die Permission-Level gelten auch fuer die explizite NTFS-Ordneranlage ueber `CreateDataArea`. Wenn der Zielordner ausserhalb des Permission-Levelbereichs liegt oder die Permission-Levelkonfiguration ungueltig ist, wird die Ordneranlage vor AD-/ACL-Aenderungen abgebrochen. Traverse-Level blockieren die Ordneranlage nicht; sie schraenken nur die Traverse-Gruppen und Traverse-ACLs ein. -Wenn nur ein Min- oder Max-Wert gesetzt ist, ist die andere Seite offen. Ungueltige Werte oder ein Min-Wert groesser als der Max-Wert fuehren dazu, dass die betroffene Ensure-Phase mit einer Warning uebersprungen wird; bei `CreateDataArea` fuehrt eine ungueltige Permission-Levelkonfiguration zum Abbruch vor der Anlage. +Wenn nur ein Min- oder Max-Wert gesetzt ist, ist die andere Seite offen. Ausnahme: Fuer Traverse ist ein fehlender Max-Wert durch `MaxDepth - 1` begrenzt. Ungueltige Werte oder ein Min-Wert groesser als der Max-Wert fuehren dazu, dass die betroffene Ensure-Phase mit einer Warning uebersprungen wird; bei `CreateDataArea` fuehrt eine ungueltige Permission-Levelkonfiguration zum Abbruch vor der Anlage. #### WhatIf / Preview