Skip to content

Commit 2090129

Browse files
Merge pull request #9 from MacPaw/feat/added_schema_cli_commands
feat: added `disallowedSchemaNames` argument for security reasons
2 parents e6a7eaa + 7aae713 commit 2090129

File tree

5 files changed

+67
-5
lines changed

5 files changed

+67
-5
lines changed

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,19 @@ Drops a PostgreSQL schema and all its objects:
9696
```yaml
9797
# config/services.yaml
9898
services:
99-
SharedServices\Command\Doctrine\DoctrineSchemaDropCommand: ~
99+
SharedServices\Command\Doctrine\DoctrineSchemaDropCommand:
100+
arguments:
101+
- '@Doctrine\DBAL\Connection'
102+
- ['public'] # Disallowed schema names for safety
100103
```
101104

102105
Usage:
103106
```bash
104107
php bin/console doctrine:schema:delete <schema_name>
105108
```
106109

110+
**Security Note:** You can specify disallowed schema names to prevent accidental deletion of critical schemas like `public`.
111+
107112
### Schema Migrations Command
108113
Runs Doctrine migrations within a specific schema. Creates the schema if it doesn't exist:
109114

@@ -129,13 +134,17 @@ services:
129134
SharedServices\Command\Doctrine\DoctrineSchemaFixturesLoadCommand:
130135
arguments:
131136
- '@doctrine.fixtures_load_command'
137+
- '@Doctrine\DBAL\Connection'
138+
- ['public'] # Disallowed schema names for safety
132139
```
133140

134141
Usage:
135142
```bash
136143
php bin/console doctrine:schema:fixtures:load <schema_name> [options]
137144
```
138145

146+
**Security Note:** You can specify disallowed schema names to prevent accidental fixture loading into critical schemas like `public`.
147+
139148
**Note:** These commands are optional and should only be registered if you're using the corresponding Doctrine features (migrations and/or fixtures) in your project.
140149

141150
## Testing

src/Command/Doctrine/DoctrineSchemaDropCommand.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@
1111

1212
class DoctrineSchemaDropCommand extends AbstractDoctrineSchemaCommand
1313
{
14-
public function __construct(Connection $connection)
15-
{
14+
/**
15+
* @param string[] $disallowedSchemaNames
16+
*/
17+
public function __construct(
18+
Connection $connection,
19+
private readonly array $disallowedSchemaNames = [],
20+
) {
1621
parent::__construct('doctrine:schema:delete', $connection);
1722
}
1823

@@ -22,6 +27,14 @@ protected function execute(
2227
): int {
2328
$schema = $this->getSchemaFromInput($input);
2429

30+
if (in_array($schema, $this->disallowedSchemaNames, true)) {
31+
$output->writeln(
32+
"<error>Command is disallowed from being called for the '$schema' schema</error>"
33+
);
34+
35+
return Command::FAILURE;
36+
}
37+
2538
$output->writeln("<info>Drop schema '{$schema}'...<info>");
2639

2740
$quotedSchema = $this->connection->quoteIdentifier($schema);

src/Command/Doctrine/DoctrineSchemaFixturesLoadCommand.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@
1313

1414
class DoctrineSchemaFixturesLoadCommand extends AbstractNestingDoctrineSchemaCommand
1515
{
16+
/**
17+
* @param string[] $disallowedSchemaNames
18+
*/
1619
public function __construct(
1720
LoadDataFixturesDoctrineCommand $parentCommand,
1821
Connection $connection,
22+
private readonly array $disallowedSchemaNames = [],
1923
) {
2024
parent::__construct('doctrine:schema:fixtures:load', $parentCommand, $connection);
2125
}
@@ -27,6 +31,14 @@ protected function execute(
2731
try {
2832
$schema = $this->getSchemaFromInput($input);
2933

34+
if (in_array($schema, $this->disallowedSchemaNames, true)) {
35+
$output->writeln(
36+
"<error>Command is disallowed from being called for the '$schema' schema</error>"
37+
);
38+
39+
return Command::FAILURE;
40+
}
41+
3042
if (!$this->isSchemaExist($schema)) {
3143
$output->writeln("<error>Schema '{$schema}' doesn't exist</error>");
3244

tests/Command/Doctrine/DoctrineSchemaDropCommandTest.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class DoctrineSchemaDropCommandTest extends TestCase
2020
protected function setUp(): void
2121
{
2222
$this->connection = $this->createMock(Connection::class);
23-
$this->command = new DoctrineSchemaDropCommand($this->connection);
23+
$this->command = new DoctrineSchemaDropCommand($this->connection, ['public']);
2424
}
2525

2626
public function testSuccess(): void
@@ -41,4 +41,18 @@ public function testSuccess(): void
4141

4242
$this->assertEquals(Command::SUCCESS, $result);
4343
}
44+
45+
public function testDisallowedSchemaNameFail(): void
46+
{
47+
$input = new ArrayInput(['schema' => 'public']);
48+
$output = new BufferedOutput();
49+
50+
$result = $this->command->run($input, $output);
51+
52+
$this->assertStringContainsString(
53+
"Command is disallowed from being called for the 'public' schema",
54+
$output->fetch()
55+
);
56+
$this->assertEquals(Command::FAILURE, $result);
57+
}
4458
}

tests/Command/Doctrine/DoctrineSchemaFixturesLoadCommandTest.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ protected function setUp(): void
3434
new InputOption('no-interaction'),
3535
]));
3636

37-
$this->command = new DoctrineSchemaFixturesLoadCommand($this->parentCommand, $this->connection);
37+
$this->command = new DoctrineSchemaFixturesLoadCommand($this->parentCommand, $this->connection, ['public']);
3838
$this->command->setApplication($this->application);
3939
}
4040

@@ -72,4 +72,18 @@ public function testSuccess(): void
7272
$this->assertEquals(Command::SUCCESS, $result);
7373
$this->assertStringContainsString("Load fixtures for 'test_schema'...", $output->fetch());
7474
}
75+
76+
public function testDisallowedSchemaNameFail(): void
77+
{
78+
$input = new ArrayInput(['schema' => 'public']);
79+
$output = new BufferedOutput();
80+
81+
$result = $this->command->run($input, $output);
82+
83+
$this->assertStringContainsString(
84+
"Command is disallowed from being called for the 'public' schema",
85+
$output->fetch()
86+
);
87+
$this->assertEquals(Command::FAILURE, $result);
88+
}
7589
}

0 commit comments

Comments
 (0)