fix: improve environment validation in published docs (#5962)
This commit is contained in:
parent
eb801889ba
commit
bc3dbdea42
3 changed files with 68 additions and 41 deletions
|
|
@ -462,6 +462,12 @@ export const USER_ENVIRONMENT_IS_NOT_GLOBAL =
|
||||||
export const USER_ENVIRONMENT_UPDATE_FAILED =
|
export const USER_ENVIRONMENT_UPDATE_FAILED =
|
||||||
'user_environment/user_env_update_failed' as const;
|
'user_environment/user_env_update_failed' as const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User environment not found for the user
|
||||||
|
* (UserEnvironmentsService)
|
||||||
|
*/
|
||||||
|
export const USER_ENVIRONMENT_NOT_FOUND = 'user_environment/not_found' as const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User environment invalid environment name
|
* User environment invalid environment name
|
||||||
* (UserEnvironmentsService)
|
* (UserEnvironmentsService)
|
||||||
|
|
@ -977,8 +983,8 @@ export const PUBLISHED_DOCS_DELETION_FAILED = 'published_docs/deletion_failed';
|
||||||
* Published Docs invalid environment
|
* Published Docs invalid environment
|
||||||
* (PublishedDocsService)
|
* (PublishedDocsService)
|
||||||
*/
|
*/
|
||||||
export const PUBLISHED_DOCS_INVALID_ENVIRONMENT =
|
export const PUBLISHED_DOCS_FORBIDDEN_ENVIRONMENT_ACCESS =
|
||||||
'published_docs/invalid_environment';
|
'published_docs/forbidden_environment_access';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Published Docs not found
|
* Published Docs not found
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,12 @@ import {
|
||||||
PUBLISHED_DOCS_CREATION_FAILED,
|
PUBLISHED_DOCS_CREATION_FAILED,
|
||||||
PUBLISHED_DOCS_DELETION_FAILED,
|
PUBLISHED_DOCS_DELETION_FAILED,
|
||||||
PUBLISHED_DOCS_INVALID_COLLECTION,
|
PUBLISHED_DOCS_INVALID_COLLECTION,
|
||||||
PUBLISHED_DOCS_INVALID_ENVIRONMENT,
|
PUBLISHED_DOCS_FORBIDDEN_ENVIRONMENT_ACCESS,
|
||||||
PUBLISHED_DOCS_NOT_FOUND,
|
PUBLISHED_DOCS_NOT_FOUND,
|
||||||
PUBLISHED_DOCS_UPDATE_FAILED,
|
PUBLISHED_DOCS_UPDATE_FAILED,
|
||||||
|
TEAM_ENVIRONMENT_NOT_FOUND,
|
||||||
TEAM_INVALID_ID,
|
TEAM_INVALID_ID,
|
||||||
|
USER_ENVIRONMENT_NOT_FOUND,
|
||||||
} from 'src/errors';
|
} from 'src/errors';
|
||||||
import * as E from 'fp-ts/Either';
|
import * as E from 'fp-ts/Either';
|
||||||
import { PrismaService } from 'src/prisma/prisma.service';
|
import { PrismaService } from 'src/prisma/prisma.service';
|
||||||
|
|
@ -1491,7 +1493,7 @@ describe('createPublishedDoc - environment support', () => {
|
||||||
userUid: user.uid,
|
userUid: user.uid,
|
||||||
} as any);
|
} as any);
|
||||||
mockPrisma.publishedDocs.findFirst.mockResolvedValueOnce(null);
|
mockPrisma.publishedDocs.findFirst.mockResolvedValueOnce(null);
|
||||||
mockPrisma.userEnvironment.findFirst.mockResolvedValueOnce(envData as any);
|
mockPrisma.userEnvironment.findUnique.mockResolvedValueOnce(envData as any);
|
||||||
mockPrisma.publishedDocs.create.mockResolvedValueOnce({
|
mockPrisma.publishedDocs.create.mockResolvedValueOnce({
|
||||||
...userPublishedDoc,
|
...userPublishedDoc,
|
||||||
environmentID: 'env_1',
|
environmentID: 'env_1',
|
||||||
|
|
@ -1537,7 +1539,7 @@ describe('createPublishedDoc - environment support', () => {
|
||||||
teamID: 'team_1',
|
teamID: 'team_1',
|
||||||
} as any);
|
} as any);
|
||||||
mockPrisma.publishedDocs.findFirst.mockResolvedValueOnce(null);
|
mockPrisma.publishedDocs.findFirst.mockResolvedValueOnce(null);
|
||||||
mockPrisma.teamEnvironment.findFirst.mockResolvedValueOnce(envData as any);
|
mockPrisma.teamEnvironment.findUnique.mockResolvedValueOnce(envData as any);
|
||||||
mockPrisma.publishedDocs.create.mockResolvedValueOnce({
|
mockPrisma.publishedDocs.create.mockResolvedValueOnce({
|
||||||
...teamPublishedDoc,
|
...teamPublishedDoc,
|
||||||
environmentID: 'team_env_1',
|
environmentID: 'team_env_1',
|
||||||
|
|
@ -1568,14 +1570,14 @@ describe('createPublishedDoc - environment support', () => {
|
||||||
userUid: user.uid,
|
userUid: user.uid,
|
||||||
} as any);
|
} as any);
|
||||||
mockPrisma.publishedDocs.findFirst.mockResolvedValueOnce(null);
|
mockPrisma.publishedDocs.findFirst.mockResolvedValueOnce(null);
|
||||||
mockPrisma.userEnvironment.findFirst.mockResolvedValueOnce(null);
|
mockPrisma.userEnvironment.findUnique.mockResolvedValueOnce(null);
|
||||||
|
|
||||||
const result = await publishedDocsService.createPublishedDoc(
|
const result = await publishedDocsService.createPublishedDoc(
|
||||||
{ ...createArgs, environmentID: 'invalid_env' },
|
{ ...createArgs, environmentID: 'invalid_env' },
|
||||||
user,
|
user,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result).toEqualLeft(PUBLISHED_DOCS_INVALID_ENVIRONMENT);
|
expect(result).toEqualLeft(USER_ENVIRONMENT_NOT_FOUND);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should return error when team environment ID is invalid', async () => {
|
test('should return error when team environment ID is invalid', async () => {
|
||||||
|
|
@ -1593,14 +1595,14 @@ describe('createPublishedDoc - environment support', () => {
|
||||||
teamID: 'team_1',
|
teamID: 'team_1',
|
||||||
} as any);
|
} as any);
|
||||||
mockPrisma.publishedDocs.findFirst.mockResolvedValueOnce(null);
|
mockPrisma.publishedDocs.findFirst.mockResolvedValueOnce(null);
|
||||||
mockPrisma.teamEnvironment.findFirst.mockResolvedValueOnce(null);
|
mockPrisma.teamEnvironment.findUnique.mockResolvedValueOnce(null);
|
||||||
|
|
||||||
const result = await publishedDocsService.createPublishedDoc(
|
const result = await publishedDocsService.createPublishedDoc(
|
||||||
teamArgs,
|
teamArgs,
|
||||||
user,
|
user,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result).toEqualLeft(PUBLISHED_DOCS_INVALID_ENVIRONMENT);
|
expect(result).toEqualLeft(TEAM_ENVIRONMENT_NOT_FOUND);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should create published doc without environment when environmentID is not provided', async () => {
|
test('should create published doc without environment when environmentID is not provided', async () => {
|
||||||
|
|
@ -1640,7 +1642,7 @@ describe('updatePublishedDoc - environment support', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
mockPrisma.publishedDocs.findUnique.mockResolvedValueOnce(userPublishedDoc);
|
mockPrisma.publishedDocs.findUnique.mockResolvedValueOnce(userPublishedDoc);
|
||||||
mockPrisma.userEnvironment.findFirst.mockResolvedValueOnce(envData as any);
|
mockPrisma.userEnvironment.findUnique.mockResolvedValueOnce(envData as any);
|
||||||
mockPrisma.publishedDocs.update.mockResolvedValueOnce({
|
mockPrisma.publishedDocs.update.mockResolvedValueOnce({
|
||||||
...userPublishedDoc,
|
...userPublishedDoc,
|
||||||
environmentID: 'env_2',
|
environmentID: 'env_2',
|
||||||
|
|
@ -1701,7 +1703,7 @@ describe('updatePublishedDoc - environment support', () => {
|
||||||
|
|
||||||
test('should return error when updating with invalid environment ID', async () => {
|
test('should return error when updating with invalid environment ID', async () => {
|
||||||
mockPrisma.publishedDocs.findUnique.mockResolvedValueOnce(userPublishedDoc);
|
mockPrisma.publishedDocs.findUnique.mockResolvedValueOnce(userPublishedDoc);
|
||||||
mockPrisma.userEnvironment.findFirst.mockResolvedValueOnce(null);
|
mockPrisma.userEnvironment.findUnique.mockResolvedValueOnce(null);
|
||||||
|
|
||||||
const result = await publishedDocsService.updatePublishedDoc(
|
const result = await publishedDocsService.updatePublishedDoc(
|
||||||
userPublishedDoc.id,
|
userPublishedDoc.id,
|
||||||
|
|
@ -1709,7 +1711,7 @@ describe('updatePublishedDoc - environment support', () => {
|
||||||
user,
|
user,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result).toEqualLeft(PUBLISHED_DOCS_INVALID_ENVIRONMENT);
|
expect(result).toEqualLeft(USER_ENVIRONMENT_NOT_FOUND);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not change environment when environmentID is not provided in update args', async () => {
|
test('should not change environment when environmentID is not provided in update args', async () => {
|
||||||
|
|
@ -1743,7 +1745,7 @@ describe('updatePublishedDoc - environment support', () => {
|
||||||
|
|
||||||
mockPrisma.publishedDocs.findUnique.mockResolvedValueOnce(teamPublishedDoc);
|
mockPrisma.publishedDocs.findUnique.mockResolvedValueOnce(teamPublishedDoc);
|
||||||
mockPrisma.team.findFirst.mockResolvedValueOnce({ id: 'team_1' } as any);
|
mockPrisma.team.findFirst.mockResolvedValueOnce({ id: 'team_1' } as any);
|
||||||
mockPrisma.teamEnvironment.findFirst.mockResolvedValueOnce(envData as any);
|
mockPrisma.teamEnvironment.findUnique.mockResolvedValueOnce(envData as any);
|
||||||
mockPrisma.publishedDocs.update.mockResolvedValueOnce({
|
mockPrisma.publishedDocs.update.mockResolvedValueOnce({
|
||||||
...teamPublishedDoc,
|
...teamPublishedDoc,
|
||||||
environmentID: 'team_env_1',
|
environmentID: 'team_env_1',
|
||||||
|
|
@ -1796,7 +1798,7 @@ describe('getPublishedDocBySlugPublic - environment support', () => {
|
||||||
mockUserCollectionService.exportUserCollectionToJSONObject.mockResolvedValueOnce(
|
mockUserCollectionService.exportUserCollectionToJSONObject.mockResolvedValueOnce(
|
||||||
E.right(collectionData as any),
|
E.right(collectionData as any),
|
||||||
);
|
);
|
||||||
mockPrisma.userEnvironment.findFirst.mockResolvedValueOnce(envData as any);
|
mockPrisma.userEnvironment.findUnique.mockResolvedValueOnce(envData as any);
|
||||||
|
|
||||||
const result = await publishedDocsService.getPublishedDocBySlugPublic(
|
const result = await publishedDocsService.getPublishedDocBySlugPublic(
|
||||||
'slug-collection-1',
|
'slug-collection-1',
|
||||||
|
|
@ -1894,14 +1896,14 @@ describe('getPublishedDocBySlugPublic - environment support', () => {
|
||||||
E.right(collectionData as any),
|
E.right(collectionData as any),
|
||||||
);
|
);
|
||||||
// Environment not found — fetchEnvironment returns Left
|
// Environment not found — fetchEnvironment returns Left
|
||||||
mockPrisma.userEnvironment.findFirst.mockResolvedValueOnce(null);
|
mockPrisma.userEnvironment.findUnique.mockResolvedValueOnce(null);
|
||||||
|
|
||||||
const result = await publishedDocsService.getPublishedDocBySlugPublic(
|
const result = await publishedDocsService.getPublishedDocBySlugPublic(
|
||||||
'slug-collection-1',
|
'slug-collection-1',
|
||||||
'1.0.0',
|
'1.0.0',
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result).toEqualLeft(PUBLISHED_DOCS_INVALID_ENVIRONMENT);
|
expect(result).toEqualLeft(USER_ENVIRONMENT_NOT_FOUND);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should return null environment fields when no environment is associated', async () => {
|
test('should return null environment fields when no environment is associated', async () => {
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,14 @@ import {
|
||||||
PUBLISHED_DOCS_CREATION_FAILED,
|
PUBLISHED_DOCS_CREATION_FAILED,
|
||||||
PUBLISHED_DOCS_DELETION_FAILED,
|
PUBLISHED_DOCS_DELETION_FAILED,
|
||||||
PUBLISHED_DOCS_INVALID_COLLECTION,
|
PUBLISHED_DOCS_INVALID_COLLECTION,
|
||||||
PUBLISHED_DOCS_INVALID_ENVIRONMENT,
|
PUBLISHED_DOCS_FORBIDDEN_ENVIRONMENT_ACCESS,
|
||||||
PUBLISHED_DOCS_NOT_FOUND,
|
PUBLISHED_DOCS_NOT_FOUND,
|
||||||
PUBLISHED_DOCS_UPDATE_FAILED,
|
PUBLISHED_DOCS_UPDATE_FAILED,
|
||||||
|
TEAM_ENVIRONMENT_NOT_FOUND,
|
||||||
TEAM_INVALID_COLL_ID,
|
TEAM_INVALID_COLL_ID,
|
||||||
TEAM_INVALID_ID,
|
TEAM_INVALID_ID,
|
||||||
USER_COLL_NOT_FOUND,
|
USER_COLL_NOT_FOUND,
|
||||||
|
USER_ENVIRONMENT_NOT_FOUND,
|
||||||
} from 'src/errors';
|
} from 'src/errors';
|
||||||
import * as E from 'fp-ts/Either';
|
import * as E from 'fp-ts/Either';
|
||||||
import { PublishedDocs, PublishedDocsVersion } from './published-docs.model';
|
import { PublishedDocs, PublishedDocsVersion } from './published-docs.model';
|
||||||
|
|
@ -100,22 +102,43 @@ export class PublishedDocsService {
|
||||||
environmentID: string,
|
environmentID: string,
|
||||||
workspaceType: WorkspaceType,
|
workspaceType: WorkspaceType,
|
||||||
workspaceID: string,
|
workspaceID: string,
|
||||||
): Promise<E.Either<string, { name: string; variables: JsonValue } | null>> {
|
): Promise<E.Either<string, { name: string; variables: JsonValue }>> {
|
||||||
|
// TEAM workspace environment
|
||||||
if (workspaceType === WorkspaceType.TEAM) {
|
if (workspaceType === WorkspaceType.TEAM) {
|
||||||
const env = await this.prisma.teamEnvironment.findFirst({
|
const env = await this.prisma.teamEnvironment.findUnique({
|
||||||
where: { id: environmentID, teamID: workspaceID },
|
where: { id: environmentID },
|
||||||
});
|
});
|
||||||
if (!env) return E.left(PUBLISHED_DOCS_INVALID_ENVIRONMENT);
|
if (!env) return E.left(TEAM_ENVIRONMENT_NOT_FOUND);
|
||||||
return E.right({ name: env.name, variables: env.variables });
|
|
||||||
} else if (workspaceType === WorkspaceType.USER) {
|
// Validate environment exists and belongs to the correct team
|
||||||
const env = await this.prisma.userEnvironment.findFirst({
|
if (env.teamID !== workspaceID)
|
||||||
where: { id: environmentID, userUid: workspaceID },
|
return E.left(PUBLISHED_DOCS_FORBIDDEN_ENVIRONMENT_ACCESS);
|
||||||
|
|
||||||
|
return E.right({
|
||||||
|
name: env.name,
|
||||||
|
variables: env.variables,
|
||||||
});
|
});
|
||||||
if (!env) return E.left(PUBLISHED_DOCS_INVALID_ENVIRONMENT);
|
|
||||||
return E.right({ name: env.name ?? '', variables: env.variables });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return E.left(PUBLISHED_DOCS_INVALID_ENVIRONMENT);
|
// USER workspace environment
|
||||||
|
if (workspaceType === WorkspaceType.USER) {
|
||||||
|
const env = await this.prisma.userEnvironment.findUnique({
|
||||||
|
where: { id: environmentID },
|
||||||
|
});
|
||||||
|
if (!env) return E.left(USER_ENVIRONMENT_NOT_FOUND);
|
||||||
|
|
||||||
|
// Validate environment exists and belongs to the correct user
|
||||||
|
if (env.userUid !== workspaceID) {
|
||||||
|
return E.left(PUBLISHED_DOCS_FORBIDDEN_ENVIRONMENT_ACCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return E.right({
|
||||||
|
name: env.name ?? '',
|
||||||
|
variables: env.variables,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return E.left(PUBLISHED_DOCS_FORBIDDEN_ENVIRONMENT_ACCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -368,11 +391,9 @@ export class PublishedDocsService {
|
||||||
);
|
);
|
||||||
if (E.isLeft(envResult)) return E.left(envResult.left);
|
if (E.isLeft(envResult)) return E.left(envResult.left);
|
||||||
|
|
||||||
if (E.isRight(envResult) && envResult.right) {
|
|
||||||
environmentName = envResult.right.name;
|
environmentName = envResult.right.name;
|
||||||
environmentVariables = envResult.right.variables;
|
environmentVariables = envResult.right.variables;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
docToReturn = {
|
docToReturn = {
|
||||||
...publishedDocs,
|
...publishedDocs,
|
||||||
|
|
@ -577,11 +598,10 @@ export class PublishedDocsService {
|
||||||
workspaceID,
|
workspaceID,
|
||||||
);
|
);
|
||||||
if (E.isLeft(envResult)) return E.left(envResult.left);
|
if (E.isLeft(envResult)) return E.left(envResult.left);
|
||||||
if (envResult.right) {
|
|
||||||
environmentName = envResult.right.name;
|
environmentName = envResult.right.name;
|
||||||
environmentVariables = envResult.right.variables;
|
environmentVariables = envResult.right.variables;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to create the published document
|
// Attempt to create the published document
|
||||||
const newPublishedDoc = await this.prisma.publishedDocs.create({
|
const newPublishedDoc = await this.prisma.publishedDocs.create({
|
||||||
|
|
@ -697,13 +717,12 @@ export class PublishedDocsService {
|
||||||
publishedDocs.workspaceID,
|
publishedDocs.workspaceID,
|
||||||
);
|
);
|
||||||
if (E.isLeft(envResult)) return E.left(envResult.left);
|
if (E.isLeft(envResult)) return E.left(envResult.left);
|
||||||
if (envResult.right) {
|
|
||||||
environmentID = args.environmentID;
|
environmentID = args.environmentID;
|
||||||
environmentName = envResult.right.name;
|
environmentName = envResult.right.name;
|
||||||
environmentVariables = envResult.right.variables;
|
environmentVariables = envResult.right.variables;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Update published document
|
// Update published document
|
||||||
const updatedPublishedDoc = await this.prisma.publishedDocs.update({
|
const updatedPublishedDoc = await this.prisma.publishedDocs.update({
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue