Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/integrations/serialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,17 @@ export function quoteTomlKey(key: string): string {
function tomlScalar(value: unknown): string {
if (typeof value === "string") return tomlString(value);
if (typeof value === "boolean") return value ? "true" : "false";
if (typeof value === "number" && Number.isFinite(value)) return String(value);
if (typeof value === "number" && Number.isFinite(value)) {
// Bun.TOML.parse returns TOML integers as JavaScript numbers. Values outside
// the safe range may already have been rounded, so writing them back would
// silently alter a user-owned config rather than merely reformatting it.
if (Number.isInteger(value) && !Number.isSafeInteger(value)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Distinguish TOML floats from unsafe integers

In src/integrations/serialize.ts, when a valid TOML float has an integral JavaScript value—for example k = 1e20 or k = 9007199254740992.0—Bun returns a number for which Number.isInteger is true, so this branch misclassifies it as a TOML integer and makes integration apply/disable refuse the entire file. This changes previously accepted scalar behavior even though the fix targets unsafe integer literals; validate integer tokens from the raw TOML before parsing, as the special-float guard does, or otherwise preserve the parsed numeric kind instead of inferring the TOML type with Number.isInteger.

AGENTS.md reference: src/AGENTS.md:L10-L10

Useful? React with 👍 / 👎.

throw new UnserializableValueError(
"TOML cannot safely rewrite an integer outside JavaScript's safe range",
);
}
return String(value);
}
/*
* Arrays of ANY scalar, not just strings. The string-only check was written
* against our own builder output; a user's config legitimately holds
Expand Down
14 changes: 14 additions & 0 deletions tests/integrations-invariants.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,20 @@ describe("a real user document is not rejected for being richer than ours", () =
});

describe("we refuse rather than corrupt or crash", () => {
test("a TOML file with an unsafe integer array is refused without being rewritten", () => {
const configPath = installClient("kimi");
const seed = '[providers.mine]\napi = "http://keep-me"\nports = [9007199254740993]\n';
writeFileSync(configPath, seed);

const result = applyIntegration({
clientId: "kimi", models: MODELS, config: CONFIG, port: 10100,
env: TEST_ENV, home, store,
});
expect(result.ok).toBe(false);
if (!result.ok) expect(result.reason).toBe("unsafe");
expect(readFileSync(configPath, "utf8")).toBe(seed);
});

test("a TOML file with special floats is refused, not silently rewritten", () => {
/*
* Bun's TOML parser mangles these before we ever see the document: `inf`
Expand Down
5 changes: 5 additions & 0 deletions tests/integrations-serialize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ describe("renderToml", () => {
expect(renderToml({ k: ["a", 1, true] })).toContain('k = ["a", 1, true]');
});

test("refuses integers outside JavaScript's safe range", () => {
expect(() => renderToml({ k: [Number.MAX_SAFE_INTEGER + 1] }))
.toThrow(/outside JavaScript's safe range/);
});

test("still refuses what TOML cannot express inline", () => {
// TOML has no null; that is a real limit of the format, not of our renderer.
expect(() => renderToml({ k: null })).toThrow(/TOML cannot represent/);
Expand Down
Loading