diff --git a/app/api/__tests__/safety.spec.ts b/app/api/__tests__/safety.spec.ts index 35575bfc3..46a484d7c 100644 --- a/app/api/__tests__/safety.spec.ts +++ b/app/api/__tests__/safety.spec.ts @@ -81,3 +81,23 @@ it('e2e tests are only in test/e2e or test/visual', () => { expect(file).toMatch(/^test\/(e2e|visual)/) } }) + +// 8-4-4-4-12 hex digits +const UUID_RE = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' + +// RFC 4122: version nibble (3rd group, 1st char) is 1-5, +// variant nibble (4th group, 1st char) is 8, 9, a, or b +const VALID_UUID_RE = + /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i + +it('all UUIDs in mock-api files are valid RFC 4122', () => { + const output = execSync(`git grep -n -oP '${UUID_RE}' -- 'mock-api/'`).toString().trim() + const invalid = output.split('\n').filter((line) => { + const uuid = line.split(':').slice(2).join(':') + return !VALID_UUID_RE.test(uuid) + }) + expect( + invalid, + `Invalid UUIDs found:\n${invalid.join('\n')}\n\nUse a reliable generator (e.g., uuidgen) to create valid v4 UUIDs.` + ).toEqual([]) +}) diff --git a/mock-api/disk.ts b/mock-api/disk.ts index 3d403e238..cee030157 100644 --- a/mock-api/disk.ts +++ b/mock-api/disk.ts @@ -229,7 +229,7 @@ export const disks: Json[] = [ read_only: false, }, { - id: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', + id: 'a1b2c3d4-e5f6-4890-abcd-ef1234567890', name: 'read-only-disk', description: 'A read-only disk created from a snapshot', project_id: project.id, diff --git a/mock-api/floating-ip.ts b/mock-api/floating-ip.ts index 986f51b2f..fb6e32e61 100644 --- a/mock-api/floating-ip.ts +++ b/mock-api/floating-ip.ts @@ -44,7 +44,7 @@ export const floatingIp2: Json = { // An IPv6 floating IP for testing IP version filtering (from ip-pool-2) export const floatingIp3: Json = { - id: 'b1c2d3e4-5f6a-7b8c-9d0e-1f2a3b4c5d6e', + id: 'b1c2d3e4-5f6a-4b8c-9d0e-1f2a3b4c5d6e', name: 'ipv6-float', description: 'An IPv6 address.', instance_id: undefined, diff --git a/mock-api/project.ts b/mock-api/project.ts index 53220f020..42d60fbfc 100644 --- a/mock-api/project.ts +++ b/mock-api/project.ts @@ -56,7 +56,7 @@ export const projectNoVpcs: DbProject = { // Projects for test silos (different IP pool configurations) export const projectKosman: DbProject = { - id: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', + id: 'a1b2c3d4-e5f6-4890-abcd-ef1234567890', name: 'kosman-project', description: 'project in myriad silo (v4-only default pool)', time_created: new Date(2024, 0, 5).toISOString(), @@ -65,7 +65,7 @@ export const projectKosman: DbProject = { } export const projectAnscombe: DbProject = { - id: 'b2c3d4e5-f6a7-8901-bcde-f12345678901', + id: 'b2c3d4e5-f6a7-4901-bcde-f12345678901', name: 'anscombe-project', description: 'project in thrax silo (v6-only default pool)', time_created: new Date(2024, 0, 7).toISOString(), @@ -74,7 +74,7 @@ export const projectAnscombe: DbProject = { } export const projectAdorno: DbProject = { - id: 'c3d4e5f6-a7b8-9012-cdef-123456789012', + id: '738c46df-35b1-44a2-ae1f-31005a0cbfee', name: 'adorno-project', description: 'project in pelerines silo (no default pools)', time_created: new Date(2024, 0, 9).toISOString(), diff --git a/mock-api/silo.ts b/mock-api/silo.ts index 69870aa61..35b65a27c 100644 --- a/mock-api/silo.ts +++ b/mock-api/silo.ts @@ -45,7 +45,7 @@ export const silos: Json = [ }, // Test silos for IP pool configuration scenarios { - id: '7a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d', + id: '7a1b2c3d-4e5f-4a7b-8c9d-0e1f2a3b4c5d', name: 'thrax', description: 'silo with v6-only default pool', time_created: new Date(2024, 0, 1).toISOString(), @@ -55,7 +55,7 @@ export const silos: Json = [ mapped_fleet_roles: {}, }, { - id: '8b2c3d4e-5f6a-7b8c-9d0e-1f2a3b4c5d6e', + id: '8b2c3d4e-5f6a-4b8c-9d0e-1f2a3b4c5d6e', name: 'pelerines', description: 'silo with no default pools', time_created: new Date(2024, 0, 3).toISOString(), @@ -65,7 +65,7 @@ export const silos: Json = [ mapped_fleet_roles: {}, }, { - id: '9c3d4e5f-6a7b-7c9d-8e1f-2a3b4c5d6e7f', + id: '9c3d4e5f-6a7b-4c9d-8e1f-2a3b4c5d6e7f', name: 'no-pools', description: 'silo with no IP pools', time_created: new Date(2024, 0, 11).toISOString(), @@ -218,13 +218,13 @@ type DbScimToken = Json & { siloId: string } export const scimTokens: DbScimToken[] = [ { - id: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', + id: 'a1b2c3d4-e5f6-4890-abcd-ef1234567890', time_created: new Date(2025, 8, 15).toISOString(), time_expires: null, siloId: defaultSilo.id, }, { - id: 'b2c3d4e5-f6a7-8901-bcde-f12345678901', + id: 'b2c3d4e5-f6a7-4901-bcde-f12345678901', time_created: new Date(2025, 8, 20).toISOString(), time_expires: null, siloId: defaultSilo.id, diff --git a/mock-api/user.ts b/mock-api/user.ts index a87ffa943..af8dbd1fe 100644 --- a/mock-api/user.ts +++ b/mock-api/user.ts @@ -48,25 +48,25 @@ export const user6: Json = { // Users for test silos (different IP pool configurations) export const userKosman: Json = { - id: '9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d', + id: '9a8b7c6d-5e4f-4a2b-9c0d-9e8f7a6b5c4d', display_name: 'Aryeh Kosman', silo_id: myriadSilo.id, } export const userAnscombe: Json = { - id: 'a9b8c7d6-e5f4-a3b2-c1d0-e9f8a7b6c5d4', + id: 'a9b8c7d6-e5f4-43b2-81d0-e9f8a7b6c5d4', display_name: 'Elizabeth Anscombe', silo_id: thraxSilo.id, } export const userAdorno: Json = { - id: 'b0c9d8e7-f6a5-b4c3-d2e1-f0a9b8c7d6e5', + id: 'b0c9d8e7-f6a5-44c3-92e1-f0a9b8c7d6e5', display_name: 'Theodor Adorno', silo_id: pelerinesSilo.id, } export const userNoPools: Json = { - id: 'c1d0e9f8-a7b6-c5d4-e3f2-a1b0c9d8e7f6', + id: 'c1d0e9f8-a7b6-45d4-a3f2-a1b0c9d8e7f6', display_name: 'Antonio Gramsci', silo_id: noPoolsSilo.id, } diff --git a/mock-api/vpc.ts b/mock-api/vpc.ts index ae97ffa5a..80861df50 100644 --- a/mock-api/vpc.ts +++ b/mock-api/vpc.ts @@ -45,7 +45,7 @@ export const vpc2: Json = { // VPCs for test silos (IP pool configuration testing) export const vpcKosman: Json = { - id: 'd1e2f3a4-b5c6-7890-abcd-ef1234567890', + id: 'd1e2f3a4-b5c6-4890-abcd-ef1234567890', name: 'kosman-vpc', description: 'VPC in myriad silo', dns_name: 'kosman-vpc', @@ -57,7 +57,7 @@ export const vpcKosman: Json = { } export const vpcAnscombe: Json = { - id: 'e2f3a4b5-c6d7-8901-bcde-f12345678901', + id: 'e2f3a4b5-c6d7-4901-bcde-f12345678901', name: 'anscombe-vpc', description: 'VPC in thrax silo', dns_name: 'anscombe-vpc', @@ -69,7 +69,7 @@ export const vpcAnscombe: Json = { } export const vpcAdorno: Json = { - id: 'f3a4b5c6-d7e8-9012-cdef-123456789012', + id: 'f3a4b5c6-d7e8-4012-8def-123456789012', name: 'adorno-vpc', description: 'VPC in pelerines silo', dns_name: 'adorno-vpc', @@ -213,7 +213,7 @@ export const vpcSubnet2: Json = { // Subnets for test silos export const subnetKosman: Json = { - id: 'a1b2c3d4-e5f6-7890-1234-567890abcdef', + id: 'a1b2c3d4-e5f6-4890-9234-567890abcdef', name: 'kosman-subnet', description: 'subnet in myriad silo', time_created, @@ -224,7 +224,7 @@ export const subnetKosman: Json = { } export const subnetAnscombe: Json = { - id: 'b2c3d4e5-f6a7-8901-2345-67890abcdef1', + id: 'b2c3d4e5-f6a7-4901-a345-67890abcdef1', name: 'anscombe-subnet', description: 'subnet in thrax silo', time_created, @@ -235,7 +235,7 @@ export const subnetAnscombe: Json = { } export const subnetAdorno: Json = { - id: 'c3d4e5f6-a7b8-9012-3456-7890abcdef12', + id: 'c3d4e5f6-a7b8-4012-b456-7890abcdef12', name: 'adorno-subnet', description: 'subnet in pelerines silo', time_created,