Conversation
📝 WalkthroughWalkthroughThis PR adds a workflow (.github/workflows/front-docs.yml) that generates an OpenAPI JSON via PHP/Composer and vendor/bin/openapi, uploads it as an artifact, and conditionally pushes an updated openapi.json to the phpList/web-frontend repository. It tightens triggers in .github/workflows/client-docs.yml to only run pushes on dev/main and PRs to main. It injects a PaginatedDataProvider into SubscribePageController and adds GET /subscribe-pages/ to return a paginated list. Also updates composer phplist/core branch constraint and the OA contact email in PhpListRestBundle. Sequence Diagram(s)sequenceDiagram
participant Actions as GitHubActions/generate-openapi
participant PHP as PHP+Composer+openapi
participant Artifact as ActionsArtifact
participant WebFrontend as phpList/web-frontend
Actions->>PHP: run vendor/bin/openapi -> docs/latest-restapi.json
PHP->>Artifact: upload docs/latest-restapi.json
Actions->>WebFrontend: checkout target branch
Actions->>Artifact: download latest-restapi.json
Actions->>WebFrontend: compare latest-restapi.json with openapi.json
Actions->>WebFrontend: commit & push updated openapi.json (if different)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
…ent-docs to specific branches
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (1)
.github/workflows/client-docs.yml (1)
1-121: Advisory: Apply the same security hardening as front-docs.yml.This workflow shares the same structure and security vulnerabilities as the newly added
front-docs.yml:
- Template injection (lines 22, 24):
github.head_refandgithub.ref_nameexpanded directly in shell- Unpinned actions (lines 28, 31, 37, 51, 63, 81): Using mutable tags instead of commit SHAs
- Missing permissions block: Runs with broad default permissions
- Credential persistence (lines 28, 63): Checkout actions don't set
persist-credentials: falseWhile these are pre-existing issues, consider applying the same fixes proposed for
front-docs.ymlto maintain consistent security posture across both documentation workflows.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/client-docs.yml around lines 1 - 121, The Determine source branch step uses untrusted shell expansion of github.head_ref and github.ref_name (template injection) and several actions are unpinned and keep credentials; fix by: (1) replace the shell-based output assignment in the "Determine source branch" step with GitHub expression-based outputs (use the official event expressions like github.event.pull_request.head.ref or github.ref_name via the step outputs syntax) so no untrusted expansion occurs in run; (2) pin all third-party actions referenced (actions/checkout, shivammathur/setup-php, actions/cache, actions/upload-artifact, actions/download-artifact, etc.) to immutable commit SHAs instead of floating tags; (3) add a top-level permissions block with minimal required rights; and (4) set persist-credentials: false on both checkout steps ("Checkout Source Repository" and "Checkout phplist-api-client Repository") to avoid credential persistence.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/front-docs.yml:
- Around line 26-28: The checkout steps using actions/checkout@v3 are leaving
credentials in .git/config; update both checkout steps (the initial "Checkout
Source Repository" and the later checkout that uses the PUSH_WEB_FRONTEND token)
to add persist-credentials: false to the action inputs so credentials are not
persisted, and ensure the subsequent commit/push logic (where you reconfigure
git credentials) remains intact to set credentials only when needed.
- Around line 1-11: Add an explicit top-level permissions block to this workflow
(named "Update phplist-web-frontend OpenAPI") to enforce least-privilege for
GITHUB_TOKEN; replace the default broad permissions with explicit, minimal
permissions required by the job(s) (for example, set contents: read and only
include write permissions for specific scopes actually needed like
pull-requests: write or workflows: write if the job updates PRs or workflow
files), placing the permissions: block directly under the workflow header so it
applies to all jobs.
- Around line 17-24: The Determine source branch step is vulnerable because it
injects github.head_ref/github.ref_name directly into a shell command; replace
this run block with a non-shell implementation (e.g., use actions/github-script
or an official action) that reads the branch from the GitHub context and sets
the step output via the Actions toolkit (e.g., core.setOutput('source_branch',
branch)) to avoid shell interpolation; locate the step with id "branch" / name
"Determine source branch" and remove direct echo of ${{ github.head_ref }} and
${{ github.ref_name }} in shell commands.
- Line 27: The workflow uses mutable action tags (e.g., the uses entry
"actions/checkout@v3") which must be replaced with immutable commit SHAs to
prevent supply-chain risks; update every "uses: actions/checkout@v3" occurrence
to pin to de0fac2e4500dabe0009e67214ff5f5447ce83dd, and similarly replace the
other mutable usages mentioned (shivammathur/setup-php, actions/cache,
actions/upload-artifact, actions/download-artifact) with the recommended commit
SHAs (7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc,
27d5ce7f107fe9357f9df03efb73ab90386fccae,
043fb46d1a93c77aae656e7c1c64a875d1fc6a0a,
3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c respectively), ensuring all “uses:”
lines in the workflow file are updated to those exact SHAs.
In `@composer.json`:
- Line 45: The composer entry "phplist/core": "dev-dev" appears to track the dev
branch (not main) — if the PR intends to follow the stable main line change it
back to "dev-main"; otherwise explicitly confirm and document the intent to
track the less-stable dev branch. Update the composer.json dependency for
phplist/core (the "phplist/core" version string) to "dev-main" for
consistency/stability or add a short comment/PR description explaining why
"dev-dev" (dev) is intentionally required.
In `@src/Subscription/Controller/SubscribePageController.php`:
- Line 59: The OpenAPI schema for the after_id parameter in
SubscribePageController (schema: new OA\Schema(...)) incorrectly sets minimum
and default to 1; change the schema so it allows 0 by setting minimum to 0 and
default to 0 (or remove the minimum/default constraint) so cursor pagination
starting at 0 is valid; update the OA\Schema for after_id accordingly.
---
Nitpick comments:
In @.github/workflows/client-docs.yml:
- Around line 1-121: The Determine source branch step uses untrusted shell
expansion of github.head_ref and github.ref_name (template injection) and
several actions are unpinned and keep credentials; fix by: (1) replace the
shell-based output assignment in the "Determine source branch" step with GitHub
expression-based outputs (use the official event expressions like
github.event.pull_request.head.ref or github.ref_name via the step outputs
syntax) so no untrusted expansion occurs in run; (2) pin all third-party actions
referenced (actions/checkout, shivammathur/setup-php, actions/cache,
actions/upload-artifact, actions/download-artifact, etc.) to immutable commit
SHAs instead of floating tags; (3) add a top-level permissions block with
minimal required rights; and (4) set persist-credentials: false on both checkout
steps ("Checkout Source Repository" and "Checkout phplist-api-client
Repository") to avoid credential persistence.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 7eaa983b-b065-4955-8333-f00eca6c5837
📒 Files selected for processing (5)
.github/workflows/client-docs.yml.github/workflows/front-docs.ymlcomposer.jsonsrc/PhpListRestBundle.phpsrc/Subscription/Controller/SubscribePageController.php
✅ Files skipped from review due to trivial changes (1)
- src/PhpListRestBundle.php
| name: Update phplist-web-frontend OpenAPI | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - dev | ||
| - main | ||
| pull_request: | ||
| branches: | ||
| - main | ||
| jobs: |
There was a problem hiding this comment.
Restrict workflow permissions following least-privilege principle.
The workflow lacks an explicit permissions: block, so it runs with broad default GITHUB_TOKEN permissions (including write access to repository contents). If the workflow is compromised (e.g., via the template injection vulnerability), the attacker inherits all default permissions.
🔒 Proposed permissions block
name: Update phplist-web-frontend OpenAPI
+permissions:
+ contents: write # Required to push to web-frontend repo
+ actions: read # Required to download artifacts
+
on:
push:🧰 Tools
🪛 zizmor (1.25.2)
[warning] 1-121: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block
(excessive-permissions)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/front-docs.yml around lines 1 - 11, Add an explicit
top-level permissions block to this workflow (named "Update phplist-web-frontend
OpenAPI") to enforce least-privilege for GITHUB_TOKEN; replace the default broad
permissions with explicit, minimal permissions required by the job(s) (for
example, set contents: read and only include write permissions for specific
scopes actually needed like pull-requests: write or workflows: write if the job
updates PRs or workflow files), placing the permissions: block directly under
the workflow header so it applies to all jobs.
| - name: Determine source branch | ||
| id: branch | ||
| run: | | ||
| if [ "${{ github.event_name }}" = "pull_request" ]; then | ||
| echo "source_branch=${{ github.head_ref }}" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "source_branch=${{ github.ref_name }}" >> "$GITHUB_OUTPUT" | ||
| fi |
There was a problem hiding this comment.
Critical: Template injection vulnerability in branch name handling.
Lines 21 and 23 directly expand github.head_ref and github.ref_name into shell commands. An attacker can craft a malicious branch name (e.g., main$(curl evil.com) or dev; malicious-command) to execute arbitrary code in the CI environment. This could lead to credential theft, supply chain compromise, or repository tampering.
🔒 Proposed fix: Use environment variables
- name: Determine source branch
id: branch
+ env:
+ EVENT_NAME: ${{ github.event_name }}
+ HEAD_REF: ${{ github.head_ref }}
+ REF_NAME: ${{ github.ref_name }}
run: |
- if [ "${{ github.event_name }}" = "pull_request" ]; then
- echo "source_branch=${{ github.head_ref }}" >> "$GITHUB_OUTPUT"
+ if [ "$EVENT_NAME" = "pull_request" ]; then
+ echo "source_branch=$HEAD_REF" >> "$GITHUB_OUTPUT"
else
- echo "source_branch=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
+ echo "source_branch=$REF_NAME" >> "$GITHUB_OUTPUT"
fi📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - name: Determine source branch | |
| id: branch | |
| run: | | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| echo "source_branch=${{ github.head_ref }}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "source_branch=${{ github.ref_name }}" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Determine source branch | |
| id: branch | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| HEAD_REF: ${{ github.head_ref }} | |
| REF_NAME: ${{ github.ref_name }} | |
| run: | | |
| if [ "$EVENT_NAME" = "pull_request" ]; then | |
| echo "source_branch=$HEAD_REF" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "source_branch=$REF_NAME" >> "$GITHUB_OUTPUT" | |
| fi |
🧰 Tools
🪛 actionlint (1.7.12)
[error] 19-19: "github.head_ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details
(expression)
🪛 zizmor (1.25.2)
[error] 21-21: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
[error] 23-23: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/front-docs.yml around lines 17 - 24, The Determine source
branch step is vulnerable because it injects github.head_ref/github.ref_name
directly into a shell command; replace this run block with a non-shell
implementation (e.g., use actions/github-script or an official action) that
reads the branch from the GitHub context and sets the step output via the
Actions toolkit (e.g., core.setOutput('source_branch', branch)) to avoid shell
interpolation; locate the step with id "branch" / name "Determine source branch"
and remove direct echo of ${{ github.head_ref }} and ${{ github.ref_name }} in
shell commands.
| - name: Checkout Source Repository | ||
| uses: actions/checkout@v3 | ||
|
|
There was a problem hiding this comment.
Prevent credential persistence in checkout actions.
Both actions/checkout steps lack persist-credentials: false, causing credentials to persist in .git/config. The checkout at line 62 is particularly sensitive because it uses the privileged PUSH_WEB_FRONTEND token. If subsequent steps are compromised or files leaked, credentials could be exposed.
🔐 Proposed fix
- name: Checkout Source Repository
uses: actions/checkout@v3
+ with:
+ persist-credentials: false - name: Checkout phpList-web-frontend Repository
uses: actions/checkout@v3
with:
repository: phpList/web-frontend
token: ${{ secrets.PUSH_WEB_FRONTEND }}
fetch-depth: 0
+ persist-credentials: falseNote: You'll need to re-configure git credentials in the commit step (line 106-107) after disabling persistence, which you're already doing correctly.
Also applies to: 61-66
🧰 Tools
🪛 actionlint (1.7.12)
[error] 27-27: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue
(action)
🪛 zizmor (1.25.2)
[warning] 26-27: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 27-27: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/front-docs.yml around lines 26 - 28, The checkout steps
using actions/checkout@v3 are leaving credentials in .git/config; update both
checkout steps (the initial "Checkout Source Repository" and the later checkout
that uses the PUSH_WEB_FRONTEND token) to add persist-credentials: false to the
action inputs so credentials are not persisted, and ensure the subsequent
commit/push logic (where you reconfigure git credentials) remains intact to set
credentials only when needed.
| fi | ||
|
|
||
| - name: Checkout Source Repository | ||
| uses: actions/checkout@v3 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Fetch latest release commit SHAs for GitHub Actions
echo "=== actions/checkout ==="
gh api repos/actions/checkout/releases/latest --jq '.tag_name as $tag | "Tag: \($tag)" | ., "SHA: TBD - check releases page"'
echo -e "\n=== shivammathur/setup-php ==="
gh api repos/shivammathur/setup-php/releases/latest --jq '.tag_name'
echo -e "\n=== actions/cache ==="
gh api repos/actions/cache/releases/latest --jq '.tag_name'
echo -e "\n=== actions/upload-artifact ==="
gh api repos/actions/upload-artifact/releases/latest --jq '.tag_name'
echo -e "\n=== actions/download-artifact ==="
gh api repos/actions/download-artifact/releases/latest --jq '.tag_name'Repository: phpList/rest-api
Length of output: 279
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== actions/checkout (latest tag -> object sha) ==="
gh api repos/actions/checkout/git/ref/tags/v6.0.2 --jq '.object.sha'
echo "=== shivammathur/setup-php (latest tag -> object sha) ==="
gh api repos/shivammathur/setup-php/git/ref/tags/2.37.1 --jq '.object.sha'
echo "=== actions/cache (latest tag -> object sha) ==="
gh api repos/actions/cache/git/ref/tags/v5.0.5 --jq '.object.sha'
echo "=== actions/upload-artifact (latest tag -> object sha) ==="
gh api repos/actions/upload-artifact/git/ref/tags/v7.0.1 --jq '.object.sha'
echo "=== actions/download-artifact (latest tag -> object sha) ==="
gh api repos/actions/download-artifact/git/ref/tags/v8.0.1 --jq '.object.sha'Repository: phpList/rest-api
Length of output: 544
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1,140p' .github/workflows/front-docs.yml | nl -ba | sed -n '1,140p'Repository: phpList/rest-api
Length of output: 103
🏁 Script executed:
#!/bin/bash
set -euo pipefail
cat -n .github/workflows/front-docs.yml | sed -n '1,140p'Repository: phpList/rest-api
Length of output: 4769
Pin GitHub Actions to immutable commit SHAs (and update outdated majors)
The workflow uses mutable action tags (@v3, @v2, @v4), which enables supply-chain tampering if an action repo is compromised. Pin each uses: to a commit SHA instead.
Recommended pins for this workflow:
actions/checkout→de0fac2e4500dabe0009e67214ff5f5447ce83dd(v6.0.2) for both occurrences (uses: actions/checkout@v3)shivammathur/setup-php→7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc(2.37.1)actions/cache→27d5ce7f107fe9357f9df03efb73ab90386fccae(v5.0.5)actions/upload-artifact→043fb46d1a93c77aae656e7c1c64a875d1fc6a0a(v7.0.1)actions/download-artifact→3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c(v8.0.1)
🧰 Tools
🪛 actionlint (1.7.12)
[error] 27-27: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue
(action)
🪛 zizmor (1.25.2)
[warning] 26-27: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 27-27: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/front-docs.yml at line 27, The workflow uses mutable
action tags (e.g., the uses entry "actions/checkout@v3") which must be replaced
with immutable commit SHAs to prevent supply-chain risks; update every "uses:
actions/checkout@v3" occurrence to pin to
de0fac2e4500dabe0009e67214ff5f5447ce83dd, and similarly replace the other
mutable usages mentioned (shivammathur/setup-php, actions/cache,
actions/upload-artifact, actions/download-artifact) with the recommended commit
SHAs (7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc,
27d5ce7f107fe9357f9df03efb73ab90386fccae,
043fb46d1a93c77aae656e7c1c64a875d1fc6a0a,
3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c respectively), ensuring all “uses:”
lines in the workflow file are updated to those exact SHAs.
| "require": { | ||
| "php": "^8.1", | ||
| "phplist/core": "dev-main", | ||
| "phplist/core": "dev-dev", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check phplist/core branches and recent activity
echo "=== Checking if dev-dev branch exists ==="
gh api repos/phpList/core/branches/dev-dev --jq '.name' 2>/dev/null || echo "Branch 'dev-dev' not found"
echo -e "\n=== Checking if dev-main branch exists ==="
gh api repos/phpList/core/branches/dev-main --jq '.name' 2>/dev/null || echo "Branch 'dev-main' not found"
echo -e "\n=== Recent commits on dev-dev (if exists) ==="
gh api repos/phpList/core/commits?sha=dev-dev --jq '.[0:3] | .[] | "\(.commit.author.date) - \(.commit.message | split("\n")[0])"' 2>/dev/null || echo "Cannot fetch commits for dev-dev"
echo -e "\n=== Recent commits on dev-main (if exists) ==="
gh api repos/phpList/core/commits?sha=dev-main --jq '.[0:3] | .[] | "\(.commit.author.date) - \(.commit.message | split("\n")[0])"' 2>/dev/null || echo "Cannot fetch commits for dev-main"Repository: phpList/rest-api
Length of output: 853
🏁 Script executed:
#!/bin/bash
set -e
echo "=== Listing branches in phpList/core (top 100) ==="
gh api repos/phpList/core/branches?per_page=100 --jq '.[].name' 2>/dev/null || echo "Cannot list branches (gh api failed)"
echo -e "\n=== Checking for likely composer-branch candidates ==="
for b in main master develop dev trunk; do
echo -e "\n-- Branch: $b"
gh api repos/phpList/core/branches/$b --jq '.name' 2>/dev/null || echo "Branch '$b' not found"
done
echo -e "\n=== Checking tags (top 50) ==="
gh api repos/phpList/core/tags?per_page=50 --jq '.[].name' 2>/dev/null || echo "Cannot list tags (gh api failed)"Repository: phpList/rest-api
Length of output: 808
Confirm intended stability for phplist/core tracking (dev-dev vs dev-main)
In phpList/core, the actual branches are dev and main (no literal dev-dev branch). Composer’s dev-dev tracks dev (while dev-main tracks main), so switching to dev-dev means opting into the less-stable dev line—ensure this is intentional for the PR’s dev → main flow and add rationale; otherwise consider reverting to dev-main for consistency/stability.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@composer.json` at line 45, The composer entry "phplist/core": "dev-dev"
appears to track the dev branch (not main) — if the PR intends to follow the
stable main line change it back to "dev-main"; otherwise explicitly confirm and
document the intent to track the less-stable dev branch. Update the
composer.json dependency for phplist/core (the "phplist/core" version string) to
"dev-main" for consistency/stability or add a short comment/PR description
explaining why "dev-dev" (dev) is intentionally required.
| description: 'Last id (starting from 0)', | ||
| in: 'query', | ||
| required: false, | ||
| schema: new OA\Schema(type: 'integer', default: 1, minimum: 1) |
There was a problem hiding this comment.
Fix OpenAPI schema constraint for after_id.
The parameter description states "Last id (starting from 0)" but the schema specifies minimum: 1 and default: 1, which prevents valid requests with after_id=0. The test suite confirms that 0 is a valid starting value for cursor pagination.
📝 Proposed fix
new OA\Parameter(
name: 'after_id',
description: 'Last id (starting from 0)',
in: 'query',
required: false,
- schema: new OA\Schema(type: 'integer', default: 1, minimum: 1)
+ schema: new OA\Schema(type: 'integer', default: 0, minimum: 0)
),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| schema: new OA\Schema(type: 'integer', default: 1, minimum: 1) | |
| schema: new OA\Schema(type: 'integer', default: 0, minimum: 0) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/Subscription/Controller/SubscribePageController.php` at line 59, The
OpenAPI schema for the after_id parameter in SubscribePageController (schema:
new OA\Schema(...)) incorrectly sets minimum and default to 1; change the schema
so it allows 0 by setting minimum to 0 and default to 0 (or remove the
minimum/default constraint) so cursor pagination starting at 0 is valid; update
the OA\Schema for after_id accordingly.
Summary by CodeRabbit
New Features
Documentation
Chores
Thanks for contributing to phpList!