---
created_by: "Generated by AI gpt-5-codex on 2026-06-06T00:00:00Z. Human review required."
---

# Test Plan: PHP 8.3 FTP-Replacement MVP

## Scope covered now

- First-launch web provisioning of the trusted account
- Authentication, login, logout, and session timeout
- Protected shell access
- Protected browsing of the approved root area
- Single-file upload into the approved root area
- Authorized file download from the approved root area
- Rename of files and folders inside the approved root area
- Delete of files and folders inside the approved root area
- Audit logging for security-relevant actions
- Server-side path traversal blocking
- Security checks for provisioning, auth, CSRF, and traversal
- Usability checks for first-time setup and sign-in

## Upload slice

- Single-file upload into the current folder
- Auth protection and CSRF rejection
- Allowed-root enforcement
- Success and failure feedback
- Existing-file collision flow with explicit confirmation before replacement

## Download slice

- Authorized file download from the current browser view
- Rejection of directory downloads
- Rejection of invalid paths and traversal attempts
- Rejection of unauthenticated requests
- Download routing through application authorization rather than public file URLs

## Rename slice

- Renaming an allowed file
- Renaming an allowed folder
- Explicit confirmation before applying the rename
- Collision rejection when the destination name exists
- Rejection of invalid paths and traversal attempts
- Rejection of unauthenticated or CSRF-invalid requests

## Delete slice

- Deleting an allowed file
- Deleting an allowed folder
- Explicit confirmation before applying the delete
- Rejection of root or protected targets
- Rejection of invalid paths and traversal attempts
- Rejection of unauthenticated or CSRF-invalid requests
- Clear success and failure outcome expectations

## Audit logging

- Logging of login success and failure
- Logging of upload, download, rename, and delete actions
- Logging of denied path and access attempts where applicable
- Timestamp and user identity in log entries where available
- No raw passwords or other secrets in log output

## Deferred coverage

- Any bulk or multi-file workflow
- Any direct file-editing workflow

## Test matrix

| ID | Area | Type | Scenario | Expected result | Status |
|---|---|---|---|---|---|
| T-001 | Provisioning | Negative | Open `/login.php`, `/app.php`, or `/files.php` before first launch | The app redirects to `/setup.php` and blocks normal use until provisioning exists | Now |
| T-002 | Provisioning | Positive | Open `/setup.php` before first launch | Setup page is shown and explains it creates the initial trusted account | Now |
| T-003 | Provisioning | Negative | Open `/setup.php` after provisioning exists | User is redirected to login; setup is no longer available | Now |
| T-004 | Provisioning | Negative | Submit setup without CSRF token | Submission is rejected with a session-token error | Now |
| T-005 | Provisioning | Negative | Submit setup with mismatched passwords | Setup fails with confirmation mismatch message | Now |
| T-006 | Provisioning | Negative | Submit setup with empty username | Setup fails with username required message | Now |
| T-007 | Provisioning | Negative | Submit setup with password shorter than 12 chars | Setup fails with password-length validation | Now |
| T-008 | Provisioning | Negative | Submit setup with invalid username characters or `..` | Setup rejects unsafe usernames | Now |
| T-009 | Provisioning | Positive | Submit setup with valid username, display name, and password | Local auth config is created and the user is redirected to login with setup-complete reason | Now |
| T-010 | Provisioning | Security | Re-open or resubmit setup after successful provisioning | Second provisioning attempt is refused; no overwrite occurs | Now |
| T-011 | Login | Positive | Load `/login.php` when unauthenticated | Sign-in form is shown | Now |
| T-012 | Login | Negative | Submit login with blank username or password | Form validation message is shown; no session is created | Now |
| T-013 | Login | Negative | Submit login with invalid credentials | Login fails with invalid-credentials message | Now |
| T-014 | Login | Positive | Submit login with valid credentials | Session is created and user reaches protected shell | Now |
| T-015 | Login | Security | Login uses CSRF token | Missing or invalid token blocks authentication | Now |
| T-016 | Login | Security | Successful login from existing session | Session ID is regenerated on login | Now |
| T-017 | Logout | Positive | Submit logout from authenticated session with valid CSRF token | Session is destroyed and user returns to login with logged-out message | Now |
| T-018 | Logout | Negative | Submit logout with missing or invalid CSRF token | Logout is rejected and session remains active | Now |
| T-019 | Logout | Negative | GET `/logout.php` directly | No logout occurs; request is redirected or ignored safely | Now |
| T-020 | Timeout | Positive | Leave session idle beyond configured timeout and then access protected page | User is redirected to login with timeout message | Now |
| T-021 | Timeout | Positive | Access protected page before timeout expires | Session stays active; last-activity timestamp is refreshed | Now |
| T-022 | Shell | Positive | Open `/app.php` after login | Protected shell is displayed | Now |
| T-023 | Shell | Negative | Open `/app.php` without authentication | User is redirected to login | Now |
| T-024 | Shell | Security | Open `/app.php` with an expired session cookie | Session is destroyed and user is sent to login | Now |
| T-025 | Browse | Positive | Open `/files.php` at approved root after login | Root listing is shown with the approved file actions available | Now |
| T-026 | Browse | Positive | Open a valid subfolder inside approved root | Subfolder contents and breadcrumb trail are shown | Now |
| T-027 | Browse | Positive | Open an empty folder inside approved root | Empty-state message is shown | Now |
| T-028 | Browse | Negative | Open `/files.php` without login | User is redirected to login | Now |
| T-029 | Browse | Security | Browse a path that does not exist | User sees a safe not-found message | Now |
| T-030 | Browse | Security | Browse a non-folder path | User sees a safe not-a-folder message | Now |
| T-031 | Traversal | Security | Request `path=..` or `path=../..` | Server blocks traversal attempt | Now |
| T-032 | Traversal | Security | Request encoded traversal such as `%2e%2e` or mixed slash/backslash forms | Server blocks traversal attempt | Now |
| T-033 | Traversal | Security | Request a path containing colon or null-byte style input | Server rejects the path as unsafe | Now |
| T-034 | Traversal | Security | Attempt to escape approved root through filesystem resolution | Request is rejected even if the resolved target would leave the root | Now |
| T-035 | Usability | Positive | First-time setup page clearly explains that it disappears after completion | Message is visible and understandable to a first-time operator | Now |
| T-036 | Usability | Positive | Login form keeps field labels and focus order simple | Username and password fields are obvious and keyboard-friendly | Now |
| T-037 | Usability | Positive | After setup completes, login page explains the next step | User sees a clear setup-complete sign-in prompt | Now |
| T-038 | Usability | Positive | After logout, login page explains the sign-out result | User sees a clear logged-out confirmation | Now |
| T-039 | Upload | Positive | Open upload entry from the current folder after login | Upload form is available in the current folder context | Now |
| T-040 | Upload | Negative | Open upload entry without authentication | User is redirected to login | Now |
| T-041 | Upload | Security | Submit upload without a valid CSRF token | Upload is rejected and no file is written | Now |
| T-042 | Upload | Security | Try to upload into a path outside the approved root | Server blocks the request and reports a safe error | Now |
| T-043 | Upload | Positive | Upload a single file into the current folder | File is stored in the current folder and success feedback is shown | Now |
| T-044 | Upload | Negative | Submit an upload that cannot be completed | Failure feedback is shown and the current folder remains unchanged | Now |
| T-045 | Upload | Security | Upload a file with the same name as an existing file without confirmation | Collision is detected and replacement does not occur yet | Now |
| T-046 | Upload | Positive | Confirm replacement for an existing-file collision | Replacement proceeds only after explicit confirmation and feedback is shown | Now |
| T-047 | Download | Positive | Open a file download from the current browser view after login | File is delivered only through the application and the user remains authorized | Now |
| T-048 | Download | Negative | Attempt to download a directory from the browser view | Directory download is rejected with safe feedback | Now |
| T-049 | Download | Security | Request a download with an invalid path or traversal pattern | Request is blocked and no file is streamed | Now |
| T-050 | Download | Negative | Request a download while unauthenticated | User is redirected to login and no file is streamed | Now |
| T-051 | Download | Security | Inspect the download route for authorization behavior | Download is served through the application, not by exposing a public file URL | Now |
| T-052 | Rename | Positive | Rename an allowed file in the current browser view after login | File is renamed successfully and the browser view reflects the change | Now |
| T-053 | Rename | Positive | Rename an allowed folder in the current browser view after login | Folder is renamed successfully and the browser view reflects the change | Now |
| T-054 | Rename | Security | Submit a rename without explicit confirmation | Rename is not applied until the user confirms the action | Now |
| T-055 | Rename | Negative | Rename to a destination name that already exists | Rename is rejected with collision feedback and no overwrite occurs | Now |
| T-056 | Rename | Security | Request a rename with an invalid path or traversal pattern | Request is blocked and no rename is performed | Now |
| T-057 | Rename | Negative | Request a rename while unauthenticated | User is redirected to login and no rename is performed | Now |
| T-058 | Rename | Security | Submit a rename with an invalid CSRF token | Rename is rejected and no filesystem change occurs | Now |
| T-059 | Delete | Positive | Delete an allowed file in the current browser view after login | File is deleted successfully and a clear success outcome is shown | Now |
| T-060 | Delete | Positive | Delete an allowed folder in the current browser view after login | Folder is deleted successfully and a clear success outcome is shown | Now |
| T-061 | Delete | Security | Submit a delete without explicit confirmation | Delete is not applied until the user confirms the action | Now |
| T-062 | Delete | Security | Attempt to delete the root or a protected target | Delete is rejected and the protected target remains unchanged | Now |
| T-063 | Delete | Security | Request a delete with an invalid path or traversal pattern | Request is blocked and no delete is performed | Now |
| T-064 | Delete | Negative | Request a delete while unauthenticated | User is redirected to login and no delete is performed | Now |
| T-065 | Delete | Security | Submit a delete with an invalid CSRF token | Delete is rejected and no filesystem change occurs | Now |
| T-066 | Delete | Positive | Verify delete success and failure feedback in the UI | Clear outcome messaging is shown for both success and failure cases | Now |
| T-067 | Audit | Positive | Log login success and login failure events | Both outcomes are recorded with an appropriate result and identity context | Now |
| T-068 | Audit | Positive | Log upload, download, rename, and delete actions | Each action is recorded with the relevant user and action type | Now |
| T-069 | Audit | Positive | Log denied path and access attempts where applicable | Denied requests are recorded with a safe reason and context | Now |
| T-070 | Audit | Positive | Verify log entries include timestamp and user identity where available | Entries contain time and actor information when the runtime has it | Now |
| T-071 | Audit | Security | Verify no raw passwords or other secrets are written to audit logs | Sensitive values are omitted or redacted from log output | Now |

## Key risks / gaps

- The first-launch setup flow is one-time and stateful, so each test run needs an isolated environment or a reset path.
- Session timeout coverage is time-dependent; deterministic tests will need controlled time or a short test timeout.
- Path traversal coverage is strongest when the fixture includes nested folders and, if available, a symlink escape case.
- Upload collision coverage needs a fixture with an existing file in the current folder and a clear replacement prompt.
- Download coverage needs a fixture file in the approved root plus a separate folder path to verify directory rejection.
- Rename coverage needs fixtures for both a file and a folder, plus a conflicting destination name for collision rejection.
- Delete coverage needs fixtures for a removable file, a removable folder, and a protected root target.
- Audit coverage needs a concrete inspection step against the generated log file in an Apache-like deployment.
- Direct web-access blocking for `storage/` is primarily a deployment concern; it should be validated in an Apache-like environment, not only in unit-style checks.
- No coverage is planned yet for bulk or multi-file workflows or direct file-editing workflows because those slices are not implemented.

## Notes

- This plan stays aligned to the current one-feature-at-a-time implementation approach.
- The current implementation direction is a protected browser shell plus approved-root file actions, not a broader file-management console.
- Reviewers can extend this matrix later by adding explicit IDs for any post-MVP hardening without changing the implemented feature set.
