Skip to content

Commit c72fe34

Browse files
Added methods to handle making URIs relative to another URI. Improved SARIF production to better deal with rules and artifact information. SARIF files now work on commonly avviable viewers.
1 parent 08982f6 commit c72fe34

File tree

12 files changed

+565
-267
lines changed

12 files changed

+565
-267
lines changed

cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/CLIProcessor.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,14 @@ public class CLIProcessor {
110110
SHOW_STACK_TRACE_OPTION,
111111
VERSION_OPTION);
112112

113+
public static final String COMMAND_VERSION = "http://csrc.nist.gov/ns/metaschema-java/cli/command-version";
114+
113115
@NonNull
114116
private final List<ICommand> commands = new LinkedList<>();
115117
@NonNull
116118
private final String exec;
117119
@NonNull
118-
private final List<IVersionInfo> versionInfos;
120+
private final Map<String, IVersionInfo> versionInfos;
119121

120122
public static void main(String... args) {
121123
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
@@ -130,10 +132,10 @@ public static void main(String... args) {
130132

131133
@SuppressWarnings("null")
132134
public CLIProcessor(@NonNull String exec) {
133-
this(exec, List.of());
135+
this(exec, Map.of());
134136
}
135137

136-
public CLIProcessor(@NonNull String exec, @NonNull List<IVersionInfo> versionInfos) {
138+
public CLIProcessor(@NonNull String exec, @NonNull Map<String, IVersionInfo> versionInfos) {
137139
this.exec = exec;
138140
this.versionInfos = versionInfos;
139141
AnsiConsole.systemInstall();
@@ -155,7 +157,7 @@ public String getExec() {
155157
* @return the versionInfo
156158
*/
157159
@NonNull
158-
public List<IVersionInfo> getVersionInfos() {
160+
public Map<String, IVersionInfo> getVersionInfos() {
159161
return versionInfos;
160162
}
161163

@@ -207,7 +209,6 @@ private static void handleNoColor() {
207209
AnsiConsole.systemUninstall();
208210
}
209211

210-
@SuppressWarnings("resource")
211212
public static void handleQuiet() {
212213
LoggerContext ctx = (LoggerContext) LogManager.getContext(false); // NOPMD not closable here
213214
Configuration config = ctx.getConfiguration();
@@ -221,7 +222,7 @@ public static void handleQuiet() {
221222

222223
protected void showVersion() {
223224
@SuppressWarnings("resource") PrintStream out = AnsiConsole.out(); // NOPMD - not owner
224-
getVersionInfos().stream().forEach(info -> {
225+
getVersionInfos().values().stream().forEach(info -> {
225226
out.println(ansi()
226227
.bold().a(info.getName()).boldOff()
227228
.a(" ")
@@ -309,6 +310,11 @@ public CallingContext(@NonNull List<String> args) {
309310
this.extraArgs = extraArgs;
310311
}
311312

313+
@NonNull
314+
public CLIProcessor getCLIProcessor() {
315+
return CLIProcessor.this;
316+
}
317+
312318
@Nullable
313319
public ICommand getTargetCommand() {
314320
return calledCommands.peekLast();

core/metaschema

core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/node/AbstractFlagInstanceNodeItem.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030
import gov.nist.secauto.metaschema.core.model.IFlagDefinition;
3131
import gov.nist.secauto.metaschema.core.model.IFlagInstance;
3232

33-
import java.net.URI;
34-
3533
import edu.umd.cs.findbugs.annotations.NonNull;
3634

3735
/**
@@ -72,11 +70,6 @@ public IFlagInstance getInstance() {
7270
return parent;
7371
}
7472

75-
@Override
76-
public URI getBaseUri() {
77-
return getDefinition().getContainingModule().getLocation();
78-
}
79-
8073
@Override
8174
public String toString() {
8275
StringBuilder builder = new StringBuilder()

core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/ConstraintValidationFinding.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,9 @@ public Level getSeverity() {
149149
return severity;
150150
}
151151

152-
@SuppressWarnings("null")
153152
@Override
154-
public @NonNull URI getDocumentUri() {
155-
return getNode().getBaseUri();
153+
public URI getDocumentUri() {
154+
return getTarget().getBaseUri();
156155
}
157156

158157
@NonNull

core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/FindingCollectingConstraintValidationHandler.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ public void handleAllowedValuesViolation(
235235
public void handleIndexDuplicateViolation(IIndexConstraint constraint, INodeItem node) {
236236
addFinding(ConstraintValidationFinding.builder(constraint, node)
237237
.kind(Kind.FAIL)
238+
.target(node)
238239
.message(newIndexDuplicateViolationMessage(constraint, node))
239240
.severity(Level.CRITICAL)
240241
.build());
@@ -245,6 +246,7 @@ public void handleIndexMiss(IIndexHasKeyConstraint constraint, INodeItem node, I
245246
addFinding(ConstraintValidationFinding.builder(constraint, node)
246247
.severity(constraint.getLevel())
247248
.kind(toKind(constraint.getLevel()))
249+
.target(target)
248250
.message(newIndexMissMessage(constraint, node, target, key))
249251
.build());
250252
}
@@ -255,13 +257,15 @@ public void handleGenericValidationViolation(IConstraint constraint, INodeItem n
255257
addFinding(ConstraintValidationFinding.builder(constraint, node)
256258
.severity(constraint.getLevel())
257259
.kind(toKind(constraint.getLevel()))
260+
.target(target)
258261
.message(newGenericValidationViolationMessage(constraint, node, target, message))
259262
.build());
260263
}
261264

262265
@Override
263266
public void handlePass(IConstraint constraint, INodeItem node, INodeItem target) {
264267
addFinding(ConstraintValidationFinding.builder(constraint, node)
268+
.target(target)
265269
.severity(Level.NONE)
266270
.kind(Kind.PASS)
267271
.build());

core/src/main/java/gov/nist/secauto/metaschema/core/model/validation/IValidationFinding.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ enum Kind {
6363
/**
6464
* Get the document's URI.
6565
*
66-
* @return the document's URI
66+
* @return the document's URI or {@code null} if it is not known
6767
*/
68-
@NonNull
68+
@Nullable
6969
URI getDocumentUri();
7070

7171
/**

core/src/main/java/gov/nist/secauto/metaschema/core/util/UriUtils.java

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,15 @@
3131
import java.nio.file.InvalidPathException;
3232
import java.nio.file.Path;
3333
import java.nio.file.Paths;
34+
import java.util.Arrays;
35+
import java.util.Objects;
36+
import java.util.regex.Pattern;
3437

3538
import edu.umd.cs.findbugs.annotations.NonNull;
3639

3740
public final class UriUtils {
41+
private static final Pattern URI_SEPERATOR_PATTERN = Pattern.compile("\\/");
42+
private static final String URI_SEPERATOR = "/";
3843

3944
private UriUtils() {
4045
// disable construction
@@ -71,4 +76,92 @@ public static URI toUri(@NonNull String location, @NonNull URI baseUri) throws U
7176
}
7277
return baseUri.resolve(asUri.normalize());
7378
}
79+
80+
/**
81+
* This function extends the functionality of {@link URI#relativize(URI)} by
82+
* supporting relative reference pathing (e.g., ..), when the {@code prepend}
83+
* parameter is set to {@code true}.
84+
*
85+
* @param base
86+
* the URI to relativize against
87+
* @param other
88+
* the URI to make relative
89+
* @param prepend
90+
* if {@code true}, then prepend relative pathing
91+
* @return a new relative URI
92+
* @throws URISyntaxException
93+
* if any of the URIs are malformed
94+
*/
95+
public static URI relativize(URI base, URI other, boolean prepend) throws URISyntaxException {
96+
URI normBase = Objects.requireNonNull(base).normalize();
97+
URI normOther = Objects.requireNonNull(other).normalize();
98+
URI retval = normBase.relativize(normOther);
99+
100+
if (prepend && !normBase.isOpaque() && !retval.isOpaque() && hasSameSchemeAndAuthority(normBase, retval)) {
101+
// the URIs are not opaque and they share the same scheme and authority
102+
String basePath = normBase.getPath();
103+
String targetPath = normOther.getPath();
104+
String newPath = prependRelativePath(basePath, targetPath);
105+
106+
retval = new URI(null, null, newPath, normOther.getQuery(), normOther.getFragment());
107+
}
108+
109+
return retval;
110+
}
111+
112+
private static boolean hasSameSchemeAndAuthority(URI base, URI other) {
113+
String baseScheme = base.getScheme();
114+
boolean retval = (baseScheme == null && other.getScheme() == null)
115+
|| (baseScheme != null && baseScheme.equals(other.getScheme()));
116+
String baseAuthority = base.getAuthority();
117+
retval = retval && ((baseAuthority == null && other.getAuthority() == null)
118+
|| (baseAuthority != null && baseAuthority.equals(other.getAuthority())));
119+
return retval;
120+
}
121+
122+
/**
123+
* Based on code from
124+
* http://stackoverflow.com/questions/10801283/get-relative-path-of-two-uris-in-java
125+
*
126+
* @param base
127+
* the base path to resolve against
128+
* @param target
129+
* the URI to relativize against the base
130+
* @return the relativized URI
131+
*/
132+
public static String prependRelativePath(String base, String target) {
133+
134+
// Split paths into segments
135+
String[] baseSegments = URI_SEPERATOR_PATTERN.split(base);
136+
String[] targetSegments = URI_SEPERATOR_PATTERN.split(target, -1);
137+
138+
// Discard trailing segment of base path, since this resource doesn't matter
139+
if (baseSegments.length > 0 && !base.endsWith(URI_SEPERATOR)) {
140+
baseSegments = Arrays.copyOf(baseSegments, baseSegments.length - 1);
141+
}
142+
143+
// Remove common prefix segments
144+
int segmentIndex = 0;
145+
while (segmentIndex < baseSegments.length && segmentIndex < targetSegments.length
146+
&& baseSegments[segmentIndex].equals(targetSegments[segmentIndex])) {
147+
segmentIndex++;
148+
}
149+
150+
// Construct the relative path
151+
StringBuilder retval = new StringBuilder();
152+
for (int j = 0; j < (baseSegments.length - segmentIndex); j++) {
153+
retval.append("..");
154+
if (retval.length() != 0) {
155+
retval.append(URI_SEPERATOR);
156+
}
157+
}
158+
159+
for (int j = segmentIndex; j < targetSegments.length; j++) {
160+
retval.append(targetSegments[j]);
161+
if (retval.length() != 0 && j < targetSegments.length - 1) {
162+
retval.append(URI_SEPERATOR);
163+
}
164+
}
165+
return retval.toString();
166+
}
74167
}

core/src/test/java/gov/nist/secauto/metaschema/core/util/UriUtilsTest.java

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.junit.jupiter.params.provider.MethodSource;
3434

3535
import java.net.URI;
36+
import java.net.URISyntaxException;
3637
import java.nio.file.Path;
3738
import java.nio.file.Paths;
3839
import java.util.stream.Stream;
@@ -61,16 +62,72 @@ private static Stream<Arguments> provideValuesTestToUri() {
6162

6263
@ParameterizedTest
6364
@MethodSource("provideValuesTestToUri")
64-
void testToUri(@NonNull String location, boolean expectedResult) {
65+
void testToUri(@NonNull String location, boolean expectedResult) throws URISyntaxException {
6566
boolean result = INVALID;
6667
Path cwd = Paths.get("");
67-
try {
68-
URI uri = UriUtils.toUri(location, cwd.toAbsolutePath().toUri());
69-
result = VALID;
70-
System.out.println(String.format("%s -> %s", location, uri.toASCIIString()));
71-
} catch (Exception ex) {
72-
ex.printStackTrace();
73-
}
68+
URI uri = UriUtils.toUri(location, cwd.toAbsolutePath().toUri());
69+
result = VALID;
70+
// System.out.println(String.format("%s -> %s", location, uri.toASCIIString()));
7471
assertEquals(result, expectedResult);
7572
}
73+
74+
private static Stream<Arguments> provideArgumentsTestRelativize() {
75+
return Stream.of(
76+
Arguments.of(
77+
"http://example.com/this/file1.txt",
78+
"http://example.com/this/file2.txt",
79+
true,
80+
"file2.txt"),
81+
Arguments.of(
82+
"http://example.com/this",
83+
"http://example.com/this/that",
84+
true,
85+
"that"),
86+
Arguments.of(
87+
"http://example.com/this/",
88+
"http://example.com/this/that",
89+
true,
90+
"that"),
91+
Arguments.of(
92+
"http://example.com/this/that",
93+
"http://example.com/this/new",
94+
true,
95+
"new"),
96+
Arguments.of(
97+
"http://example.com/this/that/A",
98+
"http://example.com/this/new/B",
99+
true,
100+
"../new/B"),
101+
Arguments.of(
102+
"http://example.com/this/that/",
103+
"http://example.com/this/new/",
104+
true,
105+
"../new/"),
106+
Arguments.of(
107+
"http://example.com/this/that/A/",
108+
"http://example.com/this/new/B",
109+
true,
110+
"../../new/B"),
111+
Arguments.of(
112+
"http://example.com/this/that/A/X/file1,text",
113+
"http://example.com/this/that/A/file2.txt",
114+
true,
115+
"../file2.txt"),
116+
Arguments.of(
117+
"http://example.com/this/that/A/",
118+
"http://example.org/this/new/B",
119+
true,
120+
"http://example.org/this/new/B"));
121+
}
122+
123+
@ParameterizedTest
124+
@MethodSource("provideArgumentsTestRelativize")
125+
void testRelativize(@NonNull String uri1, @NonNull String uri2, boolean prepend, @NonNull String expected)
126+
throws URISyntaxException {
127+
URI thisUri = URI.create(uri1);
128+
URI thatUri = URI.create(uri2);
129+
130+
URI result = UriUtils.relativize(thisUri, thatUri, prepend);
131+
assertEquals(expected, result.toASCIIString());
132+
}
76133
}

0 commit comments

Comments
 (0)