diff --git a/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/info/GitInfo.java b/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/info/GitInfo.java index 7ada49bdbd85e..1c9db2584d03d 100644 --- a/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/info/GitInfo.java +++ b/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/info/GitInfo.java @@ -168,7 +168,6 @@ private static String readFirstLine(final Path path) throws IOException { /** Find the reponame. */ public String urlFromOrigin() { - String oritin = getOrigin(); if (origin == null) { return null; // best effort, the url doesnt really matter, it is just required by maven central } diff --git a/build-tools-internal/build.gradle b/build-tools-internal/build.gradle index 61e4df6227be2..34c4b57438e86 100644 --- a/build-tools-internal/build.gradle +++ b/build-tools-internal/build.gradle @@ -290,6 +290,7 @@ dependencies { exclude module: "groovy" } testImplementation buildLibs.spock.junit4 + testImplementation buildLibs.json.assert integTestImplementation buildLibs.xmlunit.core } diff --git a/build-tools-internal/src/integTest/groovy/org/elasticsearch/gradle/internal/snyk/SnykDependencyMonitoringGradlePluginFuncTest.groovy b/build-tools-internal/src/integTest/groovy/org/elasticsearch/gradle/internal/snyk/SnykDependencyMonitoringGradlePluginFuncTest.groovy new file mode 100644 index 0000000000000..1da3f063285e4 --- /dev/null +++ b/build-tools-internal/src/integTest/groovy/org/elasticsearch/gradle/internal/snyk/SnykDependencyMonitoringGradlePluginFuncTest.groovy @@ -0,0 +1,196 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.gradle.internal.snyk + +import org.elasticsearch.gradle.fixtures.AbstractGradleInternalPluginFuncTest +import org.gradle.api.Plugin +import org.gradle.testkit.runner.TaskOutcome +import org.skyscreamer.jsonassert.JSONAssert + +import static java.net.HttpURLConnection.HTTP_CREATED +import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR +import static org.elasticsearch.gradle.fixtures.WiremockFixture.PUT +import static org.elasticsearch.gradle.fixtures.WiremockFixture.withWireMock +import static org.elasticsearch.gradle.internal.snyk.UploadSnykDependenciesGraph.GRADLE_GRAPH_ENDPOINT + +class SnykDependencyMonitoringGradlePluginFuncTest extends AbstractGradleInternalPluginFuncTest { + + Class pluginClassUnderTest = SnykDependencyMonitoringGradlePlugin.class + + def setup() { + configurationCacheCompatible = false // configuration is not cc compliant + } + + def "can calculate snyk dependency graph"() { + given: + buildFile << """ + apply plugin:'java' + version = "1.0-SNAPSHOT" + + repositories { + mavenCentral() + } + + dependencies { + implementation 'org.apache.lucene:lucene-monitor:9.2.0' + } + """ + when: + def build = gradleRunner("generateSnykDependencyGraph").build() + then: + build.task(":generateSnykDependencyGraph").outcome == TaskOutcome.SUCCESS + JSONAssert.assertEquals(file( "build/snyk/dependencies.json").text, """{ + "meta": { + "method": "custom gradle", + "id": "gradle", + "node": "v16.15.1", + "name": "gradle", + "plugin": "extern:gradle", + "pluginRuntime": "unknown", + "monitorGraph": true + }, + "depGraphJSON": { + "pkgManager": { + "version": "7.4.2", + "name": "gradle" + }, + "schemaVersion": "1.2.0", + "graph": { + "rootNodeId": "root-node", + "nodes": [ + { + "nodeId": "root-node", + "deps": [ + { + "nodeId": "org.apache.lucene:lucene-monitor@9.2.0" + } + ], + "pkgId": "hello-world@1.0-SNAPSHOT" + }, + { + "nodeId": "org.apache.lucene:lucene-monitor@9.2.0", + "deps": [ + { + "nodeId": "org.apache.lucene:lucene-memory@9.2.0" + }, + { + "nodeId": "org.apache.lucene:lucene-analysis-common@9.2.0" + }, + { + "nodeId": "org.apache.lucene:lucene-core@9.2.0" + } + ], + "pkgId": "org.apache.lucene:lucene-monitor@9.2.0" + }, + { + "nodeId": "org.apache.lucene:lucene-memory@9.2.0", + "deps": [ + { + "nodeId": "org.apache.lucene:lucene-core@9.2.0" + } + ], + "pkgId": "org.apache.lucene:lucene-memory@9.2.0" + }, + { + "nodeId": "org.apache.lucene:lucene-core@9.2.0", + "deps": [ + + ], + "pkgId": "org.apache.lucene:lucene-core@9.2.0" + }, + { + "nodeId": "org.apache.lucene:lucene-analysis-common@9.2.0", + "deps": [ + { + "nodeId": "org.apache.lucene:lucene-core@9.2.0" + } + ], + "pkgId": "org.apache.lucene:lucene-analysis-common@9.2.0" + } + ] + }, + "pkgs": [ + { + "id": "hello-world@1.0-SNAPSHOT", + "info": { + "name": "hello-world", + "version": "1.0-SNAPSHOT" + } + }, + { + "id": "org.apache.lucene:lucene-monitor@9.2.0", + "info": { + "name": "org.apache.lucene:lucene-monitor", + "version": "9.2.0" + } + }, + { + "id": "org.apache.lucene:lucene-memory@9.2.0", + "info": { + "name": "org.apache.lucene:lucene-memory", + "version": "9.2.0" + } + }, + { + "id": "org.apache.lucene:lucene-core@9.2.0", + "info": { + "name": "org.apache.lucene:lucene-core", + "version": "9.2.0" + } + }, + { + "id": "org.apache.lucene:lucene-analysis-common@9.2.0", + "info": { + "name": "org.apache.lucene:lucene-analysis-common", + "version": "9.2.0" + } + } + ] + }, + "target": { + "remoteUrl": "http://github.com/elastic/elasticsearch.git", + "branch": "unknown" + } + }""", true) + } + + def "upload fails with reasonable error message"() { + given: + buildFile << """ + apply plugin:'java' + """ + when: + def result = withWireMock(PUT, "/api/v1/monitor/gradle/graph", "OK", HTTP_CREATED) { server -> + buildFile << """ + tasks.named('uploadSnykDependencyGraph').configure { + getUrl().set('${server.baseUrl()}/api/v1/monitor/gradle/graph') + getToken().set("myToken") + } + """ + gradleRunner("uploadSnykDependencyGraph", '-i', '--stacktrace').build() + } + then: + result.task(":uploadSnykDependencyGraph").outcome == TaskOutcome.SUCCESS + result.output.contains("Snyk API call response status: 201") + + when: + result = withWireMock(PUT, GRADLE_GRAPH_ENDPOINT, "Internal Error", HTTP_INTERNAL_ERROR) { server -> + buildFile << """ + tasks.named('uploadSnykDependencyGraph').configure { + getUrl().set('${server.baseUrl()}/api/v1/monitor/gradle/graph') + } + """ + gradleRunner("uploadSnykDependencyGraph", '-i').buildAndFail() + } + + then: + result.task(":uploadSnykDependencyGraph").outcome == TaskOutcome.FAILED + result.output.contains("Uploading Snyk Graph failed with http code 500: Internal Error") + } +} diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/BuildPlugin.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/BuildPlugin.java index e5b932bc408e9..6849796579ad9 100644 --- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/BuildPlugin.java +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/BuildPlugin.java @@ -10,6 +10,7 @@ import org.elasticsearch.gradle.internal.info.GlobalBuildInfoPlugin; import org.elasticsearch.gradle.internal.precommit.InternalPrecommitTasks; +import org.elasticsearch.gradle.internal.snyk.SnykDependencyMonitoringGradlePlugin; import org.gradle.api.InvalidUserDataException; import org.gradle.api.Plugin; import org.gradle.api.Project; @@ -59,7 +60,7 @@ public void apply(final Project project) { project.getPluginManager().apply("elasticsearch.publish"); project.getPluginManager().apply(ElasticsearchJavadocPlugin.class); project.getPluginManager().apply(DependenciesInfoPlugin.class); - project.getPluginManager().apply(DependenciesGraphPlugin.class); + project.getPluginManager().apply(SnykDependencyMonitoringGradlePlugin.class); InternalPrecommitTasks.create(project, true); configureLicenseAndNotice(project); } diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DependenciesGraphPlugin.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DependenciesGraphPlugin.java deleted file mode 100644 index 8dee4d27f6a53..0000000000000 --- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DependenciesGraphPlugin.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -package org.elasticsearch.gradle.internal; - -import org.gradle.api.GradleException; -import org.gradle.api.Plugin; -import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.plugins.JavaPlugin; -import org.gradle.api.tasks.TaskProvider; - -import java.util.List; -import java.util.stream.Collectors; - -public class DependenciesGraphPlugin implements Plugin { - - public void apply(Project project) { - project.getRootProject().getPluginManager().apply(DependenciesGraphHookPlugin.class); - final String url = System.getenv("SCA_URL"); - final String token = System.getenv("SCA_TOKEN"); - TaskProvider depsGraph = project.getTasks().register("dependenciesGraph", DependenciesGraphTask.class); - depsGraph.configure(t -> { - project.getPlugins().withType(JavaPlugin.class, p -> { - t.setRuntimeConfiguration(project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)); - t.setToken(token); - t.setUrl(url); - }); - }); - } - - static class DependenciesGraphHookPlugin implements Plugin { - - @Override - public void apply(Project project) { - if (project != project.getRootProject()) { - throw new IllegalStateException(this.getClass().getName() + " can only be applied to the root project."); - } - final String url = System.getenv("SCA_URL"); - final String token = System.getenv("SCA_TOKEN"); - project.getGradle().getTaskGraph().whenReady(graph -> { - List depGraphTasks = graph.getAllTasks() - .stream() - .filter(t -> t instanceof DependenciesGraphTask) - .map(Task::getPath) - .collect(Collectors.toList()); - if (depGraphTasks.size() > 0) { - if (url == null || token == null) { - // If there are more than one DependenciesGraphTasks to run, print the message only for one of - // them as the resolving action is the same for all - throw new GradleException( - "The environment variables SCA_URL and SCA_TOKEN need to be set before task " - + depGraphTasks.get(0) - + " can run" - ); - } - } - }); - - } - } -} diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DependenciesGraphTask.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DependenciesGraphTask.java deleted file mode 100644 index 2863aec90b791..0000000000000 --- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DependenciesGraphTask.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -package org.elasticsearch.gradle.internal; - -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.util.EntityUtils; -import org.gradle.StartParameter; -import org.gradle.api.DefaultTask; -import org.gradle.api.GradleException; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.Dependency; -import org.gradle.api.artifacts.DependencySet; -import org.gradle.api.artifacts.ProjectDependency; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputFiles; -import org.gradle.api.tasks.TaskAction; - -import java.util.HashSet; -import java.util.Set; - -import javax.inject.Inject; - -import static org.elasticsearch.gradle.util.GradleUtils.projectPath; - -/** - * A task to generate a dependency graph of our runtime dependencies and push that via - * an API call to a given endpoint of a SCA tool/service. - * The graph is built according to the specification in https://github.com/snyk/dep-graph#depgraphdata - * - * Due to the nature of our dependency resolution in gradle, we are abusing the aforementioned graph definition as - * the graph we construct has a single root ( the subproject ) and all dependencies are children of that root, - * irrespective of if they are direct dependencies or transitive ones ( that should be children of other children ). - * Although we end up lacking some contextual information, this allows us to scan and monitor only the dependencies - * that are bundled and used in runtime. - */ -public class DependenciesGraphTask extends DefaultTask { - - private Configuration runtimeConfiguration; - private String token; - private String url; - private StartParameter startParameter; - - @Input - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - @Input - public String getToken() { - return token; - } - - public void setToken(String token) { - this.token = token; - } - - @InputFiles - public Configuration getRuntimeConfiguration() { - return runtimeConfiguration; - } - - public void setRuntimeConfiguration(Configuration runtimeConfiguration) { - this.runtimeConfiguration = runtimeConfiguration; - } - - @Inject - public DependenciesGraphTask(StartParameter startParameter) { - this.startParameter = startParameter; - } - - @TaskAction - void generateDependenciesGraph() { - if (startParameter.isOffline()) { - throw new GradleException("Must run in online mode in order to submit the dependency graph to the SCA service"); - } - - final DependencySet runtimeDependencies = runtimeConfiguration.getAllDependencies(); - final Set packages = new HashSet<>(); - final Set nodes = new HashSet<>(); - final Set nodeIds = new HashSet<>(); - for (final Dependency dependency : runtimeDependencies) { - final String id = dependency.getGroup() + ":" + dependency.getName(); - final String versionedId = id + "@" + dependency.getVersion(); - final StringBuilder nodeString = new StringBuilder(); - if (dependency instanceof ProjectDependency) { - continue; - } - packages.add(""" - {"id": "%s","info": {"name": "%s","version": "%s"}}\ - """.formatted(versionedId, id, dependency.getVersion())); - nodeString.append(""" - {"nodeId": "%s","pkgId": "%s","deps": []}\ - """.formatted(versionedId, versionedId)); - nodes.add(nodeString.toString()); - nodeIds.add(""" - {"nodeId": "%s"}\ - """.formatted(versionedId)); - } - // We add one package and one node for each dependency, it suffices to check packages. - if (packages.size() > 0) { - final String projectName = "elastic/elasticsearch" + projectPath(getPath()); - final String output = """ - { - "depGraph": { - "schemaVersion": "1.2.0", - "pkgManager": {"name": "gradle"}, - "pkgs": [ - { - "id": "%s@0.0.0", - "info": {"name": "%1$s", "version": "0.0.0"} - }, - %s - ], - "graph": { - "rootNodeId": "%1$s@0.0.0", - "nodes": [ - { "nodeId": "%1$s@0.0.0","pkgId": "%1$s@0.0.0","deps": [%s] }, - %s - ] - } - } - }""".formatted(projectName, String.join(",", packages), String.join(",", nodeIds), String.join(",", nodes)); - getLogger().debug("Dependency Graph: " + output); - try (CloseableHttpClient client = HttpClients.createDefault()) { - HttpPost postRequest = new HttpPost(url); - postRequest.addHeader("Authorization", "token " + token); - postRequest.addHeader("Content-Type", "application/json"); - postRequest.setEntity(new StringEntity(output.toString())); - CloseableHttpResponse response = client.execute(postRequest); - getLogger().info("API call response status: " + response.getStatusLine().getStatusCode()); - getLogger().debug(EntityUtils.toString(response.getEntity())); - } catch (Exception e) { - throw new GradleException("Failed to call API endpoint to submit updated dependency graph", e); - } - } - } - -} diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/snyk/GenerateSnykDependencyGraph.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/snyk/GenerateSnykDependencyGraph.java new file mode 100644 index 0000000000000..079b51cd05f3d --- /dev/null +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/snyk/GenerateSnykDependencyGraph.java @@ -0,0 +1,136 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.gradle.internal.snyk; + +import groovy.json.JsonOutput; + +import org.elasticsearch.gradle.internal.info.BuildParams; +import org.gradle.api.DefaultTask; +import org.gradle.api.GradleException; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.ResolvedDependency; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.TaskAction; +import org.gradle.initialization.layout.BuildLayout; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.util.Map; +import java.util.Set; + +import javax.inject.Inject; + +public class GenerateSnykDependencyGraph extends DefaultTask { + + private static final Map FIXED_META_DATA = Map.of( + "method", + "custom gradle", + "id", + "gradle", + "node", + "v16.15.1", + "name", + "gradle", + "plugin", + "extern:gradle", + "pluginRuntime", + "unknown", + "monitorGraph", + true + ); + private final Property configuration; + private final Property projectName; + private final Property projectPath; + private final Property version; + private final Property gradleVersion; + private final RegularFileProperty outputFile; + private final BuildLayout buildLayout; + + @Inject + public GenerateSnykDependencyGraph(ObjectFactory objectFactory, BuildLayout buildLayout) { + configuration = objectFactory.property(Configuration.class); + projectName = objectFactory.property(String.class); + projectPath = objectFactory.property(String.class); + version = objectFactory.property(String.class); + gradleVersion = objectFactory.property(String.class); + outputFile = objectFactory.fileProperty(); + this.buildLayout = buildLayout; + } + + @TaskAction + void resolveGraph() { + Map payload = generateGradleGraphPayload(); + String jsonOutput = JsonOutput.prettyPrint(JsonOutput.toJson(payload)); + try { + Files.writeString( + getOutputFile().getAsFile().get().toPath(), + jsonOutput, + StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING + ); + } catch (IOException e) { + throw new GradleException("Cannot generate dependencies json file", e); + } + } + + private Map generateGradleGraphPayload() { + Set firstLevelModuleDependencies = configuration.get() + .getResolvedConfiguration() + .getFirstLevelModuleDependencies(); + SnykDependencyGraphBuilder builder = new SnykDependencyGraphBuilder(gradleVersion.get()); + String effectiveProjectPath = projectPath.get(); + builder.walkGraph( + (effectiveProjectPath.equals(":") ? projectName.get() : effectiveProjectPath), + version.get(), + firstLevelModuleDependencies + ); + return Map.of("meta", FIXED_META_DATA, "depGraphJSON", builder.build(), "target", buildTargetData()); + } + + private Object buildTargetData() { + return Map.of("remoteUrl", "http://github.com/elastic/elasticsearch.git", "branch", BuildParams.getGitRevision()); + } + + @InputFiles + public Property getConfiguration() { + return configuration; + } + + @OutputFile + public RegularFileProperty getOutputFile() { + return outputFile; + } + + @Input + public Property getProjectPath() { + return projectPath; + } + + @Input + public Property getVersion() { + return version; + } + + @Input + public Property getProjectName() { + return projectName; + } + + @Input + public Property getGradleVersion() { + return gradleVersion; + } + +} diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/snyk/SnykDependencyGraph.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/snyk/SnykDependencyGraph.java new file mode 100644 index 0000000000000..fe62eb4e649db --- /dev/null +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/snyk/SnykDependencyGraph.java @@ -0,0 +1,125 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.gradle.internal.snyk; + +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +public class SnykDependencyGraph { + static private final String schemaVersion = "1.2.0"; + private final Map graph; + private final Set pkgs; + private final Map pkgManager; + + public SnykDependencyGraph(String gradleVersion, Set nodes, Set pkgs) { + this.pkgs = pkgs; + this.graph = new HashMap(); + graph.put("rootNodeId", "root-node"); + graph.put("nodes", nodes); + this.pkgManager = Map.of("name", "gradle", "version", gradleVersion); + } + + public String getSchemaVersion() { + return schemaVersion; + } + + public Map getPkgManager() { + return pkgManager; + } + + public Map getGraph() { + return graph; + } + + public Set getPkgs() { + return pkgs; + } + + static class SnykDependencyNode { + private String nodeId; + private String pkgId; + private Set> deps = new LinkedHashSet<>(); + + SnykDependencyNode(String nodeId, String pkgId) { + this.nodeId = nodeId; + this.pkgId = pkgId; + } + + public void addDep(String pkg) { + deps.add(Map.of("nodeId", pkg)); + } + + public String getNodeId() { + return nodeId; + } + + public String getPkgId() { + return pkgId; + } + + public Set> getDeps() { + return deps; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SnykDependencyNode that = (SnykDependencyNode) o; + return Objects.equals(nodeId, that.nodeId) && Objects.equals(pkgId, that.pkgId); + } + + @Override + public int hashCode() { + return Objects.hash(nodeId, pkgId); + } + + @Override + public String toString() { + return "SnykDependencyNode{" + "nodeId='" + nodeId + '\'' + ", pkgId='" + pkgId + '\'' + '}'; + } + } + + static class SnykDependencyPkg { + private final String id; + private final Map info; + + SnykDependencyPkg(String pkgId) { + id = pkgId; + String name = id.substring(0, id.indexOf('@')); + String version = id.substring(id.indexOf('@') + 1); + info = Map.of("name", name, "version", version); + } + + public String getId() { + return id; + } + + public Map getInfo() { + return info; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SnykDependencyPkg that = (SnykDependencyPkg) o; + return Objects.equals(id, that.id) && Objects.equals(info, that.info); + } + + @Override + public int hashCode() { + return Objects.hash(id, info); + } + } + +} diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/snyk/SnykDependencyGraphBuilder.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/snyk/SnykDependencyGraphBuilder.java new file mode 100644 index 0000000000000..4210c375921ec --- /dev/null +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/snyk/SnykDependencyGraphBuilder.java @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.gradle.internal.snyk; + +import org.elasticsearch.gradle.internal.snyk.SnykDependencyGraph.SnykDependencyNode; +import org.gradle.api.artifacts.ResolvedDependency; + +import java.util.LinkedHashSet; +import java.util.Set; + +public class SnykDependencyGraphBuilder { + + private Set nodes = new LinkedHashSet<>(); + private Set pkgs = new LinkedHashSet<>(); + + private SnykDependencyNode currentNode; + private String gradleVersion; + + public SnykDependencyGraphBuilder(String gradleVersion) { + this.gradleVersion = gradleVersion; + } + + public SnykDependencyNode addNode(String nodeId, String pkgIdPrefix, String version) { + String pkgId = pkgIdPrefix + "@" + version; + SnykDependencyNode node = new SnykDependencyNode(nodeId, pkgId); + SnykDependencyGraph.SnykDependencyPkg pkg = new SnykDependencyGraph.SnykDependencyPkg(pkgId); + nodes.add(node); + if (currentNode != null) { + currentNode.addDep(pkgId); + } + pkgs.add(pkg); + return node; + } + + public SnykDependencyNode addDependency(ResolvedDependency dep) { + String pkgPrefix = dep.getModuleGroup() + ":" + dep.getModuleName(); + String nodeId = pkgPrefix + "@" + dep.getModuleVersion(); + return addNode(nodeId, pkgPrefix, dep.getModuleVersion()); + } + + private void loadGraph(SnykDependencyNode parent, Set deps) { + this.currentNode = parent; + deps.forEach(dep -> { + SnykDependencyGraph.SnykDependencyNode snykDependencyNode = addDependency(dep); + loadGraph(snykDependencyNode, dep.getChildren()); + this.currentNode = parent; + }); + } + + public SnykDependencyGraph build() { + return new SnykDependencyGraph(gradleVersion, nodes, pkgs); + } + + public void walkGraph(String rootPkgId, String version, Set deps) { + SnykDependencyNode root = addNode("root-node", rootPkgId, version); + loadGraph(root, deps); + } +} diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/snyk/SnykDependencyMonitoringGradlePlugin.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/snyk/SnykDependencyMonitoringGradlePlugin.java new file mode 100644 index 0000000000000..4df33d80ee275 --- /dev/null +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/snyk/SnykDependencyMonitoringGradlePlugin.java @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.gradle.internal.snyk; + +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.file.ProjectLayout; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.plugins.JavaPluginExtension; +import org.gradle.api.provider.ProviderFactory; +import org.gradle.api.tasks.SourceSet; + +import javax.inject.Inject; + +public class SnykDependencyMonitoringGradlePlugin implements Plugin { + + public static final String UPLOAD_TASK_NAME = "uploadSnykDependencyGraph"; + private ProjectLayout projectLayout; + private ProviderFactory providerFactory; + + @Inject + public SnykDependencyMonitoringGradlePlugin(ProjectLayout projectLayout, ProviderFactory providerFactory) { + this.projectLayout = projectLayout; + this.providerFactory = providerFactory; + } + + @Override + public void apply(Project project) { + var generateTaskProvider = project.getTasks() + .register("generateSnykDependencyGraph", GenerateSnykDependencyGraph.class, generateSnykDependencyGraph -> { + generateSnykDependencyGraph.getProjectPath().set(project.getPath()); + generateSnykDependencyGraph.getProjectName().set(project.getName()); + generateSnykDependencyGraph.getVersion().set(project.getVersion().toString()); + generateSnykDependencyGraph.getGradleVersion().set(project.getGradle().getGradleVersion()); + generateSnykDependencyGraph.getOutputFile().set(projectLayout.getBuildDirectory().file("snyk/dependencies.json")); + }); + + project.getTasks().register(UPLOAD_TASK_NAME, UploadSnykDependenciesGraph.class, t -> { + t.getInputFile().set(generateTaskProvider.get().getOutputFile()); + t.getToken().set(providerFactory.gradleProperty("snykToken")); + // the elasticsearch snyk project id + t.getProjectId().set(providerFactory.gradleProperty("snykProjectId")); + }); + + project.getPlugins().withType(JavaPlugin.class, javaPlugin -> generateTaskProvider.configure(generateSnykDependencyGraph -> { + SourceSet main = project.getExtensions() + .getByType(JavaPluginExtension.class) + .getSourceSets() + .getByName(SourceSet.MAIN_SOURCE_SET_NAME); + Configuration runtimeConfiguration = project.getConfigurations().getByName(main.getRuntimeClasspathConfigurationName()); + generateSnykDependencyGraph.getConfiguration().set(runtimeConfiguration); + })); + } + +} diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/snyk/UploadSnykDependenciesGraph.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/snyk/UploadSnykDependenciesGraph.java new file mode 100644 index 0000000000000..ecfd9afb6b02d --- /dev/null +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/snyk/UploadSnykDependenciesGraph.java @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.gradle.internal.snyk; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.entity.FileEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.gradle.api.DefaultTask; +import org.gradle.api.GradleException; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.TaskAction; + +import java.io.IOException; +import java.net.HttpURLConnection; + +import javax.inject.Inject; + +public class UploadSnykDependenciesGraph extends DefaultTask { + + public static final String DEFAULT_SERVER = "https://snyk.io"; + public static final String GRADLE_GRAPH_ENDPOINT = "/api/v1/monitor/gradle/graph"; + + // This is new `experimental` api endpoint we might want to support in the future. For now it + // does not allow grouping projects and adding custom metadata to the graph data. Therefore + // we do not support this yet but keep it here for documentation purposes + public static final String SNYK_DEP_GRAPH_API_ENDPOINT = "/api/v1/monitor/dep-graph"; + + private final RegularFileProperty inputFile; + private final Property token; + private final Property url; + private final Property projectId; + + @Inject + public UploadSnykDependenciesGraph(ObjectFactory objectFactory) { + url = objectFactory.property(String.class).convention(DEFAULT_SERVER + GRADLE_GRAPH_ENDPOINT); + projectId = objectFactory.property(String.class); + token = objectFactory.property(String.class); + inputFile = objectFactory.fileProperty(); + } + + @TaskAction + void upload() { + String endpoint = calculateEffectiveEndpoint(); + CloseableHttpResponse response; + try (CloseableHttpClient client = HttpClients.createDefault()) { + HttpPut putRequest = new HttpPut(endpoint); + putRequest.addHeader("Authorization", "token " + token.get()); + putRequest.addHeader("Content-Type", "application/json"); + putRequest.setEntity(new FileEntity(inputFile.getAsFile().get())); + response = client.execute(putRequest); + int statusCode = response.getStatusLine().getStatusCode(); + String responseString = EntityUtils.toString(response.getEntity()); + getLogger().info("Snyk API call response status: " + statusCode); + if (statusCode != HttpURLConnection.HTTP_CREATED) { + throw new GradleException("Uploading Snyk Graph failed with http code " + statusCode + ": " + responseString); + } + getLogger().info(responseString); + } catch (IOException e) { + throw new GradleException("Failed to call API endpoint to submit updated dependency graph", e); + } + } + + private String calculateEffectiveEndpoint() { + String url = this.url.get(); + return url.endsWith(GRADLE_GRAPH_ENDPOINT) ? url : projectId.map(id -> url + "?org=" + id).getOrElse(url); + } + + @Input + public Property getToken() { + return token; + } + + @Input + public Property getUrl() { + return url; + } + + @Input + @Optional + public Property getProjectId() { + return projectId; + } + + @InputFile + public RegularFileProperty getInputFile() { + return inputFile; + } +} diff --git a/build-tools/src/testFixtures/groovy/org/elasticsearch/gradle/fixtures/WiremockFixture.groovy b/build-tools/src/testFixtures/groovy/org/elasticsearch/gradle/fixtures/WiremockFixture.groovy index 7c0450760359c..a3281780e16e0 100644 --- a/build-tools/src/testFixtures/groovy/org/elasticsearch/gradle/fixtures/WiremockFixture.groovy +++ b/build-tools/src/testFixtures/groovy/org/elasticsearch/gradle/fixtures/WiremockFixture.groovy @@ -14,6 +14,7 @@ import org.gradle.testkit.runner.BuildResult import static com.github.tomakehurst.wiremock.client.WireMock.aResponse import static com.github.tomakehurst.wiremock.client.WireMock.get import static com.github.tomakehurst.wiremock.client.WireMock.head +import static com.github.tomakehurst.wiremock.client.WireMock.put import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo /** @@ -21,6 +22,17 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo * */ class WiremockFixture { + static String GET = "GET" + static String PUT = "PUT" + + static BuildResult withWireMock(String expectedUrl, byte[] expectedContent, Closure buildRunClosure) { + withWireMock(GET, expectedUrl, expectedContent, HttpURLConnection.HTTP_OK, buildRunClosure) + } + + static BuildResult withWireMock(String httpMethod, String expectedUrl, String expectedContent, int expectedHttpCode, Closure buildRunClosure) { + withWireMock(httpMethod, expectedUrl, expectedContent.getBytes(), expectedHttpCode, buildRunClosure) + } + /** * the buildRunClosure has passed an instance of WireMockServer that can be used to access e.g. the baseUrl of * the configured server: @@ -29,7 +41,7 @@ class WiremockFixture { * WiremockFixture.withWireMock(mockRepoUrl, mockedContent) { server -> * buildFile << """ * // wire a gradle repository with wiremock -* repositories { + * repositories { * maven { * url = '${server.baseUrl()}' * } @@ -38,13 +50,19 @@ class WiremockFixture { * gadleRunner('myTask').build() * * */ - static BuildResult withWireMock(String expectedUrl, byte[] expectedContent, Closure buildRunClosure) { + static BuildResult withWireMock(String httpMethod, String expectedUrl, byte[] expectedContent, int expectedHttpCode, Closure buildRunClosure) { WireMockServer wireMock = new WireMockServer(0); try { - wireMock.stubFor(head(urlEqualTo(expectedUrl)).willReturn(aResponse().withStatus(200))); - wireMock.stubFor( - get(urlEqualTo(expectedUrl)).willReturn(aResponse().withStatus(200).withBody(expectedContent)) - ) + wireMock.stubFor(head(urlEqualTo(expectedUrl)).willReturn(aResponse().withStatus(expectedHttpCode))); + if(httpMethod == GET) { + wireMock.stubFor( + get(urlEqualTo(expectedUrl)).willReturn(aResponse().withStatus(expectedHttpCode).withBody(expectedContent)) + ) + } else if(httpMethod == PUT) { + wireMock.stubFor( + put(urlEqualTo(expectedUrl)).willReturn(aResponse().withStatus(expectedHttpCode).withBody(expectedContent)) + ) + } wireMock.start(); return buildRunClosure.call(wireMock); } catch (Exception e) { diff --git a/build.gradle b/build.gradle index 6ccd88e443b01..adcc3547827b1 100644 --- a/build.gradle +++ b/build.gradle @@ -155,7 +155,7 @@ if (project.gradle.startParameter.taskNames.find { it.startsWith("checkPart") } bwc_tests_enabled = false } -subprojects { +subprojects { proj -> apply plugin: 'elasticsearch.base' } @@ -229,9 +229,6 @@ allprojects { maybeConfigure(project.tasks, 'dependenciesInfo') { it.enabled = false } - maybeConfigure(project.tasks, 'dependenciesGraph') { - it.enabled = false - } } project.afterEvaluate { diff --git a/client/benchmark/build.gradle b/client/benchmark/build.gradle index ede0b6961c56e..40c277067fe6c 100644 --- a/client/benchmark/build.gradle +++ b/client/benchmark/build.gradle @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -apply plugin: 'elasticsearch.build' +apply plugin: 'elasticsearch.java' apply plugin: 'application' group = 'org.elasticsearch.client' @@ -17,9 +17,6 @@ tasks.named("assemble").configure { enabled = true } archivesBaseName = 'client-benchmarks' mainClassName = 'org.elasticsearch.client.benchmark.BenchmarkMain' -// never try to invoke tests on the benchmark project - there aren't any -tasks.named("test").configure {enabled = false } - dependencies { api 'org.apache.commons:commons-math3:3.2' @@ -27,8 +24,4 @@ dependencies { api project(':client:rest') // bottleneck should be the client, not Elasticsearch api project(path: ':client:client-benchmark-noop-api-plugin') -} - -// No licenses for our benchmark deps (we don't ship benchmarks) -tasks.named("dependencyLicenses").configure { enabled = false } -tasks.named("dependenciesInfo").configure{enabled = false } +} \ No newline at end of file diff --git a/client/client-benchmark-noop-api-plugin/build.gradle b/client/client-benchmark-noop-api-plugin/build.gradle index 198775e61b8a2..839cd9052b4f5 100644 --- a/client/client-benchmark-noop-api-plugin/build.gradle +++ b/client/client-benchmark-noop-api-plugin/build.gradle @@ -20,5 +20,4 @@ esplugin { tasks.named("assemble").configure { enabled = false } tasks.named("dependencyLicenses").configure { enabled = false } tasks.named("dependenciesInfo").configure { enabled = false } -// no unit tests -tasks.named("test").configure { enabled = false } +tasks.named("uploadSnykDependencyGraph").configure { enabled = false } \ No newline at end of file diff --git a/client/test/build.gradle b/client/test/build.gradle index 3b2fea0b56e25..c8ba708140866 100644 --- a/client/test/build.gradle +++ b/client/test/build.gradle @@ -53,10 +53,7 @@ tasks.named("jarHell").configure { enabled = false } // TODO: should we have licenses for our test deps? tasks.named("dependencyLicenses").configure { enabled = false } tasks.named("dependenciesInfo").configure { enabled = false } -tasks.named("dependenciesGraph").configure { it.enabled = false } - -//we aren't releasing this jar -tasks.named("test").configure { enabled = false } +tasks.named("uploadSnykDependencyGraph").configure { enabled = false } tasks.withType(LicenseHeadersTask.class).configureEach { approvedLicenses = ['Apache', 'Generated', 'Vendored'] diff --git a/distribution/tools/cli-launcher/build.gradle b/distribution/tools/cli-launcher/build.gradle index 17eaf3e018a09..af7530e92bdf9 100644 --- a/distribution/tools/cli-launcher/build.gradle +++ b/distribution/tools/cli-launcher/build.gradle @@ -1,4 +1,4 @@ -apply plugin: 'elasticsearch.java' +apply plugin: 'elasticsearch.build' dependencies { compileOnly project(':server') diff --git a/distribution/tools/java-version-checker/build.gradle b/distribution/tools/java-version-checker/build.gradle index 576baae3d040e..7d5298c199b58 100644 --- a/distribution/tools/java-version-checker/build.gradle +++ b/distribution/tools/java-version-checker/build.gradle @@ -1,4 +1,4 @@ -apply plugin: 'elasticsearch.java' +apply plugin: 'elasticsearch.build' sourceSets { unsupportedJdkVersionEntrypoint @@ -22,6 +22,7 @@ tasks.named("jar") { } } -["test", "javadoc"].each { +// TODO revisit forbiddenApis issues +["javadoc", "forbiddenApisMain", "forbiddenApisUnsupportedJdkVersionEntrypoint"].each { tasks.named(it).configure { enabled = false } } diff --git a/distribution/tools/windows-service-cli/build.gradle b/distribution/tools/windows-service-cli/build.gradle index 103e5322913b9..77da0d407a40d 100644 --- a/distribution/tools/windows-service-cli/build.gradle +++ b/distribution/tools/windows-service-cli/build.gradle @@ -1,4 +1,4 @@ -apply plugin: 'elasticsearch.java' +apply plugin: 'elasticsearch.build' dependencies { compileOnly project(":server") @@ -7,3 +7,7 @@ dependencies { testImplementation project(":test:framework") } + +tasks.named('forbiddenApisMain').configure { + enabled = false +} diff --git a/gradle/build.versions.toml b/gradle/build.versions.toml index 53ce5a50f6295..f0fb634833560 100644 --- a/gradle/build.versions.toml +++ b/gradle/build.versions.toml @@ -21,6 +21,7 @@ httpcore = "org.apache.httpcomponents:httpcore:4.4.12" httpclient = "org.apache.httpcomponents:httpclient:4.5.10" idea-ext = "gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext:1.1.4" json-schema-validator = "com.networknt:json-schema-validator:1.0.49" +json-assert = "org.skyscreamer:jsonassert:1.5.0" jackson-dataformat-yaml = { group = "com.fasterxml.jackson.dataformat", name="jackson-dataformat-yaml", version.ref="jackson" } jackson-platform = { group = "com.fasterxml.jackson", name="jackson-bom", version.ref="jackson" } jna = "net.java.dev.jna:jna:5.10.0" diff --git a/plugins/repository-hdfs/hadoop-client-api/build.gradle b/plugins/repository-hdfs/hadoop-client-api/build.gradle index 345f8605eac90..4ac6f79530fcb 100644 --- a/plugins/repository-hdfs/hadoop-client-api/build.gradle +++ b/plugins/repository-hdfs/hadoop-client-api/build.gradle @@ -1,4 +1,4 @@ -apply plugin: 'elasticsearch.java' +apply plugin: 'elasticsearch.build' apply plugin: 'com.github.johnrengelman.shadow' dependencies { @@ -8,3 +8,9 @@ dependencies { tasks.named('shadowJar').configure { exclude 'org/apache/hadoop/util/ShutdownHookManager$*.class' } + +['jarHell', 'thirdPartyAudit', 'forbiddenApisMain', 'splitPackagesAudit'].each { + tasks.named(it).configure { + enabled = false + } +} diff --git a/plugins/repository-hdfs/hadoop-client-api/licenses/hadoop-client-api-3.3.1.jar.sha1 b/plugins/repository-hdfs/hadoop-client-api/licenses/hadoop-client-api-3.3.1.jar.sha1 new file mode 100644 index 0000000000000..dc2f20e310d30 --- /dev/null +++ b/plugins/repository-hdfs/hadoop-client-api/licenses/hadoop-client-api-3.3.1.jar.sha1 @@ -0,0 +1 @@ +4b9c9cdd9967495838fb521001699c4c9dddf183 \ No newline at end of file diff --git a/plugins/repository-hdfs/hadoop-client-api/licenses/hadoop-client-api-LICENSE.txt b/plugins/repository-hdfs/hadoop-client-api/licenses/hadoop-client-api-LICENSE.txt new file mode 100644 index 0000000000000..d645695673349 --- /dev/null +++ b/plugins/repository-hdfs/hadoop-client-api/licenses/hadoop-client-api-LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/plugins/repository-hdfs/hadoop-client-api/licenses/hadoop-client-api-NOTICE.txt b/plugins/repository-hdfs/hadoop-client-api/licenses/hadoop-client-api-NOTICE.txt new file mode 100644 index 0000000000000..62fc5816c996b --- /dev/null +++ b/plugins/repository-hdfs/hadoop-client-api/licenses/hadoop-client-api-NOTICE.txt @@ -0,0 +1,2 @@ +This product includes software developed by The Apache Software +Foundation (http://www.apache.org/). diff --git a/rest-api-spec/build.gradle b/rest-api-spec/build.gradle index a74f25dc8a551..b0b327a9f4ff2 100644 --- a/rest-api-spec/build.gradle +++ b/rest-api-spec/build.gradle @@ -38,8 +38,6 @@ testClusters.configureEach { requiresFeature 'es.index_mode_feature_flag_registered', Version.fromString("8.0.0") } -tasks.named("test").configure { enabled = false } - tasks.named("yamlRestTestV7CompatTransform").configure { task -> task.skipTestsByFilePattern("**/cat*/*.yml", "Cat API are meant to be consumed by humans, so will not be supported by Compatible REST API") diff --git a/test/framework/build.gradle b/test/framework/build.gradle index 5a2146a1d3fba..d4b641e94808b 100644 --- a/test/framework/build.gradle +++ b/test/framework/build.gradle @@ -40,8 +40,6 @@ tasks.named('forbiddenApisMain').configure { // TODO: should we have licenses for our test deps? tasks.named("dependencyLicenses").configure { enabled = false } tasks.named("dependenciesInfo").configure { enabled = false } -tasks.named("dependenciesGraph").configure { enabled = false } - tasks.named("thirdPartyAudit").configure { ignoreMissingClasses( // classes are missing diff --git a/test/x-content/build.gradle b/test/x-content/build.gradle index 147bdecc7aa6d..5653fad724fa5 100644 --- a/test/x-content/build.gradle +++ b/test/x-content/build.gradle @@ -30,7 +30,6 @@ tasks.named('forbiddenApisMain').configure { // TODO: should we have licenses for our test deps? tasks.named("dependencyLicenses").configure { enabled = false } tasks.named("dependenciesInfo").configure { enabled = false } -tasks.named("dependenciesGraph").configure { enabled = false } tasks.named("thirdPartyAudit").configure { ignoreMissingClasses(