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
4 changes: 2 additions & 2 deletions src/adapters/kiro-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ function ensureRootObjectType(schema: unknown): Record<string, unknown> {
// Seed with the root's own properties/required so a schema like
// { type:"object", properties:{path}, required:["path"], oneOf:[...] } keeps them.
if (obj.properties && typeof obj.properties === "object") {
Object.assign(props, sanitizeKiroSchema(obj.properties) as Record<string, unknown>);
Object.assign(props, sanitizeSchemaMap(obj.properties) as Record<string, unknown>);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

bun - <<'BUN'
const source = JSON.parse('{"__proto__":{"type":"string"}}');
const out = {};

for (const [name, child] of Object.entries(source)) {
  out[name] = child;
}

if (Object.hasOwn(out, "__proto__")) {
  throw new Error("The reproduction did not expose the key-loss behavior");
}

console.log("Reproduced: __proto__ is not an own property.");
BUN

Repository: luvs01/opencodex

Length of output: 195


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- src/adapters/kiro-tools.ts ---'
sed -n '45,135p' src/adapters/kiro-tools.ts

printf '%s\n' '--- JavaScript special-key reproduction ---'
node - <<'JS'
const source = JSON.parse('{"__proto__":{"type":"string"}}');
const out = {};
for (const [name, child] of Object.entries(source)) out[name] = child;

console.log({
  sourceOwnProperty: Object.hasOwn(source, "__proto__"),
  outputOwnProperty: Object.hasOwn(out, "__proto__"),
  outputPrototype: Object.getPrototypeOf(out),
  outputPrototypeType: Object.getPrototypeOf(out)?.type,
});
JS

Repository: luvs01/opencodex

Length of output: 4853


Preserve __proto__ as a schema property name.

At src/adapters/kiro-tools.ts:106 and :121, Object.assign writes sanitized entries into normal props. sanitizeSchemaMap also writes entries into normal out at line 64. If the input contains properties.__proto__, the assignment invokes the prototype setter. The schema property is lost before Kiro receives the schema.

Use Object.create(null) for both out and props, or define entries with Object.defineProperty. Add a regression case for __proto__ beside format and pattern.

🤖 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/adapters/kiro-tools.ts` at line 106, Preserve a literal __proto__ schema
property by using null-prototype objects for the output of sanitizeSchemaMap and
the props objects receiving its entries, or define assignments as own properties
with Object.defineProperty. Update both affected Object.assign paths and add a
regression case alongside format and pattern confirming __proto__ reaches Kiro
unchanged.

}
if (Array.isArray(obj.required)) {
for (const r of obj.required) if (typeof r === "string") required.add(r);
Expand All @@ -118,7 +118,7 @@ function ensureRootObjectType(schema: unknown): Record<string, unknown> {
if (!variant || typeof variant !== "object" || Array.isArray(variant)) continue;
const v = variant as Record<string, unknown>;
if (v.properties && typeof v.properties === "object") {
Object.assign(props, sanitizeKiroSchema(v.properties) as Record<string, unknown>);
Object.assign(props, sanitizeSchemaMap(v.properties) as Record<string, unknown>);
}
if (mergeRequired && Array.isArray(v.required)) {
for (const r of v.required) if (typeof r === "string") required.add(r);
Expand Down
10 changes: 10 additions & 0 deletions tests/kiro-adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,16 @@ describe("kiro adapter — buildRequest", () => {
const withDefs = await pick({ $defs: { X: { type: "string" } }, anyOf: [{ properties: { a: { $ref: "#/$defs/X" } } }] });
expect(withDefs.$defs).toEqual({ X: { type: "string" } });
expect(withDefs.properties).toEqual({ a: { $ref: "#/$defs/X" } });

// Property names remain data while flattening, even when they collide with rejected keywords.
const keywordNames = await pick({
properties: { format: { type: "string", format: "uuid" } },
required: ["format"],
oneOf: [{ properties: { pattern: { type: "string", pattern: "^x" } } }],
});
expect(keywordNames.properties.format).toEqual({ type: "string" });
expect(keywordNames.properties.pattern).toEqual({ type: "string" });
expect(keywordNames.required).toEqual(["format"]);
});

test("tool descriptions use deterministic model-specific caps without prompt injection", async () => {
Expand Down
Loading