ci(registry): PR validation, preview comments, and tightened triggers#807
Merged
ci(registry): PR validation, preview comments, and tightened triggers#807
Conversation
Add two zero-dependency validation scripts: - validate-env-schema.js: validates all env/*.json files against the expected schema (required network.chainId, valid addresses, known top-level keys). Fast-fail gate before registry generation. - validate-registry.js: validates generated registry JSON against indexer hard requirements (version, previousRegistry.ipfsHash, startBlock, blockNumber, address, ABI completeness). Produces a sidecar .validation.json report for CI consumption.
- Add env/** and script/registry/** to pull_request paths trigger so PRs touching env files run the registry pipeline before merge - Add paths filter to push trigger (only run on env/registry changes) - Remove release trigger (env file merges are the canonical signal) - Add validate-env-schema.js step before generation (fast-fail gate) - Add validate-registry.js step after generation (indexer requirements) - Add PR preview comment with registry summary, errors, and warnings - Update pin-to-ipfs condition to remove release event - Update README with pipeline diagram, validation docs, and indexer hard/soft requirements tables
Use dnslink TXT record lookup (_dnslink.registry.centrifuge.io) to resolve the IPFS CID of the currently live registry at generation time. This is the source of truth — the DNS record points to whatever CID Cloudflare is actually serving. Eliminates the need for Pinata API key during generation and removes the fragile metadata-based lookup. SOURCE_IPFS env var still works as an explicit override. Also reverts previousRegistry.ipfsHash back to an error in the validator since it's now filled at generation time.
…to-ipfs Update pin-to-ipfs.js to use DNS dnslink lookup as the primary method for resolving the previous registry CID, with Pinata as a fallback. This aligns with abi-registry.js which now fills previousRegistry.ipfsHash via DNS at generation time. Both the pinning flow and --update-previous mode now follow the same resolution order: DNS first, Pinata if DNS fails.
Version extraction now falls back to contract-level version fields when deploymentInfo entries don't have a version (which is the case for all current env files). ABI name mapping now handles mismatches between env file contract keys and Forge artifact names: - Hook contracts: freezeOnlyHook → FreezeOnly (not FreezeOnlyHook) - NAV manager: navManager → NAVManager (not NavManager) - Token factory base: TokenFactory → ShareToken (not Token) Both abi-registry.js and validate-registry.js share the same override maps to stay in sync. Tested locally: 0 errors, 0 warnings, 53 ABIs packed.
tokenBridge is not a protocol contract — it has no Solidity source in this repo and no Forge build artifact. It was likely an artifact from a deployment session that leaked into the env files. It's not present in any mainnet env file.
Version extraction now picks the highest version across all contracts in a chain (e.g. v3.1 wins over 3), instead of the first one found. This handles chains where root kept its original v3 version while all other contracts were upgraded to v3.1. Remove warnings from validate-registry.js for fields the indexer doesn't use (txHash, deployedAt, gitCommit, previousRegistry.version). The validator now only checks what actually matters for the indexer.
lemunozm
reviewed
Apr 1, 2026
Enhance the GitHub Actions workflow by introducing an optional input for the `workflow_dispatch` event, allowing users to specify which registry to regenerate (mainnet, testnet, or both). Update the environment detection logic to accommodate this input, ensuring correct handling of changed environments based on user selection or automatic detection.
Registry Previewmainnet
✅ Passes all indexer requirements testnet
|
| Path | Message |
|---|---|
chains |
Delta registry has zero chains — nothing changed? |
✅ Passes all indexer hard requirements
Preview only — IPFS upload happens on merge to main.
Removed the optional input for `workflow_dispatch` to streamline the environment detection process. The logic now directly detects changed environments without user input, ensuring consistent behavior during CI runs. Updated conditions for pinning registry files to IPFS to enhance clarity and maintain functionality.
lemunozm
reviewed
Apr 9, 2026
lemunozm
reviewed
Apr 9, 2026
Comment on lines
+120
to
+122
| # Validate a generated registry against indexer hard requirements | ||
| node script/registry/validate-registry.js registry/registry-mainnet.json | ||
| node script/registry/validate-registry.js registry/registry-testnet.json |
Contributor
There was a problem hiding this comment.
Q. In which cases a generated registry will make fail the validation? What's the use case of this validate-registry.js script?
Collaborator
Author
There was a problem hiding this comment.
That was my way of coding in @filo87 requirements (the must-have for the indexer) to make sure whatever changes, usually as a result of changes to the registry generation code, or the env files does not break the indexer when the next deployment files are merged to main
- Require deploymentInfo.*.startBlock when any contract has blockNumber - Reject large gap vs min active contract block (chain-level indexer listeners) - Document in README; validate-registry docblock defers gap check to env step - Fix stale deployment startBlock on Arbitrum mainnet and Arbitrum Sepolia
|
Coverage after merging ci/registry-pr-validation into main will be
Coverage Report
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
gpmayorga
added a commit
that referenced
this pull request
Apr 9, 2026
Fixes unintended registry publish triggered by PR #807 merge to main. Non-contract changes (CI scripts, docs) now no longer pin to IPFS or update Cloudflare — only registries with actual contract changes do. - validate-registry.js: add `publishable` flag to summary (errors==0 && chains>0) - pin-to-ipfs.js: zero-chains guard skips pinning empty delta registries; fix FORCE_PIN="both" not bypassing the guard for all envs - registry.yml: structured workflow_dispatch input (mainnet/testnet/both); detect-changed-environments respects dispatch input; new "Validate and gate publish" step in pin-to-ipfs job re-runs validation and drops unpublishable files before pinning; Update Cloudflare step gated to push events only — workflow_dispatch pins to IPFS but never touches Cloudflare (avoids unauthorized DNSLink overwrites)
gpmayorga
added a commit
that referenced
this pull request
Apr 14, 2026
* feat(registry): add env schema and registry output validators Add two zero-dependency validation scripts: - validate-env-schema.js: validates all env/*.json files against the expected schema (required network.chainId, valid addresses, known top-level keys). Fast-fail gate before registry generation. - validate-registry.js: validates generated registry JSON against indexer hard requirements (version, previousRegistry.ipfsHash, startBlock, blockNumber, address, ABI completeness). Produces a sidecar .validation.json report for CI consumption. * ci(registry): add PR validation, preview comments, and tighten triggers - Add env/** and script/registry/** to pull_request paths trigger so PRs touching env files run the registry pipeline before merge - Add paths filter to push trigger (only run on env/registry changes) - Remove release trigger (env file merges are the canonical signal) - Add validate-env-schema.js step before generation (fast-fail gate) - Add validate-registry.js step after generation (indexer requirements) - Add PR preview comment with registry summary, errors, and warnings - Update pin-to-ipfs condition to remove release event - Update README with pipeline diagram, validation docs, and indexer hard/soft requirements tables * feat(registry): resolve previousRegistry CID via DNS instead of Pinata Use dnslink TXT record lookup (_dnslink.registry.centrifuge.io) to resolve the IPFS CID of the currently live registry at generation time. This is the source of truth — the DNS record points to whatever CID Cloudflare is actually serving. Eliminates the need for Pinata API key during generation and removes the fragile metadata-based lookup. SOURCE_IPFS env var still works as an explicit override. Also reverts previousRegistry.ipfsHash back to an error in the validator since it's now filled at generation time. * refactor(registry): use DNS dnslink as primary CID resolution in pin-to-ipfs Update pin-to-ipfs.js to use DNS dnslink lookup as the primary method for resolving the previous registry CID, with Pinata as a fallback. This aligns with abi-registry.js which now fills previousRegistry.ipfsHash via DNS at generation time. Both the pinning flow and --update-previous mode now follow the same resolution order: DNS first, Pinata if DNS fails. * fix(registry): fix version extraction and ABI name mapping Version extraction now falls back to contract-level version fields when deploymentInfo entries don't have a version (which is the case for all current env files). ABI name mapping now handles mismatches between env file contract keys and Forge artifact names: - Hook contracts: freezeOnlyHook → FreezeOnly (not FreezeOnlyHook) - NAV manager: navManager → NAVManager (not NavManager) - Token factory base: TokenFactory → ShareToken (not Token) Both abi-registry.js and validate-registry.js share the same override maps to stay in sync. Tested locally: 0 errors, 0 warnings, 53 ABIs packed. * fix(env): remove tokenBridge from testnet env files tokenBridge is not a protocol contract — it has no Solidity source in this repo and no Forge build artifact. It was likely an artifact from a deployment session that leaked into the env files. It's not present in any mainnet env file. * refactor(registry): use highest version and trim non-indexer warnings Version extraction now picks the highest version across all contracts in a chain (e.g. v3.1 wins over 3), instead of the first one found. This handles chains where root kept its original v3 version while all other contracts were upgraded to v3.1. Remove warnings from validate-registry.js for fields the indexer doesn't use (txHash, deployedAt, gitCommit, previousRegistry.version). The validator now only checks what actually matters for the indexer. * feat(registry): add workflow_dispatch input for environment selection Enhance the GitHub Actions workflow by introducing an optional input for the `workflow_dispatch` event, allowing users to specify which registry to regenerate (mainnet, testnet, or both). Update the environment detection logic to accommodate this input, ensuring correct handling of changed environments based on user selection or automatic detection. * refactor(registry): simplify environment detection logic in CI workflow Removed the optional input for `workflow_dispatch` to streamline the environment detection process. The logic now directly detects changed environments without user input, ensuring consistent behavior during CI runs. Updated conditions for pinning registry files to IPFS to enhance clarity and maintain functionality. * feat(registry): deprecations in delta and per-tag ABI cache - Emit contracts removed from env vs previous registry as address null - Skip deprecated entries in packAbis; document schema in README - Build ABIs per contract version: resolve git tag (v-prefix, .0 patch) - Cache Forge out/ under cache/abi-registry/<tag>/ via worktrees - Preserve contract version through processContracts for tag resolution - Map env names to Forge artifacts (ShareToken, NAVManager, hooks) * docs(registry): example delta JSON and consumer note for deprecations * ci(registry): align workflow with per-tag ABI cache - Remove single-commit worktree forge + out/ copy (abi-registry builds per tag) - Fetch git tags before generation for version-tag worktrees - Keep DEPLOYMENT_COMMIT for registry metadata only - Update README pipeline and detect-deployment-commit descriptions * feat(registry): validate env versions and git tags before registry work - validateEnvContractVersionTags: require version, cross-file consistency, resolvable tags - Run at start of main() before live registry fetch - Run registry workflow on PRs touching env/ or script/registry/ - Document early validation in README * ci(registry): fail early when env contract version has no git tag - Extract tag-resolution.js for shared version→tag logic - Add validate-env-contract-version-tags.js; run after fetch-tags in registry.yml - Expand PR path filters to env/, script/registry/, ci-scripts/ - Document validation in README * refactor(registry): move tag-resolution and env tag validator to utils Colocate shared tag helpers with other registry utilities. CI runs the validator from script/registry/utils; abi-registry imports ./utils/tag-resolution.js. README and workflow paths updated. * fix(registry): skip contracts already deprecated in live registry for deltas When the live registry is a delta that already carries address:null deprecations, do not re-emit those keys each run. Avoids growing redundant null entries, spurious chain inclusion, and inflated deprecation counts. * refactor(registry): remove contract version from output for smaller registries - Introduced `stripContractVersionsForRegistryOutput` to omit `version` fields from chains before JSON output, reducing size for published registries. - Updated README to reflect changes in contract data structure. * docs: add Claude Code registry rule and CLAUDE.md pointer Path-scoped .claude/rules/registry.md for script/registry, env, and registry CI. Root CLAUDE.md links README and rule; notes Cursor vs Claude rule layout. * docs: drop registry subsection from CLAUDE.md Registry workflow remains documented in script/registry/README.md and .claude/rules/registry.md for Claude Code path rules. * fix(registry): treat top-level version as optional in validate-registry Omitting registry.version is valid when provenance uses deploymentInfo.gitCommit; pass validation instead of failing when the field is absent. * refactor(registry): extract per-tag ABI cache into utils module - Add utils/abi-cache.js (ensureAbiCache, collectContractTags, findAbiInOutput, aliases) - Add build-abi-cache.js CLI to warm cache/abi-registry without full registry run - Thin abi-registry packAbis around shared module; document in .claude/rules/registry.md * docs(registry): document ABI cache on-disk layout - README: tree, lifecycle, programmatic reads, build-abi-cache CLI; table links - abi-cache.js: module header mirrors layout + README pointer - Claude registry rule: point AI/humans to README ABI cache section * feat(registry): validate deployment startBlock in env schema - Require deploymentInfo.*.startBlock when any contract has blockNumber - Reject large gap vs min active contract block (chain-level indexer listeners) - Document in README; validate-registry docblock defers gap check to env step - Fix stale deployment startBlock on Arbitrum mainnet and Arbitrum Sepolia * add branch main to registry job * docs(registry): explain how to find SOURCE_IPFS value locally * refactor(registry): remove dead ABI_NAME_OVERRIDES and FACTORY_BASE_OVERRIDES These constants were superseded by ABI_NAME_ALIASES in utils/abi-cache.js but survived the merge from main. packAbis now uses resolveArtifactName() from the shared module instead. * ci(registry): smart auto-publish with validation gate Fixes unintended registry publish triggered by PR #807 merge to main. Non-contract changes (CI scripts, docs) now no longer pin to IPFS or update Cloudflare — only registries with actual contract changes do. - validate-registry.js: add `publishable` flag to summary (errors==0 && chains>0) - pin-to-ipfs.js: zero-chains guard skips pinning empty delta registries; fix FORCE_PIN="both" not bypassing the guard for all envs - registry.yml: structured workflow_dispatch input (mainnet/testnet/both); detect-changed-environments respects dispatch input; new "Validate and gate publish" step in pin-to-ipfs job re-runs validation and drops unpublishable files before pinning; Update Cloudflare step gated to push events only — workflow_dispatch pins to IPFS but never touches Cloudflare (avoids unauthorized DNSLink overwrites)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
validate-env-schema.js) catches broken JSON, missingnetwork.chainId, invalid addresses, and structural renames before registry generation even starts.validate-registry.js) checks the 6 hard requirements the Ponder indexer needs:version,previousRegistry.ipfsHash,startBlock,address,blockNumber, and ABI completeness. Errors block the PR; warnings are shown but don't block.env/**gets a comment with the registry summary (version, chains, contracts, ABIs) plus any validation errors/warnings, so reviewers can see exactly what would be published.env/**,script/registry/**, or the workflow file itself changes. Thereleasetrigger is removed (env file merges to main are the canonical signal). This keeps the GHA log clean.Pipeline flow
flowchart TD A[env file changed] --> B[Validate env schemas] B -->|fail| X1[PR blocked] B -->|pass| C[Detect changed environments] C --> D[Generate registry] D --> E[Validate registry output] E -->|errors| X2[PR blocked] E -->|pass/warnings| F[Post PR comment] F --> G{Merged to main?} G -->|no| H[Done] G -->|yes| I[Pin to IPFS] I --> J[Update Cloudflare DNS]Indexer hard requirements (enforced by
validate-registry.js)versionpreviousRegistry.ipfsHashchains.<chainId>.deployment.startBlockchains.<chainId>.contracts.<name>.addresschains.<chainId>.contracts.<name>.blockNumberabis.<ContractName>