Skip to content

Commit af8fae3

Browse files
committed
Add SSH-key credentials
1 parent d64aeb4 commit af8fae3

File tree

7 files changed

+102
-4
lines changed

7 files changed

+102
-4
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DoctrineMigrations;
6+
7+
use Doctrine\DBAL\Schema\Schema;
8+
use Doctrine\Migrations\AbstractMigration;
9+
10+
final class Version20250312233323 extends AbstractMigration
11+
{
12+
public function getDescription(): string
13+
{
14+
return '';
15+
}
16+
17+
public function up(Schema $schema): void
18+
{
19+
$this->addSql('ALTER TABLE credentials ADD key TEXT DEFAULT NULL');
20+
}
21+
22+
public function down(Schema $schema): void
23+
{
24+
$this->addSql('ALTER TABLE credentials DROP key');
25+
}
26+
}

src/Composer/ComposerClient.php

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,35 @@
22

33
namespace CodedMonkey\Dirigent\Composer;
44

5+
use CodedMonkey\Dirigent\Doctrine\Entity\CredentialsType;
56
use CodedMonkey\Dirigent\Doctrine\Entity\Package;
67
use CodedMonkey\Dirigent\Doctrine\Entity\Registry;
78
use Composer\Config;
89
use Composer\Factory;
910
use Composer\IO\IOInterface;
1011
use Composer\IO\NullIO;
12+
use Composer\Pcre\Preg;
1113
use Composer\Repository\ComposerRepository;
1214
use Composer\Repository\VcsRepository;
15+
use Composer\Util\Filesystem as ComposerFilesystem;
16+
use Composer\Util\Git as GitUtility;
1317
use Composer\Util\HttpDownloader;
18+
use Composer\Util\ProcessExecutor;
19+
use Composer\Util\Url;
20+
use Symfony\Component\DependencyInjection\Attribute\Autowire;
21+
use Symfony\Component\Filesystem\Filesystem;
1422

15-
class ComposerClient
23+
readonly class ComposerClient
1624
{
25+
private Filesystem $filesystem;
26+
27+
public function __construct(
28+
#[Autowire(param: 'dirigent.storage.path')]
29+
private string $storagePath,
30+
) {
31+
$this->filesystem = new Filesystem();
32+
}
33+
1734
public function createComposerRepository(Package|Registry $registry, ?IOInterface $io = null, ?Config $config = null): ComposerRepository
1835
{
1936
$registry = $registry instanceof Package ? $registry->getMirrorRegistry() : $registry;
@@ -30,16 +47,42 @@ public function createComposerRepository(Package|Registry $registry, ?IOInterfac
3047

3148
public function createVcsRepository(Package $package, ?IOInterface $io = null, ?Config $config = null): VcsRepository
3249
{
33-
$repoUrl = $package->getRepositoryUrl();
50+
$repositoryUrl = $package->getRepositoryUrl();
51+
$repositoryCredentials = $package->getRepositoryCredentials();
3452

35-
$config ??= ConfigFactory::createForVcsRepository($repoUrl, $package->getRepositoryCredentials());
53+
$config ??= ConfigFactory::createForVcsRepository($repositoryUrl, $repositoryCredentials);
3654
if (!$io) {
3755
$io = new NullIO();
3856
$io->loadConfiguration($config);
3957
}
4058
$httpDownloader = $this->createHttpDownloader($io, $config);
4159

42-
return new VcsRepository(['url' => $repoUrl], $io, $config, $httpDownloader);
60+
$cacheRepositoryName = Preg::replace('{[^a-z0-9.]}i', '-', Url::sanitize($repositoryUrl));
61+
$cachePath = $config->get('cache-vcs-dir') . '/' . $cacheRepositoryName . '/';
62+
63+
if (CredentialsType::SshKey === $repositoryCredentials->getType() && !$this->filesystem->exists($cachePath)) {
64+
$gitUtility = new GitUtility(
65+
$io,
66+
$config,
67+
$process = new ProcessExecutor($io),
68+
new ComposerFilesystem($process),
69+
);
70+
71+
$keyPath = "$this->storagePath/keys/$cacheRepositoryName";
72+
73+
$this->filesystem->mkdir(dirname($keyPath));
74+
$this->filesystem->dumpFile($keyPath, str_replace("\r", '', $repositoryCredentials->getKey() . PHP_EOL));
75+
$this->filesystem->chmod($keyPath, 0400);
76+
77+
$gitConfig = sprintf('core.sshCommand="/usr/bin/ssh -i %s"', $keyPath);
78+
$gitUtility->runCommands([
79+
['git', 'clone', '-c', $gitConfig, '--mirror', '%url%', $cachePath],
80+
], $repositoryUrl, $cachePath, true, $lol);
81+
82+
dd($lol);
83+
}
84+
85+
return new VcsRepository(['url' => $repositoryUrl], $io, $config, $httpDownloader);
4386
}
4487

4588
public function createHttpDownloader(?IOInterface $io = null, ?Config $config = null): HttpDownloader

src/Controller/Dashboard/DashboardCredentialsController.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,8 @@ public function configureFields(string $pageName): iterable
4747
yield TextField::new('token')
4848
->setFormTypeOption('row_attr', ['data-credentials-field' => 'token'])
4949
->onlyOnForms();
50+
yield TextareaField::new('key')
51+
->setFormTypeOption('row_attr', ['data-credentials-field' => 'key'])
52+
->onlyOnForms();
5053
}
5154
}

src/Doctrine/Entity/Credentials.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ class Credentials
3232
#[ORM\Column(nullable: true)]
3333
private ?string $token = null;
3434

35+
#[ORM\Column(type: EncryptedTextType::TYPE, nullable: true)]
36+
private ?string $key = null;
37+
3538
public function getId(): ?int
3639
{
3740
return $this->id;
@@ -101,4 +104,14 @@ public function setToken(?string $token): void
101104
{
102105
$this->token = $token;
103106
}
107+
108+
public function getKey(): ?string
109+
{
110+
return $this->key;
111+
}
112+
113+
public function setKey(?string $key): void
114+
{
115+
$this->key = $key;
116+
}
104117
}

src/Doctrine/Entity/CredentialsType.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ enum CredentialsType: string
88
case GithubOauthToken = 'github-oauth';
99
case GitlabDeployToken = 'gitlab-dt';
1010
case GitlabPersonalAccessToken = 'gitlab-pat';
11+
case SshKey = 'ssh-key';
1112
}

src/Package/PackageVcsRepositoryValidator.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public function validate(Package $package): array
6868

6969
return $result;
7070
} catch (\Exception $e) {
71+
throw $e;
7172
return ['error' => '[' . $e::class . '] ' . $e->getMessage()];
7273
}
7374
}

templates/dashboard/credentials/js_assets.html.twig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const usernameFieldRow = document.querySelector('[data-credentials-field="username"]');
44
const passwordFieldRow = document.querySelector('[data-credentials-field="password"]');
55
const tokenFieldRow = document.querySelector('[data-credentials-field="token"]');
6+
const keyFieldRow = document.querySelector('[data-credentials-field="key"]');
67
78
const initalType = document.querySelector('[name="Credentials[type]"]:checked')?.value ?? null;
89
if (initalType) {
@@ -20,22 +21,32 @@
2021
usernameFieldRow.style.display = null;
2122
passwordFieldRow.style.display = null;
2223
tokenFieldRow.style.display = 'none';
24+
keyFieldRow.style.display = 'none';
2325
} else if (type === 'github-oauth') {
2426
usernameFieldRow.style.display = 'none';
2527
passwordFieldRow.style.display = 'none';
2628
tokenFieldRow.style.display = null;
29+
keyFieldRow.style.display = 'none';
2730
} else if (type === 'gitlab-dt') {
2831
usernameFieldRow.style.display = null;
2932
passwordFieldRow.style.display = 'none';
3033
tokenFieldRow.style.display = null;
34+
keyFieldRow.style.display = 'none';
3135
} else if (type === 'gitlab-pat') {
3236
usernameFieldRow.style.display = 'none';
3337
passwordFieldRow.style.display = 'none';
3438
tokenFieldRow.style.display = null;
39+
keyFieldRow.style.display = 'none';
40+
} else if (type === 'ssh-key') {
41+
usernameFieldRow.style.display = 'none';
42+
passwordFieldRow.style.display = 'none';
43+
tokenFieldRow.style.display = 'none';
44+
keyFieldRow.style.display = null;
3545
} else {
3646
usernameFieldRow.style.display = null;
3747
passwordFieldRow.style.display = null;
3848
tokenFieldRow.style.display = null;
49+
keyFieldRow.style.display = null;
3950
}
4051
}
4152
}

0 commit comments

Comments
 (0)