diff --git a/AGENTS.md b/AGENTS.md index 7d30cc1..c05f476 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,8 +2,22 @@ ## Code and tooling -- All code must remain compatible with PHP 7.4, and PHPStan and PHP-CS-Fixer - must be run against PHP 7.4. +- All code must remain compatible with PHP 7.4. Run PHPStan and PHP-CS-Fixer + only under a PHP 7.4.x runtime; never run either tool under any other PHP + major.minor version. +- Use fully qualified `#[\SensitiveParameter]` on concrete executable + parameters when their established role normally carries a secret, + credential-bearing aggregate, or confidential Guzzle-owned container, and + the active frame can throw or invoke throwing code. +- Repeat the attribute on every qualifying owned caller, callee, concrete trait + method, and closure parameter. Do not add it to interfaces, abstract-only + declarations, pure/no-realistic-throw helpers, assignment-only sites, + arbitrary generic payloads, or completed non-recoverable derivatives. +- For PHP 7.4 compatibility, put `#[\SensitiveParameter]` on its own line and + the parameter on the following line, expand the complete parameter list, and + never add a comma after the final parameter. Native trace redaction starts on + PHP 8.2 and does not redact logs, messages, properties, wire traffic, captured + variables, return values, or the separate backtrace `$this`/`object`. - Always pass an explicit character list to `trim()`, `ltrim()`, and `rtrim()`; never rely on the default characters. - Handle `preg_*` engine failures: when the result is used as data, test for diff --git a/CHANGELOG.md b/CHANGELOG.md index 96a86a1..e20471b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - Added a `guzzle-server/stall-brief` endpoint that stalls mid-body for 1.5s, then completes - Added `Server::enqueueRawBytes()` to queue verbatim-byte responses that bypass Node's HTTP handling - Inline Digest auth so secure endpoints avoid optional `http-auth` and no-qop is deterministic +- Hide queued and received raw HTTP records in stack traces on PHP 8.2+ ## 0.7.0 - 2026-07-16 diff --git a/UPGRADING.md b/UPGRADING.md index 0ff32b7..d95fb28 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -70,3 +70,14 @@ if (!is_int($validatedPort)) { Server::$port = $validatedPort; Server::$url = sprintf('http://127.0.0.1:%d/', Server::$port); ``` + +#### Sensitive Stack Trace Arguments + +Queued and received raw HTTP records are marked with +`#[\SensitiveParameter]`. PHP 8.2 and later replace those arguments in stack +traces with `SensitiveParameterValue`. PHP 7.4 through 8.1 do not redact trace +arguments. + +This does not redact the Node server log, other logs, exception messages, +object properties, wire traffic, captured variables, return values, user +callbacks, or the separate executing object in an explicit backtrace. diff --git a/composer.json b/composer.json index 24151c5..1f9546d 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,8 @@ "php": "^7.4 || ^8.0", "guzzlehttp/guzzle": "^8.0@dev", "guzzlehttp/psr7": "^3.0@dev", - "symfony/polyfill-php80": "^1.25" + "symfony/polyfill-php80": "^1.25", + "symfony/polyfill-php82": "^1.27" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", diff --git a/src/Server.php b/src/Server.php index e8d5279..2e2131a 100644 --- a/src/Server.php +++ b/src/Server.php @@ -73,8 +73,10 @@ public static function flush(): ResponseInterface * * @throws InvalidArgumentException */ - public static function enqueue($responses): void - { + public static function enqueue( + #[\SensitiveParameter] + $responses + ): void { if ($responses instanceof ResponseInterface) { $responses = [$responses]; } @@ -114,8 +116,14 @@ public static function enqueue($responses): void * * @throws \GuzzleHttp\Exception\GuzzleException */ - public static function enqueueRaw($statusCode, string $reasonPhrase, array $headers, ?string $body): void - { + public static function enqueueRaw( + $statusCode, + string $reasonPhrase, + #[\SensitiveParameter] + array $headers, + #[\SensitiveParameter] + ?string $body + ): void { $data = [ [ 'status' => (string) $statusCode, @@ -139,8 +147,10 @@ public static function enqueueRaw($statusCode, string $reasonPhrase, array $head * * @throws \GuzzleHttp\Exception\GuzzleException */ - public static function enqueueRawBytes(string $bytes): void - { + public static function enqueueRawBytes( + #[\SensitiveParameter] + string $bytes + ): void { self::getClient()->request('PUT', 'guzzle-server/responses', [ 'json' => [ [ @@ -176,7 +186,10 @@ public static function received(): array } return \array_map( - static function ($message): RequestInterface { + static function ( + #[\SensitiveParameter] + $message + ): RequestInterface { if (!\is_array($message)) { throw new \RuntimeException('Expected each received request from node.js server to be an array'); }