feat: add full Zonemaster stack with Docker and Spanish UI

- Clone all 5 Zonemaster component repos (LDNS, Engine, CLI, Backend, GUI)
- Dockerfile.backend: 8-stage multi-stage build LDNS→Engine→CLI→Backend
- Dockerfile.gui: Astro static build served via nginx
- docker-compose.yml: backend (internal) + frontend (port 5353)
- nginx.conf: root redirects to /es/, /api/ proxied to backend
- zonemaster-gui/config.ts: defaultLanguage set to 'es' (Spanish)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-21 08:19:24 +02:00
commit 8d4eaa1489
1567 changed files with 204155 additions and 0 deletions

View File

@@ -0,0 +1,253 @@
use strict;
use warnings;
use Try::Tiny;
use Zonemaster::Backend::Config;
my $config = Zonemaster::Backend::Config->load_config();
my %patch = (
mysql => \&patch_db_mysql,
postgresql => \&patch_db_postgresql,
sqlite => \&patch_db_sqlite,
);
my $db_engine = $config->DB_engine;
if ( $db_engine =~ /^(MySQL|PostgreSQL|SQLite)$/ ) {
$patch{ lc $db_engine }();
}
else {
die "Unknown database engine configured: $db_engine\n";
}
sub patch_db_mysql {
use Zonemaster::Backend::DB::MySQL;
my $db = Zonemaster::Backend::DB::MySQL->from_config( $config );
my $dbh = $db->dbh;
# add table constraints
$dbh->do( 'ALTER TABLE users ADD CONSTRAINT UNIQUE (username)' );
$dbh->do( 'ALTER TABLE test_results ADD CONSTRAINT UNIQUE (hash_id)' );
# update columns names, data type and default value
$dbh->do( 'ALTER TABLE test_results MODIFY COLUMN id BIGINT AUTO_INCREMENT' );
$dbh->do( 'ALTER TABLE test_results CHANGE COLUMN creation_time created_at DATETIME NOT NULL' );
$dbh->do( 'ALTER TABLE test_results CHANGE COLUMN test_start_time started_at DATETIME DEFAULT NULL' );
$dbh->do( 'ALTER TABLE test_results CHANGE COLUMN test_end_time ended_at DATETIME DEFAULT NULL' );
$dbh->do( 'ALTER TABLE batch_jobs CHANGE COLUMN creation_time created_at DATETIME NOT NULL' );
$dbh->{AutoCommit} = 0;
try {
# normalize "domain" column
$dbh->do(
q[
UPDATE test_results
SET domain = LOWER(domain)
WHERE CAST(domain AS BINARY) RLIKE '[A-Z]'
]
);
$dbh->do(
q[
UPDATE test_results
SET domain = '.'
WHERE domain = '..' OR domain = '...' OR domain = '....'
]
);
$dbh->do(
q[
UPDATE test_results
SET domain = TRIM( TRAILING '.' FROM domain )
WHERE domain != '.' AND domain LIKE '%.'
]
);
$dbh->commit();
} catch {
print( "Could not upgrade database: " . $_ );
eval { $dbh->rollback() };
};
}
sub patch_db_postgresql {
use Zonemaster::Backend::DB::PostgreSQL;
my $db = Zonemaster::Backend::DB::PostgreSQL->from_config( $config );
my $dbh = $db->dbh;
$dbh->{AutoCommit} = 0;
try {
# update sequence data type to BIGINT
$dbh->do( 'ALTER SEQUENCE test_results_id_seq AS BIGINT' );
$dbh->do( 'ALTER TABLE test_results ALTER COLUMN id SET DATA TYPE BIGINT' );
# remove default value for "creation_time"
$dbh->do( 'ALTER TABLE test_results ALTER COLUMN creation_time DROP DEFAULT' );
$dbh->do( 'ALTER TABLE batch_jobs ALTER COLUMN creation_time DROP DEFAULT' );
# rename columns
$dbh->do( 'ALTER TABLE test_results RENAME COLUMN creation_time TO created_at' );
$dbh->do( 'ALTER TABLE test_results RENAME COLUMN test_start_time TO started_at' );
$dbh->do( 'ALTER TABLE test_results RENAME COLUMN test_end_time TO ended_at' );
$dbh->do( 'ALTER TABLE batch_jobs RENAME COLUMN creation_time TO created_at' );
# add table constraints
$dbh->do( 'ALTER TABLE test_results ADD UNIQUE (hash_id)' );
$dbh->do( 'ALTER TABLE users ADD UNIQUE (username)' );
# normalize "domain" column
$dbh->do(
q[
UPDATE test_results
SET domain = LOWER(domain)
WHERE domain != LOWER(domain)
]
);
$dbh->do(
q[
UPDATE test_results
SET domain = '.'
WHERE domain = '..' OR domain = '...' OR domain = '....'
]
);
$dbh->do(
q[
UPDATE test_results
SET domain = RTRIM(domain, '.')
WHERE domain != '.' AND domain LIKE '%.'
]
);
$dbh->commit();
} catch {
print( "Could not upgrade database: " . $_ );
eval { $dbh->rollback() };
};
}
sub patch_db_sqlite {
use Zonemaster::Backend::DB::SQLite;
my $db = Zonemaster::Backend::DB::SQLite->from_config( $config );
my $dbh = $db->dbh;
$dbh->{AutoCommit} = 0;
# since we change the default value for a column, the whole table needs to
# be recreated
# 1. rename the table to "<table>_old"
# 2. recreate a clean table schema
# 3. populate it with the values from "<table>_old"
# 4. remove "<table>_old" and indexes
# 5. recreate the indexes
try {
$dbh->do('ALTER TABLE test_results RENAME TO test_results_old');
$dbh->do('ALTER TABLE batch_jobs RENAME TO batch_jobs_old');
$dbh->do('ALTER TABLE users RENAME TO users_old');
# create the tables
$db->create_schema();
# populate the tables
$dbh->do(
q[
INSERT INTO test_results
(
id,
hash_id,
domain,
batch_id,
created_at,
started_at,
ended_at,
priority,
queue,
progress,
fingerprint,
params,
results,
undelegated
)
SELECT
id,
hash_id,
lower(domain),
batch_id,
creation_time,
test_start_time,
test_end_time,
priority,
queue,
progress,
fingerprint,
params,
results,
undelegated
FROM test_results_old
]
);
$dbh->do(
q[
UPDATE test_results
SET domain = '.'
WHERE domain = '..' OR domain = '...' OR domain = '....'
]
);
$dbh->do(
q[
UPDATE test_results
SET domain = RTRIM(domain, '.')
WHERE domain != '.' AND domain LIKE '%.'
]
);
$dbh->do('
INSERT INTO batch_jobs
(
id,
username,
created_at
)
SELECT
id,
username,
creation_time
FROM batch_jobs_old
');
$dbh->do('
INSERT INTO users
(
id,
username,
api_key
)
SELECT
id,
username,
api_key
FROM users_old
');
# delete old tables
$dbh->do('DROP TABLE test_results_old');
$dbh->do('DROP TABLE batch_jobs_old');
$dbh->do('DROP TABLE users_old');
# recreate indexes
$db->create_schema();
$dbh->commit();
} catch {
print( "Error while upgrading database: " . $_ );
eval { $dbh->rollback() };
};
}