From 601f9b8da0e378d3e2d97e7400e7660d779c5cd2 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 19 May 2026 06:43:57 +0000 Subject: [PATCH 1/6] docs: correct CSRF protection opt-in description README claimed CSRF was only verified when #[CsrfProtection] was present, but SetAntiCsrfTrait alone is sufficient: the trait's #[Inject] setter populates $this->antiCsrf, postConstruct() calls enableAntiCsrf(), and AbstractForm::apply() throws CsrfViolationException on token mismatch regardless of the attribute (covered by AbstractFormTest::testAntiCsrfViolation). Document the two independent opt-in paths (per-form trait, per-action attribute) and fix the migrate-to-1.0 skill's "out of scope" note that implied SetAntiCsrfTrait-only forms silently stop enforcing CSRF in 1.0. --- .claude/skills/migrate-to-1.0/SKILL.md | 11 +++++++---- README.JA.md | 15 ++++++++++++--- README.md | 16 ++++++++++++---- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/.claude/skills/migrate-to-1.0/SKILL.md b/.claude/skills/migrate-to-1.0/SKILL.md index c8cc95e..2884504 100644 --- a/.claude/skills/migrate-to-1.0/SKILL.md +++ b/.claude/skills/migrate-to-1.0/SKILL.md @@ -194,7 +194,10 @@ Report to the user: - Migrating other libraries' annotations (only `Ray\WebFormModule\Annotation\*`). - Renaming `SetAntiCsrfTrait` — the trait and `setAntiCsrf()` method are unchanged in 1.0. -- Changes to forms that use `AntiCsrf` without `#[CsrfProtection]` — - flag these to the user: in 1.0 they will silently stop enforcing CSRF. - The user must decide whether to add `#[CsrfProtection]` to the validated - controller method or accept the new behaviour. +- Migrating `@FormValidation(antiCsrf=true)` callers that did **not** use + `SetAntiCsrfTrait` on the form. These relied on the removed `antiCsrf` + option to enable CSRF; after dropping the option they need + `#[CsrfProtection]` on the validated method (or `SetAntiCsrfTrait` on + the form) to keep enforcement. Flag these to the user so they can decide. + Forms that already use `SetAntiCsrfTrait` continue to enforce CSRF in 1.0 + via `AbstractForm::apply()` regardless of `#[CsrfProtection]`. diff --git a/README.JA.md b/README.JA.md index 1d5c2f3..ec825b8 100644 --- a/README.JA.md +++ b/README.JA.md @@ -127,9 +127,18 @@ class MyController ### CSRF Protections -CSRF対策は **opt-in** です。`SetAntiCsrfTrait` を使うフォームには `AntiCsrfInterface` が注入されますが、 -トークンの検証は `#[CsrfProtection]` 属性が付いたメソッドでのみ行われます。 -`#[CsrfProtection]` が無いメソッドでは、フォーム側に AntiCsrf がセットされていても CSRF チェックは実行されません。 +CSRF対策は **opt-in** で、独立した 2 つの経路のいずれかで有効化できます。 + +- **フォーム単位**: フォームに `use SetAntiCsrfTrait;` を追加します。 + DI で `AntiCsrfInterface` が注入され、`postConstruct()` でトークンフィールドが + 追加され、`apply()` の呼び出しごとにトークンが検証されます。 +- **アクション単位**: バリデーション対象のコントローラメソッドに + `#[CsrfProtection]` を付与します。`AuraInputInterceptor` が `apply()` 実行前に + `AntiCsrfInterface` をフォームへ注入します。 + +どちらの経路でも、トークン不一致時には `AbstractForm::apply()` が +`CsrfViolationException` を throw します。どちらも使わない場合は CSRF 検証は +行われません。 ```php use Ray\WebFormModule\AbstractAuraForm; diff --git a/README.md b/README.md index 274dca2..db92627 100644 --- a/README.md +++ b/README.md @@ -142,10 +142,18 @@ or render input element basis. ``` ### CSRF Protections -CSRF protection is **opt-in**. A form that uses `SetAntiCsrfTrait` is wired -with an `AntiCsrfInterface`, but the token is only verified when the -validated method is annotated with `#[CsrfProtection]`. Methods without -`#[CsrfProtection]` perform no CSRF check even if the form supports it. +CSRF protection is **opt-in** and can be enabled through either of two +independent paths: + +- **Per-form**: add `use SetAntiCsrfTrait;` to the form. `AntiCsrfInterface` + is injected at construction time, the token field is added in + `postConstruct()`, and every `apply()` call verifies the token. +- **Per-action**: annotate the validated controller method with + `#[CsrfProtection]`. `AuraInputInterceptor` then injects + `AntiCsrfInterface` into the form before `apply()` runs. + +Either path causes `AbstractForm::apply()` to throw `CsrfViolationException` +on token mismatch. Without either path, no CSRF check is performed. ```php use Ray\WebFormModule\AbstractAuraForm; From f967e3f898b816882265088a2ae2c47aab82b2b8 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 19 May 2026 07:28:09 +0000 Subject: [PATCH 2/6] docs: address Copilot review feedback on CSRF clarification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Reword "injected at construction time" to clarify the trait uses an #[Inject] setter (method injection by Ray.Di), not constructor injection. - Split the README example into two minimal snippets — one per opt-in path — and note that combining both is redundant. The single combined example contradicted the "two independent paths" wording. - Drop the migrate-to-1.0 "out of scope" bullet that overlapped with the automated Step 1b rewrite. Replace it with a note that #[CsrfProtection] added by 1b is redundant when the form already uses SetAntiCsrfTrait, so users can choose a single declaration site. --- .claude/skills/migrate-to-1.0/SKILL.md | 12 +++++------- README.JA.md | 25 +++++++++++++++---------- README.md | 25 +++++++++++++++---------- 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/.claude/skills/migrate-to-1.0/SKILL.md b/.claude/skills/migrate-to-1.0/SKILL.md index 2884504..20143f0 100644 --- a/.claude/skills/migrate-to-1.0/SKILL.md +++ b/.claude/skills/migrate-to-1.0/SKILL.md @@ -194,10 +194,8 @@ Report to the user: - Migrating other libraries' annotations (only `Ray\WebFormModule\Annotation\*`). - Renaming `SetAntiCsrfTrait` — the trait and `setAntiCsrf()` method are unchanged in 1.0. -- Migrating `@FormValidation(antiCsrf=true)` callers that did **not** use - `SetAntiCsrfTrait` on the form. These relied on the removed `antiCsrf` - option to enable CSRF; after dropping the option they need - `#[CsrfProtection]` on the validated method (or `SetAntiCsrfTrait` on - the form) to keep enforcement. Flag these to the user so they can decide. - Forms that already use `SetAntiCsrfTrait` continue to enforce CSRF in 1.0 - via `AbstractForm::apply()` regardless of `#[CsrfProtection]`. +- Deciding whether `#[CsrfProtection]` added by Step 1b is redundant. Forms + that already use `SetAntiCsrfTrait` enforce CSRF via `AbstractForm::apply()` + regardless of the attribute, so the attribute Step 1b inserts is harmless + but unnecessary. Flag these to the user so they can drop the attribute if + they prefer a single declaration site. diff --git a/README.JA.md b/README.JA.md index ec825b8..f6b813a 100644 --- a/README.JA.md +++ b/README.JA.md @@ -130,26 +130,22 @@ class MyController CSRF対策は **opt-in** で、独立した 2 つの経路のいずれかで有効化できます。 - **フォーム単位**: フォームに `use SetAntiCsrfTrait;` を追加します。 - DI で `AntiCsrfInterface` が注入され、`postConstruct()` でトークンフィールドが - 追加され、`apply()` の呼び出しごとにトークンが検証されます。 + Ray.Di がトレイトの `#[Inject]` setter 経由で `AntiCsrfInterface` を注入し、 + `postConstruct()` でトークンフィールドが追加され、`apply()` の呼び出しごとに + トークンが検証されます。 - **アクション単位**: バリデーション対象のコントローラメソッドに `#[CsrfProtection]` を付与します。`AuraInputInterceptor` が `apply()` 実行前に `AntiCsrfInterface` をフォームへ注入します。 どちらの経路でも、トークン不一致時には `AbstractForm::apply()` が `CsrfViolationException` を throw します。どちらも使わない場合は CSRF 検証は -行われません。 +行われません。両方を併用しても害はありませんが冗長なので、用途に合わせて +どちらか一方を選んでください。 ```php -use Ray\WebFormModule\AbstractAuraForm; +// アクション単位: コントローラのメソッドで宣言。 use Ray\WebFormModule\Annotation\CsrfProtection; use Ray\WebFormModule\Annotation\FormValidation; -use Ray\WebFormModule\SetAntiCsrfTrait; - -class MyForm extends AbstractAuraForm -{ - use SetAntiCsrfTrait; -} class MyController { @@ -159,6 +155,15 @@ class MyController { } } + +// フォーム単位: フォーム自身で宣言。 +use Ray\WebFormModule\AbstractAuraForm; +use Ray\WebFormModule\SetAntiCsrfTrait; + +class MyForm extends AbstractAuraForm +{ + use SetAntiCsrfTrait; +} ``` セキュリティレベルを高めるためにはユーザーの認証を含んだカスタムCsrfクラスを作成してフォームクラスにセットします。 diff --git a/README.md b/README.md index db92627..7822c0a 100644 --- a/README.md +++ b/README.md @@ -146,25 +146,21 @@ CSRF protection is **opt-in** and can be enabled through either of two independent paths: - **Per-form**: add `use SetAntiCsrfTrait;` to the form. `AntiCsrfInterface` - is injected at construction time, the token field is added in - `postConstruct()`, and every `apply()` call verifies the token. + is injected by Ray.Di through the trait's `#[Inject]` setter, the token + field is added in `postConstruct()`, and every `apply()` call verifies + the token. - **Per-action**: annotate the validated controller method with `#[CsrfProtection]`. `AuraInputInterceptor` then injects `AntiCsrfInterface` into the form before `apply()` runs. Either path causes `AbstractForm::apply()` to throw `CsrfViolationException` -on token mismatch. Without either path, no CSRF check is performed. +on token mismatch. Without either path, no CSRF check is performed. Combining +both paths is harmless but redundant — pick whichever fits your use case. ```php -use Ray\WebFormModule\AbstractAuraForm; +// Per-action: declare CSRF on the controller method. use Ray\WebFormModule\Annotation\CsrfProtection; use Ray\WebFormModule\Annotation\FormValidation; -use Ray\WebFormModule\SetAntiCsrfTrait; - -class MyForm extends AbstractAuraForm -{ - use SetAntiCsrfTrait; -} class MyController { @@ -174,6 +170,15 @@ class MyController { } } + +// Per-form: declare CSRF on the form itself. +use Ray\WebFormModule\AbstractAuraForm; +use Ray\WebFormModule\SetAntiCsrfTrait; + +class MyForm extends AbstractAuraForm +{ + use SetAntiCsrfTrait; +} ``` You can provide your custom `AntiCsrf` class. See more detail at [Aura.Input](https://github.com/auraphp/Aura.Input#applying-csrf-protections) From 9722f7e952a9b10ffdaf7f8b3957ac218622e881 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 19 May 2026 10:35:27 +0000 Subject: [PATCH 3/6] docs: split CSRF examples and reconcile migrate-to-1.0 wording - Split the README CSRF examples into two valid stand-alone code blocks (per-action and per-form). The previous single block had `use` statements after `class MyController`, which is not valid PHP in one file. - Reword the Step 1b note ("methods without the attribute perform no CSRF check") so it no longer contradicts the Out-of-scope note about SetAntiCsrfTrait-only forms still enforcing CSRF via AbstractForm::apply(). --- .claude/skills/migrate-to-1.0/SKILL.md | 4 +++- README.JA.md | 8 ++++++-- README.md | 8 ++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.claude/skills/migrate-to-1.0/SKILL.md b/.claude/skills/migrate-to-1.0/SKILL.md index 20143f0..4a3906d 100644 --- a/.claude/skills/migrate-to-1.0/SKILL.md +++ b/.claude/skills/migrate-to-1.0/SKILL.md @@ -82,7 +82,9 @@ becomes Also add `use Ray\WebFormModule\Annotation\CsrfProtection;`. If `antiCsrf=false` (or omitted), drop the option without adding -`#[CsrfProtection]` — methods without the attribute perform no CSRF check. +`#[CsrfProtection]`. The method itself then performs no attribute-driven +CSRF check; the form may still enforce CSRF if it uses `SetAntiCsrfTrait` +(see "Out of scope" below). ### 1c. `@InputValidation` and `@VndError` diff --git a/README.JA.md b/README.JA.md index f6b813a..e25b6ef 100644 --- a/README.JA.md +++ b/README.JA.md @@ -142,8 +142,9 @@ CSRF対策は **opt-in** で、独立した 2 つの経路のいずれかで有 行われません。両方を併用しても害はありませんが冗長なので、用途に合わせて どちらか一方を選んでください。 +アクション単位 — コントローラのメソッドで宣言: + ```php -// アクション単位: コントローラのメソッドで宣言。 use Ray\WebFormModule\Annotation\CsrfProtection; use Ray\WebFormModule\Annotation\FormValidation; @@ -155,8 +156,11 @@ class MyController { } } +``` -// フォーム単位: フォーム自身で宣言。 +フォーム単位 — フォーム自身で宣言: + +```php use Ray\WebFormModule\AbstractAuraForm; use Ray\WebFormModule\SetAntiCsrfTrait; diff --git a/README.md b/README.md index 7822c0a..f8d8a52 100644 --- a/README.md +++ b/README.md @@ -157,8 +157,9 @@ Either path causes `AbstractForm::apply()` to throw `CsrfViolationException` on token mismatch. Without either path, no CSRF check is performed. Combining both paths is harmless but redundant — pick whichever fits your use case. +Per-action — declare CSRF on the controller method: + ```php -// Per-action: declare CSRF on the controller method. use Ray\WebFormModule\Annotation\CsrfProtection; use Ray\WebFormModule\Annotation\FormValidation; @@ -170,8 +171,11 @@ class MyController { } } +``` -// Per-form: declare CSRF on the form itself. +Per-form — declare CSRF on the form itself: + +```php use Ray\WebFormModule\AbstractAuraForm; use Ray\WebFormModule\SetAntiCsrfTrait; From 2bf5fb6d114e1d7f07242b4b5061bb403bda0da9 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 19 May 2026 11:03:50 +0000 Subject: [PATCH 4/6] docs: fix nonexistent AbstractAuraForm base class reference src/AbstractForm.php only declares AbstractForm; AbstractAuraForm does not exist in this package. The example was inherited from the original CSRF section and never compiled. --- README.JA.md | 4 ++-- README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.JA.md b/README.JA.md index e25b6ef..278b46a 100644 --- a/README.JA.md +++ b/README.JA.md @@ -161,10 +161,10 @@ class MyController フォーム単位 — フォーム自身で宣言: ```php -use Ray\WebFormModule\AbstractAuraForm; +use Ray\WebFormModule\AbstractForm; use Ray\WebFormModule\SetAntiCsrfTrait; -class MyForm extends AbstractAuraForm +class MyForm extends AbstractForm { use SetAntiCsrfTrait; } diff --git a/README.md b/README.md index f8d8a52..e592716 100644 --- a/README.md +++ b/README.md @@ -176,10 +176,10 @@ class MyController Per-form — declare CSRF on the form itself: ```php -use Ray\WebFormModule\AbstractAuraForm; +use Ray\WebFormModule\AbstractForm; use Ray\WebFormModule\SetAntiCsrfTrait; -class MyForm extends AbstractAuraForm +class MyForm extends AbstractForm { use SetAntiCsrfTrait; } From b390a58c458b8bda030d1e5517757095ea135397 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 19 May 2026 14:36:26 +0000 Subject: [PATCH 5/6] chore: add markdownlint config setting MD046 to fenced README.md and README.JA.md already use fenced code blocks throughout (20+ and 24+ occurrences). The default MD046 rule infers the style from whichever block appears first, so the fenced blocks were reported as errors. Pin the style to fenced to match the established convention. --- .markdownlint.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .markdownlint.json diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..5ea4e95 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,5 @@ +{ + "MD046": { + "style": "fenced" + } +} From 35e2425d18220308840e33cf4afad75b42d42a08 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 20 May 2026 04:28:47 +0000 Subject: [PATCH 6/6] docs: add blank line after CSRF per-form code block Satisfies markdownlint MD031 (blanks-around-fences) for the fenced block introduced in the CSRF section. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e592716..fddc5e8 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,7 @@ class MyForm extends AbstractForm use SetAntiCsrfTrait; } ``` + You can provide your custom `AntiCsrf` class. See more detail at [Aura.Input](https://github.com/auraphp/Aura.Input#applying-csrf-protections) ## Migration from 0.x