Repository navigation
Conversation
Add HTTP and Unix-domain-socket transports for the shared Admin JSON-RPC API, with an attach console for trusted node operators. Include transport configuration, socket permissions, request handling, bounded client lifecycle, and startup isolation regression tests.
…ken count restrict
There was a problem hiding this comment.
Re-reviewed the complete PR at decdf68. The Admin code is unchanged since f2ce52e; the new commits only merge release_v4.8.3, and the build.gradle conflict resolution keeps the junixsocket/JLine dependencies. The previous socket-deletion, parse-error and client-validation issues are fixed. The explicit no-batch policy and the configuration layout are accepted.
The targeted regression tests and the framework Checkstyle checks pass locally on JDK 17. Additional probes confirm two remaining [MUST] issues — request-envelope validation and request id/notification handling; see the inline comments. A separate [SHOULD] covers crash recovery: SIGKILL leaves the IPC directory behind, so a node using the same persistent socket root cannot restart.
Please fix the two [MUST] items with HTTP/IPC regression tests. The crash-recovery tradeoff should either be fixed or explicitly agreed.
[SHOULD] Please document the JLine packaging/version choice, the OS/architecture/JDK combinations you tested, and junixsocket's native-library loading requirements. In particular, please verify deployment with a noexec temporary directory and document -Dorg.newsclub.net.unix.library.tmpdir=<directory> where needed. Version 2.10.1 falls back to other locations, so a noexec /tmp alone does not mean IPC startup will fail.
Please also link follow-up issues for the runtime-parameter and Peer management commands.
| AdminJsonRpc.BATCH_NOT_SUPPORTED_MESSAGE); | ||
| return; | ||
| } | ||
| ByteArrayOutputStream output = new ByteArrayOutputStream(); |
There was a problem hiding this comment.
[MUST] Request-structure errors still reach jsonrpc4j on both transports. An otherwise valid request with id:true or params:"text" gets HTTP 200 with an empty body, while IPC returns -32603. A top-level null still returns "id":"null", and "jsonrpc":"3.0" still runs the method. Please validate the request envelope in the shared handling before dispatch, and return consistent -32600 errors, with a JSON null id when the id cannot be determined. Please add HTTP/IPC tests for invalid id, params and version fields, and for non-object inputs, asserting that no Admin method runs.
There was a problem hiding this comment.
Fixed in 448d1c8. HTTP and IPC now share AdminJsonRpcRequestHandler, which validates the request object, version, method, params, and id before dispatch. The reported inputs consistently return -32600, with a JSON null id when no valid id can be determined, and no Admin method is invoked.
Added parameterized regression tests for both transports, including invalid field types, non-object inputs, out-of-range numeric ids, and invalid requests without an id. The tests assert the response and verify that no business method runs. All 173 related tests and production/test Checkstyle checks passed locally on JDK 17.
| new ByteArrayInputStream(jsonRequest.getBytes(StandardCharsets.UTF_8)); | ||
| ByteArrayOutputStream output = new ByteArrayOutputStream(); | ||
|
|
||
| try { |
There was a problem hiding this comment.
[MUST] Request id and notification handling is wrong on both transports: id:null runs the method without a response, id:9223372036854775808 runs it and returns id:0, and valid notifications get error responses for unknown methods or business exceptions. Please keep accepted ids exactly as received, and distinguish an omitted id from an explicit null. For structurally valid notifications, produce no JSON-RPC response body, whether the call succeeds or fails. If numeric ids have a supported range, reject unsupported values before calling the method. Please add HTTP/IPC tests for null, string and boundary numeric ids, and for notifications covering a successful call, an unknown method and a business error.
There was a problem hiding this comment.
Fixed in 448d1c8. The shared handler now distinguishes an omitted id from id:null: explicit null receives a response, while structurally valid notifications produce no response body on success or failure, including unknown methods and business exceptions. Accepted ids retain their JSON value and type. Numeric ids outside [Long.MIN_VALUE, Long.MAX_VALUE] are rejected with -32600 and id:null before any Admin method runs.
Added parameterized HTTP/IPC tests for null and string ids, numeric boundaries and overflow, and successful/failing notifications. Validation runs before notification handling, so malformed requests without an id still receive an error. All 173 related tests and production/test Checkstyle checks passed locally on JDK 17.
| } | ||
| } | ||
|
|
||
| void createSocketDirectory(Path socketDirectory) throws IOException { |
There was a problem hiding this comment.
[SHOULD] Rejecting every existing ipc directory also prevents restart after an unclean exit. I reproduced this by sending SIGKILL to a running IPC service process: the directory stayed, and a new process using the same root failed to start. This blocks automatic recovery whenever the socket root persists. Please consider safe stale-directory recovery with an ownership mechanism that still protects live endpoints, and add a subprocess crash/restart test. If manual recovery is intended for this release, please document the automatic-restart limitation explicitly and track recovery separately.
There was a problem hiding this comment.
Manual recovery is the intended behavior in this PR. When IPC is enabled and the ipc directory already exists, startup fails with an explicit error instructing the operator to confirm that no node is using it, remove the directory manually, and retry.
This also applies after an unclean exit: restarting with the same persistent socket root requires manual cleanup. We retain this behavior to avoid accidentally deleting a running node’s endpoint.
What does this PR do?
This PR adds the Admin JSON-RPC transport foundation requested by #6497. A single annotated
AdminJsonRpcinterface is shared by an HTTP endpoint and a local Unix-domain-socket service. The initialadmin_examplemethod verifies typed command dispatch and annotation-based JSON-RPC error handling; additional administrative methods can be added to the same interface.Admin HTTP and IPC accept only individual JSON-RPC requests; batch requests are not supported.
In this PR, JSON-RPC defines the shared API and message format, while HTTP and IPC are the two transports:
Admin HTTP service
The HTTP service is available to FullNode processes at
POST /adminand is disabled by default. It binds Jetty to the configured address and port. Enabling it on a non-loopback address emits a warning.The servlet validates the
Hostheader against the configured virtual-host allowlist, while accepting IPv4 and IPv6 literals. It acceptsapplication/json,application/json-rpc, andapplication/*+jsonmedia types, and rejects unsupported content types with HTTP 415. JSON-RPC parsing reuses a constrained object mapper with nesting-depth and token-count limits. JSON-RPC results, including protocol errors, use HTTP 200 responses.Admin HTTP is intended for trusted node operators. Deployments must restrict access to loopback or a controlled management network. Under this trust model, Admin HTTP intentionally does not apply the public JSON-RPC
node.jsonrpc.maxResponseSizelimit. The existing HTTP request-size limit and JSON nesting-depth and token-count limits still apply.The HTTP transport configuration is:
Admin IPC service
The IPC service is also FullNode-only and disabled by default. By default it creates an endpoint at:
When non-empty,
node.admin.ipc.socketDirectoryselects another socket root and must be an existing absolute directory on a POSIX-compatible filesystem; an empty value usesoutput-directory. The service creates the privateipcdirectory with owner-only access and sets the socket to0600. Startup fails if the privateipcpath already exists. Confirm that no node is using it, then remove it manually before retrying.The complete encoded socket path is limited to 100 bytes for portability across supported Unix-domain-socket implementations. If the path is longer, startup fails with guidance to configure a shorter
node.admin.ipc.socketDirectory; it does not silently relocate the endpoint.IPC uses newline-delimited, single-line JSON-RPC messages and the same
AdminJsonRpc, error resolver, and constrained JSON mapper as HTTP. Request size is bounded bynode.jsonrpc.maxMessageSize, shared with public JSON-RPC HTTP, whose default is 4 MiB. Each client has a ten-minute idle timeout. The bounded client executor supports concurrent console sessions and immediately closes connections that arrive after all handlers are occupied. Unexpected accept failures use a five-second retry delay.Startup failures and normal shutdown both clean up owned sockets and the private directory. Shutdown closes active clients before stopping executors so blocked native socket reads do not unnecessarily delay node termination.
IPC console
The FullNode executable can attach to an active node without initializing another node instance:
A single command can be executed for scripting:
Attach mode is handled immediately after CLI argument parsing and before
CommonParameter, Logback, database, witness, or node services are initialized.--execrequires--attach, an empty socket path is rejected, and attach mode cannot be combined with--config.The JLine console derives command names, parameter names, and parameter types from the annotated Admin API. It supports quoted arguments, typed JSON conversion, sorted help, canonical command completion, formatted JSON results,
help,exit, andquit. One-shot execution returns a non-zero process status for invalid commands, JSON-RPC errors, communication failures, disconnection before a response, or the 30-second response timeout.Supporting changes
HttpServicenow supports binding a service to a specific listen address. The regular JSON-RPC servlet and the Admin transports share the new constrainedJsonRpcMapper, and supported JSON media-type matching is centralized inJsonRpcMediaType.The framework adds JLine for the interactive console and junixsocket for Unix-domain-socket support. Dependency verification metadata is updated accordingly.
Why are these changes required?
Administrative operations need a local, scriptable interface without starting a second node or exposing the existing public APIs as privileged management endpoints. The Unix-domain socket provides a private local transport, while the optional HTTP endpoint supports controlled integration when explicitly enabled.
Sharing one typed Admin API across both transports keeps command names, parameters, results, and JSON-RPC errors consistent. Explicit address binding, virtual-host validation, parser limits, filesystem permissions, bounded clients, and deterministic cleanup provide safer operational defaults.
Testing
The PR adds or updates tests covering:
The related Admin HTTP, IPC, CLI, configuration, and FullNode tests, together with production and test checkstyle checks, passed during development.
Follow-up
Runtime parameter export and Peer management commands will be implemented separately using the Admin transports introduced here.