From 8c8c5e0c1acfbd51501b9ccaf6a1e06e2feb70be Mon Sep 17 00:00:00 2001 From: LingX Date: Thu, 18 Jun 2026 14:59:59 -0400 Subject: [PATCH 1/2] Validate non-file manifest fields with file sources --- packages/cli/src/subgraph.ts | 48 ++++++++++++++----- .../cli/__snapshots__/validation.test.ts.snap | 14 ++++++ packages/cli/tests/cli/validation.test.ts | 8 ++++ .../Abi.json | 7 +++ .../mapping.ts | 1 + .../schema.graphql | 3 ++ .../subgraph.yaml | 38 +++++++++++++++ 7 files changed, 107 insertions(+), 12 deletions(-) create mode 100644 packages/cli/tests/cli/validation/file-data-source-invalid-manifest/Abi.json create mode 100644 packages/cli/tests/cli/validation/file-data-source-invalid-manifest/mapping.ts create mode 100644 packages/cli/tests/cli/validation/file-data-source-invalid-manifest/schema.graphql create mode 100644 packages/cli/tests/cli/validation/file-data-source-invalid-manifest/subgraph.yaml diff --git a/packages/cli/src/subgraph.ts b/packages/cli/src/subgraph.ts index 90bcea2fe..b05d7ab42 100644 --- a/packages/cli/src/subgraph.ts +++ b/packages/cli/src/subgraph.ts @@ -37,6 +37,31 @@ const buildCombinedWarning = (filename: string, warnings: immutable.List) = type ResolveFile = (path: string) => string; +const isFileDataSourceKind = (kind: unknown) => + typeof kind === 'string' && (kind === 'file' || kind.startsWith('file/')); + +const hasFileDataSources = (data: any) => { + const hasFileKind = (entries: any) => + Array.isArray(entries) && entries.some(entry => isFileDataSourceKind(entry?.kind)); + + return hasFileKind(data?.dataSources) || hasFileKind(data?.templates); +}; + +const omitFileDataSources = (data: any) => { + if (data == null || typeof data !== 'object' || Array.isArray(data)) { + return data; + } + + const omitFileKind = (entries: any) => + Array.isArray(entries) ? entries.filter(entry => !isFileDataSourceKind(entry?.kind)) : entries; + + return { + ...data, + dataSources: omitFileKind(data.dataSources), + templates: omitFileKind(data.templates), + }; +}; + export default class Subgraph { static async validate(data: any, protocol: any, { resolveFile }: { resolveFile: ResolveFile }) { subgraphDebug.extend('validate')('Validating Subgraph with protocol %M', protocol); @@ -266,26 +291,25 @@ More than one template named '${name}', template names must be unique.`, subgraphDebug('Loading manifest from %s', filename); const raw_data = await fs.readFile(filename, 'utf-8'); subgraphDebug('Checking for file data sources in %s', filename); - has_file_data_sources = raw_data.includes('kind: file'); subgraphDebug('Parsing manifest from %s', filename); data = yaml.parse(raw_data); + has_file_data_sources = hasFileDataSources(data); } // Helper to resolve files relative to the subgraph manifest const resolveFile: ResolveFile = maybeRelativeFile => path.resolve(path.dirname(filename), maybeRelativeFile); - // TODO: Validation for file data sources - if (!has_file_data_sources) { - subgraphDebug('Validating manifest from %s', filename); - const manifestErrors = await Subgraph.validate(data, protocol, { - resolveFile, - }); - - if (manifestErrors.size > 0) { - subgraphDebug('Manifest validation failed for %s', filename); - throwCombinedError(filename, manifestErrors); - } + // TODO: Complete schema validation for file data sources themselves. + const dataForValidation = has_file_data_sources ? omitFileDataSources(data) : data; + subgraphDebug('Validating manifest from %s', filename); + const manifestErrors = await Subgraph.validate(dataForValidation, protocol, { + resolveFile, + }); + + if (manifestErrors.size > 0) { + subgraphDebug('Manifest validation failed for %s', filename); + throwCombinedError(filename, manifestErrors); } const manifest = immutable.fromJS(data) as immutable.Map; diff --git a/packages/cli/tests/cli/__snapshots__/validation.test.ts.snap b/packages/cli/tests/cli/__snapshots__/validation.test.ts.snap index ea81066dc..575b5dcd8 100644 --- a/packages/cli/tests/cli/__snapshots__/validation.test.ts.snap +++ b/packages/cli/tests/cli/__snapshots__/validation.test.ts.snap @@ -443,6 +443,20 @@ Types generated successfully " `; +exports[`Validation > File data source does not skip regular manifest validation 1`] = ` +"- Load subgraph from subgraph.yaml +✖ Failed to load subgraph from subgraph.yaml: Error in subgraph.yaml: + + Path: dataSources > 0 > network + Expected string, found number: + 11155111 +" +`; + +exports[`Validation > File data source does not skip regular manifest validation 2`] = `1`; + +exports[`Validation > File data source does not skip regular manifest validation 3`] = `""`; + exports[`Validation > Invalid @fulltext directive 1`] = ` "- Load subgraph from subgraph.yaml ✖ Failed to load subgraph from subgraph.yaml: Error in schema.graphql: diff --git a/packages/cli/tests/cli/validation.test.ts b/packages/cli/tests/cli/validation.test.ts index aeb90211a..31cc1d586 100644 --- a/packages/cli/tests/cli/validation.test.ts +++ b/packages/cli/tests/cli/validation.test.ts @@ -110,6 +110,14 @@ describe('Validation', { concurrent: true, timeout: 60_000 }, () => { exitCode: 0, }, ); + cliTest( + 'File data source does not skip regular manifest validation', + ['codegen', '--skip-migrations'], + 'validation/file-data-source-invalid-manifest', + { + exitCode: 1, + }, + ); cliTest( 'Invalid data source template', ['codegen', '--skip-migrations'], diff --git a/packages/cli/tests/cli/validation/file-data-source-invalid-manifest/Abi.json b/packages/cli/tests/cli/validation/file-data-source-invalid-manifest/Abi.json new file mode 100644 index 000000000..4d05f5839 --- /dev/null +++ b/packages/cli/tests/cli/validation/file-data-source-invalid-manifest/Abi.json @@ -0,0 +1,7 @@ +[ + { + "type": "event", + "name": "ExampleEvent", + "inputs": [{ "type": "string" }] + } +] diff --git a/packages/cli/tests/cli/validation/file-data-source-invalid-manifest/mapping.ts b/packages/cli/tests/cli/validation/file-data-source-invalid-manifest/mapping.ts new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/packages/cli/tests/cli/validation/file-data-source-invalid-manifest/mapping.ts @@ -0,0 +1 @@ + diff --git a/packages/cli/tests/cli/validation/file-data-source-invalid-manifest/schema.graphql b/packages/cli/tests/cli/validation/file-data-source-invalid-manifest/schema.graphql new file mode 100644 index 000000000..d5a41952b --- /dev/null +++ b/packages/cli/tests/cli/validation/file-data-source-invalid-manifest/schema.graphql @@ -0,0 +1,3 @@ +type MyEntity @entity(immutable: true) { + id: ID! +} diff --git a/packages/cli/tests/cli/validation/file-data-source-invalid-manifest/subgraph.yaml b/packages/cli/tests/cli/validation/file-data-source-invalid-manifest/subgraph.yaml new file mode 100644 index 000000000..3e2c4319b --- /dev/null +++ b/packages/cli/tests/cli/validation/file-data-source-invalid-manifest/subgraph.yaml @@ -0,0 +1,38 @@ +specVersion: 0.0.5 +repository: https://github.com/graphprotocol/test-subgraph +description: Test subgraph +schema: + file: ./schema.graphql +dataSources: + - kind: ethereum/contract + name: ExampleSubgraph + network: 11155111 + source: + abi: ExampleContract + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + file: ./mapping.ts + entities: + - ExampleEntity + abis: + - name: ExampleContract + file: ./Abi.json + eventHandlers: + - event: ExampleEvent(string) + handler: handleExampleEvent +templates: + - kind: file/ipfs + name: IpfsContent + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + file: ./mapping.ts + entities: + - ExampleEntity + abis: + - name: ExampleContract + file: ./Abi.json + handler: handleIpfsContent From f231e1c55aa7a5d3b2b4b77accd3663a050e4653 Mon Sep 17 00:00:00 2001 From: LingX Date: Thu, 18 Jun 2026 15:03:23 -0400 Subject: [PATCH 2/2] Add graph-cli validation changeset --- .changeset/validate-file-source-manifests.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/validate-file-source-manifests.md diff --git a/.changeset/validate-file-source-manifests.md b/.changeset/validate-file-source-manifests.md new file mode 100644 index 000000000..1f5aeae25 --- /dev/null +++ b/.changeset/validate-file-source-manifests.md @@ -0,0 +1,5 @@ +--- +'@graphprotocol/graph-cli': patch +--- + +Validate regular manifest fields when file data sources are present.