@grainulation/silo 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/import-export.js +32 -1
- package/lib/packs.js +14 -1
- package/package.json +1 -1
package/lib/import-export.js
CHANGED
|
@@ -9,10 +9,21 @@ const fs = require("node:fs");
|
|
|
9
9
|
const path = require("node:path");
|
|
10
10
|
const { Store } = require("./store.js");
|
|
11
11
|
|
|
12
|
+
const VALID_TYPES = [
|
|
13
|
+
"constraint",
|
|
14
|
+
"factual",
|
|
15
|
+
"estimate",
|
|
16
|
+
"risk",
|
|
17
|
+
"recommendation",
|
|
18
|
+
"feedback",
|
|
19
|
+
];
|
|
20
|
+
const VALID_EVIDENCE = ["stated", "web", "documented", "tested", "production"];
|
|
21
|
+
|
|
12
22
|
/**
|
|
13
23
|
* Normalize a claim to wheat's canonical schema.
|
|
14
24
|
* Handles legacy fields: tier -> evidence, text -> content.
|
|
15
25
|
* Fills in missing required fields with sensible defaults.
|
|
26
|
+
* Validates enums, sanitizes content, and ensures provenance.
|
|
16
27
|
*/
|
|
17
28
|
function normalizeClaim(claim) {
|
|
18
29
|
const normalized = { ...claim };
|
|
@@ -41,6 +52,21 @@ function normalizeClaim(claim) {
|
|
|
41
52
|
normalized.resolved_by = normalized.resolved_by || null;
|
|
42
53
|
normalized.tags = normalized.tags || [];
|
|
43
54
|
|
|
55
|
+
// Enum validation: clamp type to allowed set
|
|
56
|
+
if (!VALID_TYPES.includes(normalized.type)) {
|
|
57
|
+
normalized.type = "factual";
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Enum validation: clamp evidence to allowed set
|
|
61
|
+
if (!VALID_EVIDENCE.includes(normalized.evidence)) {
|
|
62
|
+
normalized.evidence = "stated";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// String sanitization: strip HTML tags from content
|
|
66
|
+
if (typeof normalized.content === "string") {
|
|
67
|
+
normalized.content = normalized.content.replace(/<[^>]*>/g, "");
|
|
68
|
+
}
|
|
69
|
+
|
|
44
70
|
// Normalize source to object form
|
|
45
71
|
if (!normalized.source || typeof normalized.source === "string") {
|
|
46
72
|
normalized.source = {
|
|
@@ -53,6 +79,11 @@ function normalizeClaim(claim) {
|
|
|
53
79
|
};
|
|
54
80
|
}
|
|
55
81
|
|
|
82
|
+
// Ensure provenance: if source.origin is missing, set default
|
|
83
|
+
if (!normalized.source.origin) {
|
|
84
|
+
normalized.source.origin = "silo-import";
|
|
85
|
+
}
|
|
86
|
+
|
|
56
87
|
return normalized;
|
|
57
88
|
}
|
|
58
89
|
|
|
@@ -176,4 +207,4 @@ class ImportExport {
|
|
|
176
207
|
}
|
|
177
208
|
}
|
|
178
209
|
|
|
179
|
-
module.exports = { ImportExport, normalizeClaim };
|
|
210
|
+
module.exports = { ImportExport, normalizeClaim, VALID_TYPES, VALID_EVIDENCE };
|
package/lib/packs.js
CHANGED
|
@@ -140,7 +140,20 @@ class Packs {
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
const pack = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
143
|
-
|
|
143
|
+
|
|
144
|
+
// Validate pack name against path traversal
|
|
145
|
+
const rawName = pack.name || path.basename(filePath, ".json");
|
|
146
|
+
if (
|
|
147
|
+
/[/\\]/.test(rawName) ||
|
|
148
|
+
rawName.includes("..") ||
|
|
149
|
+
rawName.startsWith(".")
|
|
150
|
+
) {
|
|
151
|
+
throw new Error(
|
|
152
|
+
`Invalid pack name "${rawName}": must not contain /, \\, .., or start with .`,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const slug = rawName
|
|
144
157
|
.toLowerCase()
|
|
145
158
|
.replace(/[^a-z0-9]+/g, "-")
|
|
146
159
|
.replace(/^-|-$/g, "");
|