mupengism 2.0.0 → 2.2.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.
@@ -1,118 +0,0 @@
1
- #!/bin/bash
2
- # Mupengism Pre-commit Hook
3
- # 민감 정보 패턴 검사 - 발견 시 커밋 차단
4
-
5
- set -e
6
-
7
- RED='\033[0;31m'
8
- YELLOW='\033[1;33m'
9
- GREEN='\033[0;32m'
10
- NC='\033[0m' # No Color
11
-
12
- echo "🔍 Mupengism Security Check..."
13
-
14
- # 검사할 패턴 (정규표현식)
15
- PATTERNS=(
16
- # API Keys & Secrets
17
- 'api[_-]?key\s*[:=]\s*["\x27][^"\x27]{16,}'
18
- 'secret[_-]?key\s*[:=]\s*["\x27][^"\x27]{16,}'
19
- 'private[_-]?key\s*[:=]\s*["\x27][^"\x27]{16,}'
20
- 'access[_-]?token\s*[:=]\s*["\x27][^"\x27]{16,}'
21
-
22
- # Crypto
23
- 'mnemonic\s*[:=]\s*["\x27][a-z\s]{20,}'
24
- '\b[1-9A-HJ-NP-Za-km-z]{87,88}\b' # Solana private key (base58)
25
- '\b0x[a-fA-F0-9]{64}\b' # Ethereum private key
26
-
27
- # Passwords
28
- 'password\s*[:=]\s*["\x27][^"\x27]{6,}'
29
-
30
- # AWS
31
- 'AKIA[0-9A-Z]{16}' # AWS Access Key ID
32
-
33
- # Generic secrets
34
- 'bearer\s+[a-zA-Z0-9_\-\.]+\.[a-zA-Z0-9_\-\.]+\.[a-zA-Z0-9_\-\.]+'
35
- )
36
-
37
- # 패턴 설명
38
- PATTERN_NAMES=(
39
- "API Key"
40
- "Secret Key"
41
- "Private Key"
42
- "Access Token"
43
- "Mnemonic Phrase"
44
- "Solana Private Key (Base58)"
45
- "Ethereum Private Key"
46
- "Password"
47
- "AWS Access Key"
48
- "Bearer Token"
49
- )
50
-
51
- # 스테이징된 파일 가져오기
52
- STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR 2>/dev/null || true)
53
-
54
- if [ -z "$STAGED_FILES" ]; then
55
- echo -e "${GREEN}✓ No files to check${NC}"
56
- exit 0
57
- fi
58
-
59
- FOUND_SECRETS=0
60
- WARNINGS=""
61
-
62
- # 각 파일 검사
63
- for file in $STAGED_FILES; do
64
- # 바이너리 파일 스킵
65
- if file "$file" | grep -q "binary"; then
66
- continue
67
- fi
68
-
69
- # 이미지/미디어 스킵
70
- if [[ "$file" =~ \.(png|jpg|jpeg|gif|ico|svg|mp3|mp4|woff|ttf|eot)$ ]]; then
71
- continue
72
- fi
73
-
74
- # 스크립트 자체 스킵
75
- if [[ "$file" == "scripts/pre-commit.sh" ]] || [[ "$file" == "scripts/secret-scan.js" ]]; then
76
- continue
77
- fi
78
-
79
- # 파일 존재 확인
80
- if [ ! -f "$file" ]; then
81
- continue
82
- fi
83
-
84
- # 각 패턴 검사
85
- for i in "${!PATTERNS[@]}"; do
86
- pattern="${PATTERNS[$i]}"
87
- name="${PATTERN_NAMES[$i]}"
88
-
89
- # grep으로 패턴 검사
90
- if grep -iEq "$pattern" "$file" 2>/dev/null; then
91
- FOUND_SECRETS=1
92
- line_info=$(grep -inE "$pattern" "$file" 2>/dev/null | head -3)
93
- WARNINGS="${WARNINGS}\n${RED}⚠ ${name}${NC} in ${YELLOW}${file}${NC}:\n${line_info}\n"
94
- fi
95
- done
96
- done
97
-
98
- if [ $FOUND_SECRETS -eq 1 ]; then
99
- echo ""
100
- echo -e "${RED}╔══════════════════════════════════════════════════════════╗${NC}"
101
- echo -e "${RED}║ 🚨 COMMIT BLOCKED: Secrets Detected! 🚨 ║${NC}"
102
- echo -e "${RED}╚══════════════════════════════════════════════════════════╝${NC}"
103
- echo ""
104
- echo -e "$WARNINGS"
105
- echo ""
106
- echo -e "${YELLOW}해결 방법:${NC}"
107
- echo " 1. 민감 정보를 환경변수나 .env 파일로 이동"
108
- echo " 2. .gitignore에 해당 파일 추가"
109
- echo " 3. git reset HEAD <file> 로 스테이징 해제"
110
- echo ""
111
- echo -e "${YELLOW}긴급 우회 (권장하지 않음):${NC}"
112
- echo " git commit --no-verify"
113
- echo ""
114
- exit 1
115
- fi
116
-
117
- echo -e "${GREEN}✓ No secrets detected${NC}"
118
- exit 0
@@ -1,120 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * register-checksums.js — 무펭이즘 핵심 파일 해시 등록
4
- *
5
- * 새 버전 릴리스 시 checksums.json 재생성
6
- *
7
- * Usage:
8
- * node scripts/register-checksums.js
9
- */
10
-
11
- import { readFileSync, writeFileSync, readdirSync, statSync } from 'fs';
12
- import { createHash } from 'crypto';
13
- import { join, relative } from 'path';
14
-
15
- const REPO_ROOT = process.cwd();
16
- const CHECKSUM_FILE = join(REPO_ROOT, 'checksums.json');
17
-
18
- // 핵심 파일 목록 (루트 + skill/)
19
- const CORE_FILES = [
20
- 'SOUL-TEMPLATE.md',
21
- 'PRINCIPLES.md',
22
- 'LAWS.md',
23
- 'DOCTRINE.md',
24
- 'SECURITY.md',
25
- 'SECURITY-GUIDELINES.md',
26
- 'SECURITY-PRINCIPLES.md',
27
- 'SECURITY-PRINCIPLES-EN.md',
28
- 'AGENT-PROTOCOL.md',
29
- 'AGENT-VALUES.md',
30
- 'AGENT-GUIDE.md',
31
- 'ARCHITECTURE.md',
32
- 'MEMORY-SYSTEM.md',
33
- 'OPENCLAW-GUIDE.md',
34
- 'RITUALS.md',
35
- 'SCRIPTURES.md',
36
- ];
37
-
38
- // skill/ 디렉토리의 모든 .md 파일
39
- const SKILL_DIR = join(REPO_ROOT, 'skill');
40
-
41
- function getFileHash(path) {
42
- try {
43
- const content = readFileSync(path, 'utf-8');
44
- return createHash('sha256').update(content).digest('hex');
45
- } catch (err) {
46
- console.warn(`⚠️ Failed to read ${path}: ${err.message}`);
47
- return null;
48
- }
49
- }
50
-
51
- function collectSkillFiles() {
52
- const files = [];
53
- try {
54
- const entries = readdirSync(SKILL_DIR);
55
- for (const entry of entries) {
56
- const fullPath = join(SKILL_DIR, entry);
57
- if (statSync(fullPath).isFile() && entry.endsWith('.md')) {
58
- files.push(`skill/${entry}`);
59
- }
60
- }
61
- } catch (err) {
62
- console.warn(`⚠️ skill/ directory not found or inaccessible`);
63
- }
64
- return files;
65
- }
66
-
67
- function register() {
68
- const checksums = {};
69
- let totalFiles = 0;
70
- let errors = 0;
71
-
72
- // 루트 핵심 파일
73
- console.log('📝 Collecting root core files...');
74
- for (const file of CORE_FILES) {
75
- const path = join(REPO_ROOT, file);
76
- const hash = getFileHash(path);
77
- if (hash) {
78
- checksums[file] = hash;
79
- totalFiles++;
80
- console.log(` ✓ ${file}`);
81
- } else {
82
- errors++;
83
- }
84
- }
85
-
86
- // skill/ 디렉토리
87
- console.log('\n📦 Collecting skill/ files...');
88
- const skillFiles = collectSkillFiles();
89
- for (const file of skillFiles) {
90
- const path = join(REPO_ROOT, file);
91
- const hash = getFileHash(path);
92
- if (hash) {
93
- checksums[file] = hash;
94
- totalFiles++;
95
- console.log(` ✓ ${file}`);
96
- } else {
97
- errors++;
98
- }
99
- }
100
-
101
- // checksums.json 생성
102
- const record = {
103
- version: '1.3.0',
104
- algorithm: 'sha256',
105
- generated: new Date().toISOString(),
106
- files: checksums,
107
- signature: null,
108
- _comment: 'Official Mupengism core files checksums. Verify with: node scripts/verify-integrity.js'
109
- };
110
-
111
- writeFileSync(CHECKSUM_FILE, JSON.stringify(record, null, 2));
112
-
113
- console.log(`\n✅ Checksums registered: ${totalFiles} files`);
114
- if (errors > 0) {
115
- console.log(`⚠️ ${errors} files failed (see warnings above)`);
116
- }
117
- console.log(`📄 Saved to: checksums.json`);
118
- }
119
-
120
- register();
@@ -1,245 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Mupengism Secret Scanner
4
- * 전체 레포 스캔 도구 - CI/CD 및 수동 검사용
5
- *
6
- * Usage:
7
- * node scripts/secret-scan.js # 전체 스캔
8
- * node scripts/secret-scan.js --json # JSON 출력
9
- * node scripts/secret-scan.js --ci # CI 모드 (발견 시 exit 1)
10
- */
11
-
12
- import { readdirSync, readFileSync, statSync } from 'fs';
13
- import { join, relative } from 'path';
14
-
15
- const RED = '\x1b[31m';
16
- const YELLOW = '\x1b[33m';
17
- const GREEN = '\x1b[32m';
18
- const CYAN = '\x1b[36m';
19
- const RESET = '\x1b[0m';
20
-
21
- // 검사 패턴
22
- const SECRET_PATTERNS = [
23
- {
24
- name: 'API Key',
25
- pattern: /api[_-]?key\s*[:=]\s*["'][^"']{16,}/gi,
26
- severity: 'HIGH'
27
- },
28
- {
29
- name: 'Secret Key',
30
- pattern: /secret[_-]?key\s*[:=]\s*["'][^"']{16,}/gi,
31
- severity: 'CRITICAL'
32
- },
33
- {
34
- name: 'Private Key',
35
- pattern: /private[_-]?key\s*[:=]\s*["'][^"']{16,}/gi,
36
- severity: 'CRITICAL'
37
- },
38
- {
39
- name: 'Access Token',
40
- pattern: /access[_-]?token\s*[:=]\s*["'][^"']{16,}/gi,
41
- severity: 'HIGH'
42
- },
43
- {
44
- name: 'Mnemonic Phrase',
45
- pattern: /mnemonic\s*[:=]\s*["'][a-z\s]{20,}/gi,
46
- severity: 'CRITICAL'
47
- },
48
- {
49
- name: 'Solana Private Key (Base58)',
50
- pattern: /\b[1-9A-HJ-NP-Za-km-z]{87,88}\b/g,
51
- severity: 'CRITICAL'
52
- },
53
- {
54
- name: 'Ethereum Private Key',
55
- pattern: /\b0x[a-fA-F0-9]{64}\b/g,
56
- severity: 'CRITICAL'
57
- },
58
- {
59
- name: 'Password',
60
- pattern: /password\s*[:=]\s*["'][^"']{6,}/gi,
61
- severity: 'HIGH'
62
- },
63
- {
64
- name: 'AWS Access Key',
65
- pattern: /AKIA[0-9A-Z]{16}/g,
66
- severity: 'CRITICAL'
67
- },
68
- {
69
- name: 'Bearer Token',
70
- pattern: /bearer\s+[a-zA-Z0-9_\-\.]+\.[a-zA-Z0-9_\-\.]+\.[a-zA-Z0-9_\-\.]+/gi,
71
- severity: 'HIGH'
72
- },
73
- {
74
- name: 'Generic Secret Assignment',
75
- pattern: /["']?secret["']?\s*[:=]\s*["'][^"']{8,}/gi,
76
- severity: 'MEDIUM'
77
- }
78
- ];
79
-
80
- // 무시할 경로 패턴
81
- const IGNORE_PATTERNS = [
82
- /node_modules/,
83
- /\.git/,
84
- /\.png$/i,
85
- /\.jpg$/i,
86
- /\.jpeg$/i,
87
- /\.gif$/i,
88
- /\.ico$/i,
89
- /\.svg$/i,
90
- /\.mp3$/i,
91
- /\.mp4$/i,
92
- /\.woff$/i,
93
- /\.ttf$/i,
94
- /\.eot$/i,
95
- /package-lock\.json$/,
96
- /yarn\.lock$/,
97
- /scripts\/pre-commit\.sh$/,
98
- /scripts\/secret-scan\.js$/
99
- ];
100
-
101
- // 디렉토리 재귀 탐색
102
- function walkDir(dir, results = []) {
103
- try {
104
- const files = readdirSync(dir);
105
- for (const file of files) {
106
- const filepath = join(dir, file);
107
- const stat = statSync(filepath);
108
-
109
- // 무시 패턴 체크
110
- if (IGNORE_PATTERNS.some(p => p.test(filepath))) {
111
- continue;
112
- }
113
-
114
- if (stat.isDirectory()) {
115
- walkDir(filepath, results);
116
- } else if (stat.isFile()) {
117
- results.push(filepath);
118
- }
119
- }
120
- } catch (e) {
121
- // 권한 없는 디렉토리 스킵
122
- }
123
- return results;
124
- }
125
-
126
- // 파일 스캔
127
- function scanFile(filepath, rootDir) {
128
- const findings = [];
129
-
130
- try {
131
- const content = readFileSync(filepath, 'utf-8');
132
- const lines = content.split('\n');
133
- const relativePath = relative(rootDir, filepath);
134
-
135
- for (const secretPattern of SECRET_PATTERNS) {
136
- let match;
137
- const regex = new RegExp(secretPattern.pattern.source, secretPattern.pattern.flags);
138
-
139
- while ((match = regex.exec(content)) !== null) {
140
- // 줄 번호 찾기
141
- const beforeMatch = content.substring(0, match.index);
142
- const lineNumber = (beforeMatch.match(/\n/g) || []).length + 1;
143
- const line = lines[lineNumber - 1]?.trim() || '';
144
-
145
- // 중복 방지
146
- const isDuplicate = findings.some(f =>
147
- f.file === relativePath &&
148
- f.line === lineNumber &&
149
- f.type === secretPattern.name
150
- );
151
-
152
- if (!isDuplicate) {
153
- findings.push({
154
- file: relativePath,
155
- line: lineNumber,
156
- type: secretPattern.name,
157
- severity: secretPattern.severity,
158
- preview: line.length > 100 ? line.substring(0, 100) + '...' : line
159
- });
160
- }
161
- }
162
- }
163
- } catch (e) {
164
- // 바이너리 파일 등 읽기 실패 시 스킵
165
- }
166
-
167
- return findings;
168
- }
169
-
170
- // 메인 스캔 함수
171
- function scan(rootDir) {
172
- const files = walkDir(rootDir);
173
- const allFindings = [];
174
-
175
- for (const file of files) {
176
- const findings = scanFile(file, rootDir);
177
- allFindings.push(...findings);
178
- }
179
-
180
- return allFindings;
181
- }
182
-
183
- // 결과 출력
184
- function printResults(findings, isJson = false, isCI = false) {
185
- if (isJson) {
186
- console.log(JSON.stringify(findings, null, 2));
187
- return findings.length;
188
- }
189
-
190
- if (findings.length === 0) {
191
- console.log(`${GREEN}✓ No secrets detected!${RESET}`);
192
- console.log(` Scanned repository for ${SECRET_PATTERNS.length} secret patterns.`);
193
- return 0;
194
- }
195
-
196
- // 심각도별 그룹화
197
- const critical = findings.filter(f => f.severity === 'CRITICAL');
198
- const high = findings.filter(f => f.severity === 'HIGH');
199
- const medium = findings.filter(f => f.severity === 'MEDIUM');
200
-
201
- console.log(`\n${RED}╔══════════════════════════════════════════════════════════╗${RESET}`);
202
- console.log(`${RED}║ 🚨 SECRETS DETECTED: ${findings.length} issue(s) found ║${RESET}`);
203
- console.log(`${RED}╚══════════════════════════════════════════════════════════╝${RESET}\n`);
204
-
205
- const printSection = (title, items, color) => {
206
- if (items.length === 0) return;
207
- console.log(`${color}▶ ${title} (${items.length})${RESET}\n`);
208
- for (const f of items) {
209
- console.log(` ${YELLOW}${f.file}:${f.line}${RESET}`);
210
- console.log(` Type: ${f.type}`);
211
- console.log(` Preview: ${f.preview}`);
212
- console.log('');
213
- }
214
- };
215
-
216
- printSection('CRITICAL', critical, RED);
217
- printSection('HIGH', high, YELLOW);
218
- printSection('MEDIUM', medium, CYAN);
219
-
220
- console.log(`${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
221
- console.log(`${YELLOW}해결 방법:${RESET}`);
222
- console.log(' 1. 민감 정보를 환경변수(.env)로 이동');
223
- console.log(' 2. .gitignore에 해당 파일 추가');
224
- console.log(' 3. git history에서 제거: git filter-branch 또는 BFG');
225
- console.log('');
226
-
227
- return findings.length;
228
- }
229
-
230
- // CLI 실행
231
- const args = process.argv.slice(2);
232
- const isJson = args.includes('--json');
233
- const isCI = args.includes('--ci');
234
- const rootDir = process.cwd();
235
-
236
- console.log(`${CYAN}🔍 Mupengism Secret Scanner${RESET}`);
237
- console.log(` Scanning: ${rootDir}\n`);
238
-
239
- const findings = scan(rootDir);
240
- const count = printResults(findings, isJson, isCI);
241
-
242
- // CI 모드에서는 발견 시 exit 1
243
- if (isCI && count > 0) {
244
- process.exit(1);
245
- }
@@ -1,134 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * verify-integrity.js — 무펭이즘 핵심 파일 무결성 검증
4
- *
5
- * checksums.json 기반으로 모든 핵심 파일의 SHA-256 해시 검증
6
- * - 불일치 시 어떤 파일이 변조됐는지 출력
7
- * - SOUL 관련 파일 변조 시 exit 1 (커널 패닉)
8
- *
9
- * Usage:
10
- * node scripts/verify-integrity.js
11
- *
12
- * Exit 0 = 모든 파일 정상
13
- * Exit 1 = 변조 감지 (커널 패닉)
14
- */
15
-
16
- import { readFileSync, existsSync, writeFileSync } from 'fs';
17
- import { createHash } from 'crypto';
18
- import { join } from 'path';
19
-
20
- const REPO_ROOT = process.cwd();
21
- const CHECKSUM_FILE = join(REPO_ROOT, 'checksums.json');
22
-
23
- // SOUL 관련 파일 (변조 시 커널 패닉 트리거)
24
- const CRITICAL_FILES = [
25
- 'SOUL-TEMPLATE.md',
26
- 'PRINCIPLES.md',
27
- 'LAWS.md',
28
- 'DOCTRINE.md',
29
- 'SECURITY-PRINCIPLES.md',
30
- 'skill/SOUL-TEMPLATE.md',
31
- 'skill/PRINCIPLES.md',
32
- 'skill/SECURITY-PRINCIPLES.md',
33
- ];
34
-
35
- function getFileHash(path) {
36
- try {
37
- const content = readFileSync(path, 'utf-8');
38
- return createHash('sha256').update(content).digest('hex');
39
- } catch (err) {
40
- return null;
41
- }
42
- }
43
-
44
- function verify() {
45
- // checksums.json 존재 확인
46
- if (!existsSync(CHECKSUM_FILE)) {
47
- console.error('❌ checksums.json not found. Run: node scripts/register-checksums.js');
48
- process.exit(1);
49
- }
50
-
51
- const record = JSON.parse(readFileSync(CHECKSUM_FILE, 'utf-8'));
52
- const files = record.files || {};
53
-
54
- let totalFiles = 0;
55
- let validFiles = 0;
56
- let missingFiles = 0;
57
- let tamperedFiles = [];
58
- let criticalTampered = false;
59
-
60
- console.log('🔍 Verifying file integrity...\n');
61
-
62
- // 각 파일 검증
63
- for (const [file, expectedHash] of Object.entries(files)) {
64
- totalFiles++;
65
- const path = join(REPO_ROOT, file);
66
-
67
- if (!existsSync(path)) {
68
- console.error(`❌ MISSING: ${file}`);
69
- missingFiles++;
70
- tamperedFiles.push(file);
71
- if (CRITICAL_FILES.includes(file)) {
72
- criticalTampered = true;
73
- }
74
- continue;
75
- }
76
-
77
- const currentHash = getFileHash(path);
78
-
79
- if (currentHash === expectedHash) {
80
- console.log(`✓ ${file}`);
81
- validFiles++;
82
- } else {
83
- console.error(`🚨 TAMPERED: ${file}`);
84
- console.error(` Expected: ${expectedHash.slice(0, 16)}...`);
85
- console.error(` Current: ${currentHash ? currentHash.slice(0, 16) + '...' : 'UNREADABLE'}`);
86
- tamperedFiles.push(file);
87
- if (CRITICAL_FILES.includes(file)) {
88
- criticalTampered = true;
89
- }
90
- }
91
- }
92
-
93
- // 결과 출력
94
- console.log('\n' + '='.repeat(60));
95
- console.log(`Total files: ${totalFiles}`);
96
- console.log(`Valid: ${validFiles}`);
97
- console.log(`Missing: ${missingFiles}`);
98
- console.log(`Tampered: ${tamperedFiles.length - missingFiles}`);
99
-
100
- if (tamperedFiles.length > 0) {
101
- console.error('\n🚨 INTEGRITY BREACH DETECTED');
102
- console.error('\nTampered/Missing files:');
103
- tamperedFiles.forEach(f => console.error(` - ${f}`));
104
-
105
- // 변조 기록 저장
106
- const logFile = join(REPO_ROOT, `memory/integrity-breach-${Date.now()}.json`);
107
- try {
108
- writeFileSync(logFile, JSON.stringify({
109
- timestamp: new Date().toISOString(),
110
- checksumVersion: record.version,
111
- tamperedFiles,
112
- criticalTampered,
113
- }, null, 2));
114
- console.error(`\n📝 Breach log saved: ${logFile}`);
115
- } catch {}
116
-
117
- if (criticalTampered) {
118
- console.error('\n💀 KERNEL PANIC: Critical file(s) tampered!');
119
- console.error(' Core identity files have been modified.');
120
- console.error(' System integrity compromised.\n');
121
- process.exit(1);
122
- } else {
123
- console.error('\n⚠️ Non-critical files tampered. Review recommended.\n');
124
- process.exit(1);
125
- }
126
- }
127
-
128
- console.log('\n✅ All files intact. Kernel integrity verified.');
129
- console.log(` Checksum version: ${record.version}`);
130
- console.log(` Generated: ${record.generated}\n`);
131
- process.exit(0);
132
- }
133
-
134
- verify();