Add additional constraint to cf resource schema

Details: username/password and client_id/client_secret should
not be used together. We now check for this and show a warning
in the concourse editor.
This commit is contained in:
Kris De Volder
2019-07-24 11:30:19 -07:00
parent ecd2393a98
commit d30a82d04f
3 changed files with 59 additions and 0 deletions

View File

@@ -37,6 +37,7 @@ import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.NodeTuple;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
@@ -61,6 +62,14 @@ public class Constraints {
};
}
public static Constraint and(Constraint... constraints) {
return (DynamicSchemaContext dc, Node parent, Node node, YType type, IProblemCollector problems) -> {
for (Constraint c : constraints) {
c.verify(dc, parent, node, type, problems);
}
};
}
public static Constraint implies(String foundProperty, String requiredProperty) {
return (DynamicSchemaContext dc, Node parent, Node node, YType type, IProblemCollector problems) -> {
@@ -176,6 +185,30 @@ public class Constraints {
};
}
public static Constraint mutuallyExclusive(List<String> group1, List<String> group2) {
return (DynamicSchemaContext dc, Node parent, Node node, YType type, IProblemCollector problems) -> {
if (node instanceof MappingNode) {
MappingNode map = (MappingNode) node;
Set<String> defined = dc.getDefinedProperties();
if (containsAny(defined, group1) && containsAny(defined, group2)) {
for (NodeTuple tup : map.getValue()) {
Node keyNode = tup.getKeyNode();
String key = NodeUtil.asScalar(keyNode);
if (group1.contains(key) || group2.contains(key)) {
problems.accept(problem(EXTRA_PROPERTY,
"Properties "+group1+" should not be used together with "+group2+" for '"+type+"'", keyNode
));
}
}
}
}
};
}
private static boolean containsAny(Set<String> set, Collection<String> lookFor) {
return lookFor.stream().filter(set::contains).findAny().isPresent();
}
public static Constraint mutuallyExclusive(String p1, String p2) {
return (DynamicSchemaContext dc, Node parent, Node node, YType type, IProblemCollector problems) -> {
if (node instanceof MappingNode) {

View File

@@ -58,6 +58,7 @@ import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
/**
* @author Kris De Volder
@@ -736,6 +737,10 @@ public class PipelineYmlSchema implements YamlSchema {
source.require(Constraints.together("username", "password"));
source.require(Constraints.together("client_id", "client_secret"));
source.require(Constraints.requireAtLeastOneOf("username", "password", "client_id", "client_secret"));
source.require(Constraints.mutuallyExclusive(
ImmutableList.of("username", "password"),
ImmutableList.of("client_id", "client_secret")
));
AbstractType get = f.ybean("CloudFoundryGetParams");
//get params deliberately left empty

View File

@@ -4532,6 +4532,27 @@ public class ConcourseEditorTest {
"not-bool-1|boolean",
"not-bool-2|boolean"
);
editor = harness.newEditor(
"resources:\n" +
"- name: pws\n" +
" type: cf\n" +
" source:\n" +
" api: https://api.run.pivotal.io\n" +
" organization: my-org\n" +
" space: my-space\n" +
" username: ((secret))\n" +
" password: ((secret))\n" +
" client_id: ((id)\n" +
" client_secret: ((secret)\n"
);
editor.assertProblems(
"pws|Unused",
"username|Properties [username, password] should not be used together with [client_id, client_secret]",
"password|Properties [username, password] should not be used together with [client_id, client_secret]",
"client_id|Properties [username, password] should not be used together with [client_id, client_secret]",
"client_secret|Properties [username, password] should not be used together with [client_id, client_secret]"
);
}
@Test public void cfResourceSourceHovers() throws Exception {