Skip to content

Fix/issue62569 - #1900

Closed
mhaya wants to merge 27 commits into
develop_v2.0.4from
fix/issue62569
Closed

Fix/issue62569#1900
mhaya wants to merge 27 commits into
develop_v2.0.4from
fix/issue62569

Conversation

@mhaya

@mhaya mhaya commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

security fix

mhaya and others added 26 commits August 26, 2026 23:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bkXKrjzJ2VNWVwTpDAPuZ
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bkXKrjzJ2VNWVwTpDAPuZ
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bkXKrjzJ2VNWVwTpDAPuZ
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bkXKrjzJ2VNWVwTpDAPuZ
--allow-writes の測定はインデックス削除系も叩くため、実行のたびに
検証用インデックスに is_deleted が立つことがある。これまでは
「無ければ作る」だけで、既にある行の状態は見ていなかった。

削除済みのまま残ると次回以降の測定が壊れる。コミュニティ配下の
判定は Indexes.get_child_list_recursive を通り、この関数は
is_deleted を除いたうえで .one() するので、ルートが削除済みだと
NoResultFound になり、認可判定が結果を返す前に例外で終わる。
コミュニティ管理者の測定値が実態とずれる。

- インデックスは毎回 is_deleted / parent / public_state を入れ直す
- コミュニティのルートが存在しない場合は差し替える
- index_health を追加し、全コミュニティについて
  「ルートから部分木を辿れるか」を実際に呼んで確認する。
  直した内容と、直せなかったものを fixtures.json と実行ログに出す
- 子インデックス(900011)を足し、他人所有のレコードをその配下に置く。
  深さ1のままでは「ルートと一致するか」しか見ておらず、
  部分木をたどる判定を測れていなかった

measure.sh は修復・未解決の明細行も表示するようにした。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bkXKrjzJ2VNWVwTpDAPuZ
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bkXKrjzJ2VNWVwTpDAPuZ
fixtures.json は平文パスワードと OAuth アクセストークンを含むため
追跡していない。その結果、測定条件(measure_profile.json)は追跡して
いるのに、その条件を当てた対象がどこにも残らない状態だった。
後から測定結果を読むとき「どの recid のどのファイルに対して
測ったのか」が分からないと解釈できない。

fixtures.py に --redact-out を追加した。秘密2つだけを (redacted) に
した同じ内容をもう1本書き出す。recid / バケット / インデックス /
activity_id などの ID は隠さない。隠す理由が無く、隠すと記録の
用途を果たさないため。

measure.sh は毎回 $WEKO_API_INVENTORY_DIR/fixtures_snapshot.json に
書き出す。こちらは台帳リポジトリ側で追跡する。

記録専用で、読み込んで測定することはできない(トークンが伏せてある)。
環境を作り直すのは従来どおり fixtures.py を流す。

README に生成物を2本に分けている理由を書いた。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bkXKrjzJ2VNWVwTpDAPuZ
install.sh のあとにこれを流せばテスト環境とデモ環境が整う、という
位置づけにした。

秘密を持たせない
  アクセストークンを固定のダミー値にした。生成値だと実行のたびに
  fixtures.json が変わるうえ、記録として残せない。パスワードは元から
  本スクリプトの定数(既に公開)で、伏せる意味が無かった。
  前コミットで入れた --redact-out は不要になったので削除した。
  fixtures.json は台帳リポジトリ側で追跡する。

  トークンは冪等にした。旧実装は実行のたびに新しい行を作っており、
  溜まったものを片付けるようにした。

規模を選べるようにした
  --scale 0(既定) はテストに必要な最低限だけ。
  100 / 1000 / 10000 / 100000 / 1000000 を想定。
  1万件以上を ORM で作ると現実的な時間に収まらないので core insert。
  冪等で、不足分だけ足す。measure.sh は既定(0)で呼ぶ。

機関リポジトリらしいデータにした
  インデックスを 紀要論文 / 学位論文 / 研究報告書 / 会議発表資料 /
  非公開資料 に分け、タイトル・著者(和英)・資料種別(COAR URI)・
  公開年月をばらした。1割を非公開にしてある。

クリーン機能を足した
  --clean demo   デモ用アイテムのみ
  --clean all    本スクリプトが作るもの全部(ユーザは消さない)

  クリーン -> 再構築を通して初めて表面化した不具合を3つ直した。
  - リダイレクト済みの親PIDが削除条件から漏れていた。insert_child が
    親を REDIRECTED にして object_uuid を Redirect 行の id に
    書き換えるため、レコードの uuid では引けない。残ると次回の
    redirect() が存在しない行を触って落ちる(pid_versioning の失敗)
  - files_bucket を records_buckets より先に消して FK 違反
  - pid_value(varchar) に数値を渡して型比較で失敗

  クリーン後に作り直しても測定値が一致することを確認した。

item_metadata を作るようにした
  無いと ES への反映が NoResultFound で落ちる。ただし完全な解決には
  至っていない。get_record_without_version(dep.pid) が depid を渡され
  親リレーションを引けず None を返すためで、これは本フィクスチャに
  限らずワークフロー経由で作られていないレコード全般で起きる
  (既存の recid 1003 でも同じ)。到達可否の測定には影響しない。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bkXKrjzJ2VNWVwTpDAPuZ
環境を作り直すのではなく既知の状態へ戻す運用にしたいが、
現状のままでは動かない箇所があったので手当てした。

動かなかった点
  - docker-compose(v1)決め打ち。v2 しか無い環境で起動しない
  - リポジトリ直下からしか動かない(./scripts/demo/... の相対パス)
  - docker-compose exec は TTY を要求するため CI で失敗する
  - 初回は ES スナップショットの削除が 404 になり errexit で止まる
  - restore が sudo chown を要求する
  - docker compose ps -q はプロジェクト名や実行ディレクトリに依存して
    空を返す。他のツール群と同じくラベルで探すようにした

変えた点
  - すべて docker exec に統一し、コンテナはラベルで検出
  - スクリプト位置から ROOT を解決。どこから叩いてもよい
  - ファイルの退避/復元を docker cp に統一。bind mount 前提と
    所有者のずれを解消し、sudo を不要にした
  - 引数で退避先/復元元を指定できるようにした(無指定は従来どおり)。
    複数世代を残せる
  - manifest.json を追加。リビジョン・日時・未コミットの有無・
    fixtures の構成を記録する。ダンプは中身を差分で読めないため、
    いつ・どのコードで取ったかが分からないと使えなくなる
  - 復元後に別バージョンなら alembic upgrade が要る旨を出力

-T alembic_version で除外する既存の方針はそのまま。
「データは戻す、スキーマはコードが作る」という意図をコメントにした。

実測: 退避 1秒 / 30MB、復元 44秒。
退避 -> 復元を通し、records 85 / index 8 / users 5 / community 2 が
戻り、トップページ 200、認可(271 が未認証 401)も維持されることを
確認している。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bkXKrjzJ2VNWVwTpDAPuZ
アイテムタイプをデフォルトアイテムタイプ(フル)(30002)に統一した。
これまで使っていた 1〜14 は harvesting_type=t のハーベスト用で、
登録アイテムに充てるのは誤りだった。

投入するもの(--scale とは無関係に常に作る)
  900100      全項目を埋めたアイテム1件
  900101〜113 リソースタイプ別13件
              journal article / departmental bulletin paper /
              doctoral thesis / conference paper / research report /
              technical report / dataset / software / book /
              still image / sound / learning object / other

項目は手書きせずアイテムタイプのスキーマから生成する。enum があれば
先頭の有効値、array/object は再帰、文字列はキー名と format から
日付/URI/メールを判定する。アイテムタイプが変わっても追随する。

records_metadata 側(attribute_name/attribute_value_mlt で包む形)と
item_metadata 側(登録フォームの生の形)の両方に入れる。

resourcetype と COAR URI の対応は推測せず、リポジトリ内の既存データ
から抽出した53件の対応を使っている。

確認: 900100 はスキーマの47項目すべてを充足(未充足なし)。
--clean all -> 再投入を通し、17件の削除と14件の再作成を確認した。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bkXKrjzJ2VNWVwTpDAPuZ
インデックス(900016〜900022)とアイテム(900201〜900207)を追加した。
公開状態・公開日・閲覧ロール・閲覧グループ・投稿ロール・ハーベスト・
親子の継承を一通り作る。

  900016 公開前資料        public_date=2099-01-01
  900017 ログイン限定      browsing_role="1,2,3,4,-98" (-99 が無い)
  900018 管理者限定        browsing_role="1,2"
  900019 グループ限定      browsing_group=<group>
  900020 投稿制限          contribute_role="1,2"
  900021 ハーベスト非公開  harvest_public_state=False
  900022 非公開の親の子    parent=900015

weko_index_tree.utils.check_roles の仕様に合わせている。-99 があれば
未ログインでも閲覧可、認証済みは自分の全ロールがリストに含まれる
必要がある(AND判定)。

PID のバージョン構造を実データに合わせた
  詳細画面は PIDVersioning(child=pid).is_last_child が真だと 404 に
  する。実レコードは parent:<n> の下に <n> / <n>.0 / <n>.1 を持ち
  base が最後の子でないため通る。これまで <n> ひとつしか作って
  おらず、権限を通っても必ず 404 になっていた。
  <n> と <n>.1 をぶら下げるようにした。

  リレーション種別も実データに合わせた(2=バージョン、3=recid->depid)。
  PIDVersioning.insert_child は親を REDIRECTED にするが実データの親は
  R のままなので使わず、PIDRelation を直接張る。

  これで ES への反映も通るようになった。errors=3 -> 0。
  「ワークフロー経由で作らないと ES に載らない」というのは誤りで、
  原因はこの PID 構造の欠落だった。

詳細画面が見る relation_version_is_last / owners / author_link も
レコードに入れるようにした。

確認(未認証 / contributor / sysadmin):
  公開通常・全項目          200 / 200 / 200
  管理者限定・公開前
  ログイン限定・非公開の親  302 / 200 / 200
  グループ限定・ハーベスト
  非公開・投稿制限          200 / 200 / 200
後半が 200 なのは仕様どおり。browsing_group は許可の追加であって
制限ではなく、harvest_public_state は OAI-PMH、contribute_role は
投稿にしか効かない。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bkXKrjzJ2VNWVwTpDAPuZ
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown

Claude によるレビュー

指摘 0 件(コスト $0.8526)

差分のみを対象にした自動レビューです。誤りが含まれることがあります。

--scale で作るアイテムは recid と depid しか持っておらず、詳細画面が
必ず 404 になっていた。一覧やページングには使えるが、デモ環境として
アイテムを開けないのは片手落ちだった。

最低限セットと同じ構成にした。1件あたり PID 5本
(recid <n> / depid <n> / recid <n>.1 / depid <n>.1 / parent:<n>)と
リレーション4本。5本とも同じ object_uuid を指す。版ごとに別レコードを
作るまでの必要はなく、レコード行数を増やさずに済む。

件数が多いのでリレーションは INSERT ... SELECT で一括生成する。
5本の PID が同じ object_uuid を指すのでそこで結合できる。
NOT EXISTS を付けてあるので再実行しても増えない。

--clean demo も直した。PID を参照する pidrelations / pidstore_redirect
を先に落とさないと FK で失敗する。

途中で踏んだもの
  - DEMO_KINDS を3要素にした際にアンパックが4要素のままだった
  - pidrelations_pidrelation の created / updated が NOT NULL

確認
  publish_status=0 のデモアイテム -> 200(公開)
  publish_status=1 のデモアイテム -> 302(ログインへ)
  100件: PID 500 / リレーション 400
  100 -> 1000 の増分900件で 13.4秒(うち約11秒はアプリ起動の固定費)
  再実行しても「既存1000 + 新規0」で件数は増えない
  --clean demo で 1000件を削除しても最低限セット(900100/900101/900201)は無傷

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bkXKrjzJ2VNWVwTpDAPuZ
@mhaya

mhaya commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

内容を整理して作り直します。

@mhaya mhaya closed this Aug 28, 2026
@github-actions

Copy link
Copy Markdown

API インベントリ差分(件数のみ)

明細は公開できないため件数のみ表示しています。該当箇所はプライベートリポジトリ側の台帳・レポートで確認してください。

ベースラインとの差分

API インベントリ差分レポート

  • 旧: d2fdc0e3b v2.0.3 (profile=default) endpoints=928 (外部ライブラリ由来 359)
  • 新: 76e790240 v2.0.3-70-g76e790240 (profile=default) endpoints=928 (外部ライブラリ由来 359)

判定: ✅ PASS (FAIL 0 / WARN 1)

サマリ

分類 件数
ADDED 0
REMOVED 0
RULE_CHANGED 0
METHODS_CHANGED 0
AUTH_CHANGED 22
IMPL_CHANGED 0
ATTRS_UNKNOWN_NEW 0
ModelView 追加 0
ModelView 削除 0
ModelView フラグ変化 0
config 変化 0
コメントアウト認証の増加 0
依存パッケージの版変化 2

[WARN] W6 依存パッケージの版が変化した — 2件

  • pyld — 3.1.0 -> 3.2.0
  • weko-redis — 0.1.0.dev20170000 -> (削除)

台帳との突き合わせ

スナップショット ↔ インベントリ 突き合わせ

  • リビジョン: 76e790240 v2.0.3-70-g76e790240 経路URI=908
  • 台帳: 行=1048 URI=919

件数のみ。詳細はプライベートリポジトリ側の完全版レポートを参照。

判定: ✅ 一致 (0件)

検出 件数
A. インベントリ未収載(抽出漏れ) 0
B. 実機に無い(未説明) 0
B'. 実機に無い(既知・許容) 11
C. メソッド不一致 0
D. app列の不一致 0
E. endpoint 未収載 0
E'. endpoint が実機に無い(参考) 1

@github-actions

Copy link
Copy Markdown

API インベントリ差分(件数のみ)

明細は公開できないため件数のみ表示しています。該当箇所はプライベートリポジトリ側の台帳・レポートで確認してください。

ベースラインとの差分

API インベントリ差分レポート

  • 旧: d2fdc0e3b v2.0.3 (profile=default) endpoints=928 (外部ライブラリ由来 359)
  • 新: f5bfd6547 v2.0.3-71-gf5bfd6547 (profile=default) endpoints=928 (外部ライブラリ由来 359)

判定: ✅ PASS (FAIL 0 / WARN 1)

サマリ

分類 件数
ADDED 0
REMOVED 0
RULE_CHANGED 0
METHODS_CHANGED 0
AUTH_CHANGED 22
IMPL_CHANGED 0
ATTRS_UNKNOWN_NEW 0
ModelView 追加 0
ModelView 削除 0
ModelView フラグ変化 0
config 変化 0
コメントアウト認証の増加 0
依存パッケージの版変化 2

[WARN] W6 依存パッケージの版が変化した — 2件

  • pyld — 3.1.0 -> 3.2.0
  • weko-redis — 0.1.0.dev20170000 -> (削除)

台帳との突き合わせ

スナップショット ↔ インベントリ 突き合わせ

  • リビジョン: f5bfd6547 v2.0.3-71-gf5bfd6547 経路URI=908
  • 台帳: 行=1048 URI=919

件数のみ。詳細はプライベートリポジトリ側の完全版レポートを参照。

判定: ✅ 一致 (0件)

検出 件数
A. インベントリ未収載(抽出漏れ) 0
B. 実機に無い(未説明) 0
B'. 実機に無い(既知・許容) 11
C. メソッド不一致 0
D. app列の不一致 0
E. endpoint 未収載 0
E'. endpoint が実機に無い(参考) 1

mhaya added a commit that referenced this pull request Aug 28, 2026
同じ差分でも実行のたびに結果が揺れる。作り直しただけで内容が同一の
PR #1900#1901 で、指摘 0 件と 1 件に割れた実績がある
(#1900 が iframe の不備を見逃していた)。

1. REVIEW_PASSES(既定3)回まわして和集合を取る
   file / line / title で重複を除く。title は空白を潰して突き合わせる。
   何回のパスで挙がったかを数え、全パスで挙がらなかったものには
   「(1/3 パス)」を添える。判断材料になる。
   1回失敗しても残りは続行し、得られた分だけで集計する。

2. 裏が取れなかったものを捨てず unverified に出す
   これまでは「裏が取れなかったものは書かない」としており、
   指摘を減らす方向に振れていた。findings とは分けたうえで
   折りたたみで出す。確認できなかった理由も書かせる。
   認可まわりでは誤検知より見逃しのほうが高くつく。

3. 出力を一般的な AI レビューの体裁に寄せた
   - 冒頭に重大度別の内訳
   - 指摘ごとに見出し。重大度を絵文字と日本語で示す
   - 直し方が明確なら「提案」を出させる(suggestion を追加)
   - 根拠(該当行の抜粋・確認したファイル)は折りたたみ
   - 未確認も折りたたみ
   - 末尾にモデル・実行回数・コスト

集計と描画は実データ形式のダミーで確認した。表記揺れのある同一指摘が
1件に統合され、1パスでしか挙がらなかった指摘が回数付きで残る。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bkXKrjzJ2VNWVwTpDAPuZ
ryoya-hayase pushed a commit to ivis-weko3-dev/weko that referenced this pull request Aug 29, 2026
同じ差分でも実行のたびに結果が揺れる。作り直しただけで内容が同一の
PR RCOSDP#1900RCOSDP#1901 で、指摘 0 件と 1 件に割れた実績がある
(RCOSDP#1900 が iframe の不備を見逃していた)。

1. REVIEW_PASSES(既定3)回まわして和集合を取る
   file / line / title で重複を除く。title は空白を潰して突き合わせる。
   何回のパスで挙がったかを数え、全パスで挙がらなかったものには
   「(1/3 パス)」を添える。判断材料になる。
   1回失敗しても残りは続行し、得られた分だけで集計する。

2. 裏が取れなかったものを捨てず unverified に出す
   これまでは「裏が取れなかったものは書かない」としており、
   指摘を減らす方向に振れていた。findings とは分けたうえで
   折りたたみで出す。確認できなかった理由も書かせる。
   認可まわりでは誤検知より見逃しのほうが高くつく。

3. 出力を一般的な AI レビューの体裁に寄せた
   - 冒頭に重大度別の内訳
   - 指摘ごとに見出し。重大度を絵文字と日本語で示す
   - 直し方が明確なら「提案」を出させる(suggestion を追加)
   - 根拠(該当行の抜粋・確認したファイル)は折りたたみ
   - 未確認も折りたたみ
   - 末尾にモデル・実行回数・コスト

集計と描画は実データ形式のダミーで確認した。表記揺れのある同一指摘が
1件に統合され、1パスでしか挙がらなかった指摘が回数付きで残る。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bkXKrjzJ2VNWVwTpDAPuZ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant