constructor()

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
        );
      }
    );
  }