Conversation
…463) (#464) * fix(status): enable Terminal RPC module and TCP streaming for devnet ckb-tui panels were always empty on devnet because the bundled devnet ckb.toml did not meet ckb-tui's two data requirements: - the Terminal RPC module (provides get_overview system metrics), which upstream CKB now enables by default, was missing from rpc.modules, so the overview dashboards showed N/A - rpc.tcp_listen_address was commented out and the status command never passed -t, so the mempool (new/rejected transactions) and logs dashboards had no subscription stream to read from Enable both in the devnet config template and have the status command read tcp_listen_address from the running node's ckb.toml and pass it to ckb-tui via -t (wildcard binds are dialed as localhost). Testnet and mainnet keep HTTP-only behavior since their proxied public RPCs expose no TCP stream. * chore: add patch changeset for status devnet fix * fix(devnet): bind RPC to loopback instead of 0.0.0.0 Address CodeRabbit review on PR #463: with the Terminal module enabled, binding the unauthenticated JSON-RPC to 0.0.0.0 exposes host system metrics (and the rest of the RPC surface) to any host on the network. Bind to 127.0.0.1 by default; all offckb-internal consumers (proxy, ckb-tui, miner, forks) already talk to 127.0.0.1:8114. Users who need remote access can edit rpc.listen_address via the config editor. * fix(devnet): align embedded reference template with devnet ckb.toml Add Terminal to rpc.modules and enable tcp_listen_address in the config editor's embedded template so configurations based on it also provide the metrics stream that offckb status needs. --------- Co-authored-by: claude-bear <noreply@anthropic.com>
…-parser for security advisories (#465) - tar ^7.5.3 -> ^7.5.19 (locked 7.5.21): fixes GHSA-23hp-3jrh-7fpw (critical), GHSA-8x88-c5mf-7j5w (high), GHSA-w8wr-v893-vjvp / GHSA-gvwx-54wh-qm9j (moderate) - brace-expansion -> 1.1.16 / 5.0.7 via overrides: fixes GHSA-3jxr-9vmj-r5cp (high) - js-yaml 4.x -> 4.3.0 via override: fixes GHSA-52cp-r559-cp3m (high) - hono -> 4.12.27 via override: fixes GHSA-xgm2-5f3f-mvvc, GHSA-hvrm-45r6-mjfj, GHSA-w62v-xxxg-mg59 (moderate, dev-only) - fast-uri -> 3.1.4 via override: fixes GHSA-v2hh-gcrm-f6hx, GHSA-4c8g-83qw-93j6 (high, dev-only) - body-parser 2.x -> 2.3.0 via override: fixes GHSA-v422-hmwv-36x6 (low, dev-only) Not fixed: elliptic GHSA-848j-6mx2-7j84 (no patched release published) and @hono/node-server GHSA-frvp-7c67-39w9 (fix requires breaking 1.x -> 2.x bump that violates @modelcontextprotocol/sdk's ^1.19.9 range; dev-only, Windows-only). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…w fixes (#466) * fix: rename mainnet-fork override flag and apply leftover 0.4.9 review fixes - Rename --allow-mainnet-replay-risk to --allow-external-key-on-mainnet-fork (#460) - Enforce the Mainnet-fork replay guard in transfer-all, udt issue/destroy, and deploy, threading the fork boundary into input selection (#462) - Validate --tx-hash before it is used in debug cache paths - Only read the fork boundary after the spawned process binds the RPC port - Reject symlinked entries when copying fork source chain data - Accept extended xUDT type args (owner hash + flags/extension) - Per-kind UDT scan budgets, deep-cloned settings fallbacks, accurate config-set errors, preserved devnet-config error, execFile process lookup, aligned ckb-tui download timeouts, EXDEV-safe install, README TOC entry Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: address PR #466 review comments - Keep --allow-mainnet-replay-risk as a hidden deprecated alias folded into --allow-external-key-on-mainnet-fork (with a deprecation warning) so 0.4.9 scripts keep working under a patch release - Treat lsof probe failures with stderr output as indeterminate (null) instead of "not listening"; only an empty-stderr exit is a genuine no-match, so permission errors fall back to the weaker genesis signal - Reject a symlinked data root before enumerating source chain data - Stage cross-device ckb-tui installs inside binDir and publish with an atomic rename, so concurrent installs never see a truncated binary Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: bound the lsof port probe with a timeout A hung lsof would block execFileSync (and with it daemon startup) indefinitely, and its empty-stderr timeout error would be misread as a genuine no-match. Cap the probe at 5s and classify ETIMEDOUT as indeterminate (null) so the genesis fallback proceeds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: make lsof probe tests platform-independent isProcessListeningOnPort short-circuits to null on win32, so the lsof outcome-mapping tests failed on the Windows CI runner (mock never called). Force a unix platform for the lsof-probing cases, cover the win32 short-circuit explicitly, and pin the probe timeout to exactly 5000 ms per review feedback. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
fix(devnet): offer Terminal module in config editor and migrate legacy ckb.toml
A healthy devnet emits almost no warn-level logs, so with the previous default filter (warn,ckb-script=debug) the `offckb status` Logs panel stayed permanently empty and looked broken. Switch the devnet ckb.toml and ckb-miner.toml templates (and the config editor's embedded reference templates) to info,ckb-script=debug so the per-block log stream is visible while script debug output is preserved. Existing chains keep their current filter; edit [logger] filter in the devnet ckb.toml to opt in. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
❌ Missing Changeset Please add a changeset describing your changes: pnpm changesetIf your changes do not need a version bump (docs, CI, refactoring), For dependency updates, use the |
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis release updates devnet RPC/status integration, migrates legacy devnet configurations, strengthens mainnet-fork transaction safeguards, improves node and installer reliability, tightens validation, and updates package metadata and dependency security overrides. ChangesMainnet fork safety and input boundaries
Devnet RPC, status, and legacy migration
Node, fork-copy, and ckb-tui reliability
Validation, configuration errors, and release maintenance
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (3)
tests/status.test.ts (1)
44-49: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueTemp dirs created here are never removed.
useDevnetConfigmkdtemps per test with no teardown, leaving directories inos.tmpdir(). Track the created dirs andfs.rmSync(..., { recursive: true, force: true })in anafterEach(astests/init-chain.test.tsdoes).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/status.test.ts` around lines 44 - 49, Update useDevnetConfig to track each directory returned by fs.mkdtempSync, then add an afterEach teardown that removes all tracked directories with fs.rmSync using recursive and force options, following the cleanup pattern in init-chain tests.src/tui/devnet-reference-templates.ts (1)
83-95: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider guarding the embedded template against drift from
ckb/devnet/ckb.toml.This template duplicates the bundled
ckb/devnet/ckb.tomlverbatim, and this PR had to hand-edit both. A test asserting the embedded string equals the bundled file (or loading the file at build time) would prevent the two from silently diverging on the next config change.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/tui/devnet-reference-templates.ts` around lines 83 - 95, Keep the embedded devnet template synchronized with the bundled ckb.toml by adding a test that compares the template string against the file contents, or by loading the bundled file at build time. Anchor the change to the embedded template definition in devnet-reference-templates.ts and ensure future configuration edits cannot silently cause the two representations to diverge.src/sdk/ckb.ts (1)
208-227: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winSequential per-input RPC calls could slow down
transferAllsweeps under a Mainnet fork.
assertInputsCreatedAfter(unchanged helper, ckb.ts lines 422-440) awaits onegetTransactionNoCachecall per input inside aforloop. This is now wired intotransferAll, which by design sweeps every spendable cell — the case most likely to accumulate many small inputs on a heavily-used devnet. When a Mainnet fork boundary is active, each sweep now pays one serial RPC round-trip per input before signing.Consider parallelizing the origin-block lookups (e.g.
Promise.all, with a bounded concurrency if the RPC endpoint is rate-sensitive) to avoid compounding latency as the number of swept inputs grows. The same helper is reused byudtIssue,udtDestroy,deployScript,deployNewTypeIDScript, andupgradeTypeIdScript, but those paths typically touch far fewer inputs.♻️ Possible direction (illustrative, not a full diff)
private async assertInputsCreatedAfter(tx: ccc.Transaction, blockNumber?: bigint): Promise<void> { if (blockNumber == null) return; - for (const input of tx.inputs) { - const outPoint = input.previousOutput; - const origin = await this.client.getTransactionNoCache(outPoint.txHash); - if (origin?.blockNumber == null) { - throw new Error(...); - } - if (origin.blockNumber <= blockNumber) { - throw new Error(...); - } - } + await Promise.all( + tx.inputs.map(async (input) => { + const outPoint = input.previousOutput; + const origin = await this.client.getTransactionNoCache(outPoint.txHash); + if (origin?.blockNumber == null) throw new Error(...); + if (origin.blockNumber <= blockNumber) throw new Error(...); + }), + ); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/sdk/ckb.ts` around lines 208 - 227, Update assertInputsCreatedAfter to perform per-input getTransactionNoCache lookups concurrently, using Promise.all or the project’s bounded-concurrency approach, while preserving the existing rejection behavior for inputs at or before the specified block. Keep transferAll and the other callers unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@README.md`:
- Line 334: Update the README sentence to use the grammatically correct “OffCKB
uses” and describe `info,ckb-script=debug` as a default log filter rather than a
log level, preserving the existing customization example.
- Line 418: Update the README replay-guard sentence to describe the shared
Mainnet-fork behavior across transfer, transfer-all, UDT issue, UDT destroy, and
deploy. Include the non-built-in-key override, Mainnet-copied input rejection,
and deprecated --allow-mainnet-replay-risk alias requirements for all listed
commands.
In `@src/cmd/status.ts`:
- Around line 27-41: Update devnetTcpListenAddress to log the caught error with
logger.debug before returning undefined, preserving its best-effort behavior.
Extend wildcard-address handling for IPv6 forms such as [::]:port and :::port by
mapping them to a dialable loopback address or returning undefined so ckb-tui is
not given an undialable target.
In `@src/node/init-chain.ts`:
- Around line 61-70: Update the single-line rewrite in the modules migration
logic around modulesStart and singleLine so an empty modules array becomes valid
TOML with only TERMINAL_RPC_MODULE, while retaining the comma separator for
non-empty arrays. Preserve existing indentation and trailing comments.
- Around line 141-156: Update the RPC migration flow around the
needsTerminal/needsTcp checks to inspect rpc.listen_address and detect the
legacy non-loopback 0.0.0.0:8114 bind. Migrate that bind to 127.0.0.1:8114
before or while adding the Terminal module, or skip Terminal enablement and emit
the required warning for non-loopback RPC; add a regression test covering this
configuration.
---
Nitpick comments:
In `@src/sdk/ckb.ts`:
- Around line 208-227: Update assertInputsCreatedAfter to perform per-input
getTransactionNoCache lookups concurrently, using Promise.all or the project’s
bounded-concurrency approach, while preserving the existing rejection behavior
for inputs at or before the specified block. Keep transferAll and the other
callers unchanged.
In `@src/tui/devnet-reference-templates.ts`:
- Around line 83-95: Keep the embedded devnet template synchronized with the
bundled ckb.toml by adding a test that compares the template string against the
file contents, or by loading the bundled file at build time. Anchor the change
to the embedded template definition in devnet-reference-templates.ts and ensure
future configuration edits cannot silently cause the two representations to
diverge.
In `@tests/status.test.ts`:
- Around line 44-49: Update useDevnetConfig to track each directory returned by
fs.mkdtempSync, then add an afterEach teardown that removes all tracked
directories with fs.rmSync using recursive and force options, following the
cleanup pattern in init-chain tests.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 0d61465b-8b67-48eb-89f0-3d0b3a7cd911
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (38)
CHANGELOG.mdREADME.mdckb/devnet/ckb-miner.tomlckb/devnet/ckb.tomlpackage.jsonpnpm-workspace.yamlsrc/cfg/setting.tssrc/cli.tssrc/cmd/config.tssrc/cmd/debug.tssrc/cmd/deploy.tssrc/cmd/devnet-config.tssrc/cmd/node.tssrc/cmd/status.tssrc/cmd/transfer-all.tssrc/cmd/transfer.tssrc/cmd/udt.tssrc/deploy/index.tssrc/devnet/fork.tssrc/node/init-chain.tssrc/sdk/ckb.tssrc/tools/ckb-tui.tssrc/tui/devnet-config-metadata.tssrc/tui/devnet-reference-templates.tssrc/util/fork-safety.tssrc/util/validator.tstests/cli-mainnet-fork-flag.test.tstests/debug-tx-file.test.tstests/devnet-config-metadata.test.tstests/devnet-fork.test.tstests/fork-safety.test.tstests/init-chain.test.tstests/node-command.test.tstests/node-listener.test.tstests/status.test.tstests/transfer-all.test.tstests/udt.test.tstests/validator.test.ts
| ### 6. Tweak Devnet Config {#tweak-devnet-config} | ||
|
|
||
| By default, OffCKB use a fixed Devnet config. You can customize it, for example by modifying the default log level (`warn,ckb-script=debug`). | ||
| By default, OffCKB use a fixed Devnet config. You can customize it, for example by modifying the default log level (`info,ckb-script=debug`). |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Correct the grammar and terminology.
Use “OffCKB uses” instead of “OffCKB use”, and call info,ckb-script=debug a log filter rather than a single log level.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@README.md` at line 334, Update the README sentence to use the grammatically
correct “OffCKB uses” and describe `info,ckb-script=debug` as a default log
filter rather than a log level, preserving the existing customization example.
| > CKB transactions carry no chain id, so a transaction built on a mainnet fork that spends copied mainnet cells is also valid on mainnet (CKB provides no replay protection). offckb's own flows only use dev keys and fork-mined cells, which cannot replay. Never sign transactions with real mainnet keys against a fork unless you intend to broadcast them yourself. | ||
|
|
||
| `offckb transfer` fails closed on a Mainnet fork: non-built-in keys require `--allow-mainnet-replay-risk`, and inputs copied from Mainnet are rejected even with that override. | ||
| `offckb transfer` fails closed on a Mainnet fork: non-built-in keys require `--allow-external-key-on-mainnet-fork`, and inputs copied from Mainnet are rejected even with that override. (`--allow-mainnet-replay-risk` from 0.4.9 remains as a deprecated alias.) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Document all guarded signing commands.
The changelog says the replay guard also covers transfer-all, udt issue, udt destroy, and deploy, but this README sentence documents only offckb transfer. Reword it as a cross-command rule and list the affected commands so users understand the same failure behavior and override requirements.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@README.md` at line 418, Update the README replay-guard sentence to describe
the shared Mainnet-fork behavior across transfer, transfer-all, UDT issue, UDT
destroy, and deploy. Include the non-built-in-key override, Mainnet-copied input
rejection, and deprecated --allow-mainnet-replay-risk alias requirements for all
listed commands.
| function devnetTcpListenAddress(): string | undefined { | ||
| try { | ||
| const settings = readSettings(); | ||
| const ckbTomlPath = path.join(settings.devnet.configPath, 'ckb.toml'); | ||
| if (!fs.existsSync(ckbTomlPath)) return undefined; | ||
| const parsed = toml.parse(fs.readFileSync(ckbTomlPath, 'utf8')); | ||
| const rpc = parsed.rpc as JsonMap | undefined; | ||
| const address = rpc?.tcp_listen_address; | ||
| if (typeof address !== 'string' || address.trim().length === 0) return undefined; | ||
| // A wildcard bind is not a dialable address; the node runs on this host. | ||
| return address.trim().replace(/^0\.0\.0\.0:/, '127.0.0.1:'); | ||
| } catch { | ||
| return undefined; | ||
| } | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Silent failure and IPv6 wildcard not normalized.
Two small gaps in this best-effort helper:
- The
catchswallows the reason entirely; alogger.debugmakes "why are my mempool/logs panels empty?" diagnosable. - Only
0.0.0.0:is rewritten. A node configured with[::]:18114(or:::18114) yields an address ckb-tui cannot dial; better to omit-t(or map to loopback) than to pass an undialable value.
♻️ Suggested handling
- // A wildcard bind is not a dialable address; the node runs on this host.
- return address.trim().replace(/^0\.0\.0\.0:/, '127.0.0.1:');
- } catch {
- return undefined;
- }
+ // A wildcard bind is not a dialable address; the node runs on this host.
+ const trimmed = address.trim();
+ const port = trimmed.match(/^(?:0\.0\.0\.0|\[::\]|::):(\d+)$/);
+ return port ? `127.0.0.1:${port[1]}` : trimmed;
+ } catch (error) {
+ logger.debug(`skipping ckb-tui TCP endpoint discovery: ${(error as Error).message}`);
+ return undefined;
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function devnetTcpListenAddress(): string | undefined { | |
| try { | |
| const settings = readSettings(); | |
| const ckbTomlPath = path.join(settings.devnet.configPath, 'ckb.toml'); | |
| if (!fs.existsSync(ckbTomlPath)) return undefined; | |
| const parsed = toml.parse(fs.readFileSync(ckbTomlPath, 'utf8')); | |
| const rpc = parsed.rpc as JsonMap | undefined; | |
| const address = rpc?.tcp_listen_address; | |
| if (typeof address !== 'string' || address.trim().length === 0) return undefined; | |
| // A wildcard bind is not a dialable address; the node runs on this host. | |
| return address.trim().replace(/^0\.0\.0\.0:/, '127.0.0.1:'); | |
| } catch { | |
| return undefined; | |
| } | |
| } | |
| function devnetTcpListenAddress(): string | undefined { | |
| try { | |
| const settings = readSettings(); | |
| const ckbTomlPath = path.join(settings.devnet.configPath, 'ckb.toml'); | |
| if (!fs.existsSync(ckbTomlPath)) return undefined; | |
| const parsed = toml.parse(fs.readFileSync(ckbTomlPath, 'utf8')); | |
| const rpc = parsed.rpc as JsonMap | undefined; | |
| const address = rpc?.tcp_listen_address; | |
| if (typeof address !== 'string' || address.trim().length === 0) return undefined; | |
| // A wildcard bind is not a dialable address; the node runs on this host. | |
| const trimmed = address.trim(); | |
| const port = trimmed.match(/^(?:0\.0\.0\.0|\[::\]|::):(\d+)$/); | |
| return port ? `127.0.0.1:${port[1]}` : trimmed; | |
| } catch (error) { | |
| logger.debug(`skipping ckb-tui TCP endpoint discovery: ${(error as Error).message}`); | |
| return undefined; | |
| } | |
| } |
🧰 Tools
🪛 ast-grep (0.44.1)
[warning] 31-31: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.readFileSync(ckbTomlPath, 'utf8')
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').
(detect-non-literal-fs-filename-typescript)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/cmd/status.ts` around lines 27 - 41, Update devnetTcpListenAddress to log
the caught error with logger.debug before returning undefined, preserving its
best-effort behavior. Extend wildcard-address handling for IPv6 forms such as
[::]:port and :::port by mapping them to a dialable loopback address or
returning undefined so ckb-tui is not given an undialable target.
| const modulesStart = lines.findIndex( | ||
| (line, index) => index > section.start && index < section.end && /^\s*modules\s*=\s*\[/.test(line), | ||
| ); | ||
| if (modulesStart < 0) return false; | ||
|
|
||
| const singleLine = lines[modulesStart].match(/^(\s*modules\s*=\s*\[[^\]]*)\](\s*(?:#.*)?)$/); | ||
| if (singleLine) { | ||
| lines[modulesStart] = `${singleLine[1]}, "${TERMINAL_RPC_MODULE}"]${singleLine[2]}`; | ||
| return true; | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Empty single-line modules = [] produces invalid TOML.
needsTerminal is true for an empty array ([].every(...) is true, includes false), and the single-line branch then rewrites modules = [] as modules = [, "Terminal"], which no longer parses — CKB will refuse to start with the migrated config. Insert without a leading comma when the array body is empty.
🐛 Proposed fix
const singleLine = lines[modulesStart].match(/^(\s*modules\s*=\s*\[[^\]]*)\](\s*(?:#.*)?)$/);
if (singleLine) {
- lines[modulesStart] = `${singleLine[1]}, "${TERMINAL_RPC_MODULE}"]${singleLine[2]}`;
+ const hasEntries = singleLine[1].slice(singleLine[1].indexOf('[') + 1).trim().length > 0;
+ const separator = hasEntries ? ', ' : '';
+ lines[modulesStart] = `${singleLine[1]}${separator}"${TERMINAL_RPC_MODULE}"]${singleLine[2]}`;
return true;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const modulesStart = lines.findIndex( | |
| (line, index) => index > section.start && index < section.end && /^\s*modules\s*=\s*\[/.test(line), | |
| ); | |
| if (modulesStart < 0) return false; | |
| const singleLine = lines[modulesStart].match(/^(\s*modules\s*=\s*\[[^\]]*)\](\s*(?:#.*)?)$/); | |
| if (singleLine) { | |
| lines[modulesStart] = `${singleLine[1]}, "${TERMINAL_RPC_MODULE}"]${singleLine[2]}`; | |
| return true; | |
| } | |
| const modulesStart = lines.findIndex( | |
| (line, index) => index > section.start && index < section.end && /^\s*modules\s*=\s*\[/.test(line), | |
| ); | |
| if (modulesStart < 0) return false; | |
| const singleLine = lines[modulesStart].match(/^(\s*modules\s*=\s*\[[^\]]*)\](\s*(?:#.*)?)$/); | |
| if (singleLine) { | |
| const hasEntries = singleLine[1].slice(singleLine[1].indexOf('[') + 1).trim().length > 0; | |
| const separator = hasEntries ? ', ' : ''; | |
| lines[modulesStart] = `${singleLine[1]}${separator}"${TERMINAL_RPC_MODULE}"]${singleLine[2]}`; | |
| return true; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/node/init-chain.ts` around lines 61 - 70, Update the single-line rewrite
in the modules migration logic around modulesStart and singleLine so an empty
modules array becomes valid TOML with only TERMINAL_RPC_MODULE, while retaining
the comma separator for non-empty arrays. Preserve existing indentation and
trailing comments.
| const modules = rpc.modules; | ||
| const needsTerminal = | ||
| Array.isArray(modules) && modules.every((m) => typeof m === 'string') && !modules.includes(TERMINAL_RPC_MODULE); | ||
| const tcpAddress = rpc.tcp_listen_address; | ||
| const needsTcp = typeof tcpAddress !== 'string' || tcpAddress.trim().length === 0; | ||
| if (!needsTerminal && !needsTcp) return false; | ||
|
|
||
| const lines = source.split('\n'); | ||
| const section = findRpcSection(lines); | ||
| if (section == null) return false; | ||
|
|
||
| const changes: string[] = []; | ||
| if (needsTerminal && addTerminalModule(lines, section)) { | ||
| changes.push('Terminal RPC module'); | ||
| } | ||
| if (needsTcp && enableTcpListenAddress(lines, findRpcSection(lines) ?? section)) { |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the relevant file and nearby helpers
ast-grep outline src/node/init-chain.ts --view expanded || true
# Inspect the target range and related helpers with line numbers
sed -n '1,260p' src/node/init-chain.ts | cat -n
# Search for listen_address handling and the legacy devnet template references
rg -n "listen_address|tcp_listen_address|TERMINAL_RPC_MODULE|get_overview|0\.0\.0\.0:8114|127\.0\.0\.1:8114|bundled template|devnet" src test . -g '!node_modules' -g '!dist' -g '!build' || trueRepository: ckb-devrel/offckb
Length of output: 50374
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check the file that the comment references if it exists in the repo
git ls-files | rg '^.*ckb\.toml$|^.*devnet.*toml$|^.*template.*toml$|^.*init-chain\.ts$' || trueRepository: ckb-devrel/offckb
Length of output: 250
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# If tests exist, inspect the migration tests around init-chain.
rg -n "init-chain|Terminal RPC module|tcp_listen_address|listen_address" test src -g '!node_modules' -g '!dist' -g '!build' || trueRepository: ckb-devrel/offckb
Length of output: 2405
🌐 Web query:
offckb 699a850 devnet ckb.toml 0.0.0.0 8114 rpc.listen_address Terminal RPC module
💡 Result:
The configuration and components you mentioned relate to running and monitoring a Nervos CKB node, particularly within a development environment using the OffCKB tool. RPC Configuration (ckb.toml) In a CKB node's ckb.toml file, the rpc.listen_address setting determines the network interface and port on which the node's JSON-RPC server listens [1][2]. By default, this is often set to 127.0.0.1:8114 to ensure only local processes can access the RPC [2]. Configuring this to 0.0.0.0:8114 instructs the node to listen on all available network interfaces, allowing external machines to make RPC requests [1][2]. This should only be done if strictly necessary, and it is highly recommended to secure the port with a firewall (e.g., via iptables) to restrict access to trusted IP addresses [3][2]. OffCKB and Proxy RPC OffCKB is a CLI tool designed to simplify local CKB development [4][5]. When you start a devnet via OffCKB, it typically runs a CKB node and an optional Proxy RPC server [4][6]. While the core CKB RPC server listens at 127.0.0.1:8114, the OffCKB Proxy RPC server is designed to forward requests to the node while recording them and automatically dumping failed transactions for easier debugging [4][6][5]. Note that port numbers for this proxy can vary (e.g., 28114 or 9000 depending on your version and configuration) [4][6][5]. Terminal RPC Module The Terminal module is a specific RPC feature introduced in recent CKB updates (e.g., via CKB-TUI integrations) to provide observability [7]. It serves as a dedicated interface for terminal-based monitoring tools (like ckb-tui) to retrieve essential runtime data, including system metrics, mining information, transaction pool status, and network peer information [7]. It uses an LRU cache with specific Time-to-Live (TTL) settings to ensure high performance when supplying this data to monitoring interfaces [7]. The reference 699a850 likely refers to a specific commit hash within a CKB-related repository, which identifies the state of the software at the time of that build [7].
Citations:
- 1: https://github.com/nervosnetwork/ckb/blob/develop/rpc/README.md
- 2: https://website-sooty-chi-72.vercel.app/lessons/19-full-node-setup
- 3: https://docs-old.nervos.org/docs/basics/guides/mainnet
- 4: https://docs.nervos.org/docs/sdk-and-devtool/offckb
- 5: https://deepwiki.com/ckb-devrel/offckb/1.1-installation-and-getting-started
- 6: https://www.npmjs.com/package/@offckb/cli
- 7: https://talk.nervos.org/t/teamckb-dev-log-updated-may-27-2026/8572?page=2
🌐 Web query:
site:github.com/nervosnetwork/ckb "rpc.tcp_listen_address" Terminal RPC module listen_address
💡 Result:
In the context of the Nervos CKB node software, rpc.tcp_listen_address is a configuration parameter used to enable and specify the bind address for a TCP-based JSON-RPC server [1][2][3]. This configuration is primarily used to support full-duplex communication, which is required for RPC subscription services (where the node pushes updates to the client) [1][2]. While CKB nodes primarily use an HTTP-based RPC server (configured via rpc.listen_address), the TCP server provides an alternative transport for these specialized, long-lived subscription connections [4][3]. The Terminal module, recently introduced in CKB v0.205.0, is a distinct RPC module designed to provide aggregated system and node data (such as mining info, transaction pool status, and network metrics) for the CKB-TUI (Terminal User Interface) [5][6]. It is one of several modules enabled within the CKB node configuration, but it is not inherently tied to the rpc.tcp_listen_address parameter [3][5]. The Terminal module's data is accessed through the standard RPC interface; the tcp_listen_address setting is simply a transport-layer configuration that may be used to handle the persistent connections required by various RPC modules if the operator chooses to enable TCP transport [2][3].
Citations:
- 1: https://github.com/nervosnetwork/ckb/wiki/RPC-subscription
- 2: https://github.com/nervosnetwork/ckb/blob/52de4eb3/rpc/src/module/subscription.rs
- 3: https://github.com/nervosnetwork/ckb/blob/develop/resource/ckb.toml
- 4: https://github.com/nervosnetwork/ckb/blob/52de4eb3/rpc/src/server.rs
- 5: CKB Dev Log 2025-02-25 nervosnetwork/ckb#5116
- 6: ckb 0.205.0 (b75a785 2026-03-17) nervosnetwork/ckb#5145
Information Disclosure (CWE-200): Exposure of Sensitive Information to an Unauthorized Actor
Reachability: External
● Entry
src/cmd/node.ts:77
initChainIfNeeded
│
▼
● Sink
src/node/init-chain.ts
Handle rpc.listen_address too The migration still leaves legacy devnet configs on 0.0.0.0:8114, so adding Terminal can expose unauthenticated get_overview over the network. Migrate that legacy bind to 127.0.0.1:8114, or skip enabling Terminal and warn on non-loopback RPC. Add a regression test for a config with rpc.listen_address = "0.0.0.0:8114".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/node/init-chain.ts` around lines 141 - 156, Update the RPC migration flow
around the needsTerminal/needsTcp checks to inspect rpc.listen_address and
detect the legacy non-loopback 0.0.0.0:8114 bind. Migrate that bind to
127.0.0.1:8114 before or while adding the Terminal module, or skip Terminal
enablement and emit the required warning for non-loopback RPC; add a regression
test covering this configuration.
No description provided.