@noy-db/test-sealer-conformance 0.7.0-pre.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 vLannaAi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # @noy-db/test-sealer-conformance
2
+
3
+ Contract tests for the `at-*` family port. Every `NoydbSealer` implementation — `at-env`, `at-aws-kms`, `at-gcp-kms`, `at-macos-keychain`, `at-azure-keyvault`, or your own — runs the same suite, so "implements the contract" means one thing rather than one thing per package.
4
+
5
+ ```ts
6
+ import { runSealerConformanceTests } from '@noy-db/test-sealer-conformance'
7
+ import { atEnv } from '@noy-db/at-env'
8
+
9
+ runSealerConformanceTests('at-env', () => atEnv({ id: 'env:a' }), {
10
+ other: () => atEnv({ id: 'env:b' }),
11
+ })
12
+ ```
13
+
14
+ `other` is required, not optional: the single most load-bearing property of a sealer is that its output is **not portable to a differently-identified provider**, and one instance cannot demonstrate that.
15
+
16
+ ## What it checks
17
+
18
+ Round-trip (including empty and multi-block secrets), that the output is not the plaintext, that `id` is present, stable and does not leak the secret — and, carrying most of the weight, that **`unseal` refuses**: another provider's blob, bytes never sealed, an empty buffer, and a tampered blob.
19
+
20
+ That emphasis is deliberate. `at-*` is the one non-zero-knowledge family, and hub treats a thrown error as *"this provider cannot unlock this vault"*. `providerId` is audit metadata, **not** a guard — so a provider that returns garbage instead of throwing hands hub a "secret" nobody sealed.
21
+
22
+ Pass `skipTamper: true` only for a backend that cannot be handed a corrupted blob (a keychain that only ever returns what it stored). Skipping it because it fails is the bug it exists to find.
23
+
24
+ ## Which providers can run what, and why
25
+
26
+ The split is not "local vs cloud" — it is **where the cryptography happens**.
27
+
28
+ | provider | full suite | obligations | why |
29
+ |---|---|---|---|
30
+ | `at-env` | ✅ | — | does its own AES-256-GCM |
31
+ | **`at-macos-keychain`** | ✅ | — | **the Keychain stores the KEY; the sealing is `crypto.subtle` in this package.** A memory-backed `KeychainEntry` swaps the key store and leaves the cryptography real |
32
+ | `at-aws-kms` | ❌ needs real KMS | ✅ | `seal` **is** an `EncryptCommand` |
33
+ | `at-gcp-kms` | ❌ needs real KMS | ✅ | `seal` **is** `client.encrypt` |
34
+ | `at-azure-keyvault` | ❌ | ❌ **no test seam** | see below |
35
+
36
+ For a **delegating** provider, refusing tampered, foreign or garbage input is the *service's* behaviour. Standing a fake KMS in front of it and asserting tamper rejection tests the fake. What remains the *provider's* is covered by `runDelegatingSealerObligations`:
37
+
38
+ | obligation | whose | how |
39
+ |---|---|---|
40
+ | refuses tampered / foreign / garbage input | **the service's** | only against the real service |
41
+ | a service failure SURFACES, never swallowed | **the provider's** | stub client |
42
+ | no ciphertext/plaintext ⇒ THROWS, never fabricates | **the provider's** | stub client |
43
+
44
+ Both obligations are already satisfied by every wired provider, so those tests **pin** the behaviour rather than having found it missing — worth saying, so a green run is not read as evidence a bug was caught. (Mutation-checked: making `unseal` fabricate empty bytes fails 1; making it swallow the failure fails 2.)
45
+
46
+ ### ⚠️ `at-azure-keyvault` cannot be tested at all
47
+
48
+ Every other `at-*` provider takes an injection seam — `entry` for the Keychain, `client` for AWS and GCP. `AzureKeyVaultSealingProviderOptions` takes only `keyId` and `algorithm`, so there is no way to exercise it without a real Key Vault. It is the one provider with **no coverage of either kind**, and closing that needs a production change (add `client?:`), not a test.
49
+
50
+ ### Still owed
51
+
52
+ A **credential-gated integration lane** running the full suite against real AWS/GCP/Azure backends. Until it exists, be blunt about what is unverified: those three providers' refusal behaviour has never been executed.
53
+
@@ -0,0 +1,79 @@
1
+ import { NoydbSealer } from '@noy-db/hub/at';
2
+
3
+ /**
4
+ * Parameterized conformance suite for the `at-*` family port.
5
+ *
6
+ * Every `NoydbSealer` implementation must pass these. The contract is three
7
+ * members — `id`, `seal`, `unseal` — and almost all of the risk is in what
8
+ * `unseal` does when it is handed something it should refuse.
9
+ *
10
+ * These assertions are not new: hub has tested them as
11
+ * `describe('NoydbSealer — contract')` against `MemorySealer` since managed
12
+ * mode landed. What was missing is that a REAL provider — `at-env`,
13
+ * `at-aws-kms`, or a third party's — had no way to run the same suite, so
14
+ * every implementation was checked against its own idea of the contract. This
15
+ * package is that extraction, mirroring `@noy-db/test-adapter-conformance`
16
+ * for stores.
17
+ *
18
+ * ⚠️ `at-*` is the one NON-zero-knowledge family: a host you control can
19
+ * decrypt the slice it unseals. That is deliberate, and it is why the
20
+ * `unseal`-must-refuse cases below matter more here than anywhere else — a
21
+ * provider that silently returns garbage instead of throwing hands hub a
22
+ * "secret" that was never sealed by anyone.
23
+ *
24
+ * NOTE ON IMPORTS: this suite binds `@noy-db/hub/at`, the family seam. It was
25
+ * written against the root barrel because `/at` did not exist yet — the seam
26
+ * follows the port, not the other way round. `/at` and its four siblings
27
+ * shipped in 0.3.0 with nothing behind them and were removed in 0.4.0 for
28
+ * "zero importers"; it returns now because this package is what stands behind
29
+ * it, and the five `at-*` providers bind it.
30
+ */
31
+ declare function runSealerConformanceTests(name: string, factory: () => Promise<NoydbSealer> | NoydbSealer, opts: {
32
+ /**
33
+ * A SECOND, differently-identified provider. Required: the single most
34
+ * load-bearing property of a sealer is that its output is not portable to
35
+ * another one, and that cannot be checked with one instance.
36
+ */
37
+ readonly other: () => Promise<NoydbSealer> | NoydbSealer;
38
+ /**
39
+ * Skip the tamper case for providers whose backend authenticates
40
+ * out-of-band and cannot be handed a corrupted blob (e.g. a keychain that
41
+ * only ever returns what it stored). Defaults to running it.
42
+ */
43
+ readonly skipTamper?: boolean;
44
+ }): void;
45
+ /**
46
+ * Obligations for a DELEGATING provider — one whose `seal` IS the service call.
47
+ *
48
+ * `runSealerConformanceTests` cannot be run against `at-aws-kms`,
49
+ * `at-gcp-kms` or `at-azure-keyvault` without real credentials, because the
50
+ * properties it asserts (refusing tampered, foreign or garbage input) are the
51
+ * SERVICE's behaviour. Standing a fake KMS in front of them would test the
52
+ * fake.
53
+ *
54
+ * Two obligations remain squarely the provider's, and a stub client covers
55
+ * them honestly:
56
+ *
57
+ * 1. a service failure must SURFACE — never be swallowed into a resolved
58
+ * promise. hub reads a thrown error as "this provider cannot unlock this
59
+ * vault"; a provider that swallows one reports success for a vault it
60
+ * never opened.
61
+ * 2. a response with no ciphertext/plaintext must THROW — never be
62
+ * fabricated into empty bytes. Returning `new Uint8Array(0)` for a failed
63
+ * Decrypt hands hub a "secret" nobody sealed.
64
+ *
65
+ * The caller supplies the providers, because each SDK's client shape differs
66
+ * and this package should not know about any of them.
67
+ *
68
+ * NOTE: at time of writing all wired providers already satisfy both. These
69
+ * tests PIN the behaviour rather than having found it missing — which is worth
70
+ * saying, so nobody reads a green run as evidence a bug was caught.
71
+ */
72
+ declare function runDelegatingSealerObligations(name: string, providers: {
73
+ /** Built with a client whose calls REJECT. */
74
+ readonly rejecting: () => Promise<NoydbSealer> | NoydbSealer;
75
+ /** Built with a client that RESOLVES but returns no ciphertext/plaintext. */
76
+ readonly empty: () => Promise<NoydbSealer> | NoydbSealer;
77
+ }): void;
78
+
79
+ export { runDelegatingSealerObligations, runSealerConformanceTests };
package/dist/index.js ADDED
@@ -0,0 +1,95 @@
1
+ // src/index.ts
2
+ import { describe, it, expect } from "vitest";
3
+ function runSealerConformanceTests(name, factory, opts) {
4
+ const make = async () => await factory();
5
+ const makeOther = async () => await opts.other();
6
+ describe(`NoydbSealer conformance: ${name}`, () => {
7
+ it("seal \u2192 unseal round-trips the exact bytes", async () => {
8
+ const sealer = await make();
9
+ const secret = new Uint8Array([1, 2, 3, 4, 5, 250, 251, 252]);
10
+ const out = await sealer.unseal(await sealer.seal(secret));
11
+ expect(Array.from(out)).toEqual(Array.from(secret));
12
+ });
13
+ it("round-trips an empty secret", async () => {
14
+ const sealer = await make();
15
+ const out = await sealer.unseal(await sealer.seal(new Uint8Array(0)));
16
+ expect(out.length).toBe(0);
17
+ });
18
+ it("round-trips a secret larger than one block", async () => {
19
+ const sealer = await make();
20
+ const secret = new Uint8Array(4096).map((_, i) => i % 256);
21
+ const out = await sealer.unseal(await sealer.seal(secret));
22
+ expect(Array.from(out)).toEqual(Array.from(secret));
23
+ });
24
+ it("produces output that is NOT the plaintext", async () => {
25
+ const sealer = await make();
26
+ const secret = new TextEncoder().encode("a recognisable secret");
27
+ const sealed = await sealer.seal(secret);
28
+ expect(Buffer.from(sealed).includes(Buffer.from(secret))).toBe(false);
29
+ });
30
+ it("THROWS when another provider tries to unseal its output", async () => {
31
+ const a = await make();
32
+ const b = await makeOther();
33
+ expect(a.id).not.toEqual(b.id);
34
+ await expect(b.unseal(await a.seal(new Uint8Array([9, 9, 9])))).rejects.toThrow();
35
+ });
36
+ it("THROWS on unsealing bytes that were never sealed", async () => {
37
+ const sealer = await make();
38
+ await expect(sealer.unseal(new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]))).rejects.toThrow();
39
+ });
40
+ it("THROWS on unsealing an empty buffer", async () => {
41
+ const sealer = await make();
42
+ await expect(sealer.unseal(new Uint8Array(0))).rejects.toThrow();
43
+ });
44
+ it.skipIf(opts.skipTamper)("THROWS on a tampered sealed blob", async () => {
45
+ const sealer = await make();
46
+ const sealed = await sealer.seal(new TextEncoder().encode("tamper me"));
47
+ const corrupted = Uint8Array.from(sealed);
48
+ const last = corrupted.length - 1;
49
+ corrupted[last] = (corrupted[last] ?? 0) ^ 255;
50
+ await expect(sealer.unseal(corrupted)).rejects.toThrow();
51
+ });
52
+ it("exposes a non-empty `id`", async () => {
53
+ const sealer = await make();
54
+ expect(typeof sealer.id).toBe("string");
55
+ expect(sealer.id.length).toBeGreaterThan(0);
56
+ });
57
+ it("keeps `id` stable across calls \u2014 hub persists it in the envelope", async () => {
58
+ const sealer = await make();
59
+ const first = sealer.id;
60
+ await sealer.seal(new Uint8Array([1]));
61
+ expect(sealer.id).toBe(first);
62
+ });
63
+ it("does not leak the secret through `id`", async () => {
64
+ const sealer = await make();
65
+ const secret = new TextEncoder().encode("super-secret-value");
66
+ await sealer.seal(secret);
67
+ expect(sealer.id).not.toContain("super-secret-value");
68
+ });
69
+ });
70
+ }
71
+ function runDelegatingSealerObligations(name, providers) {
72
+ describe(`Delegating-sealer obligations: ${name}`, () => {
73
+ it("seal THROWS when the service call rejects \u2014 never swallows it", async () => {
74
+ const s = await providers.rejecting();
75
+ await expect(s.seal(new Uint8Array([1, 2, 3]))).rejects.toThrow();
76
+ });
77
+ it("unseal THROWS when the service call rejects \u2014 never swallows it", async () => {
78
+ const s = await providers.rejecting();
79
+ await expect(s.unseal(new Uint8Array([1, 2, 3]))).rejects.toThrow();
80
+ });
81
+ it("seal THROWS when the service returns no ciphertext \u2014 never fabricates", async () => {
82
+ const s = await providers.empty();
83
+ await expect(s.seal(new Uint8Array([1, 2, 3]))).rejects.toThrow();
84
+ });
85
+ it("unseal THROWS when the service returns no plaintext \u2014 never fabricates", async () => {
86
+ const s = await providers.empty();
87
+ await expect(s.unseal(new Uint8Array([1, 2, 3]))).rejects.toThrow();
88
+ });
89
+ });
90
+ }
91
+ export {
92
+ runDelegatingSealerObligations,
93
+ runSealerConformanceTests
94
+ };
95
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { describe, it, expect } from 'vitest'\nimport type { NoydbSealer } from '@noy-db/hub/at'\n\n/**\n * Parameterized conformance suite for the `at-*` family port.\n *\n * Every `NoydbSealer` implementation must pass these. The contract is three\n * members — `id`, `seal`, `unseal` — and almost all of the risk is in what\n * `unseal` does when it is handed something it should refuse.\n *\n * These assertions are not new: hub has tested them as\n * `describe('NoydbSealer — contract')` against `MemorySealer` since managed\n * mode landed. What was missing is that a REAL provider — `at-env`,\n * `at-aws-kms`, or a third party's — had no way to run the same suite, so\n * every implementation was checked against its own idea of the contract. This\n * package is that extraction, mirroring `@noy-db/test-adapter-conformance`\n * for stores.\n *\n * ⚠️ `at-*` is the one NON-zero-knowledge family: a host you control can\n * decrypt the slice it unseals. That is deliberate, and it is why the\n * `unseal`-must-refuse cases below matter more here than anywhere else — a\n * provider that silently returns garbage instead of throwing hands hub a\n * \"secret\" that was never sealed by anyone.\n *\n * NOTE ON IMPORTS: this suite binds `@noy-db/hub/at`, the family seam. It was\n * written against the root barrel because `/at` did not exist yet — the seam\n * follows the port, not the other way round. `/at` and its four siblings\n * shipped in 0.3.0 with nothing behind them and were removed in 0.4.0 for\n * \"zero importers\"; it returns now because this package is what stands behind\n * it, and the five `at-*` providers bind it.\n */\nexport function runSealerConformanceTests(\n name: string,\n factory: () => Promise<NoydbSealer> | NoydbSealer,\n opts: {\n /**\n * A SECOND, differently-identified provider. Required: the single most\n * load-bearing property of a sealer is that its output is not portable to\n * another one, and that cannot be checked with one instance.\n */\n readonly other: () => Promise<NoydbSealer> | NoydbSealer\n /**\n * Skip the tamper case for providers whose backend authenticates\n * out-of-band and cannot be handed a corrupted blob (e.g. a keychain that\n * only ever returns what it stored). Defaults to running it.\n */\n readonly skipTamper?: boolean\n },\n): void {\n const make = async () => await factory()\n const makeOther = async () => await opts.other()\n\n describe(`NoydbSealer conformance: ${name}`, () => {\n it('seal → unseal round-trips the exact bytes', async () => {\n const sealer = await make()\n const secret = new Uint8Array([1, 2, 3, 4, 5, 250, 251, 252])\n const out = await sealer.unseal(await sealer.seal(secret))\n expect(Array.from(out)).toEqual(Array.from(secret))\n })\n\n it('round-trips an empty secret', async () => {\n // Zero-length is the boundary a length-prefixed or padded format is\n // most likely to get wrong, and hub never guarantees a minimum size.\n const sealer = await make()\n const out = await sealer.unseal(await sealer.seal(new Uint8Array(0)))\n expect(out.length).toBe(0)\n })\n\n it('round-trips a secret larger than one block', async () => {\n const sealer = await make()\n const secret = new Uint8Array(4096).map((_, i) => i % 256)\n const out = await sealer.unseal(await sealer.seal(secret))\n expect(Array.from(out)).toEqual(Array.from(secret))\n })\n\n it('produces output that is NOT the plaintext', async () => {\n // Catches a no-op or pass-through implementation, which round-trips\n // perfectly and seals nothing.\n const sealer = await make()\n const secret = new TextEncoder().encode('a recognisable secret')\n const sealed = await sealer.seal(secret)\n expect(Buffer.from(sealed).includes(Buffer.from(secret))).toBe(false)\n })\n\n it('THROWS when another provider tries to unseal its output', async () => {\n // The property hub relies on: `providerId` is audit metadata, not a\n // guard, so the only thing stopping a wrong-provider open is unseal\n // refusing. A provider that succeeds here silently unlocks vaults it\n // has no claim to.\n const a = await make()\n const b = await makeOther()\n expect(a.id).not.toEqual(b.id)\n await expect(b.unseal(await a.seal(new Uint8Array([9, 9, 9])))).rejects.toThrow()\n })\n\n it('THROWS on unsealing bytes that were never sealed', async () => {\n const sealer = await make()\n await expect(sealer.unseal(new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]))).rejects.toThrow()\n })\n\n it('THROWS on unsealing an empty buffer', async () => {\n const sealer = await make()\n await expect(sealer.unseal(new Uint8Array(0))).rejects.toThrow()\n })\n\n it.skipIf(opts.skipTamper)('THROWS on a tampered sealed blob', async () => {\n const sealer = await make()\n const sealed = await sealer.seal(new TextEncoder().encode('tamper me'))\n const corrupted = Uint8Array.from(sealed)\n const last = corrupted.length - 1\n corrupted[last] = (corrupted[last] ?? 0) ^ 0xff\n await expect(sealer.unseal(corrupted)).rejects.toThrow()\n })\n\n it('exposes a non-empty `id`', async () => {\n const sealer = await make()\n expect(typeof sealer.id).toBe('string')\n expect(sealer.id.length).toBeGreaterThan(0)\n })\n\n it('keeps `id` stable across calls — hub persists it in the envelope', async () => {\n const sealer = await make()\n const first = sealer.id\n await sealer.seal(new Uint8Array([1]))\n expect(sealer.id).toBe(first)\n })\n\n it('does not leak the secret through `id`', async () => {\n // `id` is documented NOT secret and \"fine to log\". A provider that\n // derives it from the material it protects makes that documentation\n // false for every consumer that believed it.\n const sealer = await make()\n const secret = new TextEncoder().encode('super-secret-value')\n await sealer.seal(secret)\n expect(sealer.id).not.toContain('super-secret-value')\n })\n })\n}\n\n/**\n * Obligations for a DELEGATING provider — one whose `seal` IS the service call.\n *\n * `runSealerConformanceTests` cannot be run against `at-aws-kms`,\n * `at-gcp-kms` or `at-azure-keyvault` without real credentials, because the\n * properties it asserts (refusing tampered, foreign or garbage input) are the\n * SERVICE's behaviour. Standing a fake KMS in front of them would test the\n * fake.\n *\n * Two obligations remain squarely the provider's, and a stub client covers\n * them honestly:\n *\n * 1. a service failure must SURFACE — never be swallowed into a resolved\n * promise. hub reads a thrown error as \"this provider cannot unlock this\n * vault\"; a provider that swallows one reports success for a vault it\n * never opened.\n * 2. a response with no ciphertext/plaintext must THROW — never be\n * fabricated into empty bytes. Returning `new Uint8Array(0)` for a failed\n * Decrypt hands hub a \"secret\" nobody sealed.\n *\n * The caller supplies the providers, because each SDK's client shape differs\n * and this package should not know about any of them.\n *\n * NOTE: at time of writing all wired providers already satisfy both. These\n * tests PIN the behaviour rather than having found it missing — which is worth\n * saying, so nobody reads a green run as evidence a bug was caught.\n */\nexport function runDelegatingSealerObligations(\n name: string,\n providers: {\n /** Built with a client whose calls REJECT. */\n readonly rejecting: () => Promise<NoydbSealer> | NoydbSealer\n /** Built with a client that RESOLVES but returns no ciphertext/plaintext. */\n readonly empty: () => Promise<NoydbSealer> | NoydbSealer\n },\n): void {\n describe(`Delegating-sealer obligations: ${name}`, () => {\n it('seal THROWS when the service call rejects — never swallows it', async () => {\n const s = await providers.rejecting()\n await expect(s.seal(new Uint8Array([1, 2, 3]))).rejects.toThrow()\n })\n\n it('unseal THROWS when the service call rejects — never swallows it', async () => {\n const s = await providers.rejecting()\n await expect(s.unseal(new Uint8Array([1, 2, 3]))).rejects.toThrow()\n })\n\n it('seal THROWS when the service returns no ciphertext — never fabricates', async () => {\n const s = await providers.empty()\n await expect(s.seal(new Uint8Array([1, 2, 3]))).rejects.toThrow()\n })\n\n it('unseal THROWS when the service returns no plaintext — never fabricates', async () => {\n const s = await providers.empty()\n await expect(s.unseal(new Uint8Array([1, 2, 3]))).rejects.toThrow()\n })\n })\n}\n"],"mappings":";AAAA,SAAS,UAAU,IAAI,cAAc;AA+B9B,SAAS,0BACd,MACA,SACA,MAcM;AACN,QAAM,OAAO,YAAY,MAAM,QAAQ;AACvC,QAAM,YAAY,YAAY,MAAM,KAAK,MAAM;AAE/C,WAAS,4BAA4B,IAAI,IAAI,MAAM;AACjD,OAAG,kDAA6C,YAAY;AAC1D,YAAM,SAAS,MAAM,KAAK;AAC1B,YAAM,SAAS,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,KAAK,KAAK,GAAG,CAAC;AAC5D,YAAM,MAAM,MAAM,OAAO,OAAO,MAAM,OAAO,KAAK,MAAM,CAAC;AACzD,aAAO,MAAM,KAAK,GAAG,CAAC,EAAE,QAAQ,MAAM,KAAK,MAAM,CAAC;AAAA,IACpD,CAAC;AAED,OAAG,+BAA+B,YAAY;AAG5C,YAAM,SAAS,MAAM,KAAK;AAC1B,YAAM,MAAM,MAAM,OAAO,OAAO,MAAM,OAAO,KAAK,IAAI,WAAW,CAAC,CAAC,CAAC;AACpE,aAAO,IAAI,MAAM,EAAE,KAAK,CAAC;AAAA,IAC3B,CAAC;AAED,OAAG,8CAA8C,YAAY;AAC3D,YAAM,SAAS,MAAM,KAAK;AAC1B,YAAM,SAAS,IAAI,WAAW,IAAI,EAAE,IAAI,CAAC,GAAG,MAAM,IAAI,GAAG;AACzD,YAAM,MAAM,MAAM,OAAO,OAAO,MAAM,OAAO,KAAK,MAAM,CAAC;AACzD,aAAO,MAAM,KAAK,GAAG,CAAC,EAAE,QAAQ,MAAM,KAAK,MAAM,CAAC;AAAA,IACpD,CAAC;AAED,OAAG,6CAA6C,YAAY;AAG1D,YAAM,SAAS,MAAM,KAAK;AAC1B,YAAM,SAAS,IAAI,YAAY,EAAE,OAAO,uBAAuB;AAC/D,YAAM,SAAS,MAAM,OAAO,KAAK,MAAM;AACvC,aAAO,OAAO,KAAK,MAAM,EAAE,SAAS,OAAO,KAAK,MAAM,CAAC,CAAC,EAAE,KAAK,KAAK;AAAA,IACtE,CAAC;AAED,OAAG,2DAA2D,YAAY;AAKxE,YAAM,IAAI,MAAM,KAAK;AACrB,YAAM,IAAI,MAAM,UAAU;AAC1B,aAAO,EAAE,EAAE,EAAE,IAAI,QAAQ,EAAE,EAAE;AAC7B,YAAM,OAAO,EAAE,OAAO,MAAM,EAAE,KAAK,IAAI,WAAW,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,QAAQ;AAAA,IAClF,CAAC;AAED,OAAG,oDAAoD,YAAY;AACjE,YAAM,SAAS,MAAM,KAAK;AAC1B,YAAM,OAAO,OAAO,OAAO,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,QAAQ;AAAA,IACxF,CAAC;AAED,OAAG,uCAAuC,YAAY;AACpD,YAAM,SAAS,MAAM,KAAK;AAC1B,YAAM,OAAO,OAAO,OAAO,IAAI,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,QAAQ;AAAA,IACjE,CAAC;AAED,OAAG,OAAO,KAAK,UAAU,EAAE,oCAAoC,YAAY;AACzE,YAAM,SAAS,MAAM,KAAK;AAC1B,YAAM,SAAS,MAAM,OAAO,KAAK,IAAI,YAAY,EAAE,OAAO,WAAW,CAAC;AACtE,YAAM,YAAY,WAAW,KAAK,MAAM;AACxC,YAAM,OAAO,UAAU,SAAS;AAChC,gBAAU,IAAI,KAAK,UAAU,IAAI,KAAK,KAAK;AAC3C,YAAM,OAAO,OAAO,OAAO,SAAS,CAAC,EAAE,QAAQ,QAAQ;AAAA,IACzD,CAAC;AAED,OAAG,4BAA4B,YAAY;AACzC,YAAM,SAAS,MAAM,KAAK;AAC1B,aAAO,OAAO,OAAO,EAAE,EAAE,KAAK,QAAQ;AACtC,aAAO,OAAO,GAAG,MAAM,EAAE,gBAAgB,CAAC;AAAA,IAC5C,CAAC;AAED,OAAG,yEAAoE,YAAY;AACjF,YAAM,SAAS,MAAM,KAAK;AAC1B,YAAM,QAAQ,OAAO;AACrB,YAAM,OAAO,KAAK,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC;AACrC,aAAO,OAAO,EAAE,EAAE,KAAK,KAAK;AAAA,IAC9B,CAAC;AAED,OAAG,yCAAyC,YAAY;AAItD,YAAM,SAAS,MAAM,KAAK;AAC1B,YAAM,SAAS,IAAI,YAAY,EAAE,OAAO,oBAAoB;AAC5D,YAAM,OAAO,KAAK,MAAM;AACxB,aAAO,OAAO,EAAE,EAAE,IAAI,UAAU,oBAAoB;AAAA,IACtD,CAAC;AAAA,EACH,CAAC;AACH;AA6BO,SAAS,+BACd,MACA,WAMM;AACN,WAAS,kCAAkC,IAAI,IAAI,MAAM;AACvD,OAAG,sEAAiE,YAAY;AAC9E,YAAM,IAAI,MAAM,UAAU,UAAU;AACpC,YAAM,OAAO,EAAE,KAAK,IAAI,WAAW,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,QAAQ;AAAA,IAClE,CAAC;AAED,OAAG,wEAAmE,YAAY;AAChF,YAAM,IAAI,MAAM,UAAU,UAAU;AACpC,YAAM,OAAO,EAAE,OAAO,IAAI,WAAW,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,QAAQ;AAAA,IACpE,CAAC;AAED,OAAG,8EAAyE,YAAY;AACtF,YAAM,IAAI,MAAM,UAAU,MAAM;AAChC,YAAM,OAAO,EAAE,KAAK,IAAI,WAAW,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,QAAQ;AAAA,IAClE,CAAC;AAED,OAAG,+EAA0E,YAAY;AACvF,YAAM,IAAI,MAAM,UAAU,MAAM;AAChC,YAAM,OAAO,EAAE,OAAO,IAAI,WAAW,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,QAAQ;AAAA,IACpE,CAAC;AAAA,EACH,CAAC;AACH;","names":[]}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@noy-db/test-sealer-conformance",
3
+ "version": "0.7.0-pre.0",
4
+ "description": "Parameterized contract tests for noy-db sealing-key providers — the conformance suite every NoydbSealer implementation must pass",
5
+ "license": "MIT",
6
+ "author": "vLannaAi <vicio@lanna.ai>",
7
+ "homepage": "https://github.com/vLannaAi/noy-db/tree/main/packages/test-sealer-conformance#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/vLannaAi/noy-db.git",
11
+ "directory": "packages/test-sealer-conformance"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/vLannaAi/noy-db/issues"
15
+ },
16
+ "type": "module",
17
+ "sideEffects": false,
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "default": "./dist/index.js"
22
+ }
23
+ },
24
+ "module": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "files": [
27
+ "dist",
28
+ "README.md",
29
+ "LICENSE"
30
+ ],
31
+ "engines": {
32
+ "node": ">=22.0.0"
33
+ },
34
+ "peerDependencies": {
35
+ "vitest": "^3.0.0",
36
+ "@noy-db/hub": "0.7.0-pre.0"
37
+ },
38
+ "devDependencies": {
39
+ "vitest": "^3.0.0",
40
+ "@noy-db/hub": "0.7.0-pre.0"
41
+ },
42
+ "keywords": [
43
+ "noy-db",
44
+ "conformance",
45
+ "sealing",
46
+ "testing",
47
+ "kms"
48
+ ],
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "scripts": {
53
+ "build": "tsup",
54
+ "test": "vitest run --passWithNoTests",
55
+ "typecheck": "tsc --noEmit"
56
+ }
57
+ }