@certrev/cert-block 0.5.5 → 1.0.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/CHANGELOG.md +164 -26
- package/LICENSE +21 -0
- package/README.md +415 -54
- package/dist/builder/cert-chrome-data.d.ts +26 -8
- package/dist/builder/cert-chrome-data.d.ts.map +1 -1
- package/dist/builder/cert-chrome-data.js +5 -5
- package/dist/builder/cert-chrome-data.js.map +1 -1
- package/dist/builder/cert-review-card.d.ts +35 -5
- package/dist/builder/cert-review-card.d.ts.map +1 -1
- package/dist/builder/cert-review-card.js +115 -34
- package/dist/builder/cert-review-card.js.map +1 -1
- package/dist/builder/index.d.ts +33 -16
- package/dist/builder/index.d.ts.map +1 -1
- package/dist/builder/index.js +33 -16
- package/dist/builder/index.js.map +1 -1
- package/dist/components/CertBadge.d.ts +2 -2
- package/dist/components/CertBadge.d.ts.map +1 -1
- package/dist/components/CertBadge.js +11 -5
- package/dist/components/CertBadge.js.map +1 -1
- package/dist/components/CertJsonLd.d.ts.map +1 -1
- package/dist/components/CertJsonLd.js.map +1 -1
- package/dist/components/CertRevBacklink.d.ts.map +1 -1
- package/dist/components/CertRevBacklink.js +3 -2
- package/dist/components/CertRevBacklink.js.map +1 -1
- package/dist/components/CertReview.d.ts +1 -1
- package/dist/components/ExpertBio.d.ts.map +1 -1
- package/dist/components/ExpertBio.js +12 -4
- package/dist/components/ExpertBio.js.map +1 -1
- package/dist/components/escape.d.ts +28 -1
- package/dist/components/escape.d.ts.map +1 -1
- package/dist/components/escape.js +37 -8
- package/dist/components/escape.js.map +1 -1
- package/dist/components/format.d.ts +51 -2
- package/dist/components/format.d.ts.map +1 -1
- package/dist/components/format.js +103 -6
- package/dist/components/format.js.map +1 -1
- package/dist/components/preview-block.d.ts +1 -1
- package/dist/components/preview-block.js +3 -3
- package/dist/components/preview-block.js.map +1 -1
- package/dist/components/rel.d.ts +24 -0
- package/dist/components/rel.d.ts.map +1 -0
- package/dist/components/rel.js +24 -0
- package/dist/components/rel.js.map +1 -0
- package/dist/components/render-cert-block.d.ts +50 -22
- package/dist/components/render-cert-block.d.ts.map +1 -1
- package/dist/components/render-cert-block.js +146 -80
- package/dist/components/render-cert-block.js.map +1 -1
- package/dist/components/render-def.d.ts +13 -14
- package/dist/components/render-def.d.ts.map +1 -1
- package/dist/components/render-def.js +14 -15
- package/dist/components/render-def.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/jsonld/project.d.ts +46 -13
- package/dist/jsonld/project.d.ts.map +1 -1
- package/dist/jsonld/project.js +139 -56
- package/dist/jsonld/project.js.map +1 -1
- package/dist/modal/avatar-resize.d.ts +10 -10
- package/dist/modal/avatar-resize.js +14 -14
- package/dist/modal/avatar-resize.js.map +1 -1
- package/dist/modal/cert-modal-view.d.ts +27 -7
- package/dist/modal/cert-modal-view.d.ts.map +1 -1
- package/dist/modal/cert-modal-view.js +49 -25
- package/dist/modal/cert-modal-view.js.map +1 -1
- package/dist/modal/certrev-cert-modal.d.ts +5 -5
- package/dist/modal/certrev-cert-modal.js +9 -9
- package/dist/modal/certrev-cert-modal.js.map +1 -1
- package/dist/modal/certrev-cert-modal.styles.d.ts +6 -6
- package/dist/modal/certrev-cert-modal.styles.d.ts.map +1 -1
- package/dist/modal/certrev-cert-modal.styles.js +8 -8
- package/dist/modal/certrev-cert-modal.styles.js.map +1 -1
- package/dist/modal/certrev-cert.entry.d.ts +8 -6
- package/dist/modal/certrev-cert.entry.d.ts.map +1 -1
- package/dist/modal/certrev-cert.entry.js +9 -7
- package/dist/modal/certrev-cert.entry.js.map +1 -1
- package/dist/modal/certrev-cert.js +6 -6
- package/dist/modal/display-strings.d.ts +25 -5
- package/dist/modal/display-strings.d.ts.map +1 -1
- package/dist/modal/display-strings.js +27 -5
- package/dist/modal/display-strings.js.map +1 -1
- package/dist/modal/escape.d.ts +26 -3
- package/dist/modal/escape.d.ts.map +1 -1
- package/dist/modal/escape.js +32 -3
- package/dist/modal/escape.js.map +1 -1
- package/dist/modal/font-face.d.ts.map +1 -1
- package/dist/modal/font-face.js +8 -11
- package/dist/modal/font-face.js.map +1 -1
- package/dist/modal/ftc-disclosure.d.ts +2 -2
- package/dist/modal/ftc-disclosure.js +2 -2
- package/dist/modal/ftc-guard.d.ts +44 -9
- package/dist/modal/ftc-guard.d.ts.map +1 -1
- package/dist/modal/ftc-guard.js +50 -17
- package/dist/modal/ftc-guard.js.map +1 -1
- package/dist/modal/index.d.ts +1 -1
- package/dist/modal/index.js +1 -1
- package/dist/modal/interactions.d.ts +2 -2
- package/dist/modal/interactions.js +2 -2
- package/dist/modal/logo-paths.js +2 -2
- package/dist/modal/logo-paths.js.map +1 -1
- package/dist/modal/placement.d.ts +4 -3
- package/dist/modal/placement.d.ts.map +1 -1
- package/dist/modal/placement.js +7 -6
- package/dist/modal/placement.js.map +1 -1
- package/dist/modal/revalidate.d.ts +2 -3
- package/dist/modal/revalidate.d.ts.map +1 -1
- package/dist/modal/revalidate.js +2 -3
- package/dist/modal/revalidate.js.map +1 -1
- package/dist/modal/verify-client.d.ts +2 -2
- package/dist/modal/verify-client.js +2 -2
- package/dist/verify/cache.d.ts +21 -6
- package/dist/verify/cache.d.ts.map +1 -1
- package/dist/verify/cache.js +29 -8
- package/dist/verify/cache.js.map +1 -1
- package/dist/verify/fetch-with-deadline.d.ts +35 -0
- package/dist/verify/fetch-with-deadline.d.ts.map +1 -0
- package/dist/verify/fetch-with-deadline.js +55 -0
- package/dist/verify/fetch-with-deadline.js.map +1 -0
- package/dist/verify/get-verified-envelope.d.ts +23 -9
- package/dist/verify/get-verified-envelope.d.ts.map +1 -1
- package/dist/verify/get-verified-envelope.js +89 -40
- package/dist/verify/get-verified-envelope.js.map +1 -1
- package/dist/verify/resolve-kid.d.ts +3 -0
- package/dist/verify/resolve-kid.d.ts.map +1 -1
- package/dist/verify/resolve-kid.js +17 -8
- package/dist/verify/resolve-kid.js.map +1 -1
- package/dist/webcomponent/certrev-badge.d.ts.map +1 -1
- package/dist/webcomponent/certrev-badge.js +24 -2
- package/dist/webcomponent/certrev-badge.js.map +1 -1
- package/dist/webcomponent/render-badge-html.d.ts +1 -1
- package/dist/webcomponent/render-badge-html.d.ts.map +1 -1
- package/dist/webcomponent/render-badge-html.js +36 -17
- package/dist/webcomponent/render-badge-html.js.map +1 -1
- package/package.json +5 -2
- package/src/builder/cert-chrome-data.ts +26 -8
- package/src/builder/cert-review-card.tsx +147 -38
- package/src/builder/index.tsx +34 -17
- package/src/components/CertBadge.tsx +14 -9
- package/src/components/CertJsonLd.tsx +1 -1
- package/src/components/CertRevBacklink.tsx +10 -3
- package/src/components/CertReview.tsx +1 -1
- package/src/components/ExpertBio.tsx +12 -7
- package/src/components/escape.ts +37 -7
- package/src/components/format.ts +102 -6
- package/src/components/preview-block.ts +3 -3
- package/src/components/rel.ts +23 -0
- package/src/components/render-cert-block.ts +192 -109
- package/src/components/render-def.ts +14 -15
- package/src/index.ts +4 -2
- package/src/jsonld/project.ts +155 -59
- package/src/modal/avatar-resize.ts +14 -14
- package/src/modal/cert-modal-view.ts +52 -27
- package/src/modal/certrev-cert-modal.styles.ts +8 -8
- package/src/modal/certrev-cert-modal.ts +9 -9
- package/src/modal/certrev-cert.entry.ts +9 -7
- package/src/modal/display-strings.ts +26 -5
- package/src/modal/escape.ts +32 -4
- package/src/modal/font-face.ts +8 -11
- package/src/modal/ftc-disclosure.ts +2 -2
- package/src/modal/ftc-guard.ts +73 -18
- package/src/modal/index.ts +1 -1
- package/src/modal/interactions.ts +2 -2
- package/src/modal/logo-paths.ts +2 -2
- package/src/modal/placement.ts +7 -6
- package/src/modal/revalidate.ts +2 -3
- package/src/modal/verify-client.ts +2 -2
- package/src/verify/cache.ts +34 -8
- package/src/verify/fetch-with-deadline.ts +60 -0
- package/src/verify/get-verified-envelope.ts +131 -48
- package/src/verify/resolve-kid.ts +22 -6
- package/src/webcomponent/certrev-badge.ts +24 -2
- package/src/webcomponent/render-badge-html.ts +66 -19
- package/src/__tests__/__snapshots__/render-cert-block.test.ts.snap +0 -17
- package/src/__tests__/components.test.tsx +0 -206
- package/src/__tests__/preview-block.test.ts +0 -84
- package/src/__tests__/project.test.ts +0 -128
- package/src/__tests__/readme-version.test.ts +0 -51
- package/src/__tests__/render-cert-block.test.ts +0 -657
- package/src/__tests__/render-def.test.tsx +0 -295
- package/src/__tests__/verify.test.ts +0 -239
- package/src/__tests__/webcomponent.test.tsx +0 -116
- package/src/builder/__tests__/builder.test.tsx +0 -158
- package/src/modal/cert-modal-view.test.ts +0 -175
- package/src/modal/certrev-cert-modal.test.ts +0 -125
- package/src/modal/ftc-guard.test.ts +0 -153
- package/src/modal/interactions.test.ts +0 -250
- package/src/modal/placement.test.ts +0 -398
- package/src/modal/revalidate.test.ts +0 -111
- package/src/modal/verify-client.test.ts +0 -164
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
/**
|
|
3
|
-
* Unit tests for the Shopify cert-badge Web-Component revalidation DOM layer — the fail-closed
|
|
4
|
-
* (suppress → hide) / fail-open (404|offline → keep SSR) behavior, driven with a mocked verdict
|
|
5
|
-
* (no network), plus the key-sync cross-check guarding the browser-bundled public key against
|
|
6
|
-
* signer.ts drift.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type { CertVerdict } from "@certrev/cert-contract";
|
|
10
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
11
|
-
import { type RevalidateDeps, revalidateBadge } from "./revalidate.js";
|
|
12
|
-
|
|
13
|
-
// NOTE (POR-10721 W2): the "published key sync" cross-check that lived here — asserting the
|
|
14
|
-
// browser-bundled `CERT_ISSUER_*` (certrev-cert.entry.ts) equals portal's signer
|
|
15
|
-
// `CERT_ENVELOPE_*` — is a CROSS-REPO guard and cannot run in this package (there is no portal
|
|
16
|
-
// signer to compare against). It stays a PORTAL-side test: once portal re-points at the published
|
|
17
|
-
// package, portal asserts `@certrev/cert-block/modal`'s exported CERT_ISSUER_* == its own
|
|
18
|
-
// signer's CERT_ENVELOPE_*. The package exports CERT_ISSUER_* from the modal barrel for exactly
|
|
19
|
-
// that consumer-side assertion.
|
|
20
|
-
|
|
21
|
-
/** Build a `<certrev-badge revalidate>` host wrapping an SSR `.certrev-badge`. */
|
|
22
|
-
function mountHost(attrs: Record<string, string> = {}): Element {
|
|
23
|
-
const host = document.createElement("certrev-badge");
|
|
24
|
-
host.setAttribute("revalidate", "");
|
|
25
|
-
host.setAttribute("data-delivery-api", "https://portal.certrev.com");
|
|
26
|
-
host.setAttribute("data-external-id", "gid://shopify/Article/12345");
|
|
27
|
-
host.setAttribute("data-platform", "shopify");
|
|
28
|
-
for (const [k, v] of Object.entries(attrs)) {
|
|
29
|
-
if (v === "") host.removeAttribute(k);
|
|
30
|
-
else host.setAttribute(k, v);
|
|
31
|
-
}
|
|
32
|
-
host.innerHTML =
|
|
33
|
-
'<section class="certrev-badge">Reviewed by Dr. Jane Doe</section>';
|
|
34
|
-
document.body.appendChild(host);
|
|
35
|
-
return host;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function depsReturning(verdict: CertVerdict): {
|
|
39
|
-
deps: RevalidateDeps;
|
|
40
|
-
spy: ReturnType<typeof vi.fn>;
|
|
41
|
-
} {
|
|
42
|
-
const spy = vi.fn(async () => verdict);
|
|
43
|
-
return { deps: { verify: spy as RevalidateDeps["verify"] }, spy };
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
beforeEach(() => {
|
|
47
|
-
document.body.innerHTML = "";
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
describe("revalidateBadge", () => {
|
|
51
|
-
it("leaves the SSR badge visible on a `render` verdict", async () => {
|
|
52
|
-
const host = mountHost();
|
|
53
|
-
const { deps } = depsReturning({
|
|
54
|
-
decision: "render",
|
|
55
|
-
payload: {},
|
|
56
|
-
} as unknown as CertVerdict);
|
|
57
|
-
await revalidateBadge(host, deps);
|
|
58
|
-
expect(host.querySelector(".certrev-badge")!.hasAttribute("hidden")).toBe(
|
|
59
|
-
false,
|
|
60
|
-
);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it("HIDES the SSR badge on a `suppress` verdict (fail-closed)", async () => {
|
|
64
|
-
const host = mountHost();
|
|
65
|
-
const { deps } = depsReturning({ decision: "suppress", reason: "revoked" });
|
|
66
|
-
await revalidateBadge(host, deps);
|
|
67
|
-
const badge = host.querySelector(".certrev-badge")!;
|
|
68
|
-
expect(badge.hasAttribute("hidden")).toBe(true);
|
|
69
|
-
expect(badge.getAttribute("data-certrev-suppressed")).toBe("revoked");
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it("leaves the SSR badge when verify throws (404 / offline → never a new failure mode)", async () => {
|
|
73
|
-
const host = mountHost();
|
|
74
|
-
const deps: RevalidateDeps = {
|
|
75
|
-
verify: vi.fn(async () => {
|
|
76
|
-
throw new Error("cert delivery 404");
|
|
77
|
-
}) as RevalidateDeps["verify"],
|
|
78
|
-
};
|
|
79
|
-
await revalidateBadge(host, deps);
|
|
80
|
-
expect(host.querySelector(".certrev-badge")!.hasAttribute("hidden")).toBe(
|
|
81
|
-
false,
|
|
82
|
-
);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it("does not call verify when routing attributes are missing", async () => {
|
|
86
|
-
const host = mountHost({ "data-external-id": "" });
|
|
87
|
-
const { deps, spy } = depsReturning({
|
|
88
|
-
decision: "suppress",
|
|
89
|
-
reason: "revoked",
|
|
90
|
-
});
|
|
91
|
-
await revalidateBadge(host, deps);
|
|
92
|
-
expect(spy).not.toHaveBeenCalled();
|
|
93
|
-
expect(host.querySelector(".certrev-badge")!.hasAttribute("hidden")).toBe(
|
|
94
|
-
false,
|
|
95
|
-
);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it("passes the host routing attributes through to verify", async () => {
|
|
99
|
-
const host = mountHost();
|
|
100
|
-
const { deps, spy } = depsReturning({
|
|
101
|
-
decision: "suppress",
|
|
102
|
-
reason: "expired",
|
|
103
|
-
});
|
|
104
|
-
await revalidateBadge(host, deps);
|
|
105
|
-
expect(spy).toHaveBeenCalledWith({
|
|
106
|
-
baseUrl: "https://portal.certrev.com",
|
|
107
|
-
platform: "shopify",
|
|
108
|
-
externalId: "gid://shopify/Article/12345",
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
});
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* End-to-end test of the Web Component's Delivery-API verifier with REAL crypto: mint a signed
|
|
3
|
-
* artifact (local Ed25519), stub `fetch` to serve it, and assert createDeliveryVerifier runs the
|
|
4
|
-
* canonical `verifyArtifact` kernel correctly — render on a good envelope, suppress on a subject
|
|
5
|
-
* mismatch, `suppress:'revoked'` on the SLIM `CertTombstone` (POR-10684 / POR-10481), throw on a
|
|
6
|
-
* 404 (→ the DOM layer keeps the SSR badge). Proves the fetch + URL + verify wiring the
|
|
7
|
-
* unit-mocked revalidate.test.ts stubs out.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { generateKeyPairSync } from "node:crypto";
|
|
11
|
-
import type {
|
|
12
|
-
CertSubject,
|
|
13
|
-
ResolvePublicKeyByKid,
|
|
14
|
-
} from "@certrev/cert-contract";
|
|
15
|
-
import {
|
|
16
|
-
localEd25519Signer,
|
|
17
|
-
signTombstone,
|
|
18
|
-
} from "@certrev/cert-contract/signer";
|
|
19
|
-
import { describe, expect, it, vi } from "vitest";
|
|
20
|
-
// Relocated from portal (POR-10721 W2): mint a valid signed envelope with the package's
|
|
21
|
-
// own fixture (cert-contract-native) instead of portal's `mintCertEnvelope` — the modal
|
|
22
|
-
// package must not depend on portal for its tests.
|
|
23
|
-
import { makeSignedEnvelope } from "../contract/fixtures.js";
|
|
24
|
-
import { createDeliveryVerifier } from "./verify-client.js";
|
|
25
|
-
|
|
26
|
-
const KID = "test-issuer";
|
|
27
|
-
const ARTICLE_GID = "gid://shopify/Article/12345";
|
|
28
|
-
|
|
29
|
-
function signerFor() {
|
|
30
|
-
const { publicKey, privateKey } = generateKeyPairSync("ed25519");
|
|
31
|
-
const pem = publicKey.export({ type: "spki", format: "pem" }) as string;
|
|
32
|
-
const resolveKid: ResolvePublicKeyByKid = (k) =>
|
|
33
|
-
k === KID ? { format: "pem", pem } : null;
|
|
34
|
-
return { resolveKid, sign: localEd25519Signer(privateKey) };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function subjectFor(externalId = ARTICLE_GID): CertSubject {
|
|
38
|
-
return {
|
|
39
|
-
platform: "shopify",
|
|
40
|
-
externalId,
|
|
41
|
-
logicalArticleId: "art_wc_test",
|
|
42
|
-
canonicalUrls: ["https://brand.example.com/blogs/news/post"],
|
|
43
|
-
installationId: null,
|
|
44
|
-
contentDigest: "a".repeat(64),
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function stubFetch(envelopeJson: unknown, ok = true, status = 200) {
|
|
49
|
-
return vi.fn(
|
|
50
|
-
async () =>
|
|
51
|
-
({ ok, status, json: async () => envelopeJson }) as unknown as Response,
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
describe("createDeliveryVerifier", () => {
|
|
56
|
-
it("fetches the Delivery API URL and returns `render` for a valid served envelope", async () => {
|
|
57
|
-
// Envelope bound to ARTICLE_GID — the article we ask to verify → render.
|
|
58
|
-
const { envelope, resolveKid } = makeSignedEnvelope({
|
|
59
|
-
subject: subjectFor(),
|
|
60
|
-
});
|
|
61
|
-
const fetchImpl = stubFetch(envelope);
|
|
62
|
-
const verify = createDeliveryVerifier(
|
|
63
|
-
resolveKid,
|
|
64
|
-
fetchImpl as unknown as typeof fetch,
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
const verdict = await verify({
|
|
68
|
-
baseUrl: "https://portal.certrev.com/",
|
|
69
|
-
platform: "shopify",
|
|
70
|
-
externalId: ARTICLE_GID,
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
expect(verdict.decision).toBe("render");
|
|
74
|
-
expect(fetchImpl).toHaveBeenCalledWith(
|
|
75
|
-
`https://portal.certrev.com/api/cert/v1/delivery/shopify/${encodeURIComponent(ARTICLE_GID)}`,
|
|
76
|
-
expect.objectContaining({ headers: { accept: "application/json" } }),
|
|
77
|
-
);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("returns a `suppress` verdict when the served envelope is bound to a different article", async () => {
|
|
81
|
-
// Envelope minted for a DIFFERENT article than the one we ask to verify.
|
|
82
|
-
const { envelope, resolveKid } = makeSignedEnvelope({
|
|
83
|
-
subject: subjectFor("gid://shopify/Article/99999"),
|
|
84
|
-
});
|
|
85
|
-
const verify = createDeliveryVerifier(
|
|
86
|
-
resolveKid,
|
|
87
|
-
stubFetch(envelope) as unknown as typeof fetch,
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
const verdict = await verify({
|
|
91
|
-
baseUrl: "https://portal.certrev.com",
|
|
92
|
-
platform: "shopify",
|
|
93
|
-
externalId: ARTICLE_GID,
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
expect(verdict.decision).toBe("suppress");
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('resolves the SLIM tombstone the control plane serves to `suppress:"revoked"` (POR-10684)', async () => {
|
|
100
|
-
const { resolveKid, sign } = signerFor();
|
|
101
|
-
// The revoked-placement Delivery response: a slim `CertTombstone` (kind: 'tombstone', NO
|
|
102
|
-
// payload) — what verifyEnvelope used to mis-suppress as 'unsupported_contract_version'.
|
|
103
|
-
const artifact = await signTombstone(
|
|
104
|
-
{
|
|
105
|
-
subject: subjectFor(),
|
|
106
|
-
revokedAt: "2026-06-20T00:00:00.000Z",
|
|
107
|
-
revocationReason: "cert_revoked",
|
|
108
|
-
},
|
|
109
|
-
{ kid: KID, sign },
|
|
110
|
-
);
|
|
111
|
-
const verify = createDeliveryVerifier(
|
|
112
|
-
resolveKid,
|
|
113
|
-
stubFetch(artifact) as unknown as typeof fetch,
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
const verdict = await verify({
|
|
117
|
-
baseUrl: "https://portal.certrev.com",
|
|
118
|
-
platform: "shopify",
|
|
119
|
-
externalId: ARTICLE_GID,
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
expect(verdict.decision).toBe("suppress");
|
|
123
|
-
expect(verdict.decision === "suppress" && verdict.reason).toBe("revoked");
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it("suppresses a tombstone minted for a DIFFERENT article (subject binding enforced)", async () => {
|
|
127
|
-
const { resolveKid, sign } = signerFor();
|
|
128
|
-
const artifact = await signTombstone(
|
|
129
|
-
{
|
|
130
|
-
subject: subjectFor("gid://shopify/Article/99999"),
|
|
131
|
-
revokedAt: "2026-06-20T00:00:00.000Z",
|
|
132
|
-
revocationReason: "cert_revoked",
|
|
133
|
-
},
|
|
134
|
-
{ kid: KID, sign },
|
|
135
|
-
);
|
|
136
|
-
const verify = createDeliveryVerifier(
|
|
137
|
-
resolveKid,
|
|
138
|
-
stubFetch(artifact) as unknown as typeof fetch,
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
const verdict = await verify({
|
|
142
|
-
baseUrl: "https://portal.certrev.com",
|
|
143
|
-
platform: "shopify",
|
|
144
|
-
externalId: ARTICLE_GID,
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
expect(verdict.decision).toBe("suppress");
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it("throws on a non-2xx Delivery API response (404 → caller keeps the SSR badge)", async () => {
|
|
151
|
-
const { resolveKid } = signerFor();
|
|
152
|
-
const verify = createDeliveryVerifier(
|
|
153
|
-
resolveKid,
|
|
154
|
-
stubFetch(null, false, 404) as unknown as typeof fetch,
|
|
155
|
-
);
|
|
156
|
-
await expect(
|
|
157
|
-
verify({
|
|
158
|
-
baseUrl: "https://portal.certrev.com",
|
|
159
|
-
platform: "shopify",
|
|
160
|
-
externalId: ARTICLE_GID,
|
|
161
|
-
}),
|
|
162
|
-
).rejects.toThrow();
|
|
163
|
-
});
|
|
164
|
-
});
|