@securityreviewai/securityreview-kit 0.1.50 → 0.1.52
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/README.md +105 -0
- package/bin/securityreview-kit.js +5 -0
- package/package.json +30 -24
- package/src/cli.js +109 -0
- package/src/commands/init.js +851 -0
- package/src/commands/status.js +99 -0
- package/src/commands/switch-project.js +207 -0
- package/src/generators/mcp/claude.js +85 -0
- package/src/generators/mcp/claude.test.js +64 -0
- package/src/generators/mcp/codex.js +70 -0
- package/src/generators/mcp/codex.test.js +43 -0
- package/src/generators/mcp/cursor.js +29 -0
- package/src/generators/mcp/cursor.test.js +50 -0
- package/src/generators/mcp/gemini.js +28 -0
- package/src/generators/mcp/vscode.js +29 -0
- package/src/generators/mcp/windsurf.js +27 -0
- package/src/generators/rules/antigravity.js +22 -0
- package/src/generators/rules/claude.js +87 -0
- package/src/generators/rules/claude.test.js +60 -0
- package/src/generators/rules/codex.js +141 -0
- package/src/generators/rules/codex.test.js +59 -0
- package/src/generators/rules/content.js +110 -0
- package/src/generators/rules/cursor.js +128 -0
- package/src/generators/rules/gemini.js +13 -0
- package/src/generators/rules/guardrails-init-profile.md +56 -0
- package/src/generators/rules/guardrails-profiler/SKILL.md +130 -0
- package/src/generators/rules/guardrails-profiler/references/signal-registry.json +514 -0
- package/src/generators/rules/guardrails-selection/references/category-threat-map.md +232 -0
- package/src/generators/rules/guardrails_rule.md +94 -0
- package/src/generators/rules/hooks.json +11 -0
- package/src/generators/rules/srai-profile.md +32 -0
- package/src/generators/rules/vscode.js +101 -0
- package/src/generators/rules/vscode.test.js +54 -0
- package/src/generators/rules/windsurf.js +13 -0
- package/src/utils/constants.js +95 -0
- package/src/utils/cursor-agent-path.js +67 -0
- package/src/utils/cursor-cli-permissions.js +28 -0
- package/src/utils/detect.js +27 -0
- package/src/utils/fs-helpers.js +82 -0
- package/src/utils/guardrails-profiler-bundle.js +84 -0
- package/src/utils/ide-cli-install.js +138 -0
- package/src/utils/profiler-agent.js +446 -0
- package/src/utils/profiler-agent.test.js +81 -0
- package/src/utils/srai.js +252 -0
- package/dist/api.js +0 -44
- package/dist/commands/guardrails.js +0 -13
- package/dist/commands/init.js +0 -88
- package/dist/commands/profile.js +0 -14
- package/dist/commands/status.js +0 -27
- package/dist/commands/sync.js +0 -6
- package/dist/config.js +0 -18
- package/dist/fs.js +0 -43
- package/dist/index.js +0 -44
- package/dist/profile.js +0 -113
- package/dist/scaffold/claude-code.js +0 -43
- package/dist/scaffold/codex.js +0 -41
- package/dist/scaffold/cursor.js +0 -45
- package/dist/scaffold/gemini.js +0 -10
- package/dist/scaffold/index.js +0 -22
- package/dist/scaffold/mcp.js +0 -15
- package/dist/scaffold/rules.js +0 -191
- package/dist/scaffold/vibreview.js +0 -30
- package/dist/scaffold/vscode.js +0 -28
- package/dist/scaffold/windsurf.js +0 -10
- package/dist/sync/index.js +0 -34
- package/dist/sync/payload.js +0 -23
- package/dist/sync/state.js +0 -12
- package/dist/types.js +0 -1
- package/templates/claude/CLAUDE.md +0 -13
- package/templates/claude/agents/guardrail_profiler.md +0 -12
- package/templates/claude/agents/threat_modeler.md +0 -5
- package/templates/claude/skills/vibreview/SKILL.md +0 -21
- package/templates/claude/skills/vibreview/guardrail_patterns.md +0 -12
- package/templates/cursor/rules/vibreview-security.mdc +0 -8
- /package/{templates/shared → src/generators/rules}/content.md +0 -0
- /package/{templates/shared/guardrails-selection.md → src/generators/rules/guardrails-selection/SKILL.md} +0 -0
- /package/{templates/shared/threat-modelling.md → src/generators/rules/skill.md} +0 -0
- /package/{templates/shared → src/generators/rules}/vibereview-sync/SKILL.md +0 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Guardrail Selection Threat Map
|
|
2
|
+
|
|
3
|
+
Use this file when deciding which guardrail categories apply to the current task and which threat families should influence the shortlist.
|
|
4
|
+
|
|
5
|
+
The intent is not to produce a full threat model here. The intent is to make sure likely exploit paths influence which guardrails are fetched by id and enforced during implementation.
|
|
6
|
+
|
|
7
|
+
## How to use this map
|
|
8
|
+
|
|
9
|
+
1. Start from the feature or code change.
|
|
10
|
+
2. Infer the categories involved in the implementation.
|
|
11
|
+
3. Use the mappings below to identify likely threat families.
|
|
12
|
+
4. Shortlist guardrails that directly or adjacently mitigate those threats.
|
|
13
|
+
5. Fetch those guardrails with `get_guardrail_by_id`.
|
|
14
|
+
|
|
15
|
+
## STRIDE-style mappings for guardrail selection
|
|
16
|
+
|
|
17
|
+
### Spoofing
|
|
18
|
+
|
|
19
|
+
Usually maps to authentication and session-related controls.
|
|
20
|
+
|
|
21
|
+
Threat patterns to consider:
|
|
22
|
+
|
|
23
|
+
- identity-related attacks
|
|
24
|
+
- session and token attacks
|
|
25
|
+
- business-logic attacks leading to authentication bypass
|
|
26
|
+
- injection attacks leading to authentication bypass
|
|
27
|
+
- serialization attacks leading to authentication bypass
|
|
28
|
+
- cryptographic attacks leading to authentication bypass
|
|
29
|
+
- lapses in logging leading to authentication bypass
|
|
30
|
+
- client-side trust leading to authentication bypass
|
|
31
|
+
|
|
32
|
+
Categories commonly shortlisted:
|
|
33
|
+
|
|
34
|
+
- `authentication`
|
|
35
|
+
- `session_management`
|
|
36
|
+
- `cryptography`
|
|
37
|
+
- `logging`
|
|
38
|
+
- `client_side`
|
|
39
|
+
- `business_logic`
|
|
40
|
+
- `input_validation`
|
|
41
|
+
- `deserialization`
|
|
42
|
+
|
|
43
|
+
### Tampering
|
|
44
|
+
|
|
45
|
+
Usually maps to authorization, integrity, and unsafe state change controls.
|
|
46
|
+
|
|
47
|
+
Threat patterns to consider:
|
|
48
|
+
|
|
49
|
+
- broken object level access control patterns
|
|
50
|
+
- broken functional level access control patterns
|
|
51
|
+
- injection-driven authorization bypass
|
|
52
|
+
- serialization-driven authorization bypass
|
|
53
|
+
- business-logic-driven authorization bypass
|
|
54
|
+
- client-side trust leading to unauthorized state changes
|
|
55
|
+
|
|
56
|
+
Categories commonly shortlisted:
|
|
57
|
+
|
|
58
|
+
- `authorization`
|
|
59
|
+
- `tenant_isolation`
|
|
60
|
+
- `data_access`
|
|
61
|
+
- `business_logic`
|
|
62
|
+
- `logging`
|
|
63
|
+
- `input_validation`
|
|
64
|
+
- `deserialization`
|
|
65
|
+
- `client_side`
|
|
66
|
+
|
|
67
|
+
### Repudiation
|
|
68
|
+
|
|
69
|
+
Usually appears when spoofing and tampering are possible but the system cannot prove what happened.
|
|
70
|
+
|
|
71
|
+
Threat patterns to consider:
|
|
72
|
+
|
|
73
|
+
- weak or missing audit trails for auth and authorization decisions
|
|
74
|
+
- missing actor attribution on sensitive state changes
|
|
75
|
+
- mutable or incomplete event records
|
|
76
|
+
- inability to correlate session, actor, and resource changes
|
|
77
|
+
|
|
78
|
+
Categories commonly shortlisted:
|
|
79
|
+
|
|
80
|
+
- `logging`
|
|
81
|
+
- `monitoring`
|
|
82
|
+
- `authentication`
|
|
83
|
+
- `authorization`
|
|
84
|
+
- `admin_workflows`
|
|
85
|
+
|
|
86
|
+
### Information Disclosure
|
|
87
|
+
|
|
88
|
+
Usually maps to authorization, data exposure, logging, and unsafe client-side trust.
|
|
89
|
+
|
|
90
|
+
Threat patterns to consider:
|
|
91
|
+
|
|
92
|
+
- broken object level access control patterns
|
|
93
|
+
- broken functional level access control patterns
|
|
94
|
+
- injection-driven information disclosure
|
|
95
|
+
- serialization-driven information disclosure
|
|
96
|
+
- business-logic-driven information disclosure
|
|
97
|
+
- lapses in logging leading to disclosure
|
|
98
|
+
- client-side trust causing exposure of protected data
|
|
99
|
+
|
|
100
|
+
Categories commonly shortlisted:
|
|
101
|
+
|
|
102
|
+
- `authorization`
|
|
103
|
+
- `tenant_isolation`
|
|
104
|
+
- `data_access`
|
|
105
|
+
- `logging`
|
|
106
|
+
- `input_validation`
|
|
107
|
+
- `deserialization`
|
|
108
|
+
- `client_side`
|
|
109
|
+
- `output_encoding`
|
|
110
|
+
|
|
111
|
+
### Denial of Service
|
|
112
|
+
|
|
113
|
+
Usually maps to workload protection, parsing safety, quota controls, and expensive query behavior.
|
|
114
|
+
|
|
115
|
+
Threat patterns to consider:
|
|
116
|
+
|
|
117
|
+
- broken access control patterns that expose heavy operations
|
|
118
|
+
- injection or data-access paths that amplify resource consumption
|
|
119
|
+
- serialization-driven memory or parser exhaustion
|
|
120
|
+
- business-logic-driven abuse of expensive workflows
|
|
121
|
+
- logging lapses that hide repeated abuse
|
|
122
|
+
|
|
123
|
+
Categories commonly shortlisted:
|
|
124
|
+
|
|
125
|
+
- `rate_limiting`
|
|
126
|
+
- `input_validation`
|
|
127
|
+
- `file_uploads`
|
|
128
|
+
- `deserialization`
|
|
129
|
+
- `data_access`
|
|
130
|
+
- `network`
|
|
131
|
+
- `monitoring`
|
|
132
|
+
- `logging`
|
|
133
|
+
- `business_logic`
|
|
134
|
+
|
|
135
|
+
### Elevation of Privilege
|
|
136
|
+
|
|
137
|
+
Usually maps to authorization, role boundaries, trust decisions, and privileged workflow controls.
|
|
138
|
+
|
|
139
|
+
Threat patterns to consider:
|
|
140
|
+
|
|
141
|
+
- access control bypasses from broken object or function level access
|
|
142
|
+
- injection-based privilege escalation
|
|
143
|
+
- client-side induced privilege escalation
|
|
144
|
+
- serialization-induced privilege escalation
|
|
145
|
+
- business-logic-triggered privilege escalation
|
|
146
|
+
- logging lapses that conceal privilege abuse
|
|
147
|
+
|
|
148
|
+
Categories commonly shortlisted:
|
|
149
|
+
|
|
150
|
+
- `authorization`
|
|
151
|
+
- `tenant_isolation`
|
|
152
|
+
- `admin_workflows`
|
|
153
|
+
- `business_logic`
|
|
154
|
+
- `client_side`
|
|
155
|
+
- `input_validation`
|
|
156
|
+
- `deserialization`
|
|
157
|
+
- `logging`
|
|
158
|
+
|
|
159
|
+
## Fast examples
|
|
160
|
+
|
|
161
|
+
### Add password reset flow
|
|
162
|
+
|
|
163
|
+
Likely categories:
|
|
164
|
+
|
|
165
|
+
- `authentication`
|
|
166
|
+
- `session_management`
|
|
167
|
+
- `cryptography`
|
|
168
|
+
- `logging`
|
|
169
|
+
- `rate_limiting`
|
|
170
|
+
|
|
171
|
+
Likely threat families:
|
|
172
|
+
|
|
173
|
+
- spoofing
|
|
174
|
+
- repudiation
|
|
175
|
+
- information disclosure
|
|
176
|
+
|
|
177
|
+
### Add admin endpoint to change user role
|
|
178
|
+
|
|
179
|
+
Likely categories:
|
|
180
|
+
|
|
181
|
+
- `authorization`
|
|
182
|
+
- `tenant_isolation`
|
|
183
|
+
- `admin_workflows`
|
|
184
|
+
- `logging`
|
|
185
|
+
- `business_logic`
|
|
186
|
+
|
|
187
|
+
Likely threat families:
|
|
188
|
+
|
|
189
|
+
- tampering
|
|
190
|
+
- repudiation
|
|
191
|
+
- elevation of privilege
|
|
192
|
+
- information disclosure
|
|
193
|
+
|
|
194
|
+
### Add bulk import endpoint
|
|
195
|
+
|
|
196
|
+
Likely categories:
|
|
197
|
+
|
|
198
|
+
- `input_validation`
|
|
199
|
+
- `file_uploads`
|
|
200
|
+
- `deserialization`
|
|
201
|
+
- `data_access`
|
|
202
|
+
- `logging`
|
|
203
|
+
- `rate_limiting`
|
|
204
|
+
|
|
205
|
+
Likely threat families:
|
|
206
|
+
|
|
207
|
+
- tampering
|
|
208
|
+
- information disclosure
|
|
209
|
+
- denial of service
|
|
210
|
+
|
|
211
|
+
### Move entitlement checks to the frontend
|
|
212
|
+
|
|
213
|
+
Likely categories:
|
|
214
|
+
|
|
215
|
+
- `authorization`
|
|
216
|
+
- `client_side`
|
|
217
|
+
- `tenant_isolation`
|
|
218
|
+
- `logging`
|
|
219
|
+
|
|
220
|
+
Likely threat families:
|
|
221
|
+
|
|
222
|
+
- tampering
|
|
223
|
+
- information disclosure
|
|
224
|
+
- elevation of privilege
|
|
225
|
+
|
|
226
|
+
## Selection reminders
|
|
227
|
+
|
|
228
|
+
- A feature can require guardrails from multiple categories.
|
|
229
|
+
- Shortlist for exploit chains, not isolated weaknesses.
|
|
230
|
+
- Logging often matters because poor auditability can turn spoofing, tampering, or privilege abuse into repudiation.
|
|
231
|
+
- Client-side logic often needs server-side guardrails even if the visible change is in the UI.
|
|
232
|
+
- If no existing guardrail covers a realistic recurring threat, create an `ide_generated` guardrail and carry it into the final VibeReview markdown sync.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Vibe Guardrails — Secure by Code
|
|
2
|
+
|
|
3
|
+
**Enforce project-specific security guardrails during every code-generation task.**
|
|
4
|
+
|
|
5
|
+
This rule complements the PWNISMS threat model ("secure by design") with concrete, project-level coding dos and don'ts ("secure by code"). Guardrails are maintained in SRAI and fetched via `security-review-mcp`.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## When this rule applies
|
|
10
|
+
|
|
11
|
+
This rule is **active for every code-generation or code-modification task** — including:
|
|
12
|
+
|
|
13
|
+
- Implementing new features or endpoints
|
|
14
|
+
- Fixing bugs that touch security-relevant code
|
|
15
|
+
- Refactoring code that handles auth, input, secrets, data storage, or network
|
|
16
|
+
- Generating boilerplate, scaffolding, or templates that will run in production
|
|
17
|
+
|
|
18
|
+
### When to skip
|
|
19
|
+
|
|
20
|
+
Skip guardrail enforcement for tasks with **no code output** (documentation, Q&A, formatting, renaming).
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Required behavior
|
|
25
|
+
|
|
26
|
+
### 1. Use the guardrails-selection skill at the start of every code task
|
|
27
|
+
|
|
28
|
+
Before writing or modifying code, you must read and follow `{{GUARDRAILS_SELECTION_SKILL_DIR}}/SKILL.md`.
|
|
29
|
+
|
|
30
|
+
That skill is mandatory because the IDE must not leave guardrail selection to chance. The required workflow is:
|
|
31
|
+
|
|
32
|
+
- **Analyze the task first** — infer what the user is actually building, what components are touched, what categories are involved, and what threats might occur.
|
|
33
|
+
- **Resolve the project** — use `find_project_by_name` with `name="<SRAI_PROJECT_NAME>"` to obtain `project_id`.
|
|
34
|
+
- **Load the broad catalog** — call `get_guardrails` with `project_id`.
|
|
35
|
+
- **Shortlist intentionally** — choose only the guardrails that mitigate the categories and likely threats for the current task.
|
|
36
|
+
- **Hydrate the exact shortlist** — call `get_guardrail_by_id` for the shortlisted guardrail ids so implementation uses the exact selected guardrails, not a vague reading of the full catalog.
|
|
37
|
+
- **Preserve the shortlist** — keep the selected existing guardrails in context so the final VibeReview markdown can include the same guardrails later without re-querying.
|
|
38
|
+
|
|
39
|
+
The broad `get_guardrails` result is only the candidate catalog. The active implementation guardrails must come from the shortlisted `get_guardrail_by_id` result.
|
|
40
|
+
|
|
41
|
+
Each guardrail used for implementation should preserve these fields:
|
|
42
|
+
|
|
43
|
+
| Field | Description |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `id` | Stable guardrail identifier used with `get_guardrail_by_id` |
|
|
46
|
+
| `title` | Short name of the guardrail |
|
|
47
|
+
| `rule_type` | `must` (mandatory) or `must_not` (prohibition) |
|
|
48
|
+
| `category` | Grouping label (e.g. `authentication`, `input_validation`, `secrets`) or `null` |
|
|
49
|
+
| `instruction` | The actionable coding directive |
|
|
50
|
+
|
|
51
|
+
If `get_guardrails` returns additional metadata such as `source_ref`, use it as supporting context during selection.
|
|
52
|
+
|
|
53
|
+
### 2. Apply guardrails during code generation
|
|
54
|
+
|
|
55
|
+
- **`must` rules (DOs):** Treat as mandatory implementation requirements. Every line of generated code must satisfy all applicable `must` guardrails.
|
|
56
|
+
- **`must_not` rules (DON'Ts):** Treat as hard prohibitions. Generated code must never violate a `must_not` guardrail.
|
|
57
|
+
- If a guardrail conflicts with the user's explicit instruction, **flag the conflict** to the user and ask for confirmation before proceeding.
|
|
58
|
+
- If no guardrails are returned (empty list), proceed normally using baseline PWNISMS controls.
|
|
59
|
+
|
|
60
|
+
### 3. Cross-reference with PWNISMS
|
|
61
|
+
|
|
62
|
+
Guardrails and PWNISMS are complementary:
|
|
63
|
+
|
|
64
|
+
- Guardrails provide **project-specific, concrete rules** derived from prior threat reviews, compliance requirements, and team decisions.
|
|
65
|
+
- PWNISMS provides **universal threat-category coverage** to catch gaps that guardrails may not yet cover.
|
|
66
|
+
- When PWNISMS analysis reveals a gap not covered by any existing guardrail, **create a new guardrail on the fly** and apply it immediately (marked `source: "ide_generated"` in the VibeReview markdown).
|
|
67
|
+
|
|
68
|
+
### 4. Report guardrail compliance
|
|
69
|
+
|
|
70
|
+
After code generation, include a brief guardrails compliance summary:
|
|
71
|
+
|
|
72
|
+
- List which guardrails were applied (by title), distinguishing existing vs IDE-generated.
|
|
73
|
+
- Flag any guardrails that could not be fully satisfied and explain why.
|
|
74
|
+
- Do not drop shortlisted existing guardrails from session context. The final VibeReview markdown must include the same shortlist, including any unsatisfied items with notes.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Guardrail lifecycle — updates and new guardrails
|
|
79
|
+
|
|
80
|
+
Guardrails are living artifacts. The IDE agent can create, apply, and update them:
|
|
81
|
+
|
|
82
|
+
- **New guardrail**: When threat modeling or code review reveals a recurring security pattern not yet captured, the IDE agent creates and applies a new guardrail on the fly. These are reported to SRAI in the final VibeReview markdown with `source: "ide_generated"`.
|
|
83
|
+
- **Edit suggestion**: When an existing guardrail is too broad, too narrow, or outdated, suggest an update to the user.
|
|
84
|
+
- All guardrails — existing and IDE-generated — must be preserved in the VibeReview markdown under a single `Guardrails Applied` section that the server can normalize into `guardrails_applied`.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Tool Reference
|
|
89
|
+
|
|
90
|
+
| Tool | Purpose |
|
|
91
|
+
|---|---|
|
|
92
|
+
| `get_guardrails` | Fetch the broad project guardrails catalog (requires `project_id`) |
|
|
93
|
+
| `get_guardrail_by_id` | Fetch the exact shortlisted guardrails that will govern implementation |
|
|
94
|
+
| `find_project_by_name` | Resolve project by name to get `project_id` |
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"hooks": {
|
|
4
|
+
"sessionStart": [
|
|
5
|
+
{
|
|
6
|
+
"command": "printf '%s\\n' '{\"additional_context\":\"## MANDATORY SECURITY GATE (Session Policy)\\n\\nFor ANY user request that has security impact (auth, crypto, input handling, secrets, network, data storage, dependencies, new APIs/endpoints, or any code handling untrusted data):\\n\\n**Plan order:**\\n1. **Fetch Vibe Guardrails (first)** - Use .cursor/skills/guardrails-selection/SKILL.md. Analyze the task, call get_guardrails from security-review-mcp to load the broad catalog, shortlist the relevant guardrails, then call get_guardrail_by_id for the shortlist. These exact shortlisted guardrails are the hard constraints on generated code.\\n2. **PWNISMS threat modeling (second)** - Run threat modeling as a guide before writing code. Use .cursor/skills/threat-modelling/SKILL.md. Cross-reference guardrails with PWNISMS findings to identify gaps. Document findings to inform secure implementation.\\n3. **Implement secure code (third)** - Use the threat model findings AND shortlisted guardrails as guides to create secure code. Every must guardrail must be satisfied; no must_not guardrail may be violated.\\n4. **VibeReview sync (last)** - Read .cursor/skills/vibereview-sync/SKILL.md. The main agent must write a structured `.md` artifact under `vibereview/`, must not read sibling markdown files there just to infer format, must validate that all required metadata and sections are present, and must call `sync_ai_ide_markdown` directly after implementation is done. Include the exact shortlisted guardrails from earlier plus any IDE-generated guardrails in the markdown; do not query guardrails again during sync.\\n\\nNo blocking. No deferral. Guardrails enforce secure code; threat modeling guides the design; the main agent owns the final markdown sync to SRAI. Both sync and guardrail compliance are mandatory and should be part of your to-do.\"}'",
|
|
7
|
+
"timeout": 5
|
|
8
|
+
}
|
|
9
|
+
]
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: srai-profile
|
|
3
|
+
description: Create and upload a SecurityReviewAI code profile using security-review-mcp
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SRAI Profile Uploader
|
|
7
|
+
|
|
8
|
+
Create a code profile from the current request and upload it to SRAI using `security-review-mcp`.
|
|
9
|
+
|
|
10
|
+
Configured SRAI project name: `<SRAI_PROJECT_NAME>`
|
|
11
|
+
|
|
12
|
+
## Steps
|
|
13
|
+
|
|
14
|
+
1. Determine scope from the user prompt.
|
|
15
|
+
- If the request is about a specific capability/module/endpoint, produce a **Feature Code Profile**.
|
|
16
|
+
- If the request is broad, exploratory, or architecture-level, produce a **Codebase Code Profile**.
|
|
17
|
+
2. Build detailed profile content before any upload call.
|
|
18
|
+
- Include purpose, boundaries, entry points, sensitive data, trust boundaries, integrations, threats, controls, and open risks.
|
|
19
|
+
3. Resolve the SRAI project.
|
|
20
|
+
- Use the configured project name by default; if it is missing or ambiguous, ask the user to confirm it.
|
|
21
|
+
- Call `find_project_by_name` with `name="<SRAI_PROJECT_NAME>"`.
|
|
22
|
+
- If missing, call `list_projects`; if still missing, call `create_project` with `name="<SRAI_PROJECT_NAME>"`.
|
|
23
|
+
4. Upload generated markdown content with tool 11: `upload_document`.
|
|
24
|
+
- Use this for raw markdown/text generated in the chat.
|
|
25
|
+
- Use a clear document name such as `feature-code-profile-<feature>.md` or `codebase-code-profile-<repo>.md`.
|
|
26
|
+
5. Upload files/diagrams with tool 10: `upload_document` when needed.
|
|
27
|
+
- Provide base64 file content and file name.
|
|
28
|
+
- Set `document_type` to `Component Diagram` for architecture diagrams.
|
|
29
|
+
- Set `document_type` to `Uploaded Knowledgebase doc` for other document uploads.
|
|
30
|
+
6. Confirm the result.
|
|
31
|
+
- Report project name, upload tool used, document name, and that processing is asynchronous.
|
|
32
|
+
- If upload fails, return exact error details and next retry step.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { existsSync, unlinkSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import {
|
|
4
|
+
GUARDRAILS_SELECTION_SKILL_REL_DIR,
|
|
5
|
+
THREAT_MODELLING_SKILL_REL_DIR,
|
|
6
|
+
VIBEREVIEW_SYNC_SKILL_REL_DIR,
|
|
7
|
+
} from '../../utils/constants.js';
|
|
8
|
+
import { upsertSentinelBlock, writeText } from '../../utils/fs-helpers.js';
|
|
9
|
+
import { getRuleContent, getThreatModellingSkillContent, getVibeReviewSyncSkillContent } from './content.js';
|
|
10
|
+
|
|
11
|
+
function writeGeneratedText(filePath, content) {
|
|
12
|
+
const action = existsSync(filePath) ? 'updated' : 'created';
|
|
13
|
+
writeText(filePath, content);
|
|
14
|
+
return { filePath, action };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function removeGeneratedText(filePath) {
|
|
18
|
+
if (existsSync(filePath)) {
|
|
19
|
+
unlinkSync(filePath);
|
|
20
|
+
return { filePath, action: 'deleted' };
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getCopilotSessionHookContent() {
|
|
26
|
+
const additionalContext = [
|
|
27
|
+
'## MANDATORY SECURITY GATE (Session Policy)',
|
|
28
|
+
'',
|
|
29
|
+
'For any request with security impact (auth, authorization, crypto, input handling, secrets, network, data storage, dependencies, new APIs/endpoints, infrastructure, or code handling untrusted data), follow this order:',
|
|
30
|
+
'',
|
|
31
|
+
'1. Fetch Vibe Guardrails first using .github/skills/guardrails-selection/SKILL.md. Resolve the project, call get_guardrails, shortlist relevant guardrails, then call get_guardrail_by_id for the shortlist.',
|
|
32
|
+
'2. Run PWNISMS threat modelling using .github/skills/threat-modelling/SKILL.md. Explicitly walk Product, Workload, Network, IAM, Secrets, Monitoring, and Supply Chain.',
|
|
33
|
+
'3. Implement secure code using both the hydrated guardrails and PWNISMS findings.',
|
|
34
|
+
'4. Read .github/skills/vibereview-sync/SKILL.md. Write a structured .md artifact under vibereview/, do not read sibling markdown files there just to infer format, validate it, and call sync_ai_ide_markdown directly after threat modelling or guardrail enforcement. Reuse the exact guardrail shortlist; do not re-query guardrails during the final sync.',
|
|
35
|
+
'',
|
|
36
|
+
'Do not use project-profile exploration tools during normal coding tasks. No blocking and no deferral: guardrails first, PWNISMS second, implementation third, VibeReview sync last.',
|
|
37
|
+
].join('\n');
|
|
38
|
+
|
|
39
|
+
const commandPayload = JSON.stringify({
|
|
40
|
+
hookSpecificOutput: {
|
|
41
|
+
hookEventName: 'SessionStart',
|
|
42
|
+
additionalContext,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return JSON.stringify(
|
|
47
|
+
{
|
|
48
|
+
hooks: {
|
|
49
|
+
SessionStart: [
|
|
50
|
+
{
|
|
51
|
+
type: 'command',
|
|
52
|
+
command: `printf '%s\\n' '${commandPayload.replaceAll("'", "'\\''")}'`,
|
|
53
|
+
timeout: 5,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
null,
|
|
59
|
+
2,
|
|
60
|
+
) + '\n';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Generate VS Code Copilot instructions — appends to .github/copilot-instructions.md
|
|
65
|
+
*/
|
|
66
|
+
export function generate(cwd, options = {}) {
|
|
67
|
+
const optionsWithSkillDirs = {
|
|
68
|
+
...options,
|
|
69
|
+
guardrailsSelectionSkillDir: GUARDRAILS_SELECTION_SKILL_REL_DIR.vscode,
|
|
70
|
+
threatModellingSkillDir: THREAT_MODELLING_SKILL_REL_DIR.vscode,
|
|
71
|
+
vibereviewSyncSkillDir: VIBEREVIEW_SYNC_SKILL_REL_DIR.vscode,
|
|
72
|
+
};
|
|
73
|
+
const filePath = join(cwd, '.github', 'copilot-instructions.md');
|
|
74
|
+
const content = getRuleContent(optionsWithSkillDirs);
|
|
75
|
+
const action = upsertSentinelBlock(filePath, content);
|
|
76
|
+
|
|
77
|
+
const threatSkillPath = join(cwd, THREAT_MODELLING_SKILL_REL_DIR.vscode, 'SKILL.md');
|
|
78
|
+
const threatSkill = writeGeneratedText(
|
|
79
|
+
threatSkillPath,
|
|
80
|
+
getThreatModellingSkillContent(optionsWithSkillDirs),
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const vibereviewSyncSkillPath = join(cwd, VIBEREVIEW_SYNC_SKILL_REL_DIR.vscode, 'SKILL.md');
|
|
84
|
+
const vibereviewSyncSkill = writeGeneratedText(
|
|
85
|
+
vibereviewSyncSkillPath,
|
|
86
|
+
getVibeReviewSyncSkillContent(optionsWithSkillDirs),
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const deletedLegacyAgent = removeGeneratedText(join(cwd, '.github', 'agents', 'ctm_sync.agent.md'));
|
|
90
|
+
|
|
91
|
+
const hooksPath = join(cwd, '.github', 'hooks', 'srai-session-policy.json');
|
|
92
|
+
const hooks = writeGeneratedText(hooksPath, getCopilotSessionHookContent());
|
|
93
|
+
|
|
94
|
+
return [
|
|
95
|
+
{ filePath, action, kind: 'rule' },
|
|
96
|
+
{ ...threatSkill, kind: 'skill' },
|
|
97
|
+
{ ...vibereviewSyncSkill, kind: 'skill' },
|
|
98
|
+
{ ...hooks, kind: 'hooks' },
|
|
99
|
+
...(deletedLegacyAgent ? [{ ...deletedLegacyAgent, kind: 'cleanup' }] : []),
|
|
100
|
+
];
|
|
101
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { existsSync, mkdtempSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { test } from 'node:test';
|
|
5
|
+
import assert from 'node:assert/strict';
|
|
6
|
+
import { generate } from './vscode.js';
|
|
7
|
+
|
|
8
|
+
test('VS Code Copilot generator writes instructions, skills, and hooks', () => {
|
|
9
|
+
const cwd = mkdtempSync(join(tmpdir(), 'securityreview-kit-vscode-'));
|
|
10
|
+
|
|
11
|
+
const results = generate(cwd, { projectName: 'SmokeProject' });
|
|
12
|
+
|
|
13
|
+
const expectedPaths = [
|
|
14
|
+
'.github/copilot-instructions.md',
|
|
15
|
+
'.github/skills/threat-modelling/SKILL.md',
|
|
16
|
+
'.github/skills/vibereview-sync/SKILL.md',
|
|
17
|
+
'.github/hooks/srai-session-policy.json',
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
for (const relPath of expectedPaths) {
|
|
21
|
+
assert.equal(existsSync(join(cwd, relPath)), true, `${relPath} should exist`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
assert.deepEqual(results.map((entry) => entry.kind), ['rule', 'skill', 'skill', 'hooks']);
|
|
25
|
+
|
|
26
|
+
const instructions = readFileSync(join(cwd, '.github/copilot-instructions.md'), 'utf8');
|
|
27
|
+
assert.match(instructions, /\.github\/skills\/guardrails-selection\/SKILL\.md/);
|
|
28
|
+
assert.match(instructions, /\.github\/skills\/threat-modelling\/SKILL\.md/);
|
|
29
|
+
assert.match(instructions, /\.github\/skills\/vibereview-sync\/SKILL\.md/);
|
|
30
|
+
assert.match(instructions, /sync_ai_ide_markdown/);
|
|
31
|
+
assert.match(instructions, /vibereview\//);
|
|
32
|
+
assert.doesNotMatch(instructions, /\.cursor/);
|
|
33
|
+
|
|
34
|
+
const threatSkill = readFileSync(join(cwd, '.github/skills/threat-modelling/SKILL.md'), 'utf8');
|
|
35
|
+
for (const heading of ['Product', 'Workload', 'Network', 'IAM', 'Secrets', 'Monitoring', 'Supply Chain']) {
|
|
36
|
+
assert.match(threatSkill, new RegExp(heading));
|
|
37
|
+
}
|
|
38
|
+
assert.match(threatSkill, /sync_ai_ide_markdown/);
|
|
39
|
+
assert.match(threatSkill, /vibereview\//);
|
|
40
|
+
assert.doesNotMatch(threatSkill, /get_project_profile_description/);
|
|
41
|
+
|
|
42
|
+
const vibereviewSkill = readFileSync(join(cwd, '.github/skills/vibereview-sync/SKILL.md'), 'utf8');
|
|
43
|
+
assert.match(vibereviewSkill, /Do not read other/i);
|
|
44
|
+
assert.match(vibereviewSkill, /sync_ai_ide_markdown/);
|
|
45
|
+
assert.match(vibereviewSkill, /Guardrails Applied/);
|
|
46
|
+
assert.match(vibereviewSkill, /Practice 1/);
|
|
47
|
+
assert.match(vibereviewSkill, /practice_name:/);
|
|
48
|
+
|
|
49
|
+
const hooks = JSON.parse(readFileSync(join(cwd, '.github/hooks/srai-session-policy.json'), 'utf8'));
|
|
50
|
+
assert.equal(hooks.hooks.SessionStart[0].type, 'command');
|
|
51
|
+
assert.match(hooks.hooks.SessionStart[0].command, /vibereview/);
|
|
52
|
+
assert.match(hooks.hooks.SessionStart[0].command, /sync_ai_ide_markdown/);
|
|
53
|
+
assert.match(hooks.hooks.SessionStart[0].command, /vibereview-sync\/SKILL\.md/);
|
|
54
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { writeText } from '../../utils/fs-helpers.js';
|
|
3
|
+
import { getRuleContent } from './content.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generate Windsurf workspace rule at .windsurf/rules/srai-security-review.md
|
|
7
|
+
*/
|
|
8
|
+
export function generate(cwd, options = {}) {
|
|
9
|
+
const filePath = join(cwd, '.windsurf', 'rules', 'srai-security-review.md');
|
|
10
|
+
const content = getRuleContent(options);
|
|
11
|
+
writeText(filePath, content + '\n');
|
|
12
|
+
return filePath;
|
|
13
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Shared constants for securityreview-kit
|
|
2
|
+
|
|
3
|
+
export const MCP_SERVER_PACKAGE = '@securityreviewai/security-review-mcp';
|
|
4
|
+
export const MCP_SERVER_NAME = 'security-review-mcp';
|
|
5
|
+
|
|
6
|
+
export const ENV_VARS = {
|
|
7
|
+
apiUrl: 'SECURITY_REVIEW_API_URL',
|
|
8
|
+
apiToken: 'SECURITY_REVIEW_API_TOKEN',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const TARGETS = {
|
|
12
|
+
cursor: {
|
|
13
|
+
name: 'Cursor',
|
|
14
|
+
mcpConfigPath: '.cursor/mcp.json',
|
|
15
|
+
rulePath: '.cursor/rules/srai-security-review.mdc',
|
|
16
|
+
detectDirs: ['.cursor'],
|
|
17
|
+
},
|
|
18
|
+
claude: {
|
|
19
|
+
name: 'Claude Code',
|
|
20
|
+
mcpConfigPath: '.mcp.json',
|
|
21
|
+
rulePath: '.claude/CLAUDE.md',
|
|
22
|
+
ruleMode: 'append',
|
|
23
|
+
detectDirs: ['.claude'],
|
|
24
|
+
},
|
|
25
|
+
vscode: {
|
|
26
|
+
name: 'VS Code Copilot',
|
|
27
|
+
mcpConfigPath: '.vscode/mcp.json',
|
|
28
|
+
rulePath: '.github/copilot-instructions.md',
|
|
29
|
+
ruleMode: 'append',
|
|
30
|
+
detectDirs: ['.vscode'],
|
|
31
|
+
},
|
|
32
|
+
windsurf: {
|
|
33
|
+
name: 'Windsurf',
|
|
34
|
+
mcpConfigPath: '.windsurf/mcp_config.json',
|
|
35
|
+
rulePath: '.windsurf/rules/srai-security-review.md',
|
|
36
|
+
detectDirs: ['.windsurf'],
|
|
37
|
+
},
|
|
38
|
+
codex: {
|
|
39
|
+
name: 'Codex',
|
|
40
|
+
mcpConfigPath: '.codex/config.toml',
|
|
41
|
+
rulePath: '.codex/AGENTS.md',
|
|
42
|
+
ruleMode: 'append',
|
|
43
|
+
detectDirs: ['.codex'],
|
|
44
|
+
},
|
|
45
|
+
gemini: {
|
|
46
|
+
name: 'Gemini CLI',
|
|
47
|
+
mcpConfigPath: '.gemini/settings.json',
|
|
48
|
+
rulePath: 'GEMINI.md',
|
|
49
|
+
ruleMode: 'append',
|
|
50
|
+
detectDirs: ['.gemini'],
|
|
51
|
+
},
|
|
52
|
+
antigravity: {
|
|
53
|
+
name: 'Antigravity',
|
|
54
|
+
mcpConfigPath: '.gemini/settings.json',
|
|
55
|
+
rulePath: '.agent/rules/srai-security-review.md',
|
|
56
|
+
detectDirs: ['.agent'],
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const TARGET_NAMES = Object.keys(TARGETS);
|
|
61
|
+
|
|
62
|
+
/** Relative workspace dirs for the guardrails-profiler skill (per IDE / CLI). */
|
|
63
|
+
export const GUARDRAILS_PROFILER_SKILL_REL_DIR = {
|
|
64
|
+
cursor: '.cursor/skills/guardrails-profiler',
|
|
65
|
+
claude: '.claude/skills/guardrails-profiler',
|
|
66
|
+
vscode: '.github/skills/guardrails-profiler',
|
|
67
|
+
codex: '.codex/skills/guardrails-profiler',
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/** Relative workspace dirs for the guardrails-selection skill (per IDE / CLI). */
|
|
71
|
+
export const GUARDRAILS_SELECTION_SKILL_REL_DIR = {
|
|
72
|
+
cursor: '.cursor/skills/guardrails-selection',
|
|
73
|
+
claude: '.claude/skills/guardrails-selection',
|
|
74
|
+
vscode: '.github/skills/guardrails-selection',
|
|
75
|
+
codex: '.codex/skills/guardrails-selection',
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/** Relative workspace dirs for the PWNISMS threat-modelling skill (per IDE / CLI). */
|
|
79
|
+
export const THREAT_MODELLING_SKILL_REL_DIR = {
|
|
80
|
+
cursor: '.cursor/skills/threat-modelling',
|
|
81
|
+
claude: '.claude/skills/threat-modelling',
|
|
82
|
+
vscode: '.github/skills/threat-modelling',
|
|
83
|
+
codex: '.codex/skills/threat-modelling',
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/** Relative workspace dirs for the VibeReview markdown sync skill (per IDE / CLI). */
|
|
87
|
+
export const VIBEREVIEW_SYNC_SKILL_REL_DIR = {
|
|
88
|
+
cursor: '.cursor/skills/vibereview-sync',
|
|
89
|
+
claude: '.claude/skills/vibereview-sync',
|
|
90
|
+
vscode: '.github/skills/vibereview-sync',
|
|
91
|
+
codex: '.codex/skills/vibereview-sync',
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export const SENTINEL_START = '<!-- securityreview-kit:start -->';
|
|
95
|
+
export const SENTINEL_END = '<!-- securityreview-kit:end -->';
|