@nanocollective/sentinel 0.1.0-alpha.0

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.
Files changed (163) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +66 -0
  3. package/dist/cli.d.ts +12 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +254 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/config/parse.d.ts +13 -0
  8. package/dist/config/parse.d.ts.map +1 -0
  9. package/dist/config/parse.js +271 -0
  10. package/dist/config/parse.js.map +1 -0
  11. package/dist/config/repo-override.d.ts +13 -0
  12. package/dist/config/repo-override.d.ts.map +1 -0
  13. package/dist/config/repo-override.js +128 -0
  14. package/dist/config/repo-override.js.map +1 -0
  15. package/dist/config/types.d.ts +86 -0
  16. package/dist/config/types.d.ts.map +1 -0
  17. package/dist/config/types.js +8 -0
  18. package/dist/config/types.js.map +1 -0
  19. package/dist/dedup/hash.d.ts +10 -0
  20. package/dist/dedup/hash.d.ts.map +1 -0
  21. package/dist/dedup/hash.js +18 -0
  22. package/dist/dedup/hash.js.map +1 -0
  23. package/dist/dedup/markers.d.ts +13 -0
  24. package/dist/dedup/markers.d.ts.map +1 -0
  25. package/dist/dedup/markers.js +42 -0
  26. package/dist/dedup/markers.js.map +1 -0
  27. package/dist/dedup/plan.d.ts +45 -0
  28. package/dist/dedup/plan.d.ts.map +1 -0
  29. package/dist/dedup/plan.js +83 -0
  30. package/dist/dedup/plan.js.map +1 -0
  31. package/dist/dedup/reconcile.d.ts +29 -0
  32. package/dist/dedup/reconcile.d.ts.map +1 -0
  33. package/dist/dedup/reconcile.js +73 -0
  34. package/dist/dedup/reconcile.js.map +1 -0
  35. package/dist/findings/types.d.ts +53 -0
  36. package/dist/findings/types.d.ts.map +1 -0
  37. package/dist/findings/types.js +28 -0
  38. package/dist/findings/types.js.map +1 -0
  39. package/dist/findings/validate.d.ts +36 -0
  40. package/dist/findings/validate.d.ts.map +1 -0
  41. package/dist/findings/validate.js +178 -0
  42. package/dist/findings/validate.js.map +1 -0
  43. package/dist/index.d.ts +48 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +39 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/init/args.d.ts +20 -0
  48. package/dist/init/args.d.ts.map +1 -0
  49. package/dist/init/args.js +80 -0
  50. package/dist/init/args.js.map +1 -0
  51. package/dist/init/plan.d.ts +9 -0
  52. package/dist/init/plan.d.ts.map +1 -0
  53. package/dist/init/plan.js +17 -0
  54. package/dist/init/plan.js.map +1 -0
  55. package/dist/init/scaffold.d.ts +17 -0
  56. package/dist/init/scaffold.d.ts.map +1 -0
  57. package/dist/init/scaffold.js +27 -0
  58. package/dist/init/scaffold.js.map +1 -0
  59. package/dist/init/templates.d.ts +28 -0
  60. package/dist/init/templates.d.ts.map +1 -0
  61. package/dist/init/templates.js +187 -0
  62. package/dist/init/templates.js.map +1 -0
  63. package/dist/init/types.d.ts +29 -0
  64. package/dist/init/types.d.ts.map +1 -0
  65. package/dist/init/types.js +15 -0
  66. package/dist/init/types.js.map +1 -0
  67. package/dist/issues/body.d.ts +12 -0
  68. package/dist/issues/body.d.ts.map +1 -0
  69. package/dist/issues/body.js +53 -0
  70. package/dist/issues/body.js.map +1 -0
  71. package/dist/issues/file.d.ts +24 -0
  72. package/dist/issues/file.d.ts.map +1 -0
  73. package/dist/issues/file.js +61 -0
  74. package/dist/issues/file.js.map +1 -0
  75. package/dist/issues/gh-client.d.ts +21 -0
  76. package/dist/issues/gh-client.d.ts.map +1 -0
  77. package/dist/issues/gh-client.js +133 -0
  78. package/dist/issues/gh-client.js.map +1 -0
  79. package/dist/issues/types.d.ts +85 -0
  80. package/dist/issues/types.d.ts.map +1 -0
  81. package/dist/issues/types.js +8 -0
  82. package/dist/issues/types.js.map +1 -0
  83. package/dist/orchestrator/audit.d.ts +14 -0
  84. package/dist/orchestrator/audit.d.ts.map +1 -0
  85. package/dist/orchestrator/audit.js +47 -0
  86. package/dist/orchestrator/audit.js.map +1 -0
  87. package/dist/orchestrator/auto-fix.d.ts +31 -0
  88. package/dist/orchestrator/auto-fix.d.ts.map +1 -0
  89. package/dist/orchestrator/auto-fix.js +59 -0
  90. package/dist/orchestrator/auto-fix.js.map +1 -0
  91. package/dist/orchestrator/extract.d.ts +14 -0
  92. package/dist/orchestrator/extract.d.ts.map +1 -0
  93. package/dist/orchestrator/extract.js +70 -0
  94. package/dist/orchestrator/extract.js.map +1 -0
  95. package/dist/orchestrator/nanocoder-runner.d.ts +33 -0
  96. package/dist/orchestrator/nanocoder-runner.d.ts.map +1 -0
  97. package/dist/orchestrator/nanocoder-runner.js +125 -0
  98. package/dist/orchestrator/nanocoder-runner.js.map +1 -0
  99. package/dist/orchestrator/types.d.ts +51 -0
  100. package/dist/orchestrator/types.d.ts.map +1 -0
  101. package/dist/orchestrator/types.js +8 -0
  102. package/dist/orchestrator/types.js.map +1 -0
  103. package/dist/prompt/build.d.ts +14 -0
  104. package/dist/prompt/build.d.ts.map +1 -0
  105. package/dist/prompt/build.js +123 -0
  106. package/dist/prompt/build.js.map +1 -0
  107. package/dist/prompt/types.d.ts +34 -0
  108. package/dist/prompt/types.d.ts.map +1 -0
  109. package/dist/prompt/types.js +8 -0
  110. package/dist/prompt/types.js.map +1 -0
  111. package/dist/rule-packs/dependencies.d.ts +20 -0
  112. package/dist/rule-packs/dependencies.d.ts.map +1 -0
  113. package/dist/rule-packs/dependencies.js +58 -0
  114. package/dist/rule-packs/dependencies.js.map +1 -0
  115. package/dist/rule-packs/glob.d.ts +23 -0
  116. package/dist/rule-packs/glob.d.ts.map +1 -0
  117. package/dist/rule-packs/glob.js +66 -0
  118. package/dist/rule-packs/glob.js.map +1 -0
  119. package/dist/rule-packs/parse.d.ts +21 -0
  120. package/dist/rule-packs/parse.d.ts.map +1 -0
  121. package/dist/rule-packs/parse.js +230 -0
  122. package/dist/rule-packs/parse.js.map +1 -0
  123. package/dist/rule-packs/types.d.ts +55 -0
  124. package/dist/rule-packs/types.d.ts.map +1 -0
  125. package/dist/rule-packs/types.js +10 -0
  126. package/dist/rule-packs/types.js.map +1 -0
  127. package/dist/run/audit.d.ts +20 -0
  128. package/dist/run/audit.d.ts.map +1 -0
  129. package/dist/run/audit.js +28 -0
  130. package/dist/run/audit.js.map +1 -0
  131. package/dist/run/clone.d.ts +23 -0
  132. package/dist/run/clone.d.ts.map +1 -0
  133. package/dist/run/clone.js +51 -0
  134. package/dist/run/clone.js.map +1 -0
  135. package/dist/run/preview.d.ts +34 -0
  136. package/dist/run/preview.d.ts.map +1 -0
  137. package/dist/run/preview.js +68 -0
  138. package/dist/run/preview.js.map +1 -0
  139. package/dist/run/report.d.ts +10 -0
  140. package/dist/run/report.d.ts.map +1 -0
  141. package/dist/run/report.js +73 -0
  142. package/dist/run/report.js.map +1 -0
  143. package/dist/run/run.d.ts +74 -0
  144. package/dist/run/run.d.ts.map +1 -0
  145. package/dist/run/run.js +131 -0
  146. package/dist/run/run.js.map +1 -0
  147. package/dist/run/select.d.ts +14 -0
  148. package/dist/run/select.d.ts.map +1 -0
  149. package/dist/run/select.js +31 -0
  150. package/dist/run/select.js.map +1 -0
  151. package/dist/run/sources.d.ts +11 -0
  152. package/dist/run/sources.d.ts.map +1 -0
  153. package/dist/run/sources.js +106 -0
  154. package/dist/run/sources.js.map +1 -0
  155. package/dist/run/types.d.ts +55 -0
  156. package/dist/run/types.d.ts.map +1 -0
  157. package/dist/run/types.js +7 -0
  158. package/dist/run/types.js.map +1 -0
  159. package/dist/suppression/apply.d.ts +33 -0
  160. package/dist/suppression/apply.d.ts.map +1 -0
  161. package/dist/suppression/apply.js +55 -0
  162. package/dist/suppression/apply.js.map +1 -0
  163. package/package.json +118 -0
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Assemble the templated audit prompt for one rule pack against one repository.
3
+ * The pack's Markdown body is the audit instructions; the source files (scoped
4
+ * by the pack's applies_to globs) are the material; and a fixed reporting
5
+ * contract tells the model to emit findings in the snake_case shape the
6
+ * {@link ../findings/validate.js validator} accepts.
7
+ */
8
+ import { CONFIDENCES, SEVERITIES } from '../findings/types.js';
9
+ import { matchesAppliesTo } from '../rule-packs/glob.js';
10
+ /** Prefix each line with a right-aligned 1-indexed number for line_range use. */
11
+ function numberLines(content) {
12
+ const lines = content.split('\n');
13
+ const width = String(lines.length).length;
14
+ return lines
15
+ .map((line, i) => `${String(i + 1).padStart(width)}| ${line}`)
16
+ .join('\n');
17
+ }
18
+ function formatFile(file) {
19
+ return [
20
+ `===== FILE: ${file.path} =====`,
21
+ numberLines(file.content),
22
+ `===== END FILE: ${file.path} =====`,
23
+ ].join('\n');
24
+ }
25
+ function quotedList(values) {
26
+ return values.map(value => `"${value}"`).join(', ');
27
+ }
28
+ function reportingContract(packName, category) {
29
+ return [
30
+ '## Reporting findings',
31
+ '',
32
+ 'Report the findings as a JSON array. Return [] if you find nothing.',
33
+ 'Each finding is an object with exactly these keys:',
34
+ '',
35
+ `- "rule": string — the pack rule that fired, prefixed with the pack name (e.g. "${packName}/<pattern>")`,
36
+ '- "file": string — the repository-relative path of the affected file',
37
+ '- "line_range": object — {"start": <number>, "end": <number>}, 1-indexed and inclusive',
38
+ `- "category": string — the finding category (e.g. "${category || packName}")`,
39
+ `- "severity": string — one of ${quotedList(SEVERITIES)}`,
40
+ `- "confidence": string — one of ${quotedList(CONFIDENCES)}`,
41
+ '- "offending_snippet": string — the exact code the finding refers to',
42
+ '',
43
+ 'Also include these fields where you can; they become the issue a human reads:',
44
+ '- "summary": string — a one-line description of the finding',
45
+ '- "rationale": string — why the finding has the severity you assigned',
46
+ '- "suggested_next_steps": string — what a reviewer should do next (not a patch)',
47
+ '',
48
+ 'Output format (follow exactly):',
49
+ '- Put the JSON array inside a ```json fenced code block.',
50
+ '- On the line after the closing fence, output exactly: <<<SENTINEL_END>>>',
51
+ '- Write nothing after that line.',
52
+ '',
53
+ 'Files below are shown with `N| ` line-number prefixes; use them for line_range.',
54
+ 'Do not include the prefix in offending_snippet.',
55
+ ].join('\n');
56
+ }
57
+ /**
58
+ * Build an audit prompt. Files not matching the pack's applies_to scope are
59
+ * excluded and reported back in {@link PromptResult.skippedFiles}.
60
+ */
61
+ export function buildAuditPrompt(input) {
62
+ const { pack, files, repoName, context, repoNotes } = input;
63
+ const { manifest, body } = pack;
64
+ const included = [];
65
+ const skippedFiles = [];
66
+ for (const file of files) {
67
+ if (matchesAppliesTo(manifest, file.path)) {
68
+ included.push(file);
69
+ }
70
+ else {
71
+ skippedFiles.push(file.path);
72
+ }
73
+ }
74
+ const sections = [];
75
+ const repoLabel = repoName ? `\`${repoName}\`` : 'this repository';
76
+ const languages = manifest.appliesTo.languages;
77
+ const framing = [
78
+ '# Security audit',
79
+ '',
80
+ `You are a meticulous security reviewer auditing ${repoLabel} with the rule pack "${manifest.name}" (version ${manifest.version}, category ${manifest.category || 'unspecified'}).`,
81
+ languages.length > 0 ? `The pack targets: ${languages.join(', ')}.` : '',
82
+ '',
83
+ 'Follow the audit instructions exactly. Report only issues the instructions call for. When a pattern has known exceptions you cannot rule out from the code alone, lower your confidence rather than guessing.',
84
+ ]
85
+ .filter(line => line !== '')
86
+ .join('\n');
87
+ sections.push(framing);
88
+ sections.push(['## Audit instructions', '', body.trim()].join('\n'));
89
+ const weighting = Object.entries(manifest.severityWeighting);
90
+ if (weighting.length > 0) {
91
+ sections.push([
92
+ '## Severity weighting',
93
+ '',
94
+ 'The rule pack assigns these baseline severities to specific finding types:',
95
+ '',
96
+ ...weighting.map(([key, severity]) => `- ${key}: ${severity}`),
97
+ ].join('\n'));
98
+ }
99
+ sections.push(reportingContract(manifest.name, manifest.category));
100
+ const contextParts = [];
101
+ if (repoNotes && repoNotes.trim().length > 0) {
102
+ contextParts.push(repoNotes.trim());
103
+ }
104
+ for (const file of context ?? []) {
105
+ contextParts.push(formatFile(file));
106
+ }
107
+ if (contextParts.length > 0) {
108
+ sections.push(['## Additional context', '', contextParts.join('\n\n')].join('\n'));
109
+ }
110
+ sections.push([
111
+ '## Files under audit',
112
+ '',
113
+ included.length > 0
114
+ ? included.map(formatFile).join('\n\n')
115
+ : "No files matched this pack's applies_to scope; report no findings.",
116
+ ].join('\n'));
117
+ return {
118
+ prompt: sections.join('\n\n'),
119
+ includedFiles: included.map(file => file.path),
120
+ skippedFiles,
121
+ };
122
+ }
123
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../source/prompt/build.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Inputs and output for audit prompt templating. The builder is pure: the
3
+ * orchestrator reads files from disk and passes them in, so the same code path
4
+ * serves both the Actions run and a local `sentinel run` (see
5
+ * docs/workflow/index.md#execution-model).
6
+ */
7
+ import type { RulePack } from '../rule-packs/types.js';
8
+ /** A repository file, with its POSIX-style repo-relative path. */
9
+ export interface SourceFile {
10
+ path: string;
11
+ content: string;
12
+ }
13
+ /** Everything needed to build one audit prompt for one pack against one repo. */
14
+ export interface PromptInput {
15
+ /** The rule pack whose body is the audit instructions. */
16
+ pack: RulePack;
17
+ /** Candidate source files; scoped down by the pack's applies_to. */
18
+ files: SourceFile[];
19
+ /** The audited repository, e.g. "my-org/my-program". */
20
+ repoName?: string;
21
+ /** Additional reference files the pack should read (Anchor.toml, etc.). */
22
+ context?: SourceFile[];
23
+ /** Free-text per-repo context. */
24
+ repoNotes?: string;
25
+ }
26
+ /** The assembled prompt plus which files it did and did not include. */
27
+ export interface PromptResult {
28
+ prompt: string;
29
+ /** Paths included after applies_to scoping. */
30
+ includedFiles: string[];
31
+ /** Paths excluded by applies_to scoping. */
32
+ skippedFiles: string[];
33
+ }
34
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/prompt/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAC;AAErD,kEAAkE;AAClE,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,iFAAiF;AACjF,MAAM,WAAW,WAAW;IAC3B,0DAA0D;IAC1D,IAAI,EAAE,QAAQ,CAAC;IACf,oEAAoE;IACpE,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IACvB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wEAAwE;AACxE,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,4CAA4C;IAC5C,YAAY,EAAE,MAAM,EAAE,CAAC;CACvB"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Inputs and output for audit prompt templating. The builder is pure: the
3
+ * orchestrator reads files from disk and passes them in, so the same code path
4
+ * serves both the Actions run and a local `sentinel run` (see
5
+ * docs/workflow/index.md#execution-model).
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../source/prompt/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Resolve a rule pack's `depends_on` graph into a run order. A pack can pull in
3
+ * a language-general or organisation-conventions pack that must run alongside
4
+ * it; this produces the transitive closure in dependency-first order, with
5
+ * missing dependencies and cycles reported as structured errors.
6
+ */
7
+ import type { RulePack, RulePackError } from './types.js';
8
+ /** The outcome of resolving a dependency graph. */
9
+ export interface DependencyResult {
10
+ /** Pack names in run order: every dependency precedes its dependents. */
11
+ order: string[];
12
+ /** Missing-dependency and cycle errors. Empty when resolution succeeded. */
13
+ errors: RulePackError[];
14
+ }
15
+ /**
16
+ * Resolve the dependency closure of `rootName` over `packs`. The root itself is
17
+ * included, last, after everything it (transitively) depends on.
18
+ */
19
+ export declare function resolveDependencies(packs: RulePack[], rootName: string): DependencyResult;
20
+ //# sourceMappingURL=dependencies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../../source/rule-packs/dependencies.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAC,QAAQ,EAAE,aAAa,EAAC,MAAM,YAAY,CAAC;AAExD,mDAAmD;AACnD,MAAM,WAAW,gBAAgB;IAChC,yEAAyE;IACzE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,4EAA4E;IAC5E,MAAM,EAAE,aAAa,EAAE,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,QAAQ,EAAE,EACjB,QAAQ,EAAE,MAAM,GACd,gBAAgB,CAsDlB"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Resolve a rule pack's `depends_on` graph into a run order. A pack can pull in
3
+ * a language-general or organisation-conventions pack that must run alongside
4
+ * it; this produces the transitive closure in dependency-first order, with
5
+ * missing dependencies and cycles reported as structured errors.
6
+ */
7
+ /**
8
+ * Resolve the dependency closure of `rootName` over `packs`. The root itself is
9
+ * included, last, after everything it (transitively) depends on.
10
+ */
11
+ export function resolveDependencies(packs, rootName) {
12
+ const byName = new Map(packs.map(pack => [pack.manifest.name, pack]));
13
+ const errors = [];
14
+ const order = [];
15
+ const resolved = new Set();
16
+ const onStack = new Set();
17
+ if (!byName.has(rootName)) {
18
+ return {
19
+ order: [],
20
+ errors: [
21
+ { field: 'depends_on', message: `unknown rule pack: ${rootName}` },
22
+ ],
23
+ };
24
+ }
25
+ function visit(name) {
26
+ if (resolved.has(name)) {
27
+ return;
28
+ }
29
+ if (onStack.has(name)) {
30
+ errors.push({
31
+ field: 'depends_on',
32
+ message: `dependency cycle detected at rule pack: ${name}`,
33
+ });
34
+ return;
35
+ }
36
+ const pack = byName.get(name);
37
+ if (!pack) {
38
+ errors.push({
39
+ field: 'depends_on',
40
+ message: `unknown rule pack: ${name}`,
41
+ });
42
+ return;
43
+ }
44
+ onStack.add(name);
45
+ for (const dependency of pack.manifest.dependsOn) {
46
+ visit(dependency);
47
+ }
48
+ onStack.delete(name);
49
+ resolved.add(name);
50
+ order.push(name);
51
+ }
52
+ visit(rootName);
53
+ if (errors.length > 0) {
54
+ return { order: [], errors };
55
+ }
56
+ return { order, errors: [] };
57
+ }
58
+ //# sourceMappingURL=dependencies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencies.js","sourceRoot":"","sources":["../../source/rule-packs/dependencies.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAClC,KAAiB,EACjB,QAAgB;IAEhB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACtE,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAElC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3B,OAAO;YACN,KAAK,EAAE,EAAE;YACT,MAAM,EAAE;gBACP,EAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,sBAAsB,QAAQ,EAAE,EAAC;aAChE;SACD,CAAC;IACH,CAAC;IAED,SAAS,KAAK,CAAC,IAAY;QAC1B,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,OAAO;QACR,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,IAAI,CAAC;gBACX,KAAK,EAAE,YAAY;gBACnB,OAAO,EAAE,2CAA2C,IAAI,EAAE;aAC1D,CAAC,CAAC;YACH,OAAO;QACR,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,MAAM,CAAC,IAAI,CAAC;gBACX,KAAK,EAAE,YAAY;gBACnB,OAAO,EAAE,sBAAsB,IAAI,EAAE;aACrC,CAAC,CAAC;YACH,OAAO;QACR,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClB,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;YAClD,KAAK,CAAC,UAAU,CAAC,CAAC;QACnB,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAErB,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,CAAC;IAEhB,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,EAAC,KAAK,EAAE,EAAE,EAAE,MAAM,EAAC,CAAC;IAC5B,CAAC;IAED,OAAO,EAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAC,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * A small glob matcher for `applies_to.paths`. Supports the subset of glob
3
+ * syntax rule packs actually use:
4
+ *
5
+ * ** matches any number of path segments, including none
6
+ * * matches any run of characters within a single segment (not `/`)
7
+ * ? matches a single character within a segment (not `/`)
8
+ *
9
+ * Anything else is treated literally. This is deliberately not a full glob
10
+ * implementation; the orchestrator can reach for a heavier library if a pack
11
+ * ever needs brace expansion or character classes.
12
+ */
13
+ import type { RulePackManifest } from './types.js';
14
+ /** Compile a single glob pattern to an anchored regular expression. */
15
+ export declare function globToRegExp(pattern: string): RegExp;
16
+ /** Returns true if a POSIX-style path matches the glob pattern. */
17
+ export declare function matchesGlob(pattern: string, path: string): boolean;
18
+ /**
19
+ * Returns true if a file should be read under a pack's `applies_to.paths`. An
20
+ * empty path list means the pack applies to the whole repository.
21
+ */
22
+ export declare function matchesAppliesTo(manifest: RulePackManifest, path: string): boolean;
23
+ //# sourceMappingURL=glob.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../source/rule-packs/glob.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,YAAY,CAAC;AAMjD,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA6BpD;AAED,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAElE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC/B,QAAQ,EAAE,gBAAgB,EAC1B,IAAI,EAAE,MAAM,GACV,OAAO,CAMT"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * A small glob matcher for `applies_to.paths`. Supports the subset of glob
3
+ * syntax rule packs actually use:
4
+ *
5
+ * ** matches any number of path segments, including none
6
+ * * matches any run of characters within a single segment (not `/`)
7
+ * ? matches a single character within a segment (not `/`)
8
+ *
9
+ * Anything else is treated literally. This is deliberately not a full glob
10
+ * implementation; the orchestrator can reach for a heavier library if a pack
11
+ * ever needs brace expansion or character classes.
12
+ */
13
+ function escapeRegExp(literal) {
14
+ return literal.replace(/[.+^${}()|[\]\\]/g, '\\$&');
15
+ }
16
+ /** Compile a single glob pattern to an anchored regular expression. */
17
+ export function globToRegExp(pattern) {
18
+ let out = '';
19
+ for (let i = 0; i < pattern.length; i++) {
20
+ const char = pattern[i];
21
+ if (char === '*') {
22
+ if (pattern[i + 1] === '*') {
23
+ // `**` — cross segment boundaries. Consume a trailing slash so that
24
+ // `a/**/b` still matches `a/b` with no intervening segment.
25
+ i++;
26
+ if (pattern[i + 1] === '/') {
27
+ i++;
28
+ out += '(?:.*/)?';
29
+ }
30
+ else {
31
+ out += '.*';
32
+ }
33
+ }
34
+ else {
35
+ out += '[^/]*';
36
+ }
37
+ }
38
+ else if (char === '?') {
39
+ out += '[^/]';
40
+ }
41
+ else {
42
+ out += escapeRegExp(char);
43
+ }
44
+ }
45
+ // The pattern is built from a rule pack's applies_to globs (the installing
46
+ // org's own files), with all regex specials escaped and only bounded `*`,
47
+ // `**`, and `?` expansions — no attacker-controlled quantifiers.
48
+ // nosemgrep: javascript.lang.security.audit.detect-non-literal-regexp.detect-non-literal-regexp
49
+ return new RegExp(`^${out}$`);
50
+ }
51
+ /** Returns true if a POSIX-style path matches the glob pattern. */
52
+ export function matchesGlob(pattern, path) {
53
+ return globToRegExp(pattern).test(path);
54
+ }
55
+ /**
56
+ * Returns true if a file should be read under a pack's `applies_to.paths`. An
57
+ * empty path list means the pack applies to the whole repository.
58
+ */
59
+ export function matchesAppliesTo(manifest, path) {
60
+ const { paths } = manifest.appliesTo;
61
+ if (paths.length === 0) {
62
+ return true;
63
+ }
64
+ return paths.some(pattern => matchesGlob(pattern, path));
65
+ }
66
+ //# sourceMappingURL=glob.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glob.js","sourceRoot":"","sources":["../../source/rule-packs/glob.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,SAAS,YAAY,CAAC,OAAe;IACpC,OAAO,OAAO,CAAC,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;AACrD,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,YAAY,CAAC,OAAe;IAC3C,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YAClB,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBAC5B,oEAAoE;gBACpE,4DAA4D;gBAC5D,CAAC,EAAE,CAAC;gBACJ,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;oBAC5B,CAAC,EAAE,CAAC;oBACJ,GAAG,IAAI,UAAU,CAAC;gBACnB,CAAC;qBAAM,CAAC;oBACP,GAAG,IAAI,IAAI,CAAC;gBACb,CAAC;YACF,CAAC;iBAAM,CAAC;gBACP,GAAG,IAAI,OAAO,CAAC;YAChB,CAAC;QACF,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACzB,GAAG,IAAI,MAAM,CAAC;QACf,CAAC;aAAM,CAAC;YACP,GAAG,IAAI,YAAY,CAAC,IAAc,CAAC,CAAC;QACrC,CAAC;IACF,CAAC;IACD,2EAA2E;IAC3E,0EAA0E;IAC1E,iEAAiE;IACjE,gGAAgG;IAChG,OAAO,IAAI,MAAM,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC;AAC/B,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,IAAY;IACxD,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC/B,QAA0B,EAC1B,IAAY;IAEZ,MAAM,EAAC,KAAK,EAAC,GAAG,QAAQ,CAAC,SAAS,CAAC;IACnC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Parse and validate a single rule pack file: split the YAML manifest header
3
+ * from the Markdown body, validate the manifest against the v1 contract, and
4
+ * normalise it to a {@link RulePack}. Failures come back as a structured
5
+ * {@link ParseResult}, mirroring the findings validator.
6
+ */
7
+ import type { ParseResult } from './types.js';
8
+ /**
9
+ * Split a pack file into its raw YAML manifest and Markdown body. Returns null
10
+ * when the file does not open with a `---` fenced frontmatter block.
11
+ */
12
+ export declare function splitFrontmatter(raw: string): {
13
+ yaml: string;
14
+ body: string;
15
+ } | null;
16
+ /**
17
+ * Parse a rule pack file. On success, returns the normalised pack; on failure,
18
+ * returns every reason it was rejected.
19
+ */
20
+ export declare function parseRulePack(raw: string): ParseResult;
21
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../source/rule-packs/parse.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAEX,WAAW,EAGX,MAAM,YAAY,CAAC;AAoBpB;;;GAGG;AACH,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,MAAM,GACT;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GAAG,IAAI,CAkBrC;AAoGD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CA6HtD"}
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Parse and validate a single rule pack file: split the YAML manifest header
3
+ * from the Markdown body, validate the manifest against the v1 contract, and
4
+ * normalise it to a {@link RulePack}. Failures come back as a structured
5
+ * {@link ParseResult}, mirroring the findings validator.
6
+ */
7
+ import { parse as parseYaml } from 'yaml';
8
+ import { isSeverity } from '../findings/types.js';
9
+ /** Kebab-case: lowercase alphanumerics separated by single hyphens. */
10
+ const NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
11
+ /** Semver core with an optional prerelease/build suffix. */
12
+ const VERSION_PATTERN = /^\d+\.\d+\.\d+(?:[-+].+)?$/;
13
+ function isObject(value) {
14
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
15
+ }
16
+ function isNonEmptyString(value) {
17
+ return typeof value === 'string' && value.trim().length > 0;
18
+ }
19
+ function isStringArray(value) {
20
+ return Array.isArray(value) && value.every(item => typeof item === 'string');
21
+ }
22
+ /**
23
+ * Split a pack file into its raw YAML manifest and Markdown body. Returns null
24
+ * when the file does not open with a `---` fenced frontmatter block.
25
+ */
26
+ export function splitFrontmatter(raw) {
27
+ const normalised = raw.replace(/\r\n/g, '\n');
28
+ if (!normalised.startsWith('---\n')) {
29
+ return null;
30
+ }
31
+ const rest = normalised.slice(4);
32
+ const end = rest.indexOf('\n---');
33
+ if (end === -1) {
34
+ return null;
35
+ }
36
+ const yaml = rest.slice(0, end);
37
+ // Drop the closing fence line (its trailing chars + newline), then any blank
38
+ // lines separating the fence from the body.
39
+ const afterFence = rest.slice(end + 4);
40
+ const body = afterFence.replace(/^[^\n]*\n/, '').replace(/^\n+/, '');
41
+ return { yaml, body };
42
+ }
43
+ function validateAppliesTo(value, errors) {
44
+ const appliesTo = { paths: [], languages: [] };
45
+ if (value === undefined) {
46
+ return appliesTo;
47
+ }
48
+ if (!isObject(value)) {
49
+ errors.push({
50
+ field: 'applies_to',
51
+ message: 'applies_to must be a mapping with optional paths and languages',
52
+ });
53
+ return appliesTo;
54
+ }
55
+ if (value.paths !== undefined) {
56
+ if (isStringArray(value.paths)) {
57
+ appliesTo.paths = value.paths;
58
+ }
59
+ else {
60
+ errors.push({
61
+ field: 'applies_to.paths',
62
+ message: 'applies_to.paths must be a list of glob strings',
63
+ });
64
+ }
65
+ }
66
+ if (value.languages !== undefined) {
67
+ if (isStringArray(value.languages)) {
68
+ appliesTo.languages = value.languages;
69
+ }
70
+ else {
71
+ errors.push({
72
+ field: 'applies_to.languages',
73
+ message: 'applies_to.languages must be a list of language identifiers',
74
+ });
75
+ }
76
+ }
77
+ return appliesTo;
78
+ }
79
+ function validateSeverityWeighting(value, errors) {
80
+ const weighting = {};
81
+ if (value === undefined) {
82
+ return weighting;
83
+ }
84
+ if (!isObject(value)) {
85
+ errors.push({
86
+ field: 'severity_weighting',
87
+ message: 'severity_weighting must be a mapping of finding type to severity',
88
+ });
89
+ return weighting;
90
+ }
91
+ for (const [key, severity] of Object.entries(value)) {
92
+ if (isSeverity(severity)) {
93
+ weighting[key] = severity;
94
+ }
95
+ else {
96
+ errors.push({
97
+ field: `severity_weighting.${key}`,
98
+ message: 'severity must be one of: low, medium, high, critical',
99
+ });
100
+ }
101
+ }
102
+ return weighting;
103
+ }
104
+ function validateDependsOn(value, name, errors) {
105
+ if (value === undefined) {
106
+ return [];
107
+ }
108
+ if (!isStringArray(value)) {
109
+ errors.push({
110
+ field: 'depends_on',
111
+ message: 'depends_on must be a list of pack names',
112
+ });
113
+ return [];
114
+ }
115
+ if (typeof name === 'string' && value.includes(name)) {
116
+ errors.push({
117
+ field: 'depends_on',
118
+ message: 'a pack cannot depend on itself',
119
+ });
120
+ }
121
+ return value;
122
+ }
123
+ /**
124
+ * Parse a rule pack file. On success, returns the normalised pack; on failure,
125
+ * returns every reason it was rejected.
126
+ */
127
+ export function parseRulePack(raw) {
128
+ const errors = [];
129
+ const split = splitFrontmatter(raw);
130
+ if (!split) {
131
+ return {
132
+ valid: false,
133
+ pack: null,
134
+ errors: [
135
+ {
136
+ field: 'document',
137
+ message: 'a rule pack must open with a --- fenced YAML manifest followed by a Markdown body',
138
+ },
139
+ ],
140
+ };
141
+ }
142
+ let manifestData;
143
+ try {
144
+ manifestData = parseYaml(split.yaml);
145
+ }
146
+ catch (error) {
147
+ const message = error instanceof Error ? error.message : String(error);
148
+ return {
149
+ valid: false,
150
+ pack: null,
151
+ errors: [
152
+ { field: 'document', message: `invalid YAML manifest: ${message}` },
153
+ ],
154
+ };
155
+ }
156
+ if (!isObject(manifestData)) {
157
+ return {
158
+ valid: false,
159
+ pack: null,
160
+ errors: [{ field: 'document', message: 'manifest must be a mapping' }],
161
+ };
162
+ }
163
+ // name (required, kebab-case)
164
+ if (!isNonEmptyString(manifestData.name)) {
165
+ errors.push({
166
+ field: 'name',
167
+ message: 'name is required and must be a string',
168
+ });
169
+ }
170
+ else if (!NAME_PATTERN.test(manifestData.name)) {
171
+ errors.push({ field: 'name', message: 'name must be kebab-case' });
172
+ }
173
+ // version (required, semver)
174
+ if (!isNonEmptyString(manifestData.version)) {
175
+ errors.push({
176
+ field: 'version',
177
+ message: 'version is required and must be a string',
178
+ });
179
+ }
180
+ else if (!VERSION_PATTERN.test(manifestData.version)) {
181
+ errors.push({
182
+ field: 'version',
183
+ message: 'version must be semver (e.g. 1.2.0)',
184
+ });
185
+ }
186
+ // description (optional)
187
+ if (manifestData.description !== undefined &&
188
+ typeof manifestData.description !== 'string') {
189
+ errors.push({
190
+ field: 'description',
191
+ message: 'description must be a string',
192
+ });
193
+ }
194
+ // category (optional)
195
+ if (manifestData.category !== undefined &&
196
+ !isNonEmptyString(manifestData.category)) {
197
+ errors.push({
198
+ field: 'category',
199
+ message: 'category must be a non-empty string when present',
200
+ });
201
+ }
202
+ const appliesTo = validateAppliesTo(manifestData.applies_to, errors);
203
+ const severityWeighting = validateSeverityWeighting(manifestData.severity_weighting, errors);
204
+ const dependsOn = validateDependsOn(manifestData.depends_on, manifestData.name, errors);
205
+ // body (required — a pack with no prompt does nothing)
206
+ if (split.body.trim().length === 0) {
207
+ errors.push({
208
+ field: 'body',
209
+ message: 'the Markdown body is empty; a pack must contain an audit prompt',
210
+ });
211
+ }
212
+ if (errors.length > 0) {
213
+ return { valid: false, pack: null, errors };
214
+ }
215
+ const manifest = {
216
+ name: manifestData.name,
217
+ version: manifestData.version,
218
+ description: typeof manifestData.description === 'string'
219
+ ? manifestData.description
220
+ : '',
221
+ appliesTo,
222
+ severityWeighting,
223
+ dependsOn,
224
+ category: isNonEmptyString(manifestData.category)
225
+ ? manifestData.category
226
+ : '',
227
+ };
228
+ return { valid: true, pack: { manifest, body: split.body }, errors: [] };
229
+ }
230
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../source/rule-packs/parse.ts"],"names":[],"mappings":"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"}