@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.
@@ -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
- const slug = (pack.name || path.basename(filePath, ".json"))
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, "");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grainulation/silo",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Reusable knowledge for research sprints -- shared claim libraries, templates, and knowledge packs",
5
5
  "main": "lib/index.js",
6
6
  "exports": {