Harden compliance portal data migrations
Mint certificate and domain GIDs with generate_gid, preserve org profile and domain rows that lack a trust center, and skip managed default-domain backfill when no base domain is set. Signed-off-by: Bryan Frimin <bryan@probo.com>
This commit is contained in:
@@ -18,6 +18,37 @@ ALTER TABLE custom_domains ALTER COLUMN managed DROP DEFAULT;
|
|||||||
ALTER TABLE trust_centers ADD COLUMN default_domain_id TEXT REFERENCES custom_domains(id) ON DELETE SET NULL;
|
ALTER TABLE trust_centers ADD COLUMN default_domain_id TEXT REFERENCES custom_domains(id) ON DELETE SET NULL;
|
||||||
ALTER TABLE trust_centers ADD COLUMN custom_domain_id TEXT REFERENCES custom_domains(id) ON DELETE SET NULL;
|
ALTER TABLE trust_centers ADD COLUMN custom_domain_id TEXT REFERENCES custom_domains(id) ON DELETE SET NULL;
|
||||||
|
|
||||||
|
INSERT INTO trust_centers (
|
||||||
|
id,
|
||||||
|
organization_id,
|
||||||
|
tenant_id,
|
||||||
|
active,
|
||||||
|
slug,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
generate_gid(decode_base64_unpadded(o.tenant_id), 22),
|
||||||
|
o.id,
|
||||||
|
o.tenant_id,
|
||||||
|
false,
|
||||||
|
LOWER(
|
||||||
|
REGEXP_REPLACE(
|
||||||
|
REGEXP_REPLACE(
|
||||||
|
unaccent(o.name),
|
||||||
|
'[^a-zA-Z0-9\s]', '', 'g'
|
||||||
|
),
|
||||||
|
'\s+', '-', 'g'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
NOW(),
|
||||||
|
NOW()
|
||||||
|
FROM organizations o
|
||||||
|
WHERE o.custom_domain_id IS NOT NULL
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM trust_centers tc WHERE tc.organization_id = o.id
|
||||||
|
);
|
||||||
|
|
||||||
UPDATE trust_centers tc
|
UPDATE trust_centers tc
|
||||||
SET custom_domain_id = o.custom_domain_id
|
SET custom_domain_id = o.custom_domain_id
|
||||||
FROM organizations o
|
FROM organizations o
|
||||||
|
|||||||
@@ -42,10 +42,9 @@ CREATE INDEX idx_certificates_http_challenge_token ON certificates(http_challeng
|
|||||||
WHERE http_challenge_token IS NOT NULL;
|
WHERE http_challenge_token IS NOT NULL;
|
||||||
|
|
||||||
-- Backfill one certificate per existing custom domain. A fresh GID is minted
|
-- Backfill one certificate per existing custom domain. A fresh GID is minted
|
||||||
-- for each row: the source domain's tenant (first 8 bytes of its GID) is kept,
|
-- for each row with generate_gid (entity type 104 = CertificateEntityType).
|
||||||
-- the entity type is set to 104 (CertificateEntityType), and a millisecond
|
-- The certificate hostname equals the custom domain name, which lets us link
|
||||||
-- timestamp plus random suffix guarantee uniqueness. The certificate hostname
|
-- the two afterwards.
|
||||||
-- equals the custom domain name, which lets us link the two afterwards.
|
|
||||||
INSERT INTO certificates (
|
INSERT INTO certificates (
|
||||||
id,
|
id,
|
||||||
tenant_id,
|
tenant_id,
|
||||||
@@ -66,17 +65,7 @@ INSERT INTO certificates (
|
|||||||
updated_at
|
updated_at
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
translate(
|
generate_gid(decode_base64_unpadded(cd.tenant_id), 104),
|
||||||
encode(
|
|
||||||
substring(decode(translate(cd.id, '-_', '+/'), 'base64') FROM 1 FOR 8)
|
|
||||||
|| int2send(104::smallint)
|
|
||||||
|| int8send((floor(extract(epoch FROM clock_timestamp()) * 1000))::bigint)
|
|
||||||
|| substring(decode(md5(random()::text || cd.id), 'hex') FROM 1 FOR 6),
|
|
||||||
'base64'
|
|
||||||
),
|
|
||||||
'+/',
|
|
||||||
'-_'
|
|
||||||
),
|
|
||||||
cd.tenant_id,
|
cd.tenant_id,
|
||||||
cd.domain,
|
cd.domain,
|
||||||
cd.ssl_certificate,
|
cd.ssl_certificate,
|
||||||
@@ -100,7 +89,8 @@ ALTER TABLE custom_domains ADD COLUMN certificate_id TEXT REFERENCES certificate
|
|||||||
UPDATE custom_domains cd
|
UPDATE custom_domains cd
|
||||||
SET certificate_id = c.id
|
SET certificate_id = c.id
|
||||||
FROM certificates c
|
FROM certificates c
|
||||||
WHERE c.hostname = cd.domain;
|
WHERE c.hostname = cd.domain
|
||||||
|
AND c.tenant_id = cd.tenant_id;
|
||||||
|
|
||||||
-- Repoint the certificate cache from the custom domain to the certificate.
|
-- Repoint the certificate cache from the custom domain to the certificate.
|
||||||
ALTER TABLE cached_certificates ADD COLUMN certificate_id TEXT REFERENCES certificates(id) ON DELETE CASCADE;
|
ALTER TABLE cached_certificates ADD COLUMN certificate_id TEXT REFERENCES certificates(id) ON DELETE CASCADE;
|
||||||
|
|||||||
@@ -18,6 +18,42 @@ ALTER TABLE trust_centers
|
|||||||
ADD COLUMN email CITEXT,
|
ADD COLUMN email CITEXT,
|
||||||
ADD COLUMN headquarter_address TEXT;
|
ADD COLUMN headquarter_address TEXT;
|
||||||
|
|
||||||
|
INSERT INTO trust_centers (
|
||||||
|
id,
|
||||||
|
organization_id,
|
||||||
|
tenant_id,
|
||||||
|
active,
|
||||||
|
slug,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
generate_gid(decode_base64_unpadded(o.tenant_id), 22),
|
||||||
|
o.id,
|
||||||
|
o.tenant_id,
|
||||||
|
false,
|
||||||
|
LOWER(
|
||||||
|
REGEXP_REPLACE(
|
||||||
|
REGEXP_REPLACE(
|
||||||
|
unaccent(o.name),
|
||||||
|
'[^a-zA-Z0-9\s]', '', 'g'
|
||||||
|
),
|
||||||
|
'\s+', '-', 'g'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
NOW(),
|
||||||
|
NOW()
|
||||||
|
FROM organizations o
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1 FROM trust_centers tc WHERE tc.organization_id = o.id
|
||||||
|
)
|
||||||
|
AND (
|
||||||
|
o.description IS NOT NULL
|
||||||
|
OR o.website_url IS NOT NULL
|
||||||
|
OR o.email IS NOT NULL
|
||||||
|
OR o.headquarter_address IS NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
UPDATE trust_centers tc
|
UPDATE trust_centers tc
|
||||||
SET
|
SET
|
||||||
description = o.description,
|
description = o.description,
|
||||||
|
|||||||
@@ -14,8 +14,9 @@
|
|||||||
|
|
||||||
-- Backfill managed default domains for compliance pages created before
|
-- Backfill managed default domains for compliance pages created before
|
||||||
-- default-domain provisioning existed. Hostnames use the managed base domain
|
-- default-domain provisioning existed. Hostnames use the managed base domain
|
||||||
-- suffix configured on the database (probo.trust_center_base_domain), falling
|
-- suffix configured on the database (probo.trust_center_base_domain). Self-
|
||||||
-- back to probopage.com for production installs.
|
-- managed installs without that setting are left alone — they do not get a
|
||||||
|
-- SaaS default domain invented for them.
|
||||||
|
|
||||||
WITH pending_pages AS (
|
WITH pending_pages AS (
|
||||||
SELECT
|
SELECT
|
||||||
@@ -24,14 +25,10 @@ WITH pending_pages AS (
|
|||||||
tc.organization_id,
|
tc.organization_id,
|
||||||
tc.slug,
|
tc.slug,
|
||||||
tc.created_at,
|
tc.created_at,
|
||||||
(
|
(tc.slug || '.' || current_setting('probo.trust_center_base_domain', true))::citext AS hostname
|
||||||
tc.slug || '.' || COALESCE(
|
|
||||||
NULLIF(current_setting('probo.trust_center_base_domain', true), ''),
|
|
||||||
'probopage.com'
|
|
||||||
)
|
|
||||||
)::citext AS hostname
|
|
||||||
FROM trust_centers tc
|
FROM trust_centers tc
|
||||||
WHERE tc.default_domain_id IS NULL
|
WHERE tc.default_domain_id IS NULL
|
||||||
|
AND NULLIF(current_setting('probo.trust_center_base_domain', true), '') IS NOT NULL
|
||||||
),
|
),
|
||||||
minted_certificates AS (
|
minted_certificates AS (
|
||||||
INSERT INTO certificates (
|
INSERT INTO certificates (
|
||||||
@@ -44,17 +41,7 @@ minted_certificates AS (
|
|||||||
updated_at
|
updated_at
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
translate(
|
generate_gid(decode_base64_unpadded(pp.tenant_id), 104),
|
||||||
encode(
|
|
||||||
substring(decode(translate(pp.trust_center_id, '-_', '+/'), 'base64') FROM 1 FOR 8)
|
|
||||||
|| int2send(104::smallint)
|
|
||||||
|| int8send((floor(extract(epoch FROM clock_timestamp()) * 1000))::bigint)
|
|
||||||
|| substring(decode(md5(random()::text || pp.trust_center_id), 'hex') FROM 1 FOR 6),
|
|
||||||
'base64'
|
|
||||||
),
|
|
||||||
'+/',
|
|
||||||
'-_'
|
|
||||||
),
|
|
||||||
pp.tenant_id,
|
pp.tenant_id,
|
||||||
pp.hostname,
|
pp.hostname,
|
||||||
'PENDING'::custom_domain_ssl_status,
|
'PENDING'::custom_domain_ssl_status,
|
||||||
@@ -76,17 +63,7 @@ minted_domains AS (
|
|||||||
updated_at
|
updated_at
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
translate(
|
generate_gid(decode_base64_unpadded(mc.tenant_id), 37),
|
||||||
encode(
|
|
||||||
substring(decode(translate(mc.id, '-_', '+/'), 'base64') FROM 1 FOR 8)
|
|
||||||
|| int2send(37::smallint)
|
|
||||||
|| int8send((floor(extract(epoch FROM clock_timestamp()) * 1000))::bigint)
|
|
||||||
|| substring(decode(md5(random()::text || mc.id), 'hex') FROM 1 FOR 6),
|
|
||||||
'base64'
|
|
||||||
),
|
|
||||||
'+/',
|
|
||||||
'-_'
|
|
||||||
),
|
|
||||||
mc.tenant_id,
|
mc.tenant_id,
|
||||||
pp.organization_id,
|
pp.organization_id,
|
||||||
pp.hostname,
|
pp.hostname,
|
||||||
|
|||||||
@@ -12,6 +12,9 @@
|
|||||||
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
-- PERFORMANCE OF THIS SOFTWARE.
|
-- PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
-- page_title (later renamed to title) is a full page heading, not an org-name
|
||||||
|
-- fragment for possessives like "{{name}}'s trust center". Seed from the org
|
||||||
|
-- name so existing pages keep a sensible default until editors customize it.
|
||||||
ALTER TABLE trust_centers
|
ALTER TABLE trust_centers
|
||||||
ADD COLUMN page_title TEXT;
|
ADD COLUMN page_title TEXT;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user