Enterprise 版本
Evidence — 深入參考
本頁是 NextPDF\Enterprise\Evidence 模組的深入參考。本模組會把驗證 findings 封緘成一個不可變的 EvidencePackage,以具決定性的 JSON 搭配穩定的 SHA-256 摘要匯出它,透過可插拔的儲存合約持久化它,並以 ContinuousMonitor 追蹤各次執行之間的回歸。本模組會消費由 Validation 與 Compliance 介面產生的 findings;它本身不執行任何一致性檢查。關於工作流程指引,請先閱讀 Evidence 能力頁面。
供應情況與授權
標題為「供應情況與授權」的區段此能力隨 NextPDF Enterprise(nextpdf/enterprise)交付,並以 Enterprise 層級的授權信封啟用。沒有該權益的部署不會載入此能力的類別。比較版本並取得授權。
此介面由 enterprise.compliance.evidence 能力授權;被拒絕的權益會拒絕該功能。Core 與 Pro 會產生 findings 與報告;把 findings 封緘成一個不可變、具決定性、可選擇加上時間戳記、並具備回歸追蹤的封包,沒有 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 | 類別 | 供測試與開發使用、以陣列為底的儲存區 | n/a | n/a | 不耐久;無 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 | 以字串為底的 enum | 案例 Daily、Weekly、Monthly | n/a | n/a | 背後值為 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。首次檢查時,每個當前失敗都是新出現的。 - 排程。
ContinuousMonitor::isDue會在該雜湊沒有任何證據、自已儲存的generatedAt起經過的時間達到排程頻率間隔、或已儲存證據相對於輪詢主機為未來日期時,回傳true。未來日期的情況採容錯安全:最壞只是多做一次重新檢查,絕不會漏掉。 - 儲存合約。
EvidenceStoreInterface的實作必須支援僅可附加的語意;同一文件雜湊的多個封包構成歷史,最新在前。persistImmutable針對支援 WORM 的後端;非 WORM 的實作必須表現得與store完全相同。
邊界案例與失敗模式
標題為「邊界案例與失敗模式」的區段- 空封包會回報
allPassed()為true、passRate()為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引數會以不透明字串接受。格式錯誤的符記會原封不動地嵌入,只有在下游驗證時才會浮現。
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。
- exporter 的陣列字面值鍵順序在設計上具承載作用。重新排序它會改變
exportHash並使先前已儲存的摘要失效;原始碼禁止這麼做。 packageId是由\random_bytes(16)輸出組成的第 4 版 UUID;識別碼是唯一的,但不可重現。- 耐久的持久化由主機提供。WORM 強制與存取控制是操作者的責任;記憶體內儲存區是唯一隨附的實作。
MonitorResult是一個final readonly值物件;它的八個屬性皆為public,包含checkedAt,即該次檢查的掛鐘時間。
發佈邊界
標題為「發佈邊界」的區段本頁僅記載外部可觀察的行為與受支援的公開 API 介面。內部命名空間路徑、輔助類別、機制表格、runbook 檔名與工單前綴皆不在範圍內。
另請參閱
標題為「另請參閱」的區段- Evidence — 附有工作流程指引的能力頁面。
- Validation — 深入參考
- Compliance — 深入參考
- AST 稽核軌跡 — 深入參考
- 規格:PAdES