refactor: improve type safety and enhance AWS SDK integration
All checks were successful
/ deploy_site (push) Successful in 2m14s
All checks were successful
/ deploy_site (push) Successful in 2m14s
- Updated the `Memorizer` class to use a more specific `AnyClient` type for AWS SDK clients. - Enhanced type safety in various AWS service classes by replacing `unknown` casts with specific types (e.g., `AuthorizationType`, `DistributionConfig`, `PolicyDocument`). - Refactored error handling to ensure proper type assertions for error objects across multiple services. - Simplified the `fix` method signatures in several classes to accept only non-compliant resources, improving clarity and usability.
This commit is contained in:
@ -1,6 +1,9 @@
|
||||
import { Client } from '@smithy/smithy-client'
|
||||
import shajs from 'sha.js'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type AnyClient = Client<any, any, any, any>
|
||||
|
||||
/**
|
||||
* Memorize AWS SDK operation results.
|
||||
* This util class tend to be always re-use AWS SDK Client
|
||||
@ -15,7 +18,7 @@ import shajs from 'sha.js'
|
||||
export class Memorizer {
|
||||
private static memorized = new Map<string, Memorizer>()
|
||||
|
||||
public static memo(client: Client<unknown, unknown, unknown, unknown>, salt = '') {
|
||||
public static memo(client: AnyClient, salt = '') {
|
||||
const serialized = JSON.stringify([client.constructor.name, salt])
|
||||
const hashed = shajs('sha256').update(serialized).digest('hex')
|
||||
|
||||
@ -35,7 +38,7 @@ export class Memorizer {
|
||||
|
||||
private memorized = new Map<string, unknown>()
|
||||
|
||||
private constructor(private client: Client<unknown, unknown, unknown, unknown>) {}
|
||||
private constructor(private client: AnyClient) {}
|
||||
|
||||
public readonly send: typeof this.client.send = async (command) => {
|
||||
const serialized = JSON.stringify([command.constructor.name, command.input])
|
||||
|
@ -1,4 +1,10 @@
|
||||
import { ApiGatewayV2Client, GetApisCommand, GetRoutesCommand, UpdateRouteCommand } from '@aws-sdk/client-apigatewayv2'
|
||||
import {
|
||||
ApiGatewayV2Client,
|
||||
AuthorizationType,
|
||||
GetApisCommand,
|
||||
GetRoutesCommand,
|
||||
UpdateRouteCommand
|
||||
} from '@aws-sdk/client-apigatewayv2'
|
||||
import { BPSet, BPSetFixFn, BPSetStats } from '../../types'
|
||||
import { Memorizer } from '../../Memorizer'
|
||||
|
||||
@ -135,7 +141,7 @@ export class APIGatewayV2AuthorizationTypeConfigured implements BPSet {
|
||||
new UpdateRouteCommand({
|
||||
ApiId: api.ApiId!,
|
||||
RouteId: route.RouteId!,
|
||||
AuthorizationType: authorizationType as unknown
|
||||
AuthorizationType: authorizationType as AuthorizationType
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ import {
|
||||
CloudFrontClient,
|
||||
ListDistributionsCommand,
|
||||
GetDistributionCommand,
|
||||
UpdateDistributionCommand
|
||||
UpdateDistributionCommand,
|
||||
DistributionConfig
|
||||
} from '@aws-sdk/client-cloudfront'
|
||||
import { BPSet, BPSetFixFn, BPSetStats } from '../../types'
|
||||
import { Memorizer } from '../../Memorizer'
|
||||
@ -147,7 +148,7 @@ export class CloudFrontAccessLogsEnabled implements BPSet {
|
||||
new UpdateDistributionCommand({
|
||||
Id: distributionId,
|
||||
IfMatch: etag,
|
||||
DistributionConfig: updatedConfig as unknown
|
||||
DistributionConfig: updatedConfig as DistributionConfig
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ import {
|
||||
CloudFrontClient,
|
||||
ListDistributionsCommand,
|
||||
GetDistributionCommand,
|
||||
UpdateDistributionCommand
|
||||
UpdateDistributionCommand,
|
||||
DistributionConfig
|
||||
} from '@aws-sdk/client-cloudfront'
|
||||
import { BPSet, BPSetFixFn, BPSetStats } from '../../types'
|
||||
import { Memorizer } from '../../Memorizer'
|
||||
@ -137,7 +138,7 @@ export class CloudFrontAssociatedWithWAF implements BPSet {
|
||||
new UpdateDistributionCommand({
|
||||
Id: distributionId,
|
||||
IfMatch: etag,
|
||||
DistributionConfig: updatedConfig as unknown
|
||||
DistributionConfig: updatedConfig as DistributionConfig
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ import {
|
||||
CloudFrontClient,
|
||||
ListDistributionsCommand,
|
||||
GetDistributionCommand,
|
||||
UpdateDistributionCommand
|
||||
UpdateDistributionCommand,
|
||||
DistributionConfig
|
||||
} from '@aws-sdk/client-cloudfront'
|
||||
import { BPSet, BPSetFixFn, BPSetStats } from '../../types'
|
||||
import { Memorizer } from '../../Memorizer'
|
||||
@ -143,7 +144,7 @@ export class CloudFrontDefaultRootObjectConfigured implements BPSet {
|
||||
new UpdateDistributionCommand({
|
||||
Id: distributionId,
|
||||
IfMatch: etag,
|
||||
DistributionConfig: updatedConfig as unknown
|
||||
DistributionConfig: updatedConfig as DistributionConfig
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ import {
|
||||
CloudFrontClient,
|
||||
ListDistributionsCommand,
|
||||
GetDistributionCommand,
|
||||
UpdateDistributionCommand
|
||||
UpdateDistributionCommand,
|
||||
DistributionConfig
|
||||
} from '@aws-sdk/client-cloudfront'
|
||||
import { BPSet, BPSetFixFn, BPSetStats } from '../../types'
|
||||
import { Memorizer } from '../../Memorizer'
|
||||
@ -151,7 +152,7 @@ export class CloudFrontNoDeprecatedSSLProtocols implements BPSet {
|
||||
new UpdateDistributionCommand({
|
||||
Id: distributionId,
|
||||
IfMatch: etag,
|
||||
DistributionConfig: updatedConfig as unknown
|
||||
DistributionConfig: updatedConfig as DistributionConfig
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ import {
|
||||
CloudFrontClient,
|
||||
ListDistributionsCommand,
|
||||
GetDistributionCommand,
|
||||
UpdateDistributionCommand
|
||||
UpdateDistributionCommand,
|
||||
DistributionConfig
|
||||
} from '@aws-sdk/client-cloudfront'
|
||||
import { BPSet, BPSetFixFn, BPSetStats } from '../../types'
|
||||
import { Memorizer } from '../../Memorizer'
|
||||
@ -160,7 +161,7 @@ export class CloudFrontS3OriginAccessControlEnabled implements BPSet {
|
||||
new UpdateDistributionCommand({
|
||||
Id: distributionId,
|
||||
IfMatch: etag,
|
||||
DistributionConfig: updatedConfig as unknown
|
||||
DistributionConfig: updatedConfig as DistributionConfig
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ import {
|
||||
CloudFrontClient,
|
||||
ListDistributionsCommand,
|
||||
GetDistributionCommand,
|
||||
UpdateDistributionCommand
|
||||
UpdateDistributionCommand,
|
||||
DistributionConfig
|
||||
} from '@aws-sdk/client-cloudfront'
|
||||
import { BPSet, BPSetFixFn, BPSetStats } from '../../types'
|
||||
import { Memorizer } from '../../Memorizer'
|
||||
@ -145,7 +146,7 @@ export class CloudFrontViewerPolicyHTTPS implements BPSet {
|
||||
new UpdateDistributionCommand({
|
||||
Id: distributionId,
|
||||
IfMatch: etag,
|
||||
DistributionConfig: updatedConfig as unknown
|
||||
DistributionConfig: updatedConfig as DistributionConfig
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -1,4 +1,10 @@
|
||||
import { CloudWatchClient, DescribeAlarmsCommand, PutMetricAlarmCommand } from '@aws-sdk/client-cloudwatch'
|
||||
import {
|
||||
CloudWatchClient,
|
||||
ComparisonOperator,
|
||||
DescribeAlarmsCommand,
|
||||
PutMetricAlarmCommand,
|
||||
Statistic
|
||||
} from '@aws-sdk/client-cloudwatch'
|
||||
import { BPSet, BPSetFixFn, BPSetStats } from '../../types'
|
||||
import { Memorizer } from '../../Memorizer'
|
||||
|
||||
@ -88,7 +94,7 @@ export class CloudWatchAlarmSettingsCheck implements BPSet {
|
||||
const compliantResources: string[] = []
|
||||
const nonCompliantResources: string[] = []
|
||||
const alarms = await this.getAlarms()
|
||||
const parameters = {
|
||||
const parameters: Record<string, string | null> = {
|
||||
MetricName: '', // Required
|
||||
Threshold: null,
|
||||
EvaluationPeriods: null,
|
||||
@ -100,7 +106,7 @@ export class CloudWatchAlarmSettingsCheck implements BPSet {
|
||||
for (const alarm of alarms) {
|
||||
let isCompliant = true
|
||||
|
||||
for (const key of Object.keys(parameters).filter((k) => (parameters as unknown)[k] !== null)) {
|
||||
for (const key of Object.keys(parameters).filter((k) => parameters[k] !== null)) {
|
||||
if (alarm[key as keyof typeof alarm] !== parameters[key as keyof typeof parameters]) {
|
||||
isCompliant = false
|
||||
break
|
||||
@ -144,8 +150,8 @@ export class CloudWatchAlarmSettingsCheck implements BPSet {
|
||||
Threshold: parseFloat(requiredSettings['threshold']),
|
||||
EvaluationPeriods: parseInt(requiredSettings['evaluation-periods'], 10),
|
||||
Period: parseInt(requiredSettings['period'], 10),
|
||||
ComparisonOperator: requiredSettings['comparison-operator'] as unknown,
|
||||
Statistic: requiredSettings['statistic'] as unknown
|
||||
ComparisonOperator: requiredSettings['comparison-operator'] as ComparisonOperator,
|
||||
Statistic: requiredSettings['statistic'] as Statistic
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -125,9 +125,9 @@ export class CodeBuildProjectEnvironmentPrivilegedCheck implements BPSet {
|
||||
new UpdateProjectCommand({
|
||||
name: projectName,
|
||||
environment: {
|
||||
...projectToFix.environment,
|
||||
...projectToFix.environment!,
|
||||
privilegedMode: false
|
||||
} as unknown
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ export class ECRPrivateLifecyclePolicyConfigured implements BPSet {
|
||||
)
|
||||
compliantResources.push(repository.repositoryArn!)
|
||||
} catch (error: unknown) {
|
||||
if (error.name === 'LifecyclePolicyNotFoundException') {
|
||||
if ((error as Error).name === 'LifecyclePolicyNotFoundException') {
|
||||
nonCompliantResources.push(repository.repositoryArn!)
|
||||
} else {
|
||||
throw error
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
CreatePolicyVersionCommand,
|
||||
DeletePolicyVersionCommand
|
||||
} from '@aws-sdk/client-iam'
|
||||
import { BPSet, BPSetMetadata, BPSetStats } from '../../types'
|
||||
import { BPSet, BPSetMetadata, BPSetStats, PolicyDocument } from '../../types'
|
||||
import { Memorizer } from '../../Memorizer'
|
||||
|
||||
export class IAMPolicyNoStatementsWithFullAccess implements BPSet {
|
||||
@ -88,9 +88,11 @@ export class IAMPolicyNoStatementsWithFullAccess implements BPSet {
|
||||
})
|
||||
)
|
||||
|
||||
const policyDocument = JSON.parse(decodeURIComponent(policyVersionResponse.PolicyVersion!.Document as string))
|
||||
const policyDocument = JSON.parse(
|
||||
decodeURIComponent(policyVersionResponse.PolicyVersion!.Document as string)
|
||||
) as PolicyDocument
|
||||
|
||||
const hasFullAccess = policyDocument.Statement.some((statement: unknown) => {
|
||||
const hasFullAccess = policyDocument.Statement.some((statement) => {
|
||||
if (statement.Effect === 'Deny') return false
|
||||
const actions = Array.isArray(statement.Action) ? statement.Action : [statement.Action]
|
||||
return actions.some((action: string) => action.endsWith(':*'))
|
||||
@ -143,9 +145,11 @@ export class IAMPolicyNoStatementsWithFullAccess implements BPSet {
|
||||
})
|
||||
)
|
||||
|
||||
const policyDocument = JSON.parse(decodeURIComponent(policyVersionResponse.PolicyVersion!.Document as string))
|
||||
const policyDocument = JSON.parse(
|
||||
decodeURIComponent(policyVersionResponse.PolicyVersion!.Document as string)
|
||||
) as PolicyDocument
|
||||
|
||||
policyDocument.Statement = policyDocument.Statement.filter((statement: unknown) => {
|
||||
policyDocument.Statement = policyDocument.Statement.filter((statement) => {
|
||||
if (statement.Effect === 'Deny') return true
|
||||
const actions = Array.isArray(statement.Action) ? statement.Action : [statement.Action]
|
||||
return !actions.some((action: string) => action.endsWith(':*'))
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { LambdaClient, ListFunctionsCommand, GetPolicyCommand, RemovePermissionCommand } from '@aws-sdk/client-lambda'
|
||||
import { BPSet, BPSetMetadata, BPSetStats } from '../../types'
|
||||
import { BPSet, BPSetMetadata, BPSetStats, PolicyDocument } from '../../types'
|
||||
import { Memorizer } from '../../Memorizer'
|
||||
|
||||
export class LambdaFunctionPublicAccessProhibited implements BPSet {
|
||||
@ -75,10 +75,10 @@ export class LambdaFunctionPublicAccessProhibited implements BPSet {
|
||||
for (const func of functions) {
|
||||
try {
|
||||
const response = await this.memoClient.send(new GetPolicyCommand({ FunctionName: func.FunctionName! }))
|
||||
const policy = JSON.parse(response.Policy!)
|
||||
const policy = JSON.parse(response.Policy!) as PolicyDocument
|
||||
|
||||
const hasPublicAccess = policy.Statement.some(
|
||||
(statement: unknown) => statement.Principal === '*' || statement.Principal?.AWS === '*'
|
||||
(statement) => statement.Principal === '*' || statement.Principal?.AWS === '*'
|
||||
)
|
||||
|
||||
if (hasPublicAccess) {
|
||||
@ -87,7 +87,7 @@ export class LambdaFunctionPublicAccessProhibited implements BPSet {
|
||||
compliantResources.push(func.FunctionArn!)
|
||||
}
|
||||
} catch (error) {
|
||||
if ((error as unknown).name === 'ResourceNotFoundException') {
|
||||
if ((error as Error).name === 'ResourceNotFoundException') {
|
||||
compliantResources.push(func.FunctionArn!)
|
||||
} else {
|
||||
throw error
|
||||
@ -132,7 +132,7 @@ export class LambdaFunctionPublicAccessProhibited implements BPSet {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if ((error as unknown).name !== 'ResourceNotFoundException') {
|
||||
if ((error as Error).name !== 'ResourceNotFoundException') {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
@ -81,13 +81,10 @@ export class RDSClusterIAMAuthenticationEnabled implements BPSet {
|
||||
this.stats.nonCompliantResources = nonCompliantResources
|
||||
}
|
||||
|
||||
public readonly fix = async (
|
||||
nonCompliantResources: string[],
|
||||
requiredParametersForFix: { name: string; value: string }[]
|
||||
) => {
|
||||
public readonly fix = async (nonCompliantResources: string[]) => {
|
||||
this.stats.status = 'CHECKING'
|
||||
|
||||
await this.fixImpl(nonCompliantResources, requiredParametersForFix)
|
||||
await this.fixImpl(nonCompliantResources)
|
||||
.then(() => {
|
||||
this.stats.status = 'FINISHED'
|
||||
})
|
||||
|
@ -83,13 +83,10 @@ export class RDSClusterMultiAZEnabled implements BPSet {
|
||||
this.stats.nonCompliantResources = nonCompliantResources
|
||||
}
|
||||
|
||||
public readonly fix = async (
|
||||
nonCompliantResources: string[],
|
||||
requiredParametersForFix: { name: string; value: string }[]
|
||||
) => {
|
||||
public readonly fix = async () => {
|
||||
this.stats.status = 'CHECKING'
|
||||
|
||||
await this.fixImpl(nonCompliantResources, requiredParametersForFix)
|
||||
await this.fixImpl()
|
||||
.then(() => {
|
||||
this.stats.status = 'FINISHED'
|
||||
})
|
||||
|
@ -81,13 +81,10 @@ export class RDSInstancePublicAccessCheck implements BPSet {
|
||||
this.stats.nonCompliantResources = nonCompliantResources
|
||||
}
|
||||
|
||||
public readonly fix = async (
|
||||
nonCompliantResources: string[],
|
||||
requiredParametersForFix: { name: string; value: string }[]
|
||||
) => {
|
||||
public readonly fix = async (nonCompliantResources: string[]) => {
|
||||
this.stats.status = 'CHECKING'
|
||||
|
||||
await this.fixImpl(nonCompliantResources, requiredParametersForFix)
|
||||
await this.fixImpl(nonCompliantResources)
|
||||
.then(() => {
|
||||
this.stats.status = 'FINISHED'
|
||||
})
|
||||
|
@ -91,13 +91,10 @@ export class RDSLoggingEnabled implements BPSet {
|
||||
this.stats.nonCompliantResources = nonCompliantResources
|
||||
}
|
||||
|
||||
public readonly fix = async (
|
||||
nonCompliantResources: string[],
|
||||
requiredParametersForFix: { name: string; value: string }[]
|
||||
) => {
|
||||
public readonly fix = async (nonCompliantResources: string[]) => {
|
||||
this.stats.status = 'CHECKING'
|
||||
|
||||
await this.fixImpl(nonCompliantResources, requiredParametersForFix)
|
||||
await this.fixImpl(nonCompliantResources)
|
||||
.then(() => {
|
||||
this.stats.status = 'FINISHED'
|
||||
})
|
||||
|
@ -80,7 +80,7 @@ export class S3BucketDefaultLockEnabled implements BPSet {
|
||||
await this.memoClient.send(new GetObjectLockConfigurationCommand({ Bucket: bucket.Name! }))
|
||||
compliantResources.push(`arn:aws:s3:::${bucket.Name!}`)
|
||||
} catch (error) {
|
||||
if ((error as unknown).name === 'ObjectLockConfigurationNotFoundError') {
|
||||
if ((error as Error).name === 'ObjectLockConfigurationNotFoundError') {
|
||||
nonCompliantResources.push(`arn:aws:s3:::${bucket.Name!}`)
|
||||
} else {
|
||||
throw error
|
||||
@ -92,13 +92,10 @@ export class S3BucketDefaultLockEnabled implements BPSet {
|
||||
this.stats.nonCompliantResources = nonCompliantResources
|
||||
}
|
||||
|
||||
public readonly fix = async (
|
||||
nonCompliantResources: string[],
|
||||
requiredParametersForFix: { name: string; value: string }[]
|
||||
) => {
|
||||
public readonly fix = async (nonCompliantResources: string[]) => {
|
||||
this.stats.status = 'CHECKING'
|
||||
|
||||
await this.fixImpl(nonCompliantResources, requiredParametersForFix)
|
||||
await this.fixImpl(nonCompliantResources)
|
||||
.then(() => {
|
||||
this.stats.status = 'FINISHED'
|
||||
})
|
||||
|
@ -96,13 +96,10 @@ export class S3BucketLevelPublicAccessProhibited implements BPSet {
|
||||
this.stats.nonCompliantResources = nonCompliantResources
|
||||
}
|
||||
|
||||
public readonly fix = async (
|
||||
nonCompliantResources: string[],
|
||||
requiredParametersForFix: { name: string; value: string }[]
|
||||
) => {
|
||||
public readonly fix = async (nonCompliantResources: string[]) => {
|
||||
this.stats.status = 'CHECKING'
|
||||
|
||||
await this.fixImpl(nonCompliantResources, requiredParametersForFix)
|
||||
await this.fixImpl(nonCompliantResources)
|
||||
.then(() => {
|
||||
this.stats.status = 'FINISHED'
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { S3Client, ListBucketsCommand, GetBucketPolicyCommand, PutBucketPolicyCommand } from '@aws-sdk/client-s3'
|
||||
import { BPSet, BPSetMetadata, BPSetStats } from '../../types'
|
||||
import { BPSet, BPSetMetadata, BPSetStats, PolicyDocument, Statement } from '../../types'
|
||||
import { Memorizer } from '../../Memorizer'
|
||||
|
||||
export class S3BucketSSLRequestsOnly implements BPSet {
|
||||
@ -71,10 +71,9 @@ export class S3BucketSSLRequestsOnly implements BPSet {
|
||||
for (const bucket of buckets) {
|
||||
try {
|
||||
const response = await this.memoClient.send(new GetBucketPolicyCommand({ Bucket: bucket.Name! }))
|
||||
const policy = JSON.parse(response.Policy!)
|
||||
const policy = JSON.parse(response.Policy!) as PolicyDocument
|
||||
const hasSSLCondition = policy.Statement.some(
|
||||
(stmt: unknown) =>
|
||||
stmt.Condition && stmt.Condition.Bool && stmt.Condition.Bool['aws:SecureTransport'] === 'false'
|
||||
(stmt) => stmt.Condition && stmt.Condition.Bool && stmt.Condition.Bool['aws:SecureTransport'] === 'false'
|
||||
)
|
||||
|
||||
if (hasSSLCondition) {
|
||||
@ -83,7 +82,7 @@ export class S3BucketSSLRequestsOnly implements BPSet {
|
||||
nonCompliantResources.push(`arn:aws:s3:::${bucket.Name!}`)
|
||||
}
|
||||
} catch (error) {
|
||||
if ((error as unknown).name === 'NoSuchBucketPolicy') {
|
||||
if ((error as Error).name === 'NoSuchBucketPolicy') {
|
||||
nonCompliantResources.push(`arn:aws:s3:::${bucket.Name!}`)
|
||||
} else {
|
||||
throw error
|
||||
@ -95,13 +94,10 @@ export class S3BucketSSLRequestsOnly implements BPSet {
|
||||
this.stats.nonCompliantResources = nonCompliantResources
|
||||
}
|
||||
|
||||
public readonly fix = async (
|
||||
nonCompliantResources: string[],
|
||||
requiredParametersForFix: { name: string; value: string }[]
|
||||
) => {
|
||||
public readonly fix = async (nonCompliantResources: string[]) => {
|
||||
this.stats.status = 'CHECKING'
|
||||
|
||||
await this.fixImpl(nonCompliantResources, requiredParametersForFix)
|
||||
await this.fixImpl(nonCompliantResources)
|
||||
.then(() => {
|
||||
this.stats.status = 'FINISHED'
|
||||
})
|
||||
@ -117,18 +113,18 @@ export class S3BucketSSLRequestsOnly implements BPSet {
|
||||
private readonly fixImpl = async (nonCompliantResources: string[]) => {
|
||||
for (const bucketArn of nonCompliantResources) {
|
||||
const bucketName = bucketArn.split(':::')[1]!
|
||||
let existingPolicy: unknown
|
||||
let existingPolicy
|
||||
|
||||
try {
|
||||
const response = await this.memoClient.send(new GetBucketPolicyCommand({ Bucket: bucketName }))
|
||||
existingPolicy = JSON.parse(response.Policy!)
|
||||
existingPolicy = JSON.parse(response.Policy!) as PolicyDocument
|
||||
} catch (error) {
|
||||
if ((error as unknown).name !== 'NoSuchBucketPolicy') {
|
||||
if ((error as Error).name !== 'NoSuchBucketPolicy') {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const sslPolicyStatement = {
|
||||
const sslPolicyStatement: Statement = {
|
||||
Sid: 'DenyNonSSLRequests',
|
||||
Effect: 'Deny',
|
||||
Principal: '*',
|
||||
|
@ -87,13 +87,10 @@ export class S3BucketVersioningEnabled implements BPSet {
|
||||
this.stats.nonCompliantResources = nonCompliantResources
|
||||
}
|
||||
|
||||
public readonly fix = async (
|
||||
nonCompliantResources: string[],
|
||||
requiredParametersForFix: { name: string; value: string }[]
|
||||
) => {
|
||||
public readonly fix = async (nonCompliantResources: string[]) => {
|
||||
this.stats.status = 'CHECKING'
|
||||
|
||||
await this.fixImpl(nonCompliantResources, requiredParametersForFix)
|
||||
await this.fixImpl(nonCompliantResources)
|
||||
.then(() => {
|
||||
this.stats.status = 'FINISHED'
|
||||
})
|
||||
|
@ -96,7 +96,7 @@ export class S3DefaultEncryptionKMS implements BPSet {
|
||||
nonCompliantResources.push(`arn:aws:s3:::${bucket.Name!}`)
|
||||
}
|
||||
} catch (error) {
|
||||
if ((error as unknown).name === 'ServerSideEncryptionConfigurationNotFoundError') {
|
||||
if ((error as Error).name === 'ServerSideEncryptionConfigurationNotFoundError') {
|
||||
nonCompliantResources.push(`arn:aws:s3:::${bucket.Name!}`)
|
||||
} else {
|
||||
throw error
|
||||
|
@ -2,7 +2,8 @@ import {
|
||||
S3Client,
|
||||
ListBucketsCommand,
|
||||
GetBucketNotificationConfigurationCommand,
|
||||
PutBucketNotificationConfigurationCommand
|
||||
PutBucketNotificationConfigurationCommand,
|
||||
Event
|
||||
} from '@aws-sdk/client-s3'
|
||||
import { BPSet, BPSetMetadata, BPSetStats } from '../../types'
|
||||
import { Memorizer } from '../../Memorizer'
|
||||
@ -141,7 +142,7 @@ export class S3EventNotificationsEnabled implements BPSet {
|
||||
LambdaFunctionConfigurations: [
|
||||
{
|
||||
LambdaFunctionArn: lambdaArn,
|
||||
Events: [eventType as unknown]
|
||||
Events: [eventType] as Event[]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ export class S3LifecyclePolicyCheck implements BPSet {
|
||||
await this.memoClient.send(new GetBucketLifecycleConfigurationCommand({ Bucket: bucket.Name! }))
|
||||
compliantResources.push(`arn:aws:s3:::${bucket.Name!}`)
|
||||
} catch (error) {
|
||||
if ((error as unknown).name === 'NoSuchLifecycleConfiguration') {
|
||||
if ((error as Error).name === 'NoSuchLifecycleConfiguration') {
|
||||
nonCompliantResources.push(`arn:aws:s3:::${bucket.Name!}`)
|
||||
} else {
|
||||
throw error
|
||||
|
@ -81,13 +81,10 @@ export class SecretsManagerRotationEnabledCheck implements BPSet {
|
||||
this.stats.nonCompliantResources = nonCompliantResources
|
||||
}
|
||||
|
||||
public readonly fix = async (
|
||||
nonCompliantResources: string[],
|
||||
requiredParametersForFix: { name: string; value: string }[]
|
||||
) => {
|
||||
public readonly fix = async (nonCompliantResources: string[]) => {
|
||||
this.stats.status = 'CHECKING'
|
||||
|
||||
await this.fixImpl(nonCompliantResources, requiredParametersForFix)
|
||||
await this.fixImpl(nonCompliantResources)
|
||||
.then(() => {
|
||||
this.stats.status = 'FINISHED'
|
||||
})
|
||||
|
@ -93,13 +93,10 @@ export class SecretsManagerScheduledRotationSuccessCheck implements BPSet {
|
||||
this.stats.nonCompliantResources = nonCompliantResources
|
||||
}
|
||||
|
||||
public readonly fix = async (
|
||||
nonCompliantResources: string[],
|
||||
requiredParametersForFix: { name: string; value: string }[]
|
||||
) => {
|
||||
public readonly fix = async (nonCompliantResources: string[]) => {
|
||||
this.stats.status = 'CHECKING'
|
||||
|
||||
await this.fixImpl(nonCompliantResources, requiredParametersForFix)
|
||||
await this.fixImpl(nonCompliantResources)
|
||||
.then(() => {
|
||||
this.stats.status = 'FINISHED'
|
||||
})
|
||||
|
@ -76,7 +76,7 @@ export class SecurityHubEnabled implements BPSet {
|
||||
await this.memoSecurityHubClient.send(new DescribeHubCommand({}))
|
||||
compliantResources.push(awsAccountId)
|
||||
} catch (error: unknown) {
|
||||
if (error.name === 'InvalidAccessException') {
|
||||
if ((error as Error).name === 'InvalidAccessException') {
|
||||
nonCompliantResources.push(awsAccountId)
|
||||
} else {
|
||||
throw error
|
||||
|
@ -80,7 +80,7 @@ export class SNSEncryptedKMS implements BPSet {
|
||||
const topics = await this.getTopics()
|
||||
|
||||
for (const topic of topics) {
|
||||
if ((topic as unknown).KmsMasterKeyId) {
|
||||
if (topic.KmsMasterKeyId) {
|
||||
compliantResources.push(topic.TopicArn!)
|
||||
} else {
|
||||
nonCompliantResources.push(topic.TopicArn!)
|
||||
@ -135,7 +135,7 @@ export class SNSEncryptedKMS implements BPSet {
|
||||
const topicsResponse = await this.memoClient.send(new ListTopicsCommand({}))
|
||||
const topics = topicsResponse.Topics || []
|
||||
|
||||
const topicDetails = []
|
||||
const topicDetails: Record<string, string>[] = []
|
||||
for (const topic of topics) {
|
||||
const attributes = await this.memoClient.send(new GetTopicAttributesCommand({ TopicArn: topic.TopicArn! }))
|
||||
topicDetails.push({ ...attributes.Attributes, TopicArn: topic.TopicArn! })
|
||||
|
21
src/types.d.ts
vendored
21
src/types.d.ts
vendored
@ -57,3 +57,24 @@ export interface BPSetStats {
|
||||
message: string
|
||||
}[]
|
||||
}
|
||||
interface PolicyDocument {
|
||||
Version: '2012-10-17' | '2008-10-17' // Only valid AWS IAM policy versions
|
||||
Statement: Statement[]
|
||||
}
|
||||
|
||||
interface Statement {
|
||||
Sid?: string // Optional statement ID
|
||||
Effect: 'Allow' | 'Deny' // Effect of the statement
|
||||
Action: string | string[] // Action(s) the statement applies to
|
||||
Resource: string | string[] // Resource(s) the statement applies to
|
||||
Principal?:
|
||||
| '*'
|
||||
| {
|
||||
[key: string]: string | string[]
|
||||
} // Optional principal(s) the statement applies to, can be "*"
|
||||
Condition?: {
|
||||
[key: string]: {
|
||||
[operator: string]: string | string[]
|
||||
}
|
||||
} // Optional conditions for the statement
|
||||
}
|
||||
|
Reference in New Issue
Block a user