Conversation
Add CLAUDE.md guidance for the Understand-Anything Claude Code plugin (install, daily usage, refresh process, repo-specific gotchas) and gitignore the scratch + dashboard local-diff outputs while keeping knowledge-graph.json committed so the dashboard works for the next developer without re-running a full index.
… refs
Bracket indexing already works inside the stored {{@nodeid:Label.field}}
template grammar; only bare references like step2[1] fail. Replace the
cryptic 'only allowed on workflow variables' message with one that points
at the supported grammar, and document tuple/array indexing (and that it
applies in conditions) in the agent-facing template syntax reference.
…ance check Surface a configure-time warning when a web3/write-contract node calls a known ERC-20/4626 spend method (transferFrom, redeem, withdrawFrom) and the workflow has no web3/check-allowance node, so authors catch insufficient allowance reverts before execution. Pure check in the fast validator (no network call) so it always runs, not only under opt-in deep validation.
Each action schema now carries an optional outputSchema (JSON Schema) alongside inputs, synthesized from outputFields or a statically declared schema, so agents stop probing for output keys. Extracted into a pure, unit-tested helper.
Recursively map ABI component names onto tuple and tuple-array return values in read-contract and batch-read-contract via a shared structureAbiResult helper, so downstream steps read result.liquidityIndex instead of reverse- engineering positional indices. Also fixes a double-wrapping bug for single array outputs in batch-read. Builder autocomplete surfaces the nested paths. BREAKING: web3/read-contract tuple outputs are now named objects, not positional arrays. Workflows reading result[1] must switch to result.<field>.
…assumption Strip one array dimension per recursion so tuple[][] structures correctly instead of flattening the inner dimension. Document that read-contract's single-output normalization relies on the EVM adapter auto-unwrapping single outputs.
- Ship initial knowledge graph (.understand-anything/knowledge-graph.json, 356K, 145 files indexed) so teammates can open /understand-dashboard without a full re-index on first use. - Gitignore meta.json (timestamp churn) and fingerprints.json (per-machine incremental cache) to keep PR diffs clean. Commit config.json and .understandignore as shared team settings. - Disable autoUpdate post-commit hook in config.json — it would otherwise modify the graph on every commit and pollute feature-PR diffs. Refresh cadence (weekly + after big refactors) documented in CLAUDE.md. - Add orientation pointers to /add-protocol, /fix-issue, and /develop-plugin: spend cheap graph-lookups before dispatching research subagents. - Enable the plugin in .claude/settings.json so teammates with the plugin installed see it auto-enabled. - Document install + usage in README.md (brief; CLAUDE.md has the deeper guidance).
…thing-setup chore: wire Understand-Anything codebase graph into team workflow
KEEP-612 substrate so detection-v0 alerts can ship. Adds three signal sources and the schema columns behavioral alerts need to group by: Signal sources: - Deactivated-login Sentry + structured stdout emit from better-auth session/account hooks and the org API-key auth path - Backstop-trigger reject (ERRCODE 42501) capture wrapping every workflow_executions insert; original pg error still propagates - Pre-execution content scanner for IMDS IPv4, information_schema, pg_catalog, neon_auth, refresh_token, client_secret, DATABASE_URL. Matched values never leak to alert payloads (verified by test). Attribution columns on workflow_executions (migration 0088, nullable, no backfill): triggered_by_user_api_key_id (FK api_keys), triggered_by_org_api_key_id (FK organization_api_keys), triggered_by_ip, triggered_by_country (cf-ipcountry), trigger_source. All four execution insert sites updated to populate. Alert routing lives in techops_infrastructure (separate PR adds the Loki rule module). Tests: 49 passing (35 unit + 14 integration), incl. spec-test that asserts the deactivated-login capture fires on both session and account surfaces. Out of scope (deferred per IMPLEMENTATION_PLAN.md): the behavioral alert rules themselves, runtime-payload scanning beyond static config, ASN enrichment beyond country, KeeperhubSecurityPagerduty provisioning, SAFE_FETCH_ENFORCE flip.
Round-up of the in-branch follow-ups from the post-substrate audit: - Invitation rate limiter now derives its bucket key from the trusted- proxy IP helper (getRequestSourceIp) so a caller can no longer rotate `x-forwarded-for` per request to defeat the limit. 7 unit tests cover the trusted-CF path and the spoofed-XFF collapse to the shared unknown bucket. - Content scanner now scans triggerInput alongside static node config. Each hit carries source: "config" | "trigger_input", deduped by (source, nodeId, pattern) so a pattern that appears in both surfaces emits two rows. Matched values still never leak to alert payloads. Intermediate-node outputs are intentionally not scanned -- too noisy and not the attacker entry point. - New cron endpoint /api/cron/security-behavioral-scan implements the first of three behavioral signals: any execution within the last 5 minutes by a user whose account is < 15 minutes old. Emits a structured security.behavioral.new_account_first_workflow log line per row. Needs an external scheduler (K8s CronJob) to invoke every 5 minutes -- terraform is a small follow-up. - triggered_by_country migration column already populated; design doc added at specs/security/asn-enrichment.md comparing three options (MaxMind GeoLite2, CF Enterprise header, hybrid) so the team can pick when behavioral alerting becomes a priority. - IMPLEMENTATION_PLAN.md updated with Stage 5 status + the items that remain genuinely out of scope (per-owner throughput needs org_slug metric label; country-drift needs a per-key country-history table). Tests: 70 passing across 6 files. No new lint or type errors; the two pre-existing lint warnings in lib/security/trusted-proxies.ts predate this branch. Companion infra PR adds the safe_fetch SSRF blocks Grafana alert and the new_account_first_workflow Loki alert.
Round-2 self-review fixes for KEEP-612 detection layer. Critical: register keeperhub_safe_fetch_blocks_total in the Prometheus collector counterMap. Without this, lib/safe-fetch.ts increments hit the unknown-metric warn path and the Grafana safe_fetch_blocks_alert sits at no_data forever. Medium: tighten the behavioral-cron auth bypass so a configured CRON_SECRET always wins, even if NODE_ENV is misconfigured to "test" in prod. Pre-fix logic bypassed unconditionally for dev/test envs; post-fix only bypasses when no secret is set. Medium: dual-emit the behavioral-cron signal to Sentry alongside the structured stdout line, matching the pattern the other security capture sites use. Triagers now get rich Sentry grouping plus the durable Loki path. Cosmetic: swap raw sql-template join for eq() in the cron query. Tests: extended security-behavioral-scan tests from 5 to 7 -- the new ones assert the Sentry mirror fires with the expected tag/extra shape and that a configured CRON_SECRET overrides the dev/test bypass. Audit doc: reviews/review-20260526-140001-ad204d.md documents the findings and the rationale for what was/wasn't fixed in this round.
Two post-rebase CI fixes: - lib/security/content-scanner.ts: TypeScript can't narrow Array.isArray on a union member that's a readonly array, so the bare-array branch was failing typecheck on CI. Switch to discriminating via the `nodes` property using `in`; one cast for the array branch which TS still can't narrow without the discriminant. - Delete tests/unit/invite-fetch-rate-limit.test.ts. It pinned the spoofable XFF behaviour that Codex flagged in the first review round. The new tests/unit/invitation-rate-limit.test.ts (added in 482d921) covers both the now-trusted IP path and the rate-window semantics the old file tested, so this is a deletion not a regression.
Drop the message-substring match in withBackstopCapture. The earlier
draft gated on both ERRCODE 42501 AND a fragment match against the
trigger's RAISE text, which silently breaks the detection if the
trigger message is ever reworded. 42501 ("insufficient_privilege")
is rare enough on a workflow_executions INSERT path that the false-
positive risk of dropping the message gate is acceptable.
Also documents that the sessions backstop installed in migration
0090 uses a custom SQLSTATE 'KH001' and fires inside better-auth's
session insert flow, which is intentionally out of scope for this
wrapper -- if/when we add Sentry coverage for that path it lives
in lib/auth.ts around the better-auth call, not here.
Test updated to assert the new ERRCODE-only behaviour.
Addresses PR review item #1.
Adopt the agentic-wallet-sweeper auth pattern: require CRON_SECRET unconditionally, no NODE_ENV dev/test bypass. The previous logic allowed unauth'd hits when NODE_ENV was "development" or "test" and no secret was set -- a prod container booting with NODE_ENV=test (the misconfig the v2 review flagged) would have opened the endpoint. Local dev now sets CRON_SECRET in .env to invoke via curl, same as the existing sweeper. Tests updated: removed the bypass-in-test assertion, added an explicit "401 when NODE_ENV=test and no secret" test to pin the misconfig path closed. Addresses PR review item #2.
The session.create.before and account.create.before hooks both call captureMessage on a deactivated-user attempt before returning false. A Sentry transport throw inside either hook would propagate out of better-auth and surface as a generic login error instead of the silent deactivated-user deny we want. All other capture sites in this PR (lib/api-key-auth.ts, lib/security/backstop-capture.ts, lib/security/content-scanner.ts, and the behavioral cron) already wrap in try/catch; these two were the only outliers. Wrapped for consistency. Addresses PR review item #4.
Expand the doc comment on TriggerSource to explicitly note it is a strict superset of TriggerType (lib/metrics/types.ts). TriggerType is the Prometheus-label vocabulary; TriggerSource adds mcp and internal to distinguish auth paths that the metric label set conflates -- a workflow with a manual trigger node can be invoked via the MCP marketplace path OR a direct API call, and the security attribution column wants to tell them apart even though both report "manual" to Prometheus. Adds a guard-rail note that the cast direction (TriggerType -> TriggerSource) in execute/route.ts is the safe direction; inverting it would be unsound. Addresses PR review item #6.
IMPLEMENTATION_PLAN.md is the stage-tracking doc the global CLAUDE.md philosophy guide instructs to remove once all stages are done. All stages are done. Reviewer also called these out as PR-meta artifacts that belong in the PR description or wiki, not in the source tree. reviews/review-20260526-140001-ad204d.md is the review-loop output from round 2 of self-review; it served its purpose during iteration and shouldn't ship in repo. specs/security/asn-enrichment.md is kept -- per the project CLAUDE.md convention, specs/ is the correct home for internal design docs (docs/ is public-facing). It's a durable design artifact, not PR meta. Addresses PR review item #7.
result[1] no longer works on tuple/struct read-contract outputs - the new decoder makes result a named object, so the executor throws "result is not an array" at runtime. Update the actionable validator error message and the agent-facing TEMPLATE_SYNTAX so they steer authors toward result.<componentName> for tuples and reserve bracket indexing for genuine array fields inside the path.
…bstrate feat(security): detection layer v0 substrate
…t docs - chains: add status column (stable/experimental/deprecated), default stable; 0G mainnet and Galileo seeded as experimental - mcp: surface per-chain status in list_action_schemas (/api/mcp/schemas) and note it in the tool description so agents avoid experimental chains - dashboard: show the MCP endpoint URL with a copy button in the API keys overlay - docs: add Hackathon Quickstart page consolidating supported chains, USDC addresses, faucets, API key types, rate limits, and the MCP endpoint
…rgonomics feat: improve contract-call and action-schema ergonomics
…chemas A future refactor of the chains select map in the schemas endpoint would silently drop the status field with no compile-time signal; this test locks it in. Three cases: every chain row carries a string status; row values (stable / experimental) propagate verbatim; the includeChains=false short-circuit still works (so the new field does not accidentally become mandatory). Lives under tests/integration so the existing test-integration CI job picks it up; no new workflow needed.
…start-matrix feat: surface per-chain support status, MCP endpoint URL, and hackathon quickstart
…n scripts Ethers v6 inlines info.requestUrl (which can include an API key) into Error.message. Scripts that logged error.message could leak the key on any RPC failure. The primary leak fired in CI for scripts/seed/seed-tokens.ts when chain 43114 (AVAX) hit a 403 from a misconfigured Alchemy app. Add lib/rpc/scrub-rpc-urls.ts (regex-based URL/key scrubber masking known provider key paths and stripping query strings) and lib/rpc/sanitize-rpc-error.ts (ethers-aware normalizer that prefers error.shortMessage, falls back to a scrubbed error.message, and preserves error.code for retry-decision callers). Apply formatSanitizedRpcError() in six scripts that previously logged error.message verbatim: seed-tokens.ts, verify-token.ts, register-agent.ts, update-agent-uri.ts, pin-agent-card.ts, frax-ether-v2-fork-test.ts. Add 25 unit tests including a structurally faithful ethers v6 SERVER_ERROR fixture; the critical assertion is that no fake test key marker survives sanitization. Operator actions outside this PR: rotate the exposed Alchemy app key and purge any retained CI logs or artifacts that still hold it.
…-ux-polish feat: workflow editor UX polish (name field, run-panel tooltips, faucet, workflowType auto-flip)
…suite Add an explicit dRPC pattern (lb.drpc.live/<chain>/<key>) so a future shorter dRPC key still gets caught and the chain segment stays visible in masked output; previously the generic 32+ char fallback handled it. Add a regression suite that walks every URL shape currently present in CHAIN_RPC_CONFIG with fake keys matching real-key charset and length. If a new provider lands in the config that this scrubber misses, the corresponding fake key survives and the test fails loudly. Coverage now includes: TechOps proxy, Flashbots, publicnode, binance, polygon.technology, arbitrum.io, solana official, tempo.xyz, Ankr public (all no-secret round-trip); Alchemy v2 (variable key length), Alchemy wss, dRPC https/wss including dashed chain names, and QuickNode with and without trailing slash.
…-seed-tokens fix: sanitize ethers v6 error logs to prevent RPC key leak in scripts
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.
No description provided.