fix: DockerSecretsResolver - don't normalize absolute paths like /var/www/html/...
Some checks failed
Deploy Application / deploy (push) Has been cancelled

This commit is contained in:
2025-11-24 21:28:25 +01:00
parent 4eb7134853
commit 77abc65cd7
1327 changed files with 91915 additions and 9909 deletions

View File

@@ -0,0 +1,198 @@
<?php
declare(strict_types=1);
use App\Framework\DateTime\SystemClock;
use App\Framework\Http\Session\FileSessionStorage;
use App\Framework\Http\Session\FormIdGenerator;
use App\Framework\Http\Session\Session;
use App\Framework\Http\Session\SessionId;
use App\Framework\Http\Session\SessionIdGenerator;
use App\Framework\Http\Session\SessionManager;
use App\Framework\Random\SecureRandomGenerator;
use App\Framework\Security\CsrfTokenGenerator;
use App\Framework\View\Response\FormDataResponseProcessor;
use App\Framework\Http\Cookies\SessionCookieConfig;
beforeEach(function () {
$this->tempDir = sys_get_temp_dir() . '/php_sessions_test_' . uniqid();
mkdir($this->tempDir, 0700, true);
$this->clock = new SystemClock();
$this->storage = new FileSessionStorage($this->tempDir, $this->clock);
$this->sessionIdGenerator = new SessionIdGenerator(new SecureRandomGenerator());
$this->csrfTokenGenerator = new CsrfTokenGenerator(new SecureRandomGenerator());
$this->formIdGenerator = new FormIdGenerator();
$this->cookieConfig = new SessionCookieConfig(
name: 'test_session',
lifetime: 3600,
path: '/',
domain: null,
secure: false,
httpOnly: true,
sameSite: \App\Framework\Http\Cookies\SameSite::LAX
);
$this->sessionManager = new SessionManager(
generator: $this->sessionIdGenerator,
responseManipulator: Mockery::mock(\App\Framework\Http\ResponseManipulator::class),
clock: $this->clock,
csrfTokenGenerator: $this->csrfTokenGenerator,
storage: $this->storage,
cookieConfig: $this->cookieConfig
);
$this->sessionId = $this->sessionIdGenerator->generate();
$this->session = Session::fromArray($this->sessionId, $this->clock, $this->csrfTokenGenerator, []);
$this->processor = new FormDataResponseProcessor(
$this->formIdGenerator,
$this->sessionManager
);
});
afterEach(function () {
if (isset($this->tempDir) && is_dir($this->tempDir)) {
array_map('unlink', glob($this->tempDir . '/*'));
rmdir($this->tempDir);
}
});
it('processes form HTML and replaces token placeholder', function () {
$formId = $this->formIdGenerator->generateFormId('/test', 'post');
$html = <<<HTML
<!DOCTYPE html>
<html>
<head><title>Test</title></head>
<body>
<form method="post" action="/test">
<input type="hidden" name="_form_id" value="{$formId}">
<input type="hidden" name="_token" value="___TOKEN_{$formId}___">
<input type="text" name="email" value="">
<button type="submit">Submit</button>
</form>
</body>
</html>
HTML;
$processed = $this->processor->process($html, $this->session);
// Token should be replaced
expect($processed)->not->toContain("___TOKEN_{$formId}___");
// Should contain a valid token
preg_match('/name="_token"[^>]*value="([^"]+)"/', $processed, $matches);
expect($matches)->toHaveCount(2);
$token = $matches[1];
expect(strlen($token))->toBe(64);
expect(ctype_xdigit($token))->toBeTrue();
// Token should be valid in session
$tokenObj = \App\Framework\Security\CsrfToken::fromString($token);
$result = $this->session->csrf->validateTokenWithDebug($formId, $tokenObj);
expect($result['valid'])->toBeTrue();
});
it('processes multiple forms with different form IDs', function () {
$formId1 = $this->formIdGenerator->generateFormId('/form1', 'post');
$formId2 = $this->formIdGenerator->generateFormId('/form2', 'post');
$html = <<<HTML
<!DOCTYPE html>
<html>
<body>
<form method="post" action="/form1">
<input type="hidden" name="_form_id" value="{$formId1}">
<input type="hidden" name="_token" value="___TOKEN_{$formId1}___">
</form>
<form method="post" action="/form2">
<input type="hidden" name="_form_id" value="{$formId2}">
<input type="hidden" name="_token" value="___TOKEN_{$formId2}___">
</form>
</body>
</html>
HTML;
$processed = $this->processor->process($html, $this->session);
// Both tokens should be replaced
expect($processed)->not->toContain("___TOKEN_{$formId1}___");
expect($processed)->not->toContain("___TOKEN_{$formId2}___");
// Extract tokens
preg_match_all('/name="_token"[^>]*value="([^"]+)"/', $processed, $matches);
expect($matches[1])->toHaveCount(2);
$token1 = $matches[1][0];
$token2 = $matches[1][1];
// Tokens should be different
expect($token1)->not->toBe($token2);
// Both should be valid
expect(strlen($token1))->toBe(64);
expect(strlen($token2))->toBe(64);
});
it('handles malformed HTML gracefully', function () {
$formId = $this->formIdGenerator->generateFormId('/test', 'post');
// HTML with unclosed tags
$html = <<<HTML
<form method="post" action="/test">
<input type="hidden" name="_form_id" value="{$formId}">
<input type="hidden" name="_token" value="___TOKEN_{$formId}___">
<div>
<unclosed-tag>
</form>
HTML;
// Should not throw exception
$processed = $this->processor->process($html, $this->session);
// Should still replace token (via regex fallback)
expect($processed)->not->toContain("___TOKEN_{$formId}___");
});
it('preserves HTML structure after processing', function () {
$formId = $this->formIdGenerator->generateFormId('/test', 'post');
$html = <<<HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test Page</title>
</head>
<body>
<h1>Test Form</h1>
<form method="post" action="/test">
<input type="hidden" name="_form_id" value="{$formId}">
<input type="hidden" name="_token" value="___TOKEN_{$formId}___">
<label>Email:</label>
<input type="email" name="email">
<button type="submit">Submit</button>
</form>
</body>
</html>
HTML;
$processed = $this->processor->process($html, $this->session);
// Should preserve structure
expect($processed)->toContain('<!DOCTYPE html>');
expect($processed)->toContain('<html>');
expect($processed)->toContain('<head>');
expect($processed)->toContain('<title>Test Page</title>');
expect($processed)->toContain('<h1>Test Form</h1>');
expect($processed)->toContain('<label>Email:</label>');
expect($processed)->toContain('<button type="submit">Submit</button>');
// Token should be replaced
expect($processed)->not->toContain("___TOKEN_{$formId}___");
});