refactor(actions): centralize core page request/csrf guards

This commit is contained in:
2026-04-24 19:10:37 +02:00
parent a05a628968
commit 52f10ae46c
18 changed files with 253 additions and 29 deletions

View File

@@ -0,0 +1,22 @@
{
"task_id": "2026-04-24-action-csrf-centralization-step4",
"issue_summary": "Nach Abschluss von pages/admin gab es in non-admin Core-Seiten noch direkte requestInput()->method() und Session::checkCsrfToken()-Nutzung. Ziel war die gleiche Zentralisierung auch für pages/auth, pages/page, pages/lang und pages/flash.",
"affected_layers": ["pages", "tests"],
"affected_files": [
{ "path": "pages/lang().php", "role": "Locale switch endpoint (GET/POST mixed)" },
{ "path": "pages/flash/dismiss($id).php", "role": "Flash dismiss POST endpoint" },
{ "path": "pages/page/copy-language().php", "role": "Page content locale copy action" },
{ "path": "pages/page/index($slug).php", "role": "Page edit submit flow with optional JSON response" },
{ "path": "pages/auth/login().php", "role": "Multi-stage login action" },
{ "path": "pages/auth/register().php", "role": "Registration action" },
{ "path": "pages/auth/forgot().php", "role": "Password reset request action" },
{ "path": "pages/auth/verify().php", "role": "Password reset verification code action" },
{ "path": "pages/auth/verify-email().php", "role": "Email verification and resend action" },
{ "path": "pages/auth/reset().php", "role": "Password reset completion action" },
{ "path": "tests/Architecture/CorePageRequestGuardContractTest.php", "role": "Architecture contract to prevent legacy request/csrf checks in non-admin core pages" }
],
"risks_discovered": [
"Auth/page flows rely on in-page error handling instead of redirect on CSRF mismatch in several places; helper use must preserve this behavior.",
"Mixed GET/POST endpoints (lang, page/index) require conditional CSRF enforcement without breaking GET rendering paths."
]
}

View File

@@ -0,0 +1,50 @@
{
"task_id": "2026-04-24-action-csrf-centralization-step4",
"plan_ref": ".agents/runs/2026-04-24-action-csrf-centralization-step4/plan.json",
"status": "done",
"changed_files": [
{ "path": "pages/lang().php", "summary": "Replaced direct CSRF check with actionRequireCsrf while preserving redirect + flash behavior." },
{ "path": "pages/flash/dismiss($id).php", "summary": "Replaced direct method + CSRF checks with actionRequirePost/actionRequireCsrf." },
{ "path": "pages/page/copy-language().php", "summary": "Added method guard via actionRequirePost and replaced direct CSRF check with helper call." },
{ "path": "pages/page/index($slug).php", "summary": "Replaced direct method/CSRF checks with helper-compatible request/isMethod and actionRequireCsrf." },
{ "path": "pages/auth/login().php", "summary": "Replaced direct method/CSRF checks with requestInput()->isMethod and actionRequireCsrf (non-redirect mode)." },
{ "path": "pages/auth/register().php", "summary": "Replaced direct CSRF check with actionRequireCsrf (non-redirect mode)." },
{ "path": "pages/auth/forgot().php", "summary": "Replaced direct CSRF check with actionRequireCsrf (non-redirect mode)." },
{ "path": "pages/auth/verify().php", "summary": "Replaced direct CSRF check with actionRequireCsrf (non-redirect mode)." },
{ "path": "pages/auth/verify-email().php", "summary": "Replaced direct CSRF check with actionRequireCsrf (non-redirect mode)." },
{ "path": "pages/auth/reset().php", "summary": "Replaced direct CSRF check with actionRequireCsrf (non-redirect mode)." },
{ "path": "tests/Architecture/CorePageRequestGuardContractTest.php", "summary": "Added non-admin regression guard contract test." }
],
"commands": [
{ "cmd": "docker compose exec -T php vendor/bin/phpunit tests/Architecture/CorePageRequestGuardContractTest.php tests/Architecture/AdminActionRequestGuardContractTest.php", "result": "pass" },
{ "cmd": "docker compose exec -T php vendor/bin/phpunit tests/Architecture/PostEndpointCsrfContractTest.php tests/Architecture/PostRedirectGetContractTest.php", "result": "pass" },
{ "cmd": "docker compose exec -T php vendor/bin/phpunit tests/Architecture/AuthzAdminSettingsContractTest.php tests/Architecture/AuthzAdminMasterDataContractTest.php tests/Architecture/AuthzAdminUsersContractTest.php", "result": "pass" },
{ "cmd": "docker compose exec -T php vendor/bin/phpunit", "result": "pass" },
{ "cmd": "docker compose exec -T php vendor/bin/phpstan analyse -c phpstan.neon --no-progress", "result": "pass" },
{ "cmd": "docker compose exec -T php vendor/bin/phpunit tests/Architecture/CoreStarterkitContractTest.php", "result": "pass" },
{ "cmd": "docker compose exec -T php vendor/bin/php-cs-fixer fix --config=tools/php-cs-fixer/.php-cs-fixer.dist.php --dry-run --diff --verbose", "result": "pass" },
{ "cmd": "bin/docs-link-check.sh", "result": "pass" },
{ "cmd": "bin/docs-drift-check.sh", "result": "pass" },
{ "cmd": "bin/codex-skills-sync.sh --check", "result": "pass" }
],
"quality_gate_results": [
{ "gate_id": "QG-001", "result": "pass", "notes": "PHPUnit full run green: 2027 tests, 29637 assertions." },
{ "gate_id": "QG-002", "result": "pass", "notes": "PHPStan level 5: no errors." },
{ "gate_id": "QG-003", "result": "pass", "notes": "CoreStarterkitContractTest green: 13 tests, 6986 assertions." },
{ "gate_id": "QG-006", "result": "pass", "notes": "php-cs-fixer dry-run green." },
{ "gate_id": "QG-008", "result": "pass", "notes": "docs-link-check and docs-drift-check green." },
{ "gate_id": "QG-009", "result": "pass", "notes": "codex-skills-sync --check green." }
],
"metrics": {
"step4_target_files": 10,
"before_requestinput_method_calls": 3,
"after_requestinput_method_calls": 0,
"before_inline_session_csrf_checks": 10,
"after_inline_session_csrf_checks": 0,
"non_admin_inline_method_checks_total_after": 0,
"non_admin_inline_csrf_checks_total_after": 0
},
"open_items": [
"Module pages under modules/*/pages still contain inline method/csrf checks and are intentionally out-of-scope for this step."
]
}

View File

@@ -0,0 +1,12 @@
{
"task_id": "2026-04-24-action-csrf-centralization-step4",
"ready_to_finalize": true,
"code_review": "pass",
"security_review": "pass",
"acceptance_review": "pass",
"ci_status": "required-gates-pass",
"final_action": "commit",
"hold_reason": "",
"commit_message": "refactor(actions): centralize core page request/csrf guards",
"notes": "Core non-admin pages now aligned with helper-based request and CSRF guard pattern."
}

View File

@@ -0,0 +1,23 @@
{
"task_id": "2026-04-24-action-csrf-centralization-step4",
"analysis_ref": ".agents/runs/2026-04-24-action-csrf-centralization-step4/analysis.json",
"summary": "Complete centralization of legacy request method and CSRF checks for all remaining non-admin core pages.",
"scope": {
"in": [
"Migrate remaining pages/* (excluding pages/admin) off direct requestInput()->method() and Session::checkCsrfToken()",
"Preserve existing error/redirect behavior in auth and page-edit flows",
"Add non-admin architecture contract"
],
"out": [
"modules/*/pages",
"service/repository business logic changes"
]
},
"success_criteria": [
{ "id": "SC-001", "criterion": "Remaining non-admin method checks use helper-compatible patterns (no direct requestInput()->method())." },
{ "id": "SC-002", "criterion": "Remaining non-admin CSRF checks use actionRequireCsrf (no direct Session::checkCsrfToken())." },
{ "id": "SC-003", "criterion": "New CorePageRequestGuardContractTest prevents regression in non-admin core pages." },
{ "id": "SC-004", "criterion": "Architecture + required gate set remains green." }
],
"required_quality_gate_ids": ["QG-001", "QG-002", "QG-003", "QG-006", "QG-008", "QG-009"]
}

View File

@@ -0,0 +1,37 @@
{
"task_id": "2026-04-24-action-csrf-centralization-step4",
"verdict": "pass",
"checked_criterion_ids": [
"SC-001",
"SC-002",
"SC-003",
"SC-004"
],
"checks": [
{
"criterion_id": "SC-001",
"criterion": "Remaining non-admin method checks use helper-compatible patterns (no direct requestInput()->method()).",
"result": "pass",
"evidence": "Direct requestInput()->method() usage in non-admin pages reduced to 0."
},
{
"criterion_id": "SC-002",
"criterion": "Remaining non-admin CSRF checks use actionRequireCsrf (no direct Session::checkCsrfToken()).",
"result": "pass",
"evidence": "Direct Session::checkCsrfToken() usage in non-admin pages reduced to 0."
},
{
"criterion_id": "SC-003",
"criterion": "New CorePageRequestGuardContractTest prevents regression in non-admin core pages.",
"result": "pass",
"evidence": "CorePageRequestGuardContractTest added and passing."
},
{
"criterion_id": "SC-004",
"criterion": "Architecture + required gate set remains green.",
"result": "pass",
"evidence": "All required gates and targeted architecture tests passed."
}
],
"missing_or_wrong": []
}

View File

@@ -0,0 +1,18 @@
{
"task_id": "2026-04-24-action-csrf-centralization-step4",
"verdict": "pass",
"checked_guard_ids": [
"GR-CORE-003",
"GR-CORE-012",
"GR-TEST-001"
],
"checked_quality_gate_ids": [
"QG-001",
"QG-002",
"QG-003",
"QG-006",
"QG-008",
"QG-009"
],
"findings": []
}

View File

@@ -0,0 +1,10 @@
{
"task_id": "2026-04-24-action-csrf-centralization-step4",
"verdict": "pass",
"checked_guard_ids": [
"GR-SEC-001",
"GR-SEC-008",
"GR-SEC-009"
],
"findings": []
}