Files
bpsets/src/bpsets/codeseries/CodeBuildProjectLoggingEnabled.ts
Minhyeok Park 2b0b862345
All checks were successful
/ deploy_site (push) Successful in 2m24s
feat: move external metadata to embeded
2025-01-02 20:11:14 +09:00

146 lines
4.2 KiB
TypeScript

import {
CodeBuildClient,
ListProjectsCommand,
BatchGetProjectsCommand,
UpdateProjectCommand,
} from '@aws-sdk/client-codebuild';
import { BPSet, BPSetFixFn, BPSetStats } from '../../types';
import { Memorizer } from '../../Memorizer';
export class CodeBuildProjectLoggingEnabled implements BPSet {
private readonly client = new CodeBuildClient({});
private readonly memoClient = Memorizer.memo(this.client);
private readonly getProjects = async () => {
const projectNames = await this.memoClient.send(new ListProjectsCommand({}));
if (!projectNames.projects?.length) {
return [];
}
const response = await this.memoClient.send(
new BatchGetProjectsCommand({ names: projectNames.projects })
);
return response.projects || [];
};
public readonly getMetadata = () => ({
name: 'CodeBuildProjectLoggingEnabled',
description: 'Ensures that logging is enabled for AWS CodeBuild projects.',
priority: 3,
priorityReason: 'Enabling logging allows for monitoring and debugging build processes effectively.',
awsService: 'CodeBuild',
awsServiceCategory: 'Build',
bestPracticeCategory: 'Logging and Monitoring',
requiredParametersForFix: [],
isFixFunctionUsesDestructiveCommand: false,
commandUsedInCheckFunction: [
{
name: 'ListProjectsCommand',
reason: 'Retrieve all CodeBuild projects to verify logging settings.',
},
{
name: 'BatchGetProjectsCommand',
reason: 'Fetch detailed configuration for each CodeBuild project.',
},
],
commandUsedInFixFunction: [
{
name: 'UpdateProjectCommand',
reason: 'Enable logging for projects that have it disabled.',
},
],
adviseBeforeFixFunction: 'Ensure the default log group and stream names are suitable for your organization.',
});
private readonly stats: BPSetStats = {
nonCompliantResources: [],
compliantResources: [],
status: 'LOADED',
errorMessage: [],
};
public readonly getStats = () => this.stats;
public readonly clearStats = () => {
this.stats.compliantResources = [];
this.stats.nonCompliantResources = [];
this.stats.status = 'LOADED';
this.stats.errorMessage = [];
};
public readonly check = async () => {
this.stats.status = 'CHECKING';
await this.checkImpl().then(
() => (this.stats.status = 'FINISHED'),
(err) => {
this.stats.status = 'ERROR';
this.stats.errorMessage.push({
date: new Date(),
message: err.message,
});
}
);
};
private readonly checkImpl = async () => {
const compliantResources: string[] = [];
const nonCompliantResources: string[] = [];
const projects = await this.getProjects();
for (const project of projects) {
const logsConfig = project.logsConfig;
if (
logsConfig?.cloudWatchLogs?.status === 'ENABLED' ||
logsConfig?.s3Logs?.status === 'ENABLED'
) {
compliantResources.push(project.arn!);
} else {
nonCompliantResources.push(project.arn!);
}
}
this.stats.compliantResources = compliantResources;
this.stats.nonCompliantResources = nonCompliantResources;
};
public readonly fix: BPSetFixFn = async (...args) => {
await this.fixImpl(...args).then(
() => (this.stats.status = 'FINISHED'),
(err) => {
this.stats.status = 'ERROR';
this.stats.errorMessage.push({
date: new Date(),
message: err.message,
});
}
);
};
public readonly fixImpl: BPSetFixFn = async (nonCompliantResources) => {
const projects = await this.getProjects();
for (const arn of nonCompliantResources) {
const projectName = arn.split(':').pop()!;
const projectToFix = projects.find((project) => project.arn === arn);
if (!projectToFix) {
continue;
}
await this.client.send(
new UpdateProjectCommand({
name: projectName,
logsConfig: {
...projectToFix.logsConfig,
cloudWatchLogs: {
status: 'ENABLED',
groupName: 'default-cloudwatch-group',
streamName: 'default-stream',
},
},
})
);
}
};
}