Skip to content

Commit f6ea60a

Browse files
authored
Merge pull request #90 from itk-dev/fix/user-api-key-migration-existing-rows
Fix user API key migration failing on populated databases
2 parents 611d0d5 + 554ddd0 commit f6ea60a

4 files changed

Lines changed: 76 additions & 1 deletion

File tree

.github/workflows/doctrine.yaml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,54 @@ jobs:
6262
- name: Load fixtures
6363
run: |
6464
docker compose run --rm phpfpm composer fixtures
65+
66+
# The jobs above migrate an empty database. A deployment migrates a database
67+
# that already holds rows, so a migration that cannot cope with existing
68+
# data passes those jobs unnoticed. This job builds the database as it looks
69+
# before the pull request, fixtures included, and then applies the pull
70+
# request's migrations on top of it.
71+
migrate-populated-database:
72+
name: Run migrations on a populated database
73+
runs-on: ubuntu-latest
74+
# This workflow also runs on pushes to main and develop, where there is
75+
# no pull request to read a base branch from: the checkout steps below
76+
# would get an empty revision and fail. A push has no base to compare
77+
# against, so skip the job rather than guess one.
78+
if: github.event_name == 'pull_request'
79+
80+
steps:
81+
- uses: actions/checkout@v6
82+
with:
83+
fetch-depth: 0
84+
85+
- name: Create docker network
86+
run: |
87+
docker network create frontend
88+
89+
- name: Check out the base branch
90+
run: |
91+
git checkout ${{ github.event.pull_request.base.sha }}
92+
93+
- name: Run Composer Install
94+
run: |
95+
docker compose run --rm phpfpm composer install --no-interaction
96+
97+
- name: Run Doctrine Migrations
98+
run: |
99+
docker compose run --rm phpfpm bin/console doctrine:migrations:migrate --no-interaction
100+
101+
- name: Load fixtures
102+
run: |
103+
docker compose run --rm phpfpm composer fixtures
104+
105+
- name: Check out the pull request
106+
run: |
107+
git checkout ${{ github.event.pull_request.head.sha }}
108+
109+
- name: Run Composer Install
110+
run: |
111+
docker compose run --rm phpfpm composer install --no-interaction
112+
113+
- name: Run Doctrine Migrations on the populated database
114+
run: |
115+
docker compose run --rm phpfpm bin/console doctrine:migrations:migrate --no-interaction

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
- [#90](https://github.com/itk-dev/devops_itksites/pull/90)
11+
- Fixed user API key migration failing on databases with more than one user
12+
- Generated an API key for existing users, as users created since already get
13+
- Added users to the fixtures and a CI job running migrations on a populated
14+
database
1015
- [#89](https://github.com/itk-dev/devops_itksites/pull/89)
1116
Added `--rm` to `docker compose run` in prod deployment
1217
- [#88](https://github.com/itk-dev/devops_itksites/pull/88)

fixtures/user.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,12 @@ App\Entity\User:
33
__construct: ["Admin", "admin@example.com", [ROLE_ADMIN]]
44
user_user:
55
__construct: ["User", "user@example.com", [ROLE_USER]]
6+
# A few more users so migrations are exercised against a table holding more
7+
# than one row. A single row cannot collide with itself, which hides
8+
# migrations adding a unique column to an existing table.
9+
user_1:
10+
__construct: ["User 1", "user1@example.com", [ROLE_USER]]
11+
user_2:
12+
__construct: ["User 2", "user2@example.com", [ROLE_USER]]
13+
user_3:
14+
__construct: ["User 3", "user3@example.com", [ROLE_USER]]

migrations/Version20260702123347.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,18 @@ public function getDescription(): string
1919

2020
public function up(Schema $schema): void
2121
{
22-
// this up() migration is auto-generated, please modify it to your needs
22+
// Adding the column gives every existing user the same empty string,
23+
// which collides on the unique index. Add random keys to allow unique index.
24+
//
25+
// The keys are generated in PHP because they are credentials and have
26+
// to come from a cryptographically secure source. SQL's RAND() and
27+
// UUID() are not one.
2328
$this->addSql('ALTER TABLE user ADD api_key VARCHAR(255) NOT NULL');
29+
30+
foreach ($this->connection->fetchFirstColumn('SELECT email FROM user') as $email) {
31+
$this->addSql('UPDATE user SET api_key = ? WHERE email = ?', [sha1(\random_bytes(40)), $email]);
32+
}
33+
2434
$this->addSql('CREATE UNIQUE INDEX UNIQ_8D93D649C912ED9D ON user (api_key)');
2535
}
2636

0 commit comments

Comments
 (0)