forked from phoedos/pmd
Merged
This commit is contained in:
11
.travis.yml
11
.travis.yml
@ -8,19 +8,10 @@ addons:
|
||||
language: java
|
||||
jdk: oraclejdk8
|
||||
before_install:
|
||||
- bash .travis/setup-secrets.sh
|
||||
- bash .travis/install-configure-maven.sh
|
||||
- export M2_HOME=$HOME/apache-maven-3.3.9
|
||||
- export PATH=$HOME/apache-maven-3.3.9/bin:${PATH}
|
||||
- openssl aes-256-cbc -K $encrypted_5630fbebf057_key -iv $encrypted_5630fbebf057_iv -in .travis/secrets.tar.enc -out .travis/secrets.tar -d
|
||||
- pushd .travis && tar xfv secrets.tar && popd
|
||||
- mkdir -p "$HOME/.ssh"
|
||||
- chmod 700 "$HOME/.ssh"
|
||||
- mv .travis/id_rsa "$HOME/.ssh/id_rsa"
|
||||
- chmod 600 "$HOME/.ssh/id_rsa"
|
||||
- mkdir -p "$HOME/.gpg"
|
||||
- gpg --batch --import .travis/release-signing-key-82DE7BE82166E84E.gpg
|
||||
- rm .travis/secrets.tar
|
||||
- rm .travis/release-signing-key-82DE7BE82166E84E.gpg
|
||||
install: mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V
|
||||
before_script: true
|
||||
script:
|
||||
|
43
.travis/background-job-funcs.sh
Normal file
43
.travis/background-job-funcs.sh
Normal file
@ -0,0 +1,43 @@
|
||||
#
|
||||
# Helper functions to run a chatty, long task in the background,
|
||||
# redirecting the output to file and keep travis happy by regularly
|
||||
# writing to the log.
|
||||
#
|
||||
# This is to workaround the travis log length limit of 4MB
|
||||
# Solution from http://stackoverflow.com/questions/26082444/how-to-work-around-travis-cis-4mb-output-limit/26082445#26082445
|
||||
#
|
||||
# Source this file into the shell script, that needs it.
|
||||
#
|
||||
# expected variables
|
||||
# Name | Example Value
|
||||
# PING_SLEEP | 30s
|
||||
# BUILD_OUTPUT | /tmp/build-step-logfile.out
|
||||
# PING_PID_FILE | /tmp/build-step-ping.pid
|
||||
|
||||
touch $BUILD_OUTPUT
|
||||
|
||||
dump_output() {
|
||||
echo Tailing the last 100 lines of output:
|
||||
tail -100 $BUILD_OUTPUT
|
||||
}
|
||||
kill_ping() {
|
||||
if [ -e $PING_PID_FILE ]; then
|
||||
PING_LOOP_PID=$(cat $PING_PID_FILE)
|
||||
kill $PING_LOOP_PID
|
||||
rm $PING_PID_FILE
|
||||
fi
|
||||
}
|
||||
error_handler() {
|
||||
kill_ping
|
||||
echo ERROR: An error was encountered with the build.
|
||||
dump_output
|
||||
exit 1
|
||||
}
|
||||
# If an error occurs, run our error handler to output a tail of the build
|
||||
trap 'error_handler' ERR
|
||||
|
||||
# Set up a repeating loop to send some output to Travis.
|
||||
bash -c "while true; do echo \$(date) - building ...; sleep $PING_SLEEP; done" &
|
||||
PING_LOOP_PID=$!
|
||||
echo "$PING_LOOP_PID" > $PING_PID_FILE
|
||||
|
@ -5,11 +5,19 @@ VERSION=$(mvn -q -Dexec.executable="echo" -Dexec.args='${project.version}' --non
|
||||
echo "Building PMD ${VERSION} on branch ${TRAVIS_BRANCH}"
|
||||
|
||||
if [[ "$VERSION" != *-SNAPSHOT && "$TRAVIS_TAG" != "" ]]; then
|
||||
# release build
|
||||
mvn deploy -Possrh,pmd-release -B -V
|
||||
else
|
||||
elif [[ "$VERSION" == *-SNAPSHOT ]]; then
|
||||
# snapshot build
|
||||
mvn deploy -Possrh -B -V
|
||||
else
|
||||
# other build. Can happen during release: the commit with a non snapshot version is built, but not from the tag.
|
||||
mvn verify -Possrh -B -V
|
||||
# we stop here - no need to execute further steps
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
bash .travis/build-site.sh
|
||||
|
||||
# create pmd-doc archive
|
||||
@ -33,6 +41,6 @@ fi
|
||||
|
||||
if [[ "$VERSION" == *-SNAPSHOT && "$TRAVIS_BRANCH" == "master" ]]; then
|
||||
# only do a clean build for sonar, if we are executing a snapshot build, otherwise we can't reuse the build from above for the release
|
||||
mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar -Dsonar.host.url=https://sonarqube.com -Dsonar.login=${SONAR_TOKEN} -B -V
|
||||
bash .travis/build-sonar.sh
|
||||
fi
|
||||
|
||||
|
@ -1,41 +1,11 @@
|
||||
#!/bin/bash
|
||||
set -ev
|
||||
|
||||
# Do not log the output, to avoid the travis log length limit of 4MB
|
||||
# Solution from http://stackoverflow.com/questions/26082444/how-to-work-around-travis-cis-4mb-output-limit/26082445#26082445
|
||||
|
||||
|
||||
|
||||
export PING_SLEEP=30s
|
||||
export BUILD_OUTPUT=/tmp/build-site.out
|
||||
export PING_PID_FILE=/tmp/build-site-ping.pid
|
||||
|
||||
touch $BUILD_OUTPUT
|
||||
|
||||
dump_output() {
|
||||
echo Tailing the last 500 lines of output:
|
||||
tail -500 $BUILD_OUTPUT
|
||||
}
|
||||
kill_ping() {
|
||||
if [ -e $PING_PID_FILE ]; then
|
||||
PING_LOOP_PID=$(cat $PING_PID_FILE)
|
||||
kill $PING_LOOP_PID
|
||||
rm $PING_PID_FILE
|
||||
fi
|
||||
}
|
||||
error_handler() {
|
||||
kill_ping
|
||||
echo ERROR: An error was encountered with the build.
|
||||
dump_output
|
||||
exit 1
|
||||
}
|
||||
# If an error occurs, run our error handler to output a tail of the build
|
||||
trap 'error_handler' ERR
|
||||
|
||||
# Set up a repeating loop to send some output to Travis.
|
||||
bash -c "while true; do echo \$(date) - building ...; sleep $PING_SLEEP; done" &
|
||||
PING_LOOP_PID=$!
|
||||
echo "$PING_LOOP_PID" > $PING_PID_FILE
|
||||
source .travis/background-job-funcs.sh
|
||||
|
||||
# Run the build, redirect output into the file
|
||||
mvn site site:stage -Psite -B -V >> $BUILD_OUTPUT 2>&1
|
||||
|
18
.travis/build-sonar.sh
Normal file
18
.travis/build-sonar.sh
Normal file
@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
set -ev
|
||||
|
||||
export PING_SLEEP=30s
|
||||
export BUILD_OUTPUT=/tmp/build-sonar.out
|
||||
export PING_PID_FILE=/tmp/build-sonar-ping.pid
|
||||
|
||||
source .travis/background-job-funcs.sh
|
||||
|
||||
# Run the build, redirect output into the file
|
||||
mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar -Dsonar.host.url=https://sonarqube.com -Dsonar.login=${SONAR_TOKEN} -B -V >> $BUILD_OUTPUT 2>&1
|
||||
|
||||
# The build finished without returning an error so dump a tail of the output
|
||||
dump_output
|
||||
|
||||
# nicely terminate the ping output loop
|
||||
kill_ping
|
||||
|
19
.travis/setup-secrets.sh
Normal file
19
.travis/setup-secrets.sh
Normal file
@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
set -ev
|
||||
|
||||
if [ "$TRAVIS_PULL_REQUEST" != "false" ] || [ "${TRAVIS_SECURE_ENV_VARS}" != "true" ]; then
|
||||
echo "Not setting up secrets (TRAVIS_PULL_REQUEST=${TRAVIS_PULL_REQUEST} TRAVIS_SECURE_ENV_VARS=${TRAVIS_SECURE_ENV_VARS})."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
openssl aes-256-cbc -K $encrypted_5630fbebf057_key -iv $encrypted_5630fbebf057_iv -in .travis/secrets.tar.enc -out .travis/secrets.tar -d
|
||||
pushd .travis && tar xfv secrets.tar && popd
|
||||
mkdir -p "$HOME/.ssh"
|
||||
chmod 700 "$HOME/.ssh"
|
||||
mv .travis/id_rsa "$HOME/.ssh/id_rsa"
|
||||
chmod 600 "$HOME/.ssh/id_rsa"
|
||||
mkdir -p "$HOME/.gpg"
|
||||
gpg --batch --import .travis/release-signing-key-82DE7BE82166E84E.gpg
|
||||
rm .travis/secrets.tar
|
||||
rm .travis/release-signing-key-82DE7BE82166E84E.gpg
|
@ -57,6 +57,8 @@ import com.google.common.collect.ListMultimap;
|
||||
*/
|
||||
public class ApexCRUDViolationRule extends AbstractApexRule {
|
||||
private static final Pattern VOID_OR_STRING_PATTERN = Pattern.compile("^(string|void)$", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern SELECT_FROM_PATTERN = Pattern.compile("^[\\S|\\s]+?FROM[\\s]+?(\\S+)",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private final HashMap<String, String> varToTypeMapping = new HashMap<>();
|
||||
private final ListMultimap<String, String> typeToDMLOperationMapping = ArrayListMultimap.create();
|
||||
@ -480,6 +482,7 @@ public class ApexCRUDViolationRule extends AbstractApexRule {
|
||||
|
||||
private void checkForAccessibility(final ASTSoqlExpression node, Object data) {
|
||||
final boolean isCount = node.getNode().getCanonicalQuery().startsWith("SELECT COUNT()");
|
||||
final String typeFromSOQL = getTypeFromSOQLQuery(node);
|
||||
|
||||
final HashSet<ASTMethodCallExpression> prevCalls = getPreviousMethodCalls(node);
|
||||
for (ASTMethodCallExpression prevCall : prevCalls) {
|
||||
@ -510,7 +513,7 @@ public class ApexCRUDViolationRule extends AbstractApexRule {
|
||||
.append(":").append(type);
|
||||
|
||||
if (!isGetter) {
|
||||
validateCRUDCheckPresent(node, data, ANY, typeCheck.toString());
|
||||
validateCRUDCheckPresent(node, data, ANY, typeFromSOQL == null ? typeCheck.toString() : typeFromSOQL);
|
||||
}
|
||||
|
||||
}
|
||||
@ -523,7 +526,7 @@ public class ApexCRUDViolationRule extends AbstractApexRule {
|
||||
if (varToTypeMapping.containsKey(variableWithClass)) {
|
||||
String type = varToTypeMapping.get(variableWithClass);
|
||||
if (!isGetter) {
|
||||
validateCRUDCheckPresent(node, data, ANY, type);
|
||||
validateCRUDCheckPresent(node, data, ANY, typeFromSOQL == null ? type : typeFromSOQL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -533,11 +536,23 @@ public class ApexCRUDViolationRule extends AbstractApexRule {
|
||||
final ASTReturnStatement returnStatement = node.getFirstParentOfType(ASTReturnStatement.class);
|
||||
if (returnStatement != null) {
|
||||
if (!isGetter) {
|
||||
validateCRUDCheckPresent(node, data, ANY, returnType == null ? "" : returnType);
|
||||
String retType = typeFromSOQL == null ? returnType : typeFromSOQL;
|
||||
validateCRUDCheckPresent(node, data, ANY, retType == null ? "" : retType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getTypeFromSOQLQuery(final ASTSoqlExpression node) {
|
||||
final String canonQuery = node.getNode().getCanonicalQuery();
|
||||
|
||||
Matcher m = SELECT_FROM_PATTERN.matcher(canonQuery);
|
||||
while (m.find()) {
|
||||
return new StringBuffer().append(node.getNode().getDefiningType().getApexName()).append(":")
|
||||
.append(m.group(1)).toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getReturnType(final ASTMethod method) {
|
||||
return new StringBuilder().append(method.getNode().getDefiningType().getApexName()).append(":")
|
||||
.append(method.getNode().getMethodInfo().getEmitSignature().getReturnType().getApexName()).toString();
|
||||
|
@ -2,6 +2,37 @@
|
||||
|
||||
<test-data>
|
||||
|
||||
<test-code>
|
||||
<description>Proper CRUD checks for Aggregate Result</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public void justGiveMeFoo() {
|
||||
if (Opportunity.sObjectType.getDescribe().isAccessible()) {
|
||||
return;
|
||||
}
|
||||
AggregateResult[] test = [SELECT Id FROM Opportunity];
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
|
||||
<test-code>
|
||||
<description>Proper CRUD checks for Aggregate Result return</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public AggregateResult[] justGiveMeFoo() {
|
||||
if (Opportunity.sObjectType.getDescribe().isAccessible()) {
|
||||
return null;
|
||||
}
|
||||
return [SELECT Id FROM Opportunity];
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>Not a getter</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
@ -688,7 +719,7 @@ public class Foo {
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
|
||||
<test-code>
|
||||
<description>Field detection</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
@ -703,5 +734,4 @@ public class MyProfilePageController {
|
||||
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
</test-data>
|
||||
|
@ -235,6 +235,7 @@ public class VfUnescapeElRule extends AbstractVfRule {
|
||||
case "$remoteaction":
|
||||
return true;
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
@ -385,9 +386,9 @@ public class VfUnescapeElRule extends AbstractVfRule {
|
||||
case "id":
|
||||
case "size":
|
||||
case "caseNumber":
|
||||
return true;
|
||||
return true;
|
||||
default:
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (child instanceof ASTDotExpression) {
|
||||
|
4
pom.xml
4
pom.xml
@ -8,7 +8,7 @@
|
||||
<name>PMD</name>
|
||||
|
||||
<description>
|
||||
PMD is a source code analyzer. It finds common programming flaws like unused variables, empty catch blocks, unnecessary object creation, and so forth. It supports Java, JavaScript, Salesforce.com Apex, PLSQL, Apache Velocity, XML, XSL.
|
||||
PMD is a source code analyzer. It finds common programming flaws like unused variables, empty catch blocks, unnecessary object creation, and so forth. It supports Java, JavaScript, Salesforce.com Apex, PLSQL, Salesforce.com Visualforce, Apache Velocity, XML, XSL.
|
||||
|
||||
Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code in Java, C, C++, C#, Groovy, PHP, Ruby, Fortran, JavaScript, PLSQL, Apache Velocity, Scala, Objective C, Matlab, Python, Go, Swift and Salesforce.com Apex.
|
||||
</description>
|
||||
@ -1039,7 +1039,6 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code
|
||||
<module>pmd-java</module>
|
||||
<module>pmd-javascript</module>
|
||||
<module>pmd-jsp</module>
|
||||
<module>pmd-visualforce</module>
|
||||
<module>pmd-matlab</module>
|
||||
<module>pmd-objectivec</module>
|
||||
<module>pmd-perl</module>
|
||||
@ -1049,6 +1048,7 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code
|
||||
<module>pmd-ruby</module>
|
||||
<module>pmd-swift</module>
|
||||
<module>pmd-test</module>
|
||||
<module>pmd-visualforce</module>
|
||||
<module>pmd-vm</module>
|
||||
<module>pmd-xml</module>
|
||||
</modules>
|
||||
|
@ -4,7 +4,8 @@
|
||||
|
||||
The PMD team is pleased to announce PMD 5.6.0.
|
||||
|
||||
The most significant changes are on analysis performance and a whole new **Apex Security Rule Set**.
|
||||
The most significant changes are on analysis performance, support for Salesforce's Visualforce language
|
||||
a whole new **Apex Security Rule Set**.
|
||||
|
||||
We have added initial support for **incremental analysis**. The experimental feature allows
|
||||
PMD to cache analysis results between executions to speed up the analysis for all
|
||||
@ -29,6 +30,7 @@ making it over 500X faster, and `PreserveStackTrace` which is now 7X faster.
|
||||
|
||||
* [New and noteworthy](#New_and_noteworthy)
|
||||
* [Incremental Analysis](#Incremental_Analysis)
|
||||
* [Visualforce Support](#Visualforce_support)
|
||||
* [Apex Security Rule Set](#Apex_Security_Rule_Set)
|
||||
* [New Rules](#New_Rules)
|
||||
* [Modified Rules](#Modified_Rules)
|
||||
@ -41,7 +43,7 @@ making it over 500X faster, and `PreserveStackTrace` which is now 7X faster.
|
||||
|
||||
#### Incremental Analysis
|
||||
|
||||
PMD now support incremental analysis. Analysis results can be cached and reused between runs.
|
||||
PMD now supports incremental analysis. Analysis results can be cached and reused between runs.
|
||||
This allows PMD to skip files without violations that have remained unchanged. In future releases,
|
||||
we plan to extend this behavior to unchanged files with violations too.
|
||||
|
||||
@ -71,6 +73,18 @@ For Ant, a new `cacheLocation` attribute has been added. For instance:
|
||||
</target>
|
||||
```
|
||||
|
||||
#### Visualforce Support
|
||||
|
||||
Salesforce developers rejoice. To out growing Apex support we have added full Visualforce support.
|
||||
Both CPD and PD are available. So far only a security ruleset is available (`vf-security`).
|
||||
|
||||
##### Visualforce Security Rule Set
|
||||
|
||||
###### VfUnescapeEl
|
||||
|
||||
The rule looks for Expression Language occurances printing unescaped values from the backend. These
|
||||
could lead to XSS attacks.
|
||||
|
||||
#### Apex Security Rule Set
|
||||
|
||||
A new ruleset focused on security has been added, consisting of a wide range of rules
|
||||
@ -410,4 +424,5 @@ For example:
|
||||
* [#266](https://github.com/pmd/pmd/pull/266): \[java] corrected invalid reporting of LoD violation
|
||||
* [#268](https://github.com/pmd/pmd/pull/268): \[apex] Support safe escaping via String method
|
||||
* [#273](https://github.com/pmd/pmd/pull/273): \[apex] Shade jackson on apex
|
||||
* [#280](https://github.com/pmd/pmd/pull/280): \[apex] Support for Aggregate Result in CRUD rules
|
||||
|
||||
|
Reference in New Issue
Block a user