@securityreviewai/securityreview-kit 0.1.35 → 0.1.36

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 CHANGED
@@ -29,7 +29,7 @@ npx @securityreviewai/securityreview-kit init --switch-project
29
29
  |---|---|---|---|
30
30
  | Cursor | `cursor` | `.cursor/mcp.json` | `.cursor/rules/srai-security-review.mdc`, `.cursor/rules/ctm_sync_rule.mdc`, `.cursor/commands/ctm_sync.md`, `.cursor/agents/ctm_sync.md`, `.cursor/commands/create-ide-workflow.md`, `.cursor/commands/srai-profile.md`, `.cursor/skills/threat-modelling/SKILL.md` |
31
31
  | Claude Code | `claude` | `.claude/settings.json` | `CLAUDE.md` |
32
- | VS Code Copilot | `vscode` | `.vscode/mcp.json` | `.github/copilot-instructions.md`, `.github/skills/guardrails-profiler/SKILL.md`, `.github/skills/guardrails-selection/SKILL.md` |
32
+ | VS Code Copilot | `vscode` | `.vscode/mcp.json` | `.github/copilot-instructions.md`, `.github/skills/threat-modelling/SKILL.md`, `.github/skills/guardrails-profiler/SKILL.md`, `.github/skills/guardrails-selection/SKILL.md`, `.github/agents/ctm_sync.agent.md`, `.github/hooks/srai-session-policy.json` |
33
33
  | Windsurf | `windsurf` | `.windsurf/mcp_config.json` | `.windsurf/rules/srai-security-review.md` |
34
34
  | Codex | `codex` | `.codex/config.toml` | `AGENTS.md` |
35
35
  | Gemini CLI | `gemini` | `.gemini/settings.json` | `GEMINI.md` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@securityreviewai/securityreview-kit",
3
- "version": "0.1.35",
3
+ "version": "0.1.36",
4
4
  "description": "Bootstrap security-review-mcp for AI IDEs and CLI tools",
5
5
  "author": "Debarshi Das <debarshi.das@we45.com>",
6
6
  "license": "UNLICENSED",
@@ -17,7 +17,7 @@
17
17
  "node": ">=18"
18
18
  },
19
19
  "scripts": {
20
- "test": "node --test src/**/*.test.js",
20
+ "test": "node --test",
21
21
  "start": "node bin/securityreview-kit.js"
22
22
  },
23
23
  "keywords": [
@@ -44,6 +44,18 @@ function readTemplate(templateFileName, options = {}) {
44
44
  '.cursor/skills/guardrails-selection',
45
45
  options.guardrailsSelectionSkillDir,
46
46
  );
47
+ out = injectPathPlaceholder(
48
+ out,
49
+ '{{THREAT_MODELLING_SKILL_DIR}}',
50
+ '.cursor/skills/threat-modelling',
51
+ options.threatModellingSkillDir,
52
+ );
53
+ out = injectPathPlaceholder(
54
+ out,
55
+ '{{CTM_SYNC_AGENT_PATH}}',
56
+ '.cursor/agents/ctm_sync.md',
57
+ options.ctmSyncAgentPath,
58
+ );
47
59
 
48
60
  return out;
49
61
  }
@@ -1,126 +1,54 @@
1
- # Security-First Code Generation with PWNISMS Threat Modeling
2
-
3
- **THIS RULE IS NON-NEGOTIABLE AND TRIGGERED BEFORE YOU EVEN START THINKING.** You MUST think security-first and perform on-the-go threat modeling using the PWNISMS framework BEFORE and DURING every task whether it's TODO or PLAN or codegen. This is not optional. This is not deferred to a later review. Every line of code you write must be informed by threat awareness.
4
-
5
- > **Skill Reference:** Read and apply `.cursor/skills/threat-modelling/SKILL.md` for the full PWNISMS framework — the 7 threat categories, code generation rules, and post-generation checklist. You MUST walk through all 7 categories for every code task that seems security relevant.
6
- >
7
- > **Guardrail Selection Skill:** In IDEs that support workspace skills, read and apply `{{GUARDRAILS_SELECTION_SKILL_DIR}}/SKILL.md` when fetching guardrails. In other IDEs, follow that same workflow explicitly: analyze the task, shortlist relevant guardrails, and hydrate the exact shortlist with `get_guardrail_by_id`.
8
-
9
- ### When NOT to apply
10
-
11
- Skip PWNISMS, guardrails, and the MCP flow entirely for tasks that have **no security surface**:
12
-
13
- - Documentation-only changes (README, comments, changelogs)
14
- - Code formatting, linting, or style fixes
15
- - Renaming variables/files with no logic change
16
- - General Q&A, explanations, or research that produces no code
17
- - UI copy, typo fixes, or purely cosmetic changes
18
- - Adding or updating tests that don't touch auth, crypto, or input handling
19
-
20
- If in doubt, do a quick mental scan: *does this change touch auth, input handling, secrets, network, data storage, or dependencies?* If **no**, skip. If **yes** or **maybe**, apply.
21
-
22
- **MANDATORY POST THREAT MODELLING** ALWAYS invoke `ctm_sync` immediately after threat modelling is generated or updated. This is required on every threat-model run.
23
-
24
- ---
25
-
26
- ## Two pillars of security enforcement
27
-
28
- This workflow enforces security through two complementary pillars:
29
-
30
- 1. **Secure by Design (PWNISMS)** — Universal threat-category analysis applied to every security-relevant task. Identifies risks and drives architectural/design-level mitigations.
31
- 2. **Secure by Code (Vibe Guardrails)** — Project-specific coding dos and don'ts fetched from SRAI via `get_guardrails`, shortlisted intentionally, and then hydrated via `get_guardrail_by_id`. Enforces concrete implementation rules derived from prior threat reviews, compliance requirements, and team decisions.
32
-
33
- Both pillars are **mandatory** for any code-generation task with a security surface. PWNISMS catches broad threats; guardrails enforce project-specific coding standards.
34
-
35
- ---
36
-
37
- ## MCP Enhancement — `security-review-mcp`
1
+ # Security Review Kit Agent Instructions
38
2
 
39
3
  Configured SRAI project name: `<SRAI_PROJECT_NAME>`
40
4
 
41
- Assess Task Security Relevance
42
-
43
- Before any MCP call, classify the task:
44
-
45
- 1. Bug fix or refactor with no security surface change — Enrich your context with the profile exploration below, skip review tools
46
- 2. Non-security task — Skip MCP entirely
47
- 3. New feature — Start with full profile exploration, then full MCP flow
48
-
49
- When the `security-review-mcp` MCP server is available, use it to **enrich and persist** your threat analysis. This is a force multiplier on top of PWNISMS, not a replacement.
50
-
51
- ### Enriching Your Analysis — Step-by-Step Profile Exploration
52
-
53
- Rather than fetching the entire profile at once, walk through each reasoning block below **in order**. Each step builds context for the next and directly informs your PWNISMS threat modeling.
54
-
55
- 1. **Find the project** — Call `find_project_by_name` with `name="<SRAI_PROJECT_NAME>"`. If that project does not exist, call `list_projects`. If no project exists, call `create_project`.
56
-
57
- 2. **Understand what the project does** — Call `get_project_profile_description`.
58
- - Use this to frame the threat surface: what data flows exist, what the system's purpose is, and where trust boundaries lie.
59
-
60
- 3. **Discover technology categories** — Call `list_profile_technology_categories`.
61
- - This reveals the broad technology areas (e.g., frontend, backend, database, cloud). Use this to scope which PWNISMS categories are most relevant.
62
-
63
- 4. **Deep-dive each technology category** — For each category returned above, call `get_project_profile_technology_category` with the category name.
64
- - Understand specific frameworks, libraries, and versions. Flag known-vulnerable dependencies for the **Supply Chain (S)** PWNISMS category.
5
+ These instructions are always active for security-relevant coding work. Keep this file as the routing policy; use the skills and agents below for the detailed workflows.
65
6
 
66
- 5. **Review architecture notes** — Call `list_project_profile_architecture_notes`.
67
- - Identify deployment topology, trust boundaries, and data flow patterns. Feed this into **Workload (W)** and **Network (N)** analysis.
7
+ ## Core Workflow
68
8
 
69
- 6. **Identify user groups** Call `list_project_profile_user_groups`.
70
- - Map user roles and privilege levels. This directly informs **IAM (I)** and **Product (P)** threat categories.
9
+ For any task that touches auth, authorization, input handling, secrets, network, data storage, dependencies, new APIs/endpoints, infrastructure, or code handling untrusted data:
71
10
 
72
- 7. **Get language stacks** — Call `list_project_profile_language_stacks`.
73
- - Understand the language/runtime landscape for language-specific vulnerability patterns.
11
+ 1. **Fetch Vibe Guardrails first.**
12
+ - Read and follow `{{GUARDRAILS_SELECTION_SKILL_DIR}}/SKILL.md`.
13
+ - Resolve the SRAI project with `find_project_by_name` using `name="<SRAI_PROJECT_NAME>"`.
14
+ - Call `get_guardrails`, shortlist only the relevant project guardrails, then hydrate the exact shortlist with `get_guardrail_by_id`.
15
+ - Preserve that exact shortlist in context for implementation and CTM sync.
74
16
 
75
- 8. **List security controls** Call `list_project_profile_security_controls`.
76
- - Get an overview of existing defenses. For each control that is relevant to the current task, call `get_project_profile_security_control` to get full details.
77
- - Cross-reference with your PWNISMS findings: are there gaps in **Secrets (S)**, **Monitoring (M)**, or **IAM (I)**?
17
+ 2. **Run PWNISMS threat modelling before implementation.**
18
+ - Read and follow `{{THREAT_MODELLING_SKILL_DIR}}/SKILL.md`.
19
+ - Explicitly walk all seven PWNISMS categories: Product, Workload, Network, IAM, Secrets, Monitoring, and Supply Chain.
20
+ - If a category is not applicable, say so briefly and continue.
21
+ - Cross-reference each meaningful threat with the shortlisted guardrails.
78
22
 
79
- 9. **List compliance requirements** Call `list_profile_compliance_requirements`.
80
- - For each requirement relevant to the task, call `get_profile_compliance_requirement` for full details.
81
- - Map these to security objectives and ensure your implementation meets them.
23
+ 3. **Implement secure code using both inputs.**
24
+ - Treat applicable `must` guardrails as mandatory.
25
+ - Treat applicable `must_not` guardrails as hard prohibitions.
26
+ - Use the PWNISMS findings to guide design, validation, authorization, logging, secrets handling, dependency choices, and abuse controls.
27
+ - If PWNISMS reveals a recurring security rule that is not covered by existing guardrails, create and apply an `ide_generated` guardrail in context.
82
28
 
83
- 10. **Fetch Vibe Guardrails** — Follow `{{GUARDRAILS_SELECTION_SKILL_DIR}}/SKILL.md`.
84
- - Call `get_guardrails` with `project_id` to load the broad catalog.
85
- - Analyze the task and infer the relevant security categories and likely threats first.
86
- - Shortlist only the guardrails relevant to the task and fetch the exact shortlist with `get_guardrail_by_id`.
87
- - Separate the shortlisted guardrails into `must` (mandatory requirements) and `must_not` (hard prohibitions).
88
- - Keep the shortlisted exact guardrails in context for the entire code-generation task and for later `ctm_sync`.
89
- - Cross-reference with PWNISMS findings: if a threat has no corresponding guardrail, flag it as a candidate for a new guardrail.
29
+ 4. **Run CTM sync last.**
30
+ - After threat modelling is created or updated, or after guardrails are enforced during implementation, invoke the `ctm_sync` agent/workflow.
31
+ - Use `{{CTM_SYNC_AGENT_PATH}}` for the detailed payload contract.
32
+ - Pass the current threat model summary, the stable `chat_session_id`, the exact existing guardrails shortlisted earlier, and any `ide_generated` guardrails.
33
+ - Do not re-query guardrails during CTM sync; reuse the shortlist selected before implementation.
90
34
 
91
- 11. **Check for existing reviews** — Call `list_reviews`. If a completed review exists, pull context:
92
- - `get_threat_scenarios` — Cross-reference with your PWNISMS findings
93
- - `get_countermeasures` — Apply recommended mitigations
94
- - `get_components` — Understand the system architecture
95
- - `get_data_dictionaries` — Identify sensitive data assets and stepping stones
96
- - `get_security_objectives` — Understand compliance requirements
97
- - `get_findings` — Review aggregated security insights
35
+ ## When To Skip
98
36
 
99
- 12. **No review exists?** Create one:
100
- - Upload context via `create_document_from_content`
101
- - `create_review` → `start_workflow` → poll `get_workflow_status`
37
+ Skip the SRAI security workflow only for tasks with no security surface, such as documentation-only changes, typo fixes, pure formatting, variable renames with no logic change, or general Q&A that produces no code.
102
38
 
103
- 13. **After threat modeling (ALWAYS / POST threat modelling)** Invoke `ctm_sync` agent and upload the required CTM data (including guardrail compliance and proposed guardrails).
39
+ If in doubt, run the workflow. A quick PWNISMS pass is better than silently missing a security boundary.
104
40
 
105
- ### CTM sync chat session and workflows (all IDEs)
41
+ ## Do Not Use Project Profile Exploration
106
42
 
107
- When running `ctm_sync` (dedicated agent/command where available, or the same steps inline):
43
+ Do not call project-profile exploration tools during normal coding tasks. The old profile walkthrough is no longer part of the agent workflow.
108
44
 
109
- - Include a stable **`chat_session_id`** on every event payload. Reuse one id for the entire current chat; use a different id for a different chat. Prefer an IDE-provided session/conversation id; if unavailable, generate a UUID once per chat and reuse it.
110
- - **First time** a `chat_session_id` is seen for a project: create an AI IDE workflow via `create_ai_ide_workflow` with a short name `session1`, `session2`, … (next free index) and put `chat_session_id:<id>` in the workflow **description** so it can be found later.
111
- - **Same chat later:** find the workflow whose description contains that `chat_session_id` marker and push `create_ai_ide_event` to that `workflow_id` — do **not** create another workflow for the same session.
45
+ The normal coding workflow is guardrails selection, PWNISMS threat modelling, secure implementation, then CTM sync.
112
46
 
113
- ### Tool Reference
47
+ ## Tool Reference
114
48
 
115
- | Category | Tools |
49
+ | Purpose | Tools |
116
50
  |---|---|
117
- | **Projects** | `list_projects`, `find_project_by_name`, `create_project`, `get_project` |
118
- | **Profile Exploration** | `get_project_profile_description`, `list_profile_technology_categories`, `get_project_profile_technology_category`, `list_project_profile_architecture_notes`, `list_project_profile_user_groups`, `list_project_profile_language_stacks`, `list_project_profile_security_controls`, `get_project_profile_security_control`, `list_profile_compliance_requirements`, `get_profile_compliance_requirement` |
119
- | **Guardrails** | `get_guardrails`, `get_guardrail_by_id` |
120
- | **Documents** | `list_documents`, `create_document_from_content`, `upload_document`, `link_external_document` |
121
- | **Reviews** | `create_review`, `list_reviews`, `get_review`, `get_review_overview` |
122
- | **Workflow** | `start_workflow`, `get_workflow_status`, `start_next_workflow_job`, `start_workflow_job`, `retry_workflow_job` |
123
- | **Analysis** | `get_threat_scenarios`, `get_countermeasures`, `get_components`, `get_data_dictionaries`, `get_security_objectives`, `get_findings`, `get_security_test_cases` |
124
- | **Integrations** | `fetch_jira_issue`, `fetch_confluence_page`, `search_confluence_pages`, `fetch_and_link_to_srai` |
125
- | **AI IDE CTM** | `create_ai_ide_workflow`, `create_ai_ide_event` (and any `list_*` AI IDE workflow tools exposed by the server) |
126
- | **Vibe profile & default packs** | `update_vibe_profile`, `write_default_pack` (used by the guardrails profiler / init flow — not part of `ctm_sync`) |
51
+ | Project resolution | `find_project_by_name`, `list_projects`, `create_project`, `get_project` |
52
+ | Guardrails | `get_guardrails`, `get_guardrail_by_id` |
53
+ | CTM sync | `create_ai_ide_workflow`, `create_ai_ide_event`, `get_current_user` or equivalent user identity tool |
54
+ | Profiler only | `update_vibe_profile`, `write_default_pack` are used by init-time profiling, not normal coding tasks |
@@ -3,7 +3,9 @@ import { join } from 'node:path';
3
3
  import {
4
4
  GUARDRAILS_PROFILER_SKILL_REL_DIR,
5
5
  GUARDRAILS_SELECTION_SKILL_REL_DIR,
6
+ CTM_SYNC_AGENT_REL_PATH,
6
7
  MCP_SERVER_NAME,
8
+ THREAT_MODELLING_SKILL_REL_DIR,
7
9
  } from '../../utils/constants.js';
8
10
  import { readJson, writeJson, writeText } from '../../utils/fs-helpers.js';
9
11
  import {
@@ -74,6 +76,8 @@ export function generate(cwd, options = {}) {
74
76
  const optionsWithSkillDirs = {
75
77
  ...options,
76
78
  guardrailsSelectionSkillDir: GUARDRAILS_SELECTION_SKILL_REL_DIR.cursor,
79
+ threatModellingSkillDir: THREAT_MODELLING_SKILL_REL_DIR.cursor,
80
+ ctmSyncAgentPath: CTM_SYNC_AGENT_REL_PATH.cursor,
77
81
  };
78
82
  const baseRulePath = join(cwd, '.cursor', 'rules', 'srai-security-review.mdc');
79
83
  const ctmSyncTriggerRulePath = join(cwd, '.cursor', 'rules', 'ctm_sync_rule.mdc');
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: PWNISMS Threat Modelling
3
- description: Security-first threat modelling workflow for code and architecture tasks. Walks all 7 PWNISMS categories, integrates with SRAI project profiles, enforces vibe guardrails (secure by code), and synchronizes findings via CTM sync. Use before, during, and after implementation.
3
+ description: Security-first threat modelling workflow for code and architecture tasks. Walks all 7 PWNISMS categories, enforces vibe guardrails (secure by code), and synchronizes findings via CTM sync. Use before, during, and after implementation.
4
4
  ---
5
5
 
6
6
  # PWNISMS — Security-First Threat Modelling
@@ -14,28 +14,18 @@ For EVERY security-relevant task (feature, bug fix, refactor, infra change, arch
14
14
 
15
15
  ---
16
16
 
17
- ## Phase 0 — Enrich Context from SRAI
18
-
19
- Before deep analysis, pull project context from `security-review-mcp` (if available) to ground your threat model in the actual system profile.
20
-
21
- 1. **Resolve the project** — `find_project_by_name` with `name="<SRAI_PROJECT_NAME>"`.
22
- 2. **Fetch project description** `get_project_profile_description` to understand the system's purpose and data flows.
23
- 3. **Technology categories** `list_profile_technology_categories` for each, `get_project_profile_technology_category` to understand specific frameworks, libraries, versions.
24
- 4. **Architecture notes** `list_project_profile_architecture_notes` for deployment topology, trust boundaries, data flow patterns.
25
- 5. **User groups** — `list_project_profile_user_groups` to map roles and privilege levels.
26
- 6. **Language stacks** `list_project_profile_language_stacks` for language-specific vulnerability patterns.
27
- 7. **Security controls** — `list_project_profile_security_controls` → for relevant controls, `get_project_profile_security_control` for details.
28
- 8. **Compliance requirements** `list_profile_compliance_requirements` for relevant ones, `get_profile_compliance_requirement`.
29
- 9. **Existing reviews** — `list_reviews`. If a completed review exists:
30
- - `get_threat_scenarios` — prior threats to cross-reference
31
- - `get_countermeasures` — existing mitigations to leverage
32
- - `get_components` — system architecture context
33
- - `get_data_dictionaries` — sensitive data assets
34
- - `get_security_objectives` — compliance targets
35
- - `get_findings` — aggregated insights
36
- 10. **Vibe Guardrails** — Use `{{GUARDRAILS_SELECTION_SKILL_DIR}}/SKILL.md` with `project_id` to load the guardrail catalog, shortlist the relevant guardrails, and hydrate the exact implementation set with `get_guardrail_by_id`.
37
-
38
- If SRAI is not available, proceed with whatever context the user provides — files, diffs, PRs, architecture docs.
17
+ ## Phase 0 — Guardrail Context
18
+
19
+ Before deep analysis, ensure the project-specific guardrail shortlist exists:
20
+
21
+ 1. Use `{{GUARDRAILS_SELECTION_SKILL_DIR}}/SKILL.md`.
22
+ 2. Resolve the project with `find_project_by_name` using `name="<SRAI_PROJECT_NAME>"`.
23
+ 3. Call `get_guardrails`, shortlist intentionally for this task, then hydrate the exact shortlist with `get_guardrail_by_id`.
24
+ 4. Keep the shortlisted existing guardrails in context for implementation and `ctm_sync`.
25
+
26
+ Do not perform project-profile exploration as part of PWNISMS. The old profile tools are not part of this workflow. Ground the threat model in the user request, repository code, diffs, architecture docs the user provides, and the shortlisted guardrails.
27
+
28
+ If SRAI is not available, proceed with the user-provided context and repository evidence, then clearly note that project guardrails could not be fetched.
39
29
 
40
30
  ---
41
31
 
@@ -47,7 +37,7 @@ Collect these quickly before deep analysis:
47
37
  - **Assets**: What must be protected (PII, credentials, tokens, configs, accounts, workflows)?
48
38
  - **Entry points**: How data enters/leaves (HTTP, queues, schedulers, CLI, webhooks, integrations)?
49
39
  - **Trust boundaries**: Where data crosses users/services/networks/privilege levels?
50
- - **Existing guardrails**: What shortlisted project-specific dos and don'ts apply (from Phase 0, step 10)?
40
+ - **Existing guardrails**: What shortlisted project-specific dos and don'ts apply (from Phase 0)?
51
41
 
52
42
  If the user provided specific code, diffs, or architecture artifacts, prioritize those as primary evidence.
53
43
 
@@ -71,7 +61,7 @@ If the user provided specific code, diffs, or architecture artifacts, prioritize
71
61
 
72
62
  4. **Prioritize**
73
63
  - Select the top 3-7 risks by impact and likelihood.
74
- - Factor in existing mitigations from SRAI countermeasures and guardrails.
64
+ - Factor in existing mitigations from the codebase, user-provided context, and guardrails.
75
65
 
76
66
  5. **Mitigate**
77
67
  - Propose concrete, implementable controls for each prioritized risk.
@@ -225,16 +215,15 @@ The `ctm_sync` agent builds and pushes an event payload containing:
225
215
  - **Best practices achieved**: security patterns followed during implementation
226
216
  - **Secure code snippets**: security-relevant code with explanations
227
217
  - **Guardrails applied**: all guardrails enforced during this session — both existing ones shortlisted earlier via `get_guardrails` + `get_guardrail_by_id` (`source: "existing"`) and new ones the IDE agent created on the fly (`source: "ide_generated"`), each with satisfaction status
228
- - **Project profile updates**: architecture notes, tech categories, user groups, compliance requirements, language stacks
229
218
 
230
219
  ### How to invoke
231
220
 
232
- Use the `ctm_sync` agent (Task tool with `subagent_type="ctm_sync"`) with:
221
+ Use the host's `ctm_sync` agent/workflow with:
233
222
  - A clear description of what was threat-modeled
234
223
  - The `chat_session_id` for workflow routing
235
224
  - Whether this is a new threat model or an update
236
225
 
237
- See `.cursor/agents/ctm_sync.md` (or `.cursor/commands/ctm_sync.md`) for the full workflow and payload schema.
226
+ See `{{CTM_SYNC_AGENT_PATH}}` for the full workflow and payload schema.
238
227
 
239
228
  ---
240
229
 
@@ -1,17 +1,90 @@
1
+ import { existsSync } from 'node:fs';
1
2
  import { join } from 'node:path';
2
- import { GUARDRAILS_SELECTION_SKILL_REL_DIR } from '../../utils/constants.js';
3
- import { upsertSentinelBlock } from '../../utils/fs-helpers.js';
4
- import { getRuleContent } from './content.js';
3
+ import {
4
+ CTM_SYNC_AGENT_REL_PATH,
5
+ GUARDRAILS_SELECTION_SKILL_REL_DIR,
6
+ THREAT_MODELLING_SKILL_REL_DIR,
7
+ } from '../../utils/constants.js';
8
+ import { upsertSentinelBlock, writeText } from '../../utils/fs-helpers.js';
9
+ import { getCtmSyncWorkflowContent, getRuleContent, getThreatModellingSkillContent } 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 getCopilotSessionHookContent() {
18
+ const additionalContext = [
19
+ '## MANDATORY SECURITY GATE (Session Policy)',
20
+ '',
21
+ '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:',
22
+ '',
23
+ '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.',
24
+ '2. Run PWNISMS threat modelling using .github/skills/threat-modelling/SKILL.md. Explicitly walk Product, Workload, Network, IAM, Secrets, Monitoring, and Supply Chain.',
25
+ '3. Implement secure code using both the hydrated guardrails and PWNISMS findings.',
26
+ '4. Run the ctm_sync custom agent using .github/agents/ctm_sync.agent.md after threat modelling or guardrail enforcement. Reuse the exact guardrail shortlist; do not re-query guardrails during CTM sync.',
27
+ '',
28
+ 'Do not use project-profile exploration tools during normal coding tasks. No blocking and no deferral: guardrails first, PWNISMS second, implementation third, ctm_sync last.',
29
+ ].join('\n');
30
+
31
+ const commandPayload = JSON.stringify({
32
+ hookSpecificOutput: {
33
+ hookEventName: 'SessionStart',
34
+ additionalContext,
35
+ },
36
+ });
37
+
38
+ return JSON.stringify(
39
+ {
40
+ hooks: {
41
+ SessionStart: [
42
+ {
43
+ type: 'command',
44
+ command: `printf '%s\\n' '${commandPayload.replaceAll("'", "'\\''")}'`,
45
+ timeout: 5,
46
+ },
47
+ ],
48
+ },
49
+ },
50
+ null,
51
+ 2,
52
+ ) + '\n';
53
+ }
5
54
 
6
55
  /**
7
56
  * Generate VS Code Copilot instructions — appends to .github/copilot-instructions.md
8
57
  */
9
58
  export function generate(cwd, options = {}) {
10
- const filePath = join(cwd, '.github', 'copilot-instructions.md');
11
- const content = getRuleContent({
59
+ const optionsWithSkillDirs = {
12
60
  ...options,
13
61
  guardrailsSelectionSkillDir: GUARDRAILS_SELECTION_SKILL_REL_DIR.vscode,
14
- });
62
+ threatModellingSkillDir: THREAT_MODELLING_SKILL_REL_DIR.vscode,
63
+ ctmSyncAgentPath: CTM_SYNC_AGENT_REL_PATH.vscode,
64
+ };
65
+ const filePath = join(cwd, '.github', 'copilot-instructions.md');
66
+ const content = getRuleContent(optionsWithSkillDirs);
15
67
  const action = upsertSentinelBlock(filePath, content);
16
- return { filePath, action };
68
+
69
+ const threatSkillPath = join(cwd, THREAT_MODELLING_SKILL_REL_DIR.vscode, 'SKILL.md');
70
+ const threatSkill = writeGeneratedText(
71
+ threatSkillPath,
72
+ getThreatModellingSkillContent(optionsWithSkillDirs),
73
+ );
74
+
75
+ const ctmSyncAgentPath = join(cwd, CTM_SYNC_AGENT_REL_PATH.vscode);
76
+ const ctmSyncAgent = writeGeneratedText(
77
+ ctmSyncAgentPath,
78
+ getCtmSyncWorkflowContent(optionsWithSkillDirs),
79
+ );
80
+
81
+ const hooksPath = join(cwd, '.github', 'hooks', 'srai-session-policy.json');
82
+ const hooks = writeGeneratedText(hooksPath, getCopilotSessionHookContent());
83
+
84
+ return [
85
+ { filePath, action, kind: 'rule' },
86
+ { ...threatSkill, kind: 'skill' },
87
+ { ...ctmSyncAgent, kind: 'agent' },
88
+ { ...hooks, kind: 'hooks' },
89
+ ];
17
90
  }
@@ -0,0 +1,41 @@
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, agent, 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/agents/ctm_sync.agent.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', 'agent', '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\/agents\/ctm_sync\.agent\.md/);
30
+ assert.doesNotMatch(instructions, /\.cursor/);
31
+
32
+ const threatSkill = readFileSync(join(cwd, '.github/skills/threat-modelling/SKILL.md'), 'utf8');
33
+ for (const heading of ['Product', 'Workload', 'Network', 'IAM', 'Secrets', 'Monitoring', 'Supply Chain']) {
34
+ assert.match(threatSkill, new RegExp(heading));
35
+ }
36
+ assert.match(threatSkill, /\.github\/agents\/ctm_sync\.agent\.md/);
37
+ assert.doesNotMatch(threatSkill, /get_project_profile_description/);
38
+
39
+ const hooks = JSON.parse(readFileSync(join(cwd, '.github/hooks/srai-session-policy.json'), 'utf8'));
40
+ assert.equal(hooks.hooks.SessionStart[0].type, 'command');
41
+ });
@@ -75,5 +75,17 @@ export const GUARDRAILS_SELECTION_SKILL_REL_DIR = {
75
75
  codex: '.codex/skills/guardrails-selection',
76
76
  };
77
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
+ vscode: '.github/skills/threat-modelling',
82
+ };
83
+
84
+ /** Relative workspace paths for the CTM sync agent/workflow (per IDE / CLI). */
85
+ export const CTM_SYNC_AGENT_REL_PATH = {
86
+ cursor: '.cursor/agents/ctm_sync.md',
87
+ vscode: '.github/agents/ctm_sync.agent.md',
88
+ };
89
+
78
90
  export const SENTINEL_START = '<!-- securityreview-kit:start -->';
79
91
  export const SENTINEL_END = '<!-- securityreview-kit:end -->';