Skip to content

Commit f1f0cc1

Browse files
committed
Merge branch '0.6'
2 parents 09b9fa8 + 32ac948 commit f1f0cc1

File tree

9 files changed

+151
-44
lines changed

9 files changed

+151
-44
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
* 0.6.1 (2026-03-30)
4+
* Fixed loading of encryption module in dashboard pages which prevented changes to existing credentials
5+
* Disabled autocomplete on credentials information
6+
37
* 0.6.0 (2026-03-23)
48
* Added configuration option to fetch mirrored packages from their VCS repositories by default when possible
59
* Improved the `packages:update` command with clearer arguments

phpstan.dist.neon

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,3 @@ parameters:
3434
identifier: booleanOr.rightAlwaysFalse
3535
count: 1
3636
path: src/Encryption/Encryption.php
37-
-
38-
message: '#^Property CodedMonkey\\Dirigent\\EventListener\\EncryptionListener\:\:\$connection is never read, only written\.$#'
39-
identifier: property.onlyWritten
40-
count: 1
41-
path: src/EventListener/EncryptionListener.php

src/Composer/ConfigFactory.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ private static function buildCredentialsConfig(string $domain, ?Credentials $cre
6969
CredentialsType::GitlabPersonalAccessToken => [
7070
'gitlab-token' => [
7171
$domain => [
72-
'username' => $credentials->getToken(),
73-
'token' => 'private-token',
72+
'username' => 'private-token',
73+
'token' => $credentials->getToken(),
7474
],
7575
],
7676
],

src/Controller/Dashboard/DashboardCredentialsController.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,15 @@ public function configureFields(string $pageName): iterable
4242
->renderExpanded();
4343
yield TextField::new('username')
4444
->setFormTypeOption('row_attr', ['data-credentials-field' => 'username'])
45+
->setFormTypeOption('attr', ['autocomplete' => 'off'])
4546
->onlyOnForms();
4647
yield TextField::new('password')
4748
->setFormTypeOption('row_attr', ['data-credentials-field' => 'password'])
49+
->setFormTypeOption('attr', ['autocomplete' => 'off'])
4850
->onlyOnForms();
4951
yield TextField::new('token')
5052
->setFormTypeOption('row_attr', ['data-credentials-field' => 'token'])
53+
->setFormTypeOption('attr', ['autocomplete' => 'off'])
5154
->onlyOnForms();
5255
}
5356
}

src/DependencyInjection/Compiler/EncryptionPass.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public function process(ContainerBuilder $container): void
2222
$rotatedKeyPaths = $parameterBag->get('dirigent.encryption.rotated_key_paths');
2323

2424
$container->getDefinition(Encryption::class)
25+
->setLazy(true)
2526
->setFactory([Encryption::class, 'create'])
2627
->setArguments([
2728
$privateKey,
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace CodedMonkey\Dirigent\Doctrine\Middleware;
4+
5+
use CodedMonkey\Dirigent\Doctrine\Type\EncryptedTextType;
6+
use CodedMonkey\Dirigent\Encryption\Encryption;
7+
use Doctrine\Bundle\DoctrineBundle\Attribute\AsMiddleware;
8+
use Doctrine\DBAL\Driver;
9+
use Doctrine\DBAL\Driver\Connection;
10+
use Doctrine\DBAL\Driver\Middleware;
11+
use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware;
12+
use Doctrine\DBAL\Types\Type;
13+
14+
/**
15+
* Configures EncryptedTextType by manually injecting the encryption utility after initializing Doctrine.
16+
*/
17+
#[AsMiddleware]
18+
readonly class EncryptionMiddleware implements Middleware
19+
{
20+
public function __construct(private Encryption $encryption)
21+
{
22+
}
23+
24+
public function wrap(Driver $driver): Driver
25+
{
26+
return new class($driver, $this->encryption) extends AbstractDriverMiddleware {
27+
public function __construct(Driver $driver, private readonly Encryption $encryption)
28+
{
29+
parent::__construct($driver);
30+
}
31+
32+
public function connect(array $params): Connection
33+
{
34+
/** @var EncryptedTextType $doctrineType */
35+
$doctrineType = Type::getType(EncryptedTextType::TYPE);
36+
$doctrineType->setEncryptionUtility($this->encryption);
37+
38+
return parent::connect($params);
39+
}
40+
};
41+
}
42+
}

src/EventListener/EncryptionListener.php

Lines changed: 0 additions & 34 deletions
This file was deleted.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
namespace CodedMonkey\Dirigent\Tests\FunctionalTests\Controller\Dashboard;
4+
5+
use CodedMonkey\Dirigent\Controller\Dashboard\DashboardCredentialsController;
6+
use CodedMonkey\Dirigent\Doctrine\Entity\Credentials;
7+
use CodedMonkey\Dirigent\Doctrine\Entity\CredentialsType;
8+
use CodedMonkey\Dirigent\Tests\Helper\MockEntityFactoryTrait;
9+
use CodedMonkey\Dirigent\Tests\Helper\WebTestCaseTrait;
10+
use PHPUnit\Framework\Attributes\CoversClass;
11+
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
12+
use Symfony\Component\HttpFoundation\Response;
13+
14+
#[CoversClass(DashboardCredentialsController::class)]
15+
class DashboardCredentialsControllerTest extends WebTestCase
16+
{
17+
use MockEntityFactoryTrait;
18+
use WebTestCaseTrait;
19+
20+
public function testCreate(): void
21+
{
22+
$client = static::createClient();
23+
$this->loginUser('admin');
24+
25+
$client->request('GET', '/credentials/new');
26+
27+
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
28+
29+
$client->submitForm('Create', [
30+
'Credentials[name]' => 'Test credentials',
31+
'Credentials[type]' => CredentialsType::HttpBasic->value,
32+
'Credentials[username]' => 'testuser',
33+
'Credentials[password]' => 'testpassword',
34+
]);
35+
36+
$this->assertResponseStatusCodeSame(Response::HTTP_FOUND);
37+
38+
$credentials = $this->findEntity(Credentials::class, ['name' => 'Test credentials']);
39+
40+
self::assertNotNull($credentials, 'A credentials entry was created.');
41+
self::assertSame(CredentialsType::HttpBasic, $credentials->getType());
42+
self::assertSame('testuser', $credentials->getUsername());
43+
}
44+
45+
public function testEdit(): void
46+
{
47+
$client = static::createClient();
48+
$this->loginUser('admin');
49+
50+
$credentials = new Credentials();
51+
$credentials->setName('Original name');
52+
$credentials->setType(CredentialsType::HttpBasic);
53+
$credentials->setUsername('originaluser');
54+
$credentials->setPassword('originalpassword');
55+
56+
$this->persistEntities($credentials);
57+
58+
$credentialsId = $credentials->getId();
59+
60+
$client->request('GET', "/credentials/{$credentialsId}/edit");
61+
62+
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
63+
64+
$client->submitForm('Save changes', [
65+
'Credentials[name]' => 'Updated name',
66+
'Credentials[type]' => CredentialsType::HttpBasic->value,
67+
'Credentials[username]' => 'updateduser',
68+
'Credentials[password]' => 'updatedpassword',
69+
]);
70+
71+
$this->assertResponseStatusCodeSame(Response::HTTP_FOUND);
72+
73+
$this->clearEntities();
74+
$credentials = $this->findEntity(Credentials::class, $credentialsId);
75+
76+
self::assertNotNull($credentials);
77+
self::assertSame('Updated name', $credentials->getName());
78+
self::assertSame('updateduser', $credentials->getUsername());
79+
}
80+
}

tests/Helper/MockEntityFactoryTrait.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,24 @@ protected function createMockVersion(Package $package, string $versionName = '1.
4949
return $version;
5050
}
5151

52+
/**
53+
* Find a single entity by its ID or an array of criteria.
54+
*
55+
* @template T of object
56+
*
57+
* @param class-string<T> $className
58+
*
59+
* @return T|null
60+
*/
61+
protected function findEntity(string $className, array|int $criteria): ?object
62+
{
63+
if (is_array($criteria)) {
64+
return $this->getService(EntityManagerInterface::class)->getRepository($className)->findOneBy($criteria);
65+
}
66+
67+
return $this->getService(EntityManagerInterface::class)->find($className, $criteria);
68+
}
69+
5270
/**
5371
* Persist and flush all given entities.
5472
*
@@ -67,8 +85,6 @@ protected function persistEntities(...$entities): void
6785

6886
protected function clearEntities(): void
6987
{
70-
$entityManager = $this->getService(EntityManagerInterface::class);
71-
72-
$entityManager->clear();
88+
$this->getService(EntityManagerInterface::class)->clear();
7389
}
7490
}

0 commit comments

Comments
 (0)