mimic-check 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.
@@ -0,0 +1,111 @@
1
+ Metadata-Version: 2.4
2
+ Name: mimic-check
3
+ Version: 0.1.0
4
+ Summary: A security tool to check for typosquatting and package reliability in requirements.txt
5
+ Author-email: Disnana <support@disnana.com>
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.7
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: requests
12
+ Requires-Dist: toml
13
+
14
+ # mimic-check
15
+
16
+ `mimic-check` は、`requirements.txt` に記載された Python パッケージの安全性を検証するためのツールです。
17
+ タイポスクワッティング(有名なパッケージに似た名前の悪意あるパッケージ)の検出や、ダウンロード数・GitHub スター数に基づいた信頼性の評価を行います。
18
+
19
+ ## 特徴
20
+
21
+ - **タイポ検出**: `requests` を `reqeusts` と書き間違えているようなケースを検出し警告します。
22
+ - **信頼性評価**: PyPI のダウンロード数(直近1ヶ月)と GitHub のスター数を確認し、閾値未満のパッケージを警告します。
23
+ - **効率的なキャッシュ**: 検証結果を当日中のみ有効なキャッシュとして保存し、不要な API リクエストを削減します。
24
+ - **PyPI 存在確認**: パッケージが PyPI に存在しない場合、即座に警告し後続のチェックをスキップします。
25
+ - **CI 対応**: `--ci` フラグを使用することで、問題検出時に非ゼロの終了コードで終了し、パイプラインを停止させることができます。
26
+
27
+ ## セットアップ
28
+
29
+ ### 必要条件
30
+
31
+ - Python 3.x
32
+ - `requests`, `toml` パッケージ
33
+
34
+ ### インストール
35
+
36
+ PyPIからインストールする場合(公開後):
37
+
38
+ ```bash
39
+ pip install mimic-check
40
+ ```
41
+
42
+ ローカルで開発用にインストールする場合:
43
+
44
+ ```bash
45
+ pip install -e .
46
+ ```
47
+
48
+ これにより、`mimi` コマンドが使用可能になります。
49
+
50
+ ## 使い方
51
+
52
+ ### 基本的な実行
53
+
54
+ ```bash
55
+ mimi --file requirements.txt
56
+ ```
57
+
58
+ 実行すると、パッケージごとに以下のチェックが行われます:
59
+ 1. 有名パッケージとの名前の類似性(タイポ)チェック
60
+ 2. PyPI での存在確認
61
+ 3. ダウンロード数とスター数の確認
62
+
63
+ 問題が見つかった場合、警告が表示され、続行するかどうかを確認されます。`y` を入力すると、そのパッケージを含めた一時的な requirements ファイルで `pip install` が実行されます。
64
+
65
+ ### CI モードでの実行
66
+
67
+ CI/CD パイプラインなどで、問題検出時に自動的にエラーとしたい場合は `--ci` フラグを使用します。
68
+
69
+ ```bash
70
+ mimi --file requirements.txt --ci
71
+ ```
72
+
73
+ ## PyPIへの配布方法
74
+
75
+ 1. ビルドツールのインストール:
76
+ ```bash
77
+ pip install build twine
78
+ ```
79
+
80
+ 2. パッケージのビルド:
81
+ ```bash
82
+ python -m build
83
+ ```
84
+
85
+ 3. PyPIへのアップロード (テスト環境):
86
+ ```bash
87
+ python -m twine upload --repository testpypi dist/*
88
+ ```
89
+
90
+ 4. PyPIへのアップロード (本番環境):
91
+ ```bash
92
+ python -m twine upload dist/*
93
+ ```
94
+
95
+ ## 設定 (`config.toml`)
96
+
97
+ プロジェクトのルートにある `config.toml` で動作をカスタマイズできます。
98
+
99
+ ```toml
100
+ [mimi]
101
+ min_downloads = 1000 # 信頼できるとみなす最小ダウンロード数
102
+ min_stars = 10 # 信頼できるとみなす最小 GitHub スター数
103
+ famous_packages = ["requests", "numpy", "pandas", ...] # タイポチェック対象の有名パッケージ
104
+ trusted_packages = [] # チェックをスキップする信頼済みパッケージ
105
+ ```
106
+
107
+ ## キャッシュ
108
+
109
+ `package_cache.json` に検証結果がキャッシュされます。
110
+ - キャッシュは日付ごとに管理され、翌日には自動的に再検証されます。
111
+ - 信頼性の基準を満たしたパッケージのみがキャッシュされ、警告対象のパッケージは毎回チェックされます。
@@ -0,0 +1,98 @@
1
+ # mimic-check
2
+
3
+ `mimic-check` は、`requirements.txt` に記載された Python パッケージの安全性を検証するためのツールです。
4
+ タイポスクワッティング(有名なパッケージに似た名前の悪意あるパッケージ)の検出や、ダウンロード数・GitHub スター数に基づいた信頼性の評価を行います。
5
+
6
+ ## 特徴
7
+
8
+ - **タイポ検出**: `requests` を `reqeusts` と書き間違えているようなケースを検出し警告します。
9
+ - **信頼性評価**: PyPI のダウンロード数(直近1ヶ月)と GitHub のスター数を確認し、閾値未満のパッケージを警告します。
10
+ - **効率的なキャッシュ**: 検証結果を当日中のみ有効なキャッシュとして保存し、不要な API リクエストを削減します。
11
+ - **PyPI 存在確認**: パッケージが PyPI に存在しない場合、即座に警告し後続のチェックをスキップします。
12
+ - **CI 対応**: `--ci` フラグを使用することで、問題検出時に非ゼロの終了コードで終了し、パイプラインを停止させることができます。
13
+
14
+ ## セットアップ
15
+
16
+ ### 必要条件
17
+
18
+ - Python 3.x
19
+ - `requests`, `toml` パッケージ
20
+
21
+ ### インストール
22
+
23
+ PyPIからインストールする場合(公開後):
24
+
25
+ ```bash
26
+ pip install mimic-check
27
+ ```
28
+
29
+ ローカルで開発用にインストールする場合:
30
+
31
+ ```bash
32
+ pip install -e .
33
+ ```
34
+
35
+ これにより、`mimi` コマンドが使用可能になります。
36
+
37
+ ## 使い方
38
+
39
+ ### 基本的な実行
40
+
41
+ ```bash
42
+ mimi --file requirements.txt
43
+ ```
44
+
45
+ 実行すると、パッケージごとに以下のチェックが行われます:
46
+ 1. 有名パッケージとの名前の類似性(タイポ)チェック
47
+ 2. PyPI での存在確認
48
+ 3. ダウンロード数とスター数の確認
49
+
50
+ 問題が見つかった場合、警告が表示され、続行するかどうかを確認されます。`y` を入力すると、そのパッケージを含めた一時的な requirements ファイルで `pip install` が実行されます。
51
+
52
+ ### CI モードでの実行
53
+
54
+ CI/CD パイプラインなどで、問題検出時に自動的にエラーとしたい場合は `--ci` フラグを使用します。
55
+
56
+ ```bash
57
+ mimi --file requirements.txt --ci
58
+ ```
59
+
60
+ ## PyPIへの配布方法
61
+
62
+ 1. ビルドツールのインストール:
63
+ ```bash
64
+ pip install build twine
65
+ ```
66
+
67
+ 2. パッケージのビルド:
68
+ ```bash
69
+ python -m build
70
+ ```
71
+
72
+ 3. PyPIへのアップロード (テスト環境):
73
+ ```bash
74
+ python -m twine upload --repository testpypi dist/*
75
+ ```
76
+
77
+ 4. PyPIへのアップロード (本番環境):
78
+ ```bash
79
+ python -m twine upload dist/*
80
+ ```
81
+
82
+ ## 設定 (`config.toml`)
83
+
84
+ プロジェクトのルートにある `config.toml` で動作をカスタマイズできます。
85
+
86
+ ```toml
87
+ [mimi]
88
+ min_downloads = 1000 # 信頼できるとみなす最小ダウンロード数
89
+ min_stars = 10 # 信頼できるとみなす最小 GitHub スター数
90
+ famous_packages = ["requests", "numpy", "pandas", ...] # タイポチェック対象の有名パッケージ
91
+ trusted_packages = [] # チェックをスキップする信頼済みパッケージ
92
+ ```
93
+
94
+ ## キャッシュ
95
+
96
+ `package_cache.json` に検証結果がキャッシュされます。
97
+ - キャッシュは日付ごとに管理され、翌日には自動的に再検証されます。
98
+ - 信頼性の基準を満たしたパッケージのみがキャッシュされ、警告対象のパッケージは毎回チェックされます。
@@ -0,0 +1,31 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "mimic-check"
7
+ version = "0.1.0"
8
+ authors = [
9
+ { name = "Disnana", email = "support@disnana.com" },
10
+ ]
11
+ description = "A security tool to check for typosquatting and package reliability in requirements.txt"
12
+ readme = "README.md"
13
+ requires-python = ">=3.7"
14
+ license = { text = "MIT" }
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "Operating System :: OS Independent",
18
+ ]
19
+ dependencies = [
20
+ "requests",
21
+ "toml",
22
+ ]
23
+
24
+ [project.scripts]
25
+ mimi = "mimic.main:main"
26
+
27
+ [tool.setuptools.packages.find]
28
+ where = ["src"]
29
+
30
+ [tool.setuptools.package-data]
31
+ mimic = ["*.toml"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,236 @@
1
+ import sys
2
+ import argparse
3
+ import time
4
+
5
+ import toml
6
+ import requests
7
+ import subprocess
8
+ import os
9
+ import re
10
+ import json
11
+ import datetime
12
+ from pathlib import Path
13
+
14
+ # キャッシュと設定の管理
15
+ DEFAULT_CONFIG_PATH = Path(__file__).parent / "config.toml"
16
+ CACHE_FILE = Path.home() / ".mimic_package_cache.json"
17
+ USER_CONFIG_FILE = Path.home() / ".mimic_config.toml"
18
+ REMOTE_CONFIG_URL = "https://raw.githubusercontent.com/disnana/mimic-check/main/config.toml"
19
+
20
+
21
+ def load_remote_config():
22
+ try:
23
+ res = requests.get(REMOTE_CONFIG_URL, timeout=5)
24
+ if res.status_code == 200:
25
+ return toml.loads(res.text)
26
+ except Exception:
27
+ pass
28
+ return None
29
+
30
+
31
+ def load_cache():
32
+ if CACHE_FILE.exists():
33
+ try:
34
+ with open(CACHE_FILE, "r") as f:
35
+ return json.load(f)
36
+ except Exception:
37
+ return {}
38
+ return {}
39
+
40
+
41
+ def save_cache(cache):
42
+ with open(CACHE_FILE, "w") as f:
43
+ json.dump(cache, f, indent=2)
44
+
45
+
46
+ def get_stats(pkg_name, config):
47
+ if pkg_name in config.get("trusted_packages", []):
48
+ return {"downloads": 999999, "stars": 999999, "date": "trusted"}
49
+ # キャッシュを読み込む(存在しない場合は空)
50
+ cache = load_cache()
51
+ today = str(datetime.date.today())
52
+
53
+ # キャッシュの有効性チェック(当日分のみ有効)
54
+ if pkg_name in cache:
55
+ cached_data = cache[pkg_name]
56
+ if cached_data.get("date") == today and cached_data.get("downloads", 0) > 0:
57
+ return cached_data
58
+
59
+ stats = {"downloads": 0, "stars": 0, "date": today}
60
+
61
+ # 1. Downloads (pypistats)
62
+ try:
63
+ url = f"https://pypistats.org/api/packages/{pkg_name}/recent"
64
+ for _ in range(3):
65
+ res = requests.get(url, headers={'User-Agent': 'Mimi-Security-Scanner'}, timeout=5)
66
+ if res.status_code == 200:
67
+ # 公式APIのレスポンス構造(辞書型)に合わせる
68
+ data = res.json().get("data", {})
69
+ stats["downloads"] = data.get("last_month", 0)
70
+ break
71
+ elif res.status_code == 404:
72
+ # 404の場合はPyPIに存在しないとみなし、チェックを即座に終了
73
+ stats["not_found"] = True
74
+ return stats
75
+ else:
76
+ time.sleep(1*_)
77
+ continue
78
+ except Exception as e:
79
+ print(f"DEBUG: Pypistats failed for {pkg_name}: {e}")
80
+
81
+ # 2. Stars (GitHub API)
82
+ try:
83
+ pypi_res = requests.get(f"https://pypi.org/pypi/{pkg_name}/json", timeout=5)
84
+ if pypi_res.status_code == 200:
85
+ pypi_res = pypi_res.json()
86
+ urls = pypi_res["info"].get("project_urls", {})
87
+ if urls:
88
+ candidates = [url for url in urls.values() if "github.com" in url]
89
+ repo_path = None
90
+
91
+ for url in candidates:
92
+ # 除外キーワード
93
+ if any(k in url for k in ["/sponsors/", "/issues/", "/pulls/"]):
94
+ continue
95
+ # 正確なキャプチャ
96
+ match = re.search(r"github\.com/([^/]+)/([^/]+)", url)
97
+ if match:
98
+ repo_path = f"{match.group(1)}/{match.group(2)}"
99
+ break
100
+
101
+ if repo_path:
102
+ api_url = f"https://api.github.com/repos/{repo_path}"
103
+ gh_res = requests.get(api_url, headers={'User-Agent': 'Mimi-Security-Scanner'}, timeout=5)
104
+ if gh_res.status_code == 200:
105
+ stats["stars"] = gh_res.json().get("stargazers_count", 0)
106
+ except Exception as e:
107
+ print(f"DEBUG: GitHub lookup failed for {pkg_name}: {e}")
108
+
109
+ # 基準を満たした場合のみキャッシュする(=未合格ならキャッシュされず、次回も再検証される)
110
+ min_dl = config.get("min_downloads", 1000)
111
+ min_st = config.get("min_stars", 10)
112
+
113
+ if stats["downloads"] >= min_dl or stats["stars"] >= min_st:
114
+ cache[pkg_name] = stats
115
+ save_cache(cache)
116
+
117
+ return stats
118
+
119
+
120
+ def levenshtein_distance(s1, s2):
121
+ s1, s2 = s1.lower(), s2.lower()
122
+ if len(s1) < len(s2): s1, s2 = s2, s1
123
+ if len(s2) == 0: return len(s1)
124
+ prev = range(len(s2) + 1)
125
+ for i, c1 in enumerate(s1):
126
+ curr = [i + 1]
127
+ for j, c2 in enumerate(s2):
128
+ curr.append(min(prev[j + 1] + 1, curr[j] + 1, prev[j] + (c1 != c2)))
129
+ prev = curr
130
+ return prev[-1]
131
+
132
+
133
+ def analyze_package(pkg_name, config):
134
+ # タイポチェック
135
+ for famous in config.get("famous_packages", []):
136
+ dist = levenshtein_distance(pkg_name, famous)
137
+ if 0 < dist <= 2:
138
+ return f"🚨 TYPO ALERT: '{pkg_name}' is close to '{famous}'"
139
+
140
+ # 安全性評価 (configで閾値を可変に)
141
+ stats = get_stats(pkg_name, config)
142
+
143
+ if stats.get("not_found"):
144
+ return f"🚨 NOT FOUND: '{pkg_name}' was not found on PyPI"
145
+
146
+ downloads = stats["downloads"]
147
+ stars = stats["stars"]
148
+
149
+ min_dl = config.get("min_downloads", 1000)
150
+ min_st = config.get("min_stars", 10)
151
+
152
+ if downloads >= min_dl or stars >= min_st:
153
+ return None
154
+
155
+ return f"⚠️ UNVERIFIED: '{pkg_name}' (Downloads: {downloads}, Stars: {stars})"
156
+
157
+
158
+ def main():
159
+ # WindowsのコンソールでUnicode出力をサポートするための設定
160
+ if sys.platform == "win32":
161
+ import io
162
+ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
163
+ sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
164
+
165
+ parser = argparse.ArgumentParser()
166
+ parser.add_argument("--file", default="requirements.txt")
167
+ parser.add_argument("--config")
168
+ parser.add_argument("--ci", action="store_true")
169
+ args = parser.parse_args()
170
+
171
+ # 設定ファイルの読み込み優先順位:
172
+ # 1. 引数 --config
173
+ # 2. ユーザーホームディレクトリの .mimic_config.toml
174
+ # 3. カレントディレクトリの config.toml
175
+ # 4. パッケージ同梱のデフォルト config.toml
176
+
177
+ # 設定ファイルの読み出し
178
+ config = None
179
+ config_path = None
180
+
181
+ if args.config:
182
+ config_path = Path(args.config)
183
+ if config_path.exists():
184
+ config = toml.load(config_path)
185
+ elif USER_CONFIG_FILE.exists():
186
+ config_path = USER_CONFIG_FILE
187
+ config = toml.load(config_path)
188
+ elif Path("config.toml").exists():
189
+ config_path = Path("config.toml")
190
+ config = toml.load(config_path)
191
+
192
+ # ローカルに見つからない場合はリモート(GitHub)を試行
193
+ if config is None:
194
+ config = load_remote_config()
195
+ if config:
196
+ config_path = REMOTE_CONFIG_URL
197
+
198
+ # リモートもダメなら同梱のデフォルト
199
+ if config is None:
200
+ config_path = DEFAULT_CONFIG_PATH
201
+ if config_path.exists():
202
+ config = toml.load(config_path)
203
+
204
+ if config is None or "mimi" not in config:
205
+ print(f"Config load error: Could not find valid config")
206
+ sys.exit(1)
207
+
208
+ config = config["mimi"]
209
+
210
+ with open(args.file, "r") as f:
211
+ lines = [line.strip() for line in f if line.strip() and not line.startswith("#")]
212
+
213
+ safe_lines = []
214
+ for line in lines:
215
+ match = re.match(r"^([a-zA-Z0-9\-_.]+)", line)
216
+ if not match: continue
217
+ pkg_name = match.group(1)
218
+
219
+ issue = analyze_package(pkg_name, config)
220
+ if issue:
221
+ print(issue)
222
+ if args.ci: sys.exit(1)
223
+ if input(f"Proceed with '{line}'? [y/N]: ").lower() != 'y': continue
224
+
225
+ safe_lines.append(line)
226
+
227
+ tmp_file = "requirements.tmp.txt"
228
+ with open(tmp_file, "w") as f:
229
+ f.write("\n".join(safe_lines))
230
+
231
+ subprocess.run([sys.executable, "-m", "pip", "install", "-r", tmp_file])
232
+ os.remove(tmp_file)
233
+
234
+
235
+ if __name__ == "__main__":
236
+ main()
@@ -0,0 +1,111 @@
1
+ Metadata-Version: 2.4
2
+ Name: mimic-check
3
+ Version: 0.1.0
4
+ Summary: A security tool to check for typosquatting and package reliability in requirements.txt
5
+ Author-email: Disnana <support@disnana.com>
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.7
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: requests
12
+ Requires-Dist: toml
13
+
14
+ # mimic-check
15
+
16
+ `mimic-check` は、`requirements.txt` に記載された Python パッケージの安全性を検証するためのツールです。
17
+ タイポスクワッティング(有名なパッケージに似た名前の悪意あるパッケージ)の検出や、ダウンロード数・GitHub スター数に基づいた信頼性の評価を行います。
18
+
19
+ ## 特徴
20
+
21
+ - **タイポ検出**: `requests` を `reqeusts` と書き間違えているようなケースを検出し警告します。
22
+ - **信頼性評価**: PyPI のダウンロード数(直近1ヶ月)と GitHub のスター数を確認し、閾値未満のパッケージを警告します。
23
+ - **効率的なキャッシュ**: 検証結果を当日中のみ有効なキャッシュとして保存し、不要な API リクエストを削減します。
24
+ - **PyPI 存在確認**: パッケージが PyPI に存在しない場合、即座に警告し後続のチェックをスキップします。
25
+ - **CI 対応**: `--ci` フラグを使用することで、問題検出時に非ゼロの終了コードで終了し、パイプラインを停止させることができます。
26
+
27
+ ## セットアップ
28
+
29
+ ### 必要条件
30
+
31
+ - Python 3.x
32
+ - `requests`, `toml` パッケージ
33
+
34
+ ### インストール
35
+
36
+ PyPIからインストールする場合(公開後):
37
+
38
+ ```bash
39
+ pip install mimic-check
40
+ ```
41
+
42
+ ローカルで開発用にインストールする場合:
43
+
44
+ ```bash
45
+ pip install -e .
46
+ ```
47
+
48
+ これにより、`mimi` コマンドが使用可能になります。
49
+
50
+ ## 使い方
51
+
52
+ ### 基本的な実行
53
+
54
+ ```bash
55
+ mimi --file requirements.txt
56
+ ```
57
+
58
+ 実行すると、パッケージごとに以下のチェックが行われます:
59
+ 1. 有名パッケージとの名前の類似性(タイポ)チェック
60
+ 2. PyPI での存在確認
61
+ 3. ダウンロード数とスター数の確認
62
+
63
+ 問題が見つかった場合、警告が表示され、続行するかどうかを確認されます。`y` を入力すると、そのパッケージを含めた一時的な requirements ファイルで `pip install` が実行されます。
64
+
65
+ ### CI モードでの実行
66
+
67
+ CI/CD パイプラインなどで、問題検出時に自動的にエラーとしたい場合は `--ci` フラグを使用します。
68
+
69
+ ```bash
70
+ mimi --file requirements.txt --ci
71
+ ```
72
+
73
+ ## PyPIへの配布方法
74
+
75
+ 1. ビルドツールのインストール:
76
+ ```bash
77
+ pip install build twine
78
+ ```
79
+
80
+ 2. パッケージのビルド:
81
+ ```bash
82
+ python -m build
83
+ ```
84
+
85
+ 3. PyPIへのアップロード (テスト環境):
86
+ ```bash
87
+ python -m twine upload --repository testpypi dist/*
88
+ ```
89
+
90
+ 4. PyPIへのアップロード (本番環境):
91
+ ```bash
92
+ python -m twine upload dist/*
93
+ ```
94
+
95
+ ## 設定 (`config.toml`)
96
+
97
+ プロジェクトのルートにある `config.toml` で動作をカスタマイズできます。
98
+
99
+ ```toml
100
+ [mimi]
101
+ min_downloads = 1000 # 信頼できるとみなす最小ダウンロード数
102
+ min_stars = 10 # 信頼できるとみなす最小 GitHub スター数
103
+ famous_packages = ["requests", "numpy", "pandas", ...] # タイポチェック対象の有名パッケージ
104
+ trusted_packages = [] # チェックをスキップする信頼済みパッケージ
105
+ ```
106
+
107
+ ## キャッシュ
108
+
109
+ `package_cache.json` に検証結果がキャッシュされます。
110
+ - キャッシュは日付ごとに管理され、翌日には自動的に再検証されます。
111
+ - 信頼性の基準を満たしたパッケージのみがキャッシュされ、警告対象のパッケージは毎回チェックされます。
@@ -0,0 +1,10 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/mimic/__init__.py
4
+ src/mimic/main.py
5
+ src/mimic_check.egg-info/PKG-INFO
6
+ src/mimic_check.egg-info/SOURCES.txt
7
+ src/mimic_check.egg-info/dependency_links.txt
8
+ src/mimic_check.egg-info/entry_points.txt
9
+ src/mimic_check.egg-info/requires.txt
10
+ src/mimic_check.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ mimi = mimic.main:main
@@ -0,0 +1,2 @@
1
+ requests
2
+ toml