From a21f52a7b820493bba40e3b900f461cda6d3f05e Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Sat, 13 Jun 2026 15:23:53 -0400 Subject: [PATCH] Add RAT for header checking --- build.gradle.kts | 71 +++++++++++++++++++ gradle/libs.versions.toml | 18 +++++ .../resources/application-http.properties | 16 +++++ .../resources/application-stdio.properties | 16 +++++ src/main/resources/application.properties | 16 +++++ 5 files changed, 137 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 075fafa9..f8b65474 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,6 +28,7 @@ plugins { alias(libs.plugins.jib) alias(libs.plugins.graalvm.native) apply false alias(libs.plugins.cyclonedx) + alias(libs.plugins.rat) } // GraalVM Native Image (Opt-In) @@ -313,6 +314,76 @@ spotless { } } +// Apache RAT (Release Audit Tool) — enforces Apache license headers. +// `rat` is wired into `check` by the plugin, so `./gradlew build` runs it. +// Report: build/reports/rat/index.html. +// +// Exclusions come from two sources so we don't duplicate patterns: +// 1. .gitignore — reused as the single source of truth for everything git +// already ignores (build output, .gradle, IDE dirs, *.iml, out/, bin/, +// .vscode, etc.). The plugin's own excludeFile does NOT apply .gitignore +// path semantics, so we translate each entry to a Gradle (Ant) glob: +// non-anchored entries match at any depth ("**/" prefix) and each is also +// emitted in directory-contents form ("/**") so ignored folders are pruned. +// 2. The explicit list below — only *tracked* files that RAT would scan but +// that legitimately carry no Apache header (binaries, data without a +// comment syntax, docs, tool/infra config, and LICENSE/NOTICE themselves). +tasks.rat { + val gitignoreExcludes = + rootProject + .file(".gitignore") + .readLines() + .map { it.trim() } + .filter { it.isNotEmpty() && !it.startsWith("#") && !it.startsWith("!") } + .map { it.removeSuffix("/") } + .map { + if (it.startsWith("/")) { + it.removePrefix("/") + } else if (it.startsWith("**/")) { + it + } else { + "**/$it" + } + }.flatMap { listOf(it, "$it/**") } + excludes.addAll(gitignoreExcludes) + + excludes.addAll( + listOf( + // Gradle wrapper (ships under its own license) + on-disk OS cruft + "gradlew", + "gradlew.bat", + "gradle/wrapper/**", + "**/.DS_Store", + // Tracked dotfiles that take no header + ".run/**", + ".gitignore", + ".gitattributes", + ".editorconfig", + ".tool-versions", + ".env.example", + // License/notice files themselves (no header by definition) + "LICENSE", + "NOTICE", + // ASF infra metadata and tool config (no header by convention) + ".asf.yaml", + "config/**", + // Tabular data — no comment syntax to hold a header + "**/*.csv", + // Documentation (markdown carries no license header) + "**/*.md", + "docs/**", + "dev-docs/**", + "security-docs/**", + // Binary assets + "images/**", + "**/*.png", + // Data / generated content (JSON cannot hold comments) + "mydata/**", + "**/*.json", + ), + ) +} + // Docker Integration Test Task // ============================= // Runs integration tests against the appropriate Docker image: diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6fc21873..4616d359 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,3 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# [versions] # Build plugins spring-boot = "3.5.14" @@ -7,6 +23,7 @@ jib = "3.5.3" spotless = "7.0.2" graalvm-native = "0.10.6" cyclonedx-plugin = "2.4.1" +apache-rat = "0.8.1" # Main dependencies spring-ai = "1.1.7" @@ -114,3 +131,4 @@ jib = { id = "com.google.cloud.tools.jib", version.ref = "jib" } spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } graalvm-native = { id = "org.graalvm.buildtools.native", version.ref = "graalvm-native" } cyclonedx = { id = "org.cyclonedx.bom", version.ref = "cyclonedx-plugin" } +rat = { id = "org.nosphere.apache.rat", version.ref = "apache-rat" } diff --git a/src/main/resources/application-http.properties b/src/main/resources/application-http.properties index c1b97597..77578a3c 100644 --- a/src/main/resources/application-http.properties +++ b/src/main/resources/application-http.properties @@ -1,3 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# spring.main.web-application-type=servlet spring.ai.mcp.server.type=sync spring.ai.mcp.server.protocol=stateless diff --git a/src/main/resources/application-stdio.properties b/src/main/resources/application-stdio.properties index b8864dfa..37f848be 100644 --- a/src/main/resources/application-stdio.properties +++ b/src/main/resources/application-stdio.properties @@ -1,3 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# spring.main.web-application-type=none # NOTE: You must disable the banner and the console logging # to allow the STDIO transport to work !!! diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 1592a770..c2038f5c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,3 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# spring.application.name=solr-mcp spring.profiles.active=${PROFILES:stdio} spring.ai.mcp.server.instructions=This server provides tools to interact with Apache Solr using Model Context Protocol (MCP) over STDIO and/or HTTP.