mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-25 11:51:15 +00:00
Bound diagnostic config file read with size cap (#110591)
* Bound diagnostic config read with size cap * fix: use buffer.toString for readRegularFileSync result in diagnostic export * test: verify normal and oversized diagnostic config export behavior PR #110591 — Add focused regression coverage for the bounded diagnostic config read: - Test: normal config file (<8MB) produces parseOk: true in config/shape.json - Test: oversized config file (>8MB) produces parseOk: false with graceful error handling - Both tests verify the support bundle zip is still written with all expected contents * refactor(logging): clarify support export config limit Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com> --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -912,4 +912,50 @@ describe("diagnostic support export", () => {
|
||||
expect(combined).toContain("config stat failed with token");
|
||||
expect(combined).toContain("Attach this zip to the bug report");
|
||||
});
|
||||
|
||||
it("finishes the support export when the config exceeds its read limit", async () => {
|
||||
const configPath = path.join(tempDir, "openclaw.json");
|
||||
const outputPath = path.join(tempDir, "support-oversized-config.zip");
|
||||
fs.writeFileSync(configPath, Buffer.alloc(8 * 1024 * 1024 + 1, "{"));
|
||||
|
||||
await writeDiagnosticSupportExport({
|
||||
env: {
|
||||
...process.env,
|
||||
HOME: tempDir,
|
||||
OPENCLAW_CONFIG_PATH: configPath,
|
||||
OPENCLAW_STATE_DIR: tempDir,
|
||||
},
|
||||
stateDir: tempDir,
|
||||
outputPath,
|
||||
now: new Date("2026-07-18T12:00:01.000Z"),
|
||||
readLogTail: async () => ({
|
||||
file: path.join(tempDir, "logs", "openclaw.log"),
|
||||
cursor: 0,
|
||||
size: 0,
|
||||
truncated: false,
|
||||
reset: false,
|
||||
lines: [],
|
||||
}),
|
||||
});
|
||||
|
||||
const entries = await readZipTextEntries(outputPath);
|
||||
const configShape = JSON.parse(entries["config/shape.json"] ?? "{}") as {
|
||||
parseOk?: boolean;
|
||||
error?: string;
|
||||
};
|
||||
expect(configShape.parseOk).toBe(false);
|
||||
expect(configShape.error).toContain("File exceeds 8388608 bytes");
|
||||
expect(entries["config/sanitized.json"]).toBe("null\n");
|
||||
expect(Object.keys(entries).toSorted()).toEqual([
|
||||
"config/sanitized.json",
|
||||
"config/shape.json",
|
||||
"diagnostics.json",
|
||||
"logs/openclaw-sanitized.jsonl",
|
||||
"manifest.json",
|
||||
"summary.md",
|
||||
]);
|
||||
|
||||
const combined = Object.values(entries).join("\n");
|
||||
expect(combined).toContain("Attach this zip to the bug report");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ import { resolveConfigPath, resolveStateDir } from "../config/paths.js";
|
||||
import { redactConfigObject } from "../config/redact-snapshot.js";
|
||||
import { buildConfigSchema } from "../config/schema.js";
|
||||
import { resolveHomeRelativePath } from "../infra/home-dir.js";
|
||||
import { readRegularFileSync } from "../infra/regular-file.js";
|
||||
import { VERSION } from "../version.js";
|
||||
import {
|
||||
readDiagnosticStabilityBundleFileSync,
|
||||
@@ -38,6 +39,9 @@ const DIAGNOSTIC_SUPPORT_EXPORT_VERSION = 1;
|
||||
|
||||
const DEFAULT_LOG_LIMIT = 5000;
|
||||
const DEFAULT_LOG_MAX_BYTES = 1_000_000;
|
||||
// Support export must remain usable when the config is corrupt or unexpectedly
|
||||
// large. This defensive ceiling is not the product's general config-file limit.
|
||||
const SUPPORT_EXPORT_CONFIG_MAX_BYTES = 8 * 1024 * 1024;
|
||||
const SUPPORT_EXPORT_PREFIX = "openclaw-diagnostics-";
|
||||
const SUPPORT_EXPORT_SUFFIX = ".zip";
|
||||
type Awaitable<T> = T | Promise<T>;
|
||||
@@ -343,7 +347,11 @@ function readConfigExport(options: {
|
||||
let stat: fs.Stats | undefined;
|
||||
try {
|
||||
stat = fs.statSync(options.configPath);
|
||||
const parsed = parseConfigJson5(fs.readFileSync(options.configPath, "utf8"));
|
||||
const { buffer } = readRegularFileSync({
|
||||
filePath: options.configPath,
|
||||
maxBytes: SUPPORT_EXPORT_CONFIG_MAX_BYTES,
|
||||
});
|
||||
const parsed = parseConfigJson5(buffer.toString("utf8"));
|
||||
if (!parsed.ok) {
|
||||
return {
|
||||
shape: configShapeReadFailure({
|
||||
|
||||
Reference in New Issue
Block a user