-
Notifications
You must be signed in to change notification settings - Fork 32
Add static code rules to the file module #558
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 9 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
37b7aca
[Automated] Update the native jar versions
SachinAkash01 59406f1
Init commit for insecure directory access prevention
SachinAkash01 b24fe8f
Add ballerina test files
SachinAkash01 217da55
Fix checkstyle issues
SachinAkash01 df440bd
Update changelog
SachinAkash01 1119c83
Add insecure directory access analyzer
SachinAkash01 0fadc0a
Update rule1.json
SachinAkash01 9142c37
Add file path injection analyzer
SachinAkash01 49d3a09
Add Constants
SachinAkash01 f8dca8a
Fix test failures
SachinAkash01 3421d2d
Simplify if-else statements
SachinAkash01 5122155
Improve code quality
SachinAkash01 012e1c4
Simplify if-else statements
SachinAkash01 2ff5fa9
Add jacoco plugin to the compiler plugin test
SachinAkash01 e0923a5
Add jacoco plugin version
SachinAkash01 ae15fb1
Add jacocoTestReport
SachinAkash01 f91a8d5
Check for file import aliases and improve code quality
SachinAkash01 6f549e2
Merge branch 'master' into master
SachinAkash01 ec61a62
Merge branch 'master' into master
SachinAkash01 28297d4
Merge branch 'master' into master
daneshk 00483cf
Update compiler-plugin-test/src/test/resources/static_code_analyzer/b…
daneshk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,3 +41,5 @@ target | |
| # Ballerina | ||
| velocity.log* | ||
| *Ballerina.lock | ||
|
|
||
| compiler-plugin-test/**/target | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
.../test/java/io/ballerina/stdlib/file/compiler/staticcodeanalyzer/ProcessOutputGobbler.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| /* | ||
| * 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. | ||
| */ | ||
|
|
||
| package io.ballerina.stdlib.file.compiler.staticcodeanalyzer; | ||
|
|
||
| import java.io.BufferedReader; | ||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.io.InputStreamReader; | ||
| import java.nio.charset.StandardCharsets; | ||
|
|
||
| /** | ||
| * Helper class to consume the process streams. | ||
| */ | ||
| class ProcessOutputGobbler implements Runnable { | ||
| private final InputStream inputStream; | ||
| private final StringBuilder output; | ||
| private int exitCode; | ||
|
|
||
| public ProcessOutputGobbler(InputStream inputStream) { | ||
| this.inputStream = inputStream; | ||
| this.output = new StringBuilder(); | ||
| } | ||
|
|
||
| @Override | ||
| public void run() { | ||
| try (BufferedReader reader = new BufferedReader( | ||
| new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { | ||
| String line; | ||
| while ((line = reader.readLine()) != null) { | ||
| output.append(line).append("\n"); | ||
| } | ||
| } catch (IOException e) { | ||
| this.output.append(e.getMessage()); | ||
| } | ||
| } | ||
|
|
||
| public String getOutput() { | ||
| return output.toString(); | ||
| } | ||
|
|
||
| public int getExitCode() { | ||
| return exitCode; | ||
| } | ||
|
|
||
| public void setExitCode(int exitCode) { | ||
| this.exitCode = exitCode; | ||
| } | ||
| } |
125 changes: 125 additions & 0 deletions
125
...est/java/io/ballerina/stdlib/file/compiler/staticcodeanalyzer/StaticCodeAnalyzerTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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. | ||
| */ | ||
|
|
||
| package io.ballerina.stdlib.file.compiler.staticcodeanalyzer; | ||
|
|
||
| import org.testng.Assert; | ||
| import org.testng.annotations.BeforeSuite; | ||
| import org.testng.annotations.Test; | ||
| import org.testng.internal.ExitCode; | ||
|
|
||
| import java.io.IOException; | ||
| import java.nio.file.Files; | ||
| import java.nio.file.Path; | ||
| import java.nio.file.Paths; | ||
| import java.util.Arrays; | ||
| import java.util.Locale; | ||
| import java.util.regex.Pattern; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| public class StaticCodeAnalyzerTest { | ||
| private static final Path RESOURCE_PACKAGES_DIRECTORY = Paths | ||
| .get("src", "test", "resources", "static_code_analyzer", "ballerina_packages").toAbsolutePath(); | ||
| private static final Path EXPECTED_JSON_OUTPUT_DIRECTORY = Paths | ||
| .get("src", "test", "resources", "static_code_analyzer", "expected_output").toAbsolutePath(); | ||
| private static final Path BALLERINA_PATH = getBalCommandPath(); | ||
| private static final Path JSON_RULES_FILE_PATH = Paths | ||
| .get("../", "compiler-plugin", "src", "main", "resources", "rules.json").toAbsolutePath(); | ||
| private static final String SCAN_COMMAND = "scan"; | ||
|
|
||
| private static Path getBalCommandPath() { | ||
| String balCommand = isWindows() ? "bal.bat" : "bal"; | ||
| return Paths.get("../", "target", "ballerina-runtime", "bin", balCommand).toAbsolutePath(); | ||
| } | ||
|
|
||
| @BeforeSuite | ||
| public void pullScanTool() throws IOException, InterruptedException { | ||
| ProcessBuilder processBuilder = new ProcessBuilder(BALLERINA_PATH.toString(), "tool", "pull", SCAN_COMMAND); | ||
| ProcessOutputGobbler output = getOutput(processBuilder.start()); | ||
| if (Pattern.compile("tool 'scan:.+\\..+\\..+' successfully set as the active version\\.") | ||
| .matcher(output.getOutput()).find() || Pattern.compile("tool 'scan:.+\\..+\\..+' is already active\\.") | ||
| .matcher(output.getOutput()).find()) { | ||
| return; | ||
| } | ||
| Assert.assertFalse(ExitCode.hasFailure(output.getExitCode())); | ||
| } | ||
|
|
||
| @Test | ||
| public void validateRulesJson() throws IOException { | ||
| String expectedRules = "[" + Arrays.stream(FileRule.values()) | ||
| .map(FileRule::toString).collect(Collectors.joining(",")) + "]"; | ||
| String actualRules = Files.readString(JSON_RULES_FILE_PATH); | ||
| assertJsonEqual(normalizeJson(actualRules), normalizeJson(expectedRules)); | ||
| } | ||
|
|
||
| @Test | ||
| public void testStaticCodeRules() throws IOException, InterruptedException { | ||
| for (FileRule rule : FileRule.values()) { | ||
| String targetPackageName = "rule" + rule.getId(); | ||
| String actualJsonReport = StaticCodeAnalyzerTest.executeScanProcess(targetPackageName); | ||
| String expectedJsonReport = Files | ||
| .readString(EXPECTED_JSON_OUTPUT_DIRECTORY.resolve(targetPackageName + ".json")); | ||
| assertJsonEqual(actualJsonReport, expectedJsonReport); | ||
| } | ||
| } | ||
|
|
||
| private static String executeScanProcess(String targetPackage) throws IOException, InterruptedException { | ||
| ProcessBuilder processBuilder = new ProcessBuilder(BALLERINA_PATH.toString(), SCAN_COMMAND); | ||
| processBuilder.directory(RESOURCE_PACKAGES_DIRECTORY.resolve(targetPackage).toFile()); | ||
| ProcessOutputGobbler output = getOutput(processBuilder.start()); | ||
| Assert.assertFalse(ExitCode.hasFailure(output.getExitCode())); | ||
| return Files.readString(RESOURCE_PACKAGES_DIRECTORY.resolve(targetPackage) | ||
| .resolve("target").resolve("report").resolve("scan_results.json")); | ||
| } | ||
|
|
||
| private static ProcessOutputGobbler getOutput(Process process) throws InterruptedException { | ||
| ProcessOutputGobbler outputGobbler = new ProcessOutputGobbler(process.getInputStream()); | ||
| ProcessOutputGobbler errorGobbler = new ProcessOutputGobbler(process.getErrorStream()); | ||
| Thread outputThread = new Thread(outputGobbler); | ||
| Thread errorThread = new Thread(errorGobbler); | ||
| outputThread.start(); | ||
| errorThread.start(); | ||
| int exitCode = process.waitFor(); | ||
| outputGobbler.setExitCode(exitCode); | ||
| errorGobbler.setExitCode(exitCode); | ||
| outputThread.join(); | ||
| errorThread.join(); | ||
| return outputGobbler; | ||
| } | ||
|
|
||
| private void assertJsonEqual(String actual, String expected) { | ||
| Assert.assertEquals(normalizeJson(actual), normalizeJson(expected)); | ||
| } | ||
|
|
||
| private static String normalizeJson(String json) { | ||
| String normalizedJson = json.replaceAll("\\s*\"\\s*", "\"") | ||
| .replaceAll("\\s*:\\s*", ":") | ||
| .replaceAll("\\s*,\\s*", ",") | ||
| .replaceAll("\\s*\\{\\s*", "{") | ||
| .replaceAll("\\s*}\\s*", "}") | ||
| .replaceAll("\\s*\\[\\s*", "[") | ||
| .replaceAll("\\s*]\\s*", "]") | ||
| .replaceAll("\n", "") | ||
| .replaceAll(":\".*module-ballerina-file", ":\"module-ballerina-file"); | ||
| return isWindows() ? normalizedJson.replaceAll("/", "\\\\\\\\") : normalizedJson; | ||
| } | ||
|
|
||
| private static boolean isWindows() { | ||
| return System.getProperty("os.name").toLowerCase(Locale.ENGLISH).startsWith("windows"); | ||
| } | ||
| } |
8 changes: 8 additions & 0 deletions
8
...ugin-test/src/test/resources/static_code_analyzer/ballerina_packages/rule1/Ballerina.toml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| [package] | ||
| org = "sachink" | ||
| name = "rule1" | ||
| version = "0.1.0" | ||
| distribution = "2201.11.0-20250127-101700-a4b67fe5" | ||
|
|
||
| [build-options] | ||
| observabilityIncluded = true |
30 changes: 30 additions & 0 deletions
30
...ler-plugin-test/src/test/resources/static_code_analyzer/ballerina_packages/rule1/main.bal
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| // 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. | ||
|
|
||
| import ballerina/file; | ||
| import ballerina/os; | ||
| import ballerina/io; | ||
|
|
||
| public function main() { | ||
| string tempFolderPath = os:getEnv("TMP"); | ||
| error? output = file:create(tempFolderPath + "/" + "myfile.txt"); | ||
|
|
||
| if (output is error) { | ||
| io:println("Error occurred: " + output.message()); | ||
| } else { | ||
| io:println("File created successfully: " + tempFolderPath + "/" + "myfile.txt"); | ||
| } | ||
| } |
8 changes: 8 additions & 0 deletions
8
...ugin-test/src/test/resources/static_code_analyzer/ballerina_packages/rule2/Ballerina.toml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| [package] | ||
| org = "sachink" | ||
| name = "rule2" | ||
| version = "0.1.0" | ||
| distribution = "2201.11.0-20250127-101700-a4b67fe5" | ||
|
|
||
| [build-options] | ||
| observabilityIncluded = true | ||
30 changes: 30 additions & 0 deletions
30
...ler-plugin-test/src/test/resources/static_code_analyzer/ballerina_packages/rule2/main.bal
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| // 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. | ||
|
|
||
| import ballerina/file; | ||
| import ballerina/io; | ||
|
|
||
| public function executeCommand(string fileName) returns file:Error? { | ||
| string unsafeFilePath = "./target/" + fileName; | ||
| file:Error? remove = file:remove(unsafeFilePath); | ||
|
|
||
| return remove; | ||
| } | ||
|
|
||
| public function main() { | ||
| file:Error? result = executeCommand("sample.json"); | ||
| io:println("Result: ", result); | ||
| } |
58 changes: 58 additions & 0 deletions
58
compiler-plugin-test/src/test/resources/static_code_analyzer/expected_output/rule1.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| [ { | ||
| "location" : { | ||
| "filePath" : "main.bal", | ||
| "startLine" : 22, | ||
| "endLine" : 22, | ||
| "startColumn" : 20, | ||
| "endColumn" : 68, | ||
| "startOffset" : 800, | ||
| "length" : 48 | ||
| }, | ||
| "rule" : { | ||
| "id" : "ballerina/file:1", | ||
| "numericId" : 1, | ||
| "description" : "Avoid using publicly writable directories for file operations without proper access controls", | ||
| "ruleKind" : "VULNERABILITY" | ||
| }, | ||
| "source" : "BUILT_IN", | ||
| "fileName" : "rule1/main.bal", | ||
| "filePath" : "/Users/sachink/Desktop/module-ballerina-file/compiler-plugin-test/src/test/resources/static_code_analyzer/ballerina_packages/rule1/main.bal" | ||
| }, { | ||
| "location" : { | ||
| "filePath" : "main.bal", | ||
| "startLine" : 25, | ||
| "endLine" : 25, | ||
| "startColumn" : 8, | ||
| "endColumn" : 57, | ||
| "startOffset" : 886, | ||
| "length" : 49 | ||
| }, | ||
| "rule" : { | ||
| "id" : "ballerina/file:1", | ||
| "numericId" : 1, | ||
| "description" : "Avoid using publicly writable directories for file operations without proper access controls", | ||
| "ruleKind" : "VULNERABILITY" | ||
| }, | ||
| "source" : "BUILT_IN", | ||
| "fileName" : "rule1/main.bal", | ||
| "filePath" : "/Users/sachink/Desktop/module-ballerina-file/compiler-plugin-test/src/test/resources/static_code_analyzer/ballerina_packages/rule1/main.bal" | ||
| }, { | ||
| "location" : { | ||
| "filePath" : "main.bal", | ||
| "startLine" : 27, | ||
| "endLine" : 27, | ||
| "startColumn" : 8, | ||
| "endColumn" : 87, | ||
| "startOffset" : 958, | ||
| "length" : 79 | ||
| }, | ||
| "rule" : { | ||
| "id" : "ballerina/file:1", | ||
| "numericId" : 1, | ||
| "description" : "Avoid using publicly writable directories for file operations without proper access controls", | ||
| "ruleKind" : "VULNERABILITY" | ||
| }, | ||
| "source" : "BUILT_IN", | ||
| "fileName" : "rule1/main.bal", | ||
| "filePath" : "/Users/sachink/Desktop/module-ballerina-file/compiler-plugin-test/src/test/resources/static_code_analyzer/ballerina_packages/rule1/main.bal" | ||
| } ] |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.