跳到內容
getnextpdf.com

Enterprise 版本

Evidence — 深入參考

本頁是 NextPDF\Enterprise\Evidence 模組的深入參考。本模組會把驗證 findings 封緘成一個不可變的 EvidencePackage,以具決定性的 JSON 搭配穩定的 SHA-256 摘要匯出它,透過可插拔的儲存合約持久化它,並以 ContinuousMonitor 追蹤各次執行之間的回歸。本模組會消費由 Validation 與 Compliance 介面產生的 findings;它本身不執行任何一致性檢查。關於工作流程指引,請先閱讀 Evidence 能力頁面

此能力隨 NextPDF Enterprisenextpdf/enterprise)交付,並以 Enterprise 層級的授權信封啟用。沒有該權益的部署不會載入此能力的類別。比較版本並取得授權

此介面由 enterprise.compliance.evidence 能力授權;被拒絕的權益會拒絕該功能。Core 與 Pro 會產生 findings 與報告;把 findings 封緘成一個不可變、具決定性、可選擇加上時間戳記、並具備回歸追蹤的封包,沒有 Core 層級或 Pro 層級的對應物。

Terminal window
composer require nextpdf/enterprise:^3
符號參數預設行為回傳拋出或失敗於備註
EvidencePortal::__constructEvidenceStoreInterface $store, EvidenceExporter $exporter串接 store 與 exporterEvidencePortal未宣告任何項目兩個協作者皆可注入
EvidencePortal::generateEvidencestring $documentHash, list<EvidenceRecord> $records, ?string $tsaTimestamp = null計算通過/失敗數量,以全新 UUID id 與掛鐘時間 generatedAt 封緘一個封包,並持久化它EvidencePackage未宣告任何項目透過 store() 持久化,而非 persistImmutable()
EvidencePortal::getEvidencestring $documentHash該雜湊最新已儲存的封包?EvidencePackage未宣告任何項目未儲存時為 null
EvidencePortal::getHistorystring $documentHash完整歷史,最新在前list<EvidencePackage>未宣告任何項目排序由 store 提供
EvidencePortal::exportAsJsonEvidencePackage $package委派給 exporternon-empty-stringJsonExceptionEvidenceExporter::toJson 位元組相同
EvidencePackage::__construct八個具名參數,見程式碼區塊不可變的值物件EvidencePackage未宣告任何項目計數不會對 $records 進行驗證
EvidencePackage::allPassedfailedCount === 0bool未宣告任何項目空封包為 true;請以 totalFindings 為閘
EvidencePackage::passRatepassedCount / totalFindingsfloat未宣告任何項目totalFindings === 0 時為 0.0
EvidenceRecord::__constructstring $policyName, bool $passed, string $details, string $validatorVersion, DateTimeImmutable $timestamp不可變的單一原則檢查結果EvidenceRecord未宣告任何項目所有屬性皆為 public readonly
EvidenceExporter::toJsonEvidencePackage $package固定鍵順序的 JSON;斜線與 Unicode 未跳脫non-empty-stringJsonException鍵順序具承載作用
EvidenceExporter::exportHashEvidencePackage $packagetoJson() 位元組取 SHA-256non-empty-string(64 位十六進位)JsonException每個封包穩定
EvidenceStoreInterface::storeEvidencePackage $package附加;允許每個文件雜湊保留歷史void由實作定義要求僅可附加語意
EvidenceStoreInterface::persistImmutableEvidencePackage $package在後端支援時進行 WORM 寫入void由實作定義非 WORM 後端的行為等同 store()
EvidenceStoreInterface::findByDocumentHashstring $documentHash該雜湊最近的封包?EvidencePackage由實作定義
EvidenceStoreInterface::findAllByDocumentHashstring $documentHash該雜湊的所有封包,最新在前list<EvidencePackage>由實作定義
EvidenceStoreInterface::count已儲存封包的總數int<0, max>由實作定義
InMemoryEvidenceStore類別供測試與開發使用、以陣列為底的儲存區n/an/a不耐久;無 WORM 語意
ContinuousMonitor::__constructEvidenceStoreInterface $store串接 storeContinuousMonitor未宣告任何項目
ContinuousMonitor::checkEvidencePackage $currentEvidence, string $documentHash將失敗的原則名稱與已儲存的最新封包做差異比對MonitorResult未宣告任何項目首次檢查會把每個當前失敗都視為新出現
ContinuousMonitor::isDuestring $documentHash, MonitorSchedule $schedule在沒有先前證據、間隔已過、或已儲存證據為未來日期時到期bool未宣告任何項目對時鐘偏移採容錯安全
MonitorResult::__construct八個具名參數,見程式碼區塊不可變的差異結果MonitorResult未宣告任何項目同時包含兩個封包與 checkedAt
MonitorSchedule::__constructMonitorFrequency $frequency, int $retentionDays = 90, bool $alertOnNewIssues = true設定用的值物件MonitorSchedule未宣告任何項目保留與警示由主機強制執行
MonitorFrequency以字串為底的 enum案例 DailyWeeklyMonthlyn/an/a背後值為 dailyweeklymonthly
MonitorFrequency::intervalSeconds各案例的間隔:86400、604800、2592000positive-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 是封緘的入口點。外部可觀察的規則如下:

  1. 組裝。generateEvidence 會計算通過與失敗的記錄,並將 totalFindings 設為兩者之和。它會指派一個全新的第 4 版 UUID packageId,以掛鐘時間標記 generatedAt,透過 EvidenceStoreInterface::store 持久化該封包,並回傳它。記錄清單會依給定順序原封不動地嵌入。
  2. 不可變性。EvidencePackagefinal readonly,建構後絕不變動;它適合 WORM 儲存。allPassed()failedCount === 0passRate()passedCount / totalFindings,而當 totalFindings === 0 時為 0.0
  3. 決定性匯出。EvidenceExporter::toJson 會以固定、手寫的鍵順序輸出信封與每筆記錄;記錄序列跟隨封包。編碼嚴格,失敗時會拋出例外,斜線與 Unicode 保持未跳脫(JSON_UNESCAPED_SLASHES)。時間戳記以 DateTimeInterface::RFC3339_EXTENDED 序列化,即帶有小數秒的 RFC 3339 擴充形式。exportHash 會回傳對那些位元組精確計算的 64 字元 SHA-256 十六進位摘要。同一個封包在任何主機、任何時間都產生相同的摘要。為同一份文件重新產生證據會得到新的 packageIdgeneratedAt,因而是新的摘要:決定性是以封包為單位,而非以文件為單位。
  4. **時間戳記是時間的證據,不是判定。**封包可帶有一個可選、由呼叫端提供的 RFC 3161 符記(base64 編碼)。該符記把封包資料綁定到一個時間值。本模組會將它以不透明字串嵌入;它不會擷取、剖析或驗證符記,也不為該 TSA 背書。符記驗證屬於 Signature 與 Security 模組。
  5. 回歸追蹤。ContinuousMonitor::check 會載入該文件雜湊已儲存的最新封包,並比對唯一的失敗原則名稱之差異。問題會分類為 newIssues(現在失敗、先前未失敗)、resolvedIssues(先前失敗、現在未失敗)與 unchangedIssues(兩次皆失敗)。只有在存在新出現或已解決的問題時,hasChanges 才為 true;僅有未變動的失敗會回報 false。首次檢查時,每個當前失敗都是新出現的。
  6. 排程。ContinuousMonitor::isDue 會在該雜湊沒有任何證據、自已儲存的 generatedAt 起經過的時間達到排程頻率間隔、或已儲存證據相對於輪詢主機為未來日期時,回傳 true。未來日期的情況採容錯安全:最壞只是多做一次重新檢查,絕不會漏掉。
  7. 儲存合約。EvidenceStoreInterface 的實作必須支援僅可附加的語意;同一文件雜湊的多個封包構成歷史,最新在前。persistImmutable 針對支援 WORM 的後端;非 WORM 的實作必須表現得與 store 完全相同。
  • 空封包會回報 allPassed()truepassRate()0.0。在把封包視為通過之前,請以 totalFindings > 0 為閘。
  • 直接建構 EvidencePackage 不會對 $records 驗證計數。請使用 portal,或自行維持計數一致。
  • generateEvidence 會在回傳前先持久化。請在持久化新封包之前先以它執行 ContinuousMonitor::check;在持久化之後才檢查,會把封包與它自身做差異比對而回報沒有變更。
  • exportHash 涵蓋的是精確的 toJson 位元組。任何其他序列化器、鍵順序或跳脫策略重新計算出的摘要都不會相符。
  • MonitorFrequency::Monthly 是固定的 30 天窗口,而非日曆月。
  • MonitorSchedule::$retentionDays$alertOnNewIssues 是為主機排程器攜帶的設定。本模組絕不刪除證據,也絕不發送警示。
  • InMemoryEvidenceStore 供測試與開發使用。封包會在行程結束時遺失,其 persistImmutable 沒有 WORM 語意。
  • 記錄的 details 字串會逐字匯出;exporter 不會遮蔽。請勿在 details 中放入機密與受監管的個人資料。資料落地、保留與存取控制遵循操作者的儲存區實作。
  • tsaTimestamp 引數會以不透明字串接受。格式錯誤的符記會原封不動地嵌入,只有在下游驗證時才會浮現。

本模組計算 SHA-256 摘要,並嵌入呼叫端提供的 RFC 3161 符記。它不執行任何簽署,也不進行任何金鑰保管。FIPS 模式行為由 SecuritySignature 模組掌管。

主張標準條款
時間戳記符記表明某筆資料在特定時間點已存在。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/enterprise 3.1.0 所交付的介面。
  • 一切都在你主機的行程內執行。本模組不進行任何網路 I/O,也絕不自行連絡 TSA。
  • exporter 的陣列字面值鍵順序在設計上具承載作用。重新排序它會改變 exportHash 並使先前已儲存的摘要失效;原始碼禁止這麼做。
  • packageId 是由 \random_bytes(16) 輸出組成的第 4 版 UUID;識別碼是唯一的,但不可重現。
  • 耐久的持久化由主機提供。WORM 強制與存取控制是操作者的責任;記憶體內儲存區是唯一隨附的實作。
  • MonitorResult 是一個 final readonly 值物件;它的八個屬性皆為 public,包含 checkedAt,即該次檢查的掛鐘時間。

本頁僅記載外部可觀察的行為與受支援的公開 API 介面。內部命名空間路徑、輔助類別、機制表格、runbook 檔名與工單前綴皆不在範圍內。