@securityreviewai/securityreview-kit 0.1.47 → 0.1.49

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 (79) hide show
  1. package/dist/api.js +44 -0
  2. package/dist/commands/guardrails.js +13 -0
  3. package/dist/commands/init.js +88 -0
  4. package/dist/commands/profile.js +14 -0
  5. package/dist/commands/status.js +27 -0
  6. package/dist/commands/sync.js +6 -0
  7. package/dist/config.js +18 -0
  8. package/dist/fs.js +43 -0
  9. package/dist/index.js +44 -0
  10. package/dist/profile.js +113 -0
  11. package/dist/scaffold/claude-code.js +37 -0
  12. package/dist/scaffold/codex.js +35 -0
  13. package/dist/scaffold/cursor.js +39 -0
  14. package/dist/scaffold/gemini.js +10 -0
  15. package/dist/scaffold/index.js +22 -0
  16. package/dist/scaffold/mcp.js +15 -0
  17. package/dist/scaffold/rules.js +165 -0
  18. package/dist/scaffold/vibreview.js +24 -0
  19. package/dist/scaffold/vscode.js +22 -0
  20. package/dist/scaffold/windsurf.js +10 -0
  21. package/dist/sync/index.js +34 -0
  22. package/dist/sync/payload.js +23 -0
  23. package/dist/sync/state.js +12 -0
  24. package/dist/types.js +1 -0
  25. package/package.json +24 -30
  26. package/templates/claude/CLAUDE.md +13 -0
  27. package/templates/claude/agents/guardrail_profiler.md +12 -0
  28. package/templates/claude/agents/threat_modeler.md +5 -0
  29. package/templates/claude/skills/vibreview/SKILL.md +21 -0
  30. package/templates/claude/skills/vibreview/guardrail_patterns.md +12 -0
  31. package/templates/cursor/rules/vibreview-security.mdc +8 -0
  32. package/README.md +0 -105
  33. package/bin/securityreview-kit.js +0 -5
  34. package/src/cli.js +0 -109
  35. package/src/commands/init.js +0 -851
  36. package/src/commands/status.js +0 -99
  37. package/src/commands/switch-project.js +0 -207
  38. package/src/generators/mcp/claude.js +0 -85
  39. package/src/generators/mcp/claude.test.js +0 -64
  40. package/src/generators/mcp/codex.js +0 -70
  41. package/src/generators/mcp/codex.test.js +0 -43
  42. package/src/generators/mcp/cursor.js +0 -29
  43. package/src/generators/mcp/cursor.test.js +0 -50
  44. package/src/generators/mcp/gemini.js +0 -28
  45. package/src/generators/mcp/vscode.js +0 -48
  46. package/src/generators/mcp/vscode.test.js +0 -21
  47. package/src/generators/mcp/windsurf.js +0 -27
  48. package/src/generators/rules/antigravity.js +0 -22
  49. package/src/generators/rules/claude.js +0 -87
  50. package/src/generators/rules/claude.test.js +0 -60
  51. package/src/generators/rules/codex.js +0 -141
  52. package/src/generators/rules/codex.test.js +0 -59
  53. package/src/generators/rules/content.js +0 -110
  54. package/src/generators/rules/content.md +0 -57
  55. package/src/generators/rules/cursor.js +0 -128
  56. package/src/generators/rules/gemini.js +0 -13
  57. package/src/generators/rules/guardrails-init-profile.md +0 -56
  58. package/src/generators/rules/guardrails-profiler/SKILL.md +0 -130
  59. package/src/generators/rules/guardrails-profiler/references/signal-registry.json +0 -514
  60. package/src/generators/rules/guardrails-selection/SKILL.md +0 -187
  61. package/src/generators/rules/guardrails-selection/references/category-threat-map.md +0 -232
  62. package/src/generators/rules/guardrails_rule.md +0 -94
  63. package/src/generators/rules/hooks.json +0 -11
  64. package/src/generators/rules/skill.md +0 -256
  65. package/src/generators/rules/srai-profile.md +0 -32
  66. package/src/generators/rules/vibereview-sync/SKILL.md +0 -378
  67. package/src/generators/rules/vscode.js +0 -101
  68. package/src/generators/rules/vscode.test.js +0 -54
  69. package/src/generators/rules/windsurf.js +0 -13
  70. package/src/utils/constants.js +0 -95
  71. package/src/utils/cursor-agent-path.js +0 -67
  72. package/src/utils/cursor-cli-permissions.js +0 -28
  73. package/src/utils/detect.js +0 -27
  74. package/src/utils/fs-helpers.js +0 -82
  75. package/src/utils/guardrails-profiler-bundle.js +0 -84
  76. package/src/utils/ide-cli-install.js +0 -138
  77. package/src/utils/profiler-agent.js +0 -446
  78. package/src/utils/profiler-agent.test.js +0 -81
  79. package/src/utils/srai.js +0 -252
package/src/utils/srai.js DELETED
@@ -1,252 +0,0 @@
1
- import { existsSync } from 'node:fs';
2
- import { join } from 'node:path';
3
- import { MCP_SERVER_NAME, TARGET_NAMES, TARGETS } from './constants.js';
4
- import { readJson, readText } from './fs-helpers.js';
5
-
6
- const PROJECT_LIST_PATH = '/api/projects/';
7
-
8
- /**
9
- * Normalize API URL from raw input.
10
- */
11
- export function normalizeApiUrl(value) {
12
- const trimmed = String(value || '').trim();
13
- if (!trimmed) return '';
14
-
15
- if (trimmed.startsWith('http://') || trimmed.startsWith('https://')) {
16
- return trimmed;
17
- }
18
-
19
- return `https://${trimmed}`;
20
- }
21
-
22
- function parseTomlEnvValue(content, key) {
23
- const match = content.match(new RegExp(`${key}\\s*=\\s*"(.*?)"`));
24
- return match ? match[1].trim() : '';
25
- }
26
-
27
- function extractCredentialsFromJsonConfig(content) {
28
- const servers = content?.mcpServers || content?.servers;
29
- if (!servers || typeof servers !== 'object') return null;
30
-
31
- const server = servers[MCP_SERVER_NAME];
32
- if (!server || typeof server !== 'object') return null;
33
-
34
- const apiUrl = normalizeApiUrl(server?.env?.SECURITY_REVIEW_API_URL || '');
35
- const apiToken = String(server?.env?.SECURITY_REVIEW_API_TOKEN || '').trim();
36
- if (!apiUrl || !apiToken) return null;
37
-
38
- return { apiUrl, apiToken };
39
- }
40
-
41
- /**
42
- * Read previously saved API credentials from any configured MCP file.
43
- */
44
- export function getStoredCredentials(cwd) {
45
- for (const targetName of TARGET_NAMES) {
46
- const target = TARGETS[targetName];
47
- const mcpPath = join(cwd, target.mcpConfigPath);
48
- if (!existsSync(mcpPath)) continue;
49
-
50
- if (mcpPath.endsWith('.toml')) {
51
- const content = readText(mcpPath);
52
- if (!content) continue;
53
-
54
- const apiUrl = normalizeApiUrl(parseTomlEnvValue(content, 'SECURITY_REVIEW_API_URL'));
55
- const apiToken = parseTomlEnvValue(content, 'SECURITY_REVIEW_API_TOKEN');
56
- if (apiUrl && apiToken) {
57
- return { apiUrl, apiToken };
58
- }
59
- continue;
60
- }
61
-
62
- const json = readJson(mcpPath);
63
- const extracted = extractCredentialsFromJsonConfig(json);
64
- if (extracted) {
65
- return extracted;
66
- }
67
- }
68
-
69
- return { apiUrl: '', apiToken: '' };
70
- }
71
-
72
- function resolveProjectsEndpoint(apiUrl) {
73
- const parsed = new URL(apiUrl);
74
- const pathname = parsed.pathname.replace(/\/+$/, '');
75
-
76
- if (pathname.endsWith('/api/projects')) {
77
- parsed.pathname = `${pathname}/`;
78
- } else if (pathname.endsWith('/api')) {
79
- parsed.pathname = `${pathname}/projects/`;
80
- } else if (!pathname || pathname === '/') {
81
- parsed.pathname = PROJECT_LIST_PATH;
82
- } else {
83
- parsed.pathname = `${pathname}${PROJECT_LIST_PATH}`;
84
- }
85
-
86
- parsed.search = '';
87
- parsed.hash = '';
88
- return parsed.toString();
89
- }
90
-
91
- function toProjectName(entry) {
92
- if (typeof entry === 'string') return entry.trim();
93
- if (!entry || typeof entry !== 'object') return '';
94
-
95
- const nameFields = [
96
- 'name',
97
- 'projectName',
98
- 'project_name',
99
- 'displayName',
100
- 'display_name',
101
- 'title',
102
- ];
103
-
104
- for (const key of nameFields) {
105
- const value = entry[key];
106
- if (typeof value === 'string' && value.trim()) {
107
- return value.trim();
108
- }
109
- }
110
-
111
- if (entry.project && typeof entry.project === 'object') {
112
- return toProjectName(entry.project);
113
- }
114
-
115
- return '';
116
- }
117
-
118
- function collectProjectLists(payload) {
119
- const collections = [];
120
-
121
- if (Array.isArray(payload)) {
122
- collections.push(payload);
123
- }
124
-
125
- if (payload && typeof payload === 'object') {
126
- const keys = ['projects', 'data', 'results', 'items'];
127
- for (const key of keys) {
128
- if (Array.isArray(payload[key])) {
129
- collections.push(payload[key]);
130
- }
131
- }
132
- }
133
-
134
- return collections;
135
- }
136
-
137
- function extractProjectNames(payload) {
138
- const names = new Set();
139
- for (const list of collectProjectLists(payload)) {
140
- for (const entry of list) {
141
- const name = toProjectName(entry);
142
- if (name) names.add(name);
143
- }
144
- }
145
-
146
- return [...names].sort((a, b) => a.localeCompare(b));
147
- }
148
-
149
- /**
150
- * Whether a project object is marked for AI / vibe review kit selection.
151
- * Only entries with an explicit true-like `is_vibe_review` (or common API aliases) qualify.
152
- */
153
- export function isVibeReviewProject(entry) {
154
- if (!entry || typeof entry !== 'object') return false;
155
-
156
- const keys = ['is_vibe_review', 'isVibeReview', 'vibe_review', 'vibeReview'];
157
- for (const key of keys) {
158
- if (!Object.prototype.hasOwnProperty.call(entry, key)) continue;
159
- const value = entry[key];
160
- if (value === true || value === 1) return true;
161
- if (typeof value === 'string') {
162
- const v = value.toLowerCase().trim();
163
- if (v === 'true' || v === '1' || v === 'yes') return true;
164
- }
165
- return false;
166
- }
167
-
168
- return false;
169
- }
170
-
171
- /**
172
- * Extract { name, entry } pairs from a projects API payload.
173
- */
174
- export function extractProjectEntries(payload) {
175
- const out = [];
176
- const seen = new Set();
177
-
178
- for (const list of collectProjectLists(payload)) {
179
- for (const entry of list) {
180
- const name = toProjectName(entry);
181
- if (!name || seen.has(name)) continue;
182
- seen.add(name);
183
- out.push({ name, entry });
184
- }
185
- }
186
-
187
- out.sort((a, b) => a.name.localeCompare(b.name));
188
- return out;
189
- }
190
-
191
- async function fetchProjectsPayload(apiUrl, apiToken) {
192
- const endpoint = resolveProjectsEndpoint(apiUrl);
193
-
194
- let response;
195
- try {
196
- response = await fetch(endpoint, {
197
- method: 'GET',
198
- headers: {
199
- Authorization: `Bearer ${apiToken}`,
200
- Accept: 'application/json',
201
- },
202
- });
203
- } catch (err) {
204
- throw new Error(`Could not reach SRAI API at ${endpoint}: ${err.message}`);
205
- }
206
-
207
- if (!response.ok) {
208
- throw new Error(
209
- `Project fetch failed (${response.status} ${response.statusText}) at ${endpoint}`,
210
- );
211
- }
212
-
213
- let payload;
214
- try {
215
- payload = await response.json();
216
- } catch {
217
- throw new Error(`Project fetch returned non-JSON content at ${endpoint}`);
218
- }
219
-
220
- return { payload, endpoint };
221
- }
222
-
223
- /**
224
- * Fetch all project names from SRAI (no filtering).
225
- */
226
- export async function fetchProjectNames(apiUrl, apiToken) {
227
- const { payload, endpoint } = await fetchProjectsPayload(apiUrl, apiToken);
228
- const names = extractProjectNames(payload);
229
- if (names.length === 0) {
230
- throw new Error(`No project names found in API response from ${endpoint}`);
231
- }
232
-
233
- return names;
234
- }
235
-
236
- /**
237
- * Fetch project names that have `is_vibe_review` (or API alias) set true — used for kit init / project switch.
238
- */
239
- export async function fetchVibeReviewProjectNames(apiUrl, apiToken) {
240
- const { payload, endpoint } = await fetchProjectsPayload(apiUrl, apiToken);
241
- const entries = extractProjectEntries(payload);
242
- const names = entries.filter(({ entry }) => isVibeReviewProject(entry)).map(({ name }) => name);
243
-
244
- if (names.length === 0) {
245
- throw new Error(
246
- `No projects with vibe review enabled (is_vibe_review=true) were returned from ${endpoint}. ` +
247
- 'Enable vibe review on at least one SRAI project, or check your API token and URL.',
248
- );
249
- }
250
-
251
- return names;
252
- }