Release 0.0.7
This commit is contained in:
53
lang/de.json
53
lang/de.json
@@ -4,19 +4,19 @@
|
|||||||
"Menu": {
|
"Menu": {
|
||||||
"Name": "Kosmos Storage Audit",
|
"Name": "Kosmos Storage Audit",
|
||||||
"Label": "Report öffnen",
|
"Label": "Report öffnen",
|
||||||
"Hint": "Die Storage-Analyse ausführen und priorisierte Findings prüfen."
|
"Hint": "Die Speicher-Analyse ausführen und priorisierte Funde prüfen."
|
||||||
},
|
},
|
||||||
"Hero": {
|
"Hero": {
|
||||||
"Title": "Kosmos Storage Audit",
|
"Title": "Kosmos Storage Audit",
|
||||||
"Intro1": "Prüft Medienreferenzen und markiert primär benutzerrelevante Risiken in den Foundry-Roots {dataRoot} und {publicRoot}.",
|
"Intro1": "Prüft Medienreferenzen und markiert primär benutzerrelevante Risiken in den Foundry-Roots {dataRoot} und {publicRoot}.",
|
||||||
"Intro2": "Orphans werden bewusst nicht global für den gesamten {dataRoot}-Root behauptet, sondern nur in klar weltlokalen oder explizit riskanten Bereichen.",
|
"Intro2": "Orphans werden bewusst nicht global für den gesamten {dataRoot}-Root behauptet, sondern nur in klar weltlokalen oder explizit riskanten Bereichen.",
|
||||||
"Intro3": "Weltverweise auf Modul- oder Systemassets gelten nicht pauschal als Problem. Relevant sind vor allem Ziele, die im owning Paket selbst nicht sichtbar referenziert werden."
|
"Intro3": "Weltverweise auf Modul- oder Systemassets gelten nicht pauschal als Problem. Relevant sind vor allem Ziele, die im besitzenden Paket selbst nicht sichtbar referenziert werden."
|
||||||
},
|
},
|
||||||
"Action": {
|
"Action": {
|
||||||
"Run": "Analyse starten",
|
"Run": "Analyse starten",
|
||||||
"Running": "Analysiere...",
|
"Running": "Analysiere...",
|
||||||
"Export": "Report exportieren",
|
"Export": "Bericht exportieren",
|
||||||
"ShowAll": "Alle Findings",
|
"ShowAll": "Alle Funde",
|
||||||
"ShowWarnings": "Nur Warnungen",
|
"ShowWarnings": "Nur Warnungen",
|
||||||
"ShowRaw": "Einzelfälle anzeigen",
|
"ShowRaw": "Einzelfälle anzeigen",
|
||||||
"HideRaw": "Einzelfälle ausblenden"
|
"HideRaw": "Einzelfälle ausblenden"
|
||||||
@@ -24,16 +24,20 @@
|
|||||||
"Progress": {
|
"Progress": {
|
||||||
"Initialize": "Initialisiere Analyse",
|
"Initialize": "Initialisiere Analyse",
|
||||||
"Analyzing": "Analysiere",
|
"Analyzing": "Analysiere",
|
||||||
|
"ScanFiles": "Scanne Dateien",
|
||||||
|
"ReadReferences": "Lese Referenzen",
|
||||||
|
"ClassifyFindings": "Klassifiziere Funde",
|
||||||
|
"Completed": "Analyse abgeschlossen",
|
||||||
"Current": "Aktuell: {source}",
|
"Current": "Aktuell: {source}",
|
||||||
"Files": "Dateien: {count}",
|
"Files": "Dateien: {count}",
|
||||||
"Sources": "Quellen: {count}",
|
"Sources": "Quellen: {count}",
|
||||||
"References": "Referenzen: {count}",
|
"References": "Referenzen: {count}",
|
||||||
"Findings": "Findings: {count}",
|
"Findings": "Funde: {count}",
|
||||||
"BrowseStorage": "Durchsuche {storage}:{path}",
|
"BrowseStorage": "Durchsuche {storage}:{path}",
|
||||||
"ReadPack": "Lese Paket-Pack {pack}"
|
"ReadPack": "Lese Paket-Pack {pack}"
|
||||||
},
|
},
|
||||||
"Notify": {
|
"Notify": {
|
||||||
"Completed": "Kosmos Storage Audit abgeschlossen: {count} Findings.",
|
"Completed": "Kosmos Storage Audit abgeschlossen: {count} Funde.",
|
||||||
"Failed": "Kosmos Storage Audit fehlgeschlagen: {message}",
|
"Failed": "Kosmos Storage Audit fehlgeschlagen: {message}",
|
||||||
"OpenSourceFailed": "Die Quelle konnte nicht geöffnet werden: {uuid}"
|
"OpenSourceFailed": "Die Quelle konnte nicht geöffnet werden: {uuid}"
|
||||||
},
|
},
|
||||||
@@ -41,11 +45,11 @@
|
|||||||
"NoAnalysis": "Noch keine Analyse ausgeführt.",
|
"NoAnalysis": "Noch keine Analyse ausgeführt.",
|
||||||
"Files": "Dateien",
|
"Files": "Dateien",
|
||||||
"References": "Referenzen",
|
"References": "Referenzen",
|
||||||
"Findings": "Findings",
|
"Findings": "Funde",
|
||||||
"High": "High",
|
"High": "Hoch",
|
||||||
"Warning": "Warning",
|
"Warning": "Warnung",
|
||||||
"ByType": "Findings nach Typ",
|
"ByType": "Funde nach Typ",
|
||||||
"NoFindings": "Keine Findings",
|
"NoFindings": "Keine Funde",
|
||||||
"WorkBlocks": "Arbeitsblöcke",
|
"WorkBlocks": "Arbeitsblöcke",
|
||||||
"MissingTargets": "Deduplizierte fehlende Ziele",
|
"MissingTargets": "Deduplizierte fehlende Ziele",
|
||||||
"UnanchoredPackageTargets": "Unverankerte Paketziele",
|
"UnanchoredPackageTargets": "Unverankerte Paketziele",
|
||||||
@@ -53,21 +57,21 @@
|
|||||||
},
|
},
|
||||||
"Section": {
|
"Section": {
|
||||||
"WorkView": "Arbeitsansicht",
|
"WorkView": "Arbeitsansicht",
|
||||||
"NoGrouped": "Keine gruppierten {scope}Findings vorhanden.",
|
"NoGrouped": "Keine gruppierten {scope}Funde vorhanden.",
|
||||||
"NoPrompt": "Die Analyse kann direkt aus dieser Ansicht gestartet werden.",
|
"NoPrompt": "Die Analyse kann direkt aus dieser Ansicht gestartet werden.",
|
||||||
"Running": "Analyse läuft...",
|
"Running": "Analyse läuft...",
|
||||||
"NoRaw": "Keine {scope}Findings gefunden.",
|
"NoRaw": "Keine {scope}Funde gefunden.",
|
||||||
"RawEntries": "Einzelfälle",
|
"RawEntries": "Einzelfälle",
|
||||||
"Samples": "Beispiele",
|
"Samples": "Beispiele",
|
||||||
"UnanchoredPackageTargets": "Unverankerte Paketziele",
|
"UnanchoredPackageTargets": "Unverankerte Paketziele",
|
||||||
"UnanchoredPackageTargetsDesc": "Diese Ziele liegen in Modul- oder Systemordnern, werden aus Weltdaten referenziert, sind im owning Paket selbst aber derzeit nicht als Referenz sichtbar.",
|
"UnanchoredPackageTargetsDesc": "Diese Ziele liegen in Modul- oder Systemordnern, werden aus Weltdaten referenziert, sind im besitzenden Paket selbst aber derzeit nicht als Referenz sichtbar.",
|
||||||
"BrokenTargets": "Kaputte Ziele",
|
"BrokenTargets": "Kaputte Ziele",
|
||||||
"BrokenTargetsDesc": "Diese Dateien fehlen, werden aber weiterhin referenziert.",
|
"BrokenTargetsDesc": "Diese Dateien fehlen, werden aber weiterhin referenziert.",
|
||||||
"OrphanCandidates": "Orphan-Kandidaten",
|
"OrphanCandidates": "Orphan-Kandidaten",
|
||||||
"OrphanCandidatesDesc": "Diese Dateien haben im aktuellen Analysekontext keine eingehende Referenz."
|
"OrphanCandidatesDesc": "Diese Dateien haben im aktuellen Analysekontext keine eingehende Referenz."
|
||||||
},
|
},
|
||||||
"Field": {
|
"Field": {
|
||||||
"OwnerPackage": "Owner-Paket",
|
"OwnerPackage": "Besitzendes Paket",
|
||||||
"Assessment": "Bewertung",
|
"Assessment": "Bewertung",
|
||||||
"Target": "Ziel",
|
"Target": "Ziel",
|
||||||
"Source": "Quelle"
|
"Source": "Quelle"
|
||||||
@@ -83,10 +87,25 @@
|
|||||||
"WildcardNoMatch": "Musterreferenz: Wildcard wird von Foundry unterstützt, derzeit aber ohne passenden Treffer im Dateisystem."
|
"WildcardNoMatch": "Musterreferenz: Wildcard wird von Foundry unterstützt, derzeit aber ohne passenden Treffer im Dateisystem."
|
||||||
},
|
},
|
||||||
"Severity": {
|
"Severity": {
|
||||||
"high": "High",
|
"high": "Hoch",
|
||||||
"warning": "Warning",
|
"warning": "Warnung",
|
||||||
"info": "Info"
|
"info": "Info"
|
||||||
},
|
},
|
||||||
|
"FindingReason": {
|
||||||
|
"BrokenWildcard": "Die Wildcard-Referenz {locator} passt auf keine Datei in den gescannten Roots.",
|
||||||
|
"BrokenReference": "Die referenzierte Datei {locator} existiert in den gescannten Roots nicht.",
|
||||||
|
"UnanchoredPackageTarget": "{sourceOwner} verweist auf paketgebundenen Speicher {locator}, aber das Asset ist im besitzenden Paket selbst nicht sichtbar referenziert.",
|
||||||
|
"RiskyPublicTarget": "{sourceOwner} verweist auf release-nahen Public-Speicher {locator}.",
|
||||||
|
"OrphanFile": "Für {locator} wurde keine eingehende Medienreferenz gefunden."
|
||||||
|
},
|
||||||
|
"FindingRecommendation": {
|
||||||
|
"CheckWildcard": "Prüfe, ob das Wildcard-Muster noch korrekt ist und ob passende Dateien noch vorhanden sind.",
|
||||||
|
"CheckMissingFile": "Prüfe, ob die Datei verschoben, gelöscht oder an einen stabilen Ort kopiert werden sollte.",
|
||||||
|
"MoveToStableStorage": "Prüfe, ob die Datei manuell in den Paketordner gelegt wurde. Falls das Paket sie selbst nicht nutzt, verschiebe sie bevorzugt in benutzerkontrollierten Speicher.",
|
||||||
|
"CopyToStableStorage": "Kopiere das Asset bevorzugt in Welt- oder benutzerkontrollierten Speicher.",
|
||||||
|
"ReviewOrMoveOrphan": "Prüfe, ob die Datei sicher entfernt oder an einen stabilen Speicherort verschoben werden sollte.",
|
||||||
|
"KeepAsReserve": "Prüfe, ob die Datei absichtlich als Reserveinhalt vorgehalten wird."
|
||||||
|
},
|
||||||
"Owner": {
|
"Owner": {
|
||||||
"Unknown": "unbekannt"
|
"Unknown": "unbekannt"
|
||||||
},
|
},
|
||||||
|
|||||||
19
lang/en.json
19
lang/en.json
@@ -24,6 +24,10 @@
|
|||||||
"Progress": {
|
"Progress": {
|
||||||
"Initialize": "Initializing analysis",
|
"Initialize": "Initializing analysis",
|
||||||
"Analyzing": "Analyzing",
|
"Analyzing": "Analyzing",
|
||||||
|
"ScanFiles": "Scanning files",
|
||||||
|
"ReadReferences": "Reading references",
|
||||||
|
"ClassifyFindings": "Classifying findings",
|
||||||
|
"Completed": "Analysis complete",
|
||||||
"Current": "Current: {source}",
|
"Current": "Current: {source}",
|
||||||
"Files": "Files: {count}",
|
"Files": "Files: {count}",
|
||||||
"Sources": "Sources: {count}",
|
"Sources": "Sources: {count}",
|
||||||
@@ -87,6 +91,21 @@
|
|||||||
"warning": "Warning",
|
"warning": "Warning",
|
||||||
"info": "Info"
|
"info": "Info"
|
||||||
},
|
},
|
||||||
|
"FindingReason": {
|
||||||
|
"BrokenWildcard": "Wildcard reference {locator} did not match any files in the scanned roots.",
|
||||||
|
"BrokenReference": "Referenced file {locator} does not exist in the scanned roots.",
|
||||||
|
"UnanchoredPackageTarget": "{sourceOwner} references package-owned storage {locator}, but the asset is not visibly referenced by its owning package.",
|
||||||
|
"RiskyPublicTarget": "{sourceOwner} references release-public storage {locator}.",
|
||||||
|
"OrphanFile": "No incoming media reference was found for {locator}."
|
||||||
|
},
|
||||||
|
"FindingRecommendation": {
|
||||||
|
"CheckWildcard": "Check whether the wildcard pattern is still correct and whether matching files still exist.",
|
||||||
|
"CheckMissingFile": "Check whether the file was moved, deleted, or should be copied into a stable location.",
|
||||||
|
"MoveToStableStorage": "Review whether the file was manually placed into the package folder. If the package does not use it itself, prefer moving it into user-controlled storage.",
|
||||||
|
"CopyToStableStorage": "Prefer copying the asset into world or user-controlled storage.",
|
||||||
|
"ReviewOrMoveOrphan": "Review whether the file is safe to remove or should be moved into a stable storage location.",
|
||||||
|
"KeepAsReserve": "Review whether the file is intentionally kept as reserve content."
|
||||||
|
},
|
||||||
"Owner": {
|
"Owner": {
|
||||||
"Unknown": "unknown"
|
"Unknown": "unknown"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"id": "kosmos-storage-audit",
|
"id": "kosmos-storage-audit",
|
||||||
"title": "Kosmos Storage Audit",
|
"title": "Kosmos Storage Audit",
|
||||||
"description": "Analyzes media references and risky storage locations across Foundry data and public roots.",
|
"description": "Analyzes media references and risky storage locations across Foundry data and public roots.",
|
||||||
"version": "0.0.6",
|
"version": "0.0.7",
|
||||||
"compatibility": {
|
"compatibility": {
|
||||||
"minimum": "13",
|
"minimum": "13",
|
||||||
"verified": "13"
|
"verified": "13"
|
||||||
|
|||||||
@@ -111,7 +111,8 @@ export async function runRuntimeAnalysis({ onProgress }={}) {
|
|||||||
return analyzeStorage({
|
return analyzeStorage({
|
||||||
listFiles: () => listFoundryFiles(onProgress),
|
listFiles: () => listFoundryFiles(onProgress),
|
||||||
listSources: () => listFoundrySources(onProgress),
|
listSources: () => listFoundrySources(onProgress),
|
||||||
onProgress
|
onProgress,
|
||||||
|
i18n: { format }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,24 +2,24 @@ import { buildFindings, createFileRecord } from "./finding-engine.js";
|
|||||||
import { extractReferencesFromValue } from "./reference-extractor.js";
|
import { extractReferencesFromValue } from "./reference-extractor.js";
|
||||||
import { createFileLocator } from "./path-utils.js";
|
import { createFileLocator } from "./path-utils.js";
|
||||||
|
|
||||||
export async function analyzeStorage({ listFiles, listSources, onProgress }={}) {
|
export async function analyzeStorage({ listFiles, listSources, onProgress, i18n }={}) {
|
||||||
const files = [];
|
const files = [];
|
||||||
let fileCount = 0;
|
let fileCount = 0;
|
||||||
let sourceCount = 0;
|
let sourceCount = 0;
|
||||||
let referenceCount = 0;
|
let referenceCount = 0;
|
||||||
|
|
||||||
onProgress?.({ phase: "files", label: "Scanne Dateien", files: 0, sources: 0, references: 0 });
|
onProgress?.({ phase: "files", label: format(i18n, "KSA.Progress.ScanFiles"), files: 0, sources: 0, references: 0 });
|
||||||
for await (const entry of listFiles()) {
|
for await (const entry of listFiles()) {
|
||||||
files.push(createFileRecord(createFileLocator(entry.storage, entry.path), entry.size ?? null));
|
files.push(createFileRecord(createFileLocator(entry.storage, entry.path), entry.size ?? null));
|
||||||
fileCount += 1;
|
fileCount += 1;
|
||||||
if ((fileCount % 100) === 0) {
|
if ((fileCount % 100) === 0) {
|
||||||
onProgress?.({ phase: "files", label: "Scanne Dateien", files: fileCount, sources: sourceCount, references: referenceCount });
|
onProgress?.({ phase: "files", label: format(i18n, "KSA.Progress.ScanFiles"), files: fileCount, sources: sourceCount, references: referenceCount });
|
||||||
await yieldToUI();
|
await yieldToUI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const references = [];
|
const references = [];
|
||||||
onProgress?.({ phase: "sources", label: "Lese Referenzen", files: fileCount, sources: 0, references: 0 });
|
onProgress?.({ phase: "sources", label: format(i18n, "KSA.Progress.ReadReferences"), files: fileCount, sources: 0, references: 0 });
|
||||||
for await (const source of listSources()) {
|
for await (const source of listSources()) {
|
||||||
sourceCount += 1;
|
sourceCount += 1;
|
||||||
const extracted = extractReferencesFromValue(source.value, {
|
const extracted = extractReferencesFromValue(source.value, {
|
||||||
@@ -34,7 +34,7 @@ export async function analyzeStorage({ listFiles, listSources, onProgress }={})
|
|||||||
if ((sourceCount % 50) === 0) {
|
if ((sourceCount % 50) === 0) {
|
||||||
onProgress?.({
|
onProgress?.({
|
||||||
phase: "sources",
|
phase: "sources",
|
||||||
label: "Lese Referenzen",
|
label: format(i18n, "KSA.Progress.ReadReferences"),
|
||||||
files: fileCount,
|
files: fileCount,
|
||||||
sources: sourceCount,
|
sources: sourceCount,
|
||||||
references: referenceCount,
|
references: referenceCount,
|
||||||
@@ -44,11 +44,11 @@ export async function analyzeStorage({ listFiles, listSources, onProgress }={})
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onProgress?.({ phase: "findings", label: "Klassifiziere Findings", files: fileCount, sources: sourceCount, references: referenceCount });
|
onProgress?.({ phase: "findings", label: format(i18n, "KSA.Progress.ClassifyFindings"), files: fileCount, sources: sourceCount, references: referenceCount });
|
||||||
const findings = buildFindings({ files, references });
|
const findings = buildFindings({ files, references, i18n });
|
||||||
onProgress?.({
|
onProgress?.({
|
||||||
phase: "done",
|
phase: "done",
|
||||||
label: "Analyse abgeschlossen",
|
label: format(i18n, "KSA.Progress.Completed"),
|
||||||
files: fileCount,
|
files: fileCount,
|
||||||
sources: sourceCount,
|
sources: sourceCount,
|
||||||
references: referenceCount,
|
references: referenceCount,
|
||||||
@@ -60,3 +60,7 @@ export async function analyzeStorage({ listFiles, listSources, onProgress }={})
|
|||||||
async function yieldToUI() {
|
async function yieldToUI() {
|
||||||
await new Promise(resolve => setTimeout(resolve, 0));
|
await new Promise(resolve => setTimeout(resolve, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function format(i18n, key, data = {}) {
|
||||||
|
return i18n?.format?.(key, data) ?? key;
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ function compareOwner(sourceScope, targetOwner) {
|
|||||||
return "allowed";
|
return "allowed";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildFindings({ files, references }) {
|
export function buildFindings({ files, references, i18n }={}) {
|
||||||
const fileByLocator = new Map(files.map(file => [createCanonicalLocator(file.storage, file.path), file]));
|
const fileByLocator = new Map(files.map(file => [createCanonicalLocator(file.storage, file.path), file]));
|
||||||
const fileLocators = files.map(file => ({
|
const fileLocators = files.map(file => ({
|
||||||
storage: file.storage,
|
storage: file.storage,
|
||||||
@@ -71,11 +71,11 @@ export function buildFindings({ files, references }) {
|
|||||||
target: { ...normalized, locator: normalizedLocator },
|
target: { ...normalized, locator: normalizedLocator },
|
||||||
source: reference,
|
source: reference,
|
||||||
reason: normalized.targetKind === "wildcard"
|
reason: normalized.targetKind === "wildcard"
|
||||||
? `Wildcard reference ${normalized.locator} did not match any files in the scanned roots.`
|
? format(i18n, "KSA.FindingReason.BrokenWildcard", { locator: normalized.locator })
|
||||||
: `Referenced file ${normalized.locator} does not exist in the scanned roots.`,
|
: format(i18n, "KSA.FindingReason.BrokenReference", { locator: normalized.locator }),
|
||||||
recommendation: normalized.targetKind === "wildcard"
|
recommendation: normalized.targetKind === "wildcard"
|
||||||
? "Check whether the wildcard pattern is still correct and whether matching files still exist."
|
? format(i18n, "KSA.FindingRecommendation.CheckWildcard")
|
||||||
: "Check whether the file was moved, deleted, or should be copied into a stable location.",
|
: format(i18n, "KSA.FindingRecommendation.CheckMissingFile"),
|
||||||
confidence: "high"
|
confidence: "high"
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
@@ -89,8 +89,11 @@ export function buildFindings({ files, references }) {
|
|||||||
severity: "high",
|
severity: "high",
|
||||||
target: { ...normalized, locator: normalizedLocator },
|
target: { ...normalized, locator: normalizedLocator },
|
||||||
source: reference,
|
source: reference,
|
||||||
reason: `${reference.sourceScope.ownerType}:${reference.sourceScope.ownerId} references package-owned storage ${normalized.locator}, but the asset is not visibly referenced by its owning package.`,
|
reason: format(i18n, "KSA.FindingReason.UnanchoredPackageTarget", {
|
||||||
recommendation: "Review whether the file was manually placed into the package folder. If the package does not use it itself, prefer moving it into user-controlled storage.",
|
sourceOwner: `${reference.sourceScope.ownerType}:${reference.sourceScope.ownerId}`,
|
||||||
|
locator: normalized.locator
|
||||||
|
}),
|
||||||
|
recommendation: format(i18n, "KSA.FindingRecommendation.MoveToStableStorage"),
|
||||||
confidence: "high"
|
confidence: "high"
|
||||||
});
|
});
|
||||||
} else if (ownerRelation === "risky-public") {
|
} else if (ownerRelation === "risky-public") {
|
||||||
@@ -100,8 +103,11 @@ export function buildFindings({ files, references }) {
|
|||||||
severity: "high",
|
severity: "high",
|
||||||
target: { ...normalized, locator: normalizedLocator },
|
target: { ...normalized, locator: normalizedLocator },
|
||||||
source: reference,
|
source: reference,
|
||||||
reason: `${reference.sourceScope.ownerType}:${reference.sourceScope.ownerId} references release-public storage ${normalized.locator}.`,
|
reason: format(i18n, "KSA.FindingReason.RiskyPublicTarget", {
|
||||||
recommendation: "Prefer copying the asset into world or user-controlled storage.",
|
sourceOwner: `${reference.sourceScope.ownerType}:${reference.sourceScope.ownerId}`,
|
||||||
|
locator: normalized.locator
|
||||||
|
}),
|
||||||
|
recommendation: format(i18n, "KSA.FindingRecommendation.CopyToStableStorage"),
|
||||||
confidence: "high"
|
confidence: "high"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -122,10 +128,10 @@ export function buildFindings({ files, references }) {
|
|||||||
severity,
|
severity,
|
||||||
target: file,
|
target: file,
|
||||||
source: null,
|
source: null,
|
||||||
reason: `No incoming media reference was found for ${file.locator}.`,
|
reason: format(i18n, "KSA.FindingReason.OrphanFile", { locator: file.locator }),
|
||||||
recommendation: severity === "warning"
|
recommendation: severity === "warning"
|
||||||
? "Review whether the file is safe to remove or should be moved into a stable storage location."
|
? format(i18n, "KSA.FindingRecommendation.ReviewOrMoveOrphan")
|
||||||
: "Review whether the file is intentionally kept as reserve content.",
|
: format(i18n, "KSA.FindingRecommendation.KeepAsReserve"),
|
||||||
confidence: "medium"
|
confidence: "medium"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -194,3 +200,7 @@ export function createFileRecord(locator, size = null) {
|
|||||||
exists: true
|
exists: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function format(i18n, key, data = {}) {
|
||||||
|
return i18n?.format?.(key, data) ?? key;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user