{ "task_id": "LOGIN-AUTH-QUALITY-CHECK-001", "plan_ref": "agent-system/runs/LOGIN-AUTH-QUALITY-CHECK-001/plan.json", "status": "done", "changed_files": [ { "path": "agent-system/runs/LOGIN-AUTH-QUALITY-CHECK-001/guard-matrix.json", "summary": "Explizite Guard-Matrix fuer alle In-Scope-Flows angelegt (Flow->Datei-Zuordnung, Guard-Refs, priorisierte Findings, priority_summary mit critical/high/medium open=0)." }, { "path": "pages/auth/register().php", "summary": "Register-POST auf klares POST-Gate umgestellt und CSRF-Pruefung vor Request-Verarbeitung erzwungen; CSRF-Fehlerpfad konsistent umgesetzt." }, { "path": "templates/login.phtml", "summary": "Lokalisierte Passwort-Toggle-Labels als Datenattribute fuer JS-Consumer bereitgestellt." }, { "path": "web/js/components/app-password-toggle.js", "summary": "Login-Passwort-Toggle konsolidiert: duplicate-init-Guard eingefuehrt (passwordToggleBound), erneute Wrapper/Listener-Bindungen verhindert." }, { "path": "web/js/components/app-password-hints.js", "summary": "Login-Passworthinweise konsolidiert: idempotente Container-Bindung eingefuehrt (passwordHintsBound), Mehrfach-Listener bei Re-Init verhindert." }, { "path": "web/css/pages/app-login.css", "summary": "Ungenutzten Legacy-Selektor .back_to_login entfernt (konkrete CSS-Cleanup-Massnahme im Login-Scope)." }, { "path": "i18n/default_de.json", "summary": "Neue i18n-Keys fuer Passwort-Toggle (Show/Hide password) in Deutsch ergaenzt." }, { "path": "i18n/default_en.json", "summary": "Neue i18n-Keys fuer Passwort-Toggle (Show/Hide password) in Englisch ergaenzt." }, { "path": "tests/Service/Auth/PasswordResetServiceTest.php", "summary": "Neue Unit-Tests fuer PasswordResetService (requestReset/verifyCode/resetPassword inkl. expiry/attempts/used/success)." }, { "path": "tests/Service/Auth/EmailVerificationServiceTest.php", "summary": "Neue Unit-Tests fuer EmailVerificationService (sendVerification/verifyCode/resendVerification inkl. already_verified/attempt-limit)." }, { "path": "tests/Service/Auth/MicrosoftOidcServiceTest.php", "summary": "Automatisierten SSO-Regressionstest fuer Callback-Domain-Policy ergänzt (email_domain_not_allowed)." }, { "path": "tests/Architecture/AuthLoginFrontendCleanupContractTest.php", "summary": "Neuer Architektur-Contract fuer Frontend-Cleanup-Invarianten (kein .back_to_login, duplicate-binding guards in Login-JS)." }, { "path": "tests/Architecture/AuthLoginAccessibilityContractTest.php", "summary": "A11y-Contract erweitert: Toggle muss lokalisierte Labels nutzen und darf kein tabIndex=-1 verwenden." }, { "path": "tests/Architecture/AuthRegisterSecurityContractTest.php", "summary": "Neuer Security-Contract: Register-POST muss CSRF vor Payload-Verarbeitung pruefen." } ], "guard_evidence": [ { "guard_id": "GR-CORE-001", "status": "pass", "evidence": "Guard-Matrix dokumentiert pro Auth-Flow die Layer-Zuordnung; Aenderungen bleiben in bestehender Schichtung (Pages orchestration, Services business logic)." }, { "guard_id": "GR-CORE-002", "status": "pass", "evidence": "QG-004 structural checks weiterhin 0; keine direkte Service/Gateway/Repository-Instanziierung in pages eingefuehrt." }, { "guard_id": "GR-CORE-003", "status": "pass", "evidence": "Auth pages nutzen weiterhin requestInput()-Vertrag; register nutzt now isMethod('POST') + requestInput body access ohne superglobal drift." }, { "guard_id": "GR-CORE-004", "status": "pass", "evidence": "QG-004 ApiResponse::readJsonBody check in pages/api/v1 bleibt 0." }, { "guard_id": "GR-CORE-005", "status": "pass", "evidence": "Keine Abschwaechung serverseitiger AuthZ-Pruefungen; Guard-Matrix zeigt keine offenen critical/high findings in AuthZ-relevanten Flows." }, { "guard_id": "GR-CORE-006", "status": "pass", "evidence": "Tenant-Scope-Invarianten unveraendert; SSO-Callback-Regression nun automatisiert mit Domain-Policy-Fehlerpfad abgesichert." }, { "guard_id": "GR-CORE-008", "status": "pass", "evidence": "Keine neuen direkten Superglobal-Zugriffe in pages/auth oder api pages eingefuehrt." }, { "guard_id": "GR-CORE-012", "status": "pass", "evidence": "Mutierende Erfolgsfaelle bleiben PRG-konform (register success -> redirect verify-email etc.)." }, { "guard_id": "GR-SEC-001", "status": "pass", "evidence": "Register-POST enforce't CSRF vor Payload-Verarbeitung; AuthRegisterSecurityContractTest bestaetigt die Reihenfolge." }, { "guard_id": "GR-SEC-002", "status": "pass", "evidence": "Keine neuen unredacted PII/secret logging paths eingefuehrt; neue Tests arbeiten mock-basiert ohne Log-Ausleitung." }, { "guard_id": "GR-SEC-003", "status": "pass", "evidence": "Keine SQL-String-Building-Aenderungen; QG-004 structural checks weiterhin 0 und neue Tests nutzen Repository-Interfaces." }, { "guard_id": "GR-SEC-004", "status": "pass", "evidence": "Keine externen CDN/remote assets in touched login templates/js/css eingefuehrt." }, { "guard_id": "GR-SEC-005", "status": "pass", "evidence": "Keine Kryptografie-Aenderungen in diesem Run; bestehende Crypto-Pfade unveraendert." }, { "guard_id": "GR-UI-009", "status": "pass", "evidence": "A11y bleibt intakt: AuthLoginAccessibilityContractTest gruen, Toggle keyboard-fokusfaehig und semantisch button-basiert." }, { "guard_id": "GR-UI-010", "status": "pass", "evidence": "Neue Toggle-Texte werden ueber t()-Keys bereitgestellt und in de/en gepflegt." }, { "guard_id": "GR-UI-011", "status": "pass", "evidence": "Login-JS konsolidiert: app-password-toggle und app-password-hints besitzen duplicate-binding guards (idempotente Initialisierung)." }, { "guard_id": "GR-UI-012", "status": "pass", "evidence": "Konkrete Login-CSS-Cleanup-Massnahme umgesetzt: ungenutzter Selektor .back_to_login entfernt; Contract testet Abwesenheit." }, { "guard_id": "GR-UI-013", "status": "pass", "evidence": "Interaktive Controls bleiben semantisch/keyboard-operabel; Toggle aktualisiert aria-labels korrekt (show/hide)." }, { "guard_id": "GR-UI-015", "status": "pass", "evidence": "i18n key completeness erfuellt: Show/Hide password in default_de.json und default_en.json vorhanden." }, { "guard_id": "GR-TEST-001", "status": "pass", "evidence": "Testabdeckung erweitert fuer Reset/Verify plus explizite SSO-Regression (MicrosoftOidcServiceTest callback domain policy)." }, { "guard_id": "GR-TEST-002", "status": "pass", "evidence": "Neue Tests bleiben DI/mock-freundlich ohne untestbare neue global side-effects." }, { "guard_id": "GR-LANG-002", "status": "pass", "evidence": "composer cs:check pass (0/518 files fixable)." } ], "commands": [ { "cmd": "docker compose exec php vendor/bin/phpunit tests/Service/Auth/MicrosoftOidcServiceTest.php --no-progress", "result": "pass" }, { "cmd": "docker compose exec php vendor/bin/phpunit tests/Architecture/AuthLoginFrontendCleanupContractTest.php --no-progress", "result": "pass" }, { "cmd": "docker compose exec php vendor/bin/phpunit tests/Service/Auth/PasswordResetServiceTest.php tests/Service/Auth/EmailVerificationServiceTest.php --no-progress", "result": "pass" }, { "cmd": "docker compose exec php vendor/bin/phpunit tests/Architecture/AuthLoginAccessibilityContractTest.php tests/Architecture/AuthRegisterSecurityContractTest.php --no-progress", "result": "pass" }, { "cmd": "docker compose exec php vendor/bin/phpunit --no-progress", "result": "pass" }, { "cmd": "docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress", "result": "pass" }, { "cmd": "docker compose exec php vendor/bin/phpunit tests/Architecture/CoreStarterkitContractTest.php --no-progress", "result": "pass" }, { "cmd": "(rg 'new\\s+[^\\s(]+Factory\\(' lib/Service || true) | wc -l && (rg --glob '!**/*Factory.php' 'new\\s+[^\\s(]+(Service|Gateway|Repository)\\(' lib/Service || true) | wc -l && (rg \"\\b(accessServicesFactory|directoryServicesFactory|userServicesFactory|authServicesFactory|tenantServicesFactory|settingServicesFactory|userRepositoryFactory|authRepositoryFactory|authGatewayFactory)\\(\" pages lib templates web || true) | wc -l && (rg -n 'new\\s+[^\\s(]+(Service|Gateway|Repository)\\(' pages -g '*.php' || true) | wc -l && (rg -n '\\bDB::' pages -g '*.php' || true) | wc -l && (rg -n 'app\\([^\\n]*Factory::class\\)->create' pages/admin -g '*.php' || true) | wc -l && (rg -n 'Factory::class' pages/admin -g '*.php' || true) | wc -l && (rg -n 'ApiResponse::readJsonBody\\(' pages/api/v1 -g '*.php' || true) | wc -l", "result": "pass" }, { "cmd": "docker compose exec php composer cs:check", "result": "pass" }, { "cmd": "Manual browser smoke (QG-005) for /login, /password/forgot->verify->reset, /verify-email, /auth/microsoft/start+callback, devtools console", "result": "pass" } ], "quality_gate_results": [ { "gate_id": "QG-001", "result": "pass", "notes": "Exit code 0. PHPUnit full: 487 tests, 11030 assertions, Warnings 1, Deprecations 1 (non-blocking)." }, { "gate_id": "QG-002", "result": "pass", "notes": "Exit code 0. PHPStan: [OK] No errors." }, { "gate_id": "QG-003", "result": "pass", "notes": "Exit code 0. CoreStarterkitContractTest: 11 tests, 6167 assertions." }, { "gate_id": "QG-004", "result": "pass", "notes": "Alle strukturellen rg-check Zaehler sind 0 (8/8 checks gruen)." }, { "gate_id": "QG-005", "result": "pass", "notes": "Manueller Browser-Smoke zuvor erfolgreich bestaetigt (lokal+SSO+Recovery+Verify+Console)." }, { "gate_id": "QG-006", "result": "pass", "notes": "Exit code 0. composer cs:check: 0 von 518 Dateien fixbar." } ], "test_results": [ { "name": "MicrosoftOidcServiceTest", "result": "pass", "notes": "15 tests, 61 assertions; inkl. neuer callback regression email_domain_not_allowed." }, { "name": "AuthLoginFrontendCleanupContractTest", "result": "pass", "notes": "3 tests, 15 assertions; prueft CSS cleanup + JS duplicate-binding guards." }, { "name": "PasswordResetServiceTest + EmailVerificationServiceTest", "result": "pass", "notes": "27 tests, 81 assertions." }, { "name": "AuthLoginAccessibilityContractTest + AuthRegisterSecurityContractTest", "result": "pass", "notes": "6 tests, 105 assertions." }, { "name": "CoreStarterkitContractTest", "result": "pass", "notes": "11 tests, 6167 assertions." }, { "name": "PHPUnit Full", "result": "pass", "notes": "487 tests, 11030 assertions, warnings/deprecations vorhanden aber kein failure." }, { "name": "PHPStan", "result": "pass", "notes": "No errors." }, { "name": "PHP CS Check", "result": "pass", "notes": "0/518 files fixable." }, { "name": "Manual Browser Smoke (QG-005)", "result": "pass", "notes": "Manueller Smoke erfolgreich bestaetigt." } ], "open_items": [] }