secure-coding-rules 2.0.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.
- package/LICENSE +21 -0
- package/README.md +168 -0
- package/bin/cli.js +8 -0
- package/package.json +64 -0
- package/src/adapters/agents.js +54 -0
- package/src/adapters/claude.js +88 -0
- package/src/adapters/copilot.js +82 -0
- package/src/adapters/cursor.js +68 -0
- package/src/adapters/windsurf.js +57 -0
- package/src/index.js +177 -0
- package/src/loader.js +85 -0
- package/src/prompts.js +307 -0
- package/src/templates/core/access-control.md +112 -0
- package/src/templates/core/authentication.md +138 -0
- package/src/templates/core/cryptographic.md +114 -0
- package/src/templates/core/data-integrity.md +144 -0
- package/src/templates/core/error-handling.md +180 -0
- package/src/templates/core/injection.md +125 -0
- package/src/templates/core/logging-alerting.md +156 -0
- package/src/templates/core/secure-design.md +117 -0
- package/src/templates/core/security-config.md +118 -0
- package/src/templates/core/supply-chain.md +127 -0
- package/src/templates/frontend/csp.md +146 -0
- package/src/templates/frontend/csrf-protection.md +151 -0
- package/src/templates/frontend/secure-state.md +167 -0
- package/src/templates/frontend/xss-prevention.md +125 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 곽성재 (Gwak Seong-jae)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# secure-coding-rules
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/secure-coding-rules)
|
|
4
|
+
[](https://github.com/user/secure-coding-rules/blob/main/LICENSE)
|
|
5
|
+
[](https://nodejs.org)
|
|
6
|
+
|
|
7
|
+
**OWASP Top 10 2025** 기반 JavaScript/TypeScript 보안 코딩 룰을 AI 코딩 어시스턴트에 자동 적용하는 CLI 도구입니다.
|
|
8
|
+
|
|
9
|
+
`npx secure-coding-rules` 한 줄이면 프로젝트의 CLAUDE.md, .cursor/rules, .windsurf/rules, copilot-instructions.md, AGENTS.md에 보안 룰이 적용됩니다.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx secure-coding-rules
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
인터랙티브 프롬프트:
|
|
20
|
+
1. AI 도구 선택 (Claude Code / Cursor / Windsurf / Copilot / AGENTS.md)
|
|
21
|
+
2. 프레임워크 선택 (React / Vue / Node.js / Vanilla) - **자동 감지됨**
|
|
22
|
+
3. 보안 카테고리 선택 (전체 또는 개별)
|
|
23
|
+
|
|
24
|
+
### Auto Mode
|
|
25
|
+
|
|
26
|
+
프로젝트를 분석하여 자동으로 최적의 설정을 적용합니다:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx secure-coding-rules --yes
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- 기존 AI 도구 설정 파일이 있으면 자동 감지 후 업데이트
|
|
33
|
+
- package.json에서 프레임워크 자동 감지 (React, Vue, Node.js 등)
|
|
34
|
+
- CI/CD 등 non-interactive 환경에서도 동작
|
|
35
|
+
|
|
36
|
+
### Status Check
|
|
37
|
+
|
|
38
|
+
현재 프로젝트의 보안 룰 상태만 확인:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx secure-coding-rules --check
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 지원 AI 도구
|
|
45
|
+
|
|
46
|
+
| AI Tool | Output | 기존 파일 |
|
|
47
|
+
|---------|--------|----------|
|
|
48
|
+
| **Claude Code** | `CLAUDE.md` | 자동 병합 |
|
|
49
|
+
| **Cursor** | `.cursor/rules/*.mdc` | 개별 파일 생성 |
|
|
50
|
+
| **Windsurf** | `.windsurf/rules/*.md` | 개별 파일 생성 |
|
|
51
|
+
| **GitHub Copilot** | `.github/copilot-instructions.md` | 자동 병합 |
|
|
52
|
+
| **AGENTS.md** | `AGENTS.md` | 자동 병합 |
|
|
53
|
+
|
|
54
|
+
## 보안 카테고리 (OWASP Top 10 2025)
|
|
55
|
+
|
|
56
|
+
| Code | Category | Description |
|
|
57
|
+
|------|----------|-------------|
|
|
58
|
+
| A01 | Broken Access Control | RBAC/ABAC, IDOR 방지, 서버사이드 인가 |
|
|
59
|
+
| A02 | Security Misconfiguration | 보안 헤더, CORS, 환경변수 관리 |
|
|
60
|
+
| A03 | Supply Chain Failures | npm audit, lockfile 무결성, SRI **(2025 신규)** |
|
|
61
|
+
| A04 | Cryptographic Failures | 안전한 해싱, 암호화, 키 관리 |
|
|
62
|
+
| A05 | Injection | XSS, SQLi, NoSQLi, Command Injection |
|
|
63
|
+
| A06 | Insecure Design | Threat modeling, 최소 권한 원칙 |
|
|
64
|
+
| A07 | Authentication Failures | MFA, 세션 관리, 패스워드 정책 |
|
|
65
|
+
| A08 | Data Integrity Failures | SRI, 안전한 역직렬화, CI/CD 보안 |
|
|
66
|
+
| A09 | Logging & Alerting | 보안 로깅, 민감정보 마스킹, 알림 |
|
|
67
|
+
| A10 | Error Handling | Fail-safe 기본값, 에러 정보 노출 방지 **(2025 신규)** |
|
|
68
|
+
|
|
69
|
+
### Frontend Modules
|
|
70
|
+
|
|
71
|
+
| Code | Category | Description |
|
|
72
|
+
|------|----------|-------------|
|
|
73
|
+
| FE-01 | XSS Prevention | DOM 조작 보안, sanitization |
|
|
74
|
+
| FE-02 | CSRF Protection | 토큰 기반 방어, SameSite 쿠키 |
|
|
75
|
+
| FE-03 | Content Security Policy | CSP 헤더, nonce, 리포팅 |
|
|
76
|
+
| FE-04 | Secure State | 안전한 상태관리, 메모리 내 토큰 |
|
|
77
|
+
|
|
78
|
+
## 동작 방식
|
|
79
|
+
|
|
80
|
+
### 룰 형식
|
|
81
|
+
|
|
82
|
+
모든 보안 룰은 AI가 이해하기 쉬운 일관된 구조를 따릅니다:
|
|
83
|
+
|
|
84
|
+
```markdown
|
|
85
|
+
### 1. Rule Title
|
|
86
|
+
- **DO**: 구체적으로 해야 할 것
|
|
87
|
+
- **DON'T**: 하지 말아야 할 것
|
|
88
|
+
- **WHY**: 왜 중요한지
|
|
89
|
+
|
|
90
|
+
## Code Examples
|
|
91
|
+
### Bad Practice / Good Practice
|
|
92
|
+
|
|
93
|
+
## Quick Checklist
|
|
94
|
+
- [ ] 체크리스트 항목
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 기존 파일 병합
|
|
98
|
+
|
|
99
|
+
이미 CLAUDE.md 등이 있으면 기존 내용을 보존하고 보안 섹션만 추가/업데이트합니다:
|
|
100
|
+
|
|
101
|
+
```html
|
|
102
|
+
<!-- js-secure-coding:start -->
|
|
103
|
+
(이 영역만 업데이트됨)
|
|
104
|
+
<!-- js-secure-coding:end -->
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
다시 실행하면 해당 영역만 최신 버전으로 교체됩니다.
|
|
108
|
+
|
|
109
|
+
### 프로젝트 자동 감지
|
|
110
|
+
|
|
111
|
+
`secure-coding-rules`는 실행 시 현재 프로젝트를 분석합니다:
|
|
112
|
+
|
|
113
|
+
- **AI 도구 감지**: CLAUDE.md, .cursor/, .windsurf/, .github/ 존재 여부 확인
|
|
114
|
+
- **프레임워크 감지**: package.json의 dependencies에서 React/Vue/Express 등 파악
|
|
115
|
+
- **상태 표시**: 인터랙티브 모드에서 감지 결과를 보여주고, 관련 항목을 우선 추천
|
|
116
|
+
|
|
117
|
+
## 수동 사용
|
|
118
|
+
|
|
119
|
+
CLI 없이 `src/templates/` 마크다운 파일을 직접 복사하여 사용 가능합니다:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
src/templates/
|
|
123
|
+
├── core/ # OWASP Top 10 2025 (A01-A10)
|
|
124
|
+
│ ├── access-control.md
|
|
125
|
+
│ ├── authentication.md
|
|
126
|
+
│ ├── cryptographic.md
|
|
127
|
+
│ ├── data-integrity.md
|
|
128
|
+
│ ├── error-handling.md
|
|
129
|
+
│ ├── injection.md
|
|
130
|
+
│ ├── logging-alerting.md
|
|
131
|
+
│ ├── secure-design.md
|
|
132
|
+
│ ├── security-config.md
|
|
133
|
+
│ └── supply-chain.md
|
|
134
|
+
└── frontend/ # Frontend 특화 보안 룰
|
|
135
|
+
├── xss-prevention.md
|
|
136
|
+
├── csrf-protection.md
|
|
137
|
+
├── csp.md
|
|
138
|
+
└── secure-state.md
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## CLI Options
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
npx secure-coding-rules 인터랙티브 모드 (자동 감지)
|
|
145
|
+
npx secure-coding-rules --yes 스마트 기본값으로 자동 적용
|
|
146
|
+
npx secure-coding-rules --check 프로젝트 보안 상태 확인
|
|
147
|
+
npx secure-coding-rules --help 도움말
|
|
148
|
+
npx secure-coding-rules --version 버전
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Legacy Templates
|
|
152
|
+
|
|
153
|
+
v1.0 원본 템플릿은 `legacy/` 디렉토리에 보존되어 있습니다.
|
|
154
|
+
|
|
155
|
+
## 참고 자료
|
|
156
|
+
|
|
157
|
+
- [OWASP Top 10 2025](https://owasp.org/Top10/2025/)
|
|
158
|
+
- [Node.js Security Best Practices](https://nodejs.org/en/learn/getting-started/security-best-practices)
|
|
159
|
+
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/IndexTopTen.html)
|
|
160
|
+
- [JavaScript Secure Coding Guide (KISA)](https://www.kisa.or.kr/2060204/form?postSeq=14&page=1)
|
|
161
|
+
|
|
162
|
+
## Contributing
|
|
163
|
+
|
|
164
|
+
PR을 환영합니다! 새로운 보안 룰, AI 도구 어댑터, 기존 내용 개선 등.
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
[MIT](LICENSE) - 곽성재 (Gwak Seong-jae)
|
package/bin/cli.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "secure-coding-rules",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "OWASP 2025 security rules for AI coding assistants. Auto-apply to CLAUDE.md, Cursor, Windsurf, Copilot, AGENTS.md with one command.",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./src/index.js",
|
|
8
|
+
"./loader": "./src/loader.js"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"secure-coding-rules": "bin/cli.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"bin/",
|
|
15
|
+
"src/",
|
|
16
|
+
"LICENSE",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"start": "node bin/cli.js",
|
|
21
|
+
"test": "node --test src/__tests__/*.test.js"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"security",
|
|
25
|
+
"owasp",
|
|
26
|
+
"owasp-top-10",
|
|
27
|
+
"secure-coding",
|
|
28
|
+
"javascript",
|
|
29
|
+
"typescript",
|
|
30
|
+
"claude",
|
|
31
|
+
"claude-md",
|
|
32
|
+
"cursor",
|
|
33
|
+
"cursorrules",
|
|
34
|
+
"windsurf",
|
|
35
|
+
"copilot",
|
|
36
|
+
"agents-md",
|
|
37
|
+
"ai-coding",
|
|
38
|
+
"code-security",
|
|
39
|
+
"security-rules",
|
|
40
|
+
"xss",
|
|
41
|
+
"csrf",
|
|
42
|
+
"injection",
|
|
43
|
+
"access-control"
|
|
44
|
+
],
|
|
45
|
+
"author": {
|
|
46
|
+
"name": "Gwak Seong-jae",
|
|
47
|
+
"url": "https://github.com/user"
|
|
48
|
+
},
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "git+https://github.com/user/secure-coding-rules.git"
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://github.com/user/secure-coding-rules#readme",
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/user/secure-coding-rules/issues"
|
|
57
|
+
},
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=18.0.0"
|
|
60
|
+
},
|
|
61
|
+
"type": "module",
|
|
62
|
+
"dependencies": {},
|
|
63
|
+
"devDependencies": {}
|
|
64
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AGENTS.md adapter - vendor-neutral format
|
|
3
|
+
* Compatible with Sourcegraph Amp and other tools that support AGENTS.md
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { getCategoryInfo } from '../loader.js';
|
|
7
|
+
|
|
8
|
+
export const name = 'AGENTS.md (Vendor-neutral)';
|
|
9
|
+
export const outputPath = 'AGENTS.md';
|
|
10
|
+
export const description = 'Generates AGENTS.md (vendor-neutral AI assistant rules)';
|
|
11
|
+
|
|
12
|
+
const SECTION_START = '<!-- js-secure-coding:start -->';
|
|
13
|
+
const SECTION_END = '<!-- js-secure-coding:end -->';
|
|
14
|
+
|
|
15
|
+
export function format(templates, options = {}) {
|
|
16
|
+
const { framework = 'vanilla' } = options;
|
|
17
|
+
const lines = [];
|
|
18
|
+
|
|
19
|
+
lines.push(SECTION_START);
|
|
20
|
+
lines.push('<!-- version: 2.0.0 -->');
|
|
21
|
+
lines.push('');
|
|
22
|
+
lines.push('# Security Guidelines');
|
|
23
|
+
lines.push('');
|
|
24
|
+
lines.push('Based on OWASP Top 10 2025. Follow these rules when writing or modifying JavaScript/TypeScript code.');
|
|
25
|
+
lines.push(`Framework context: ${framework}`);
|
|
26
|
+
lines.push('');
|
|
27
|
+
|
|
28
|
+
for (const [category, content] of templates) {
|
|
29
|
+
const info = getCategoryInfo(category);
|
|
30
|
+
lines.push(`## ${info.owasp}: ${info.title}`);
|
|
31
|
+
lines.push('');
|
|
32
|
+
lines.push(content.replace(/^# .+\n+(?:>.*\n+)*/, ''));
|
|
33
|
+
lines.push('');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
lines.push(SECTION_END);
|
|
37
|
+
|
|
38
|
+
return lines.join('\n');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function merge(existingContent, newSection) {
|
|
42
|
+
if (existingContent.includes(SECTION_START)) {
|
|
43
|
+
const before = existingContent.substring(
|
|
44
|
+
0,
|
|
45
|
+
existingContent.indexOf(SECTION_START)
|
|
46
|
+
);
|
|
47
|
+
const after = existingContent.substring(
|
|
48
|
+
existingContent.indexOf(SECTION_END) + SECTION_END.length
|
|
49
|
+
);
|
|
50
|
+
return before.trimEnd() + '\n\n' + newSection + '\n' + after.trimStart();
|
|
51
|
+
}
|
|
52
|
+
const trimmed = existingContent.trimEnd();
|
|
53
|
+
return (trimmed ? trimmed + '\n\n' : '') + newSection + '\n';
|
|
54
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code adapter - generates CLAUDE.md format
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getCategoryInfo } from '../loader.js';
|
|
6
|
+
|
|
7
|
+
export const name = 'Claude Code';
|
|
8
|
+
export const outputPath = 'CLAUDE.md';
|
|
9
|
+
export const description = 'Generates CLAUDE.md for Claude Code';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Check if an existing CLAUDE.md has a security section
|
|
13
|
+
*/
|
|
14
|
+
const SECTION_START = '<!-- js-secure-coding:start -->';
|
|
15
|
+
const SECTION_END = '<!-- js-secure-coding:end -->';
|
|
16
|
+
|
|
17
|
+
export function format(templates, options = {}) {
|
|
18
|
+
const { framework = 'vanilla' } = options;
|
|
19
|
+
const lines = [];
|
|
20
|
+
|
|
21
|
+
lines.push(SECTION_START);
|
|
22
|
+
lines.push('<!-- version: 2.0.0 -->');
|
|
23
|
+
lines.push('');
|
|
24
|
+
lines.push('# Security Rules (OWASP 2025)');
|
|
25
|
+
lines.push('');
|
|
26
|
+
lines.push(`> Auto-generated by js-secure-coding v2.0 | Framework: ${framework}`);
|
|
27
|
+
lines.push('> Reference: https://owasp.org/Top10/2025/');
|
|
28
|
+
lines.push('');
|
|
29
|
+
|
|
30
|
+
for (const [category, content] of templates) {
|
|
31
|
+
const info = getCategoryInfo(category);
|
|
32
|
+
lines.push(`## ${info.owasp}: ${info.title}`);
|
|
33
|
+
lines.push('');
|
|
34
|
+
// Extract just the Rules and Quick Checklist sections for conciseness
|
|
35
|
+
lines.push(extractEssentials(content));
|
|
36
|
+
lines.push('');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
lines.push(SECTION_END);
|
|
40
|
+
|
|
41
|
+
return lines.join('\n');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Merge security rules into existing CLAUDE.md content
|
|
46
|
+
*/
|
|
47
|
+
export function merge(existingContent, newSection) {
|
|
48
|
+
if (existingContent.includes(SECTION_START)) {
|
|
49
|
+
// Replace existing section
|
|
50
|
+
const before = existingContent.substring(
|
|
51
|
+
0,
|
|
52
|
+
existingContent.indexOf(SECTION_START)
|
|
53
|
+
);
|
|
54
|
+
const after = existingContent.substring(
|
|
55
|
+
existingContent.indexOf(SECTION_END) + SECTION_END.length
|
|
56
|
+
);
|
|
57
|
+
return before.trimEnd() + '\n\n' + newSection + '\n' + after.trimStart();
|
|
58
|
+
}
|
|
59
|
+
// Append to end
|
|
60
|
+
const trimmed = existingContent.trimEnd();
|
|
61
|
+
return (trimmed ? trimmed + '\n\n' : '') + newSection + '\n';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function extractEssentials(content) {
|
|
65
|
+
const lines = content.split('\n');
|
|
66
|
+
const result = [];
|
|
67
|
+
let inRules = false;
|
|
68
|
+
let inChecklist = false;
|
|
69
|
+
|
|
70
|
+
for (const line of lines) {
|
|
71
|
+
if (line.startsWith('## Rules') || line.startsWith('## Quick Checklist')) {
|
|
72
|
+
inRules = line.startsWith('## Rules');
|
|
73
|
+
inChecklist = line.startsWith('## Quick Checklist');
|
|
74
|
+
result.push(line);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (line.startsWith('## ') && (inRules || inChecklist)) {
|
|
78
|
+
inRules = false;
|
|
79
|
+
inChecklist = false;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (inRules || inChecklist) {
|
|
83
|
+
result.push(line);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return result.join('\n').trim();
|
|
88
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Copilot adapter - generates .github/copilot-instructions.md
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getCategoryInfo } from '../loader.js';
|
|
6
|
+
|
|
7
|
+
export const name = 'GitHub Copilot';
|
|
8
|
+
export const outputPath = '.github/copilot-instructions.md';
|
|
9
|
+
export const description = 'Generates .github/copilot-instructions.md';
|
|
10
|
+
|
|
11
|
+
const SECTION_START = '<!-- js-secure-coding:start -->';
|
|
12
|
+
const SECTION_END = '<!-- js-secure-coding:end -->';
|
|
13
|
+
|
|
14
|
+
export function format(templates, options = {}) {
|
|
15
|
+
const { framework = 'vanilla' } = options;
|
|
16
|
+
const lines = [];
|
|
17
|
+
|
|
18
|
+
lines.push(SECTION_START);
|
|
19
|
+
lines.push('<!-- version: 2.0.0 -->');
|
|
20
|
+
lines.push('');
|
|
21
|
+
lines.push('## Security Coding Guidelines (OWASP 2025)');
|
|
22
|
+
lines.push('');
|
|
23
|
+
lines.push(
|
|
24
|
+
'When writing or reviewing JavaScript/TypeScript code, follow these security rules:'
|
|
25
|
+
);
|
|
26
|
+
lines.push('');
|
|
27
|
+
|
|
28
|
+
for (const [category, content] of templates) {
|
|
29
|
+
const info = getCategoryInfo(category);
|
|
30
|
+
// Copilot instructions should be concise - extract rules only
|
|
31
|
+
lines.push(`### ${info.owasp}: ${info.title}`);
|
|
32
|
+
lines.push('');
|
|
33
|
+
lines.push(extractRulesOnly(content));
|
|
34
|
+
lines.push('');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
lines.push(SECTION_END);
|
|
38
|
+
|
|
39
|
+
return lines.join('\n');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function merge(existingContent, newSection) {
|
|
43
|
+
if (existingContent.includes(SECTION_START)) {
|
|
44
|
+
const before = existingContent.substring(
|
|
45
|
+
0,
|
|
46
|
+
existingContent.indexOf(SECTION_START)
|
|
47
|
+
);
|
|
48
|
+
const after = existingContent.substring(
|
|
49
|
+
existingContent.indexOf(SECTION_END) + SECTION_END.length
|
|
50
|
+
);
|
|
51
|
+
return before.trimEnd() + '\n\n' + newSection + '\n' + after.trimStart();
|
|
52
|
+
}
|
|
53
|
+
const trimmed = existingContent.trimEnd();
|
|
54
|
+
return (trimmed ? trimmed + '\n\n' : '') + newSection + '\n';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function extractRulesOnly(content) {
|
|
58
|
+
const lines = content.split('\n');
|
|
59
|
+
const result = [];
|
|
60
|
+
let inRules = false;
|
|
61
|
+
|
|
62
|
+
for (const line of lines) {
|
|
63
|
+
if (line.startsWith('## Rules')) {
|
|
64
|
+
inRules = true;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (line.startsWith('## ') && inRules) {
|
|
68
|
+
inRules = false;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (inRules) {
|
|
72
|
+
// Convert ### to bullet points for Copilot's flatter format
|
|
73
|
+
if (line.startsWith('### ')) {
|
|
74
|
+
result.push(`- **${line.replace('### ', '').replace(/^\d+\.\s*/, '')}**`);
|
|
75
|
+
} else if (line.startsWith('- **DO') || line.startsWith('- **DON\'T') || line.startsWith('- **WHY')) {
|
|
76
|
+
result.push(` ${line}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return result.join('\n').trim();
|
|
82
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor adapter - generates .cursor/rules/*.mdc format
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getCategoryInfo } from '../loader.js';
|
|
6
|
+
|
|
7
|
+
export const name = 'Cursor';
|
|
8
|
+
export const outputDir = '.cursor/rules';
|
|
9
|
+
export const description = 'Generates .cursor/rules/*.mdc files';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Format templates into individual .mdc files
|
|
13
|
+
* Returns Map<filename, content>
|
|
14
|
+
*/
|
|
15
|
+
export function formatMultiple(templates, options = {}) {
|
|
16
|
+
const files = new Map();
|
|
17
|
+
|
|
18
|
+
for (const [category, content] of templates) {
|
|
19
|
+
const info = getCategoryInfo(category);
|
|
20
|
+
const filename = `security-${category}.mdc`;
|
|
21
|
+
const mdc = formatMdc(category, content, info, options);
|
|
22
|
+
files.set(filename, mdc);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return files;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Format a single template into .mdc format
|
|
30
|
+
* MDC files have frontmatter with description and globs
|
|
31
|
+
*/
|
|
32
|
+
function formatMdc(category, content, info, options = {}) {
|
|
33
|
+
const { framework = 'vanilla' } = options;
|
|
34
|
+
|
|
35
|
+
const globs = getGlobsForCategory(category, framework);
|
|
36
|
+
const lines = [];
|
|
37
|
+
|
|
38
|
+
lines.push('---');
|
|
39
|
+
lines.push(`description: "${info.owasp} ${info.title} - OWASP 2025 Security Rules"`);
|
|
40
|
+
if (globs) {
|
|
41
|
+
lines.push(`globs: "${globs}"`);
|
|
42
|
+
}
|
|
43
|
+
lines.push('---');
|
|
44
|
+
lines.push('');
|
|
45
|
+
lines.push(content);
|
|
46
|
+
|
|
47
|
+
return lines.join('\n');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function getGlobsForCategory(category, framework) {
|
|
51
|
+
const isReact = ['react', 'next', 'nextjs'].includes(framework);
|
|
52
|
+
const codeExts = isReact ? '{jsx,tsx,js,ts}' : '{js,ts,jsx,tsx}';
|
|
53
|
+
|
|
54
|
+
const globMap = {
|
|
55
|
+
'authentication': `**/{auth,login,signup,session}*.${codeExts}`,
|
|
56
|
+
'access-control': `**/{middleware,guard,policy,permission,role}*.${codeExts}`,
|
|
57
|
+
'injection': `**/{api,route,handler,query,db}*.${codeExts}`,
|
|
58
|
+
'cryptographic': `**/{crypto,hash,encrypt,token,secret}*.${codeExts}`,
|
|
59
|
+
'xss-prevention': isReact ? '**/*.{jsx,tsx}' : '**/*.{jsx,tsx,vue,svelte}',
|
|
60
|
+
'csrf-protection': `**/{form,api,fetch,request}*.${codeExts}`,
|
|
61
|
+
'csp': '**/{middleware,header,config,server}*.{js,ts}',
|
|
62
|
+
'secure-state': `**/{store,context,state,reducer}*.${codeExts}`,
|
|
63
|
+
'supply-chain': '**/package.json',
|
|
64
|
+
'logging-alerting': '**/{log,logger,monitor,alert}*.{js,ts}',
|
|
65
|
+
'error-handling': `**/{error,handler,middleware,catch}*.${codeExts}`,
|
|
66
|
+
};
|
|
67
|
+
return globMap[category] || null;
|
|
68
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windsurf adapter - generates .windsurf/rules/*.md format
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getCategoryInfo } from '../loader.js';
|
|
6
|
+
|
|
7
|
+
export const name = 'Windsurf';
|
|
8
|
+
export const outputDir = '.windsurf/rules';
|
|
9
|
+
export const description = 'Generates .windsurf/rules/*.md files';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Format templates into individual .md files for Windsurf
|
|
13
|
+
* Returns Map<filename, content>
|
|
14
|
+
*/
|
|
15
|
+
export function formatMultiple(templates, options = {}) {
|
|
16
|
+
const files = new Map();
|
|
17
|
+
|
|
18
|
+
for (const [category, content] of templates) {
|
|
19
|
+
const info = getCategoryInfo(category);
|
|
20
|
+
const filename = `security-${category}.md`;
|
|
21
|
+
const formatted = formatWindsurfRule(category, content, info, options);
|
|
22
|
+
files.set(filename, formatted);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return files;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function formatWindsurfRule(category, content, info, options = {}) {
|
|
29
|
+
const { framework = 'vanilla' } = options;
|
|
30
|
+
const lines = [];
|
|
31
|
+
|
|
32
|
+
lines.push(`# ${info.owasp}: ${info.title}`);
|
|
33
|
+
lines.push('');
|
|
34
|
+
lines.push(`> OWASP 2025 Security Rule | Framework: ${framework}`);
|
|
35
|
+
lines.push('> Generated by js-secure-coding');
|
|
36
|
+
lines.push('');
|
|
37
|
+
lines.push(stripTitle(content));
|
|
38
|
+
|
|
39
|
+
return lines.join('\n');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function stripTitle(content) {
|
|
43
|
+
const lines = content.split('\n');
|
|
44
|
+
// Remove the first H1 title if present (we add our own)
|
|
45
|
+
if (lines[0]?.startsWith('# ')) {
|
|
46
|
+
lines.shift();
|
|
47
|
+
// Remove blank line after title
|
|
48
|
+
if (lines[0]?.trim() === '') lines.shift();
|
|
49
|
+
// Remove blockquote lines after title (e.g., > description)
|
|
50
|
+
while (lines[0]?.startsWith('>')) {
|
|
51
|
+
lines.shift();
|
|
52
|
+
}
|
|
53
|
+
// Remove blank line after blockquote
|
|
54
|
+
if (lines[0]?.trim() === '') lines.shift();
|
|
55
|
+
}
|
|
56
|
+
return lines.join('\n');
|
|
57
|
+
}
|