in packages/pipeline/src/code_scanner/sonar-code-scanner.ts [132:287]
constructor(scope: Construct, id: string, props: SonarCodeScannerProps) {
super(scope, id);
const sonarQubeToken = new Secret(this, "SonarQubeToken");
const synthBuildProject = Project.fromProjectArn(
this,
"SynthBuildProject",
props.synthBuildArn
);
const validationProject = new Project(this, "ValidationProject", {
environment: {
buildImage: LinuxBuildImage.STANDARD_5_0,
},
environmentVariables: {
SONARQUBE_TOKEN: {
type: BuildEnvironmentVariableType.SECRETS_MANAGER,
value: sonarQubeToken.secretArn,
},
SONARQUBE_ENDPOINT: {
type: BuildEnvironmentVariableType.PLAINTEXT,
value: props.sonarqubeEndpoint,
},
PROJECT_NAME: {
type: BuildEnvironmentVariableType.PLAINTEXT,
value: props.sonarqubeProjectName,
},
},
buildSpec: BuildSpec.fromObject({
version: "0.2",
env: {
shell: "bash",
},
phases: {
install: {
commands: ["npm install -g aws-cdk", "gem install cfn-nag"],
},
build: {
commands: [
"export RESOLVED_SOURCE_VERSION=`aws codebuild batch-get-builds --ids $SYNTH_BUILD_ID | jq -r '.builds[0].resolvedSourceVersion'`",
...unpackSourceAndArtifacts(props.includeGlobsForScan),
...createSonarqubeProject(props),
"mkdir -p src/reports",
owaspScan(),
cfnNagScan(props.cdkOutDir, props.cfnNagIgnorePath),
"cd src",
sonarqubeScanner(props.excludeGlobsForScan),
...generateSonarqubeReports(),
...(props.preArchiveCommands || []),
],
},
},
}),
});
validationProject.addToRolePolicy(
new PolicyStatement({
actions: ["codebuild:BatchGetBuilds"],
effect: Effect.ALLOW,
resources: [synthBuildProject.projectArn],
})
);
validationProject.addToRolePolicy(
new PolicyStatement({
actions: ["s3:GetObject*"],
effect: Effect.ALLOW,
resources: [props.artifactBucketArn, `${props.artifactBucketArn}/**`],
})
);
props.artifactBucketKeyArn &&
validationProject.addToRolePolicy(
new PolicyStatement({
actions: ["kms:Decrypt", "kms:DescribeKey"],
effect: Effect.ALLOW,
resources: [props.artifactBucketKeyArn],
})
);
synthBuildProject.onBuildSucceeded("OnSynthSuccess", {
target: new CodeBuildProject(validationProject, {
event: RuleTargetInput.fromObject({
environmentVariablesOverride: [
{
name: "SYNTH_BUILD_ID",
type: "PLAINTEXT",
value: EventField.fromPath("$.detail.build-id"),
},
],
}),
}),
});
new CfnOutput(this, "SonarqubeSecretArn", {
value: sonarQubeToken.secretArn,
});
[
"AwsSolutions-SMG4",
"AwsPrototyping-SecretsManagerRotationEnabled",
].forEach((RuleId) => {
NagSuppressions.addResourceSuppressions(sonarQubeToken, [
{
id: RuleId,
reason:
"Key rotation is not possible as a user token needs to be generated from Sonarqube",
},
]);
});
const stack = Stack.of(this);
["AwsSolutions-IAM5", "AwsPrototyping-IAMNoWildcardPermissions"].forEach(
(RuleId) => {
NagSuppressions.addResourceSuppressions(
validationProject.role!,
[
{
id: RuleId,
reason:
"Validation CodeBuild project requires access to the ArtifactsBucket and ability to create logs.",
appliesTo: [
{
regex: `/^Resource::arn:${PDKNag.getStackPartitionRegex(
stack
)}:logs:${PDKNag.getStackRegionRegex(
stack
)}:${PDKNag.getStackAccountRegex(
stack
)}:log-group:/aws/codebuild/<.*SonarCodeScannerValidationProject.*>:\\*$/g`,
},
{
regex: `/^Resource::arn:${PDKNag.getStackPartitionRegex(
stack
)}:codebuild:${PDKNag.getStackRegionRegex(
stack
)}:${PDKNag.getStackAccountRegex(
stack
)}:report-group/<.*SonarCodeScannerValidationProject.*>-\\*$/g`,
},
{
regex: `/^Action::s3:GetObject\\*$/g`,
},
{
regex: "/^Resource::<ArtifactsBucket.*.Arn>/\\*\\*$/g",
},
],
},
],
true
);
}
);
}