From b845dff6f25a9b33c6520069c63b726a73cda380 Mon Sep 17 00:00:00 2001 From: Nureka Rodrigo Date: Fri, 23 May 2025 14:23:42 +0530 Subject: [PATCH] Initialize compiler plugin --- .gitignore | 2 + ballerina/CompilerPlugin.toml | 6 + ballerina/build.gradle | 10 +- build-config/resources/CompilerPlugin.toml | 6 + compiler-plugin-tests/build.gradle | 125 ++++++++++++++++++ compiler-plugin/build.gradle | 78 +++++++++++ .../crypto/compiler/CryptoCompilerPlugin.java | 28 ++++ .../CryptoCipherAlgorithmAnalyzer.java | 23 ++++ .../CryptoCodeAnalyzer.java | 23 ++++ .../staticcodeanalyzer/CryptoRule.java | 22 +++ .../staticcodeanalyzer/RuleFactory.java | 35 +++++ .../compiler/staticcodeanalyzer/RuleImpl.java | 54 ++++++++ .../src/main/java/module-info.java | 24 ++++ compiler-plugin/src/main/resources/rules.json | 0 gradle.properties | 3 + settings.gradle | 4 + 16 files changed, 441 insertions(+), 2 deletions(-) create mode 100644 ballerina/CompilerPlugin.toml create mode 100644 build-config/resources/CompilerPlugin.toml create mode 100644 compiler-plugin-tests/build.gradle create mode 100644 compiler-plugin/build.gradle create mode 100644 compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/CryptoCompilerPlugin.java create mode 100644 compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/CryptoCipherAlgorithmAnalyzer.java create mode 100644 compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/CryptoCodeAnalyzer.java create mode 100644 compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/CryptoRule.java create mode 100644 compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/RuleFactory.java create mode 100644 compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/RuleImpl.java create mode 100644 compiler-plugin/src/main/java/module-info.java create mode 100644 compiler-plugin/src/main/resources/rules.json diff --git a/.gitignore b/.gitignore index 85e001f2..10e9dd00 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,5 @@ target # Ballerina velocity.log* *Ballerina.lock + +compiler-plugin-tests/**/target diff --git a/ballerina/CompilerPlugin.toml b/ballerina/CompilerPlugin.toml new file mode 100644 index 00000000..2e2112d3 --- /dev/null +++ b/ballerina/CompilerPlugin.toml @@ -0,0 +1,6 @@ +[plugin] +id = "crypto-compiler-plugin" +class = "io.ballerina.stdlib.crypto.compiler.CryptoCompilerPlugin" + +[[dependency]] +path = "../compiler-plugin/build/libs/crypto-compiler-plugin-2.9.1-SNAPSHOT.jar" diff --git a/ballerina/build.gradle b/ballerina/build.gradle index ba00d348..ccd6a1a1 100644 --- a/ballerina/build.gradle +++ b/ballerina/build.gradle @@ -28,6 +28,8 @@ def packageOrg = "ballerina" def tomlVersion = stripBallerinaExtensionVersion("${project.version}") def ballerinaTomlFile = new File("$project.projectDir/Ballerina.toml") def ballerinaTomlFilePlaceHolder = new File("${project.rootDir}/build-config/resources/Ballerina.toml") +def compilerPluginTomlFilePlaceHolder = new File("${project.rootDir}/build-config/resources/CompilerPlugin.toml") +def compilerPluginTomlFile = new File("$project.projectDir/CompilerPlugin.toml") def stripBallerinaExtensionVersion(String extVersion) { if (extVersion.matches(project.ext.timestampedVersionRegex)) { @@ -68,18 +70,20 @@ dependencies { } } -task updateTomlFiles { +tasks.register('updateTomlFiles') { doLast { def stdlibDependentBouncycastleVersion = project.bouncycastleVersion def newBallerinaToml = ballerinaTomlFilePlaceHolder.text.replace("@project.version@", project.version) newBallerinaToml = newBallerinaToml.replace("@toml.version@", tomlVersion) newBallerinaToml = newBallerinaToml.replace("@bouncycastle.version@", stdlibDependentBouncycastleVersion) + def newCompilerPluginToml = compilerPluginTomlFilePlaceHolder.text.replace("@project.version@", project.version) ballerinaTomlFile.text = newBallerinaToml + compilerPluginTomlFile.text = newCompilerPluginToml } } -task commitTomlFiles { +tasks.register('commitTomlFiles') { doLast { project.exec { ignoreExitValue true @@ -117,6 +121,8 @@ test.dependsOn ":${packageName}-native:build" build.dependsOn "generatePomFileForMavenPublication" build.dependsOn ":${packageName}-native:build" +build.dependsOn ":${packageName}-compiler-plugin:build" +test.dependsOn ":${packageName}-compiler-plugin:build" publishToMavenLocal.dependsOn build publish.dependsOn build diff --git a/build-config/resources/CompilerPlugin.toml b/build-config/resources/CompilerPlugin.toml new file mode 100644 index 00000000..4ed52ceb --- /dev/null +++ b/build-config/resources/CompilerPlugin.toml @@ -0,0 +1,6 @@ +[plugin] +id = "crypto-compiler-plugin" +class = "io.ballerina.stdlib.crypto.compiler.CryptoCompilerPlugin" + +[[dependency]] +path = "../compiler-plugin/build/libs/crypto-compiler-plugin-@project.version@.jar" diff --git a/compiler-plugin-tests/build.gradle b/compiler-plugin-tests/build.gradle new file mode 100644 index 00000000..3643110c --- /dev/null +++ b/compiler-plugin-tests/build.gradle @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.org) + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +plugins { + id 'java' + id 'checkstyle' + id 'com.github.spotbugs' +} + +description = 'Ballerina - Crypto Compiler Plugin Tests' + +dependencies { + checkstyle project(':checkstyle') + checkstyle "com.puppycrawl.tools:checkstyle:${checkstylePluginVersion}" + + implementation project(':crypto-compiler-plugin') + + testImplementation group: 'org.ballerinalang', name: 'ballerina-lang', version: "${ballerinaLangVersion}" + testImplementation group: 'org.ballerinalang', name: 'ballerina-tools-api', version: "${ballerinaLangVersion}" + testImplementation group: 'org.ballerinalang', name: 'ballerina-parser', version: "${ballerinaLangVersion}" + + testImplementation group: 'org.testng', name: 'testng', version: "${testngVersion}" +} +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' +} + +sourceCompatibility = JavaVersion.VERSION_21 + +test { + systemProperty "ballerina.offline.flag", "true" + useTestNG() { + suites 'src/test/resources/testng.xml' + } + testLogging.showStandardStreams = true + testLogging { + events "PASSED", "FAILED", "SKIPPED" + afterSuite { desc, result -> + if (!desc.parent) { // will match the outermost suite + def output = "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)" + def startItem = '| ', endItem = ' |' + def repeatLength = startItem.length() + output.length() + endItem.length() + println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength)) + } + } + } +} + +spotbugsTest { + def classLoader = plugins["com.github.spotbugs"].class.classLoader + def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence") + def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort") + ignoreFailures = true + effort = SpotBugsEffort.MAX + reportLevel = SpotBugsConfidence.LOW + reportsDir = file("$project.buildDir/reports/spotbugs") + def excludeFile = file("${rootDir}/build-config/spotbugs-exclude.xml") + if (excludeFile.exists()) { + it.excludeFilter = excludeFile + } + reports { + text.enabled = true + } +} + +spotbugsMain { + enabled false +} + +tasks.register('validateSpotbugs') { + doLast { + if (spotbugsMain.reports.size() > 0 && + spotbugsMain.reports[0].destination.exists() && + spotbugsMain.reports[0].destination.text.readLines().size() > 0) { + spotbugsMain.reports[0].destination?.eachLine { + println 'Failure: ' + it + } + throw new GradleException("Spotbugs rule violations were found."); + } + } +} + +tasks.withType(Checkstyle).configureEach { + exclude '**/module-info.java' +} + +checkstyle { + toolVersion "${project.checkstylePluginVersion}" + configFile rootProject.file("build-config/checkstyle/build/checkstyle.xml") + configProperties = ["suppressionFile": file("${rootDir}/build-config/checkstyle/build/suppressions.xml")] +} + +checkstyleMain { + enabled false +} + +spotbugsTest.finalizedBy validateSpotbugs +checkstyleTest.dependsOn ':checkstyle:downloadCheckstyleRuleFiles' + +compileJava { + doFirst { + options.compilerArgs = [ + '--module-path', classpath.asPath, + ] + classpath = files() + } +} + +test.dependsOn ":crypto-ballerina:build" +build.dependsOn ":crypto-ballerina:build" diff --git a/compiler-plugin/build.gradle b/compiler-plugin/build.gradle new file mode 100644 index 00000000..3a8c41cb --- /dev/null +++ b/compiler-plugin/build.gradle @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +plugins { + id 'java' + id 'checkstyle' + id 'com.github.spotbugs' +} + +description = 'Ballerina - Crypto Compiler Plugin' + + +dependencies { + checkstyle project(':checkstyle') + checkstyle "com.puppycrawl.tools:checkstyle:${checkstylePluginVersion}" + + implementation group: 'org.ballerinalang', name: 'ballerina-lang', version: "${ballerinaLangVersion}" + implementation group: 'org.ballerinalang', name: 'ballerina-tools-api', version: "${ballerinaLangVersion}" + implementation group: 'org.ballerinalang', name: 'ballerina-parser', version: "${ballerinaLangVersion}" + implementation group: 'io.ballerina.scan', name: 'scan-command', version: "${balScanVersion}" + implementation project(":crypto-native") +} + +def excludePattern = '**/module-info.java' +tasks.withType(Checkstyle).configureEach { + exclude excludePattern +} + +checkstyle { + toolVersion "${project.checkstylePluginVersion}" + configFile rootProject.file("build-config/checkstyle/build/checkstyle.xml") + configProperties = ["suppressionFile": file("${rootDir}/build-config/checkstyle/build/suppressions.xml")] +} + +checkstyleMain.dependsOn(":checkstyle:downloadCheckstyleRuleFiles") + +spotbugsMain { + def classLoader = plugins["com.github.spotbugs"].class.classLoader + def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence") + def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort") + effort = SpotBugsEffort.MAX + reportLevel = SpotBugsConfidence.LOW + reportsDir = file("$project.buildDir/reports/spotbugs") + reports { + html.enabled true + text.enabled = true + } + def excludeFile = file("${rootDir}/spotbugs-exclude.xml") + if (excludeFile.exists()) { + excludeFilter = excludeFile + } +} + +compileJava { + doFirst { + options.compilerArgs = [ + '--module-path', classpath.asPath, + ] + classpath = files() + } +} + +build.dependsOn ":crypto-native:build" diff --git a/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/CryptoCompilerPlugin.java b/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/CryptoCompilerPlugin.java new file mode 100644 index 00000000..2c1202ec --- /dev/null +++ b/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/CryptoCompilerPlugin.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.stdlib.crypto.compiler; + +/** + * Crypto compiler plugin. + * + * @since 2.9.1 + */ +public class CryptoCompilerPlugin { + +} diff --git a/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/CryptoCipherAlgorithmAnalyzer.java b/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/CryptoCipherAlgorithmAnalyzer.java new file mode 100644 index 00000000..327c79d1 --- /dev/null +++ b/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/CryptoCipherAlgorithmAnalyzer.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.stdlib.crypto.compiler.staticcodeanalyzer; + +public class CryptoCipherAlgorithmAnalyzer { + +} diff --git a/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/CryptoCodeAnalyzer.java b/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/CryptoCodeAnalyzer.java new file mode 100644 index 00000000..202d6a48 --- /dev/null +++ b/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/CryptoCodeAnalyzer.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.stdlib.crypto.compiler.staticcodeanalyzer; + +public class CryptoCodeAnalyzer { + +} diff --git a/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/CryptoRule.java b/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/CryptoRule.java new file mode 100644 index 00000000..40152abc --- /dev/null +++ b/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/CryptoRule.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.stdlib.crypto.compiler.staticcodeanalyzer; + +public class CryptoRule { +} diff --git a/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/RuleFactory.java b/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/RuleFactory.java new file mode 100644 index 00000000..fba2ea03 --- /dev/null +++ b/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/RuleFactory.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.stdlib.crypto.compiler.staticcodeanalyzer; + +import io.ballerina.scan.Rule; +import io.ballerina.scan.RuleKind; + +/** + * {@code RuleFactory} contains the logic to create a {@link Rule}. + */ +public class RuleFactory { + + private RuleFactory() { + } + + public static Rule createRule(int id, String description, RuleKind kind) { + return new RuleImpl(id, description, kind); + } +} diff --git a/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/RuleImpl.java b/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/RuleImpl.java new file mode 100644 index 00000000..80a87b2b --- /dev/null +++ b/compiler-plugin/src/main/java/io/ballerina/stdlib/crypto/compiler/staticcodeanalyzer/RuleImpl.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.stdlib.crypto.compiler.staticcodeanalyzer; + +import io.ballerina.scan.Rule; +import io.ballerina.scan.RuleKind; + +public class RuleImpl implements Rule { + private final int id; + private final String description; + private final RuleKind kind; + + RuleImpl(int id, String description, RuleKind kind) { + this.id = id; + this.description = description; + this.kind = kind; + } + + @Override + public String id() { + return Integer.toString(this.id); + } + + @Override + public int numericId() { + return this.id; + } + + @Override + public String description() { + return this.description; + } + + @Override + public RuleKind kind() { + return this.kind; + } +} diff --git a/compiler-plugin/src/main/java/module-info.java b/compiler-plugin/src/main/java/module-info.java new file mode 100644 index 00000000..0a406a12 --- /dev/null +++ b/compiler-plugin/src/main/java/module-info.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +module io.ballerina.stdlib.crypto.compiler { + requires io.ballerina.lang; + requires io.ballerina.tools.api; + requires io.ballerina.parser; + requires io.ballerina.scan; +} diff --git a/compiler-plugin/src/main/resources/rules.json b/compiler-plugin/src/main/resources/rules.json new file mode 100644 index 00000000..e69de29b diff --git a/gradle.properties b/gradle.properties index 766596ad..36081279 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,3 +13,6 @@ nativeImageVersion=22.2.0 ballerinaLangVersion=2201.12.0 stdlibTimeVersion=2.7.0 stdlibIoVersion=1.8.0 + +testngVersion=7.6.1 +balScanVersion=0.9.0 diff --git a/settings.gradle b/settings.gradle index 2dfaa987..7d952f1f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -37,10 +37,14 @@ rootProject.name = 'crypto' include ':checkstyle' include ':crypto-native' include ':crypto-ballerina' +include ':crypto-compiler-plugin' +include ':crypto-compiler-plugin-tests' project(':checkstyle').projectDir = file("build-config${File.separator}checkstyle") project(':crypto-native').projectDir = file('native') project(':crypto-ballerina').projectDir = file('ballerina') +project(':crypto-compiler-plugin').projectDir = file('compiler-plugin') +project(':crypto-compiler-plugin-tests').projectDir = file('compiler-plugin-tests') gradleEnterprise { buildScan {