Skip to content

release: to prod#1329

Merged
suisuss merged 10 commits into
prodfrom
staging
May 21, 2026
Merged

release: to prod#1329
suisuss merged 10 commits into
prodfrom
staging

Conversation

@eskp

@eskp eskp commented May 21, 2026

Copy link
Copy Markdown

Summary

Promote the following merged PRs from staging to prod:

Post-deploy verification

  • deploy-keeperhub workflow finishes green
  • curl -fsS https://app.keeperhub.com/api/health returns 200
  • Blockscout actions expose a working Chain selector (Base/Optimism/etc. query the right instance; unmapped chain errors instead of falling back to Ethereum)
  • validate_workflow no longer rejects template-valued address fields (fix(mcp): skip template-valued addresses in validate_workflow address check #1325)
  • Watch Sentry / logs for ~10 minutes after the rollout

eskp and others added 7 commits May 21, 2026 07:51
… check

tokenAddressFormat ran ethers.isAddress() on any non-empty contractAddress
(and embedded tokenConfig.customToken.address). When the field holds a
runtime template reference such as `{{@prep:Prep.governor_address_safe}}`
-- which resolves to a real address at execution time -- the literal format
check failed and emitted a false invalid-token-address. governance-scanner
workflows that build their target address from a prior node flunked
validate_workflow despite executing fine.

Skip values containing a `{{...}}` template token before the isAddress
check, for both contractAddress and the embedded tokenConfig address.
Literal addresses are still validated; advisory-only (validateWorkflow is
not on the save/listing path).

KEEP-576
…sses

A contractAddress containing any {{...}} token is dynamic and cannot be
statically format-checked, so it is skipped even with a literal-looking
prefix. Locks the boundary two reviewers flagged.
…ution

collectContractRefs fed any non-empty contractAddress to resolveAbi during
the deep tier. A template reference like {{@prep:Prep.governor_address_safe}}
resolves to a real address only at execution time, so the literal template
always mismatched and emitted a spurious low-confidence-abi-match warning.
Skip refs whose contractAddress is a template token, reusing the
isTemplateReference helper now exported from validate-workflow-web3.

KEEP-576
Each Blockscout action now has an optional Chain selector that maps a chain
ID to its hosted Blockscout instance, so a workflow can query Base, Optimism,
Arbitrum, Gnosis, Polygon, the testnets, or Ethereum without configuring a
connection.

- Add BLOCKSCOUT_INSTANCES (chainId -> instance URL) and resolveInstance() in
  blockscout-core. Precedence: connection instance URL (self-hosted/rate-limit
  override) > selected chain's hosted instance > Ethereum mainnet default.
- A selected chain with no known hosted instance and no connection now errors
  instead of silently falling back to Ethereum.
- Thread an optional `network` (chain-select) input through all five actions;
  omitting it preserves the previous Ethereum-mainnet default, so existing
  workflows are unaffected.
- Document supported chains and update unit tests (19 pass).

Instance URLs verified live against each chain's Blockscout v2 API.
Move the chainId -> instance map to a client-safe chains.ts shared by the
plugin definition and the step runtime. The Chain selector's allowedChainIds
now derives from the same map instead of a hand-maintained list, so adding a
chain is genuinely a one-line edit and the dropdown can't drift from the
instances the runtime actually supports. (The map can't be imported from
blockscout-core directly because that file is server-only and index.ts is
client-loaded.)
fix(mcp): skip template-valued addresses in validate_workflow address check
…hain-select

feat(blockscout): add chain selector for zero-config multi-chain queries
suisuss added 3 commits May 21, 2026 19:43
Extends safe-fetch buildBlockList with four IPv6 CIDRs (RFC 8215 site-local
NAT64 64:ff9b:1::/48, Teredo 2001::/32, 6to4 2002::/16, documentation
2001:db8::/32) and adds a pre-DNS hostname denylist (isBlockedHost) covering
localhost, *.local, *.internal, *.svc.cluster.local, *.pod.cluster.local.
Both checks are wired into safeFetch and assertUrlIsPublic.

Introduces assertConnectionUrlIsPublic as the single source of truth for
non-HTTP outbound plugins. Wires it into the workflow database-query step
(which previously called postgres.js with zero host validation) and into
the existing test-connection endpoint.

Tests cover all new CIDRs, the hostname denylist, the new SoT helper, and
a regression assertion that the SoT never leaks the input connection
string into error messages.
In shadow mode, a single request to a blocked target previously recorded
two safe_fetch.blocks.total events: once from the entry-point check
(pre-DNS hostname pattern, or IP-literal isBlockedIp), and again from the
connector's post-DNS isBlockedIp after `localhost` -> 127.0.0.1 or for
the IP literal itself. Inflated the exploit-attempt counter by 2x for
those cases.

Threads an `initialBlockRecorded` flag through pluginContext so the
connector skips its own recordBlock when the synchronous check has
already counted the request. Shadow-mode "log and continue" semantics
preserved - the connect still attempts and the connector still throws
in enforce mode; only the duplicate counter increment is suppressed.

Tightens the existing IP-literal shadow-mode test to assert exactly one
block call. Adds a regression test for the hostname-pattern shadow path
(localhost).
…-guard

hotfix: SSRF guard parity across HTTP and database plugins
@suisuss suisuss merged commit 0f218a7 into prod May 21, 2026
22 of 23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants