mirror of
https://github.com/OneUptime/oneuptime
synced 2024-11-21 22:59:07 +00:00
refactor: Update GitHub token handling in Config.ts
The Config.ts file has been updated to handle the GitHub token more efficiently. The GetGitHubToken function now checks the repository type and throws an exception if a GitHub token is required but not provided. This change improves the security and reliability of the application by ensuring that the correct token is used for GitHub repositories.
This commit is contained in:
parent
e719bb3b70
commit
64acf372d6
6
Common/Types/CodeRepository/CodeRepositoryType.ts
Normal file
6
Common/Types/CodeRepository/CodeRepositoryType.ts
Normal file
@ -0,0 +1,6 @@
|
||||
enum CodeRepositoryType {
|
||||
GitHub = "GitHub",
|
||||
GitLab = "GitLab",
|
||||
}
|
||||
|
||||
export default CodeRepositoryType;
|
11
Common/Utils/Enum.ts
Normal file
11
Common/Utils/Enum.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import GenericObject from "../Types/GenericObject";
|
||||
|
||||
export default class EnumUtil {
|
||||
public static isValidEnumValue<T extends GenericObject>(enumType: T, value: any): boolean {
|
||||
return this.getValues(enumType).includes(value);
|
||||
}
|
||||
|
||||
public static getValues<T extends GenericObject>(enumType: T): Array<string> {
|
||||
return Object.values(enumType);
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
import ServiceRepository from 'Model/Models/ServiceRepository';
|
||||
import UserMiddleware from '../Middleware/UserAuthorization';
|
||||
import CodeRepositoryService, {
|
||||
Service as CodeRepositoryServiceType,
|
||||
} from '../Services/CodeRepositoryService';
|
||||
import ServiceRepositoryService from '../Services/ServiceRepositoryService';
|
||||
import {
|
||||
ExpressRequest,
|
||||
ExpressResponse,
|
||||
@ -12,6 +14,7 @@ import BaseAPI from './BaseAPI';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import CodeRepository from 'Model/Models/CodeRepository';
|
||||
import { LIMIT_PER_PROJECT } from 'Common/Types/Database/LimitMax';
|
||||
|
||||
export default class CodeRepositoryAPI extends BaseAPI<
|
||||
CodeRepository,
|
||||
@ -44,17 +47,46 @@ export default class CodeRepositoryAPI extends BaseAPI<
|
||||
},
|
||||
select: {
|
||||
name: true,
|
||||
mainBranchName: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
return Response.sendEntityResponse(
|
||||
if(!codeRepository) {
|
||||
throw new BadDataException('Code repository not found');
|
||||
}
|
||||
|
||||
|
||||
const servicesRepository: Array<ServiceRepository> = await ServiceRepositoryService.findBy({
|
||||
query: {
|
||||
codeRepositoryId: codeRepository.id!,
|
||||
enablePullRequests: true,
|
||||
},
|
||||
select: {
|
||||
serviceCatalog: {
|
||||
name: true,
|
||||
_id: true,
|
||||
},
|
||||
servicePathInRepository: true,
|
||||
limitNumberOfOpenPullRequestsCount: true,
|
||||
},
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
skip: 0,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
return Response.sendJsonObjectResponse(
|
||||
req,
|
||||
res,
|
||||
codeRepository,
|
||||
CodeRepository
|
||||
{
|
||||
"codeRepository": CodeRepository.toJSON(codeRepository, CodeRepository),
|
||||
"servicesRepository": ServiceRepository.toJSONArray(servicesRepository, ServiceRepository),
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
|
@ -0,0 +1,17 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class MigrationName1718186569787 implements MigrationInterface {
|
||||
public name = 'MigrationName1718186569787';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "CodeRepository" DROP COLUMN "mainBranchName"`
|
||||
);
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ import { MigrationName1718101665865 } from './1718101665865-MigrationName';
|
||||
import { MigrationName1718119926223 } from './1718119926223-MigrationName';
|
||||
import { MigrationName1718124277321 } from './1718124277321-MigrationName';
|
||||
import { MigrationName1718126316684 } from './1718126316684-MigrationName';
|
||||
import { MigrationName1718186569787 } from './1718186569787-MigrationName';
|
||||
|
||||
export default [
|
||||
InitialMigration,
|
||||
@ -21,5 +22,6 @@ export default [
|
||||
MigrationName1718101665865,
|
||||
MigrationName1718119926223,
|
||||
MigrationName1718124277321,
|
||||
MigrationName1718126316684
|
||||
MigrationName1718126316684,
|
||||
MigrationName1718186569787,
|
||||
];
|
||||
|
@ -1,3 +1,4 @@
|
||||
ONEUPTIME_URL=https://oneuptime.com
|
||||
ONEUPTIME_REPOSITORY_SECRET_KEY=your-repository-secret-key
|
||||
ONEUPTIME_LOCAL_REPOSITORY_PATH=/repository
|
||||
GITHUB_TOKEN=
|
||||
|
@ -1,4 +1,7 @@
|
||||
import URL from 'Common/Types/API/URL';
|
||||
import CodeRepositoryType from 'Common/Types/CodeRepository/CodeRepositoryType';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import EnumUtil from 'Common/Utils/Enum';
|
||||
|
||||
type GetStringFunction = () => string;
|
||||
type GetURLFunction = () => URL;
|
||||
@ -16,3 +19,30 @@ export const GetRepositorySecretKey: GetStringFunction = (): string => {
|
||||
export const GetLocalRepositoryPath: GetStringFunction = (): string => {
|
||||
return process.env['ONEUPTIME_LOCAL_REPOSITORY_PATH'] || '/repository';
|
||||
};
|
||||
|
||||
export const GetRepositoryType: GetStringFunction = (): CodeRepositoryType => {
|
||||
const repoType: string | undefined = process.env['REPOSITORY_TYPE'];
|
||||
|
||||
if(!repoType) {
|
||||
return CodeRepositoryType.GitHub;
|
||||
}
|
||||
|
||||
if(EnumUtil.isValidEnumValue(CodeRepositoryType, repoType)) {
|
||||
return repoType as CodeRepositoryType;
|
||||
}
|
||||
// check if the repository type is valid and is from the values in the enum.
|
||||
|
||||
throw new BadDataException(`Invalid Repository Type ${repoType}. It should be one of ${EnumUtil.getValues(CodeRepositoryType).join(', ')}`);
|
||||
};
|
||||
|
||||
|
||||
export const GetGitHubToken: GetStringFunction = (): string => {
|
||||
const token: string = process.env['GITHUB_TOKEN'] || '';
|
||||
|
||||
|
||||
if(GetRepositoryType() === CodeRepositoryType.GitHub && !token) {
|
||||
throw new BadDataException('GitHub Token is required for GitHub Repository');
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
@ -1,22 +1,23 @@
|
||||
import { GetLocalRepositoryPath } from './Config';
|
||||
import CodeRepositoryUtil from './Utils/CodeRepository';
|
||||
import CodeRepositoryUtil, { CodeRepositoryResult } from './Utils/CodeRepository';
|
||||
import Dictionary from 'Common/Types/Dictionary';
|
||||
import { PromiseVoidFunction } from 'Common/Types/FunctionTypes';
|
||||
import CodeRepositoryCommonServerUtil from 'CommonServer/Utils/CodeRepository/CodeRepository';
|
||||
import CodeRepositoryFile from 'CommonServer/Utils/CodeRepository/CodeRepositoryFile';
|
||||
import logger from 'CommonServer/Utils/Logger';
|
||||
import CodeRepository from 'Model/Models/CodeRepository';
|
||||
import dotenv from 'dotenv';
|
||||
import InitUtil from './Utils/Init';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
logger.info('OneUptime Copilot is starting...');
|
||||
|
||||
const init: PromiseVoidFunction = async (): Promise<void> => {
|
||||
const codeRepository: CodeRepository =
|
||||
await CodeRepositoryUtil.getCodeRepository();
|
||||
|
||||
logger.info(`Code Repository found: ${codeRepository.name}`);
|
||||
await InitUtil.validate(); // validate all the configurations
|
||||
|
||||
const codeRepositoryResult: CodeRepositoryResult =
|
||||
await CodeRepositoryUtil.getCodeRepository();
|
||||
|
||||
const allFiles: Dictionary<CodeRepositoryFile> =
|
||||
await CodeRepositoryCommonServerUtil.getFilesInDirectoryRecursive({
|
||||
|
@ -3,12 +3,19 @@ import HTTPErrorResponse from 'Common/Types/API/HTTPErrorResponse';
|
||||
import HTTPResponse from 'Common/Types/API/HTTPResponse';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import { JSONArray, JSONObject } from 'Common/Types/JSON';
|
||||
import API from 'Common/Utils/API';
|
||||
import logger from 'CommonServer/Utils/Logger';
|
||||
import CodeRepositoryModel from 'Model/Models/CodeRepository';
|
||||
import ServiceRepository from 'Model/Models/ServiceRepository';
|
||||
|
||||
export interface CodeRepositoryResult {
|
||||
codeRepository: CodeRepositoryModel;
|
||||
servicesRepository: Array<ServiceRepository>;
|
||||
}
|
||||
|
||||
export default class CodeRepositoryUtil {
|
||||
public static async getCodeRepository(): Promise<CodeRepositoryModel> {
|
||||
public static async getCodeRepository(): Promise<CodeRepositoryResult> {
|
||||
const repositorySecretKey: string = GetRepositorySecretKey();
|
||||
|
||||
if (!repositorySecretKey) {
|
||||
@ -33,16 +40,42 @@ export default class CodeRepositoryUtil {
|
||||
|
||||
const codeRepository: CodeRepositoryModel =
|
||||
CodeRepositoryModel.fromJSON(
|
||||
codeRepositoryResult.data as JSONObject,
|
||||
codeRepositoryResult.data['codeRepository'] as JSONObject,
|
||||
CodeRepositoryModel
|
||||
) as CodeRepositoryModel;
|
||||
|
||||
const servicesRepository: Array<ServiceRepository> =
|
||||
(codeRepositoryResult.data['servicesRepository'] as JSONArray).map(
|
||||
(serviceRepository: JSONObject) =>
|
||||
ServiceRepository.fromJSON(
|
||||
serviceRepository,
|
||||
ServiceRepository
|
||||
) as ServiceRepository
|
||||
);
|
||||
|
||||
if (!codeRepository) {
|
||||
throw new BadDataException(
|
||||
'Code Repository not found with the secret key provided.'
|
||||
);
|
||||
}
|
||||
|
||||
return codeRepository;
|
||||
if (!servicesRepository || servicesRepository.length === 0) {
|
||||
throw new BadDataException(
|
||||
'No services attached to this repository. Please attach services to this repository on OneUptime Dashboard.'
|
||||
);
|
||||
}
|
||||
|
||||
logger.info(`Code Repository found: ${codeRepository.name}`);
|
||||
|
||||
logger.info('Services found in the repository:');
|
||||
|
||||
servicesRepository.forEach((serviceRepository: ServiceRepository) => {
|
||||
logger.info(`- ${serviceRepository.serviceCatalog?.name}`);
|
||||
});
|
||||
|
||||
return {
|
||||
codeRepository,
|
||||
servicesRepository,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
18
Copilot/Utils/Init.ts
Normal file
18
Copilot/Utils/Init.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import CodeRepositoryType from "Common/Types/CodeRepository/CodeRepositoryType";
|
||||
import { GetGitHubToken, GetRepositorySecretKey, GetRepositoryType } from "../Config";
|
||||
import BadDataException from "Common/Types/Exception/BadDataException";
|
||||
|
||||
export default class InitUtil {
|
||||
public static async validate(): Promise<void> {
|
||||
|
||||
// Check if the repository type is GitHub and the GitHub token is provided
|
||||
if(GetRepositoryType() === CodeRepositoryType.GitHub && !GetGitHubToken()){
|
||||
throw new BadDataException("GitHub token is required");
|
||||
}
|
||||
|
||||
|
||||
if(!GetRepositorySecretKey()){
|
||||
throw new BadDataException("Repository Secret Key is required");
|
||||
}
|
||||
}
|
||||
}
|
@ -138,9 +138,7 @@ const ServiceRepositoryPage: FunctionComponent<PageComponentProps> = (
|
||||
|
||||
getElement: (item: ServiceRepository): ReactElement => {
|
||||
if (!item['serviceCatalog']) {
|
||||
throw new BadDataException(
|
||||
'Service not found'
|
||||
);
|
||||
throw new BadDataException('Service not found');
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -460,4 +460,39 @@ export default class CodeRepository extends BaseModel {
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public secretToken?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateCodeRepository,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadCodeRepository,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.EditCodeRepository,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
required: true,
|
||||
type: TableColumnType.ShortText,
|
||||
canReadOnRelationQuery: true,
|
||||
title: 'Main Branch Name',
|
||||
description: 'Name of the main branch of this repository',
|
||||
})
|
||||
@Column({
|
||||
nullable: false,
|
||||
type: ColumnType.ShortText,
|
||||
length: ColumnLength.ShortText,
|
||||
})
|
||||
public mainBranchName?: string = undefined;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user