Skip to content

Commit

Permalink
Add validation for SafeApp['socialProfiles'][number]['platform'] (#…
Browse files Browse the repository at this point in the history
…2094)

Adds the relevant validation for `SafeApp['socialProfiles'][number]['platform']`, falling back to `UNKNOWN` if it does not match:

- Add `SafeAppSocialProfilePlatforms` enum
- Propagate enum to relevant types
- Update tests accordingly
  • Loading branch information
iamacook authored Nov 6, 2024
1 parent 1a84d6b commit a1c7f31
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { faker } from '@faker-js/faker';
import type { IBuilder } from '@/__tests__/builder';
import { Builder } from '@/__tests__/builder';
import { SafeAppSocialProfilePlatforms } from '@/domain/safe-apps/entities/schemas/safe-app.schema';
import type { SafeAppSocialProfile } from '@/domain/safe-apps/entities/safe-app-social-profile.entity';

export function safeAppSocialProfileBuilder(): IBuilder<SafeAppSocialProfile> {
return new Builder<SafeAppSocialProfile>()
.with('platform', faker.word.sample())
.with('platform', faker.helpers.objectValue(SafeAppSocialProfilePlatforms))
.with('url', faker.internet.url({ appendSlash: false }));
}
11 changes: 9 additions & 2 deletions src/domain/safe-apps/entities/safe-app-social-profile.entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
export interface SafeAppSocialProfile {
platform: string;
import type { z } from 'zod';
import type {
SafeAppSocialProfilePlatforms,
SafeAppSocialProfileSchema,
} from '@/domain/safe-apps/entities/schemas/safe-app.schema';

export interface SafeAppSocialProfile
extends z.infer<typeof SafeAppSocialProfileSchema> {
platform: SafeAppSocialProfilePlatforms;
url: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { safeAppProviderBuilder } from '@/domain/safe-apps/entities/__tests__/sa
import { safeAppSocialProfileBuilder } from '@/domain/safe-apps/entities/__tests__/safe-app-social-profile.builder';
import { safeAppBuilder } from '@/domain/safe-apps/entities/__tests__/safe-app.builder';
import { SafeAppAccessControlPolicies } from '@/domain/safe-apps/entities/safe-app-access-control.entity';
import type { SafeAppSocialProfile } from '@/domain/safe-apps/entities/safe-app-social-profile.entity';
import { SafeAppSchema } from '@/domain/safe-apps/entities/schemas/safe-app.schema';
import { faker } from '@faker-js/faker';
import { ZodError } from 'zod';
Expand Down Expand Up @@ -64,14 +65,31 @@ describe('SafeAppSchema', () => {
);
});

it('should validate nested socialProfile and provider urls', () => {
it('should throw if a socialProfile has an invalid url', () => {
const safeApp = safeAppBuilder()
.with('socialProfiles', [
safeAppSocialProfileBuilder().build(),
safeAppSocialProfileBuilder()
.with('url', faker.string.alphanumeric())
.build(),
])
.build();

const result = SafeAppSchema.safeParse(safeApp);

expect(!result.success && result.error).toStrictEqual(
new ZodError([
{
validation: 'url',
code: 'invalid_string',
message: 'Invalid url',
path: ['socialProfiles', 0, 'url'],
},
]),
);
});

it('should throw if a profile has an invalid url', () => {
const safeApp = safeAppBuilder()
.with(
'provider',
safeAppProviderBuilder()
Expand All @@ -84,12 +102,6 @@ describe('SafeAppSchema', () => {

expect(!result.success && result.error).toStrictEqual(
new ZodError([
{
validation: 'url',
code: 'invalid_string',
message: 'Invalid url',
path: ['socialProfiles', 1, 'url'],
},
{
validation: 'url',
code: 'invalid_string',
Expand All @@ -100,6 +112,22 @@ describe('SafeAppSchema', () => {
);
});

it('should fallback to UNKNOWN nested socialProfile', () => {
const safeApp = safeAppBuilder()
.with('socialProfiles', [
safeAppSocialProfileBuilder()
.with('platform', 'invalid' as SafeAppSocialProfile['platform'])
.build(),
])
.build();

const result = SafeAppSchema.safeParse(safeApp);

expect(result.success && result.data.socialProfiles[0].platform).toBe(
'UNKNOWN',
);
});

it('should validate accessControl field', () => {
const safeApp = safeAppBuilder()
.with(
Expand Down
11 changes: 10 additions & 1 deletion src/domain/safe-apps/entities/schemas/safe-app.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,17 @@ export const SafeAppAccessControlSchema = z.discriminatedUnion('type', [
}),
]);

export enum SafeAppSocialProfilePlatforms {
Discord = 'DISCORD',
GitHub = 'GITHUB',
Twitter = 'TWITTER',
Unknown = 'UNKNOWN',
}

export const SafeAppSocialProfileSchema = z.object({
platform: z.string(),
platform: z
.nativeEnum(SafeAppSocialProfilePlatforms)
.catch(SafeAppSocialProfilePlatforms.Unknown),
url: z.string().url(),
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { ApiProperty } from '@nestjs/swagger';
import { SafeAppSocialProfile as DomainSafeAppSocialProfile } from '@/domain/safe-apps/entities/safe-app-social-profile.entity';
import { SafeAppSocialProfilePlatforms } from '@/domain/safe-apps/entities/schemas/safe-app.schema';

export class SafeAppSocialProfile implements DomainSafeAppSocialProfile {
@ApiProperty()
platform!: string;
@ApiProperty({ enum: SafeAppSocialProfilePlatforms })
platform!: SafeAppSocialProfilePlatforms;
@ApiProperty()
url!: string;
}

0 comments on commit a1c7f31

Please sign in to comment.