Skip to content

chore(release): prepare 1.2.2#3

Merged
soulevilx merged 2 commits intodevelopfrom
release/1.2.2
Apr 5, 2026
Merged

chore(release): prepare 1.2.2#3
soulevilx merged 2 commits intodevelopfrom
release/1.2.2

Conversation

@soulevilx
Copy link
Copy Markdown
Contributor

@soulevilx soulevilx commented Apr 5, 2026

Summary by CodeRabbit

  • New Features

    • Added AI workflow playbooks, validation rules, and prompt templates for change validation and release readiness.
  • Documentation

    • Added docs verification and quality-check guidance; updated development, testing, and contributing docs; fixed README license badge.
  • CI/CD

    • Split and expanded CI jobs (security, lint matrix, dependency review, tests, coverage upload); added concurrency and standardized PHP version; refined release workflow with validate/publish steps.
  • Chores

    • Reworked composer scripts, commit-hook config, and static-analysis/tooling configs.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 5, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 926420b4-62c0-4a94-9927-e4c7c1d24564

📥 Commits

Reviewing files that changed from the base of the PR and between d78ac13 and 27a48cb.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml

📝 Walkthrough

Walkthrough

This PR adds AI workflow/playbook and prompt documents, new Cursor rules, CI/CD workflow restructures, stronger static-analysis/tooling configs, Composer scripts and hook changes, several source refactors (client, middleware, caching, logging), and documentation updates for release and developer workflows.

Changes

Cohort / File(s) Summary
AI Workflow Playbooks
.claude/commands/README.md, .claude/commands/quality-check.md, .claude/commands/docs-verify.md, .claude/commands/release-readiness.md
Added Claude command playbooks and replaced placeholder README with playbook-oriented guidance and an Available Commands list.
Cursor Rules
.cursor/rules/README.md, .cursor/rules/api-stability.mdc, .cursor/rules/docs-structure.mdc, .cursor/rules/validation-gates.mdc
Introduced Cursor rule files and updated README to list and link rules enforcing API stability, docs structure, and validation gates.
AI Prompt Templates
antigravity/prompts/..., jetbrains/prompts/...
Added Antigravity and JetBrains prompt templates (quality-check.md, docs-verify.md, release-readiness.md) and README listings for both sets.
Docs & Guides
README.md, CONTRIBUTING.md, CHANGELOG.md, docs/04-development/...
Updated badges, QA/CI guidance, Conventional Commits guidance, changelog (v1.2.2), and development docs to reference new playbooks, Cursor rules, coverage gates, and CaptainHook behavior.
CI/CD Workflows
.github/workflows/ci.yml, .github/workflows/release.yml, .github/workflows/pr-labeler.yml, .github/workflows/scorecard.yml, .github/workflows/semantic-pr.yml
Added workflow-level concurrency, split lint/security/dependency jobs, added validate/publish steps for release, updated triggers/permissions, enforced PR-title subject pattern, and bumped action versions.
Labeler & Hooking
.github/labeler.yml, captainhook.json
Reorganized label categories/globs; added CaptainHook schema and configured commit-msg, pre-commit, pre-push sequences including gitleaks and tool-specific lint steps.
Tooling Config
composer.json, phpstan.neon, phpcs.xml, phpmd.xml, phpunit.xml, .php-cs-fixer.dist.php
Bumped package to 1.2.2, reworked composer scripts to lint:*/test:*, enabled captainhook plugin, hardened static-analysis configs (phpstan max + ignores), adjusted PHPCS/PHPMD rules, PHPUnit and CS-Fixer changes.
Source Refactors (Client & Middleware)
src/Client/ClientBuilder.php, src/Client/HttpClient.php, src/Middleware/..., src/Middleware/MiddlewarePipeline.php
Extracted helpers, changed ClientBuilder return type to HttpClientInterface&AsyncHttpClientInterface, refactored async/batch promise handling, added option/key normalization, and added PHPDoc callable signatures.
Caching, Logging, Models, Response
src/Cache/FilesystemCache.php, src/Cache/MemoryCache.php, src/Logging/MongoDbLogger.php, src/Models/Mongo/ClientRequestLog.php, src/Response/ResponseWrapper.php
Added cache payload/expires helpers and safer expiry handling, updated docblocks/generics, changed logger default writer wiring and PHPDoc, adjusted response header/DTO validation.
PHPStorm/Benchmark/Tests
tests/Benchmark/CoreBench.php, tests/Feature/AsyncTest.php
Added explicit types/return types to benchmarks; swapped PHPDoc-only asserts for runtime PHPUnit assertions in async tests.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer
    participant Builder as ClientBuilder
    participant Client as HttpClient
    participant Pipeline as MiddlewarePipeline
    participant Adapter as HTTP Adapter
    participant Logger as MongoDbLogger

    Dev->>Builder: build() -> HttpClientInterface & AsyncHttpClientInterface
    Builder->>Client: returns configured client (handler stack, headers)
    Client->>Pipeline: request/async request with options
    Pipeline->>Adapter: normalized options, middleware chain
    Adapter-->>Client: Response / Promise
    Client->>Logger: log request/response (via LoggingMiddleware helpers)
    Logger-->>Dev: persisted log entry (optional)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

Poem

🐰 I hopped through playbooks, rules, and streams,
Linted code and chased coverage dreams,
Middleware routed each request with care,
Logs tucked in Mongo, promises in the air—
A rabbit cheers: the repo’s neat and fair! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'chore(release): prepare 1.2.2' directly and accurately describes the main objective: preparing version 1.2.2 for release. This is clearly evident from the extensive changeset that includes updating the package version, refactoring CI/CD workflows, adding new command playbooks and rule files, and updating documentation to align with the release preparation process.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/1.2.2

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Release 1.2.2: Refactor internals, enhance CI/CD, and implement AI workflow scaffolding

✨ Enhancement 📝 Documentation

Grey Divider

Walkthroughs

Description
• Refactored cache payload reading and expiration parsing into separate methods for improved
  maintainability
• Restructured ClientBuilder.build() to extract adapter and handler-stack creation into dedicated
  private methods
• Simplified batch processing in HttpClient by extracting promise resolution and wrapping logic
• Enhanced PHP-CS-Fixer configuration to focus on PHPDoc cleanup without overlapping with Pint
• Expanded CI/CD workflows with security checks, lint matrix, dependency review, and coverage
  uploads
• Added comprehensive AI workflow scaffolding: Claude commands, Cursor rules, and
  Antigravity/JetBrains prompts
• Updated documentation, coding standards, and linting guides to reflect new tooling and validation
  contract
• Bumped version to 1.2.2 and updated CHANGELOG with release notes
Diagram
flowchart LR
  A["Source Code Refactoring"] -->|extract methods| B["Improved Maintainability"]
  C["PHP-CS-Fixer Config"] -->|focus PHPDoc| D["Non-overlapping Tools"]
  E["CI/CD Expansion"] -->|security, lint matrix, coverage| F["Enhanced Validation"]
  G["AI Scaffolding"] -->|commands, rules, prompts| H["Documented Workflows"]
  I["Documentation Updates"] -->|standards, guides| J["Aligned Guidance"]
  B --> K["Version 1.2.2"]
  D --> K
  F --> K
  H --> K
  J --> K
Loading

Grey Divider

File Changes

1. .php-cs-fixer.dist.php ⚙️ Configuration changes +22/-9

Refocus PHP-CS-Fixer on PHPDoc cleanup rules

.php-cs-fixer.dist.php


2. src/Cache/FilesystemCache.php ✨ Enhancement +47/-25

Extract cache payload and expiration parsing methods

src/Cache/FilesystemCache.php


3. src/Cache/MemoryCache.php 📝 Documentation +1/-2

Update PHPDoc for setMultiple parameter type

src/Cache/MemoryCache.php


View more (48)
4. src/Client/ClientBuilder.php ✨ Enhancement +68/-46

Extract adapter and handler-stack creation logic

src/Client/ClientBuilder.php


5. src/Client/HttpClient.php ✨ Enhancement +71/-33

Extract batch promise resolution and wrapping methods

src/Client/HttpClient.php


6. src/Contracts/AsyncHttpClientInterface.php 📝 Documentation +2/-2

Improve batch method PHPDoc type hints

src/Contracts/AsyncHttpClientInterface.php


7. src/Logging/MongoDbLogger.php ✨ Enhancement +14/-15

Use first-class callable and update PHPDoc types

src/Logging/MongoDbLogger.php


8. src/Middleware/InterceptorMiddleware.php 📝 Documentation +6/-0

Add PHPDoc for callback parameters

src/Middleware/InterceptorMiddleware.php


9. src/Middleware/LoggingMiddleware.php ✨ Enhancement +45/-35

Extract body logging and transfer context methods

src/Middleware/LoggingMiddleware.php


10. src/Middleware/MiddlewarePipeline.php ✨ Enhancement +24/-4

Add options normalization and improve type hints

src/Middleware/MiddlewarePipeline.php


11. src/Models/Mongo/ClientRequestLog.php 📝 Documentation +1/-4

Update PHPDoc for connection property

src/Models/Mongo/ClientRequestLog.php


12. src/Response/ResponseWrapper.php ✨ Enhancement +15/-2

Improve header method and add DTO template type hints

src/Response/ResponseWrapper.php


13. tests/Benchmark/CoreBench.php 🧪 Tests +10/-6

Add type hints and improve handler signature

tests/Benchmark/CoreBench.php


14. tests/Feature/AsyncTest.php 🧪 Tests +8/-8

Replace type casts with instanceof assertions

tests/Feature/AsyncTest.php


15. .claude/commands/README.md 📝 Documentation +9/-11

Document Claude command playbooks and usage

.claude/commands/README.md


16. .claude/commands/docs-verify.md 📝 Documentation +39/-0

Add markdown link verification workflow

.claude/commands/docs-verify.md


17. .claude/commands/quality-check.md 📝 Documentation +27/-0

Add quality validation workflow

.claude/commands/quality-check.md


18. .claude/commands/release-readiness.md 📝 Documentation +26/-0

Add release preflight checks workflow

.claude/commands/release-readiness.md


19. .cursor/rules/README.md 📝 Documentation +7/-11

Document Cursor rule files and maintenance

.cursor/rules/README.md


20. .cursor/rules/api-stability.mdc 📝 Documentation +11/-0

Add API stability preservation rule

.cursor/rules/api-stability.mdc


21. .cursor/rules/docs-structure.mdc 📝 Documentation +18/-0

Add documentation structure alignment rule

.cursor/rules/docs-structure.mdc


22. .cursor/rules/validation-gates.mdc 📝 Documentation +19/-0

Add validation gates requirement rule

.cursor/rules/validation-gates.mdc


23. .github/labeler.yml ⚙️ Configuration changes +19/-16

Reorganize PR labels to DTO-style categories

.github/labeler.yml


24. .github/workflows/ci.yml Ci/cd +126/-21

Expand CI with security, lint matrix, coverage uploads

.github/workflows/ci.yml


25. .github/workflows/pr-labeler.yml Ci/cd +14/-5

Add concurrency and improve workflow structure

.github/workflows/pr-labeler.yml


26. .github/workflows/release.yml Ci/cd +65/-6

Add validate job and Packagist publish step

.github/workflows/release.yml


27. .github/workflows/scorecard.yml Ci/cd +19/-15

Update to OpenSSF Scorecard v2.4.3

.github/workflows/scorecard.yml


28. .github/workflows/semantic-pr.yml Ci/cd +21/-4

Add uppercase subject enforcement and concurrency

.github/workflows/semantic-pr.yml


29. CHANGELOG.md 📝 Documentation +13/-0

Add 1.2.2 release notes with AI scaffolding

CHANGELOG.md


30. CONTRIBUTING.md 📝 Documentation +12/-7

Update quality checks and add hook documentation

CONTRIBUTING.md


31. README.md 📝 Documentation +29/-12

Update badges, quality section, and AI workflow

README.md


32. antigravity/prompts/README.md 📝 Documentation +8/-0

Document Antigravity prompt templates

antigravity/prompts/README.md


33. antigravity/prompts/docs-verify.md 📝 Documentation +17/-0

Add Antigravity docs verification prompt

antigravity/prompts/docs-verify.md


34. antigravity/prompts/quality-check.md 📝 Documentation +18/-0

Add Antigravity quality check prompt

antigravity/prompts/quality-check.md


35. antigravity/prompts/release-readiness.md 📝 Documentation +18/-0

Add Antigravity release readiness prompt

antigravity/prompts/release-readiness.md


36. captainhook.json ⚙️ Configuration changes +33/-2

Add commit-msg validation and expand pre-commit hooks

captainhook.json


37. composer.json Dependencies +56/-22

Bump version to 1.2.2 and refactor scripts

composer.json


38. docs/04-development/ai-skills.md 📝 Documentation +15/-4

Document AI guidance locations and update policy

docs/04-development/ai-skills.md


39. docs/04-development/ci-cd.md 📝 Documentation +18/-3

Document expanded CI flow and auxiliary automation

docs/04-development/ci-cd.md


40. docs/04-development/coding-standards.md 📝 Documentation +16/-1

Add tool responsibilities and main commands

docs/04-development/coding-standards.md


41. docs/04-development/linting-standards.md 📝 Documentation +20/-6

Expand command map and document tool order

docs/04-development/linting-standards.md


42. docs/04-development/setup.md 📝 Documentation +7/-2

Update setup instructions and hook documentation

docs/04-development/setup.md


43. docs/04-development/testing.md 📝 Documentation +9/-0

Add coverage gate and source documentation

docs/04-development/testing.md


44. jetbrains/prompts/README.md 📝 Documentation +8/-0

Document JetBrains prompt templates

jetbrains/prompts/README.md


45. jetbrains/prompts/docs-verify.md 📝 Documentation +17/-0

Add JetBrains docs verification prompt

jetbrains/prompts/docs-verify.md


46. jetbrains/prompts/quality-check.md 📝 Documentation +18/-0

Add JetBrains quality check prompt

jetbrains/prompts/quality-check.md


47. jetbrains/prompts/release-readiness.md 📝 Documentation +18/-0

Add JetBrains release readiness prompt

jetbrains/prompts/release-readiness.md


48. phpcs.xml ⚙️ Configuration changes +18/-4

Refine PHPCS rules to avoid Pint overlap

phpcs.xml


49. phpmd.xml ⚙️ Configuration changes +70/-18

Expand PHPMD ruleset with detailed thresholds

phpmd.xml


50. phpstan.neon ⚙️ Configuration changes +167/-4

Upgrade to max level with strict rules and PHPUnit

phpstan.neon


51. phpunit.xml ⚙️ Configuration changes +38/-8

Enhance PHPUnit configuration with strict settings

phpunit.xml


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Apr 5, 2026

Code Review by Qodo

🐞 Bugs (4) 📘 Rule violations (1) 📎 Requirement gaps (0) 🎨 UX Issues (0)

Grey Divider


Action required

1. Duplicate middleware on rebuild 🐞 Bug ≡ Correctness
Description
ClientBuilder::build() now reuses the same user-supplied HandlerStack object across multiple build()
calls and re-runs MiddlewarePipeline::buildHandlerStack(), which pushes middleware onto that same
stack again. This can lead to duplicated logging/retry/cache/interceptor layers (e.g., double
logging, double retries) when a builder instance is reused.
Code

src/Client/ClientBuilder.php[R254-286]

+    private function createDefaultAdapter(): TransportAdapterInterface
+    {
+        $guzzleOptions = $this->options;
+        $guzzleOptions['handler'] = $this->createHandlerStack($guzzleOptions);
+        $guzzleOptions['headers'] = $this->normalizeHeaders($guzzleOptions['headers'] ?? []);
+
+        $guzzle = new GuzzleClient($guzzleOptions);
+
+        return new GuzzleHttpClientAdapter($guzzle);
+    }
+
+    /**
+     * @param array<string, mixed> $guzzleOptions
+     */
+    private function createHandlerStack(array &$guzzleOptions): HandlerStack
+    {
+        $userHandler = $guzzleOptions['handler'] ?? null;
+        unset($guzzleOptions['handler']);
+
+        if ($userHandler instanceof HandlerStack) {
+            $handlerStack = $userHandler;
+        } elseif (is_callable($userHandler)) {
+            $handlerStack = HandlerStack::create($userHandler);
+        } else {
+            $handlerStack = HandlerStack::create();
+        }
+
+        if ($this->pipeline !== null) {
+            return $this->pipeline->buildHandlerStack($handlerStack);
+        }
+
+        return $handlerStack;
+    }
Evidence
ClientBuilder copies $this->options but keeps the same HandlerStack object reference inside it;
createHandlerStack() picks up that HandlerStack and passes it to
MiddlewarePipeline::buildHandlerStack(), which mutates the stack by pushing middleware. Because
$this->options is never cleared of 'handler', subsequent build() calls will push the same middleware
again onto the same HandlerStack instance.

src/Client/ClientBuilder.php[119-124]
src/Client/ClientBuilder.php[254-286]
src/Middleware/MiddlewarePipeline.php[78-130]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`ClientBuilder::build()` can be called multiple times on the same builder. If the user provided a `GuzzleHttp\HandlerStack` via `withOption('handler', $stack)`, the builder currently reuses *the same stack object* and re-applies the middleware pipeline on every build, pushing duplicate middleware entries.

### Issue Context
- `createHandlerStack()` unsets `handler` from the *local* `$guzzleOptions` array only; the original `$this->options['handler']` remains set.
- When the handler is a `HandlerStack`, it’s an object reference, so repeated builds mutate the same instance.

### Fix Focus Areas
- src/Client/ClientBuilder.php[254-286]
- src/Middleware/MiddlewarePipeline.php[78-130]

### Implementation notes
Choose one:
1) **Clone** a user-supplied `HandlerStack` before passing it into `MiddlewarePipeline::buildHandlerStack()` (preferred, avoids mutating caller-owned stack and prevents duplication).
2) **Consume** the builder option (unset `$this->options['handler']`) after the first build, restoring prior “one-time consumption” behavior.
3) Add an internal guard to avoid pushing middleware that already exists on the stack (harder / more coupled to Guzzle internals).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. ClientBuilder::build() return type narrowed 📘 Rule violation ⚙ Maintainability
Description
ClientBuilder::build() now declares an intersection return type
(HttpClientInterface&AsyncHttpClientInterface) instead of the previous HttpClientInterface,
which changes a public method signature. This can be a backward-incompatible API change for
downstream consumers relying on the original signature (e.g., reflection-based checks or strict
callable type expectations).
Code

src/Client/ClientBuilder.php[237]

+    public function build(): HttpClientInterface&AsyncHttpClientInterface
Evidence
PR Compliance ID 3 forbids backward-incompatible changes to public method signatures. The PR changes
the declared return type of the public ClientBuilder::build() method to an intersection type,
which is a signature modification in the public API surface under src/.

AGENTS.md
src/Client/ClientBuilder.php[237-237]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ClientBuilder::build()` changed its declared return type to `HttpClientInterface&AsyncHttpClientInterface`, modifying the public API signature.

## Issue Context
Even if the returned object still implements `HttpClientInterface`, changing a public method signature can be considered a breaking change for downstream consumers.

## Fix Focus Areas
- src/Client/ClientBuilder.php[237-237]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Broken labeler glob patterns 🐞 Bug ☼ Reliability
Description
The new .github/labeler.yml uses patterns like **.md, **.xml, and **.neon, which are likely
not valid recursive globs and can cause label application to silently miss matching files. As a
result, PRs touching documentation/config files may not receive the intended labels.
Code

.github/labeler.yml[R5-29]

+'documentation':
  - changed-files:
      - any-glob-to-any-file:
-          - '.github/workflows/**'
+          - '**.md'
+          - 'docs/**/*'

-quality:
+'dependencies':
  - changed-files:
      - any-glob-to-any-file:
-          - 'phpstan.neon'
-          - 'phpcs.xml'
-          - 'phpmd.xml'
-          - 'pint.json'
-          - '.php-cs-fixer.dist.php'
          - 'composer.json'
+          - 'composer.lock'

-source:
+'ci/cd':
  - changed-files:
      - any-glob-to-any-file:
-          - 'src/**'
+          - '.github/**/*'
+          - 'captainhook.json'

-tests:
+'configuration':
  - changed-files:
      - any-glob-to-any-file:
-          - 'tests/**'
+          - '**.xml'
+          - '**.neon'
+          - '.php-cs-fixer.dist.php'
+          - '.editorconfig'
Evidence
The label rules for documentation and configuration rely on **.md / **.xml / **.neon (instead
of typical recursive forms like **/*.md), so these rules may fail to match most paths, especially
in nested directories.

.github/labeler.yml[5-29]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`.github/labeler.yml` uses glob patterns (`**.md`, `**.xml`, `**.neon`) that likely don't match the intended file sets. This can break auto-labeling for docs/config changes.

### Issue Context
The labeler config intends to apply labels for:
- any markdown files
- any xml / neon config files

### Fix Focus Areas
- .github/labeler.yml[5-29]

### Implementation notes
Replace ambiguous patterns with explicit recursive patterns, e.g.:
- `**/*.md` (or `*.md` + `docs/**/*.md`)
- `**/*.xml`
- `**/*.neon`
Then keep existing specific directories (like `docs/**/*`) only if needed.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Scorecard branch mismatch 🐞 Bug ✧ Quality
Description
scorecard.yml only runs on pushes to master, while ci.yml runs on main and develop, so
Scorecard may never run on the repo’s active development branches. This reduces security
observability because SARIF results won’t be produced for normal pushes.
Code

.github/workflows/scorecard.yml[R3-8]

on:
-  branch_protection_rule:
-  schedule:
-    - cron: '30 1 * * 1'
  push:
-    branches: [main]
+    branches: [master]
+  schedule:
+    - cron: '0 0 * * 1'
+  workflow_dispatch:
Evidence
The Scorecard workflow is filtered to branches: [master], but CI is filtered to `branches: [main,
develop]`, demonstrating an inconsistent branch model inside the repository workflow configuration.

.github/workflows/scorecard.yml[3-8]
.github/workflows/ci.yml[3-8]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
OpenSSF Scorecard currently triggers on pushes to `master`, but the repository CI triggers on `main` and `develop`. If `master` isn't the active branch, Scorecard won't run on normal pushes.

### Issue Context
CI workflow (`ci.yml`) indicates the active branches are `main` and `develop`.

### Fix Focus Areas
- .github/workflows/scorecard.yml[3-8]
- .github/workflows/ci.yml[3-8]

### Implementation notes
Update `scorecard.yml` to run on the same branches as CI (e.g., `[main, develop]`) or on the repository default branch consistently across workflows.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
5. Labeler reads PR config 🐞 Bug ⛨ Security
Description
pr-labeler.yml now runs on pull_request and checks out PR code before running actions/labeler,
so .github/labeler.yml changes in the PR can influence labeling. This allows a PR author to change
label rules applied to their own PR, which can undermine any processes that rely on labels.
Code

.github/workflows/pr-labeler.yml[R3-27]

on:
-  pull_request_target:
+  pull_request:
    types: [opened, synchronize, reopened]

+concurrency:
+  group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
+  cancel-in-progress: true
+
+permissions:
+  contents: read
+  pull-requests: write
+
jobs:
  label:
+    name: Auto-label PR
    runs-on: ubuntu-latest
-    permissions:
-      pull-requests: write
-      contents: read

    steps:
-      - name: Label pull requests
+      - name: Checkout code
+        uses: actions/checkout@v6.0.2
+
+      - name: Label PR
        uses: actions/labeler@v5
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
Evidence
The workflow triggers on pull_request and explicitly checks out code, then runs
actions/labeler@v5 (which by default uses .github/labeler.yml). This combination means the
labeler configuration used at runtime can come from the PR contents rather than the base branch.

.github/workflows/pr-labeler.yml[3-27]
.github/labeler.yml[1-33]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The PR labeler workflow checks out PR code and runs the labeler, so a PR can modify `.github/labeler.yml` and affect how it gets labeled.

### Issue Context
Label-based automation is typically expected to be controlled by the base branch configuration, not by the PR author.

### Fix Focus Areas
- .github/workflows/pr-labeler.yml[3-27]

### Implementation notes
Safer options:
1) Switch back to `pull_request_target` and avoid checking out PR code (or check out the base ref) so the config comes from the trusted base branch.
2) If staying on `pull_request`, explicitly check out the base SHA/ref for reading `.github/labeler.yml` (or configure the labeler to load config from the base ref if supported).
3) Document that label rules are PR-controlled (only if you truly want that behavior).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +254 to +286
private function createDefaultAdapter(): TransportAdapterInterface
{
$guzzleOptions = $this->options;
$guzzleOptions['handler'] = $this->createHandlerStack($guzzleOptions);
$guzzleOptions['headers'] = $this->normalizeHeaders($guzzleOptions['headers'] ?? []);

$guzzle = new GuzzleClient($guzzleOptions);

return new GuzzleHttpClientAdapter($guzzle);
}

/**
* @param array<string, mixed> $guzzleOptions
*/
private function createHandlerStack(array &$guzzleOptions): HandlerStack
{
$userHandler = $guzzleOptions['handler'] ?? null;
unset($guzzleOptions['handler']);

if ($userHandler instanceof HandlerStack) {
$handlerStack = $userHandler;
} elseif (is_callable($userHandler)) {
$handlerStack = HandlerStack::create($userHandler);
} else {
$handlerStack = HandlerStack::create();
}

if ($this->pipeline !== null) {
return $this->pipeline->buildHandlerStack($handlerStack);
}

return $handlerStack;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Duplicate middleware on rebuild 🐞 Bug ≡ Correctness

ClientBuilder::build() now reuses the same user-supplied HandlerStack object across multiple build()
calls and re-runs MiddlewarePipeline::buildHandlerStack(), which pushes middleware onto that same
stack again. This can lead to duplicated logging/retry/cache/interceptor layers (e.g., double
logging, double retries) when a builder instance is reused.
Agent Prompt
### Issue description
`ClientBuilder::build()` can be called multiple times on the same builder. If the user provided a `GuzzleHttp\HandlerStack` via `withOption('handler', $stack)`, the builder currently reuses *the same stack object* and re-applies the middleware pipeline on every build, pushing duplicate middleware entries.

### Issue Context
- `createHandlerStack()` unsets `handler` from the *local* `$guzzleOptions` array only; the original `$this->options['handler']` remains set.
- When the handler is a `HandlerStack`, it’s an object reference, so repeated builds mutate the same instance.

### Fix Focus Areas
- src/Client/ClientBuilder.php[254-286]
- src/Middleware/MiddlewarePipeline.php[78-130]

### Implementation notes
Choose one:
1) **Clone** a user-supplied `HandlerStack` before passing it into `MiddlewarePipeline::buildHandlerStack()` (preferred, avoids mutating caller-owned stack and prevents duplication).
2) **Consume** the builder option (unset `$this->options['handler']`) after the first build, restoring prior “one-time consumption” behavior.
3) Add an internal guard to avoid pushing middleware that already exists on the stack (harder / more coupled to Guzzle internals).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@codecov-commenter
Copy link
Copy Markdown

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

Thanks for integrating Codecov - We've got you covered ☂️

@soulevilx soulevilx merged commit 07ff2c9 into develop Apr 5, 2026
24 of 25 checks passed
@soulevilx soulevilx deleted the release/1.2.2 branch April 5, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants