Add C2PA Monitor experiment#459
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #459 +/- ##
=============================================
+ Coverage 69.07% 70.25% +1.17%
- Complexity 957 1129 +172
=============================================
Files 60 66 +6
Lines 4511 4975 +464
=============================================
+ Hits 3116 3495 +379
- Misses 1395 1480 +85
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
ec97690 to
43d3bde
Compare
… tests - JSON postmeta contract; @see DIF wpai-monitor-record schema - Partial README (postmeta + constraints) Made-with: Cursor
- Format_Detector for JPEG/PNG/WebP C2PA segments - Synthetic fixtures and Format_DetectorTest Made-with: Cursor
- Streaming Manifest_Reader and Sidecar_Writer - README: sidecar layout, rationale, test fixtures Made-with: Cursor
- capture_for_attachment, sidecar, Record persistence - C2pa_MonitorTest; README: full flow, DIF schema cross-links, out of scope Made-with: Cursor
Made-with: Cursor
1e33baa to
8257f84
Compare
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Unlinked AccountsThe following contributors have not linked their GitHub and WordPress.org accounts: @lnispel. Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases. If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Synthetic fixtures are not valid renderable images. GD's WebP codec fatals when create_upload_object triggers wp_generate_attachment_metadata. Suppress intermediate_image_sizes_advanced in setUp/tearDown so GD is never invoked on fixture bytes. Made-with: Cursor
Read-only feature that detects [C2PA Content Credentials](https://c2pa.org/) in uploaded JPEG/PNG/WebP images at the
add_attachmenthook, captures the raw manifest store to a sidecar file underwp-content/uploads/ai-c2pa/, and persists a structured_wpai_monitor_recordpostmeta entry for downstream consumers.What?
Closes
Adds a new
C2pa_Monitorexperiment that:caBX, WebP RIFFC2PA. Hard byte caps throughout.c2pa/jumbtoken in their first 64 bytes.uploads/ai-c2pa/<attachment_id>.<format>.c2pa, hashing in flight (SHA-256). Postmeta stores the hash, length, and relative sidecar path — not the bytes themselves..htaccess(Apache deny) andindex.phphardening. nginx operators must add a deny rule manually (documented in the experiment README).try / catch ( Throwable )boundary: errors land in the record'serrors[]array and the upload itself is never blocked.Why?
C2PA Content Credentials are increasingly embedded in images uploaded to WordPress sites (camera firmware, AI image generators, editorial signing tools), but WordPress's image processing pipeline destroys them — APP11 segments don't survive GD/Imagick re-encoding. Capturing the manifest at
add_attachment, before subsize generation, is the only point in the WordPress lifecycle where the original bytes are still intact.This PR establishes that capture as read-only infrastructure: nothing user-facing changes, but the manifest data becomes available to downstream consumers (admin UI, REST endpoints, verification tooling) without each of them having to re-parse containers.
How?
Implementation lives entirely under
includes/Experiments/C2pa_Monitor/with one entry point:C2pa_Monitor::capture_for_attachment()is hooked toadd_attachmentat priority 20, gated by MIME onimage/jpeg,image/png, andimage/webp.Format_Detectorwalks containers and returns a location descriptor (segments + total length) without reading payload bytes.Manifest_Readerconsumes that descriptor, streams the bytes viafreadinto a hash context and an in-memory buffer, and produces an immutableRaw_Manifestvalue object.Sidecar_Writerpersists the bytes, ensuring the directory and hardening files exist exactly once.Recordnormalizes the structured payload and persists it as JSON-encoded postmeta at_wpai_monitor_record.Reviewing this PR. The diff is large but cleanly partitioned. The work was developed in five layers and the integration branch's commits are organized that way:
Raw_Manifest,Record, tests).Format_Detector, fixtures, tests).Manifest_Reader,Sidecar_Writer, tests).register()body,capture_for_attachment, end-to-end tests).Each layer is independently coherent if you'd rather review incrementally; otherwise, the integrated diff stands on its own.
Use of AI Tools
AI assistance: Yes
Tool(s): Cursor, Claude
Model(s):
Used for: Architecture and PR-segmentation planning, initial code drafts, test scaffolding. Final implementation, all design decisions, and the byte-level format work were reviewed and edited by me.
Testing Instructions
c2patoolcan also generate test files)._wpai_monitor_record— it should be JSON withc2pa.present: true, a SHA-256 hash, and asidecar_path_relativevalue.wp-content/uploads/ai-c2pa/<attachment_id>.jpeg.c2paand that its bytes matchmanifest_sha256.c2pa.present: falseand no sidecar should be written..txtfile) — no postmeta should be written at all.Automated coverage:
Format_Detector: magic bytes, single-segment APP11, multi-segment reassembly, interleaved APP0/APP1/APP2 around C2PA, generic JUMBF (non-C2PA) ignored, truncated input,JPEG_MAX_SEGMENTScap (positive and negative), PNG/caBX, WebP simple + extended (VP8X) + odd-length padding.Manifest_Reader: byte-exact roundtrip for JPEG/PNG/WebP, multi-segment reassembly, deterministic SHA-256,MAX_MANIFEST_BYTESrejection, missing file, empty segments, bad offsets.Sidecar_Writer: write + roundtrip, hardening files, format sanitization, overwrite, multi-attachment coexistence, custom.htaccesspreserved acrossensure_dir().Record: roundtrip, defaults on empty input, JSON-not-serialize storage format, null on corrupt JSON, null when absent.C2pa_Monitorend-to-end: JPEG/PNG/WebP present, JPEG absent, unsupported MIME, fail-open on bogus ID, truncated JPEG,duration_msrecorded,add_attachmenthook actually fires, file-deleted-on-disk produceserrors[0].stage = 'resolve_path'.Synthetic fixtures are generated at runtime so no binary blobs land in the repo and there is no third-party fixture licensing question.
Deferred (out of scope for this PR)
c2pa.decodedclaim summary (claim generator, digital source type, action history).Screenshots or screencast
No UI changes in this PR.
Changelog Entry