haechi 0.3.2 → 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/README.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Haechi
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/haechi)](https://www.npmjs.com/package/haechi)
4
+ [![CI](https://github.com/raeseoklee/haechi/actions/workflows/ci.yml/badge.svg)](https://github.com/raeseoklee/haechi/actions/workflows/ci.yml)
5
+ [![license](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
6
+ [![node](https://img.shields.io/node/v/haechi)](https://nodejs.org)
7
+ [![status](https://img.shields.io/badge/status-developer%20preview-orange)](docs/current/risk-register-release-gate.md)
8
+
3
9
  Haechi is an experimental developer preview of a self-hosted AI context enforcement layer for protecting LLM, MCP, vLLM, Ollama, and agent payloads before they reach models, tools, logs, or proxies.
4
10
 
5
11
  The name comes from Haechi, a Korean guardian figure associated with discernment and protection.
@@ -12,9 +18,27 @@ The current developer-preview scope focuses on local adoption:
12
18
  - `haechi protect`: inspect and protect an OpenAI-compatible JSON payload
13
19
  - `haechi report`: summarize audit events without raw payloads
14
20
  - `haechi proxy`: run a local HTTP JSON proxy for existing LLM calls
21
+ - `haechi status`: show what is and is not protected under the current config
22
+ - `haechi audit-verify`: verify the audit hash chain and print its head hash
23
+ - `haechi mcp-wrap -- <command>`: wrap an MCP server with bidirectional stdio protection
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ npm install -g haechi
29
+ haechi init
30
+ ```
31
+
32
+ Or run without installing:
33
+
34
+ ```bash
35
+ npx haechi init
36
+ ```
15
37
 
16
38
  ## Quickstart
17
39
 
40
+ From a clone of this repository:
41
+
18
42
  ```bash
19
43
  npm test
20
44
  npm run demo:init
@@ -66,6 +90,96 @@ Haechi 0.3 includes protocol adapter presets for OpenAI-compatible servers, vLLM
66
90
 
67
91
  Then point an OpenAI-compatible client at `http://127.0.0.1:1016/v1`. For Ollama native APIs, use `target.adapter: "ollama"` and call `/api/chat` or `/api/generate` through the proxy.
68
92
 
93
+ ## Token Round-Trip
94
+
95
+ With tokenization the model sees stable tokens while the caller gets plaintext back:
96
+
97
+ ```json
98
+ {
99
+ "policy": { "mode": "enforce", "actions": { "email": "tokenize" } },
100
+ "responseProtection": { "enabled": true, "mode": "enforce" },
101
+ "tokenVault": {
102
+ "deterministic": true,
103
+ "detokenizeResponses": true
104
+ }
105
+ }
106
+ ```
107
+
108
+ - `tokenVault.deterministic` (default `false`): the same value always maps to the same token (HMAC over a domain-separated key derived from the local key — never the raw AES key). Required for multi-turn chats, since resent history re-tokenizes into the same tokens. **Trade-off:** equal values become linkable across requests. `deterministicTypes` (e.g. `["email"]`) limits determinism to selected types.
109
+ - `tokenVault.detokenizeResponses` (default `false`): restores **only the tokens issued while protecting the same request** in that request's response. Tokens from other clients or requests are never restored. Independent of `revealPolicy`; every restoration is audited by count, never by value. Requires `responseProtection.enabled`.
110
+
111
+ ## MCP Wrap
112
+
113
+ Wrap any stdio MCP server so its traffic is filtered in both directions — change only the command in your MCP client config:
114
+
115
+ ```json
116
+ {
117
+ "mcpServers": {
118
+ "some-server": {
119
+ "command": "npx",
120
+ "args": ["-y", "haechi", "mcp-wrap", "--config", "/path/haechi.config.json", "--", "npx", "some-mcp-server"]
121
+ }
122
+ }
123
+ }
124
+ ```
125
+
126
+ Client→server requests pass the `mcp.allowedMethods` allowlist and params protection; server→client results get params/result protection plus injection heuristics (see below). Rejections are answered to the client and never reach the server; stderr and exit codes pass through.
127
+
128
+ ## Injection Detection (Preview)
129
+
130
+ Response and tool-result text is screened with heuristic rules for indirect prompt injection (instruction overrides, role reassignment, prompt markers, conceal-from-user phrasing, covert tool induction). The `injection` type is **report-only by default**: detections are written to the audit log but nothing is modified or blocked. Escalate explicitly once you trust the signal:
131
+
132
+ ```json
133
+ { "policy": { "actions": { "injection": "block" } } }
134
+ ```
135
+
136
+ These heuristics are not a complete defense against prompt injection; see `docs/current/threat-model.md`.
137
+
138
+ ## Configuration
139
+
140
+ `haechi init` writes `haechi.config.json`; a non-secret template lives at `haechi.config.example.json`. All keys validate fail-closed — unknown or malformed values refuse to start.
141
+
142
+ | Key | Default | Meaning |
143
+ |---|---|---|
144
+ | `mode` / `policy.mode` | `dry-run` | `dry-run` and `report-only` detect + audit only; `enforce` transforms/blocks. `policy.mode` wins over `mode` |
145
+ | `target.type` / `target.adapter` | `llm-http` / `openai-compatible` | Upstream protocol: `openai-compatible`, `vllm-openai`, `ollama`, `llama-cpp`. Unknown types fail closed |
146
+ | `target.upstream` | `http://127.0.0.1:9999` | The only upstream the proxy will forward to (absolute-URL request targets are rejected) |
147
+ | `proxy.host` / `proxy.port` | `127.0.0.1` / `1016` | Proxy bind address. See remote binding below |
148
+ | `responseProtection.enabled` | `false` | Inspect upstream JSON responses. `failureMode: fail-closed` rejects non-JSON/compressed/oversized responses |
149
+ | `responseProtection.maxBytes` | `1048576` | Hard response size cap — enforced even in `failureMode: allow` |
150
+ | `streaming.requestMode` | `block` | `stream: true` requests get 501 unless `pass-through` (uninspected, audited). Ollama chat/generate count as streaming unless `stream: false` |
151
+ | `limits.maxRequestBytes` | `1048576` | Request body cap (413 over the limit) |
152
+ | `limits.upstreamTimeoutMs` | `120000` | Upstream timeout (504 on expiry) |
153
+ | `policy.presets` | `korean-pii`, `secrets-only`, `llm-redact` | Merged preset actions; merges can strengthen but never weaken |
154
+ | `policy.actions` | `card: block` | Per-type action: `allow`/`redact`/`mask`/`tokenize`/`encrypt`/`block` |
155
+ | `filters.customRules` | `[]` | Extra regex rules (ReDoS-screened: no nested quantifiers/backreferences) |
156
+ | `keys.provider` / `keys.keyFile` | `local` / `.haechi/dev.keys.json` | Dev-only software keys (0600). `external` requires injecting a crypto provider programmatically |
157
+ | `audit.path` | `.haechi/audit.jsonl` | Hash-chained JSONL audit log; verify with `haechi audit-verify` |
158
+ | `tokenVault.revealPolicy` | `disabled` | Manual reveal gate (`local-dev` to enable; every decision is audited) |
159
+ | `tokenVault.retentionDays` | `30` | Expired tokens are deleted on vault writes or `haechi token-purge --expired` |
160
+ | `tokenVault.deterministic` / `deterministicTypes` / `detokenizeResponses` | `false` / `null` / `false` | Token round-trip (see above) |
161
+ | `privacy.profile` | `null` | `kr-pipa`, `eu-gdpr`, `us-general` baseline actions (strengthen-only) |
162
+ | `mcp.allowedMethods` | `initialize`, `tools/call`, `resources/read`, `prompts/get` | Client-callable method allowlist for `mcp-stdio`/`mcp-wrap` |
163
+
164
+ Check the effective state at any time:
165
+
166
+ ```bash
167
+ haechi status
168
+ ```
169
+
170
+ ### Binding beyond loopback (0.0.0.0)
171
+
172
+ The proxy refuses non-loopback hosts unless the CLI flag is given explicitly — setting `proxy.host: "0.0.0.0"` in config alone will not start, by design (copying a config file must not silently expose the gateway):
173
+
174
+ ```bash
175
+ haechi proxy --config haechi.config.json --host 0.0.0.0 --allow-remote-bind
176
+ ```
177
+
178
+ **The proxy has no client authentication yet** (planned for 0.6): anyone who can reach the port can use your upstream and the token round-trip path. Use `--allow-remote-bind` only behind explicit network controls:
179
+
180
+ - **Containers**: binding `0.0.0.0` inside a container is the normal pattern — restrict exposure at the port mapping, e.g. `-p 127.0.0.1:1016:1016`
181
+ - **LAN/remote**: put a firewall, VPN (e.g. Tailscale), or an authenticating reverse proxy in front
182
+
69
183
  ## Privacy Profiles
70
184
 
71
185
  Haechi includes baseline regional privacy profiles for local policy bootstrapping:
@@ -100,3 +214,5 @@ Set `privacy.profile` in `haechi.config.json` to apply the profile's default act
100
214
  0.3.1 adds release safety gates, response fail-closed behavior, audit hash chaining, token reveal governance, provider injection, privacy profiles, CI/SBOM/provenance workflow scaffolding, and dedicated threat/shared-responsibility/API-stability docs.
101
215
 
102
216
  0.3.2 is a security-hardening release and the first npm developer preview target: Ollama implicit-streaming fail-closed handling, audited token reveal/purge, retention purge, kid-based key rotation, domain-separated policy bundle signing, JSON number/object key detection, upstream timeouts, stale lock recovery, and non-enforcing-mode warnings. See `docs/current/release-0.3.2-hardening-scope.md`.
217
+
218
+ 0.4.0 adds the token round-trip (deterministic tokenization + request-scoped response detokenization), the `mcp-wrap` bidirectional MCP filter, `status` and `audit-verify` commands, report-only injection detection heuristics, and reserves the PII-safe `identity`/`authProvider` contracts for 0.6 auth. See `docs/current/release-0.4-implementation-scope.md`.
@@ -2,7 +2,7 @@
2
2
 
3
3
  - 문서 상태: Draft 0.1
4
4
  - 작성일: 2026-06-10
5
- - 기준 버전: 0.3.2
5
+ - 기준 버전: 0.4.0
6
6
 
7
7
  ## 1. 버전 해석
8
8
 
@@ -11,8 +11,9 @@
11
11
  | 버전 범위 | 의미 |
12
12
  |---|---|
13
13
  | `0.3.x` | local inference/proxy safety patch line |
14
- | `0.4.x` | streaming/deployment hardening target |
15
- | `0.5.x` | key custody/audit hardening target |
14
+ | `0.4.x` | token round-trip and adoption line |
15
+ | `0.5.x` | streaming hardening target |
16
+ | `0.6.x` | auth 및 운영 통제 target |
16
17
  | `1.0.0` | API compatibility contract를 선언할 수 있는 첫 stable 후보 |
17
18
 
18
19
  ## 2. 변경 정책
@@ -28,13 +29,18 @@
28
29
 
29
30
  ## 3. Experimental exports
30
31
 
31
- 다음 export는 0.3.2에서 preview로 취급한다.
32
+ 다음 export는 0.4.0에서 preview로 취급한다.
32
33
 
33
34
  - `haechi/runtime`
34
35
  - `haechi/proxy`
35
36
  - `haechi/protocol-adapters`
36
37
  - `haechi/privacy-profiles`
37
38
  - `haechi/plugin`
39
+ - `haechi/mcp-stdio` `wrapMcpChild`
40
+ - `haechi/token-vault` `detokenize`, deterministic tokenization 옵션
41
+ - `injection` detection type과 휴리스틱 룰
42
+ - `identity` audit 필드와 `authProvider` 계약 (0.4 예약, 0.6 구현 — 그 전까지 형태 변경 가능)
43
+ - `status` / `audit-verify` CLI 출력 형태
38
44
 
39
45
  ## 4. Migration note 기준
40
46
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  - Status: Draft 0.1
4
4
  - Date: 2026-06-10
5
- - Target version: 0.3.2
5
+ - Target version: 0.4.0
6
6
 
7
7
  ## 1. Version Interpretation
8
8
 
@@ -11,8 +11,9 @@
11
11
  | Version range | Meaning |
12
12
  |---|---|
13
13
  | `0.3.x` | local inference/proxy safety patch line |
14
- | `0.4.x` | streaming/deployment hardening target |
15
- | `0.5.x` | key custody/audit hardening target |
14
+ | `0.4.x` | token round-trip and adoption line |
15
+ | `0.5.x` | streaming hardening target |
16
+ | `0.6.x` | auth and operational controls target |
16
17
  | `1.0.0` | First stable candidate at which an API compatibility contract may be declared |
17
18
 
18
19
  ## 2. Change Policy
@@ -28,13 +29,18 @@
28
29
 
29
30
  ## 3. Experimental exports
30
31
 
31
- The following exports are treated as preview in 0.3.2.
32
+ The following exports are treated as preview in 0.4.0.
32
33
 
33
34
  - `haechi/runtime`
34
35
  - `haechi/proxy`
35
36
  - `haechi/protocol-adapters`
36
37
  - `haechi/privacy-profiles`
37
38
  - `haechi/plugin`
39
+ - `haechi/mcp-stdio` `wrapMcpChild`
40
+ - `haechi/token-vault` `detokenize`, deterministic tokenization options
41
+ - `injection` detection type and its heuristic rules
42
+ - `identity` audit field and the `authProvider` contract (reserved in 0.4, implemented in 0.6 — shape may change until then)
43
+ - `status` / `audit-verify` CLI output shapes
38
44
 
39
45
  ## 4. Migration note criteria
40
46
 
@@ -4,12 +4,13 @@
4
4
  - 작성일: 2026-06-10
5
5
  - 기준 버전: 0.3.2
6
6
  - 성격: 보안 하드닝 릴리스, 첫 npm developer preview 배포 대상
7
+ - 배포: 2026-06-10 — npm `haechi@0.3.2` (로컬 패스키 publish, provenance 이월), `v0.3.2` 태그, GitHub pre-release
7
8
 
8
9
  ## 1. 배경
9
10
 
10
11
  0.3.1 전체 코드 리뷰에서 식별된 16건의 리스크를 해소한 릴리스다. 상세 리스크 목록과 해소 증거는 `risk-register-release-gate.md` 5.2절(P0-SEC-016 ~ P2-DOC-005)을 따른다.
11
12
 
12
- npm에 한 번도 배포된 적이 없으므로 0.3.2가 첫 배포 버전이다. 첫 배포를 기능 릴리스(0.4.0)와 분리해 패키지 이름 소유권 확정과 publish 파이프라인(provenance, GitHub release workflow) 검증을 저위험 릴리스에서 먼저 통과시킨다.
13
+ npm에 한 번도 배포된 적이 없었으므로 0.3.2가 첫 배포 버전이다. 첫 배포를 기능 릴리스(0.4.0)와 분리해 패키지 이름 소유권을 저위험 릴리스에서 확정했고, provenance 기반 GitHub Actions publish 경로는 후속 하드닝 항목으로 이월한다.
13
14
 
14
15
  ## 2. 변경 요약
15
16
 
@@ -4,12 +4,13 @@
4
4
  - Date: 2026-06-10
5
5
  - Target version: 0.3.2
6
6
  - Type: Security hardening release; first npm developer preview distribution target
7
+ - Published: 2026-06-10 — `haechi@0.3.2` on npm (local passkey publish; provenance deferred), tag `v0.3.2`, GitHub pre-release
7
8
 
8
9
  ## 1. Background
9
10
 
10
11
  This release resolves the 16 risks identified during the full 0.3.1 code review. The detailed risk list and closure evidence follow `risk-register-release-gate.md` section 5.2 (P0-SEC-016 through P2-DOC-005).
11
12
 
12
- Because no version has ever been published to npm, 0.3.2 is the first published version. Separating the first publication from a feature release (0.4.0) allows package-name ownership to be confirmed and the publish pipeline (provenance, GitHub release workflow) to be validated in a low-risk release first.
13
+ Because no version had ever been published to npm before 0.3.2, this is the first published version. Separating the first publication from a feature release (0.4.0) confirmed package-name ownership in a low-risk release while leaving the provenance-backed GitHub Actions publish path as a follow-up hardening item.
13
14
 
14
15
  ## 2. Change Summary
15
16
 
@@ -1,9 +1,10 @@
1
1
  # Haechi 0.4 Implementation Scope
2
2
 
3
- - 문서 상태: Draft 0.1
3
+ - 문서 상태: Final
4
4
  - 작성일: 2026-06-10
5
5
  - 기준 버전: 0.4.0 (0.3.2 이후)
6
6
  - 주제: token round-trip and adoption
7
+ - 구현 완료: 2026-06-10 — PR #7 (round-trip), #8 (audit-verify/status), #9 (mcp-wrap), #10 (injection + identity 예약)
7
8
 
8
9
  ## 1. 릴리스 목표
9
10
 
@@ -1,9 +1,10 @@
1
1
  # Haechi 0.4 Implementation Scope
2
2
 
3
- - Status: Draft 0.1
3
+ - Status: Final
4
4
  - Date: 2026-06-10
5
5
  - Target version: 0.4.0 (after 0.3.2)
6
6
  - Type: token round-trip and adoption
7
+ - Shipped: 2026-06-10 — PRs #7 (round-trip), #8 (audit-verify/status), #9 (mcp-wrap), #10 (injection + identity reservation)
7
8
 
8
9
  ## 1. Release Goals
9
10
 
@@ -12,7 +12,7 @@ npm run sbom
12
12
  npm run bench:payload
13
13
  ```
14
14
 
15
- `release:preflight`는 테스트, stale-name scan, pack dry-run을 실행한다. npm 계정 인증과 package ownership 확인까지 포함하려면 다음을 사용한다.
15
+ `release:preflight`는 테스트, 타입 체크, stale-name scan, pack dry-run을 실행한다. npm 계정 인증과 package ownership 확인까지 포함하려면 다음을 사용한다.
16
16
 
17
17
  ```bash
18
18
  npm run release:preflight:npm
@@ -20,13 +20,22 @@ npm run release:preflight:npm
20
20
 
21
21
  첫 publish 전에는 `npm view <package> version`이 `E404 Not Found`를 반환하는 것이 정상이다. 이 경우 preflight는 인증된 계정에서 이름을 claim할 준비가 된 상태로 통과한다. 단, `npm view <package>@<version> version`이 성공하면 같은 버전을 다시 배포할 수 없으므로 실패한다.
22
22
 
23
- ## 2. npm provenance
23
+ ## 2. npm provenance와 trusted publishing
24
24
 
25
- npm provenance는 GitHub Actions release workflow에서 생성한다. 공식 npm 문서의 요구사항에 맞춰 GitHub-hosted runner, `id-token: write`, `npm publish --provenance --access public`을 사용한다.
25
+ 의도된 publish 경로는 GitHub Actions trusted publishing이다: npm이 release workflow OIDC로 인증하고 provenance 증명을 자동 생성한다. 공식 npm 요구사항에 따라 GitHub-hosted runner, `id-token: write`, 연결된 workflow에서의 publish 필요하다.
26
+
27
+ **현재 상태: trusted publishing 구성 완료, 첫 증명 릴리스 대기.** `haechi@0.3.2`는 로컬 머신에서 패스키 인증과 `--provenance=false`로 배포되어 해당 버전의 provenance 증명이 존재하지 않는다. 활성화 runbook과 진행 상태:
28
+
29
+ 1. ✅ npmjs.com에서: package settings → Trusted Publisher → `raeseoklee/haechi` 저장소와 `npm-publish.yml` workflow 연결 (2026-06-10).
30
+ 2. ✅ `.github/workflows/npm-publish.yml` OIDC 인증 전환 (2026-06-10): `NODE_AUTH_TOKEN`과 `registry-url` 제거, runner의 npm CLI를 `>= 11.5.1`로 업그레이드.
31
+ 3. ⏳ 다음 릴리스 후 `npm view haechi --json`(`dist.attestations`)으로 증명을 확인. OIDC 경로는 아직 실제 publish를 수행한 적이 없으며, 잘못 구성된 경우 publish 시점에 fail-closed로 실패한다.
32
+
33
+ provenance 없이 수행한 publish는 release note에 갭을 명시적으로 기록해야 한다(`CONTRIBUTING.md` 참조).
26
34
 
27
35
  참고:
28
36
 
29
37
  - https://docs.npmjs.com/generating-provenance-statements/
38
+ - https://docs.npmjs.com/trusted-publishers/
30
39
  - https://docs.github.com/actions/publishing-packages/publishing-nodejs-packages
31
40
 
32
41
  ## 3. GitHub Actions
@@ -34,7 +43,7 @@ npm provenance는 GitHub Actions release workflow에서 생성한다. 공식 npm
34
43
  | Workflow | 목적 |
35
44
  |---|---|
36
45
  | `.github/workflows/ci.yml` | test, release preflight, SBOM artifact |
37
- | `.github/workflows/npm-publish.yml` | GitHub release published 이벤트에서 npm provenance publish |
46
+ | `.github/workflows/npm-publish.yml` | GitHub release published 이벤트에서 npm publish (trusted publishing 구성 후 provenance 경로) |
38
47
 
39
48
  ## 4. 배포 차단 조건
40
49
 
@@ -46,3 +55,4 @@ npm provenance는 GitHub Actions release workflow에서 생성한다. 공식 npm
46
55
  - SBOM 생성 실패
47
56
  - npm package name ownership 불확실
48
57
  - README/SECURITY가 developer preview와 production 제한을 명시하지 않음
58
+ - trusted publishing/provenance가 미구성인데 release note에 provenance 갭을 명시하지 않음
@@ -12,7 +12,7 @@ npm run sbom
12
12
  npm run bench:payload
13
13
  ```
14
14
 
15
- `release:preflight` runs tests, a stale-name scan, and a pack dry-run. To also verify npm account authentication and package ownership, use:
15
+ `release:preflight` runs tests, a type check, a stale-name scan, and a pack dry-run. To also verify npm account authentication and package ownership, use:
16
16
 
17
17
  ```bash
18
18
  npm run release:preflight:npm
@@ -20,13 +20,22 @@ npm run release:preflight:npm
20
20
 
21
21
  Before the first publish, it is normal for `npm view <package> version` to return `E404 Not Found`. In that case, preflight passes with the package name ready to be claimed from an authenticated account. However, if `npm view <package>@<version> version` succeeds, the same version cannot be published again and preflight will fail.
22
22
 
23
- ## 2. npm provenance
23
+ ## 2. npm provenance and trusted publishing
24
24
 
25
- npm provenance is generated by the GitHub Actions release workflow. Following the requirements in the official npm documentation, it uses a GitHub-hosted runner, `id-token: write`, and `npm publish --provenance --access public`.
25
+ The intended publish path is GitHub Actions trusted publishing: npm authenticates the release workflow via OIDC and generates a provenance statement automatically. Per the official npm requirements this needs a GitHub-hosted runner, `id-token: write`, and a publish from the linked workflow.
26
+
27
+ **Current state: trusted publishing is configured; first attested release pending.** `haechi@0.3.2` was published from a local machine using passkey authentication with `--provenance=false`, so no provenance attestation exists for that version. The enablement runbook and its status:
28
+
29
+ 1. ✅ On npmjs.com: package settings → Trusted Publisher → linked the `raeseoklee/haechi` repository and the `npm-publish.yml` workflow (2026-06-10).
30
+ 2. ✅ `.github/workflows/npm-publish.yml` authenticates via OIDC (2026-06-10): `NODE_AUTH_TOKEN` and `registry-url` removed, npm CLI upgraded to `>= 11.5.1` in the runner.
31
+ 3. ⏳ After the next release, verify the attestation with `npm view haechi --json` (`dist.attestations`). The OIDC path has not carried a real publish yet; if misconfigured it fails closed at publish time.
32
+
33
+ Any publish performed without provenance must record the gap explicitly in the release notes (see `CONTRIBUTING.md`).
26
34
 
27
35
  References:
28
36
 
29
37
  - https://docs.npmjs.com/generating-provenance-statements/
38
+ - https://docs.npmjs.com/trusted-publishers/
30
39
  - https://docs.github.com/actions/publishing-packages/publishing-nodejs-packages
31
40
 
32
41
  ## 3. GitHub Actions
@@ -34,7 +43,7 @@ References:
34
43
  | Workflow | Purpose |
35
44
  |---|---|
36
45
  | `.github/workflows/ci.yml` | Tests, release preflight, SBOM artifact |
37
- | `.github/workflows/npm-publish.yml` | npm provenance publish on GitHub release published event |
46
+ | `.github/workflows/npm-publish.yml` | npm publish on GitHub release published event (provenance path once trusted publishing is configured) |
38
47
 
39
48
  ## 4. Deployment block conditions
40
49
 
@@ -46,3 +55,4 @@ npm publish is not performed if any of the following fail.
46
55
  - SBOM generation fails
47
56
  - npm package name ownership is uncertain
48
57
  - README/SECURITY does not explicitly state developer preview and production restrictions
58
+ - Trusted publishing/provenance is not configured and the release notes do not explicitly record the provenance gap
@@ -2,18 +2,18 @@
2
2
 
3
3
  - 문서 상태: Draft 0.3
4
4
  - 작성일: 2026-06-10
5
- - 기준 버전: 0.3.2
6
- - 기준 브랜치: `irae/risk-resolution`
5
+ - 기준 버전: 0.4.0
6
+ - 기준 브랜치: `main`
7
7
 
8
8
  ## 1. 현재 판단
9
9
 
10
- 0.3.2는 0.3.1 전체 코드 리뷰에서 식별된 추가 보안/운영 리스크를 developer preview 기준으로 해소했다. GitHub 공개와 npm developer preview 배포는 허용 가능하다. 단, 실제 npm publish는 npm 계정 인증, package ownership, GitHub release workflow 실행이라는 외부 운영자 게이트를 통과해야 한다.
10
+ 0.3.2는 0.3.1 전체 코드 리뷰에서 식별된 추가 보안/운영 리스크를 developer preview 기준으로 해소했다. 외부 운영자 게이트(npm 계정 인증, package ownership, GitHub tag/release)는 2026-06-10에 통과했다: `haechi@0.3.2`가 로컬 패스키 인증으로 npm 배포되었고, `v0.3.2` 태그와 GitHub pre-release 생성되었다. npm provenance는 GitHub Actions trusted publishing 경로로 이월한다.
11
11
 
12
12
  | 구분 | 판단 | 이유 |
13
13
  |---|---|---|
14
14
  | GitHub public | 허용 | 보안 한계, threat model, shared responsibility, developer preview 문구가 문서화됨 |
15
15
  | GitHub release/tag | 허용 | production-ready가 아닌 developer preview로 표현해야 함 |
16
- | npm developer preview | 조건부 허용 | `npm run release:preflight` 통과 후, 인증된 계정에서 `release:preflight:npm` provenance publish 필요 |
16
+ | npm developer preview | 허용 (배포 완료) | 2026-06-10 인증된 계정에서 `haechi@0.3.2` publish 완료, provenance trusted publishing으로 이월 |
17
17
  | npm stable | 보류 | 1.0 API 안정성, 운영 KMS/HSM/Vault reference adapter, stream-aware enforcement 전까지 stable 표현 금지 |
18
18
  | production use | 금지 | 0.3.2는 self-hosted developer preview이며 운영 인증/인가/key custody는 사용자 책임 |
19
19
 
@@ -23,14 +23,14 @@
23
23
  |---|---|---|---|
24
24
  | G0 | GitHub source 공개 | 테스트 통과, 보안 한계 문서화, 평문 audit leak 없음 | Pass |
25
25
  | G1 | GitHub pre-release | P0 코드 리스크 해결, production-ready 표현 없음 | Pass |
26
- | G2 | npm developer preview | P0 해결, preflight/SBOM/provenance 경로 준비, npm auth 확인 | Conditional Pass |
26
+ | G2 | npm developer preview | P0 해결, preflight/SBOM/provenance 경로 준비, npm auth 확인 | Pass (`haechi@0.3.2` 2026-06-10 배포) |
27
27
  | G3 | npm stable | P1 운영 reference, stream-aware enforcement, API stability 강화 | Blocked |
28
28
 
29
29
  ## 3. P0 배포 차단 리스크 상태
30
30
 
31
31
  | ID | 기존 리스크 | 상태 | 해소 증거 |
32
32
  |---|---|---|---|
33
- | P0-REL-001 | npm 인증/권한 미해결 | External Gate | `release:preflight:npm`, GitHub release workflow, `npm publish --provenance --access public`로 게이트화. 실제 인증은 운영자 필요 |
33
+ | P0-REL-001 | npm 인증/권한 미해결 | Resolved | 2026-06-10 로컬 패스키 인증으로 `haechi@0.3.2` publish 성공, npm 인증·package ownership 확정 |
34
34
  | P0-REL-002 | proxy 외부 노출 위험 | Resolved | non-loopback bind는 기본 실패, `--allow-remote-bind` 필요 |
35
35
  | P0-REL-003 | streaming 요청 처리 불명확 | Resolved | `stream: true` 기본 501 fail-closed, `streaming.requestMode: "pass-through"` 명시 필요 |
36
36
  | P0-REL-004 | responseProtection 실패 모드 불명확 | Resolved | 비JSON/invalid JSON/압축/대용량 응답 fail-closed, 명시 allow 정책 분리 |
@@ -58,7 +58,7 @@
58
58
  | P1-OPS-002 | SBOM/provenance 부재 | Resolved | `npm run sbom`, `.github/workflows/npm-publish.yml`, `publishConfig.provenance` |
59
59
  | P1-OPS-003 | 실제 vLLM/Ollama/llama.cpp 통합 테스트 부재 | Resolved for preview | env-gated optional local inference integration tests 추가. CI는 외부 모델 서버 없이 skip |
60
60
  | P1-OPS-004 | 성능/대용량 payload 미측정 | Resolved for preview | request/response byte limit, `npm run bench:payload` |
61
- | P1-OPS-005 | npm ownership 미확정 | External Gate | 인증된 npm 계정에서 `npm run release:preflight:npm`, publish `npm view haechi version` 필요 |
61
+ | P1-OPS-005 | npm ownership 미확정 | Resolved | `npm view haechi version`이 `0.3.2` 반환, 최초 publish 성공으로 ownership 확정 |
62
62
 
63
63
  ## 5.1 추가 보안 검토 리스크 해소 상태
64
64
 
@@ -110,9 +110,9 @@ base64/인코딩 값 디코딩 검사, query string 검사, audit tail truncatio
110
110
  현재 외부 npm 게이트 확인 결과:
111
111
 
112
112
  - `npm whoami`: `raeseoklee`
113
- - `npm view haechi version`: `E404 Not Found`
113
+ - `npm view haechi version`: `0.3.2`
114
114
 
115
- `haechi` 이름은 비어 있어 보이나, package ownership은 인증된 계정에서 최초 publish 성공해야 확정된다. `release:preflight:npm`은 인증 확인 `haechi@<현재 버전>`의 중복 publish를 차단하고, publish package E404는 통과 조건으로 처리한다.
115
+ 아래 체크리스트는 2026-06-10 0.3.2 배포에서 provenance publish 경로를 제외하고 완료되었다(`v0.3.2` 태그와 GitHub pre-release 완료). provenance는 GitHub Actions trusted publishing으로 이월하며, 체크리스트는 이후 릴리스의 템플릿으로 유지한다.
116
116
 
117
117
  1. `npm run release:preflight`
118
118
  2. `npm run sbom`
@@ -126,7 +126,7 @@ base64/인코딩 값 디코딩 검사, query string 검사, audit tail truncatio
126
126
 
127
127
  | 버전 | 목표 | 남은 범위 |
128
128
  |---|---|---|
129
- | 0.4.0 | token round-trip and adoption | 요청 스코프 response detokenization, deterministic tokenization(파생 키), `haechi mcp-wrap`(양방향 stdio), `haechi audit-verify`/`haechi status`, injection detection type(기본 allow), PII-safe `identity` 필드 및 `authProvider` 계약 예약. `docs/current/release-0.4-implementation-scope.md` 참조 |
129
+ | 0.4.0 | token round-trip and adoption | 2026-06-10 구현 완료: 요청 스코프 response detokenization, deterministic tokenization(파생 키), `haechi mcp-wrap`, `haechi audit-verify`/`haechi status`, injection detection type(기본 allow), `identity`/`authProvider` 계약 예약. `docs/current/release-0.4-implementation-scope.md` 참조 |
130
130
  | 0.5.0 | streaming hardening | SSE/NDJSON stream inspection, stream sequence AAD, replay cache, stronger remote deployment guide |
131
131
  | 0.6.0 | auth and 운영 통제 | built-in bearer auth, client별 policy scope, model allowlist/rate budget, Vault/AWS KMS reference adapter, external append-only audit sink, signed release artifacts, npm org(`@haechi/*`) 확보 |
132
132
  | 0.7.0 | observability | npm workspaces 전환, `@haechi/dashboard` read-only audit viewer (hash chain 무결성 표시, 요약/검색/타임라인) |
@@ -2,18 +2,18 @@
2
2
 
3
3
  - Status: Draft 0.3
4
4
  - Date: 2026-06-10
5
- - Target version: 0.3.2
6
- - Branch: `irae/risk-resolution`
5
+ - Target version: 0.4.0
6
+ - Branch: `main`
7
7
 
8
8
  ## 1. Current Assessment
9
9
 
10
- 0.3.2 resolves the additional security and operational risks identified during the full 0.3.1 code review, meeting the bar for developer preview. Publishing to GitHub and distributing on npm as a developer preview are permitted. Actual npm publish must pass the following external operator gates: npm account authentication, package ownership, and successful execution of the GitHub release workflow.
10
+ 0.3.2 resolves the additional security and operational risks identified during the full 0.3.1 code review, meeting the bar for developer preview. The external operator gates (npm account authentication, package ownership, GitHub tag/release) were passed on 2026-06-10: `haechi@0.3.2` is published to npm via local passkey authentication, tagged `v0.3.2`, and released as a GitHub pre-release. npm provenance remains deferred to the GitHub Actions trusted publishing path.
11
11
 
12
12
  | Category | Judgment | Rationale |
13
13
  |---|---|---|
14
14
  | GitHub public | Allowed | Security limitations, threat model, shared responsibility, and developer preview language are documented |
15
15
  | GitHub release/tag | Allowed | Must be presented as developer preview, not production-ready |
16
- | npm developer preview | Conditionally allowed | Requires passing `npm run release:preflight`, then running `release:preflight:npm` and a provenance publish from an authenticated account |
16
+ | npm developer preview | Allowed (published) | `haechi@0.3.2` published from an authenticated account on 2026-06-10; provenance deferred to trusted publishing |
17
17
  | npm stable | On hold | Stable label prohibited until 1.0 API stability, production KMS/HSM/Vault reference adapter, and stream-aware enforcement are in place |
18
18
  | Production use | Prohibited | 0.3.2 is a self-hosted developer preview; production auth/authz/key custody is the user's responsibility |
19
19
 
@@ -23,14 +23,14 @@
23
23
  |---|---|---|---|
24
24
  | G0 | GitHub source publication | Tests pass, security limitations documented, no plaintext audit leak | Pass |
25
25
  | G1 | GitHub pre-release | P0 code risks resolved, no production-ready language | Pass |
26
- | G2 | npm developer preview | P0 resolved, preflight/SBOM/provenance paths ready, npm auth confirmed | Conditional Pass |
26
+ | G2 | npm developer preview | P0 resolved, preflight/SBOM/provenance paths ready, npm auth confirmed | Pass (`haechi@0.3.2` published 2026-06-10) |
27
27
  | G3 | npm stable | P1 production reference, stream-aware enforcement, API stability hardened | Blocked |
28
28
 
29
29
  ## 3. P0 Distribution-Blocking Risk Status
30
30
 
31
31
  | ID | Risk | Status | Resolution evidence |
32
32
  |---|---|---|---|
33
- | P0-REL-001 | npm authentication/authorization unresolved | External Gate | Gated via `release:preflight:npm`, GitHub release workflow, and `npm publish --provenance --access public`. Actual authentication requires an operator |
33
+ | P0-REL-001 | npm authentication/authorization unresolved | Resolved | `haechi@0.3.2` published via local passkey authentication on 2026-06-10; npm authentication and package ownership confirmed |
34
34
  | P0-REL-002 | Proxy exposed to external network | Resolved | Non-loopback bind fails by default; `--allow-remote-bind` must be specified explicitly |
35
35
  | P0-REL-003 | Streaming request handling unclear | Resolved | `stream: true` defaults to 501 fail-closed; `streaming.requestMode: "pass-through"` must be set explicitly |
36
36
  | P0-REL-004 | `responseProtection` failure mode unclear | Resolved | Non-JSON, invalid JSON, compressed, and oversized responses are fail-closed; explicit allow policies are separated |
@@ -58,7 +58,7 @@
58
58
  | P1-OPS-002 | No SBOM/provenance | Resolved | `npm run sbom`, `.github/workflows/npm-publish.yml`, `publishConfig.provenance` |
59
59
  | P1-OPS-003 | No real vLLM/Ollama/llama.cpp integration tests | Resolved for preview | Env-gated optional local inference integration tests added. CI skips when no external model server is present |
60
60
  | P1-OPS-004 | Performance/large payload not measured | Resolved for preview | Request/response byte limits, `npm run bench:payload` |
61
- | P1-OPS-005 | npm ownership unconfirmed | External Gate | `npm run release:preflight:npm` from an authenticated npm account required; post-publish `npm view haechi version` needed |
61
+ | P1-OPS-005 | npm ownership unconfirmed | Resolved | `npm view haechi version` returns `0.3.2`; ownership confirmed by the first successful publish |
62
62
 
63
63
  ## 5.1 Additional Security Review Risk Resolution Status
64
64
 
@@ -107,12 +107,12 @@ Base64/encoded-value decode inspection, query-string inspection, and audit tail
107
107
 
108
108
  ## 7. npm Developer Preview Pre-Distribution Checklist
109
109
 
110
- Current external npm gate check results:
110
+ External npm gate check results (2026-06-10, post-publish):
111
111
 
112
112
  - `npm whoami`: `raeseoklee`
113
- - `npm view haechi version`: `E404 Not Found`
113
+ - `npm view haechi version`: `0.3.2`
114
114
 
115
- The `haechi` name appears to be available, but package ownership is confirmed only after the first successful publish from an authenticated account. `release:preflight:npm` verifies authentication and blocks duplicate publish of `haechi@<current version>`; E404 before the first publish is treated as a passing condition.
115
+ All checklist items below were completed for 0.3.2 on 2026-06-10 except the provenance publish path, which is deferred to GitHub Actions trusted publishing (`v0.3.2` tag and GitHub pre-release were completed). The checklist remains the template for future releases.
116
116
 
117
117
  1. `npm run release:preflight`
118
118
  2. `npm run sbom`
@@ -126,7 +126,7 @@ The `haechi` name appears to be available, but package ownership is confirmed on
126
126
 
127
127
  | Version | Goal | Remaining scope |
128
128
  |---|---|---|
129
- | 0.4.0 | Token round-trip and adoption | Request-scoped response detokenization, deterministic tokenization (derived key), `haechi mcp-wrap` (bidirectional stdio), `haechi audit-verify`/`haechi status`, injection detection type (default allow), PII-safe `identity` field and `authProvider` contract reserved. See `docs/current/release-0.4-implementation-scope.md` |
129
+ | 0.4.0 | Token round-trip and adoption | Shipped 2026-06-10: request-scoped response detokenization, deterministic tokenization (derived key), `haechi mcp-wrap`, `haechi audit-verify`/`haechi status`, injection detection type (default allow), `identity`/`authProvider` contracts reserved. See `docs/current/release-0.4-implementation-scope.md` |
130
130
  | 0.5.0 | Streaming hardening | SSE/NDJSON stream inspection, stream sequence AAD, replay cache, stronger remote deployment guide |
131
131
  | 0.6.0 | Auth and operational controls | Built-in bearer auth, per-client policy scope, model allowlist/rate budget, Vault/AWS KMS reference adapter, external append-only audit sink, signed release artifacts, npm org (`@haechi/*`) acquisition |
132
132
  | 0.7.0 | Observability | npm workspaces migration, `@haechi/dashboard` read-only audit viewer (hash chain integrity display, summary/search/timeline) |
@@ -2,7 +2,7 @@
2
2
 
3
3
  - 문서 상태: Draft 0.1
4
4
  - 작성일: 2026-06-10
5
- - 기준 버전: 0.3.2
5
+ - 기준 버전: 0.4.0
6
6
 
7
7
  ## 1. 보호 대상
8
8
 
@@ -47,6 +47,8 @@ Haechi가 보호하려는 주요 자산은 다음이다.
47
47
  | 행 걸린 upstream | proxy 연결 고갈 | `limits.upstreamTimeoutMs` 기본 120s, 초과 시 504 fail |
48
48
  | signing/encryption 키 혼용 | key separation 위반 | policy bundle 서명 키를 domain-separated 파생 키로 분리 |
49
49
  | JSON number/object key 은닉 | 카드번호 등 비문자열 leaf 미탐지 | number leaf와 object key도 detection/transform 대상 |
50
+ | token round-trip의 타 토큰 복원 | 클라이언트/요청 간 평문 복구 | detokenization은 opt-in(`detokenizeResponses`)이며 요청 스코프: 같은 요청을 보호하며 발급된 토큰만 복원 |
51
+ | tool result/응답 내 간접 prompt injection | 심어진 지시문에 의한 agent 조작 | 응답 방향 휴리스틱, 기본 report-only(`injection` action `allow`), 격상은 명시적 정책 선택. 완전 방어 아님 |
50
52
 
51
53
  ## 4. 명시적 제외
52
54
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  - Status: Draft 0.1
4
4
  - Date: 2026-06-10
5
- - Target version: 0.3.2
5
+ - Target version: 0.4.0
6
6
 
7
7
  ## 1. Assets Under Protection
8
8
 
@@ -47,6 +47,8 @@ The primary assets Haechi protects are:
47
47
  | Hung upstream | Proxy connection exhaustion | `limits.upstreamTimeoutMs` default 120 s; 504 fail on timeout |
48
48
  | Signing/encryption key conflation | Key separation violation | Policy bundle signing key isolated as a domain-separated derived key |
49
49
  | JSON number / object key concealment | Undetected non-string leaves such as card numbers | Number leaves and object keys included in detection/transform scope |
50
+ | Token round-trip restoring foreign tokens | Cross-client/request plaintext recovery | Detokenization is opt-in (`detokenizeResponses`) and request-scoped: only tokens issued while protecting the same request are restored |
51
+ | Indirect prompt injection in tool results/responses | Agent manipulation via planted instructions | Response-direction heuristics, report-only by default (`injection` action `allow`); escalation is an explicit policy choice. Not a complete defense |
50
52
 
51
53
  ## 4. Explicit Exclusions
52
54
 
@@ -51,7 +51,10 @@
51
51
  "provider": "local",
52
52
  "path": ".haechi/token-vault.json",
53
53
  "revealPolicy": "disabled",
54
- "retentionDays": 30
54
+ "retentionDays": 30,
55
+ "deterministic": false,
56
+ "deterministicTypes": null,
57
+ "detokenizeResponses": false
55
58
  },
56
59
  "privacy": {
57
60
  "profile": null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "haechi",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "Experimental developer preview for self-hosted AI context enforcement across LLM, MCP, vLLM, Ollama, and agent traffic.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -57,6 +57,7 @@
57
57
  ],
58
58
  "scripts": {
59
59
  "test": "node --test",
60
+ "check:types": "tsc -p jsconfig.json --noEmit",
60
61
  "pack:dry": "npm pack --dry-run",
61
62
  "scan:stale-names": "node scripts/stale-name-scan.mjs",
62
63
  "sbom": "node scripts/generate-sbom.mjs",
@@ -70,5 +71,9 @@
70
71
  },
71
72
  "engines": {
72
73
  "node": ">=22"
74
+ },
75
+ "devDependencies": {
76
+ "@types/node": "^22.19.20",
77
+ "typescript": "^5.7.3"
73
78
  }
74
79
  }
@@ -127,7 +127,9 @@ export async function verifyAuditChain(path) {
127
127
  records += 1;
128
128
  }
129
129
 
130
- return { valid: true, records };
130
+ // headHash anchors the chain externally: publishing it out-of-band is the
131
+ // only defense against tail truncation, which the chain alone cannot detect.
132
+ return { valid: true, records, headHash: expectedPreviousHash };
131
133
  }
132
134
 
133
135
  async function buildIntegrityRecord(path, event) {