c2pa-check 0.1.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,10 +26,43 @@ c2pa-check photo.jpg --format json | jq .result.credential.status
26
26
  c2pa-check inspect photo.jpg # manifest tree
27
27
  c2pa-check trust status # which list judged it
28
28
  c2pa-check mcp # stdio MCP server
29
+ c2pa-check 'dist/**/*.jpg' --format junit --output c2pa-check.xml # report to a file
30
+ c2pa-check doctor # key, quota, network, webhook secret, Node
29
31
  ```
30
32
 
31
- Exit codes: `0` pass · `1` expectation or coverage failed · `2` usage · `3` unreadable asset ·
32
- `4` network.
33
+ `--format text|json|ndjson|junit` (default `text`) and `--output PATH` (default: stdout) apply
34
+ to the check command. JUnit marks every target that is not `valid_trusted` as a failure.
35
+
36
+ | Exit | Meaning |
37
+ |---|---|
38
+ | `0` | pass |
39
+ | `1` | expectation or coverage failed · `doctor` found a failing check · `carry --strict` found an unpaired file |
40
+ | `2` | usage or I/O error |
41
+ | `3` | unreadable asset (missing or unreadable local file, over 64 MiB, malformed manifest) |
42
+ | `4` | a URL could not be fetched |
43
+ | `5` | `carry` refused (rule in `--json`) |
44
+
45
+ ## Check your setup
46
+
47
+ ```console
48
+ $ npx -y c2pa-check doctor
49
+ ok api_key live key c2pa_live_AbC…
50
+ ok network https://api.c2pa.design/v1 answered HTTP 200
51
+ ok whoami live key, organization Acme, plan team, signatures 940 of 1000 left until 2026-11-01
52
+ ok webhook_secret valid (whsec_ + base64)
53
+ ok node Node.js 22.11.0
54
+ ```
55
+
56
+ | Check | Reads | Fails when |
57
+ |---|---|---|
58
+ | `api_key` | `C2PA_API_KEY` (deprecated fallback `C2PA_DESIGN_API_KEY`) | not `c2pa_live_` / `c2pa_test_` + 32 letters and digits (unset is a warning) |
59
+ | `network` | `C2PA_API_BASE` (deprecated fallback `C2PA_DESIGN_API_URL`, default `https://api.c2pa.design/v1`) | no HTTP answer |
60
+ | `whoami` | `GET {C2PA_API_BASE}/whoami` | the key is refused; an exhausted quota is a warning |
61
+ | `webhook_secret` | `C2PA_WEBHOOK_SECRET` | not `whsec_` + standard base64 (unset is skipped) |
62
+ | `node` | the Node.js running `npx` | older than 18 |
63
+
64
+ `doctor --json` prints `{ok, api_base, checks: [{name, state, detail, data?}]}` with `state`
65
+ `ok | warn | fail | skip`; the `whoami` check carries the API answer in `data`.
33
66
 
34
67
  ## In CI
35
68
 
@@ -39,8 +72,21 @@ Exit codes: `0` pass · `1` expectation or coverage failed · `2` usage · `3` u
39
72
  paths: "public/**/*.{jpg,png,webp}"
40
73
  coverage: 100
41
74
  format: junit
75
+ output: c2pa-check.xml
42
76
  ```
43
77
 
78
+ The action installs the release named by `version` (default `v0.2.0`) and checks it against the
79
+ release's `SHA256SUMS` before running it. Every release publishes `SHA256SUMS` and a GitHub
80
+ build-provenance attestation (`gh attestation verify c2pa-check-<target>.tar.gz -R
81
+ c2pa-design/c2pa-check`); the npm packages are published with npm provenance
82
+ (`npm audit signatures`).
83
+
84
+ Outside GitHub Actions, any image with Node.js 18+ runs `npx -y c2pa-check@0.2.0`
85
+ (`node:22-bookworm-slim` is the smallest that also has the glibc tools most pipelines expect;
86
+ the binary itself is static musl, so `node:22-alpine` works too). Pin the version so `npx` hits
87
+ its cache instead of resolving `latest` on every run, and cache `~/.npm` between jobs; or skip
88
+ Node entirely and download the static binary from the release.
89
+
44
90
  Add `urls:` to check what your CDN actually serves after a deploy — that is where credentials
45
91
  usually disappear.
46
92
 
@@ -56,19 +102,50 @@ npx -y c2pa-check carry --from hero.png --to hero.webp # one pair, in
56
102
  npx -y c2pa-check carry 'public/**/*.{webp,avif}' --from-dir src/ # pairs by file name
57
103
  c2pa-check carry --from clip.mov --to clip.mp4 --force # non-picture media
58
104
  c2pa-check keygen --out-dir .c2pa # cert.pem + key.pem for CI
105
+ c2pa-check carry --from hero.png --to hero.webp --json # machine-readable result
59
106
  ```
60
107
 
61
108
  | Signer (first that is set) | Signed as | Verifies as |
62
109
  |---|---|---|
63
110
  | `C2PA_SIGN_CERT` + `C2PA_SIGN_KEY` (PEM, a path, or `*_FILE`) | your certificate | `valid_trusted` if your CA is on the C2PA trust list |
64
- | `C2PA_DESIGN_API_KEY` (or `C2PA_API_KEY`) | "<your verified domain> via c2pa.design" | `valid_untrusted` |
111
+ | `C2PA_API_KEY` (deprecated fallback `C2PA_DESIGN_API_KEY`) | "<your verified domain> via c2pa.design" | `valid_untrusted` |
65
112
  | nothing | a local key in `~/.config/c2pa-check/identity` | `valid_untrusted` |
66
113
 
67
- Pictures are compared first (PDQ distance ≤ 31); a different picture or an original without a
68
- credential is refused with exit `1`. With an API key, c2pa.design checks the carry again and
114
+ Pictures are compared first by perceptual hash; a different picture or an original without a
115
+ credential is refused with exit `5`. With an API key, c2pa.design checks the carry again and
69
116
  signs only an honest one; if hosted signing is unavailable, `carry` signs locally and warns.
70
117
  Never `COPY` or `ARG` a key into a Docker image: use `RUN --mount=type=secret`.
71
118
 
119
+ `carry --json` prints one object (an array for several files):
120
+
121
+ ```json
122
+ {"status": "refused", "rule": "different_picture", "message": "the two files are not the same picture",
123
+ "source": "hero.png", "derived": "hero.webp"}
124
+ ```
125
+
126
+ `status` is `carried | composed | skipped | refused | error | unpaired | ambiguous`; `output`
127
+ is the file written; `credential_status` is how the written file verifies. `rule` is set on a
128
+ refusal: `different_picture`, `source_unsigned`, `low_quality`, `not_comparable`, or the rule
129
+ c2pa.design returned with `carry_rejected` (`source_invalid`, `ingredient_mismatch`,
130
+ `action_not_allowed`, `generator_changed`, `certificate_mismatch`, …). Refusals exit `5`.
131
+
132
+ ### Composites and generated assets
133
+
134
+ An atlas, sprite sheet or collage is a new work, not a conversion. `--compose` signs the
135
+ rendered file with every source attached as a `componentOf` ingredient (each keeps its own
136
+ manifest) and a `c2pa.created` action (digital source type `composite`), plus `c2pa.placed`
137
+ per source:
138
+
139
+ ```bash
140
+ c2pa-check carry --compose a.png b.png c.png --to atlas.webp
141
+ c2pa-check carry --compose base.png logo.png --to banner.webp --edited # base.png is parentOf
142
+ ```
143
+
144
+ `--edited` records `c2pa.opened` on the first source (as `parentOf`), `c2pa.edited`, and
145
+ `c2pa.placed` for the rest. Composites are signed with `C2PA_SIGN_CERT` / `C2PA_SIGN_KEY` or
146
+ the local key; hosted signing does not accept composites yet, so with only an API key the
147
+ composite is signed locally and `carry` warns.
148
+
72
149
  ## For AI agents
73
150
 
74
151
  The agent skill lives in [c2pa-design/skills](https://github.com/c2pa-design/skills):
@@ -77,7 +154,8 @@ The agent skill lives in [c2pa-design/skills](https://github.com/c2pa-design/ski
77
154
  npx skills add c2pa-design/skills
78
155
  ```
79
156
 
80
- MCP only: `claude mcp add c2pa-check -- npx -y c2pa-check mcp`.
157
+ MCP only: `claude mcp add c2pa-check -- npx -y c2pa-check mcp`. `initialize` echoes the client's
158
+ `protocolVersion` when supported (`2026-07-28`, `2025-11-25`, `2025-06-18`, `2025-03-26`), else `2026-07-28`.
81
159
 
82
160
  ## How trust works
83
161
 
package/bin/c2pa-check.js CHANGED
@@ -10,6 +10,6 @@ try {
10
10
  console.error(`c2pa-check: no prebuilt binary for ${process.platform}-${process.arch}; use cargo install c2pa-check`);
11
11
  process.exit(2);
12
12
  }
13
- const r = spawnSync(bin, process.argv.slice(2), { stdio: "inherit" });
13
+ const r = spawnSync(bin, process.argv.slice(2), { stdio: "inherit", env: { ...process.env, C2PA_CHECK_NODE_VERSION: process.versions.node } });
14
14
  if (r.error) throw r.error;
15
15
  process.exit(r.status ?? 1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c2pa-check",
3
- "version": "0.1.6",
3
+ "version": "0.2.0",
4
4
  "license": "MIT OR Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -18,9 +18,9 @@
18
18
  "node": ">=18"
19
19
  },
20
20
  "optionalDependencies": {
21
- "c2pa-check-linux-x64": "0.1.6",
22
- "c2pa-check-linux-arm64": "0.1.6",
23
- "c2pa-check-darwin-arm64": "0.1.6",
24
- "c2pa-check-darwin-x64": "0.1.6"
21
+ "c2pa-check-linux-x64": "0.2.0",
22
+ "c2pa-check-linux-arm64": "0.2.0",
23
+ "c2pa-check-darwin-arm64": "0.2.0",
24
+ "c2pa-check-darwin-x64": "0.2.0"
25
25
  }
26
26
  }