Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions tools/api-inventory/scripts/add_authmech.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def _write(path, hd, data, newcols):
"""既存の同名列は **その位置のまま値を差し替える**。無い列だけ末尾に足す。

末尾に付け直すと列順が変わり、README の awk 例や他スクリプトの
列位置前提(c[13]=impl_file 等)が壊れる。
列位置前提(_col(c,"impl_file")=impl_file 等)が壊れる。
"""
pos = {n: i for i, n in enumerate(hd)}
add_cols = [n for n in newcols if n not in pos]
Expand Down Expand Up @@ -48,6 +48,14 @@ def _write(path, hd, data, newcols):
def load(p): return [l.rstrip("\n").split("\t") for l in open(p,encoding="utf-8") if l.rstrip("\n")]
rows=load(TSV); hd=rows[0]; data=rows[1:]

def _col(c, name, _cache={}):
"""列名で引く。列の統合・追加で位置がずれても壊れないようにするため。"""
if not _cache:
_cache.update({n: i for i, n in enumerate(hd)})
i = _cache.get(name)
return c[i] if i is not None and len(c) > i else ""


filecache={}
def get_file(fp):
if fp in filecache: return filecache[fp]
Expand Down Expand Up @@ -78,16 +86,16 @@ def func_src(fp,ln):

# --- auth_mechanism: この行の認証はどこで定義されるか ---
def col_mech(c):
at=c[2] # api_type
am=c[21] # auth_method
at=_col(c,"api_type") # api_type
am=_col(c,"auth_method") # auth_method
if "ModelView" in at: return "modelview(Flask-Admin is_accessible/role_has_access)"
if at=="フレームワーク": return "framework(invenio/flask-security既定)"
# config駆動REST判定: uriに<string:version>やREST系、blueprintが*_rest
bp=c[10]
if bp.endswith("_rest") or bp.endswith("_rest2") or "REST" in c[11] or "_options" in c[11]:
bp=_col(c,"blueprint")
if bp.endswith("_rest") or bp.endswith("_rest2") or "REST" in _col(c,"endpoint") or "_options" in _col(c,"endpoint"):
return "config-factory(*_REST_ENDPOINTS permission_factory_imp)"
if am=="admin-role-table": return "modelview/admin(role_has_access)"
if am in("none","rate-limit-only","不要") or c[20]=="不要": return "none(デコレータ無し・公開)"
if am in("none","rate-limit-only","不要") or _col(c,"auth_required")=="不要": return "none(デコレータ無し・公開)"
if "action-need" in am: return "decorator(@x_permission.require)"
if "record-permission" in am: return "decorator(@need_record_permission)"
if "files-action" in am: return "decorator(@need_permissions)+ActionRole(グローバル付与注意)"
Expand All @@ -99,22 +107,22 @@ def col_mech(c):
# --- bola_risk: object-level認可(所有者/対象単位チェック)が実装にあるか ---
OWNER=re.compile(r"created_by|check_created_id|owner|current_user\.(id|get_id)|weko_shared|can_edit|is_himself|has_permission|check_authority|activity_login_user|check_index_permission|permission_factory|need_record_permission|get_or_404|filter_by\([^)]*user")
def col_bola(c,seg):
m=(c[4] or "GET").split(",")[0]
m=(_col(c,"method") or "GET").split(",")[0]
# パスにリソースID(<...pid/id/recid...>)があるか
has_id=bool(re.search(r"<[^>]*(pid_value|recid|id|identifier|bucket_id|activity_id|group_id|key)", c[5]))
has_id=bool(re.search(r"<[^>]*(pid_value|recid|id|identifier|bucket_id|activity_id|group_id|key)", _col(c,"uri")))
if not has_id: return "N/A(リソースID無し)"
if "ModelView" in c[2]: return "admin-role-tableのみ(オブジェクト単位判定なし=管理者は全件)"
if "ModelView" in _col(c,"api_type"): return "admin-role-tableのみ(オブジェクト単位判定なし=管理者は全件)"
if OWNER.search(seg): return "object-level認可あり(所有者/対象単位)"
# sec_patternに所有者チェック欠落があれば実証済み
if len(c)>41 and "所有者チェック欠落" in c[41]: return "★object-level認可なし(BOLA・実証済)"
if "所有者チェック欠落" in _col(c,"sec_pattern"): return "★object-level認可なし(BOLA・実証済)"
return "★object-level認可なし(要確認・ID直指定で他リソース操作の懸念)"

mech_c=collections.Counter() if False else {}
nb=0
import collections
mc=collections.Counter(); bc=collections.Counter()
for c in data:
seg=func_src(c[13],c[14]) if (len(c)>14 and str(c[14]).isdigit() and c[14]!="0") else ""
seg=func_src(_col(c,"impl_file"),_col(c,"impl_line")) if (str(_col(c,"impl_line")).isdigit() and _col(c,"impl_line")!="0") else ""
mech=col_mech(c); bola=col_bola(c,seg)
c += [mech,bola]
mc[mech.split("(")[0]]+=1; bc[bola.split("(")[0]]+=1
Expand Down
18 changes: 13 additions & 5 deletions tools/api-inventory/scripts/add_cols.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def _write(path, hd, data, newcols):
"""既存の同名列は **その位置のまま値を差し替える**。無い列だけ末尾に足す。

末尾に付け直すと列順が変わり、README の awk 例や他スクリプトの
列位置前提(c[13]=impl_file 等)が壊れる。
列位置前提(_col(c,"impl_file")=impl_file 等)が壊れる。
"""
pos = {n: i for i, n in enumerate(hd)}
add_cols = [n for n in newcols if n not in pos]
Expand Down Expand Up @@ -48,6 +48,14 @@ def _write(path, hd, data, newcols):
def load(p): return [l.rstrip("\n").split("\t") for l in open(p,encoding="utf-8") if l.rstrip("\n")]
rows=load(TSV); hd=rows[0]; data=rows[1:]

def _col(c, name, _cache={}):
"""列名で引く。列の統合・追加で位置がずれても壊れないようにするため。"""
if not _cache:
_cache.update({n: i for i, n in enumerate(hd)})
i = _cache.get(name)
return c[i] if i is not None and len(c) > i else ""


# 実装関数のソース断片をキャッシュ
srccache={}
def get_src(fp,ln):
Expand All @@ -70,12 +78,12 @@ def get_src(fp,ln):
srccache[key]=seg; return seg

def col_csrf(c,seg):
m=c[4];
m=_col(c,"method");
if not re.search(r"POST|PUT|DELETE|PATCH",m): return "N/A(参照系)"
if "csrf_random" in seg or "validate_csrf" in seg: return "手動csrf照合あり"
# このアプリはCSRFProtect未初期化 → session認証の状態変更は無防備
if c[21] in("session","session+guest") or "session" in c[21] or c[20]=="要":
if "oauth" in c[21] or "Bearer" in seg or "require_api_auth" in seg: return "OAuth(CSRF非該当)"
if _col(c,"auth_method") in("session","session+guest") or "session" in _col(c,"auth_method") or _col(c,"auth_required")=="要":
if "oauth" in _col(c,"auth_method") or "Bearer" in seg or "require_api_auth" in seg: return "OAuth(CSRF非該当)"
return "★CSRF保護なし(CSRFProtect未初期化・状態変更)"
return "CSRF該当外(未認証public)"

Expand Down Expand Up @@ -109,7 +117,7 @@ def col_reslimit(seg):

newcols=["csrf_protection","input_validation","audit_logged","triggers_task","resource_limit"]
for c in data:
seg=get_src(c[13],c[14]) if c[14].isdigit() else ""
seg=get_src(_col(c,"impl_file"),_col(c,"impl_line")) if _col(c,"impl_line").isdigit() else ""
c += [col_csrf(c,seg), col_input(seg), col_audit(seg), col_task(seg), col_reslimit(seg)]
_write(TSV, hd, data, ['csrf_protection', 'input_validation', 'audit_logged', 'triggers_task', 'resource_limit'])
# サマリ
Expand Down
26 changes: 18 additions & 8 deletions tools/api-inventory/scripts/add_dataop4.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
"""data_op_detail列: 取得/作成/更新/物理削除/論理削除 を実装から4区分評価"""
"""data_op列: 取得/作成/更新/物理削除/論理削除 を実装から4区分評価

(旧 data_op_detail。data_op と統合したため書き込み先を data_op に変更)"""
import ast,re,os
import os as _os, sys as _sys
_sys.path.insert(0, _os.path.dirname(_os.path.abspath(__file__)))
Expand All @@ -15,7 +17,7 @@ def _write(path, hd, data, newcols):
"""既存の同名列は **その位置のまま値を差し替える**。無い列だけ末尾に足す。

末尾に付け直すと列順が変わり、README の awk 例や他スクリプトの
列位置前提(c[13]=impl_file 等)が壊れる。
列位置前提(_col(c,"impl_file")=impl_file 等)が壊れる。
"""
pos = {n: i for i, n in enumerate(hd)}
add_cols = [n for n in newcols if n not in pos]
Expand Down Expand Up @@ -48,6 +50,14 @@ def _write(path, hd, data, newcols):
def load(p): return [l.rstrip("\n").split("\t") for l in open(p,encoding="utf-8") if l.rstrip("\n")]
rows=load(TSV); hd=rows[0]; data=rows[1:]

def _col(c, name, _cache={}):
"""列名で引く。列の統合・追加で位置がずれても壊れないようにするため。"""
if not _cache:
_cache.update({n: i for i, n in enumerate(hd)})
i = _cache.get(name)
return c[i] if i is not None and len(c) > i else ""


# ファイル全体をキャッシュし、関数本体+同ファイル内で呼ぶヘルパも1段追う
filecache={}
def get_file(fp):
Expand Down Expand Up @@ -102,11 +112,11 @@ def eval4(c,seg,method):

nc=0
for c in data:
method=(c[4] or "GET").split(",")[0]
fp=c[13] if (len(c)>13) else ""; ln=c[14] if len(c)>14 else "0"
method=(_col(c,"method") or "GET").split(",")[0]
fp=_col(c,"impl_file") if (len(c)>13) else ""; ln=_col(c,"impl_line") if len(c)>14 else "0"
# ModelView/frameworkは実パス無し→methodベース
if "ModelView" in c[2] or c[2]=="フレームワーク" or not str(ln).isdigit() or ln=="0":
act=c[11].split(".")[-1] if len(c)>11 else ""
if "ModelView" in _col(c,"api_type") or _col(c,"api_type")=="フレームワーク" or not str(ln).isdigit() or ln=="0":
act=_col(c,"endpoint").split(".")[-1] if len(c)>11 else ""
if act=="delete_view": v="物理削除(Flask-Admin ModelView.delete_model=db.session.delete)"
elif act=="create_view": v="作成"
elif act=="edit_view": v="更新"
Expand All @@ -118,5 +128,5 @@ def eval4(c,seg,method):
v=eval4(c,seg,method)
c.append(v)
if "論理削除" in v or "物理削除" in v: nc+=1
_write(TSV, hd, data, ['data_op_detail'])
print("data_op_detail付与。削除系(論理/物理):",nc,"列数:",len(hd)+1)
_write(TSV, hd, data, ['data_op'])
print("data_op付与。削除系(論理/物理):",nc,"列数:",len(hd))
14 changes: 11 additions & 3 deletions tools/api-inventory/scripts/add_idempotency.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def _write(path, hd, data, newcols):
"""既存の同名列は **その位置のまま値を差し替える**。無い列だけ末尾に足す。

末尾に付け直すと列順が変わり、README の awk 例や他スクリプトの
列位置前提(c[13]=impl_file 等)が壊れる。
列位置前提(_col(c,"impl_file")=impl_file 等)が壊れる。
"""
pos = {n: i for i, n in enumerate(hd)}
add_cols = [n for n in newcols if n not in pos]
Expand Down Expand Up @@ -45,6 +45,14 @@ def _write(path, hd, data, newcols):
R = _os.environ.get("WEKO_ROOT", "/home/mhaya/wekov2") + "/"
def load(p): return [l.rstrip("\n").split("\t") for l in open(p,encoding="utf-8") if l.rstrip("\n")]
rows=load(TSV); hd=rows[0]; data=rows[1:]

def _col(c, name, _cache={}):
"""列名で引く。列の統合・追加で位置がずれても壊れないようにするため。"""
if not _cache:
_cache.update({n: i for i, n in enumerate(hd)})
i = _cache.get(name)
return c[i] if i is not None and len(c) > i else ""

srccache={}
def get_src(fp,ln):
key=(fp,ln)
Expand All @@ -61,7 +69,7 @@ def get_src(fp,ln):
if s<=int(ln)<=e and (best is None or (e-s)<(best[1]-best[0])): best=(s,e)
seg="\n".join(lines[best[0]-1:best[1]]) if best else ""; srccache[key]=seg; return seg
def col_idem(c,seg):
m=c[4].split(",")[0]
m=_col(c,"method").split(",")[0]
if m in("GET","HEAD"): return "N/A(参照系)"
if m in("PUT","DELETE"):
# 状態チェックあれば冪等
Expand All @@ -74,7 +82,7 @@ def col_idem(c,seg):
return "-"
nc=0
for c in data:
seg=get_src(c[13],c[14]) if (len(c)>14) else ""
seg=get_src(_col(c,"impl_file"),_col(c,"impl_line")) if (len(c)>14) else ""
v=col_idem(c,seg); c.append(v)
if "★" in v: nc+=1
_write(TSV, hd, data, ['idempotency'])
Expand Down
Loading
Loading