From be5f369f35a0a886aefc489b41100fe5413e61fe Mon Sep 17 00:00:00 2001 From: Volodymyr Vreshch Date: Mon, 1 Dec 2025 23:21:37 +0100 Subject: [PATCH] feat: add SHA256 content hashing to agent registry Add contentHash (SHA256) to agent versions to support agent.lock.json on the CLI side. Changes: - Add latestContentHash to AgentDocument and agents collection schema - Add contentHash to AgentVersionDocument and agent_versions collection schema - Add computeContentHash helper function using Node.js crypto module - Compute and store SHA256 hash when publishing agents - Include contentHash in API responses: - POST /api/agents returns contentHash in publish response - GET /api/agents/:owner/:name returns latestContentHash - GET /api/agents/:owner/:name versions array includes contentHash - GET /api/agents/:owner/:name/versions/:version returns contentHash This enables: - Integrity verification: Verify installed agents match registry content - Lock file support: Track exact versions with cryptographic hashes - Reproducible installs: Guarantee identical agent content across environments --- .../src/collections/agent-versions.collection.ts | 1 + .../backend/src/collections/agents.collection.ts | 1 + packages/backend/src/routes/agents/get-agent.ts | 1 + packages/backend/src/routes/agents/publish.ts | 1 + packages/backend/src/services/agent.service.ts | 16 +++++++++++++++- .../backend/src/utils/agent-response.mapper.ts | 2 ++ packages/shared/src/types/agent.types.ts | 5 +++++ 7 files changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/collections/agent-versions.collection.ts b/packages/backend/src/collections/agent-versions.collection.ts index 848c3a6..8e79bba 100644 --- a/packages/backend/src/collections/agent-versions.collection.ts +++ b/packages/backend/src/collections/agent-versions.collection.ts @@ -22,6 +22,7 @@ export const agentVersionsCollectionSchema = z.object({ agentId: z.string(), version: z.string().regex(/^\d+\.\d+\.\d+$/), content: z.string().max(100000), + contentHash: z.string().length(64), // SHA256 hex = 64 chars changelog: z.string().max(1000).optional(), isLatest: z.boolean(), downloads: z.number().int().min(0), diff --git a/packages/backend/src/collections/agents.collection.ts b/packages/backend/src/collections/agents.collection.ts index 89db8c4..21c652b 100644 --- a/packages/backend/src/collections/agents.collection.ts +++ b/packages/backend/src/collections/agents.collection.ts @@ -44,6 +44,7 @@ export const agentsCollectionSchema = z.object({ readme: z.string().max(50000).optional(), latestVersion: z.string().regex(/^\d+\.\d+\.\d+$/), latestContent: z.string().max(100000), + latestContentHash: z.string().length(64), // SHA256 hex = 64 chars totalDownloads: z.number().int().min(0), stars: z.number().int().min(0), forks: z.number().int().min(0), diff --git a/packages/backend/src/routes/agents/get-agent.ts b/packages/backend/src/routes/agents/get-agent.ts index f34c4d3..d882432 100644 --- a/packages/backend/src/routes/agents/get-agent.ts +++ b/packages/backend/src/routes/agents/get-agent.ts @@ -40,6 +40,7 @@ export const getAgentHandler = (serviceProvider: ServiceProvider) mappedAgent.versions = versions.map((v) => ({ version: v.version, agentVersion: v.agentVersion, + contentHash: v.contentHash, publishedAt: v.publishedAt.toISOString(), downloads: v.downloads, isLatest: v.isLatest, diff --git a/packages/backend/src/routes/agents/publish.ts b/packages/backend/src/routes/agents/publish.ts index 604c217..a71a4dc 100644 --- a/packages/backend/src/routes/agents/publish.ts +++ b/packages/backend/src/routes/agents/publish.ts @@ -41,6 +41,7 @@ export const publishAgentHandler = (serviceProvider: ServiceProvider