Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions nohttp-checkstyle/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,22 @@ For example, the following will allowlist `http://example.com` and `http://examp
NOTE: Use `&#10` to specify new lines.


=== Excluding files matched by .gitignore

By default, `NoHttpCheck` additionally excludes any file matched by a `.gitignore` file found in `baseDir` (which defaults to the current working directory), so that paths already ignored by git (build output, IDE metadata, etc.) don't need to be duplicated in your checkstyle configuration or `<excludes>`. This is especially useful for Maven and Ant users, since (unlike Gradle) there is no dedicated nohttp plugin to configure exclusions on - `NoHttpCheck` is wired up directly via `maven-checkstyle-plugin` or the Ant checkstyle task, so this is applied automatically.

This can be disabled with the `useGitIgnore` property, and the directory that `.gitignore` is looked up from (and that paths are matched relative to) can be overridden with the `baseDir` property:

[source,xml]
----
<module name="io.spring.nohttp.checkstyle.check.NoHttpCheck">
<property name="useGitIgnore" value="false"/>
<property name="baseDir" value="${basedir}" default=""/>
</module>
----

NOTE: Only a single `.gitignore` file, at the root of `baseDir`, is considered; nested `.gitignore` files in subdirectories are not supported.

=== Suppress With Comments

The above <<configuration>> demonstrates how to suppress checks using https://checkstyle.org/config_filters.html#SuppressWithPlainTextCommentFilter[SuppressWithPlainTextCommentFilter]. For example, the following will ignore the URL `http://example.org/schema/` only in the location of code surrounded by the `CHECKSTYLE:OFF` / `CHECKSTYLE:ON` comments.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder;
import com.puppycrawl.tools.checkstyle.api.FileText;
import io.spring.nohttp.*;
import io.spring.nohttp.file.GitIgnoreFileFilter;

import java.io.ByteArrayInputStream;
import java.io.File;
Expand Down Expand Up @@ -111,11 +112,46 @@
* &lt;/module&gt;
* </pre>
*
* <h2>useGitIgnore</h2>
*
* <p>
* By default, files matched by a {@code .gitignore} file found in {@code baseDir} are
* additionally excluded, so that paths already ignored by git (build output, IDE
* metadata, etc.) do not need to be duplicated in the checkstyle configuration. Set to
* {@code false} to disable.
* </p>
*
* <pre>
* &lt;module name="io.spring.nohttp.checkstyle.check.NoHttpCheck"&gt;
* &lt;property name="useGitIgnore" value="false"/&gt;
* &lt;/module&gt;
* </pre>
*
* <h2>baseDir</h2>
*
* <p>
* The directory that a {@code .gitignore} file is looked up from, and that files are
* resolved relative to when matching {@code .gitignore} patterns. Defaults to the
* current working directory.
* </p>
*
* <pre>
* &lt;module name="io.spring.nohttp.checkstyle.check.NoHttpCheck"&gt;
* &lt;property name="baseDir" value="${basedir}" default=""/&gt;
* &lt;/module&gt;
* </pre>
*
* @author Rob Winch
*/
public class NoHttpCheck extends AbstractFileSetCheck implements ExternalResourceHolder {
private HttpMatcher matcher;

private String baseDir = System.getProperty("user.dir");

private boolean useGitIgnore = true;

private GitIgnoreFileFilter gitIgnoreFilter;

private String allowlistFileName = "";

private String allowlist = "";
Expand Down Expand Up @@ -159,6 +195,29 @@ public void setWhitelist(String allowlist) {
setWhitelistFileName(allowlist);
}

/**
* Sets the directory that a {@code .gitignore} file is looked up from, and that
* files are resolved relative to when matching {@code .gitignore} patterns.
* @param baseDir the base directory to use
* @since 0.0.12
*/
public void setBaseDir(String baseDir) {
if (baseDir == null) {
throw new IllegalArgumentException("baseDir cannot be null");
}
this.baseDir = baseDir;
}

/**
* Sets whether files matched by a {@code .gitignore} file found in {@link
* #setBaseDir(String) baseDir} should additionally be excluded.
* @param useGitIgnore true to exclude files matched by {@code .gitignore}
* @since 0.0.12
*/
public void setUseGitIgnore(boolean useGitIgnore) {
this.useGitIgnore = useGitIgnore;
}

private boolean isAllowlistFileSet() {
return !this.allowlistFileName.isEmpty();
}
Expand Down Expand Up @@ -190,11 +249,17 @@ protected void finishLocalSetup() throws CheckstyleException {
matcher.addHttpAllow(RegexPredicate.createAllowlistFromPatterns(inputStream));
}
this.matcher = matcher;

this.gitIgnoreFilter = this.useGitIgnore ?
GitIgnoreFileFilter.forBaseDir(new File(this.baseDir)).orElse(null) : null;
}

@Override
protected void processFiltered(File file, FileText fileText)
throws CheckstyleException {
if (this.gitIgnoreFilter != null && this.gitIgnoreFilter.test(file)) {
return;
}
int lineNum = 0;
for (int index = 0; index < fileText.size(); index++) {
final String line = fileText.get(index);
Expand All @@ -212,6 +277,12 @@ public Set<String> getExternalResourceLocations() {
if (isAllowlistFileSet()) {
result.add(this.allowlistFileName);
}
if (this.useGitIgnore) {
File gitignore = new File(this.baseDir, ".gitignore");
if (gitignore.isFile()) {
result.add(gitignore.getPath());
}
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,16 @@

package io.spring.nohttp.checkstyle.check;

import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
import com.puppycrawl.tools.checkstyle.api.FileText;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

import static org.assertj.core.api.Assertions.*;

Expand All @@ -25,6 +34,9 @@
*/
public class NoHttpCheckTest {

@Rule
public TemporaryFolder temp = new TemporaryFolder();

private NoHttpCheck check = new NoHttpCheck();

@Test
Expand All @@ -42,14 +54,100 @@ public void setAllowlistWhenNullThenIllegalArgumentException() {
}

@Test
public void getExternalResourceLocationsWhenNoAllowlistlistThenEmpty() {
public void setBaseDirWhenNullThenIllegalArgumentException() {
assertThatCode(() -> this.check.setBaseDir(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("baseDir cannot be null");
}

@Test
public void getExternalResourceLocationsWhenNoAllowlistlistThenEmpty() throws IOException {
this.check.setBaseDir(this.temp.newFolder().getPath());
assertThat(this.check.getExternalResourceLocations()).isEmpty();
}

@Test
public void getExternalResourceLocationsWhenAllowlistlistThenEmpty() {
public void getExternalResourceLocationsWhenAllowlistlistThenEmpty() throws IOException {
this.check.setBaseDir(this.temp.newFolder().getPath());
String allowlistFileName = "allowlist.lines";
this.check.setAllowlistFileName(allowlistFileName);
assertThat(this.check.getExternalResourceLocations()).containsOnly(allowlistFileName);
}

@Test
public void getExternalResourceLocationsWhenGitIgnoreThenIncludesGitIgnore() throws IOException {
File baseDir = this.temp.newFolder();
File gitignore = writeGitignore(baseDir);
this.check.setBaseDir(baseDir.getPath());

assertThat(this.check.getExternalResourceLocations()).containsOnly(gitignore.getPath());
}

@Test
public void getExternalResourceLocationsWhenGitIgnoreAndUseGitIgnoreDisabledThenEmpty() throws IOException {
File baseDir = this.temp.newFolder();
writeGitignore(baseDir);
this.check.setBaseDir(baseDir.getPath());
this.check.setUseGitIgnore(false);

assertThat(this.check.getExternalResourceLocations()).isEmpty();
}

@Test
public void processWhenGitIgnoredThenNoViolationsLogged() throws Exception {
File baseDir = this.temp.newFolder();
writeGitignore(baseDir, "ignored.txt");
File file = newFile(baseDir, "ignored.txt", "http://example.com");
this.check.setBaseDir(baseDir.getPath());
this.check.configure(new DefaultConfiguration("NoHttpCheck"));

assertThat(this.check.process(file, fileTextFor(file))).isEmpty();
}

@Test
public void processWhenNotGitIgnoredThenViolationsLogged() throws Exception {
File baseDir = this.temp.newFolder();
writeGitignore(baseDir, "ignored.txt");
File file = newFile(baseDir, "found.txt", "http://example.com");
this.check.setBaseDir(baseDir.getPath());
this.check.configure(new DefaultConfiguration("NoHttpCheck"));

assertThat(this.check.process(file, fileTextFor(file))).isNotEmpty();
}

@Test
public void processWhenGitIgnoredAndUseGitIgnoreDisabledThenViolationsLogged() throws Exception {
File baseDir = this.temp.newFolder();
writeGitignore(baseDir, "ignored.txt");
File file = newFile(baseDir, "ignored.txt", "http://example.com");
this.check.setBaseDir(baseDir.getPath());
this.check.setUseGitIgnore(false);
this.check.configure(new DefaultConfiguration("NoHttpCheck"));

assertThat(this.check.process(file, fileTextFor(file))).isNotEmpty();
}

private static FileText fileTextFor(File file) throws IOException {
return new FileText(file, StandardCharsets.UTF_8.name());
}

private static File writeGitignore(File baseDir, String... patterns) throws IOException {
File gitignore = new File(baseDir, ".gitignore");
StringBuilder content = new StringBuilder();
for (String pattern : patterns) {
content.append(pattern).append('\n');
}
if (patterns.length == 0) {
content.append("*.log\n");
}
Files.write(gitignore.toPath(), content.toString().getBytes());
return gitignore;
}

private static File newFile(File baseDir, String relativePath, String content) throws IOException {
File file = new File(baseDir, relativePath);
file.getParentFile().mkdirs();
Files.write(file.toPath(), content.getBytes());
return file;
}
}
7 changes: 5 additions & 2 deletions nohttp-cli/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ Keep in mind this may delete things you want (i.e. IDE related files).
=== Hello nohttp

The easiest approach is to run the application with no arguments.
This will attempt to find http in all text based files in the current directory while ignoring `.git` folder.
This will attempt to find http in all text based files in the current directory while ignoring the `.git` folder.
If a `.gitignore` file exists at the root of the scanned directory, files it matches are excluded as well; use the `-g` flag shown in <<help,Help>> to disable this.

[NOTE]
====
Expand Down Expand Up @@ -84,7 +85,7 @@ You can get help with additional options using `--help`.
----
java -jar $NOHTTP --help
...
Usage: nohttp [-fhMrsTV] [-w=<allowlistFile>] [-D=<regex>]... [-F=<regex>]...
Usage: nohttp [-fghMrsTV] [-w=<allowlistFile>] [-D=<regex>]... [-F=<regex>]...
[<dir>]
[<dir>] The directory to scan. Default is current working directory.
-D=<regex> Regular expression of directories to exclude scanning.
Expand All @@ -94,6 +95,8 @@ Usage: nohttp [-fhMrsTV] [-w=<allowlistFile>] [-D=<regex>]... [-F=<regex>]...
-F=<regex> Regular expression of files to exclude scanning. Specify
multiple times to provide multiple exclusions. Default is
no file exclusions.
-g Disable additionally excluding files matched by a .gitignore
file found at the root of the scanned directory.
-h, --help Show this help message and exit.
-M Disables printing each match within their specific files.
-r Enables replacing the values that were found. The default is
Expand Down
2 changes: 2 additions & 0 deletions nohttp-cli/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ repositories {
dependencies {
compile project(':nohttp')
compile 'info.picocli:picocli:3.9.5'
testCompile 'junit:junit'
testCompile 'org.assertj:assertj-core'
}

shadowJar {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.spring.nohttp.RegexPredicate;
import io.spring.nohttp.StatusHttpReplacer;
import io.spring.nohttp.file.DirScanner;
import io.spring.nohttp.file.GitIgnoreFileFilter;
import io.spring.nohttp.file.PreGradle21Scanner;
import io.spring.nohttp.file.HttpMatcherProcessor;
import io.spring.nohttp.file.HttpReplacerProcessor;
Expand Down Expand Up @@ -68,6 +69,9 @@ public class ReplaceFilesRunner implements Callable<Integer> {
@CommandLine.Option(names = "-F", paramLabel = "<regex>", description = "Regular expression of files to exclude scanning. Specify multiple times to provide multiple exclusions. Default is no file exclusions.")
private List<Pattern> fileExclusions = new ArrayList<>();

@CommandLine.Option(names = "-g", description = "Disable additionally excluding files matched by a .gitignore file found at the root of the scanned directory.", defaultValue = "true")
private boolean gitIgnore = true;

@CommandLine.Option(names = "-M", description = "Disables printing each match within their specific files.", defaultValue = "false")
private boolean disablePrintMatches;

Expand Down Expand Up @@ -98,11 +102,17 @@ public Integer call() throws Exception {

System.out.println();
System.out.println("Looking for restricted http:// URLs");
DirScanner.create(this.dir)
DirScanner scanner = DirScanner.create(this.dir)
.textFiles(this.textFilesOnly)
.excludeDirs(dirExclusions())
.excludeFiles(fileExclusions())
.scan(withHttpProcessor(processor));
.excludeFiles(fileExclusions());
if (this.gitIgnore) {
GitIgnoreFileFilter.forBaseDir(this.dir).ifPresent(filter -> {
scanner.excludeDirs(filter);
scanner.excludeFiles(filter);
});
}
scanner.scan(withHttpProcessor(processor));

Set<String> httpUrlMatches = processor.getHttpMatches();
writeSummaryReport(httpUrlMatches);
Expand Down
Loading