Skip to content

Hotfix/v2.0.4 - #1954

Merged
ivis-miyachi merged 2 commits into
develop_v2.0.5from
hotfix/v2.0.4
Oct 30, 2026
Merged

ivis-miyachi merged 2 commits into
develop_v2.0.5from
hotfix/v2.0.4

Conversation

@ivis-miyachi

@ivis-miyachi ivis-miyachi commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

概要 (Summary)

関連Issue / チケット (Related Issues)

  • close #

変更タイプ (Type of Change)

  • 🚀 新機能追加 (Feature)
  • 🐛 バグ修正 (Bug Fix)
  • 🔒 セキュリティ修正 (Security Fix)
  • 🚫 機能のクローズ・非公開化・削除 (Feature Deprecation/Disable)
  • ⚠️ 破壊的変更・データ移行を伴う修正 (Breaking Change / Migration)
  • 📚 仕様書・マニュアル・APIリストの更新 (Documentation)

🤖 0. CI 自動チェック (API Inventory Drift)

PR ごとに WEKO3 コンテナを起動し、url_map のダンプ・台帳との突き合わせ・変更行の
到達可否測定を自動実行する。結果は PR コメントと Actions の artifact
(api-inventory-summary) に出る。

このリポジトリは public のため、台帳もベースラインも同梱していない。
実データはプライベートリポジトリ RCOSDP/weko-secret にあり、CI は Secret 経由で取得する。
以降この文書では、そこを単にプライベートリポジトリと呼ぶ。

台帳はブランチごとに内容が違うため、CI は weko 側と同名のブランチを
プライベートリポジトリから探して使う(head → base → 既定ブランチ の順)。
採用されたブランチ名は PR コメントの冒頭に出るので、件数を読む前にそこを見ること。
対応ブランチが無い場合は既定ブランチと比較され、コメント冒頭に警告が出る。
その件数は当てにならないので、PASS でも「確認済み」と読まないこと。
詳細: tools/api-inventory/ci/README.md §3a

  • CI が PASS している、または FAIL の各項目に対処済み
    Secret (API_INVENTORY_REPO / API_INVENTORY_SSH_KEY) が未設定のリポジトリ、
    および fork からの PR では、このジョブは何もせずスキップされる。

API を追加・変更した場合(必須)

  • プライベートリポジトリ側の作業ブランチを、この PR のブランチと同名で切った
    この PR が fix/issue62569 → develop_v2.0.4 なら、プライベート側も
    fix/issue62569 → develop_v2.0.4。同名にしておけば台帳 PR が未マージでも
    CI がそれを見るので、2つの PR のマージ順を気にしなくてよい。
  • プライベートリポジトリの api_snapshot.json を更新し、対応する PR を出した
    bash export WEKO_API_INVENTORY_DIR=/path/to/weko-secret ./install.sh python3 tools/api-inventory/scripts/snapshot.py --out "$WEKO_API_INVENTORY_DIR/api_snapshot.json"
    更新しないと CI が落ちる。公開リポジトリのコード変更とは別の PRになる。
  • プライベートリポジトリの weko3_api_list_full.tsv に行を追加・更新し、
    build_checklist.py で 24 列版を再生成した(未収載だと reconcile が FAIL する)
  • 台帳・スナップショット・実測結果をこの公開リポジトリにコミットしていない
    (git status に *.tsv / api_snapshot.json が出ていないこと)

FAIL したときの対処(要約)

まず PR コメント冒頭の台帳ブランチを見る。警告が出ていれば、件数を追う前に
プライベートリポジトリ側の対応ブランチを用意すること(比較相手が違うので件数に意味がない)。

ジョブが落ちる条件は 3 つある。PR コメントのどのセクションに件数が出ているかで切り分ける。

落ちた場所 落ちる条件
ベースラインとの差分 (drift.md) G1〜G7 のいずれかに該当
台帳との突き合わせ (reconcile.md) A + B + C + D + E の合計が 1 件以上
変更行の到達可否測定 (probe) G8 / G9 に該当(結果は artifact に含めないので Actions のログで件数を見る)
検出 意味 対処
G1 / G2 新規経路に認証系デコレータが無い / 認証系デコレータが削除された 実装を直す。意図的な公開なら台帳に根拠を書いてベースライン更新
G3 認証・認可デコレータのコメントアウトが増えた 原則やり直し。残す場合は理由をコード中のコメントに明記する
G4 *_PERMISSION_FACTORY / CSRF 保護 等が危険側の値に変わった 原則やり直し
G5 ModelView の can_delete / can_export が False → True 意図的なら台帳の data_op を更新
G6 静的解析で属性が取れない経路が追加された 台帳に行を追加してレビューする(外部ライブラリ由来など)
G7 依存パッケージの更新で経路が増減した 増えた経路は台帳に追加。消えた経路は行を削除するか allow に登録
G8 台帳で data_op が作成/更新/削除の経路に、未認証で到達した 原則やり直し。意図的な公開なら台帳の根拠を更新。data_op の記載誤りなら台帳を直す
G9 台帳では遮断なのに実測で到達(認可の回帰) 原則やり直し
reconcile A / E 実機にあるが台帳に無い(A: URI 単位 / E: 同一 URI の endpoint 単位) 台帳に行を追加する
reconcile B 台帳にあるが実機の url_map に無い 理由を確認し、正当なら allow に登録する
reconcile C / D メソッド・app 列の記載誤り 台帳を実機に合わせる

reconcile B のうち、実機に存在しないことが正当な行(プラグイン未登録・config で無効等)は
プライベートリポジトリの reconcile_allow.json に理由付きで登録する。理由なしの登録は不可。
登録済みの行は B'(既知・許容)として集計され、E'(endpoint が実機に無い)と併せてゲート対象外になる。

W1〜W6 は WARN でゲートは通るが、レビューでは見ること
(ModelView の追加 / 実装本体の変化 / HTTP メソッド・URL の変化 / 監視対象 config の変化 /
依存パッケージの版の変化)。特に W6(依存の版)は、ベースラインを CI と異なる環境で作ると
毎回出続けて形骸化するため、ベースラインは install.sh で作った環境から生成する。

CI の出力は件数のみ。該当した経路名は Actions には出ないので、プライベートリポジトリ側の
完全版レポート(--summary-only なしで再実行したもの)で確認すること
(このリポジトリは public で、ログ・artifact・PR コメントは誰でも読めるため)。


🔒 1. セキュリティ & API アクセス制御チェック (必須)

認証・認可 (Authentication & Authorization)

  • 新規/変更された Blueprint・View・REST リソースに適切なデコレータ / Permission を設定している
    • 例: @login_required, @pass_record, need(...), Invenio Access Action
    • /api/* では Permission.require(http_exception=403) を使うこと。
      @login_required は API アプリに security.login が無いため 401 ではなく 500 になる
    • CI: G1 / G2 が自動検出(デコレータの有無・削除)
  • 状態変更・破壊的メソッド (POST / PUT / PATCH / DELETE) の権限が正しく制限されている
    • CI: G8 が変更行を未認証で実測(使い捨て環境なので --allow-writes 付きで
      GET / HEAD 以外も叩く)
  • 未ログイン(Anonymous)状態でアクセスした際、意図しないデータ取得・変更が拒絶される
    • CI: G8 / G9 が変更行を実測。ただし測定対象は変更行のみ、かつ既定プロファイルで
      起動した経路のみ。ワークフロー系など未解決プレースホルダの行は skip される
  • 認可を config の permission factory に委ねている場合、None で無効化していない
    • CI: G4 が *_PERMISSION_FACTORY 等を監視

機能クローズ・非公開化の場合 (Feature Disable)

  • UI(画面・ボタン)の非表示だけでなく、バックエンド API(ルーティング・View)も完全に遮断されている
  • 無効化状態で直接 API を叩いた場合、404 Not Found または 403 Forbidden が返ることを確認した

🧪 2. テストコード観点チェック (pytest / Invenio Test Suite)

権限・異常系テスト (Negative & Authorization Tests)

  • 未認証アクセス (Anonymous): トークン/セッションなしのリクエストで 401 Unauthorized または 403 Forbidden / 404 Not Found が返ることを検証するテストがある
  • 権限不足ユーザー (Forbidden): 閲覧権限のみのユーザーが更新/削除 API を叩いた際に 403 になるテストがある
  • 無効化/非公開機能の遮断テスト: 対象機能が無効化されている場合、エンドポイントが 404 / 403 を返すテストがある

境界値・入力バリデーションテスト (Boundary & Validation)

  • 不正なパラメータ(巨大ファイル、異常な MIME タイプ、無効な JSON/XML スキーマ、SQLi/XSS ペイロード等)で適切に 400 Bad Request / バリデーションエラーが返るテストがある

データ整合性・トランザクションテスト (Integrity & Rollback)

  • ファイルストレージ(S3/ローカル)書き込み失敗時や DB エラー時に、中途半端なレコードやゴミファイルが残らずロールバックされるテストがある

🛡️ 3. データ保護 & 破壊的変更防止チェック (Data Safety)

  • 物理削除・上書きの安全性:
    • ファイル・アイテム・メタデータの完全削除/置換処理に、意図しない一括削除や別レコードへの誤適用リスクがない
    • 論理削除、バージョン管理、バックアップ等のロールバック機構が考慮されている
  • トランザクション整合性:
    • DB 更新とストレージ操作がアトミックに管理されている

⚙️ 4. マイグレーション & システム影響チェック (Invenio / WEKO3 Stack)

データベース (DB / Alembic)

  • invenio alembic upgrade(適用)および downgrade(ロールバック)スクリプトを作成・検証した
  • 既存データに対する破壊的変更(カラム削除、型変更、NOT NULL 制約追加等)の移行スクリプト/データパッチを用意した

検索インデックス (Elasticsearch / OpenSearch)

  • マッピング定義変更の有無を確認した
  • インデックス再作成(Reindex)やエイリアス切り替え手順を準備・検証した

設定 & 非同期処理 (Config / Celery / Cache)

  • invenio.cfg / 環境変数のデフォルト値を設定した
  • Celery タスクのシグネチャ変更によるキュー滞留・不整合が発生しない
  • キャッシュ(Redis/Memcached)のパージが必要か確認した

📚 5. ドキュメント・仕様書更新チェック (weko-document)

  • API インベントリ: ツールは本リポジトリの tools/api-inventory/、
    台帳・調査記録はプライベートリポジトリ(public リポジトリには置かない)。
    §0 のチェック項目で対応済みなら、ここは確認のみ。
    • エンドポイントの追加・変更・廃止、メソッド、認証・認可要件、リクエスト/レスポンス仕様を更新した
    • 調査記録(weko3_api_auth_findings.md)もプライベートリポジトリに置く。台帳は二重管理しない
  • WEKO3 機能仕様書:
    • 対象機能の仕様追加・変更・クローズ(非公開化)内容を反映した
  • 各種マニュアル (管理者 / 利用者マニュアル):
    • 画面導線・操作手順・権限仕様の変更を反映した
  • 更新不要な場合(理由):

📋 6. 動作検証エビデンス (Verification Evidence)

テスト実行結果

cd modules/<対象モジュール> && pytest
# -> PASS

CI の成果物 (artifact: api-inventory-summary)

ファイル 内容
drift.md ベースラインとの差分(件数のみ)
reconcile.md 台帳と実機の突き合わせ(件数のみ)

明細(該当した経路名・実測結果)は公開できないため artifact に含めていない。
プライベートリポジトリ側で同じコマンドを --summary-only なしで実行して確認する。

手動で確認したこと

Summary by Sourcery

Harden guest activity access and REST mutation authorization while adding configuration-based controls for guest token functionality.

New Features:

  • Add configuration controls for issuing and accepting guest activity tokens, defaulting to enabled in the application configuration.
  • Support method-specific decorators for deposit REST create and update operations.
  • Enforce authentication and edit permissions on deposit creation and updates, and deny direct record mutations through search REST endpoints.

Bug Fixes:

  • Prevent guest-token-based activity creation, usage reports, reminders, and access when guest token functionality is disabled.
  • Clear guest session data when guest token acceptance is disabled.

Enhancements:

  • Return consistent forbidden responses when disabled guest-token functionality is requested.

Tests:

  • Add coverage for guest-token configuration, session handling, disabled-token behavior, REST route decorators, and endpoint permissions.

mhaya and others added 2 commits October 30, 2026 01:07
- records 系エンドポイントの permission factory を明示的に設定
- deposit エンドポイントにメソッド単位でデコレータを指定できる
  create_decorators / update_decorators オプションを追加

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- WEKO_WORKFLOW_GUEST_TOKEN_ISSUE_ENABLED / WEKO_WORKFLOW_GUEST_TOKEN_ACCEPT_ENABLED
  を追加(既定値は False)
- scripts/instance.cfg で両設定を True に設定

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

This hotfix hardens REST write access with method-specific authentication and authorization decorators, and adds configuration-driven controls that disable guest activity token issuance/acceptance and related workflows when turned off, while explicitly denying record mutations on key search endpoints.

Sequence diagram for guest activity token gating

sequenceDiagram
    participant Guest
    participant WorkflowView
    participant WorkflowUtils
    participant Config
    participant Session

    Guest->>WorkflowView: POST /activity/init-guest
    WorkflowView->>WorkflowUtils: guest_token_issue_required()
    WorkflowUtils->>Config: is_guest_token_issue_enabled()
    alt guest token issuance disabled
        WorkflowUtils-->>Guest: GuestTokenDisabledError 403
    else guest token issuance enabled
        WorkflowView->>WorkflowUtils: init_activity_for_guest_user()
        WorkflowUtils-->>Guest: Guest activity URL and token
    end
    WorkflowView->>WorkflowUtils: clear_guest_session()
    WorkflowUtils->>Config: is_guest_token_accept_enabled()
    alt guest token acceptance disabled
        WorkflowUtils->>Session: pop guest_token, guest_email, guest_url
    end
Loading

Sequence diagram for method-specific REST write authorization

sequenceDiagram
    participant Client
    participant DepositREST
    participant DecoratedView
    participant Auth
    participant RecordAPI

    Client->>DepositREST: POST create item
    DepositREST->>DecoratedView: dispatch()
    DecoratedView->>Auth: login_required_customize()
    Auth-->>DecoratedView: authenticated request
    DecoratedView->>RecordAPI: create item
    RecordAPI-->>Client: response

    Client->>DepositREST: PUT or PATCH update item
    DepositREST->>DecoratedView: dispatch()
    DecoratedView->>Auth: require_item_edit_permission()
    Auth-->>DecoratedView: edit permission granted
    DecoratedView->>RecordAPI: update item
    RecordAPI-->>Client: response
Loading

File-Level Changes

Change Details Files
Adds method-specific decorator support to deposit REST routes and applies authentication and edit-permission guards to create/update operations.
  • Introduces configurable create_decorators and update_decorators applied only to POST, PUT, and PATCH requests.
  • Configures deposit endpoints to require login for creation and item-edit permission for updates.
  • Adds unit coverage for method-specific dispatch and endpoint configuration.
modules/invenio-deposit/invenio_deposit/views/rest.py
modules/invenio-deposit/tests/test_views_rest.py
modules/weko-deposit/weko_deposit/config.py
modules/weko-deposit/tests/test_weko_deposit.py
Makes guest activity token issuance and acceptance controlled by explicit configuration, defaulting to disabled in the workflow package while enabling both behaviors in the shipped instance configuration.
  • Adds configuration checks, a 403 exception/decorator for issuance, and validation short-circuiting when token acceptance is disabled.
  • Clears guest session data before requests when token acceptance is disabled.
  • Prevents guest usage-report creation and reminder emails when issuance is disabled.
  • Rejects guest usage-report requests when token issuance is disabled.
  • Adds coverage for enabled, disabled, and session-clearing behavior.
modules/weko-workflow/weko_workflow/config.py
modules/weko-workflow/weko_workflow/errors.py
modules/weko-workflow/weko_workflow/ext.py
modules/weko-workflow/weko_workflow/utils.py
modules/weko-workflow/weko_workflow/views.py
modules/weko-workflow/tests/conftest.py
modules/weko-workflow/tests/test_utils.py
modules/weko-records-ui/weko_records_ui/rest.py
modules/weko-records-ui/weko_records_ui/utils.py
modules/weko-records-ui/tests/conftest.py
modules/weko-records-ui/tests/test_utils.py
modules/weko-admin/weko_admin/utils.py
modules/weko-admin/tests/conftest.py
modules/weko-admin/tests/test_utils.py
modules/weko-workspace/tests/conftest.py
scripts/instance.cfg
Explicitly disables create, update, and delete permission factories for records REST endpoints.
  • Sets deny-all permission factories for the recid, OpenSearch, and workspace endpoints.
  • Adds tests asserting all mutating permission factories remain deny-all.
modules/weko-search-ui/weko_search_ui/config.py
modules/weko-search-ui/tests/test_weko_search_ui.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Oct 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2bc96db1-60b1-44dc-baab-13d8ba381f03

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ivis-miyachi
ivis-miyachi merged commit f588c08 into develop_v2.0.5 Oct 30, 2026
32 of 98 checks passed
@github-actions

Copy link
Copy Markdown

🔍 Claude によるレビュー

指摘 2 件 — 🔴 高 1 / 🟠 中 1 / 🟡 低 0 / 🔎 未確認 9 件


🔴 [高] 認証・編集権限のデコレータが deposit の actions / files ルートに及んでいない

modules/weko-deposit/weko_deposit/config.py:131 (1/3 パス)

create_decorators と update_decorators は list_route の POST と item_route の PUT/PATCH にしか掛からない。{item_route}/actions/<action>(publish/edit/discard)の POST と files 系ルートは対象外で、update_permission_factory が None のため権限判定も無い。ログインしていないユーザーや編集権限の無いユーザーが、他人の deposit に対して actions を呼べる可能性がある。

提案

update_permission_factory_imp に edit_permission_factory 相当を設定する。または、actions・files ルートにも同じデコレータを適用する({item_route}/actions/... と file_list_route、file_item_route)。

根拠
create_decorators=['weko_accounts.utils:login_required_customize'],
update_decorators=['weko_deposit.rest:require_item_edit_permission'],  /  RECORDS_REST_DEFAULT_UPDATE_PERMISSION_FACTORY = None

確認: invenio_deposit/views/rest.py:130-230 を確認した。decorate_view は list_route と item_route にしか適用されず、DepositActionResource.post は @pass_record と @need_record_permission('update_permission_factory') だけで、require_api_auth は付いていない。invenio_records_rest/views.py:433-453 で、need_record_permission は factory が None だと検証を飛ばすことを確認した。weko_deposit/config.py:163 で RECORDS_REST_DEFAULT_UPDATE_PERMISSION_FACTORY=None であることを確認した。files 系の POST/PUT/DELETE には require_api_auth があるが、所有者・編集権限のチェックは無い。weko_deposit/rest.py:51-92 の require_item_edit_permission は item_route の PUT/PATCH にしか付かない。


🟠 [中] 認可デコレータの対象が一覧・アイテムのルートに限られ、files と actions の各ルートに認可が残らない

modules/weko-deposit/weko_deposit/config.py:131 (1/3 パス)

create_decorators と update_decorators は list_route(POST)と item_route(PUT/PATCH)にしか掛からない。同じ depid エンドポイントの DepositActionResource(publish/edit/discard の POST)と DepositFilesResource/DepositFileResource(ファイルの POST/PUT/DELETE)は対象外。これらは update_permission_factory に頼っているが、update_permission_factory_imp はコメントアウトのままなので、未設定時は権限チェックがスキップされる。ロールを問わず(未認証も含め)ファイルの変更や、publish/edit/discard の実行ができる可能性が残る。

提案

update_permission_factory_imp に edit_permission 相当の factory を設定する。またはファイル/アクション用ルートにも update_decorators を適用する。

根拠
create_decorators=['weko_accounts.utils:login_required_customize'],
update_decorators=['weko_deposit.rest:require_item_edit_permission'],
# create_permission_factory_imp='', / update_permission_factory_imp='' はコメントアウトのまま

確認: invenio_deposit/views/rest.py:139-162 を確認。route_decorators のキーは list_route と item_route だけで、files/actions のルートは decorate_view を通らない。同 :233-475 を確認。DepositActionResource.post、DepositFilesResource.post/put、DepositFileResource.put/delete は need_record_permission('update_permission_factory') のみで保護されている。invenio_records_rest/views.py:438-454 を確認。factory が None なら if permission_factory and record: が偽になり検査されない。weko_deposit/config.py:100-134 を確認。update_permission_factory_imp は未設定。ただし /api 配下のどの経路で外部公開されるか、別のミドルウェアでの保護があるかは未確認。


🔎 未確認 — 裏が取れなかったもの 9 件
  • ゲストトークン発行が無効のとき、利用報告の作成が黙って None を返す modules/weko-records-ui/weko_records_ui/utils.py:1097 (1/3 パス)
    • create_usage_report_for_user は is_guest かつ発行無効のとき None を返して終了する。呼び出し側がこの戻り値を前提にしていると、利用報告が作られないまま処理が進む恐れがある。
    • 確認できなかった理由: 呼び出し元の追跡と戻り値の扱いの確認までは行っていない。
  • validate_guest_activity_token が常に (False, None, None) を返す場合の呼び出し側の挙動 modules/weko-workflow/weko_workflow/views.py:721 (1/3 パス)
    • 受付が無効のとき validate_guest_activity_token は (False, None, None) を返す。views.py:721 と rest.py:909 の分岐が、これを期限切れトークンのエラーとして扱うか、403 として扱うかは確認していない。応答コードが変わる可能性がある。
    • 確認できなかった理由: views.py と rest.py の呼び出し後の分岐までは読んでいない。
  • post_v1 の汎用 except が GuestTokenDisabledError を 500 に変える可能性 modules/weko-records-ui/weko_records_ui/rest.py:576 (1/3 パス)
    • init_activity_for_guest_user は発行が無効だと GuestTokenDisabledError を送出する。これは 576 行目の try 内で呼ばれ、except BaseException が 500 の InternalServerError に変換する。ただし直前の 506 行目で事前チェックしているため、実際に到達するのは競合状態のときだけと思われる。
    • 確認できなかった理由: 到達条件が設定変更と競合したときに限られ、実害は小さいと見ている。
  • weko_deposit_rest の ItemResource.post/put に require_item_edit_permission が二重に付く可能性 modules/weko-deposit/weko_deposit/rest.py:267 (1/3 パス)
    • ItemResource.post/put には require_item_edit_permission が既に付いている。rdc_route は invenio_deposit の item_route とは別ルートなので、今回のデコレータ追加とは別経路になる。ただし post には @pass_record もあり、PID 解決の経路が複数ある。バージョン付き pid_value で 404 になるなど挙動が食い違う場合がある。
    • 確認できなかった理由: edit_permission_factory の実装と、実際の URL コンバータが渡す pid_value の形(depid と recid の対応、バージョン付き)を実行して確かめられなかった。
  • 全リクエストに対する before_request の副作用 modules/weko-workflow/weko_workflow/ext.py:47 (1/3 パス)
    • app.before_request(clear_guest_session) は、ACCEPT が無効のとき、全リクエストでセッションの guest_token・guest_email・guest_url を消す。他のモジュールが同じ session キーをゲスト以外の用途で使っていないか未確認。
    • 確認できなかった理由: session['guest_token'] などのキーを、全モジュールにわたって網羅的に追えていない。
  • recid/opensearch/workspace の create/update/delete を deny_all に固定した影響 modules/weko-search-ui/weko_search_ui/config.py:141 (1/3 パス)
    • 3 つのエンドポイントすべてで create/update/delete が deny_all になる。他モジュールが /api/records への PUT/POST/DELETE を使っていると 403 になる。キー名 worksapce は元コードの typo のままで、一貫してはいる。
    • 確認できなかった理由: /api/records への書き込み呼び出しがフロントエンドや外部連携にあるかを網羅的に grep していない。
  • GET など、デコレータ対象外のメソッドは従来どおり無認可 modules/invenio-deposit/invenio_deposit/views/rest.py:139 (1/3 パス)
    • decorate_view は methods に含まれないメソッド(GET、DELETE など)を素通しする。DELETE は delete_permission_factory_imp=deny_all で保護されている。GET は read_permission_factory が未設定のため、下書き(未公開)の deposit が誰でも読める可能性がある。これは本 PR の後退ではなく既存の挙動。
    • 確認できなかった理由: deposit の GET が read_permission_factory なしで実際に公開されるか、別のミドルウェアや nginx で制限されているかを確認していない。
  • recid/opensearch/worksapce の create/update/delete を deny_all に変更した影響 modules/weko-search-ui/weko_search_ui/config.py:141 (1/3 パス)
    • 3 つの RECORDS_REST_ENDPOINTS で create/update/delete を一律 deny_all にしている。認可を締める方向の変更なので後退ではない。ただし、既存の呼び出し元(管理画面、外部連携、テスト)が POST/PUT/DELETE /records を使っていると、403 になる。
    • 確認できなかった理由: /records の書き込み系 API を使う呼び出し元(JS、外部システム、他モジュールのテスト)を全件 grep しきれていない。
  • init_activity_for_guest_user の例外が呼び出し元で別の応答に変わる modules/weko-workflow/weko_workflow/utils.py:3637 (1/3 パス)
    • init_activity_for_guest_user が GuestTokenDisabledError を投げるようになった。weko_records_ui/rest.py:576 は except BaseException で受けて 500 の InternalServerError にする。weko_records_ui/utils.py:1140 の呼び出しは、create_usage_report_for_user の先頭で返しているため通常は到達しない。views.py:675 は @guest_token_issue_required を通過した後なので到達しない。
    • 確認できなかった理由: rest.py:576 は直前の post_v1 の事前チェック(is_guest_token_issue_enabled)で保護されているが、設定が実行中に切り替わるケースや、他の間接的な呼び出し箇所は全件確認していない。

モデル sonnet / 3 回実行して和集合 / コスト $0.7066。同じ差分でも結果が揺れるため複数回まわし、一部のパスでしか挙がらなかったものには回数を添えています

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

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 5 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="modules/weko-deposit/weko_deposit/config.py" line_range="131" />
<code_context>
         # read_permission_factory_imp='',
         # update_permission_factory_imp='',
         delete_permission_factory_imp=deny_all,
+        create_decorators=['weko_accounts.utils:login_required_customize'],
+        update_decorators=['weko_deposit.rest:require_item_edit_permission'],
     )
</code_context>
<issue_to_address>
**Guests can create deposits**

When an unauthenticated visitor has a guest-token session and the create permission factory does not reject that visitor, `login_required_customize` treats the guest-token session as authenticated, so the new create decorator lets the request reach deposit creation without an authenticated account or an item-specific create check. The guest can create a deposit.

Require an authenticated account for deposit creation or add a create permission check that rejects guest-token sessions.
</issue_to_address>

### Comment 2
<location path="modules/weko-workflow/weko_workflow/utils.py" line_range="3564" />
<code_context>
+        bool: True if ``WEKO_WORKFLOW_GUEST_TOKEN_ISSUE_ENABLED`` is set.
+    """
+    return bool(current_app.config.get(
+        'WEKO_WORKFLOW_GUEST_TOKEN_ISSUE_ENABLED', False))
+
+
</code_context>
<issue_to_address>
**String false enables guest tokens**

When an environment-specific config supplies either guest-token flag as the nonempty string `"False"`, `bool()` treats any nonempty string as true, so a setting supplied as the string `"False"` leaves the corresponding guest-token gate enabled. Both issuing and accepting tokens can therefore remain enabled when an operator intended to disable them.

Require actual boolean config values or parse supported string values explicitly and reject malformed values.

Also at `modules/weko-workflow/weko_workflow/utils.py:3574`.
</issue_to_address>

### Comment 3
<location path="modules/invenio-deposit/invenio_deposit/views/rest.py" line_range="139-144" />
<code_context>
             '{0}/files/<path:key>'.format(options['item_route'])
         )

+        route_decorators = {
+            options['list_route']: (
+                options.pop('create_decorators', []), ('POST',)),
+            options['item_route']: (
+                options.pop('update_decorators', []), ('PUT', 'PATCH')),
+        }
+
         options.setdefault('search_class', DepositSearch)
</code_context>
<issue_to_address>
**File mutations skip edit checks**

When an authenticated API caller has the write scope but lacks permission to edit the deposit, `create_blueprint` attaches `update_decorators` only to the item route, while file routes are registered separately; a caller with the API write scope but no item edit permission can therefore add, rename, reorder, or delete deposit files.

Apply the item edit check to file mutation routes too, or configure an update permission factory that enforces per-record edit access there.

Also at `modules/weko-deposit/weko_deposit/config.py:132`.
</issue_to_address>

### Comment 4
<location path="modules/weko-admin/weko_admin/utils.py" line_range="1995-1997" />
<code_context>
                 .get("WEKO_WORKFLOW_REQUEST_FOR_REGISTER_USAGE_REPORT")

         for activity in activities:
+            if (activity.extra_info or {}).get('is_guest') \
+                    and not self.__is_guest_token_issue_enabled():
+                continue
             if activity.item_id:
                 records_id.append(activity.item_id)
</code_context>
<issue_to_address>
**Skipped guests trigger other reminder emails**

When the activities contain a registered-user activity followed by a guest activity while guest token issuing is disabled, `send_reminder_mail` skips a disabled guest activity but leaves it in `activity`; the later guest check at line 2027 still runs and sends every accumulated entry in `self.__mail_info_lst`, including registered-user reminders that would not be sent without `forced_send`. The caller can therefore trigger unintended reminder emails.

Track whether any eligible guest activity was processed, and only use that state to trigger guest reminder sending.
</issue_to_address>

### Comment 5
<location path="modules/weko-admin/weko_admin/utils.py" line_range="1995-1996" />
<code_context>
                 .get("WEKO_WORKFLOW_REQUEST_FOR_REGISTER_USAGE_REPORT")

         for activity in activities:
+            if (activity.extra_info or {}).get('is_guest') \
+                    and not self.__is_guest_token_issue_enabled():
+                continue
             if activity.item_id:
</code_context>
<issue_to_address>
**Reminders send unusable links**

When guest token issuance is enabled, acceptance is disabled, and a guest activity is due for a reminder, `UsageReport.send_reminder_mail` checks only issuance, so it builds and sends a guest link that `validate_guest_activity_token` rejects; recipients receive a link they cannot use.

Skip sending guest reminders when guest-token acceptance is disabled.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 5 findings to address first, and with guest-token issuance and acceptance enabled in the instance config, unauthenticated users may obtain and use guest activity tokens; if that trust boundary is too permissive, data or workflow access could be exposed before the configuration is reverted. The REST permission changes restrict writes, but reverting does not undo any access already granted.

Blocking findings: modules/weko-deposit/weko_deposit/config.py:131, modules/weko-workflow/weko_workflow/utils.py:3564, modules/invenio-deposit/invenio_deposit/views/rest.py:144, modules/weko-admin/weko_admin/utils.py:1997, modules/weko-admin/weko_admin/utils.py:1996


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

# read_permission_factory_imp='',
# update_permission_factory_imp='',
delete_permission_factory_imp=deny_all,
create_decorators=['weko_accounts.utils:login_required_customize'],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High · Guests can create deposits

When an unauthenticated visitor has a guest-token session and the create permission factory does not reject that visitor, login_required_customize treats the guest-token session as authenticated, so the new create decorator lets the request reach deposit creation without an authenticated account or an item-specific create check. The guest can create a deposit.

Require an authenticated account for deposit creation or add a create permission check that rejects guest-token sessions.

Prompt for AI agents
In `modules/weko-deposit/weko_deposit/config.py` at line 131:

**Guests can create deposits**

When an unauthenticated visitor has a guest-token session and the create permission factory does not reject that visitor, `login_required_customize` treats the guest-token session as authenticated, so the new create decorator lets the request reach deposit creation without an authenticated account or an item-specific create check. The guest can create a deposit.

Require an authenticated account for deposit creation or add a create permission check that rejects guest-token sessions.

bool: True if ``WEKO_WORKFLOW_GUEST_TOKEN_ISSUE_ENABLED`` is set.
"""
return bool(current_app.config.get(
'WEKO_WORKFLOW_GUEST_TOKEN_ISSUE_ENABLED', False))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High · String false enables guest tokens

When an environment-specific config supplies either guest-token flag as the nonempty string "False", bool() treats any nonempty string as true, so a setting supplied as the string "False" leaves the corresponding guest-token gate enabled. Both issuing and accepting tokens can therefore remain enabled when an operator intended to disable them.

Require actual boolean config values or parse supported string values explicitly and reject malformed values.

Also at modules/weko-workflow/weko_workflow/utils.py:3574.

Prompt for AI agents
In `modules/weko-workflow/weko_workflow/utils.py` at line 3564:

**String false enables guest tokens**

When an environment-specific config supplies either guest-token flag as the nonempty string `"False"`, `bool()` treats any nonempty string as true, so a setting supplied as the string `"False"` leaves the corresponding guest-token gate enabled. Both issuing and accepting tokens can therefore remain enabled when an operator intended to disable them.

Require actual boolean config values or parse supported string values explicitly and reject malformed values.

Also at `modules/weko-workflow/weko_workflow/utils.py:3574`.

Comment on lines +139 to +144
route_decorators = {
options['list_route']: (
options.pop('create_decorators', []), ('POST',)),
options['item_route']: (
options.pop('update_decorators', []), ('PUT', 'PATCH')),
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High · File mutations skip edit checks

When an authenticated API caller has the write scope but lacks permission to edit the deposit, create_blueprint attaches update_decorators only to the item route, while file routes are registered separately; a caller with the API write scope but no item edit permission can therefore add, rename, reorder, or delete deposit files.

Apply the item edit check to file mutation routes too, or configure an update permission factory that enforces per-record edit access there.

Also at modules/weko-deposit/weko_deposit/config.py:132.

Prompt for AI agents
In `modules/invenio-deposit/invenio_deposit/views/rest.py` at lines 139-144:

**File mutations skip edit checks**

When an authenticated API caller has the write scope but lacks permission to edit the deposit, `create_blueprint` attaches `update_decorators` only to the item route, while file routes are registered separately; a caller with the API write scope but no item edit permission can therefore add, rename, reorder, or delete deposit files.

Apply the item edit check to file mutation routes too, or configure an update permission factory that enforces per-record edit access there.

Also at `modules/weko-deposit/weko_deposit/config.py:132`.

Comment on lines +1995 to +1997
if (activity.extra_info or {}).get('is_guest') \
and not self.__is_guest_token_issue_enabled():
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Skipped guests trigger other reminder emails

When the activities contain a registered-user activity followed by a guest activity while guest token issuing is disabled, send_reminder_mail skips a disabled guest activity but leaves it in activity; the later guest check at line 2027 still runs and sends every accumulated entry in self.__mail_info_lst, including registered-user reminders that would not be sent without forced_send. The caller can therefore trigger unintended reminder emails.

Track whether any eligible guest activity was processed, and only use that state to trigger guest reminder sending.

Prompt for AI agents
In `modules/weko-admin/weko_admin/utils.py` at lines 1995-1997:

**Skipped guests trigger other reminder emails**

When the activities contain a registered-user activity followed by a guest activity while guest token issuing is disabled, `send_reminder_mail` skips a disabled guest activity but leaves it in `activity`; the later guest check at line 2027 still runs and sends every accumulated entry in `self.__mail_info_lst`, including registered-user reminders that would not be sent without `forced_send`. The caller can therefore trigger unintended reminder emails.

Track whether any eligible guest activity was processed, and only use that state to trigger guest reminder sending.

Comment on lines +1995 to +1996
if (activity.extra_info or {}).get('is_guest') \
and not self.__is_guest_token_issue_enabled():

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Reminders send unusable links

When guest token issuance is enabled, acceptance is disabled, and a guest activity is due for a reminder, UsageReport.send_reminder_mail checks only issuance, so it builds and sends a guest link that validate_guest_activity_token rejects; recipients receive a link they cannot use.

Skip sending guest reminders when guest-token acceptance is disabled.

Prompt for AI agents
In `modules/weko-admin/weko_admin/utils.py` at lines 1995-1996:

**Reminders send unusable links**

When guest token issuance is enabled, acceptance is disabled, and a guest activity is due for a reminder, `UsageReport.send_reminder_mail` checks only issuance, so it builds and sends a guest link that `validate_guest_activity_token` rejects; recipients receive a link they cannot use.

Skip sending guest reminders when guest-token acceptance is disabled.

@github-actions

Copy link
Copy Markdown

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

⚠️ プライベートリポジトリに対応ブランチが無いため、既定ブランチの台帳と比較しています。
ブランチ間の経路差がそのまま差分として出るので、以下の件数は当てになりません。
この PR のブランチと同名のブランチをプライベートリポジトリに作ってください。

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

ベースラインとの差分

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

  • 旧: 5f4bef44c v2.0.4 (profile=default) endpoints=928 (外部ライブラリ由来 359)
  • 新: 950b2edf6 v2.0.4-3-g950b2edf6 (profile=default) endpoints=928 (外部ライブラリ由来 359)

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

サマリ

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

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

  • distlib — 0.4.3 -> 0.4.4
  • frozendict — 2.4.7 -> 2.5.0
  • pbr — 7.0.3 -> 7.1.3
  • pyld — 3.1.0 -> 3.3.0
  • orjson — 3.6.1 -> (削除)
  • weko-redis — 0.1.0.dev20170000 -> (削除)

[WARN] W5 監視対象 config が変化した — 1件

件数のみ。該当の経路名はプライベートリポジトリ側の完全版レポートを参照。


台帳との突き合わせ

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

  • リビジョン: 950b2edf6 v2.0.4-3-g950b2edf6 経路URI=908
  • 台帳: 行=1048 URI=919

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

判定: ✅ 一致 (0件)

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

@mhaya mhaya mentioned this pull request Oct 30, 2026
35 tasks
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.

2 participants