shield-harness 1.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/.claude/hooks/lib/session-modules/.gitkeep +0 -0
- package/.claude/hooks/lib/sh-utils.js +241 -0
- package/.claude/hooks/lint-on-save.js +240 -0
- package/.claude/hooks/sh-circuit-breaker.js +111 -0
- package/.claude/hooks/sh-config-guard.js +252 -0
- package/.claude/hooks/sh-data-boundary.js +315 -0
- package/.claude/hooks/sh-dep-audit.js +101 -0
- package/.claude/hooks/sh-elicitation.js +241 -0
- package/.claude/hooks/sh-evidence.js +193 -0
- package/.claude/hooks/sh-gate.js +330 -0
- package/.claude/hooks/sh-injection-guard.js +165 -0
- package/.claude/hooks/sh-instructions.js +210 -0
- package/.claude/hooks/sh-output-control.js +183 -0
- package/.claude/hooks/sh-permission-learn.js +223 -0
- package/.claude/hooks/sh-permission.js +157 -0
- package/.claude/hooks/sh-pipeline.js +639 -0
- package/.claude/hooks/sh-postcompact.js +173 -0
- package/.claude/hooks/sh-precompact.js +114 -0
- package/.claude/hooks/sh-quiet-inject.js +147 -0
- package/.claude/hooks/sh-session-end.js +143 -0
- package/.claude/hooks/sh-session-start.js +196 -0
- package/.claude/hooks/sh-subagent.js +86 -0
- package/.claude/hooks/sh-task-gate.js +138 -0
- package/.claude/hooks/sh-user-prompt.js +181 -0
- package/.claude/hooks/sh-worktree.js +227 -0
- package/.claude/patterns/injection-patterns.json +137 -0
- package/.claude/rules/binding-governance.md +62 -0
- package/.claude/rules/channel-security.md +90 -0
- package/.claude/rules/coding-principles.md +79 -0
- package/.claude/rules/dev-environment.md +37 -0
- package/.claude/rules/implementation-context.md +112 -0
- package/.claude/rules/language.md +26 -0
- package/.claude/rules/security.md +109 -0
- package/.claude/rules/testing.md +43 -0
- package/LICENSE +21 -0
- package/README.ja.md +107 -0
- package/README.md +105 -0
- package/bin/shield-harness.js +141 -0
- package/package.json +33 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Shield Harness Implementation Context
|
|
2
|
+
|
|
3
|
+
> Shield Harness = Claude Code の `.claude/` ディレクトリ構造によるセキュリティハーネス(hooks + rules + skills + settings.json)
|
|
4
|
+
|
|
5
|
+
## Design Documents(実装時に必ず参照)
|
|
6
|
+
|
|
7
|
+
| # | ドキュメント | 層 | パス | 用途 |
|
|
8
|
+
| --- | ------------------ | --------- | -------------------------------------------- | ---------------------------------------- |
|
|
9
|
+
| ① | REQUIREMENTS.md | Why | docs/REQUIREMENTS.md | 機能要件・受入基準 |
|
|
10
|
+
| ② | THREAT_MODEL.md | Why→What | docs/THREAT_MODEL.md | 脅威 ID・攻撃ベクトル |
|
|
11
|
+
| ③ | ARCHITECTURE.md | What | docs/ARCHITECTURE.md | 22 フック一覧・ディレクトリ構造 |
|
|
12
|
+
| ④ | CLAUDE_MD_SPEC.md | What | docs/CLAUDE_MD_SPEC.md | 28 ルール仕様・トレーサビリティ |
|
|
13
|
+
| ⑤ | DETAILED_DESIGN.md | How | docs/DETAILED_DESIGN.md | 各フックの入出力・正規表現・分岐ロジック |
|
|
14
|
+
| ADR | ADR 設計提案 | Reference | .reference/CLAWLESS_ADR_REDESIGN_PROPOSAL.md | 35 ADR の設計判断根拠 |
|
|
15
|
+
|
|
16
|
+
## Implementation Order(依存関係グラフに基づく)
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
Phase A(基盤 — 最初に実装):
|
|
20
|
+
ADR-033: backlog.yaml スキーマ + sync-project-views.ps1
|
|
21
|
+
↓ 他 ADR の前提
|
|
22
|
+
|
|
23
|
+
Phase B(パイプライン):
|
|
24
|
+
ADR-031: sh-pipeline.sh(STG ゲート駆動)
|
|
25
|
+
ADR-032: 承認レスモード(approval_free) ← 並列可
|
|
26
|
+
ADR-035: バイリンガル README + sync-readme.ps1 ← 並列可
|
|
27
|
+
↓
|
|
28
|
+
|
|
29
|
+
Phase C(自律ループ):
|
|
30
|
+
ADR-034: auto-pickup + チャンネル連携 + ブロック通知
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Technical Constraints
|
|
34
|
+
|
|
35
|
+
- **Hook language**: pure bash + jq(ミリ秒応答必須)。複雑ロジックのみ Node.js CommonJS
|
|
36
|
+
- **Hook protocol**: exit 0 = allow, exit 2 = deny(stdout に JSON)。deny() は sh-utils.sh 経由
|
|
37
|
+
- **Target**: 22 hook scripts + lib/sh-utils.sh + injection-patterns.json
|
|
38
|
+
- **External deps**: yq (Go), jq 1.6+, node (NFKC), pwsh (sync scripts, bash fallback あり), gh (optional)
|
|
39
|
+
- **OS**: Windows ネイティブファースト(Git Bash 環境)。WSL2/Linux 互換
|
|
40
|
+
- **Trusted Operation**: pipeline の git 操作は bash 子プロセスとして直接実行(フックエンジン非経由)
|
|
41
|
+
- **fail-close**: 安全条件を確認できない場合は exit 2 で停止
|
|
42
|
+
|
|
43
|
+
## Directory Structure(生成対象の全量)
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
.claude/
|
|
47
|
+
├─ settings.json
|
|
48
|
+
├─ settings.local.json
|
|
49
|
+
├─ hooks/
|
|
50
|
+
│ ├─ sh-permission.sh
|
|
51
|
+
│ ├─ sh-permission-learn.sh
|
|
52
|
+
│ ├─ sh-gate.sh
|
|
53
|
+
│ ├─ sh-injection-guard.sh
|
|
54
|
+
│ ├─ sh-user-prompt.sh
|
|
55
|
+
│ ├─ sh-evidence.sh
|
|
56
|
+
│ ├─ sh-output-control.sh
|
|
57
|
+
│ ├─ sh-quiet-inject.sh
|
|
58
|
+
│ ├─ sh-circuit-breaker.sh
|
|
59
|
+
│ ├─ sh-task-gate.sh
|
|
60
|
+
│ ├─ sh-precompact.sh
|
|
61
|
+
│ ├─ sh-postcompact.sh
|
|
62
|
+
│ ├─ sh-instructions.sh
|
|
63
|
+
│ ├─ sh-session-start.sh
|
|
64
|
+
│ ├─ sh-session-end.sh
|
|
65
|
+
│ ├─ sh-config-guard.sh
|
|
66
|
+
│ ├─ sh-subagent.sh
|
|
67
|
+
│ ├─ sh-dependency-guard.sh
|
|
68
|
+
│ ├─ sh-elicitation.sh
|
|
69
|
+
│ ├─ sh-worktree.sh
|
|
70
|
+
│ ├─ sh-data-boundary.sh
|
|
71
|
+
│ ├─ sh-pipeline.sh
|
|
72
|
+
│ └─ lib/
|
|
73
|
+
│ └─ sh-utils.sh
|
|
74
|
+
├─ patterns/
|
|
75
|
+
│ └─ injection-patterns.json
|
|
76
|
+
├─ rules/
|
|
77
|
+
│ ├─ security.md
|
|
78
|
+
│ ├─ coding-principles.md
|
|
79
|
+
│ └─ channel-security.md
|
|
80
|
+
└─ logs/
|
|
81
|
+
├─ evidence-ledger.jsonl
|
|
82
|
+
└─ instructions-hashes.json
|
|
83
|
+
|
|
84
|
+
.shield-harness/
|
|
85
|
+
├─ session.json
|
|
86
|
+
├─ config/
|
|
87
|
+
│ └─ pipeline-config.json
|
|
88
|
+
└─ logs/
|
|
89
|
+
|
|
90
|
+
tasks/
|
|
91
|
+
└─ backlog.yaml
|
|
92
|
+
|
|
93
|
+
docs/project/
|
|
94
|
+
├─ ROADMAP.md
|
|
95
|
+
├─ WBS.md
|
|
96
|
+
├─ GANTT.md
|
|
97
|
+
└─ MILESTONES.md
|
|
98
|
+
|
|
99
|
+
scripts/
|
|
100
|
+
├─ sync-project-views.ps1
|
|
101
|
+
└─ sync-readme.ps1
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Coding Rules for Hook Scripts
|
|
105
|
+
|
|
106
|
+
- **DETAILED_DESIGN.md が唯一の実装仕様書** — 各フックの §番号を参照して実装すること
|
|
107
|
+
- deny() は stdout に JSON を出力 + exit 2(stderr ではない)
|
|
108
|
+
- NFKC 正規化: Node.js 不在時は fail-close(deny)
|
|
109
|
+
- Hash chain: flock ベースロック(Windows Git Bash では mkdir フォールバック)
|
|
110
|
+
- READONLY_PATTERNS から sed を除外(sed -i は書込操作)
|
|
111
|
+
- permissions.allow: standard プロファイルで 40 操作
|
|
112
|
+
- Circuit breaker: stop_hook_active フラグは allow 後にリセット
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Language Rules
|
|
2
|
+
|
|
3
|
+
## Thinking and Reasoning
|
|
4
|
+
|
|
5
|
+
- **Always think and reason in English**
|
|
6
|
+
- Internal analysis, planning, and problem-solving should be in English
|
|
7
|
+
- Code comments, variable names, function names, and docstrings should be in English
|
|
8
|
+
|
|
9
|
+
## User Communication
|
|
10
|
+
|
|
11
|
+
- **Always respond to users in Japanese**
|
|
12
|
+
- Explanations, questions, and status updates should be in Japanese
|
|
13
|
+
- Error messages shown to users should be in Japanese
|
|
14
|
+
|
|
15
|
+
## Code
|
|
16
|
+
|
|
17
|
+
- All code should be written in English:
|
|
18
|
+
- Variable names: `user_count`, not `ユーザー数`
|
|
19
|
+
- Function names: `calculate_total()`, not `合計計算()`
|
|
20
|
+
- Comments: `# Check if valid`, not `# 有効かチェック`
|
|
21
|
+
- Docstrings: English descriptions
|
|
22
|
+
|
|
23
|
+
## Documentation
|
|
24
|
+
|
|
25
|
+
- Technical documentation: English
|
|
26
|
+
- User-facing documentation (README, etc.): Japanese is acceptable
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Security Rules
|
|
2
|
+
|
|
3
|
+
Security checklist to always verify when writing code.
|
|
4
|
+
|
|
5
|
+
## Secrets Management
|
|
6
|
+
|
|
7
|
+
### Never Do
|
|
8
|
+
|
|
9
|
+
- Hardcode API keys or passwords
|
|
10
|
+
- Log sensitive information
|
|
11
|
+
- Commit `.env` files
|
|
12
|
+
|
|
13
|
+
### Required
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
# Good: Get from environment variables
|
|
17
|
+
import os
|
|
18
|
+
API_KEY = os.environ["API_KEY"]
|
|
19
|
+
|
|
20
|
+
# Good: With existence check
|
|
21
|
+
API_KEY = os.environ.get("API_KEY")
|
|
22
|
+
if not API_KEY:
|
|
23
|
+
raise ValueError("API_KEY environment variable is required")
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Input Validation
|
|
27
|
+
|
|
28
|
+
Always validate external input:
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from pydantic import BaseModel, EmailStr, Field
|
|
32
|
+
|
|
33
|
+
class UserInput(BaseModel):
|
|
34
|
+
email: EmailStr
|
|
35
|
+
age: int = Field(ge=0, le=150)
|
|
36
|
+
name: str = Field(min_length=1, max_length=100)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## SQL Injection Prevention
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
# Bad: String concatenation
|
|
43
|
+
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
|
|
44
|
+
|
|
45
|
+
# Good: Parameterized query
|
|
46
|
+
cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## XSS Prevention
|
|
50
|
+
|
|
51
|
+
- Escape user input before embedding in HTML
|
|
52
|
+
- Enable template engine auto-escaping
|
|
53
|
+
|
|
54
|
+
## Error Messages
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
# Bad: Too detailed (gives attackers information)
|
|
58
|
+
raise Exception(f"Database connection failed: {connection_string}")
|
|
59
|
+
|
|
60
|
+
# Good: Minimal information
|
|
61
|
+
raise Exception("Database connection failed")
|
|
62
|
+
# Details go to logs (logs are private)
|
|
63
|
+
logger.error(f"Database connection failed: {connection_string}")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Dependencies
|
|
67
|
+
|
|
68
|
+
- Regular vulnerability checks: `pip-audit`, `safety`
|
|
69
|
+
- Remove unused dependencies
|
|
70
|
+
- Pin versions (`==` over `>=`)
|
|
71
|
+
|
|
72
|
+
## Code Review Checklist
|
|
73
|
+
|
|
74
|
+
- [ ] No hardcoded secrets
|
|
75
|
+
- [ ] External input is validated
|
|
76
|
+
- [ ] SQL queries are parameterized
|
|
77
|
+
- [ ] Error messages are not too detailed
|
|
78
|
+
- [ ] Logs don't contain sensitive information
|
|
79
|
+
|
|
80
|
+
## Git Operations Safety
|
|
81
|
+
|
|
82
|
+
git rm --cached is a prohibited operation.
|
|
83
|
+
Locally it appears to only remove files from the index,
|
|
84
|
+
but after committing, it propagates as physical deletion
|
|
85
|
+
when others pull/merge from the remote.
|
|
86
|
+
|
|
87
|
+
Prohibited commands:
|
|
88
|
+
|
|
89
|
+
- git rm --cached (single files or directories)
|
|
90
|
+
- git rm -r --cached (recursive untrack)
|
|
91
|
+
|
|
92
|
+
When managing files that should not be tracked via .gitignore,
|
|
93
|
+
the principle is to never commit them in the first place.
|
|
94
|
+
Simply adding an already-committed file to .gitignore does not
|
|
95
|
+
remove it from tracking, which tempts the use of git rm --cached,
|
|
96
|
+
but it is prohibited for the reasons stated above.
|
|
97
|
+
|
|
98
|
+
Alternative: When you need to remove already-committed files from tracking,
|
|
99
|
+
consult the human (project owner) and determine the approach
|
|
100
|
+
after confirming the impact scope.
|
|
101
|
+
|
|
102
|
+
## Line Ending Management
|
|
103
|
+
|
|
104
|
+
Line ending normalization is managed by `.gitattributes` only.
|
|
105
|
+
Do not set `core.autocrlf=true` in this repository.
|
|
106
|
+
|
|
107
|
+
When restoring files from old commits (`git checkout <commit> -- <path>`),
|
|
108
|
+
always run `git add --renormalize .` afterward to re-apply `.gitattributes` rules.
|
|
109
|
+
Otherwise, phantom diffs will appear in `git status` due to EOL mismatch.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Testing Rules
|
|
2
|
+
|
|
3
|
+
## Principles (Language-Agnostic)
|
|
4
|
+
|
|
5
|
+
- **TDD when possible**: Write tests before implementation (Red-Green-Refactor)
|
|
6
|
+
- **AAA Pattern**: Arrange / Act / Assert
|
|
7
|
+
- **Naming**: `test_{subject}_{condition}_{expected_result}`
|
|
8
|
+
- **Coverage target**: 80%+ for source code
|
|
9
|
+
|
|
10
|
+
## Test Categories
|
|
11
|
+
|
|
12
|
+
1. **Happy path**: Normal input, expected output
|
|
13
|
+
2. **Boundary values**: Min, max, empty, zero
|
|
14
|
+
3. **Error cases**: Invalid input, error conditions
|
|
15
|
+
4. **Edge cases**: Null, empty string, special characters
|
|
16
|
+
|
|
17
|
+
## PowerShell Testing (Pester)
|
|
18
|
+
|
|
19
|
+
When Pester is available:
|
|
20
|
+
|
|
21
|
+
```powershell
|
|
22
|
+
# Run tests
|
|
23
|
+
Invoke-Pester -Verbose
|
|
24
|
+
|
|
25
|
+
# Run with coverage
|
|
26
|
+
Invoke-Pester -CodeCoverage ./scripts/*.ps1
|
|
27
|
+
|
|
28
|
+
# Test file naming: {Module}.Tests.ps1
|
|
29
|
+
# Test structure: Describe / Context / It
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Current Testing Approach
|
|
33
|
+
|
|
34
|
+
Until a formal test framework is adopted:
|
|
35
|
+
|
|
36
|
+
- **Git guard**: Pre-commit hooks catch secrets and sensitive data
|
|
37
|
+
- **Manual verification**: Review output before committing
|
|
38
|
+
|
|
39
|
+
## Mocking
|
|
40
|
+
|
|
41
|
+
- Isolate external dependencies (file I/O, network, CLI tools)
|
|
42
|
+
- Use `unittest.mock` (Python hooks) or Pester `Mock` (PowerShell)
|
|
43
|
+
- Test fixtures in dedicated `tests/` directory when available
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 sora
|
|
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.ja.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# Shield Harness
|
|
4
|
+
|
|
5
|
+
**Claude Code のセキュリティハーネス — 苦労なし、フック駆動の防御**
|
|
6
|
+
|
|
7
|
+
> くろうレス — 苦労レス — 苦労しない
|
|
8
|
+
|
|
9
|
+
[](README.md)
|
|
10
|
+
[](#)
|
|
11
|
+
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
## Shield Harness とは
|
|
15
|
+
|
|
16
|
+
Claude Code が安全・再現可能に開発を進めるためのハーネス。
|
|
17
|
+
`.claude/` ディレクトリに展開される hooks + rules + permissions + settings の多層防御でエージェントを統制します。
|
|
18
|
+
|
|
19
|
+
## クイックスタート
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx shield-harness init [--profile minimal|standard|strict]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## なぜ Shield Harness なのか
|
|
26
|
+
|
|
27
|
+
- **フック駆動の防御**: 22 のセキュリティフックが Claude Code の全操作を監視
|
|
28
|
+
- **承認レスモード**: hooks に全セキュリティ判定を委譲し、人間の承認ダイアログを排除
|
|
29
|
+
- **fail-close 原則**: 安全条件を確認できない場合は自動的に停止
|
|
30
|
+
- **証跡記録**: SHA-256 ハッシュチェーンで全 allow/deny 決定を改ざん不能な形で記録
|
|
31
|
+
|
|
32
|
+
## アーキテクチャ概要
|
|
33
|
+
|
|
34
|
+
3 層防御モデル:
|
|
35
|
+
|
|
36
|
+
| 層 | 防御 | 実装 |
|
|
37
|
+
| ------- | -------------- | ------------------------------------ |
|
|
38
|
+
| Layer 1 | 権限制御 | `settings.json` の deny/allow ルール |
|
|
39
|
+
| Layer 2 | フック防御 | 22 の Node.js フックスクリプト |
|
|
40
|
+
| Layer 3 | サンドボックス | OS レベルのプロセス隔離 |
|
|
41
|
+
|
|
42
|
+
## プロファイル
|
|
43
|
+
|
|
44
|
+
| プロファイル | 説明 | 承認レス | 用途 |
|
|
45
|
+
| ------------ | -------- | -------- | ---------------------------- |
|
|
46
|
+
| **minimal** | 最小構成 | 有効 | 低リスクタスク |
|
|
47
|
+
| **standard** | 推奨構成 | 有効 | 通常の開発 |
|
|
48
|
+
| **strict** | 厳格構成 | 無効 | セキュリティ監査が必要な場合 |
|
|
49
|
+
|
|
50
|
+
## フックカタログ
|
|
51
|
+
|
|
52
|
+
| # | フック | イベント | 責務 |
|
|
53
|
+
| --- | ---------------- | --------------------- | --------------------------------------------- |
|
|
54
|
+
| 1 | permission | PreToolUse | ツール使用の 4 カテゴリ分類 |
|
|
55
|
+
| 2 | gate | PreToolUse | Bash コマンドの 7 攻撃ベクトル検査 |
|
|
56
|
+
| 3 | injection-guard | PreToolUse | 9 カテゴリ 50+ パターンのインジェクション検出 |
|
|
57
|
+
| 4 | data-boundary | PreToolUse | 本番データ境界 + 管轄追跡 |
|
|
58
|
+
| 5 | quiet-inject | PreToolUse | quiet フラグ自動注入 |
|
|
59
|
+
| 6 | evidence | PostToolUse | SHA-256 ハッシュチェーン証跡 |
|
|
60
|
+
| 7 | output-control | PostToolUse | 出力トランケーション + トークン予算 |
|
|
61
|
+
| 8 | dep-audit | PostToolUse | パッケージインストール検出 |
|
|
62
|
+
| 9 | lint-on-save | PostToolUse | 自動 lint 実行 |
|
|
63
|
+
| 10 | session-start | SessionStart | セッション初期化 + 整合性ベースライン |
|
|
64
|
+
| 11 | session-end | SessionEnd | クリーンアップ + 統計 |
|
|
65
|
+
| 12 | circuit-breaker | Stop | リトライ上限 (3 回) |
|
|
66
|
+
| 13 | config-guard | ConfigChange | 設定変更の監視 |
|
|
67
|
+
| 14 | user-prompt | UserPromptSubmit | ユーザー入力のインジェクション検査 |
|
|
68
|
+
| 15 | permission-learn | PermissionRequest | 権限学習ガード |
|
|
69
|
+
| 16 | elicitation | Elicitation | フィッシング + スコープガード |
|
|
70
|
+
| 17 | subagent | SubagentStart | サブエージェント予算制約 (25%) |
|
|
71
|
+
| 18 | instructions | InstructionsLoaded | ルールファイル整合性監視 |
|
|
72
|
+
| 19 | precompact | PreCompact | コンパクション前バックアップ |
|
|
73
|
+
| 20 | postcompact | PostCompact | コンパクション後復元 + 検証 |
|
|
74
|
+
| 21 | worktree | WorktreeCreate/Remove | セキュリティ伝播 + 証跡マージ |
|
|
75
|
+
| 22 | task-gate | TaskCompleted | テストゲート |
|
|
76
|
+
|
|
77
|
+
## パイプライン
|
|
78
|
+
|
|
79
|
+
STG ゲート駆動の自動化パイプライン:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
STG0 → STG1 → STG2 → STG3 → STG4 → STG5 → STG6
|
|
83
|
+
要件 設計 実装 検証 CI コミット PR/マージ
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## チャンネル連携
|
|
87
|
+
|
|
88
|
+
Claude Code Channels (Telegram/Discord) との連携をサポート。
|
|
89
|
+
チャンネル経由のメッセージには自動的に severity boost が適用されます。
|
|
90
|
+
|
|
91
|
+
## システム要件
|
|
92
|
+
|
|
93
|
+
| ツール | バージョン | 用途 | 必須/任意 |
|
|
94
|
+
| ------------ | ------------ | ------------------------ | -------------- |
|
|
95
|
+
| Git | 2.x | バージョン管理 | 必須 |
|
|
96
|
+
| Git Bash | (Git 同梱) | フックスクリプト実行環境 | 必須 (Windows) |
|
|
97
|
+
| Node.js | 18+ | フック実行 + NFKC 正規化 | 必須 |
|
|
98
|
+
| jq | 1.6+ | フック内 JSON 処理 | 必須 |
|
|
99
|
+
| yq | v4+ (Go版) | backlog.yaml 操作 | 必須 |
|
|
100
|
+
| PowerShell 7 | 7.x (`pwsh`) | sync スクリプト | 推奨 |
|
|
101
|
+
| GitHub CLI | 2.x (`gh`) | PR 作成・マージ自動化 | 任意 |
|
|
102
|
+
|
|
103
|
+
OS: Windows ネイティブファースト(Git Bash 環境)、WSL2/Linux 互換。
|
|
104
|
+
|
|
105
|
+
## ライセンス
|
|
106
|
+
|
|
107
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# Shield Harness
|
|
4
|
+
|
|
5
|
+
**Security harness for Claude Code — zero-hassle, hooks-driven defense**
|
|
6
|
+
|
|
7
|
+
[](#)
|
|
8
|
+
[](README.ja.md)
|
|
9
|
+
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
## What is Shield Harness
|
|
13
|
+
|
|
14
|
+
A security harness that governs Claude Code through multi-layered defense:
|
|
15
|
+
hooks + rules + permissions + settings deployed in the `.claude/` directory.
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx shield-harness init [--profile minimal|standard|strict]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Why Shield Harness
|
|
24
|
+
|
|
25
|
+
- **Hooks-driven defense**: 22 security hooks monitor every Claude Code operation
|
|
26
|
+
- **Approval-free mode**: Delegate all security decisions to hooks, eliminating human approval dialogs
|
|
27
|
+
- **fail-close principle**: Automatically stops when safety conditions cannot be verified
|
|
28
|
+
- **Evidence recording**: Tamper-proof SHA-256 hash chain records all allow/deny decisions
|
|
29
|
+
|
|
30
|
+
## Architecture Overview
|
|
31
|
+
|
|
32
|
+
3-layer defense model:
|
|
33
|
+
|
|
34
|
+
| Layer | Defense | Implementation |
|
|
35
|
+
| ------- | ------------------ | -------------------------------- |
|
|
36
|
+
| Layer 1 | Permission control | `settings.json` deny/allow rules |
|
|
37
|
+
| Layer 2 | Hook defense | 22 Node.js hook scripts |
|
|
38
|
+
| Layer 3 | Sandbox | OS-level process isolation |
|
|
39
|
+
|
|
40
|
+
## Profiles
|
|
41
|
+
|
|
42
|
+
| Profile | Description | Approval-free | Use case |
|
|
43
|
+
| ------------ | -------------- | ------------- | ------------------------------------------- |
|
|
44
|
+
| **minimal** | Minimal config | Enabled | Low-risk tasks |
|
|
45
|
+
| **standard** | Recommended | Enabled | Normal development |
|
|
46
|
+
| **strict** | Strict config | Disabled | When security audit requires human approval |
|
|
47
|
+
|
|
48
|
+
## Hook Catalog
|
|
49
|
+
|
|
50
|
+
| # | Hook | Event | Responsibility |
|
|
51
|
+
| --- | ---------------- | --------------------- | ------------------------------------------------ |
|
|
52
|
+
| 1 | permission | PreToolUse | 4-category tool usage classification |
|
|
53
|
+
| 2 | gate | PreToolUse | 7 attack vector inspection for Bash commands |
|
|
54
|
+
| 3 | injection-guard | PreToolUse | 9-category 50+ pattern injection detection |
|
|
55
|
+
| 4 | data-boundary | PreToolUse | Production data boundary + jurisdiction tracking |
|
|
56
|
+
| 5 | quiet-inject | PreToolUse | Auto-inject quiet flags |
|
|
57
|
+
| 6 | evidence | PostToolUse | SHA-256 hash chain evidence |
|
|
58
|
+
| 7 | output-control | PostToolUse | Output truncation + token budget |
|
|
59
|
+
| 8 | dep-audit | PostToolUse | Package install detection |
|
|
60
|
+
| 9 | lint-on-save | PostToolUse | Auto lint execution |
|
|
61
|
+
| 10 | session-start | SessionStart | Session init + integrity baseline |
|
|
62
|
+
| 11 | session-end | SessionEnd | Cleanup + statistics |
|
|
63
|
+
| 12 | circuit-breaker | Stop | Retry limit (3 attempts) |
|
|
64
|
+
| 13 | config-guard | ConfigChange | Settings change monitoring |
|
|
65
|
+
| 14 | user-prompt | UserPromptSubmit | User input injection scanning |
|
|
66
|
+
| 15 | permission-learn | PermissionRequest | Permission learning guard |
|
|
67
|
+
| 16 | elicitation | Elicitation | Phishing + scope guard |
|
|
68
|
+
| 17 | subagent | SubagentStart | Subagent budget constraint (25%) |
|
|
69
|
+
| 18 | instructions | InstructionsLoaded | Rule file integrity monitoring |
|
|
70
|
+
| 19 | precompact | PreCompact | Pre-compaction backup |
|
|
71
|
+
| 20 | postcompact | PostCompact | Post-compaction restore + verify |
|
|
72
|
+
| 21 | worktree | WorktreeCreate/Remove | Security propagation + evidence merge |
|
|
73
|
+
| 22 | task-gate | TaskCompleted | Test gate |
|
|
74
|
+
|
|
75
|
+
## Pipeline
|
|
76
|
+
|
|
77
|
+
STG gate-driven automation pipeline:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
STG0 → STG1 → STG2 → STG3 → STG4 → STG5 → STG6
|
|
81
|
+
Reqs Design Impl Verify CI Commit PR/Merge
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Channel Integration
|
|
85
|
+
|
|
86
|
+
Supports Claude Code Channels (Telegram/Discord).
|
|
87
|
+
Channel-sourced messages automatically receive severity boost for enhanced security.
|
|
88
|
+
|
|
89
|
+
## System Requirements
|
|
90
|
+
|
|
91
|
+
| Tool | Version | Purpose | Required |
|
|
92
|
+
| ------------ | ------------------ | ----------------------------------- | ------------------ |
|
|
93
|
+
| Git | 2.x | Version control | Required |
|
|
94
|
+
| Git Bash | (bundled with Git) | Hook script runtime | Required (Windows) |
|
|
95
|
+
| Node.js | 18+ | Hook execution + NFKC normalization | Required |
|
|
96
|
+
| jq | 1.6+ | JSON processing in hooks | Required |
|
|
97
|
+
| yq | v4+ (Go) | backlog.yaml operations | Required |
|
|
98
|
+
| PowerShell 7 | 7.x (`pwsh`) | Sync scripts | Recommended |
|
|
99
|
+
| GitHub CLI | 2.x (`gh`) | PR creation/merge automation | Optional |
|
|
100
|
+
|
|
101
|
+
OS: Windows-native first (Git Bash), WSL2/Linux compatible.
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
MIT
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
|
|
7
|
+
const PROFILES = ["minimal", "standard", "strict"];
|
|
8
|
+
const DEFAULT_PROFILE = "standard";
|
|
9
|
+
|
|
10
|
+
// Source directories within the npm package
|
|
11
|
+
const PKG_ROOT = path.resolve(__dirname, "..");
|
|
12
|
+
const HOOK_SRC = path.join(PKG_ROOT, ".claude", "hooks");
|
|
13
|
+
const PATTERN_SRC = path.join(PKG_ROOT, ".claude", "patterns");
|
|
14
|
+
const RULES_SRC = path.join(PKG_ROOT, ".claude", "rules");
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Recursively copy a directory.
|
|
18
|
+
* @param {string} src
|
|
19
|
+
* @param {string} dest
|
|
20
|
+
*/
|
|
21
|
+
function copyDir(src, dest) {
|
|
22
|
+
if (!fs.existsSync(src)) return;
|
|
23
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
24
|
+
|
|
25
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
26
|
+
const srcPath = path.join(src, entry.name);
|
|
27
|
+
const destPath = path.join(dest, entry.name);
|
|
28
|
+
|
|
29
|
+
if (entry.isDirectory()) {
|
|
30
|
+
copyDir(srcPath, destPath);
|
|
31
|
+
} else {
|
|
32
|
+
fs.copyFileSync(srcPath, destPath);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Main init command.
|
|
39
|
+
* @param {string} profile
|
|
40
|
+
*/
|
|
41
|
+
function init(profile) {
|
|
42
|
+
const targetDir = process.cwd();
|
|
43
|
+
const claudeDir = path.join(targetDir, ".claude");
|
|
44
|
+
const shieldHarnessDir = path.join(targetDir, ".shield-harness");
|
|
45
|
+
|
|
46
|
+
// Check if already initialized
|
|
47
|
+
if (fs.existsSync(path.join(claudeDir, "hooks", "sh-gate.js"))) {
|
|
48
|
+
console.error("Shield Harness is already initialized in this directory.");
|
|
49
|
+
console.error("To re-initialize, remove .claude/hooks/sh-*.js first.");
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.log(`Initializing Shield Harness (profile: ${profile})...`);
|
|
54
|
+
|
|
55
|
+
// Copy hooks
|
|
56
|
+
copyDir(HOOK_SRC, path.join(claudeDir, "hooks"));
|
|
57
|
+
console.log(" [OK] hooks/");
|
|
58
|
+
|
|
59
|
+
// Copy patterns
|
|
60
|
+
copyDir(PATTERN_SRC, path.join(claudeDir, "patterns"));
|
|
61
|
+
console.log(" [OK] patterns/");
|
|
62
|
+
|
|
63
|
+
// Copy rules
|
|
64
|
+
copyDir(RULES_SRC, path.join(claudeDir, "rules"));
|
|
65
|
+
console.log(" [OK] rules/");
|
|
66
|
+
|
|
67
|
+
// Create .shield-harness runtime directories
|
|
68
|
+
fs.mkdirSync(path.join(shieldHarnessDir, "config"), { recursive: true });
|
|
69
|
+
fs.mkdirSync(path.join(shieldHarnessDir, "logs"), { recursive: true });
|
|
70
|
+
fs.mkdirSync(path.join(shieldHarnessDir, "state"), { recursive: true });
|
|
71
|
+
console.log(" [OK] .shield-harness/");
|
|
72
|
+
|
|
73
|
+
// Create default pipeline config
|
|
74
|
+
const pipelineConfig = {
|
|
75
|
+
auto_commit: false,
|
|
76
|
+
auto_push: false,
|
|
77
|
+
auto_pr: false,
|
|
78
|
+
auto_merge: false,
|
|
79
|
+
auto_branch_cleanup: false,
|
|
80
|
+
commit_message_format: "[{task_id}] STG{gate}: {intent}",
|
|
81
|
+
pr_template: ".github/pull_request_template.md",
|
|
82
|
+
protected_branches: ["main", "master"],
|
|
83
|
+
approval_free: profile !== "strict",
|
|
84
|
+
sync_views_on_commit: true,
|
|
85
|
+
sync_views_on_session_start: true,
|
|
86
|
+
auto_tag: false,
|
|
87
|
+
version_bump: "patch",
|
|
88
|
+
auto_pickup_next_task: false,
|
|
89
|
+
auto_skip_blocked: false,
|
|
90
|
+
blocked_notification_channel: null,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const configPath = path.join(
|
|
94
|
+
shieldHarnessDir,
|
|
95
|
+
"config",
|
|
96
|
+
"pipeline-config.json",
|
|
97
|
+
);
|
|
98
|
+
if (!fs.existsSync(configPath)) {
|
|
99
|
+
fs.writeFileSync(
|
|
100
|
+
configPath,
|
|
101
|
+
JSON.stringify(pipelineConfig, null, 2) + "\n",
|
|
102
|
+
);
|
|
103
|
+
console.log(" [OK] pipeline-config.json");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
console.log("");
|
|
107
|
+
console.log(`Shield Harness initialized successfully (profile: ${profile}).`);
|
|
108
|
+
console.log("Run 'claude' to start a secured session.");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
// CLI
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
|
|
115
|
+
const args = process.argv.slice(2);
|
|
116
|
+
const command = args[0];
|
|
117
|
+
|
|
118
|
+
if (command === "init") {
|
|
119
|
+
let profile = DEFAULT_PROFILE;
|
|
120
|
+
const profileIdx = args.indexOf("--profile");
|
|
121
|
+
if (profileIdx !== -1 && args[profileIdx + 1]) {
|
|
122
|
+
profile = args[profileIdx + 1];
|
|
123
|
+
if (!PROFILES.includes(profile)) {
|
|
124
|
+
console.error(`Unknown profile: ${profile}`);
|
|
125
|
+
console.error(`Available profiles: ${PROFILES.join(", ")}`);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
init(profile);
|
|
130
|
+
} else {
|
|
131
|
+
const pkg = require("../package.json");
|
|
132
|
+
console.log(`Shield Harness v${pkg.version}`);
|
|
133
|
+
console.log("");
|
|
134
|
+
console.log("Usage:");
|
|
135
|
+
console.log(" npx shield-harness init [--profile minimal|standard|strict]");
|
|
136
|
+
console.log("");
|
|
137
|
+
console.log("Profiles:");
|
|
138
|
+
console.log(" minimal — Minimal config, approval-free");
|
|
139
|
+
console.log(" standard — Recommended (default), approval-free");
|
|
140
|
+
console.log(" strict — Strict config, requires human approval");
|
|
141
|
+
}
|