Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,54 @@ All notable changes to the DKG V10 node are documented here. The format is based

## [Unreleased]

## [10.0.10] - 2026-07-28

This release lands OT-RFC-64, the public author catalog: a node-local subsystem that announces, discovers, fetches, and verifies another author's finalized Knowledge Assets over five new `/dkg/catalog/1/*` libp2p protocols. It is active by default on every node with a data directory, while authoring, auto-publish, and bootstrap targets stay opt-in. Because its persistence opens before networking, such a node now requires a Node runtime where `node:sqlite` is available unflagged — Node 22.13 or newer, or 23.4 or newer on the 23.x line. The rest is durability hardening on paths that could strand, mis-report, or lose verified work. Two changes are operator-visible: one encoded SWM share or promotion is capped at 4 MiB instead of 10 MB, and the dashboard database migrates 30 → 31. **No smart-contract changes — no deployment required** (no Solidity source, ABI, or deployment-registry changes since 10.0.9).

### Upgrading from 10.0.9

| Change | Impact | Action |
| --- | --- | --- |
| RFC-64 persistence requires unflagged `node:sqlite` | on a node with a data directory the RFC-64 inventory and the finalization inbox open before networking, so a runtime without `node:sqlite` fails the start with `requires Node runtime support for node:sqlite` | run **Node >= 22.13.0**, or **>= 23.4.0** on the 23.x line, or Node 24+. `node:sqlite` exists from 22.5.0 but stays behind `--experimental-sqlite` until 22.13.0/23.4.0, and the daemon never passes that flag — so 22.5–22.12 and 23.0–23.3 install cleanly and then fail to boot. `@origintrail-official/dkg` and `@origintrail-official/dkg-agent` both declare this range in `engines.node` — the agent package owns the `node:sqlite` code, so a builder embedding it directly gets the same contract. |
| SWM payload ceiling 10 MB → 4 MiB | one encoded SWM share or promotion above 4 MiB is rejected, and a 10.0.9 peer emitting more is dropped inbound | reduce importer batch size (`dkg-importer` guidance moves 1000 → 400 records) |
| `@origintrail-official/dkg-agent` declares `"exports"` | deep imports of internal paths fail with `ERR_PACKAGE_PATH_NOT_EXPORTED` | import from the package root |
| RFC-64 catalog is active by default | first boot creates `DKG_HOME/rfc64-sync/` and serves five new inbound catalog protocols (three without chain configuration) | no action; authoring/auto-publish stays opt-in |
| Dashboard database migrates 30 → 31 | one additive index table; rolling back to 10.0.9 is safe | no action |

### Added

- **Public author catalog (OT-RFC-64) runs on every node with a data directory** (#1930, #1882, #1929): first boot opens `DKG_HOME/rfc64-sync/` and registers the five catalog protocols, but a graph is answered for only after an operator accepts its current policy snapshot.
- **Catalog access follows the Context Graph policy cell** (#1835, #1881, #1905): every catalog operation is authorized in both directions against an accepted current `ContextGraphPolicyV1`, and an invite-only graph requires both ends in a roster bound to that policy digest.
- **Catalog chain state is read at one pinned finalized block** (#1821, #1909, #1911, #1913, #1914, #1915): policy, name binding, and finalized inventory resolve inside one EIP-1898 session, and rows are materialized before the applied-head pointer moves, so no node advertises a head it has not stored.
- **Opt-in catalog automation: cold start, bootstrap, and auto-advance** (#1819, #1926, #1928, #1927): a node can cold-start a public scope from a named provider, `rfc64PublicCatalogBootstrap` retries pinned provider targets across restarts, and `rfc64PublicCatalogAutoPublish` bridges a confirmed fully-public VM publish into it.
- **Clear a single terminal publish or share job by exact job ID** (#1883, #1910, #1899): new idempotent `clear-job` routes on the publisher and SWM share APIs remove one terminal record atomically; previously only a status-scoped bulk clear existed.

### Fixed

- **A transient store timeout no longer strands a verified Knowledge Asset outside Verifiable Memory** (#1939): finalization envelopes are now recorded in a durable SQLite inbox before any store work, so a crash or store failure between verification and materialization leaves the graph untouched and the evidence replayable instead of returning `verified-vm-metadata-pending` forever. Recovery surfaces as `finalizationRecovery` on `GET /api/status`.
- **Durable recovery drains its backlog and reports a truthful verdict** (#1967, #1898, #1908, #1895, #1937, #1906): exact VM repair now spends one peer attempt per asset under a far larger transfer ceiling and rotates the peer order, so large assets no longer time out together. A catch-up leg carries an explicit state, so a run that reached no eligible peer fails instead of reporting success, foreground catch-up retries backpressure, and a named `peerId` is probed.
- **The store no longer answers routine work with full scans** (#1877, #1959, #1873, #1917): a write racing an in-flight index probe demoted a scoped update to an `O(store)` rebuild that stalled publishes and starved sync; public exact-asset reads are now byte-bounded, and snapshot paging seeks to a persisted checkpoint.
- **Durable metadata pages no longer split an author seal** (#1916, #1936): pages end on a `(graph, subject)` boundary, so a seal straddling a boundary arrives whole instead of an unverifiable prefix that left curated Context Graphs unable to VM-publish, and a peer can no longer inject a non-IRI `_meta` subject.
- **Curator no longer silently publishes its own same-named Knowledge Asset** (#1969): author resolution returned the caller's own assertion before the ambiguity check, spending real TRAC and gas on the wrong asset; both VM publish routes now accept `selectedAuthorAgentAddress`, so a caller answered `409 AMBIGUOUS_ASSERTION_AUTHOR` can name one.
- **Publisher job records survive a crash mid-transition** (#1919, #1935, #1945, #1902): every async publish and share transition is now a single-subject atomic replace instead of a delete-then-insert that could strand it empty and lose the queue row; publisher admin routes also answer a malformed body without a 500.
- **Transport failures are classified by what they actually mean** (#1942, #1918, #1904): an aborted fetch now fails over instead of failing a publish whose mint is already on chain, an unambiguous pre-mempool reject terminates at once rather than entering recovery, and a failed chain read is no longer a negative authentication verdict.

### Changed

- **SWM gossip payload ceiling aligned with StorageACK:** one encoded SWM share or promotion is now capped at 4 MiB, matching the untrusted inline StorageACK staging ceiling. GossipSub retains 256 KiB of framing headroom, while the general direct-protocol frame/read limit remains 10 MiB.
- **SWM gossip payload ceiling aligned with StorageACK** (#1932): one encoded SWM share or promotion is now capped at 4 MiB, matching the untrusted inline StorageACK staging ceiling. GossipSub retains 256 KiB of framing headroom, while the general direct-protocol frame/read limit remains 10 MiB.
- **`@origintrail-official/dkg-agent` declares an explicit `"exports"` map** (#1835, #1930): it previously had none, so any subpath resolved; it now exposes only the root, `./package.json`, an allowlist of catalog subpaths, and `./dist/*`.
- **Dashboard SQLite schema 30 → 31** (#1873): adds a `snapshot_page_indexes` table for public-snapshot page offsets; additive, so rolling back to 10.0.9 is safe.
- **Node UI metric snapshots are collected once a day** (#1981): the collector's interval moves from 30 seconds to 24 hours, cutting dashboard database growth and periodic store-scan counters by roughly three orders of magnitude.
- **Knowledge Asset metadata states how a confirmation was obtained** (#1920): `_meta` now carries `dkg:confirmationKind`, distinguishing an asset confirmed by its own publish transaction from one rebuilt by a finalized on-chain scan.
- **Release version set:** all workspace packages move together to 10.0.10.

### Deployment

- **No contract changes in this release.** No Solidity source, ABI, or mainnet/testnet deployment-registry files changed since 10.0.9; nodes can upgrade through the normal npm release path.

### Known issues

- `engines.node` on `@origintrail-official/dkg` declares the supported runtime range, but npm and pnpm both treat `engines` as advisory unless `engine-strict` is set, so an unsupported runtime still installs with only an `EBADENGINE` warning. Neither the RFC-64 inventory nor the finalization inbox degrades gracefully, so such a node then fails at daemon start. Blue-green auto-update verifies build output exists before activating a slot but does not prove the new slot boots, so a node auto-updating on an unsupported runtime can activate and then restart-loop. Check `node --version` before upgrading.

## [10.0.9] - 2026-07-21

Expand Down
21 changes: 17 additions & 4 deletions RELEASE_PROCESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,14 @@ One OTP covers the batch; a TOTP code can expire mid-loop, so if some fail, re-r

### 6c) Create the GitHub Release (manual)

Because there is no tag-triggered release workflow, make the Release by hand from the signed tag, with notes taken from the matching `CHANGELOG.md` section (theme header, npm + channel line, PR-tagged bullets, a `compare/vPREV...vNEW` link):
Because there is no tag-triggered release workflow, make the Release by hand from the signed tag. **This section owns GitHub Release note generation.** The notes are the matching `CHANGELOG.md` section copied *verbatim* — including its `### Upgrading from <PRIOR>` matrix, if §10 put one there — with only fixed metadata added around it. Do not reword, reorder, or drop bullets while assembling; if the notes need to say something the CHANGELOG does not, fix the CHANGELOG first so the two cannot drift.

Assemble `notes.md` as:

1. A `# DKG vX.Y.Z` title line.
2. The CHANGELOG section body verbatim, minus its own `## [X.Y.Z] - DATE` heading.
3. An npm + channel line directly under the theme paragraph: ``**npm:** `@origintrail-official/dkg@X.Y.Z` — dist-tags `latest`, `testnet`, `mainnet``, naming only the tags this release actually moved.
4. A closing `**Full changelog:** https://github.com/OriginTrail/dkg/compare/vPREV...vX.Y.Z` link.

```bash
gh release create vX.Y.Z --repo OriginTrail/dkg --verify-tag \
Expand Down Expand Up @@ -223,17 +230,23 @@ dkg start

## 10) Builder upgrade guides (per release)

Every breaking or builder-impacting release ships a focused upgrade guide alongside the CHANGELOG entry. The guide lives at `docs/UPGRADE_<PRIOR>_TO_<NEW>.md` (e.g. `docs/UPGRADE_RC11_TO_RC12.md`).
Every breaking or builder-impacting release ships upgrade guidance alongside the CHANGELOG entry. Scale the artifact to the migration:

This section defines **when** upgrade guidance is required and **where it is written**. §6c owns how it reaches the GitHub Release: it copies the matching CHANGELOG section verbatim, so anything placed in that section ships to builders automatically and the two cannot drift.

A good upgrade guide:
**Small migrations (a handful of discrete changes) — default.** Put an `### Upgrading from <PRIOR>` section directly in the release's `CHANGELOG.md` entry, immediately after the theme paragraph, as a `Change | Impact | Action` matrix. No standalone document is required.

**Large migrations (mass renames, contract/ABI changes, economic changes).** Write a standalone guide at `docs/release-notes/<version>.md` (e.g. `docs/release-notes/v10-1-0.md`) and link it from the `### Upgrading from <PRIOR>` section. One file per release, never a growing shared file: shipped notes are immutable, per-release files stay directly linkable from the CHANGELOG and the GitHub Release, and they do not conflict on every release. A good standalone guide:

- Opens with an agent-prompt template builders can paste into Cursor / Claude Code / Codex CLI / any AGENTS.md-honouring tool to drive the migration end-to-end.
- Includes a breaking-change matrix at the top so a reader can grep for what affects them in 30 seconds.
- Provides mechanical search-and-replace tables for the TS and Solidity surfaces (sed / git-grep examples are fine — most rename work is regex-shaped).
- Documents every economic / contract / wire-format change a downstream caller could trip on, with concrete `tokenAmount`, ABI, and Hub-registration steps.
- Cross-links the relevant `CHANGELOG.md` section for per-PR detail.

Cross-link the new guide from [`docs/RELEASE.md`](docs/RELEASE.md) § "Upgrading from a prior release" before tagging.
**Keep release notes out of GitBook.** GitBook syncs the `docs/` tree and builds its navigation from `docs/SUMMARY.md`, so a file under `docs/` that is **not** listed in `SUMMARY.md` is not published. `docs/release-notes/` must stay unlisted, matching `docs/reports/`, `docs/rfcs/`, and `docs/adr/`, which already live in `docs/` outside the navigation. Do not add a `SUMMARY.md` entry when adding a release-notes file.

This document is the authoritative release runbook. Superseded V9-era material — the old `RELEASE.md` runbook and the rc-line `UPGRADE_RC11_TO_*.md` guides — is retained under `docs/archive/internal/` for history only and should not be followed or extended.

## 11) Promotion policy

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dkg-v10",
"version": "10.0.9",
"version": "10.0.10",
"private": true,
"packageManager": "pnpm@10.28.1",
"dkgBuild": {
Expand Down
2 changes: 1 addition & 1 deletion packages/adapter-elizaos/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@origintrail-official/dkg-adapter-elizaos",
"version": "10.0.9",
"version": "10.0.10",
"description": "ElizaOS plugin adapter — turns any ElizaOS agent into a DKG V10 node",
"type": "module",
"main": "dist/index.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/adapter-hermes/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@origintrail-official/dkg-adapter-hermes",
"version": "10.0.9",
"version": "10.0.10",
"description": "Hermes Agent adapter — connects Hermes AI agents to a DKG V10 node for verifiable shared memory",
"type": "module",
"main": "dist/index.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/adapter-openclaw/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@origintrail-official/dkg-adapter-openclaw",
"version": "10.0.9",
"version": "10.0.10",
"description": "OpenClaw plugin adapter for connecting a DKG V10 node and chat bridge to an OpenClaw agent",
"type": "module",
"main": "dist/index.js",
Expand Down
5 changes: 4 additions & 1 deletion packages/agent/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
{
"name": "@origintrail-official/dkg-agent",
"version": "10.0.9",
"version": "10.0.10",
"type": "module",
"engines": {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: New Node runtime contract is not locked by tests

What's wrong
The PR makes the supported Node range an operator-facing packaging contract, but there is no automated check that the two published packages keep declaring the same unflagged-node:sqlite range. That leaves a high-risk release detail verified only by manual review.

Example
A packaging edit could remove or mistype one range, for example leaving @origintrail-official/dkg-agent without >=22.13.0 <23.0.0 || >=23.4.0, while the current package-root tests still pass. Consumers embedding the agent directly would then lose the EBADENGINE signal and only discover the unsupported runtime when node:sqlite fails at daemon start.

Suggested direction
Cover the new manifest contract with a static test so CI fails if either published package drops or diverges from the documented Node range.

Confidence note
I did not find an existing manifest/package-root assertion for this new runtime contract; this is a static review of the PR diff and nearby package-root checks.

For Agents
Add a small manifest-contract test near the package-root/export checks, or a shared release/package metadata test, that reads packages/agent/package.json and packages/cli/package.json and asserts both published packages expose the exact supported engines.node range required by unflagged node:sqlite. Keep the existing export checks intact.

"node": ">=22.13.0 <23.0.0 || >=23.4.0"
},
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
Expand Down
15 changes: 13 additions & 2 deletions packages/agent/test/agent.part-16.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,19 @@ describe('DKGAgent config — syncContextGraphs and queryAccess warning', () =>
});

expect(peerStoreReads).toBe(3);
expect(syncFromPeerDetailed.calls.at(-1)).toEqual([remotePeer.toString(), ['runtime-contextGraph']]);
expect(syncSharedMemoryFromPeerDetailed.calls.at(-1)).toEqual([remotePeer.toString(), ['runtime-contextGraph']]);
expect(syncFromPeerDetailed.calls.at(-1)).toEqual([

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: The test now codifies optional positional-argument plumbing

What's wrong
The changed expectation locks the test to incidental call mechanics rather than the behavior this scenario cares about. It also exposes a broader readability smell: the sync method API has accumulated optional positional parameters, so simple calls now need placeholder undefineds to reach later arguments.

Example
Adding a new optional parameter before options would force this assertion to change even if syncContextGraphFromConnectedPeers still sends the same peer and context graph IDs.

Suggested direction
Prefer a semantic assertion over an exact tuple full of placeholders, and consider moving the detailed sync API toward a named options object so callers do not have to encode undefined slots.

Confidence note
This is anchored in a test-only hunk, so the risk is maintainability friction rather than runtime behavior.

For Agents
In packages/agent/test/agent.part-16.test.ts, avoid asserting the entire private positional tuple. Either assert the semantic prefix and the specific option slot that matters, or introduce a small named-options helper around the detailed sync calls and test that boundary. Preserve the result aggregation assertions.

remotePeer.toString(),
['runtime-contextGraph'],
undefined,
undefined,
undefined,
undefined,
]);
expect(syncSharedMemoryFromPeerDetailed.calls.at(-1)).toEqual([
remotePeer.toString(),
['runtime-contextGraph'],
undefined,
]);
expect(result.connectedPeers).toBe(1);
expect(result.syncCapablePeers).toBe(1);
expect(result.peersTried).toBe(1);
Expand Down
5 changes: 5 additions & 0 deletions packages/agent/test/outbox-shutdown-lifecycle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, expect, it, vi } from 'vitest';
import { DKGAgent } from '../src/dkg-agent.js';
import { DKGAgentBase } from '../src/dkg-agent-base.js';
import { VmReconcileDispatcher } from '../src/chain-reconciler.js';
import { FinalizationRuntime } from '../src/finalization-runtime.js';
import { VmReconcileQueueClosedError } from '../src/vm-reconcile-service.js';

describe('DKGAgent outbox shutdown lifecycle', () => {
Expand Down Expand Up @@ -34,6 +35,7 @@ describe('DKGAgent outbox shutdown lifecycle', () => {
inFlightSubstrateFanOutCount: () => 0,
router: { closePooling: vi.fn(async () => {}) },
node: { stop: stopNode },
finalizationRuntime: new FinalizationRuntime(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: Repeated hand-built agent fixtures keep spreading private lifecycle dependencies

What's wrong
Adding finalizationRuntime to every hand-rolled any agent fixture deepens an existing test-maintenance trap: these tests bypass the constructor, then mirror whatever private fields stop() happens to touch. That makes lifecycle refactors noisy and encourages future changes to patch scattered object literals rather than improve the fixture boundary.

Example
The next dependency read by agent.stop() will require editing each object literal again. Missing one fixture will fail for fixture-shape reasons rather than because the shutdown scenario changed.

Suggested direction
Collapse the duplicated Object.create setup into a focused fixture factory for the shutdown surface. The tests should describe which collaborator each scenario varies, not restate the full private agent shape every time.

For Agents
In packages/agent/test/outbox-shutdown-lifecycle.test.ts, extract a local makeStartedAgentForStop(overrides) helper that installs the default shutdown collaborators, including finalizationRuntime, and lets each test override only the collaborator it asserts. Preserve the four shutdown scenarios and prove the helper still supports the timeout override and warning assertions.

store: { close: closeStore },
log: { warn: vi.fn() },
});
Expand Down Expand Up @@ -85,6 +87,7 @@ describe('DKGAgent outbox shutdown lifecycle', () => {
inFlightSubstrateFanOutCount: () => 0,
router: { closePooling: vi.fn(async () => {}) },
node: { stop: stopNode },
finalizationRuntime: new FinalizationRuntime(),
store: { close: closeStore },
log: { warn },
});
Expand Down Expand Up @@ -124,6 +127,7 @@ describe('DKGAgent outbox shutdown lifecycle', () => {
inFlightSubstrateFanOutCount: () => 0,
router: { closePooling: vi.fn(async () => {}) },
node: { stop: stopNode },
finalizationRuntime: new FinalizationRuntime(),
store: { close: vi.fn(async () => {}) },
log: { warn: vi.fn() },
});
Expand Down Expand Up @@ -157,6 +161,7 @@ describe('DKGAgent outbox shutdown lifecycle', () => {
inFlightSubstrateFanOutCount: () => 0,
router: { closePooling: vi.fn(async () => {}) },
node: { stop: stopNode },
finalizationRuntime: new FinalizationRuntime(),
store: { close: closeStore },
log: { warn },
});
Expand Down
2 changes: 1 addition & 1 deletion packages/chain/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@origintrail-official/dkg-chain",
"version": "10.0.9",
"version": "10.0.10",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
5 changes: 4 additions & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
{
"name": "@origintrail-official/dkg",
"version": "10.0.9",
"version": "10.0.10",
"type": "module",
"engines": {
"node": ">=22.13.0 <23.0.0 || >=23.4.0"
},
"main": "dist/cli.js",
"bin": {
"dkg": "./dist/cli.js"
Expand Down
9 changes: 7 additions & 2 deletions packages/cli/test/skill-endpoint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,16 @@ describe('SKILL.md file', () => {
// register/publishPolicy caveat, create-failure recovery semantics) — content we
// deliberately added, where trimming would regress the accuracy we just fixed.
//
// 950 lines stays a realistic ceiling: well below the documented Agent Skills
// Resident-author selection (GH#1786) raised the cap 950 → 1000. The added
// contract distinguishes selection from authorship and documents the
// synchronous/async non-custodial failure modes; omitting it would make the
// canonical skill inaccurate for the newly exposed API.
//
// 1000 lines stays a realistic ceiling: well below the documented Agent Skills
// "should be concise" guidance for very large skills, while still catching
// unbounded growth (e.g. an accidental dump of full OpenAPI schema in-line).
const lines = skillContent.split('\n').length;
expect(lines).toBeLessThan(950);
expect(lines).toBeLessThan(1000);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: Raising the skill size budget normalizes the sprawl instead of decomposing it

What's wrong
This change makes the size guard less effective exactly when the canonical skill is already close to the 1k-line boundary. The comments justify accumulated growth, but the cleaner move is to split the content model so future feature documentation has a natural home. Otherwise every new API surface will pressure this same file and the test will keep becoming a budget waiver instead of a maintainability guard.

Example
A future endpoint addition can add another ~25 lines before this guard trips, keeping the main dkg-node skill as the dumping ground instead of forcing a split into focused referenced material.

Suggested direction
Treat the failing 950-line budget as a design signal. Keep dkg-node/SKILL.md as the concise routing/overview artifact and move expanded contracts or workflows into focused referenced docs, rather than ratcheting the cap upward.

For Agents
Look at packages/cli/skills/dkg-node/SKILL.md and the skill-serving routes. Preserve the newly documented resident-author behavior, but extract long secondary sections into a dedicated referenced skill/reference endpoint or trim duplicated API teaching so the primary skill remains comfortably below the prior budget. Keep a line-budget test that fails before the doc approaches 1k lines again.

});
});

Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@origintrail-official/dkg-core",
"version": "10.0.9",
"version": "10.0.10",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/epcis/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@origintrail-official/dkg-epcis",
"version": "10.0.9",
"version": "10.0.10",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
9 changes: 8 additions & 1 deletion packages/epcis/src/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,14 @@ export function assertWithinTraversalLimits(
}

export function createValidator(): EpcisValidator {
const ajv = new (Ajv as unknown as typeof Ajv.default)({ allErrors: true, strict: false, validateFormats: true });
// This validator runs on attacker-controlled HTTP payloads. The traversal
// guard below bounds input shape, while fail-fast schema validation prevents
// a wide invalid document from accumulating one error object per bad node.
const ajv = new (Ajv as unknown as typeof Ajv.default)({
allErrors: false,
strict: false,
validateFormats: true,
});
(addFormats as unknown as typeof addFormats.default)(ajv);
const validateSchema = ajv.compile(epcisSchema);

Expand Down
Loading
Loading