Apache Rat 0.18 介绍与 CLI 审计实战

Apache Rat 0.18 入门与 CLI 审计实战:Creadur 项目定位与许可证审计原理、java -jar 快速上手、审计报告字段解读(AL/???/! 与计数)、退出码语义与 CI 判定、jar 自动解包审计,全部参数 Ubuntu 22.04 + JDK 17 实测

Apache RatRatApache许可证审计2026/10/15

Apache Rat 0.18 介绍与 CLI 审计实战

目标:介绍 Apache Rat(Apache Creadur 项目的许可证审计工具)的定位与工作原理,并以 0.18 版本的独立 CLI 形态(java -jar)完成一次从下载、校验、首次审计、报告解读、退出码判定到 jar 归档解包审计的完整实战;全部命令与回显均在 Ubuntu 22.04 + OpenJDK 17(java 17.0.20.1)环境实测通过,实测日期 2026-10-15。

一、环境信息

  • 操作系统:Ubuntu 22.04(x86_64)
  • JDK:OpenJDK 17.0.20.1(apt 安装 openjdk-17-jdk-headless)
  • Apache Rat:apache-rat-0.18(发布文件时间戳 2026-03-20,Apache Creadur 项目)
  • Rat 主程序:/opt/rat/apache-rat-0.18/apache-rat-0.18.jar(7,479,290 字节)
  • 分发包:apache-rat-0.18-bin.tar.gz(6,768,552 字节,即 6.5M)
  • 示例源码树:/opt/demo-src(5 个文件,第四章构造)
  • 示例归档:/opt/demo.jar(2,182 字节,第六章构造)

二、Apache Rat 定位与工作原理

本节先说清 RAT 是什么、它和构建工具插件版的关系、以及 0.18 这个版本的时间线,为后面的 CLI 实战建立背景。

2.1 RAT 是什么:Creadur 项目的许可证审计工具

Apache Rat(Release Audit Tool)是 Apache Creadur 项目的核心工具,用于审计源码树中每个文件的许可证头(license header)情况:哪些文件带上了已批准的许可证(如 Apache License 2.0)、哪些文件完全没有任何许可证声明。它解决的典型问题是——Apache 基金会及众多开源项目在发布版本前,要求对发行包做一次 release audit,确认所有源文件都带有正确的许可证头,避免"某个新文件忘了加头"这类合规事故进入正式发布。

RAT 的工作原理是基于启发式匹配(heuristics):它对每个文件做类型识别与许可证模式匹配,把文件归入若干文档类型(标准源码文件、归档、二进制、通知文件等),并对文本内容匹配内置的许可证族(license family)模式(如 AL = Apache License 2.0 家族),最终输出一份审计报告,包含计数汇总与逐文件明细。官方在 --help 末尾的 Notes 中原文写明了它的定位边界:

1. RAT highlights possible issues.
2. RAT reports require interpretation.
3. RAT often requires some tuning before it runs well against a project.
4. RAT relies on heuristics: it may miss issues

即:RAT 只做"高亮疑似问题",报告需要人来解读,通常要针对项目做一轮排除规则调优,且启发式可能漏报——这四句话是理解 RAT 报告的官方总纲。

💡 说明:RAT 检测的是"许可证头是否存在且能被识别",不校验许可证文本的法律有效性,也不能替代法务审查。报告中的 ?(未知)不等于"侵权",只代表"没匹配上内置模式"。

2.2 与 Maven 插件版、Ant 任务版的关系

Apache Rat 不只有命令行一种形态。Creadur 项目在 Maven Central 上发布同一套审计内核的多种载体,命名均为 org.apache.rat 组:

载体坐标/形态适用场景
独立 CLIapache-rat-0.18.jar(本文主角)任意环境 java -jar 直接审计,CI 里最省事
Maven 插件org.apache.rat:apache-rat-plugin:0.18Maven 构建,把审计绑进构建生命周期
Ant 任务org.apache.rat:apache-rat-tasks:0.18Ant 构建脚本内嵌 <rat:report> 任务

关键差异:三种形态共用同一套许可证匹配内核,但入口与参数体系不同——CLI 用命令行选项(本文实测的 --input-exclude 等),Maven 插件用 <configuration> XML 配置。CI 场景下独立 CLI 最通用:不依赖构建工具、不污染构建配置,一条命令出一个报告和一个退出码。

2.3 0.18 版本时间线与获取渠道概览

  • 0.18 是当前最新版本:官方分发目录 https://dlcdn.apache.org/creadur/apache-rat-0.18/ 内的发布文件时间戳为 2026-03-20(2026-10-15 实测核实)。
  • 0.17 起 CLI 参数体系大幅改版:旧短参数(-e、-o、-x、-A 等)被标记 Deprecated for removal since 0.17,新参数为 --input-exclude、--output-file、--output-style、--edit-license 等长名形式;0.18 中旧参数仍可用但会打 WARN(对照表见系列篇《Apache Rat 0.18 排除规则与输出格式详解》第八章,本文第五章的退出码行为对新旧参数一致生效)。
  • 0.18 相比更早版本(如 0.16)有一个重要默认行为变化:0 配置下不做任何标准排除——pom.xml、target/、.git/ 等不会自动过滤(实测见 4.3 节),旧教程"下载即扫、自带排除"的描述已不适用。

三、环境准备与安装

本节完成从零到可运行:安装 JDK → 下载分发包 → 校验 sha512 → 解压 → 确认包结构与运行方式 → 验证 --help。

3.1 安装 JDK 17

RAT 是纯 Java 工具,先装 JDK。实测使用 Ubuntu 22.04 仓库中的 OpenJDK 17:

apt-get update
apt-get install -y openjdk-17-jdk-headless wget ca-certificates

验证:

java -version

实测回显:

openjdk version "17.0.20.1" 2026-07-15
OpenJDK Runtime Environment (build 17.0.20.1+1-Ubuntu-1ubuntu122.04)
OpenJDK 64-Bit Server VM (build 17.0.20.1+1-Ubuntu-1ubuntu122.04, mixed mode, sharing)

⚠️ 注意:后续所有 jar cf、java -jar 命令依赖 JDK(而非仅 JRE),务必安装 jdk-headless 而非只装 jre-headless,否则第六章构造示例 jar 的 jar 命令不存在。

3.2 下载 apache-rat-0.18-bin.tar.gz 并校验 sha512

Rat 属 Apache Creadur 项目,官方分发目录在 https://dlcdn.apache.org/creadur/apache-rat-0.18/(直接访问 https://dlcdn.apache.org/rat/ 会 404,排障细节见第八章 FAQ)。目录内提供 bin/src 两种包,各有 tar.gz/tar.bz2/zip 格式,且每份文件配 .asc(签名)、.sha256、.sha512 校验件。本文采用 bin tar.gz:

mkdir -p /opt/rat && cd /opt/rat
wget https://dlcdn.apache.org/creadur/apache-rat-0.18/apache-rat-0.18-bin.tar.gz
wget https://dlcdn.apache.org/creadur/apache-rat-0.18/apache-rat-0.18-bin.tar.gz.sha512

校验。官方 .sha512 文件是"纯哈希一行"格式(内容只有哈希值,不带 sha512sum -c 需要的"哈希 + 文件名"两列),直接 sha512sum -c apache-rat-0.18-bin.tar.gz.sha512 会失败,需自行拼接后用 -c - 从标准输入读取:

sha512sum apache-rat-0.18-bin.tar.gz
echo '315b16536526838237c42b5e6b613d29adc77e25a6e44a866b2b7f8b162e03d3629d49c9faea86ceb864a36b2c42838b8ce43d6f2db544e961f2259e242748f4  apache-rat-0.18-bin.tar.gz' | sha512sum -c -

实测回显(第一条为本地计算值,与官方 .sha512 文件内容一致;第二条为校验结果):

315b16536526838237c42b5e6b613d29adc77e25a6e44a866b2b7f8b162e03d3629d49c9faea86ceb864a36b2c42838b8ce43d6f2db544e961f2259e242748f4  apache-rat-0.18-bin.tar.gz
apache-rat-0.18-bin.tar.gz: OK

💡 技术拓展:Apache 分发包普遍同时提供三种完整性/真实性校验件,选型对比——

校验件原理/特点适用场景
.sha512 / .sha256哈希摘要,验证"下载完整性"(防传输损坏)日常下载快速校验,一条命令完成
.ascGPG 签名,验证"发布真实性"(防篡改+确认发布者)正式发布审计、安全敏感场景,需导入 Apache 公钥
两者配合先验哈希确认完整,再验签名确认来源最高要求场景

本文采用 .sha512:官方随包提供、无需准备密钥环,且已实测校验通过 OK;如需更高保证再补 .asc 验签。

3.3 解压与目录结构(bin 包仅 4 个文件,无启动脚本)

tar xzf apache-rat-0.18-bin.tar.gz -C /opt/rat
ls -l /opt/rat/apache-rat-0.18/

实测回显:

total 7308
-rw-r--r-- 1 root root 7479290 Mar 20  2026 apache-rat-0.18.jar
-rw-r--r-- 1 root root     98 Mar 20  2026 LICENSE
-rw-r--r-- 1 root root    663 Mar 20  2026 NOTICE
-rw-r--r-- 1 root root  55499 Mar 20  2026 RELEASE_NOTES.txt

要点:bin 包内只有 4 个文件——LICENSE、NOTICE、RELEASE_NOTES.txt 和主 jar,没有任何启动脚本。RAT 0.18 的标准运行方式就是直接 java -jar:

java -jar /opt/rat/apache-rat-0.18/apache-rat-0.18.jar --help

实测回显(首 2 行,完整 501 行帮助见 3.5 节):

INFO: Apache Creadur RAT 0.18 (Apache Software Foundation)
usage: java -jar apache-rat/target/apache-rat-0.18.jar [options] [DIR|ARCHIVE]

命令骨架为 java -jar <jar 路径> [options] [DIR|ARCHIVE]:末位位置参数是要扫描的目录或归档文件(DIR|ARCHIVE),中间是选项。usage 行中的 apache-rat/target/apache-rat-0.18.jar 是官方构建时的源路径残留,照抄无效,实际使用时替换为你自己的 jar 路径即可。

3.4 裸 jar 的两种获取方式

若只需要主 jar(CI 场景最常见),有两种等价获取方式,二者字节完全一致(7,479,290 字节,实测比对):

方式一:从 bin 包解出(3.3 节已完成):

ls -l /opt/rat/apache-rat-0.18/apache-rat-0.18.jar
-rw-r--r-- 1 root root 7479290 Mar 20  2026 /opt/rat/apache-rat-0.18/apache-rat-0.18.jar

方式二:直接从 Maven Central 下载裸 jar(官方分发目录不含裸 jar,Maven Central 上有,实测 HTTP 200 且 content-length 7479290 一致):

wget https://repo1.maven.org/maven2/org/apache/rat/apache-rat/0.18/apache-rat-0.18.jar
ls -l apache-rat-0.18.jar
-rw-r--r-- 1 root root 7479290 Oct 15 10:12 apache-rat-0.18.jar

💡 说明:两种方式得到的都是同一主 jar,java -jar 运行行为一致。CI 里选方式二可以少下载 6.5M 的完整分发包;但正式 release audit 建议用方式一并完成 3.2 节的哈希校验流程。

3.5 运行方式验证(--help 首跑)

--help 是验证安装与查看全部参数的入口,完整帮助约 501 行,这里摘录关键骨架(原文逐字):

INFO: Apache Creadur RAT 0.18 (Apache Software Foundation)
usage: java -jar apache-rat/target/apache-rat-0.18.jar [options] [DIR|ARCHIVE]

====== Available Options ======
 -?,--help                                            Print help for the RAT command line interface and exit.
    --input-exclude <Expression>                      Excludes files matching <Expression>. Multiple values may be
                                                      specified. Note that '--' or a following option is required when
                                                      using this parameter.
    --output-file <File>                              Define the output file where to write a report to. (Default value
                                                      = System.out)
    --output-style <StyleSheet>                       XSLT stylesheet to use when creating the report. Either an
                                                      external xsl file may be specified or one of the internal named
                                                      sheets.
    --help-licenses                                   Print information about registered licenses.

(以上为输出节选,仅摘录 5 个代表性选项,两个选项之间的其余选项行已省略、完整约 501 行以 --help 实际输出为准;--input-exclude 帮助原文中的 Note that '--' or a following option is required when using this parameter 是 0.18 最重要的参数约定,第三章与系列篇实测展开。)

0.18 推荐的新参数体系按功能分组速查(默认值均摘自 --help 原文):

功能组参数说明(默认值)
输入过滤--input-exclude <Expression>按 Ant/gitignore 风格模式排除,多值,多值后必须 --
--input-exclude-file <File>从文件批量读取排除模式
--input-exclude-std <StandardCollection>按标准集合排除(GIT/MAVEN/ALL 等 25 种)
--input-include / --input-include-file / --input-include-std包含规则,覆盖排除规则
输出控制--output-file <File>报告输出文件(默认 System.out)
--output-style <StyleSheet>报告样式(内置 plain-rat/missing-headers/unapproved-licenses/xml)
--output-archive <ProcessingType>归档文件报告粒度(默认 NOTIFICATION)
--output-standard <ProcessingType>标准文件报告粒度(默认 ABSENCE)
自动补头--edit-license / --edit-overwrite / --edit-copyright <arg> / --dry-run为无头文件补 Apache-2.0 头
计数阈值--counter-max <CounterPattern> / --counter-min <CounterPattern>控制某计数器的允许范围,驱动退出码
许可配置--license-families-approved/--denied、--licenses-approved/--denied 及对应 -file定制批准/拒绝的许可证族与许可证
其他--config <File>、--configuration-no-defaults、--log-level <LogLevel>(默认 WARN)、--help-licenses系统配置文件、日志级别、列出注册许可证

验证安装完成的判定标准:--help 能打印 INFO: Apache Creadur RAT 0.18 横幅且退出码为 0(echo $? 实测 0)。

四、首次审计实战

本节构造一个 5 文件的最小示例源码树,先看 0.18 无参运行的行为变化,再跑第一次真实审计,最后逐列解读报告。

4.1 构造示例源码树

在 /opt/demo-src 下构造 5 个文件,覆盖四种典型情况:两个带 Apache 2.0 头的 Java 文件、一个无头 Java 文件、一个无头 XML、一个无头 README:

mkdir -p /opt/demo-src/src /opt/demo-src/resources

# 带 Apache 2.0 全文许可证头的 Main.java
cat > /opt/demo-src/src/Main.java <<'JAVA'
/*
 * 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.
 */
public class Main {
    public static void main(String[] args) {
        System.out.println("demo");
    }
}
JAVA

# 带 Apache 2.0 全文许可证头的 Utils.java(头同上,类体不同)
cat > /opt/demo-src/src/Utils.java <<'JAVA'
/*
 * 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.
 */
public class Utils {
}
JAVA

# 无任何许可证头的 Legacy.java(模拟历史遗留文件)
cat > /opt/demo-src/src/Legacy.java <<'JAVA'
// Legacy code without any license header.
public class Legacy {
}
JAVA

# 无头的 XML 配置文件
cat > /opt/demo-src/resources/config.xml <<'XML'
<?xml version="1.0"?>
<config>
  <name>demo</name>
</config>
XML

# 两行普通文本的 README
cat > /opt/demo-src/README.txt <<'TXT'
Demo project for Apache Rat audit walkthrough.
Plain text without any license header.
TXT

验证树结构:

find /opt/demo-src -type f | sort

实测回显:

/opt/demo-src/README.txt
/opt/demo-src/resources/config.xml
/opt/demo-src/src/Legacy.java
/opt/demo-src/src/Main.java
/opt/demo-src/src/Utils.java

💡 说明:示例树内容为演示用最小构造(Legacy.java 的首两行、config.xml 的 <?xml version="1.0"?> 首行与下文实测回显中的判定完全对应);后文审计报告为 0.18 对该树的真实输出。

4.2 无参运行:0.18 的行为变化

先跑一条最朴素的命令——不带任何参数直接运行。旧版教程普遍写"无参即扫描当前目录",0.18 中此行为已变:

cd /opt/demo-src && java -jar /opt/rat/apache-rat-0.18/apache-rat-0.18.jar

完整回显:

INFO: Apache Creadur RAT 0.18 (Apache Software Foundation)
INFO: Please use the "--help" option to see a list of valid commands and options, as you did not provide any arguments.

确认退出码:

echo $?
0

⚠️ 注意:0.18 无参运行不再扫描当前目录,只打印提示并以退出码 0 结束。审计目标必须显式给出 [DIR|ARCHIVE] 位置参数(或经 -- 分隔后给出)。把旧脚本原样迁移到 0.18 会得到"看似成功、实则什么都没扫"的结果——这是 CI 迁移的第一个坑(第五章汇总全部退出码陷阱)。

4.3 带路径默认审计与完整报告

现在给扫描目标,做 0 配置下的默认审计(stdout/stderr 分流便于分别留档):

cd /opt && java -jar rat/apache-rat-0.18/apache-rat-0.18.jar demo-src > /tmp/audit1.out 2>/tmp/audit1.err; echo $?
1

退出码为 1(原因见 4.4 与第五章)。完整 stdout 报告如下(逐字实测):

INFO: Apache Creadur RAT 0.18 (Apache Software Foundation)
*****************************************************
Summary
*****************************************************
Generated at: 2026-10-14T16:49:28Z
    by Apache Creadur RAT 0.18 (Apache Software Foundation)

-----------------------------------------------------
Counters
-----------------------------------------------------
    (Entries starting with '!' exceed the minimum or maximum values)
  Approved:           2    A count of approved licenses.
  Archives:           0    A count of archive files.
  Binaries:           0    A count of binary files.
  Document types:     2    A count of distinct document types.
  Ignored:            0    A count of ignored files.
  License categories: 2    A count of distinct license categories.
  License names:      2    A count of distinct license names.
  Notices:            1    A count of notice files.
  Standards:          4    A count of standard files.
! Unapproved:         2    A count of unapproved licenses.
  Unknown:            2    A count of unknown file types.


-----------------------------------------------------
Licenses detected
-----------------------------------------------------

Apache License 2.0: 2 
Unknown license: 2 

-----------------------------------------------------
License Categories detected
-----------------------------------------------------

?????: 2 
AL   : 2 

-----------------------------------------------------
Document Types detected
-----------------------------------------------------

NOTICE: 1 
STANDARD: 4 

*****************************************************
Files with unapproved licenses
*************************************

  /resources/config.xml
  /src/Legacy.java

*****************************************************
Detail
*****************************************************

  Documents with unapproved licenses will start with a '!'
  The first character on the next line identifies the document type.
   
   char         type
    A       Archive file
    B       Binary file
    I       Ignored file
    N       Notice file
    S       Standard file
    U       Unknown file.
  
  /README.txt
  N         text/plain    ISO-8859-1

! /resources/config.xml
  S         application/xml    ISO-8859-1
    ?????    ?????         Unknown license (Unapproved)

! /src/Legacy.java
  S         text/x-java-source    ISO-8859-1
    ?????    ?????         Unknown license (Unapproved)

  /src/Main.java
  S         text/x-java-source    ISO-8859-1
    AL       AL2.0         Apache License 2.0

  /src/Utils.java
  S         text/x-java-source    ISO-8859-1
    AL       AL2.0         Apache License 2.0


INFO: RAT summary:
INFO:   Approved:  2
INFO:   Archives:  0
INFO:   Binaries:  0
INFO:   Document types:  2
INFO:   Ignored:  0
INFO:   License categories:  2
INFO:   License names:  2
INFO:   Notices:  1
INFO:   Standards:  4
INFO:   Unapproved:  2
INFO:   Unknown:  2

stderr 顶部固定有 3 行 SLF4J 提示(无害噪音):

SLF4J(W): No SLF4J providers were found.
SLF4J(W): Defaulting to no-operation (NOP) logger implementation
SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details.

stderr 尾部是导致退出码 1 的关键错误(完整):

ERROR: Unexpected count for UNAPPROVED, limit is [0,0].  Count: 2
Exception in thread "main" org.apache.rat.document.RatDocumentAnalysisException: Issues with UNAPPROVED
        at org.apache.rat.Report.main(Report.java:60)

4.4 报告逐列解读:计数器、类别缩写与文件标记

以上报告共 6 个区段,逐段解读(全部结论以上面实测输出为据):

(1)Summary → Counters 段:11 个计数器。 开头的提示行 (Entries starting with '!' exceed the minimum or maximum values) 说明:带 ! 的计数行表示超出该计数器的默认允许范围。实测只有 ! Unapproved: 2 带 !,因为 UNAPPROVED 计数器默认范围为 [0,0](即"0 个未批准")——这是 0.18 退出码机制的根源。各计数器含义即行尾原文注释(Approved=批准许可证文件数、Standards=标准文件数、Notices=通知文件数、Ignored=被排除忽略数、Unknown=未知类型数等);每个计数器的默认范围与 --counter-max/--counter-min 调法见系列篇《Apache Rat 0.18 排除规则与输出格式详解》第六章。

(2)Licenses detected 段: 检测到的许可证名及命中文件数——Apache License 2.0: 2(Main.java/Utils.java)、Unknown license: 2(Legacy.java/config.xml)。

(3)License Categories detected 段: 许可证家族缩写列。AL 即 Apache License 2.0 所在家族;????? 是"未知许可证"家族的 5 问号占位(凡未被内置模式识别的内容都归入此类)。家族缩写就是 Detail 段每文件许可证判定行的第一列。

(4)Document Types detected 段: 文档类型统计——NOTICE: 1(README.txt)、STANDARD: 4(4 个被正常解析的文本文件)。

(5)Files with unapproved licenses 段: 未批准清单,直接给出需要补头的文件路径 /resources/config.xml、/src/Legacy.java。

(6)Detail 段: 逐文件明细,每文件三部分:路径行(! 前缀表示 unapproved)→ 类型码/媒体类型/编码行 → 许可证判定行。报告自带类型码图例(原文):A=Archive、B=Binary、I=Ignored、N=Notice、S=Standard、U=Unknown。许可证判定行格式为"家族缩写 + 许可证 ID + 全名",如 AL AL2.0 Apache License 2.0,或未识别时的 ????? ????? Unknown license (Unapproved)。

三个实测要点:

  • README.txt 被识别为 N(NOTICE)类型:不做许可证判定、不计入 unapproved——RAT 对 README/NOTICE 类文本有专门类型归类,这是报告惯例,不是漏报。
  • 0 配置下无任何自动排除:若示例树里有 pom.xml、target/、.git/,它们会全部进入报告(系列篇实测复现,0.18 与 0.16 的关键差异)。
  • 报告尾部 INFO: RAT summary: 会把 Counters 逐行复述一遍(到 stdout),无论成败都会打印,可用于脚本快速取数。

验证解读正确性的办法:报告显示 unapproved 的恰是构造时无头的 2 个文件(config.xml、Legacy.java),带头的 2 个 Java 文件判 AL,与构造预期一致——报告可信。

五、退出码语义与 CI 判定

退出码是 RAT 接入 CI 的核心接口。本节用 echo $? 逐条实测各种场景的退出码,并重点排雷"参数拼错也是 exit 0"这个 CI 大坑。

5.1 退出码实测汇总

场景命令要点Unapproved退出码
无参数(缺 DIR 参数,仅提示)-0
存在未批准文件-- demo-src(2 个 unapproved)21
存在未批准文件(1 个)--input-exclude '**/*.xml' -- demo-src11
全部批准/排除--input-exclude-file excludes.txt -- demo-src00
阈值放宽--counter-max UNAPPROVED:5 -- demo-src20
参数错误--nonexistent-opt -- demo-src-0

语义归纳(全部实测):

  • Unapproved > 0 → 退出码 1:UNAPPROVED 计数器默认范围 [0,0],任何一个未批准文件都会触发 ERROR: Unexpected count for UNAPPROVED, limit is [0,0]. Count: N + RatDocumentAnalysisException: Issues with UNAPPROVED。这不是 bug,是 0.18 设计内的 CI 判定机制。
  • 全部批准/被排除 → 退出码 0:例如用排除文件把 2 个无头文件都排除后,Unapproved: 0,正常收尾。
  • --counter-max UNAPPROVED:5 → 退出码 0:把允许上限放宽到 5 后,同样的 2 个 unapproved 不再触发失败——"允许最多 n 个未批准文件"的 CI 放行阈值开关。
  • 退出码由 counter 范围检查驱动:所有 --counter-max/--counter-min 都遵循同一机制(完整 CounterPattern 默认范围表见系列篇第六章)。

5.2 CI 大坑:参数拼错也是 exit 0 与规避方案

三个"退出码 0 但其实什么都没审计"的场景,在 CI 里全部表现为"绿灯通过",必须显式规避:

坑 1:参数拼错。 选项名打错时 stderr 有 ERROR: Unrecognized option: --nonexistent-opt,但退出码仍是 0:

java -jar /opt/rat/apache-rat-0.18/apache-rat-0.18.jar --nonexistent-opt -- demo-src; echo $?
ERROR: Unrecognized option: --nonexistent-opt
0

(stdout 另会打印整份 usage。)

坑 2:多值参数吞掉扫描目标。 --input-exclude 等多值参数漏写 -- 分隔符时,扫描目标被当作第二个排除表达式,stderr 报 ERROR: No directories or files specified for scanning. Did you forget to close a multi-argument option?,退出码同样为 0(实测复现与正确写法见系列篇第三章)。

坑 3:无参运行。 4.2 节实测:0.18 无参只提示、不扫描、退出码 0。

💡 技术拓展:CLI 工具"参数错误时的退出码约定"业界并不统一——

约定典型代表行为
参数错误返回非 0(如 2)GNU 风格工具(ls、grep 等)拼错参数 CI 直接红
参数错误返回 0,仅 stderr 报错Apache Rat 0.18(实测)拼错参数 CI 静默绿灯,需自行兜底

Rat 属于第二类,且它的退出码被"复用"为审计判定(unapproved 超限=1),因此不能用退出码发现参数错误。

规避方案(按优先级):

  1. 升级参数拼写:全部使用 0.18 新长参数(--input-exclude 等),不凭旧教程记忆写 -e/-E 短参数;写 CI 前先在交互环境跑一遍 --help 核对参数名。

  2. CI 脚本里显式校验 stderr:RAT 的错误都走 stderr 且有固定措辞,可以在管道里检查。示例(判断是否出现两类致命错误字样):

    java -jar /opt/rat/apache-rat-0.18/apache-rat-0.18.jar --input-exclude '**/*.xml' -- demo-src >/tmp/rat.out 2>/tmp/rat.err
    grep -q 'ERROR: Unrecognized option' /tmp/rat.err && { echo '参数拼写错误'; exit 2; }
    grep -q 'ERROR: No directories or files specified' /tmp/rat.err && { echo '多值参数未用 -- 分隔'; exit 2; }
    
  3. 校验 stdout 报告存在性:正常审计的 stdout 一定包含 INFO: RAT summary: 计数块(4.3 节实测),报错场景没有;可在 CI 里 grep -q 'INFO: RAT summary:' /tmp/rat.out || exit 2 兜底。

  4. 用 --output-file 把报告落文件(见系列篇 4.1 节),再对文件做存在性与内容校验。

验证规避有效:按方案 1 的正确写法重跑,grep -c 'INFO: RAT summary:' /tmp/rat.out 应输出 1(实测)。

六、jar 归档自动解包审计

RAT 对 jar/war 等 ARCHIVE 类型文件自动解包并逐条目审计,无需任何解压步骤。本节实测一个 2,182 字节的 demo jar。

构造(jar 命令来自 JDK,把示例树 5 个文件打进 jar):

cd /opt/demo-src && jar cf /opt/demo.jar src/Main.java src/Utils.java src/Legacy.java resources/config.xml README.txt
ls -l /opt/demo.jar
-rw-r--r-- 1 root root 2182 Oct 15 10:30 /opt/demo.jar

审计。归档报告粒度由 --output-archive 控制(默认 NOTIFICATION 仅列出条目存在;PRESENCE 列出条目内识别到的许可证;ABSENCE 列出许可证与未知许可证)。为展示 jar 内逐条目的许可证判定,升到 PRESENCE:

cd /opt && java -jar rat/apache-rat-0.18/apache-rat-0.18.jar --output-archive PRESENCE -- demo.jar > /tmp/jar1.out 2>/tmp/jar1.err; echo $?
1

完整 stdout 报告(逐字实测):

INFO: Apache Creadur RAT 0.18 (Apache Software Foundation)
*****************************************************
Summary
*****************************************************
Generated at: 2026-10-14T16:52:30Z
    by Apache Creadur RAT 0.18 (Apache Software Foundation)

-----------------------------------------------------
Counters
-----------------------------------------------------
    (Entries starting with '!' exceed the minimum or maximum values)
  Approved:           2    A count of approved licenses.
  Archives:           0    A count of archive files.
  Binaries:           0    A count of binary files.
  Document types:     2    A count of distinct document types.
  Ignored:            0    A count of ignored files.
  License categories: 2    A count of distinct license categories.
  License names:      2    A count of distinct license names.
  Notices:            1    A count of notice files.
  Standards:          5    A count of standard files.
! Unapproved:         3    A count of unapproved licenses.
  Unknown:            3    A count of unknown file types.


-----------------------------------------------------
Licenses detected
-----------------------------------------------------

Apache License 2.0: 2 
Unknown license: 3 

-----------------------------------------------------
License Categories detected
-----------------------------------------------------

?????: 3 
AL   : 2 

-----------------------------------------------------
Document Types detected
-----------------------------------------------------

NOTICE: 1 
STANDARD: 5 

*****************************************************
Files with unapproved licenses
*************************************

  /demo.jar#/META-INF/MANIFEST.MF
  /demo.jar#/src/Legacy.java
  /demo.jar#/resources/config.xml

*****************************************************
Detail
*****************************************************

  Documents with unapproved licenses will start with a '!'
  The first character on the next line identifies the document type.
   
   char         type
    A       Archive file
    B       Binary file
    I       Ignored file
    N       Notice file
    S       Standard file
    U       Unknown file.
  
! /demo.jar#/META-INF/MANIFEST.MF
  S         text/plain    ISO-8859-1
    ?????    ?????         Unknown license (Unapproved)

  /demo.jar#/src/Main.java
  S         text/x-java-source    ISO-8859-1
    AL       AL2.0         Apache License 2.0

  /demo.jar#/src/Utils.java
  S         text/x-java-source    ISO-8859-1
    AL       AL2.0         Apache License 2.0

! /demo.jar#/src/Legacy.java
  S         text/x-java-source    ISO-8859-1
    ?????    ?????         Unknown license (Unapproved)

! /demo.jar#/resources/config.xml
  S         application/xml    ISO-8859-1
    ?????    ?????         Unknown license (Unapproved)

  /demo.jar#/README.txt
  N         text/plain    ISO-8859-1


INFO: RAT summary:
INFO:   Approved:  2
INFO:   Archives:  0
INFO:   Binaries:  0
INFO:   Document types:  2
INFO:   Ignored:  0
INFO:   License categories:  2
INFO:   License names:  2
INFO:   Notices:  1
INFO:   Standards:  5
INFO:   Unapproved:  3
INFO:   Unknown:  3

要点:

  • jar 条目以 <归档文件>#<内部路径> 语法展示(实测 demo.jar#/src/Legacy.java),jar 被自动解包、每个条目作为独立文档审计,无需任何额外参数。
  • 计数变化:Standards 4→5(多了 META-INF/MANIFEST.MF)、Unapproved 2→3、Unknown 2→3,退出码仍为 1。
  • META-INF/MANIFEST.MF 也被判 unapproved:0.18 的 0 配置默认不做任何标准排除,MAVEN 标准排除集合(含 **/MANIFEST.MF 模式)不会自动启用——审计含构建产物的归档时,记得用 --input-exclude-std MAVEN 或 --input-exclude 'META-INF/**' 类规则放行清单文件(见系列篇第二章)。
  • 验证:报告 unapproved 清单里的 3 个条目(MANIFEST.MF、Legacy.java、config.xml)均为打包内容中无许可证头的文件,与构造一致。

七、Maven / Gradle 集成概览(官方文档视角)

本章给不想用独立 CLI 的团队一个路线图。以下为官方文档与 Maven Central 坐标形态的概览,本文未对插件做实测,具体参数与行为以各插件官方文档为准。

Maven 插件:坐标 org.apache.rat:apache-rat-plugin:0.18,常用两个 goal——org.apache.rat:apache-rat-plugin:0.18:check(把审计绑进构建生命周期,发现未批准文件时使构建失败,适合发布前卡口)与 org.apache.rat:apache-rat-plugin:0.18:report(生成报告)。排除规则经插件 <configuration> 下的 <excludes> 等元素配置,与 CLI 的 --input-exclude 语义对应。

Ant 任务:坐标 org.apache.rat:apache-rat-tasks:0.18(Maven Central 坐标形态),在 Ant 构建文件中以内嵌任务方式产出报告,适合仍在用 Ant 的老项目。

Gradle:官方未提供第一方 Gradle 插件。社区通行做法有二:直接在 Gradle 任务里调 java -jar apache-rat-0.18.jar(即本文的 CLI 形态,退出码即任务成败);或经 apache-rat-tasks 走 Ant 任务桥接。选型建议:Maven 项目优先官方插件、其余场景用 CLI——CLI 形态的参数体系就是本文实测的这套,迁移成本最低。

八、常见问题(FAQ)

Q1:按 https://dlcdn.apache.org/rat/ 下载 404?

Rat 归 Apache Creadur 项目,分发路径在 /creadur/ 下。实测 2026-10-15:https://dlcdn.apache.org/rat/、https://downloads.apache.org/rat/、https://archive.apache.org/dist/rat/ 均 404。正确地址:

  • 最新版本:https://dlcdn.apache.org/creadur/apache-rat-0.18/
  • 全版本归档:https://archive.apache.org/dist/creadur/(该目录未实测下载验证,使用前请自行核验)

Q2:JDK 版本有要求吗?需要 21 或 11 吗?

实测 OpenJDK 17.0.20.1(Ubuntu 22.04 的 openjdk-17-jdk-headless)运行 apache-rat-0.18.jar 全部功能正常:--help、目录审计、xml 样式输出、--edit-license 自动补头、jar 归档解包,均无需更换 21 或 11。如遇兼容问题可查 bin 包内附带的 RELEASE_NOTES.txt(55,499 字节)。

Q3:README.txt 为什么不算 unapproved?是漏报吗?

不是。实测 README.txt 被归为 N(NOTICE)文档类型(见 4.3 报告 Detail 段),RAT 对此类文件不做许可证判定、也不计入 unapproved。这属于 RAT 的报告惯例:报告需要人来解读(官方 Notes 原文第 2 条),对判定存疑的文件应人工复核。

Q4:CI 绿灯通过,但审计好像没跑?

三个退出码为 0 但实际未审计的场景之一大概率命中:参数拼错(ERROR: Unrecognized option)、多值参数漏 --(ERROR: No directories or files specified for scanning)、无参运行(只打提示)。三者退出码都是 0,按 5.2 节的规避方案在脚本里校验 stderr 措辞与 INFO: RAT summary: 存在性。

Q5:stderr 里的 SLF4J(W) 三行警告要处理吗?

不用。SLF4J(W): No SLF4J providers were found. 等 3 行是无害噪音(RAT 未捆绑 SLF4J 实现所致),不影响功能与退出码,可忽略或在 CI 里过滤。

Q6:sha512sum -c 直接校验官方 .sha512 文件失败?

官方 .sha512 文件是"纯哈希一行"格式,缺少 sha512sum -c 期望的"哈希 + 文件名"两列。按 3.2 节方式自行拼接 '<哈希值> <文件名>' | sha512sum -c -,实测输出 apache-rat-0.18-bin.tar.gz: OK。

九、参考链接