@nahisaho/katashiro-security 0.4.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/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@nahisaho/katashiro-security",
3
+ "version": "0.4.0",
4
+ "description": "KATASHIRO Security - Security analysis and action auditing",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc -p tsconfig.json",
16
+ "test": "vitest run",
17
+ "test:watch": "vitest",
18
+ "typecheck": "tsc --noEmit",
19
+ "clean": "rm -rf dist"
20
+ },
21
+ "dependencies": {
22
+ "@nahisaho/katashiro-core": "workspace:*",
23
+ "micromatch": "^4.0.8"
24
+ },
25
+ "devDependencies": {
26
+ "@types/micromatch": "^4.0.9",
27
+ "@types/node": "^22.10.7",
28
+ "typescript": "^5.7.3",
29
+ "vitest": "^2.1.9"
30
+ },
31
+ "keywords": [
32
+ "katashiro",
33
+ "security",
34
+ "risk-analysis",
35
+ "audit-log",
36
+ "action-validation"
37
+ ],
38
+ "author": "nahisaho",
39
+ "license": "MIT",
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/nahisaho/KATASHIRO.git",
43
+ "directory": "katashiro/packages/security"
44
+ }
45
+ }
@@ -0,0 +1,327 @@
1
+ /**
2
+ * ActionLogger - 監査ログ記録クラス
3
+ *
4
+ * @requirement REQ-012-05
5
+ * @design すべてのアクションをタイムスタンプ付きで記録
6
+ */
7
+
8
+ import {
9
+ Action,
10
+ SecurityAnalysis,
11
+ Observation,
12
+ AuditLogEntry,
13
+ AuditLogFilter,
14
+ UserConfirmation,
15
+ RiskLevel,
16
+ RISK_LEVEL_ORDER,
17
+ } from './types';
18
+
19
+ /**
20
+ * ログストレージインターフェース
21
+ */
22
+ export interface LogStorage {
23
+ /** ログエントリを追加 */
24
+ append(entry: AuditLogEntry): Promise<void>;
25
+ /** ログを検索 */
26
+ query(filter: AuditLogFilter): Promise<AuditLogEntry[]>;
27
+ /** ログをクリア */
28
+ clear(): Promise<void>;
29
+ /** ログ件数を取得 */
30
+ count(): Promise<number>;
31
+ }
32
+
33
+ /**
34
+ * インメモリログストレージ
35
+ */
36
+ export class InMemoryLogStorage implements LogStorage {
37
+ private logs: AuditLogEntry[] = [];
38
+ private maxEntries: number;
39
+
40
+ constructor(maxEntries: number = 10000) {
41
+ this.maxEntries = maxEntries;
42
+ }
43
+
44
+ async append(entry: AuditLogEntry): Promise<void> {
45
+ this.logs.push(entry);
46
+
47
+ // 最大件数を超えたら古いログを削除
48
+ if (this.logs.length > this.maxEntries) {
49
+ this.logs = this.logs.slice(-this.maxEntries);
50
+ }
51
+ }
52
+
53
+ async query(filter: AuditLogFilter): Promise<AuditLogEntry[]> {
54
+ let results = [...this.logs];
55
+
56
+ // 時間範囲フィルター
57
+ if (filter.startTime) {
58
+ results = results.filter((e) => e.timestamp >= filter.startTime!);
59
+ }
60
+ if (filter.endTime) {
61
+ results = results.filter((e) => e.timestamp <= filter.endTime!);
62
+ }
63
+
64
+ // アクションタイプフィルター
65
+ if (filter.actionTypes && filter.actionTypes.length > 0) {
66
+ results = results.filter((e) => filter.actionTypes!.includes(e.action.type));
67
+ }
68
+
69
+ // リスクレベルフィルター
70
+ if (filter.minRiskLevel) {
71
+ const minOrder = RISK_LEVEL_ORDER[filter.minRiskLevel];
72
+ results = results.filter(
73
+ (e) => RISK_LEVEL_ORDER[e.analysis.riskLevel] >= minOrder
74
+ );
75
+ }
76
+
77
+ // 成功/失敗フィルター
78
+ if (filter.success !== undefined) {
79
+ results = results.filter(
80
+ (e) => e.observation?.success === filter.success
81
+ );
82
+ }
83
+
84
+ // ユーザーIDフィルター
85
+ if (filter.userId) {
86
+ results = results.filter(
87
+ (e) => e.action.context?.userId === filter.userId
88
+ );
89
+ }
90
+
91
+ // キーワード検索
92
+ if (filter.keyword) {
93
+ const keyword = filter.keyword.toLowerCase();
94
+ results = results.filter((e) => {
95
+ const searchText = [
96
+ e.action.name,
97
+ e.action.target,
98
+ ...e.analysis.reasons,
99
+ e.observation?.error,
100
+ ]
101
+ .filter(Boolean)
102
+ .join(' ')
103
+ .toLowerCase();
104
+ return searchText.includes(keyword);
105
+ });
106
+ }
107
+
108
+ // ソート(新しい順)
109
+ results.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
110
+
111
+ // ページング
112
+ const offset = filter.offset ?? 0;
113
+ const limit = filter.limit ?? 100;
114
+ return results.slice(offset, offset + limit);
115
+ }
116
+
117
+ async clear(): Promise<void> {
118
+ this.logs = [];
119
+ }
120
+
121
+ async count(): Promise<number> {
122
+ return this.logs.length;
123
+ }
124
+
125
+ /**
126
+ * 全ログを取得(テスト用)
127
+ */
128
+ getAllLogs(): AuditLogEntry[] {
129
+ return [...this.logs];
130
+ }
131
+ }
132
+
133
+ /**
134
+ * ActionLoggerオプション
135
+ */
136
+ export interface ActionLoggerOptions {
137
+ /** ログストレージ */
138
+ storage?: LogStorage;
139
+ /** 最小記録リスクレベル */
140
+ minLogLevel?: RiskLevel;
141
+ /** ID生成関数 */
142
+ generateId?: () => string;
143
+ }
144
+
145
+ /**
146
+ * アクションロガー
147
+ */
148
+ export class ActionLogger {
149
+ private readonly storage: LogStorage;
150
+ private readonly minLogLevel: RiskLevel;
151
+ private readonly generateId: () => string;
152
+
153
+ constructor(options: ActionLoggerOptions = {}) {
154
+ this.storage = options.storage ?? new InMemoryLogStorage();
155
+ this.minLogLevel = options.minLogLevel ?? 'low';
156
+ this.generateId =
157
+ options.generateId ??
158
+ (() => `log-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
159
+ }
160
+
161
+ /**
162
+ * アクションと分析結果を記録(REQ-012-05)
163
+ */
164
+ async logAction(
165
+ action: Action,
166
+ analysis: SecurityAnalysis,
167
+ observation?: Observation,
168
+ userConfirmation?: UserConfirmation
169
+ ): Promise<string> {
170
+ // 最小リスクレベル未満はスキップ
171
+ if (
172
+ RISK_LEVEL_ORDER[analysis.riskLevel] < RISK_LEVEL_ORDER[this.minLogLevel]
173
+ ) {
174
+ return '';
175
+ }
176
+
177
+ const entry: AuditLogEntry = {
178
+ id: this.generateId(),
179
+ timestamp: new Date().toISOString(),
180
+ action,
181
+ analysis,
182
+ observation,
183
+ userConfirmation,
184
+ };
185
+
186
+ await this.storage.append(entry);
187
+ return entry.id;
188
+ }
189
+
190
+ /**
191
+ * アクション開始を記録
192
+ */
193
+ async logActionStart(action: Action, analysis: SecurityAnalysis): Promise<string> {
194
+ return this.logAction(action, analysis);
195
+ }
196
+
197
+ /**
198
+ * アクション完了を記録(既存エントリを更新)
199
+ */
200
+ async logActionComplete(
201
+ logId: string,
202
+ observation: Observation,
203
+ userConfirmation?: UserConfirmation
204
+ ): Promise<void> {
205
+ // 簡易実装: 新しいエントリとして追加
206
+ // 本格的な実装では既存エントリを更新する
207
+ const logs = await this.storage.query({ limit: 1000 });
208
+ const entry = logs.find((e) => e.id === logId);
209
+ if (entry) {
210
+ entry.observation = observation;
211
+ if (userConfirmation) {
212
+ entry.userConfirmation = userConfirmation;
213
+ }
214
+ }
215
+ }
216
+
217
+ /**
218
+ * ログを検索
219
+ */
220
+ async queryLogs(filter: AuditLogFilter): Promise<AuditLogEntry[]> {
221
+ return this.storage.query(filter);
222
+ }
223
+
224
+ /**
225
+ * 最近のログを取得
226
+ */
227
+ async getRecentLogs(count: number = 10): Promise<AuditLogEntry[]> {
228
+ return this.storage.query({ limit: count });
229
+ }
230
+
231
+ /**
232
+ * 高リスクログを取得
233
+ */
234
+ async getHighRiskLogs(count: number = 10): Promise<AuditLogEntry[]> {
235
+ return this.storage.query({ minRiskLevel: 'high', limit: count });
236
+ }
237
+
238
+ /**
239
+ * ユーザーのログを取得
240
+ */
241
+ async getUserLogs(userId: string, count: number = 10): Promise<AuditLogEntry[]> {
242
+ return this.storage.query({ userId, limit: count });
243
+ }
244
+
245
+ /**
246
+ * ログをクリア
247
+ */
248
+ async clearLogs(): Promise<void> {
249
+ return this.storage.clear();
250
+ }
251
+
252
+ /**
253
+ * ログ件数を取得
254
+ */
255
+ async getLogCount(): Promise<number> {
256
+ return this.storage.count();
257
+ }
258
+
259
+ /**
260
+ * サマリーを生成
261
+ */
262
+ async generateSummary(filter: AuditLogFilter = {}): Promise<AuditLogSummary> {
263
+ const logs = await this.storage.query({ ...filter, limit: 10000 });
264
+
265
+ const summary: AuditLogSummary = {
266
+ totalActions: logs.length,
267
+ byRiskLevel: { low: 0, medium: 0, high: 0, critical: 0 },
268
+ byActionType: {},
269
+ successRate: 0,
270
+ blockedCount: 0,
271
+ confirmedCount: 0,
272
+ };
273
+
274
+ let successCount = 0;
275
+ let totalWithObservation = 0;
276
+
277
+ for (const log of logs) {
278
+ // リスクレベル別
279
+ summary.byRiskLevel[log.analysis.riskLevel]++;
280
+
281
+ // アクションタイプ別
282
+ summary.byActionType[log.action.type] =
283
+ (summary.byActionType[log.action.type] ?? 0) + 1;
284
+
285
+ // 成功率計算
286
+ if (log.observation) {
287
+ totalWithObservation++;
288
+ if (log.observation.success) {
289
+ successCount++;
290
+ }
291
+ }
292
+
293
+ // ブロック数
294
+ if (!log.analysis.allowed) {
295
+ summary.blockedCount++;
296
+ }
297
+
298
+ // 確認数
299
+ if (log.userConfirmation?.confirmed) {
300
+ summary.confirmedCount++;
301
+ }
302
+ }
303
+
304
+ summary.successRate =
305
+ totalWithObservation > 0 ? successCount / totalWithObservation : 0;
306
+
307
+ return summary;
308
+ }
309
+ }
310
+
311
+ /**
312
+ * 監査ログサマリー
313
+ */
314
+ export interface AuditLogSummary {
315
+ /** 総アクション数 */
316
+ totalActions: number;
317
+ /** リスクレベル別件数 */
318
+ byRiskLevel: Record<RiskLevel, number>;
319
+ /** アクションタイプ別件数 */
320
+ byActionType: Record<string, number>;
321
+ /** 成功率 */
322
+ successRate: number;
323
+ /** ブロック数 */
324
+ blockedCount: number;
325
+ /** 確認数 */
326
+ confirmedCount: number;
327
+ }
package/src/index.ts ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @nahisaho/katashiro-security
3
+ *
4
+ * Security analysis and audit logging for KATASHIRO
5
+ * @requirement REQ-012
6
+ */
7
+
8
+ // Types
9
+ export {
10
+ RiskLevel,
11
+ RISK_LEVEL_ORDER,
12
+ compareRiskLevels,
13
+ isRiskLevelAtLeast,
14
+ ActionType,
15
+ Action,
16
+ ActionContext,
17
+ Observation,
18
+ PatternRule,
19
+ SecurityPolicy,
20
+ RiskRule,
21
+ RiskRuleMatch,
22
+ SecurityAnalysis,
23
+ AuditLogEntry,
24
+ UserConfirmation,
25
+ AuditLogFilter,
26
+ DEFAULT_SECURITY_POLICY,
27
+ BUILTIN_RISK_RULES,
28
+ SecurityErrorCode,
29
+ SecurityError,
30
+ } from './types';
31
+
32
+ // SecurityAnalyzer
33
+ export { SecurityAnalyzer, SecurityAnalyzerOptions } from './security-analyzer';
34
+
35
+ // ActionLogger
36
+ export {
37
+ LogStorage,
38
+ InMemoryLogStorage,
39
+ ActionLogger,
40
+ ActionLoggerOptions,
41
+ AuditLogSummary,
42
+ } from './action-logger';