fuseji 0.1.0__tar.gz
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.
- fuseji-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
- fuseji-0.1.0/.github/ISSUE_TEMPLATE/config.yml +2 -0
- fuseji-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +25 -0
- fuseji-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +14 -0
- fuseji-0.1.0/.github/workflows/ci.yml +92 -0
- fuseji-0.1.0/.github/workflows/publish.yml +96 -0
- fuseji-0.1.0/.gitignore +37 -0
- fuseji-0.1.0/.python-version +1 -0
- fuseji-0.1.0/CHANGELOG.md +84 -0
- fuseji-0.1.0/CLAUDE.md +47 -0
- fuseji-0.1.0/CONTRIBUTING.md +55 -0
- fuseji-0.1.0/LICENSE +190 -0
- fuseji-0.1.0/PKG-INFO +219 -0
- fuseji-0.1.0/README.en.md +160 -0
- fuseji-0.1.0/README.md +174 -0
- fuseji-0.1.0/SECURITY.md +173 -0
- fuseji-0.1.0/docs/api.md +333 -0
- fuseji-0.1.0/docs/design.md +243 -0
- fuseji-0.1.0/examples/README.md +21 -0
- fuseji-0.1.0/examples/ginza/README.md +36 -0
- fuseji-0.1.0/examples/ginza/main.py +28 -0
- fuseji-0.1.0/examples/ginza/requirements.txt +1 -0
- fuseji-0.1.0/examples/langfuse_ingestion_callback/README.md +49 -0
- fuseji-0.1.0/examples/langfuse_ingestion_callback/docker-compose.yml +21 -0
- fuseji-0.1.0/examples/langfuse_sdk/README.md +33 -0
- fuseji-0.1.0/examples/langfuse_sdk/main.py +43 -0
- fuseji-0.1.0/examples/langfuse_sdk/requirements.txt +2 -0
- fuseji-0.1.0/examples/otel/README.md +35 -0
- fuseji-0.1.0/examples/otel/otel-collector-config.yaml +40 -0
- fuseji-0.1.0/pyproject.toml +118 -0
- fuseji-0.1.0/src/fuseji/__init__.py +28 -0
- fuseji-0.1.0/src/fuseji/engine.py +176 -0
- fuseji-0.1.0/src/fuseji/entity_types.py +46 -0
- fuseji-0.1.0/src/fuseji/exceptions.py +32 -0
- fuseji-0.1.0/src/fuseji/integrations/__init__.py +5 -0
- fuseji-0.1.0/src/fuseji/integrations/langfuse.py +76 -0
- fuseji-0.1.0/src/fuseji/ner/__init__.py +5 -0
- fuseji-0.1.0/src/fuseji/ner/base.py +19 -0
- fuseji-0.1.0/src/fuseji/ner/ginza.py +70 -0
- fuseji-0.1.0/src/fuseji/py.typed +0 -0
- fuseji-0.1.0/src/fuseji/recognizers/__init__.py +17 -0
- fuseji-0.1.0/src/fuseji/recognizers/base.py +117 -0
- fuseji-0.1.0/src/fuseji/recognizers/credit_card.py +55 -0
- fuseji-0.1.0/src/fuseji/recognizers/email.py +31 -0
- fuseji-0.1.0/src/fuseji/recognizers/jp_phone.py +66 -0
- fuseji-0.1.0/src/fuseji/recognizers/jp_postal.py +73 -0
- fuseji-0.1.0/src/fuseji/recognizers/my_number.py +65 -0
- fuseji-0.1.0/src/fuseji/server/__init__.py +5 -0
- fuseji-0.1.0/src/fuseji/server/app.py +168 -0
- fuseji-0.1.0/src/fuseji/strategies.py +158 -0
- fuseji-0.1.0/src/fuseji/types.py +54 -0
- fuseji-0.1.0/src/fuseji/vault.py +165 -0
- fuseji-0.1.0/tests/__init__.py +0 -0
- fuseji-0.1.0/tests/bench/README.md +36 -0
- fuseji-0.1.0/tests/bench/__init__.py +0 -0
- fuseji-0.1.0/tests/bench/bench_masker.py +43 -0
- fuseji-0.1.0/tests/bench/bench_recognizers.py +42 -0
- fuseji-0.1.0/tests/bench/bench_replace_spans.py +28 -0
- fuseji-0.1.0/tests/bench/bench_vault.py +37 -0
- fuseji-0.1.0/tests/conftest.py +30 -0
- fuseji-0.1.0/tests/test_engine.py +159 -0
- fuseji-0.1.0/tests/test_engine_vault_json.py +121 -0
- fuseji-0.1.0/tests/test_entity_types.py +65 -0
- fuseji-0.1.0/tests/test_integrations_langfuse.py +137 -0
- fuseji-0.1.0/tests/test_latency_regression.py +72 -0
- fuseji-0.1.0/tests/test_ner_base.py +21 -0
- fuseji-0.1.0/tests/test_ner_ginza.py +59 -0
- fuseji-0.1.0/tests/test_public_api.py +69 -0
- fuseji-0.1.0/tests/test_recognizers_base.py +80 -0
- fuseji-0.1.0/tests/test_recognizers_credit_card.py +97 -0
- fuseji-0.1.0/tests/test_recognizers_email.py +53 -0
- fuseji-0.1.0/tests/test_recognizers_jp_phone.py +118 -0
- fuseji-0.1.0/tests/test_recognizers_jp_postal.py +77 -0
- fuseji-0.1.0/tests/test_recognizers_my_number.py +90 -0
- fuseji-0.1.0/tests/test_server.py +149 -0
- fuseji-0.1.0/tests/test_strategies.py +151 -0
- fuseji-0.1.0/tests/test_types.py +78 -0
- fuseji-0.1.0/tests/test_vault.py +282 -0
- fuseji-0.1.0/tests/test_vault_strategy.py +83 -0
- fuseji-0.1.0/uv.lock +2375 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: バグ報告
|
|
3
|
+
about: 不具合を報告する
|
|
4
|
+
title: ""
|
|
5
|
+
labels: bug
|
|
6
|
+
assignees: ""
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 現象
|
|
10
|
+
|
|
11
|
+
<!-- 何が起きたかを簡潔に記述してください -->
|
|
12
|
+
|
|
13
|
+
## 再現手順
|
|
14
|
+
|
|
15
|
+
1.
|
|
16
|
+
2.
|
|
17
|
+
3.
|
|
18
|
+
|
|
19
|
+
## 期待する動作
|
|
20
|
+
|
|
21
|
+
<!-- 本来どうなるべきかを記述してください -->
|
|
22
|
+
|
|
23
|
+
## 実際の動作
|
|
24
|
+
|
|
25
|
+
<!-- 実際に起きたことを記述してください -->
|
|
26
|
+
|
|
27
|
+
## 再現コード
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from fuseji import Masker
|
|
31
|
+
|
|
32
|
+
masker = Masker()
|
|
33
|
+
# ここに再現コードを記述
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 環境
|
|
37
|
+
|
|
38
|
+
- fuseji バージョン:
|
|
39
|
+
- Python バージョン:
|
|
40
|
+
- OS:
|
|
41
|
+
- extras(ginza, server 等):
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 機能要望
|
|
3
|
+
about: 新しい機能やエンティティタイプの追加を提案する
|
|
4
|
+
title: ""
|
|
5
|
+
labels: enhancement
|
|
6
|
+
assignees: ""
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 概要
|
|
10
|
+
|
|
11
|
+
<!-- どのような機能が欲しいかを簡潔に記述してください -->
|
|
12
|
+
|
|
13
|
+
## 背景・動機
|
|
14
|
+
|
|
15
|
+
<!-- なぜこの機能が必要かを記述してください -->
|
|
16
|
+
|
|
17
|
+
## 想定する利用イメージ
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
# この機能をどのように使いたいかを記述
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 備考
|
|
24
|
+
|
|
25
|
+
<!-- 参考情報、代替案などがあれば記述してください -->
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## 関連 Issue
|
|
2
|
+
|
|
3
|
+
<!-- closes #123 -->
|
|
4
|
+
|
|
5
|
+
## 変更内容
|
|
6
|
+
|
|
7
|
+
<!-- 何をどう変更したかを簡潔に記述してください -->
|
|
8
|
+
|
|
9
|
+
## テスト
|
|
10
|
+
|
|
11
|
+
- [ ] 既存テストが通ること(`uv run pytest`)
|
|
12
|
+
- [ ] 新規テストを追加した(該当する場合)
|
|
13
|
+
- [ ] リントが通ること(`uv run ruff check src/ tests/`)
|
|
14
|
+
- [ ] 型チェックが通ること(`uv run mypy src/`)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
lint:
|
|
15
|
+
name: lint / type-check (Python 3.13)
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- name: Set up uv
|
|
20
|
+
uses: astral-sh/setup-uv@v6
|
|
21
|
+
with:
|
|
22
|
+
enable-cache: true
|
|
23
|
+
- name: Set up Python
|
|
24
|
+
run: uv python install 3.13
|
|
25
|
+
- name: Install dependencies (all extras for mypy stubs)
|
|
26
|
+
run: uv sync --all-extras
|
|
27
|
+
- name: ruff check
|
|
28
|
+
run: uv run ruff check src/ tests/
|
|
29
|
+
- name: ruff format check
|
|
30
|
+
run: uv run ruff format --check src/ tests/
|
|
31
|
+
- name: mypy
|
|
32
|
+
run: uv run mypy src/
|
|
33
|
+
|
|
34
|
+
test-core:
|
|
35
|
+
name: test (core, ${{ matrix.python }})
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
strategy:
|
|
38
|
+
fail-fast: false
|
|
39
|
+
matrix:
|
|
40
|
+
# Python 3.14 まで含める。test-extras(ginza)は spaCy 3.8 の wheel 制約で
|
|
41
|
+
# 3.13 までしか試せないため、本マトリクスは core のみ。
|
|
42
|
+
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@v4
|
|
45
|
+
- name: Set up uv
|
|
46
|
+
uses: astral-sh/setup-uv@v6
|
|
47
|
+
with:
|
|
48
|
+
enable-cache: true
|
|
49
|
+
- name: Set up Python ${{ matrix.python }}
|
|
50
|
+
run: uv python install ${{ matrix.python }}
|
|
51
|
+
- name: Install dependencies (core only — extras なし)
|
|
52
|
+
run: uv sync --python ${{ matrix.python }}
|
|
53
|
+
- name: pytest (extras なし — ginza/server テストは skip)
|
|
54
|
+
run: uv run pytest -q
|
|
55
|
+
|
|
56
|
+
test-extras:
|
|
57
|
+
name: test (all extras, Python 3.13)
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@v4
|
|
61
|
+
- name: Set up uv
|
|
62
|
+
uses: astral-sh/setup-uv@v6
|
|
63
|
+
with:
|
|
64
|
+
enable-cache: true
|
|
65
|
+
- name: Set up Python
|
|
66
|
+
run: uv python install 3.13
|
|
67
|
+
- name: Install all extras (ginza + server)
|
|
68
|
+
run: uv sync --all-extras
|
|
69
|
+
- name: pytest (all extras)
|
|
70
|
+
run: uv run pytest -q
|
|
71
|
+
|
|
72
|
+
bench:
|
|
73
|
+
name: bench (informational)
|
|
74
|
+
runs-on: ubuntu-latest
|
|
75
|
+
# 情報表示のみ。回帰検知 assertion 化は別 Issue で対応。
|
|
76
|
+
continue-on-error: true
|
|
77
|
+
steps:
|
|
78
|
+
- uses: actions/checkout@v4
|
|
79
|
+
- name: Set up uv
|
|
80
|
+
uses: astral-sh/setup-uv@v6
|
|
81
|
+
with:
|
|
82
|
+
enable-cache: true
|
|
83
|
+
- name: Set up Python
|
|
84
|
+
run: uv python install 3.13
|
|
85
|
+
- name: Install dependencies
|
|
86
|
+
run: uv sync --all-extras
|
|
87
|
+
- name: pytest-benchmark (情報表示)
|
|
88
|
+
run: |
|
|
89
|
+
uv run pytest tests/bench/ --benchmark-enable \
|
|
90
|
+
--benchmark-columns=min,mean,max,stddev,median \
|
|
91
|
+
--benchmark-group-by=group \
|
|
92
|
+
--benchmark-warmup=on
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
target:
|
|
7
|
+
description: '公開先 (testpypi で検証 → pypi で本番公開)'
|
|
8
|
+
required: true
|
|
9
|
+
type: choice
|
|
10
|
+
options:
|
|
11
|
+
- testpypi
|
|
12
|
+
- pypi
|
|
13
|
+
push:
|
|
14
|
+
tags:
|
|
15
|
+
# vX.Y.Z 形式のタグ push 時に PyPI 本番へ自動公開
|
|
16
|
+
- 'v[0-9]+.[0-9]+.[0-9]+'
|
|
17
|
+
- 'v[0-9]+.[0-9]+.[0-9]+rc[0-9]+'
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
build:
|
|
21
|
+
name: Build sdist + wheel
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
with:
|
|
26
|
+
fetch-depth: 0 # version 推定や changelog 生成のため履歴フル取得
|
|
27
|
+
- name: Set up uv
|
|
28
|
+
uses: astral-sh/setup-uv@v6
|
|
29
|
+
with:
|
|
30
|
+
enable-cache: true
|
|
31
|
+
- name: Set up Python 3.13
|
|
32
|
+
run: uv python install 3.13
|
|
33
|
+
- name: Install dependencies (all extras for mypy stubs)
|
|
34
|
+
run: uv sync --all-extras
|
|
35
|
+
- name: ruff check
|
|
36
|
+
run: uv run ruff check src/ tests/
|
|
37
|
+
- name: ruff format check
|
|
38
|
+
run: uv run ruff format --check src/ tests/
|
|
39
|
+
- name: mypy
|
|
40
|
+
run: uv run mypy src/
|
|
41
|
+
- name: pytest
|
|
42
|
+
run: uv run pytest -q
|
|
43
|
+
- name: Build distributions
|
|
44
|
+
run: uv build
|
|
45
|
+
- name: Verify built artifacts
|
|
46
|
+
run: |
|
|
47
|
+
ls -la dist/
|
|
48
|
+
uv run python -m zipfile -l dist/*.whl | head -20
|
|
49
|
+
- name: Upload build artifacts
|
|
50
|
+
uses: actions/upload-artifact@v4
|
|
51
|
+
with:
|
|
52
|
+
name: dist
|
|
53
|
+
path: dist/
|
|
54
|
+
retention-days: 7
|
|
55
|
+
|
|
56
|
+
publish-testpypi:
|
|
57
|
+
name: Publish to TestPyPI
|
|
58
|
+
needs: build
|
|
59
|
+
if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
environment:
|
|
62
|
+
name: testpypi
|
|
63
|
+
url: https://test.pypi.org/p/fuseji
|
|
64
|
+
permissions:
|
|
65
|
+
id-token: write # OIDC token for trusted publishing
|
|
66
|
+
steps:
|
|
67
|
+
- name: Download build artifacts
|
|
68
|
+
uses: actions/download-artifact@v4
|
|
69
|
+
with:
|
|
70
|
+
name: dist
|
|
71
|
+
path: dist/
|
|
72
|
+
- name: Publish to TestPyPI
|
|
73
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
74
|
+
with:
|
|
75
|
+
repository-url: https://test.pypi.org/legacy/
|
|
76
|
+
|
|
77
|
+
publish-pypi:
|
|
78
|
+
name: Publish to PyPI
|
|
79
|
+
needs: build
|
|
80
|
+
if: >-
|
|
81
|
+
github.event_name == 'push' ||
|
|
82
|
+
(github.event_name == 'workflow_dispatch' && inputs.target == 'pypi')
|
|
83
|
+
runs-on: ubuntu-latest
|
|
84
|
+
environment:
|
|
85
|
+
name: pypi
|
|
86
|
+
url: https://pypi.org/p/fuseji
|
|
87
|
+
permissions:
|
|
88
|
+
id-token: write # OIDC token for trusted publishing
|
|
89
|
+
steps:
|
|
90
|
+
- name: Download build artifacts
|
|
91
|
+
uses: actions/download-artifact@v4
|
|
92
|
+
with:
|
|
93
|
+
name: dist
|
|
94
|
+
path: dist/
|
|
95
|
+
- name: Publish to PyPI
|
|
96
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
fuseji-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
*.egg-info/
|
|
7
|
+
*.egg
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
*.whl
|
|
11
|
+
|
|
12
|
+
# 仮想環境
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
env/
|
|
16
|
+
|
|
17
|
+
# テスト・カバレッジ
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
htmlcov/
|
|
21
|
+
.mypy_cache/
|
|
22
|
+
.ruff_cache/
|
|
23
|
+
|
|
24
|
+
# IDE
|
|
25
|
+
.vscode/
|
|
26
|
+
.idea/
|
|
27
|
+
*.swp
|
|
28
|
+
*.swo
|
|
29
|
+
*~
|
|
30
|
+
|
|
31
|
+
# OS
|
|
32
|
+
.DS_Store
|
|
33
|
+
Thumbs.db
|
|
34
|
+
|
|
35
|
+
# 環境変数
|
|
36
|
+
.env
|
|
37
|
+
.env.local
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# 変更履歴 / Changelog
|
|
2
|
+
|
|
3
|
+
本ファイルは [Keep a Changelog](https://keepachangelog.com/ja/1.1.0/) に従い、
|
|
4
|
+
バージョニングは [Semantic Versioning](https://semver.org/spec/v2.0.0.html) に従います。
|
|
5
|
+
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-06-12
|
|
9
|
+
|
|
10
|
+
初回 PyPI リリース。日本語特化の PII 検出・マスキングミドルウェア。
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
#### コア機能
|
|
15
|
+
|
|
16
|
+
- **コア型**: `Entity`、`MaskResult`(frozen dataclass、バリデーション付き)
|
|
17
|
+
- **マスキング戦略**: `MaskStrategy` プロトコル + `Placeholder` / `Redact` / `Hash` / `VaultStrategy` の 4 実装
|
|
18
|
+
- **仮名化バウルト**: `Vault` プロトコル + `InMemoryVault` 実装。同一 (type, surface) → 同一 placeholder、`MY_NUMBER` をデフォルト除外(番号法対応)
|
|
19
|
+
- `restore()` は placeholder regex マッチで silent corruption を構造的に防ぐ
|
|
20
|
+
- `clear()` で全マッピングを破棄可能(`excluded_types` 設定は維持)
|
|
21
|
+
- `size` プロパティで登録済み placeholder 数を取得
|
|
22
|
+
- `assign()` は `threading.Lock` で保護(並行採番衝突なし)
|
|
23
|
+
- `__repr__` で状態を可視化
|
|
24
|
+
- **PII 認識器(v0.1 セット)**:
|
|
25
|
+
- `EMAIL`(RFC-lite)
|
|
26
|
+
- `CREDIT_CARD`(Luhn 検証)
|
|
27
|
+
- `MY_NUMBER`(12 桁、総務省公開仕様のチェックディジット、recall 優先)
|
|
28
|
+
- `JP_PHONE_NUMBER`(携帯 070/080/090、フリーダイヤル 0120、ナビダイヤル 0570、固定電話)
|
|
29
|
+
- `JP_POSTAL_CODE`(〒、コンテキストブースト)
|
|
30
|
+
- すべて全角数字・全角ハイフン対応、共通ヘルパ(`SEPARATOR_PATTERN`, `has_digit_boundary`)
|
|
31
|
+
- **NER バックエンド**: `NerBackend` プロトコル + GiNZA 実装(`[ginza]` extra)で PERSON 検出
|
|
32
|
+
- **Masker エンジン**:
|
|
33
|
+
- `Masker.mask` / `Masker.mask_json` / `Masker.detect`
|
|
34
|
+
- オーバーラップ解決はスコア優先 → 長 span 優先 → 開始位置順
|
|
35
|
+
- `max_json_depth`(既定 100)で `mask_json` の再帰深度を制限、超過時は fail-closed
|
|
36
|
+
- `Masker(vault=..., strategy=...)` 同時指定で `UserWarning`(vault 優先)
|
|
37
|
+
|
|
38
|
+
#### 統合
|
|
39
|
+
|
|
40
|
+
- **Langfuse SDK アダプタ**: `make_mask_fn()`。fail-closed 設計
|
|
41
|
+
- 例外時は固定 placeholder `"[fuseji: masking failed]"` を返し原データを露出しない
|
|
42
|
+
- デフォルトログは例外型名のみ(traceback 内 PII 漏洩防止)、`FUSEJI_LANGFUSE_LOG_TRACEBACK=1` で詳細出力
|
|
43
|
+
- **FastAPI サーバー**(`[server]` extra):
|
|
44
|
+
- `POST /mask` / `POST /detect` / `GET /healthz` / OpenAPI 自動生成
|
|
45
|
+
- `create_app(masker=..., max_body_bytes=...)` factory で DI
|
|
46
|
+
- `BodySizeLimitMiddleware` で 1MB 超リクエストを 413 で拒否(環境変数で上書き可)
|
|
47
|
+
|
|
48
|
+
#### API ユーティリティ
|
|
49
|
+
|
|
50
|
+
- **`fuseji.entity_types` 定数モジュール**: `EMAIL` / `CREDIT_CARD` / `MY_NUMBER` / `JP_PHONE_NUMBER` / `JP_POSTAL_CODE` / `PERSON` を str 定数として提供
|
|
51
|
+
- **`FusejiError` 例外階層**: `FusejiError`(基底)/ `InvalidEntityError` / `InvalidConfigError`。多重継承で `ValueError` も継承(後方互換)
|
|
52
|
+
- **公開 API の docstring に Example セクション**(doctest として実行可能)
|
|
53
|
+
|
|
54
|
+
#### 品質・運用
|
|
55
|
+
|
|
56
|
+
- **CI**: GitHub Actions で ruff / mypy / pytest を Python 3.10–3.14 マトリクス + 全 extras ジョブ + 情報的 bench ジョブ
|
|
57
|
+
- **fuseji-bench**: `pytest-benchmark` 基盤と 23 ベンチケース
|
|
58
|
+
- **レイテンシ回帰検知テスト**: O(n²) バグ等を通常 pytest で即時 fail(Masker 1KB/4KB、Vault.restore m=1000)
|
|
59
|
+
- **PyPI 公開**: Trusted Publishing (OIDC) workflow
|
|
60
|
+
|
|
61
|
+
### Performance
|
|
62
|
+
|
|
63
|
+
- `_replace_spans` を list-of-segments の 1 パスに変更し O(n²) → O(n+k)
|
|
64
|
+
- `normalize()` の translate テーブルを統合し 2 パスから 1 パスに
|
|
65
|
+
|
|
66
|
+
### Security
|
|
67
|
+
|
|
68
|
+
- マイナンバーは Vault のデフォルト除外集合に含み復元不可
|
|
69
|
+
- `InMemoryVault.restore()` を placeholder regex マッチに変更し silent corruption を構造的に排除
|
|
70
|
+
- `InMemoryVault.assign` を `threading.Lock` で保護
|
|
71
|
+
- Langfuse adapter のデフォルトログから traceback 除去
|
|
72
|
+
- `Masker(max_json_depth=...)` で DoS 対策
|
|
73
|
+
- `BodySizeLimitMiddleware` で巨大ペイロードを拒否
|
|
74
|
+
|
|
75
|
+
### Documentation
|
|
76
|
+
|
|
77
|
+
- README(日本語メイン + 英語ミラー)
|
|
78
|
+
- SECURITY.md(番号法対応・脆弱性報告窓口・設計上の安全保証)
|
|
79
|
+
- docs/design.md / docs/api.md
|
|
80
|
+
- examples/(Langfuse SDK / ingestion callback / OTel / GiNZA)
|
|
81
|
+
- CONTRIBUTING.md
|
|
82
|
+
|
|
83
|
+
[Unreleased]: https://github.com/sserada/fuseji/compare/v0.1.0...HEAD
|
|
84
|
+
[0.1.0]: https://github.com/sserada/fuseji/releases/tag/v0.1.0
|
fuseji-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# fuseji 開発ガイド
|
|
2
|
+
|
|
3
|
+
## プロジェクト概要
|
|
4
|
+
|
|
5
|
+
fuseji (伏せ字) — 日本語特化のPII検出・マスキングミドルウェア(LLMオブザーバビリティ向け)。
|
|
6
|
+
Python 3.10+、`uv` でパッケージ管理。
|
|
7
|
+
|
|
8
|
+
## 開発フロー
|
|
9
|
+
|
|
10
|
+
1. GitHub Issue を作成し、タスクを記述する
|
|
11
|
+
2. `main` からブランチを作成する: `feat/<issue番号>-<短い説明>`, `fix/<issue番号>-<短い説明>`, `chore/<issue番号>-<短い説明>`
|
|
12
|
+
3. 開発・コミット
|
|
13
|
+
4. Issue を参照する PR を `main` に対して作成する
|
|
14
|
+
5. レビュー後にマージ
|
|
15
|
+
|
|
16
|
+
`main` への直接 push は禁止。必ず PR を経由すること。
|
|
17
|
+
|
|
18
|
+
## コマンド
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
uv sync # 依存関係のインストール
|
|
22
|
+
uv run ruff check src/ tests/ # リント
|
|
23
|
+
uv run ruff format src/ tests/ # フォーマット
|
|
24
|
+
uv run mypy src/ # 型チェック
|
|
25
|
+
uv run pytest # テスト実行
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## コード規約
|
|
29
|
+
|
|
30
|
+
- ソースレイアウト: `src/fuseji/`
|
|
31
|
+
- 公開APIには型アノテーション必須
|
|
32
|
+
- docstring・コメントは日本語
|
|
33
|
+
- Issue・PR・コミットメッセージは日本語
|
|
34
|
+
|
|
35
|
+
## ディレクトリ構成
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
src/fuseji/
|
|
39
|
+
├── engine.py # Maskerエンジン
|
|
40
|
+
├── types.py # Entity, MaskResult
|
|
41
|
+
├── strategies.py # Placeholder / Redact / Hash
|
|
42
|
+
├── vault.py # 仮名化バウルト
|
|
43
|
+
├── recognizers/ # PII認識器
|
|
44
|
+
├── ner/ # NERバックエンド
|
|
45
|
+
├── integrations/ # 外部サービス連携
|
|
46
|
+
└── server/ # FastAPIサーバー
|
|
47
|
+
```
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# コントリビューションガイド
|
|
2
|
+
|
|
3
|
+
fuseji への貢献に感謝します。
|
|
4
|
+
|
|
5
|
+
## 開発環境のセットアップ
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# リポジトリをクローン
|
|
9
|
+
git clone https://github.com/sserada/fuseji.git
|
|
10
|
+
cd fuseji
|
|
11
|
+
|
|
12
|
+
# 依存関係をインストール(uv が必要)
|
|
13
|
+
uv sync --all-extras
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## 開発フロー
|
|
17
|
+
|
|
18
|
+
1. Issue を作成し、やることを記述する
|
|
19
|
+
2. `main` からブランチを作成する
|
|
20
|
+
- 機能追加: `feat/<issue番号>-<短い説明>`
|
|
21
|
+
- バグ修正: `fix/<issue番号>-<短い説明>`
|
|
22
|
+
- その他: `chore/<issue番号>-<短い説明>`
|
|
23
|
+
3. 開発・コミット
|
|
24
|
+
4. PR を作成し、関連 Issue を参照する
|
|
25
|
+
|
|
26
|
+
## コマンド
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
uv run ruff check src/ tests/ # リント
|
|
30
|
+
uv run ruff format src/ tests/ # フォーマット
|
|
31
|
+
uv run mypy src/ # 型チェック
|
|
32
|
+
uv run pytest # テスト
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## コード規約
|
|
36
|
+
|
|
37
|
+
- docstring・コメントは日本語
|
|
38
|
+
- 公開 API には型アノテーション必須
|
|
39
|
+
- PR 前にリント・型チェック・テストをすべて通すこと
|
|
40
|
+
|
|
41
|
+
## 認識器の追加
|
|
42
|
+
|
|
43
|
+
新しい PII 認識器の追加は歓迎します。`Recognizer` プロトコルを実装してください:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
class Recognizer(Protocol):
|
|
47
|
+
entity_type: str
|
|
48
|
+
def analyze(self, text: str) -> Iterable[Entity]: ...
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
テストには全角/半角バリエーション、コンテキスト語の有無、偽陽性ケースを含めてください。
|
|
52
|
+
|
|
53
|
+
## ライセンス
|
|
54
|
+
|
|
55
|
+
コントリビューションは Apache-2.0 ライセンスの下で提供されます。
|