Enterprise 版本
Evidence — 深度参考
本页是 NextPDF\Enterprise\Evidence 模块的深度参考。该模块将各项验证发现封存进一个不可变的 EvidencePackage,以确定性 JSON 形式并附带稳定的 SHA-256 摘要将其导出,通过一个可插拔的存储契约进行持久化,并用 ContinuousMonitor 追踪各次运行之间的回归。该模块消费由 Validation 与 Compliance 接口面产出的各项发现;它本身并不执行任何符合性检查。有关工作流程指引,请先阅读 Evidence 能力页。
可用性与授权
标题为“可用性与授权”的章节此能力随 NextPDF Enterprise(nextpdf/enterprise)发行,并通过一个 Enterprise 层级的授权信封激活。没有该权益的部署不会加载此能力的各个类。比较各版本并获取授权。
该接口面受 enterprise.compliance.evidence 能力授权;被拒绝的权益会拒绝该功能。Core 与 Pro 会产出各项发现与报告;而将各项发现封存为一个不可变、确定性、可选带时间戳并具回归追踪的包,则没有 Core 层级或 Pro 层级的对等物。
公共 API 接口面
标题为“公共 API 接口面”的章节composer require nextpdf/enterprise:^3| 符号 | 参数 | 默认行为 | 返回 | 抛出或失败于 | 说明 |
|---|---|---|---|---|---|
EvidencePortal::__construct | EvidenceStoreInterface $store、EvidenceExporter $exporter | 装配 store 与 exporter | EvidencePortal | 未声明 | 两个协作者均可注入 |
EvidencePortal::generateEvidence | string $documentHash、list<EvidenceRecord> $records、?string $tsaTimestamp = null | 统计通过/失败,用一个全新的 UUID id 与挂钟 generatedAt 封存一个包,并将其持久化 | EvidencePackage | 未声明 | 通过 store() 而非 persistImmutable() 进行持久化 |
EvidencePortal::getEvidence | string $documentHash | 该哈希对应的最新已存储包 | ?EvidencePackage | 未声明 | 无存储时为 null |
EvidencePortal::getHistory | string $documentHash | 完整历史,最新在前 | list<EvidencePackage> | 未声明 | 排序由 store 提供 |
EvidencePortal::exportAsJson | EvidencePackage $package | 委托给 exporter | non-empty-string | JsonException | 与 EvidenceExporter::toJson 字节相同 |
EvidencePackage::__construct | 八个具名参数,见代码块 | 不可变值对象 | EvidencePackage | 未声明 | 各计数不会针对 $records 进行校验 |
EvidencePackage::allPassed | 无 | failedCount === 0 | bool | 未声明 | 空包时为 true;请以 totalFindings 作为判断闸门 |
EvidencePackage::passRate | 无 | passedCount / totalFindings | float | 未声明 | 当 totalFindings === 0 时为 0.0 |
EvidenceRecord::__construct | string $policyName、bool $passed、string $details、string $validatorVersion、DateTimeImmutable $timestamp | 不可变的单条策略检查结果 | EvidenceRecord | 未声明 | 所有属性均为 public readonly |
EvidenceExporter::toJson | EvidencePackage $package | 固定键顺序的 JSON;不转义斜杠与 Unicode | non-empty-string | JsonException | 键顺序至关重要 |
EvidenceExporter::exportHash | EvidencePackage $package | 针对 toJson() 字节计算的 SHA-256 | non-empty-string(64 位十六进制) | JsonException | 每个包稳定不变 |
EvidenceStoreInterface::store | EvidencePackage $package | 追加;允许按文档哈希保留历史 | void | 由实现定义 | 要求仅追加语义 |
EvidenceStoreInterface::persistImmutable | EvidencePackage $package | 在后端支持时进行 WORM 写入 | void | 由实现定义 | 非 WORM 后端表现为 store() |
EvidenceStoreInterface::findByDocumentHash | string $documentHash | 该哈希对应的最新包 | ?EvidencePackage | 由实现定义 | |
EvidenceStoreInterface::findAllByDocumentHash | string $documentHash | 该哈希对应的所有包,最新在前 | list<EvidencePackage> | 由实现定义 | |
EvidenceStoreInterface::count | 无 | 已存储包的总数 | int<0, max> | 由实现定义 | |
InMemoryEvidenceStore | 类 | 用于测试与开发的数组存储 | 不适用 | 不适用 | 不具持久性;无 WORM 语义 |
ContinuousMonitor::__construct | EvidenceStoreInterface $store | 装配 store | ContinuousMonitor | 未声明 | |
ContinuousMonitor::check | EvidencePackage $currentEvidence、string $documentHash | 将失败的策略名称与已存储的最新包进行差异比对 | MonitorResult | 未声明 | 首次检查会将每一项当前失败都视为新增 |
ContinuousMonitor::isDue | string $documentHash、MonitorSchedule $schedule | 当不存在先前证据、间隔已过、或已存储证据的日期在未来时,即为到期 | bool | 未声明 | 对时钟偏移采取故障安全策略 |
MonitorResult::__construct | 八个具名参数,见代码块 | 不可变的差异比对结果 | MonitorResult | 未声明 | 同时包含两个包与 checkedAt |
MonitorSchedule::__construct | MonitorFrequency $frequency、int $retentionDays = 90、bool $alertOnNewIssues = true | 配置值对象 | MonitorSchedule | 未声明 | 留存与告警由宿主强制执行 |
MonitorFrequency | 字符串背衬的枚举 | 各成员 Daily、Weekly、Monthly | 不适用 | 不适用 | 背衬值 daily、weekly、monthly |
MonitorFrequency::intervalSeconds | 无 | 各成员的间隔:86400、604800、2592000 | positive-int | 未声明 | Monthly 为固定的 30 天 |
入口点签名
标题为“入口点签名”的章节final class EvidencePortal{ public function __construct( private readonly EvidenceStoreInterface $store, private readonly EvidenceExporter $exporter, )
public function generateEvidence(string $documentHash, array $records, ?string $tsaTimestamp = null): EvidencePackage
public function getEvidence(string $documentHash): ?EvidencePackage
public function getHistory(string $documentHash): array
public function exportAsJson(EvidencePackage $package): string}final readonly class EvidencePackage{ public function __construct( public string $packageId, public string $documentHash, public array $records, public int $totalFindings, public int $passedCount, public int $failedCount, public DateTimeImmutable $generatedAt, public ?string $tsaTimestamp = null, )
public function allPassed(): bool
public function passRate(): float}final readonly class EvidenceRecord{ public function __construct( public string $policyName, public bool $passed, public string $details, public string $validatorVersion, public DateTimeImmutable $timestamp, )}final readonly class EvidenceExporter{ public function toJson(EvidencePackage $package): string
public function exportHash(EvidencePackage $package): string}interface EvidenceStoreInterface{ public function store(EvidencePackage $package): void;
public function persistImmutable(EvidencePackage $package): void;
public function findByDocumentHash(string $documentHash): ?EvidencePackage;
public function findAllByDocumentHash(string $documentHash): array;
public function count(): int;}final class ContinuousMonitor{ public function __construct( private readonly EvidenceStoreInterface $store, )
public function check(EvidencePackage $currentEvidence, string $documentHash): MonitorResult
public function isDue(string $documentHash, MonitorSchedule $schedule): bool}final readonly class MonitorSchedule{ public function __construct( public MonitorFrequency $frequency, public int $retentionDays = 90, public bool $alertOnNewIssues = true, )}
enum MonitorFrequency: string{ case Daily = 'daily'; case Weekly = 'weekly'; case Monthly = 'monthly';
public function intervalSeconds(): int}行为契约
标题为“行为契约”的章节EvidencePortal::generateEvidence(string $documentHash, list<EvidenceRecord> $records, ?string $tsaTimestamp = null): EvidencePackage 是封存的入口点。可从外部观察到的规则如下:
- 组装。
generateEvidence会统计通过与失败的记录,并将totalFindings设为二者之和。它会分配一个全新的版本 4 UUIDpackageId,用挂钟为generatedAt打上时间戳,通过EvidenceStoreInterface::store持久化该包,并返回它。记录列表按给定顺序原样嵌入,不作修改。 - 不可变性。
EvidencePackage是final readonly,构造后绝不会被修改;它适用于 WORM 存储。allPassed()即failedCount === 0。passRate()为passedCount / totalFindings,当totalFindings === 0时为0.0。 - 确定性导出。
EvidenceExporter::toJson以一个固定的、手写的键顺序输出信封与每一条记录;记录顺序跟随包。编码是严格的,失败时抛出异常,斜杠与 Unicode 保持不转义(JSON_UNESCAPED_SLASHES)。时间戳以DateTimeInterface::RFC3339_EXTENDED序列化,即带小数秒的 RFC 3339 扩展形式。exportHash返回恰好针对这些字节计算的 64 字符 SHA-256 十六进制摘要。同一个包在任何主机、任何时间始终产出相同的摘要。为同一文档重新生成证据会产生新的packageId与generatedAt,因而产生新的摘要:确定性是针对每个包的,而非针对每个文档的。 - 时间戳是关于时间的证据,而非一项判定。 一个包可以携带一个可选的、由调用方提供的 RFC 3161 令牌(base64 编码)。该令牌将包的数据绑定到一个时间值。该模块将其作为一个不透明字符串嵌入;它不会获取、解析或验证令牌,也不会为 TSA 担保。令牌验证属于 Signature 与 Security 模块。
- 回归追踪。
ContinuousMonitor::check会加载该文档哈希已存储的最新包,并对唯一的失败策略名称进行差异比对。问题被归类为newIssues(当前失败、此前未失败)、resolvedIssues(此前失败、当前未失败)与unchangedIssues(两次均失败)。仅当存在新增或已解决的问题时hasChanges才为true;仅有未变更的失败会报告为false。在首次检查时,每一项当前失败都是新增的。 - 调度。 当该哈希不存在证据、自已存储的
generatedAt起经过的时间达到调度频率间隔、或已存储证据相对于轮询主机的日期在未来时,ContinuousMonitor::isDue返回true。未来日期的情形是故障安全的:最坏只是多做一次重新检查,绝不会漏掉一次。 - 存储契约。
EvidenceStoreInterface的实现必须支持仅追加语义;每个文档哈希对应的多个包构成历史,最新在前。persistImmutable面向具备 WORM 能力的后端;非 WORM 实现必须表现得与store完全一致。
边界情形与失败模式
标题为“边界情形与失败模式”的章节- 空包会报告
allPassed()为true、passRate()为0.0。在将一个包视为通过之前,请以totalFindings > 0作为判断闸门。 - 直接构造
EvidencePackage不会针对$records校验各计数。请使用门户,或自行保持各计数一致。 generateEvidence会在返回前进行持久化。请在持久化新包之前,用它运行ContinuousMonitor::check;在持久化之后再检查会将该包与其自身比对,从而报告无变更。exportHash覆盖的是确切的toJson字节。由任何其他序列化器、键顺序或转义策略重新计算的摘要都不会匹配。MonitorFrequency::Monthly是一个固定的 30 天窗口,而非一个日历月。MonitorSchedule::$retentionDays与$alertOnNewIssues是为宿主调度器携带的配置。该模块从不删除证据,也从不发送告警。InMemoryEvidenceStore供测试与开发使用。各个包会在进程退出时丢失,且其persistImmutable不具 WORM 语义。- 记录的
details字符串会被原样导出;导出器不作脱敏。请勿将机密与受监管的个人数据放入details。驻留地、留存与访问控制取决于运营方的存储实现。 tsaTimestamp参数被作为一个不透明字符串接受。格式错误的令牌会原样嵌入,仅在下游验证时才会显现。
FIPS 模式行为
标题为“FIPS 模式行为”的章节本模块计算 SHA-256 摘要并嵌入一个由调用方提供的 RFC 3161 令牌。它不执行任何签名,也不进行任何密钥保管。FIPS 模式行为由 Security 与 Signature 模块管辖。
符合性
标题为“符合性”的章节| 声明 | 标准 | 条款 |
|---|---|---|
| 时间戳令牌表明某个数据在某个特定时间点已存在。 | IETF RFC 3161 | §2 |
| 导出的时间戳使用 ISO 8601 的互联网日期/时间剖面,并带小数秒。 | IETF RFC 3339 | §5.6 |
| 嵌入 PDF 内部的验证材料属于 Document Security Store;那一接口面属于 Signature 模块,而非本模块。 | ISO 32000-2:2020 | §12.8.4 |
所有条款均为释义;NextPDF 不复现规范性文本。NextPDF 不作任何认证声明。 证据采集可支撑审计工作流程;它不是一份法律证明,也不是一项审计认证。时间戳令牌仅是关于时间的证据,且本模块不断言任何内容是符合规范的。有效性与符合性仍是最终文件外加一个校验器的属性。本参考不构成法律意见;请咨询你自己的合规与法律顾问。
开发说明
标题为“开发说明”的章节- 模块源码标注
@since 2.2.0;本参考记录的是nextpdf/enterprise3.1.0 中发行的接口面。 - 一切都在你主机上的进程内运行。该模块不执行任何网络 I/O,也从不自行联系 TSA。
- 导出器的数组字面量键顺序在设计上就是关键所在。重新排序会改变
exportHash并使先前存储的摘要失效;源码禁止这样做。 packageId是由\random_bytes(16)输出组装而成的版本 4 UUID;标识符唯一但不可复现。- 持久化存储由宿主提供。WORM 强制与访问控制是运营方的责任;内存存储是唯一随附的实现。
MonitorResult是一个final readonly值对象;它的八个属性均为public,包括checkedAt,即检查的挂钟时间。
发布边界
标题为“发布边界”的章节本页仅记录可从外部观察到的行为与受支持的公共 API 接口面。内部命名空间路径、辅助类、机制表、runbook 文件名与工单前缀均不在范围内。
另请参阅
标题为“另请参阅”的章节- Evidence — 附带工作流程指引的能力页。
- Validation — 深度参考
- Compliance — 深度参考
- AST 审计轨迹 — 深度参考
- 规范:PAdES