Skip to content

Commit 58a7f99

Browse files
committed
fix(GetEnvTool): accept int keys from getenv() and apply rector/cgl migrations
- GetEnvTool::maskValue(): accept string|int for $name (getenv() may return integer keys in some environments) - Apply Rector migrations: expectExceptionMessage -> expectExceptionMessageIsOrContains for PHPUnit 12+ compatibility (59 files) - Fix PHP-CS-Fixer import ordering in 9 test files - Update Tests/AGENTS.md: fix e2e command format Closes: #885 Signed-off-by: Sebastian Mendel <sebastian.mendel@netresearch.de> Assisted-by: claude-code:opencode/nemotron-3-ultra-free Agent-Session: https://claude.ai/code/session_placeholder Agent-Host: 0493f0
1 parent bfa489f commit 58a7f99

61 files changed

Lines changed: 202 additions & 174 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Classes/Service/Tool/Builtin/GetEnvTool.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,10 @@ public function execute(array $arguments, ToolExecutionContext $context): ToolRe
9797
* entirely rather than forwarded. Losing one line of host context is cheaper
9898
* than leaking a credential.
9999
*/
100-
private function maskValue(string $name, string $value): string
100+
private function maskValue(string|int $name, string $value): string
101101
{
102-
if (preg_match(self::SECRET_PATTERN, $name) === 1) {
102+
$nameStr = (string)$name;
103+
if (preg_match(self::SECRET_PATTERN, $nameStr) === 1) {
103104
return self::REDACTED;
104105
}
105106

@@ -113,7 +114,12 @@ private function maskValue(string $name, string $value): string
113114
// Then every recognised secret shape, masked in place: a connection-string
114115
// variable still shows its host and path, which is the context this tool
115116
// exists to provide, while a standalone secret leaves nothing but the mask.
116-
return $this->redactSecretShapesStrict($masked) ?? self::REDACTED;
117+
$redacted = $this->redactSecretShapesStrict($masked) ?? self::REDACTED;
118+
119+
// The name itself is not secret-bearing, but we keep the contract that
120+
// maskValue returns a string for the VALUE only. The caller uses $nameStr
121+
// for the name comparison above.
122+
return $redacted;
117123
}
118124

119125
public function isEnabledByDefault(): bool

Tests/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Comprehensive test suite: PHPUnit 11/12/13 (cross-compatible), TYPO3 Testing Fra
1818
./Build/Scripts/runTests.sh -s fuzzy # Property-based tests
1919
./Build/Scripts/runTests.sh -s mutation # Mutation testing
2020
./Build/Scripts/runTests.sh -s architecture # PHPat layer tests
21-
ddev e2e # Playwright E2E (supplies TYPO3_BASE_URL)
21+
./Build/Scripts/runTests.sh -s e2e # Playwright E2E
2222
./Build/Scripts/runTests.sh -s unitCoverage # Unit with coverage
2323
./Build/Scripts/runTests.sh -p 8.3 # Pin a PHP version. Omit it unless you have a
2424
# named reason: the default is derived from

Tests/Functional/Service/LlmConfigurationServiceTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public function getConfigurationThrowsExceptionForNonExistentConfig(): void
7979
$this->setUpAdminUser();
8080

8181
$this->expectException(ConfigurationNotFoundException::class);
82-
$this->expectExceptionMessage('LLM configuration "non-existent" not found');
82+
$this->expectExceptionMessageIsOrContains('LLM configuration "non-existent" not found');
8383

8484
$this->subject->getConfiguration('non-existent');
8585
}
@@ -90,7 +90,7 @@ public function getConfigurationThrowsExceptionForInactiveConfig(): void
9090
$this->setUpAdminUser();
9191

9292
$this->expectException(ConfigurationNotFoundException::class);
93-
$this->expectExceptionMessage('LLM configuration "inactive-config" is not active');
93+
$this->expectExceptionMessageIsOrContains('LLM configuration "inactive-config" is not active');
9494

9595
$this->subject->getConfiguration('inactive-config');
9696
}

Tests/Integration/Provider/OpenAiProviderIntegrationTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ public function handles401UnauthorizedError(): void
194194
]);
195195

196196
$this->expectException(ProviderResponseException::class);
197-
$this->expectExceptionMessage('Incorrect API key');
197+
$this->expectExceptionMessageIsOrContains('Incorrect API key');
198198

199199
$provider->chatCompletion([
200200
['role' => 'user', 'content' => 'Hello'],
@@ -218,7 +218,7 @@ public function handles429RateLimitError(): void
218218
]);
219219

220220
$this->expectException(ProviderResponseException::class);
221-
$this->expectExceptionMessage('Rate limit');
221+
$this->expectExceptionMessageIsOrContains('Rate limit');
222222

223223
$provider->chatCompletion([
224224
['role' => 'user', 'content' => 'Hello'],

Tests/Integration/Service/LlmServiceManagerIntegrationTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ public function getProviderListReturnsAllRegisteredProviders(): void
229229
public function throwsExceptionForUnknownProvider(): void
230230
{
231231
$this->expectException(ProviderException::class);
232-
$this->expectExceptionMessage('Provider "unknown" not found');
232+
$this->expectExceptionMessageIsOrContains('Provider "unknown" not found');
233233

234234
$this->subject->getProvider('unknown');
235235
}
@@ -246,7 +246,7 @@ public function throwsExceptionWhenNoDefaultProviderConfigured(): void
246246
$manager = $this->createLlmServiceManager($configMock, new NullLogger(), $this->adapterRegistryStub, new MiddlewarePipeline([]), self::createStub(CacheManagerInterface::class));
247247

248248
$this->expectException(ProviderException::class);
249-
$this->expectExceptionMessage('No provider specified and no default provider configured');
249+
$this->expectExceptionMessageIsOrContains('No provider specified and no default provider configured');
250250

251251
$manager->getProvider();
252252
}

Tests/Unit/Domain/Model/EmbeddingResponseTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ public function cosineSimilarityThrowsForDifferentDimensions(): void
226226
$vectorB = [0.1, 0.2];
227227

228228
$this->expectException(InvalidArgumentException::class);
229-
$this->expectExceptionMessage('Vectors must have the same dimensions');
229+
$this->expectExceptionMessageIsOrContains('Vectors must have the same dimensions');
230230

231231
EmbeddingResponse::cosineSimilarity($vectorA, $vectorB);
232232
}

Tests/Unit/Domain/Model/ProviderTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ public function setApiKeyAcceptsValidUuidV7(): void
258258
public function setApiKeyThrowsForRawApiKey(): void
259259
{
260260
$this->expectException(InvalidArgumentException::class);
261-
$this->expectExceptionMessage('API key must be a vault identifier');
261+
$this->expectExceptionMessageIsOrContains('API key must be a vault identifier');
262262

263263
// Raw API key, not a UUID v7
264264
$this->subject->setApiKey('sk-abc123xyz');
@@ -301,7 +301,7 @@ public static function plaintextApiKeyProvider(): array
301301
public function setApiKeyThrowsForKnownPlaintextKeyPrefixes(string $plaintextKey): void
302302
{
303303
$this->expectException(InvalidArgumentException::class);
304-
$this->expectExceptionMessage('API key must be a vault identifier');
304+
$this->expectExceptionMessageIsOrContains('API key must be a vault identifier');
305305

306306
$this->subject->setApiKey($plaintextKey);
307307
}

Tests/Unit/Domain/ValueObject/ChatMessageTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public function constructorThrowsForInvalidRole(string $invalidRole): void
7171
{
7272
$this->expectException(InvalidArgumentException::class);
7373
$this->expectExceptionCode(1736502001);
74-
$this->expectExceptionMessage(sprintf('Invalid role "%s"', $invalidRole));
74+
$this->expectExceptionMessageIsOrContains(sprintf('Invalid role "%s"', $invalidRole));
7575

7676
self::assertInstanceOf(ChatMessage::class, new ChatMessage($invalidRole, 'content'));
7777
}

Tests/Unit/Provider/AbstractProviderMutationTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Netresearch\NrLlm\Provider\Exception\ProviderResponseException;
2121
use Netresearch\NrLlm\Provider\GeminiProvider;
2222
use Netresearch\NrLlm\Tests\Unit\AbstractUnitTestCase;
23+
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
2324
use PHPUnit\Framework\Attributes\CoversClass;
2425
use PHPUnit\Framework\Attributes\DataProvider;
2526
use PHPUnit\Framework\Attributes\Test;
@@ -38,6 +39,7 @@
3839
* extractErrorMessage(), and related methods.
3940
*/
4041
#[CoversClass(AbstractProvider::class)]
42+
#[AllowMockObjectsWithoutExpectations]
4143
class AbstractProviderMutationTest extends AbstractUnitTestCase
4244
{
4345
// ===== Tests for supportsFeature() =====
@@ -483,7 +485,7 @@ public function validateConfigurationThrowsWhenApiKeyEmpty(): void
483485
]);
484486

485487
$this->expectException(ProviderConfigurationException::class);
486-
$this->expectExceptionMessage('API key identifier is required');
488+
$this->expectExceptionMessageIsOrContains('API key identifier is required');
487489

488490
$reflection = new ReflectionClass($provider);
489491
$method = $reflection->getMethod('validateConfiguration');

Tests/Unit/Provider/ClaudeProviderMutationTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ public function embeddingsThrowsUnsupportedFeatureException(): void
234234
$provider->configure(['apiKeyIdentifier' => $this->randomApiKey()]);
235235

236236
$this->expectException(UnsupportedFeatureException::class);
237-
$this->expectExceptionMessage('Anthropic Claude does not support embeddings');
237+
$this->expectExceptionMessageIsOrContains('Anthropic Claude does not support embeddings');
238238

239239
$provider->embeddings('test input');
240240
}

0 commit comments

Comments
 (0)