diff --git a/cartridges/cross-cutting/agentic/agent-mcp/ffi/cartridge_shim.zig b/cartridges/cross-cutting/agentic/agent-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/cross-cutting/agentic/agent-mcp/ffi/cartridge_shim.zig +++ b/cartridges/cross-cutting/agentic/agent-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/cross-cutting/agentic/claude-agents-power-mcp/ffi/cartridge_shim.zig b/cartridges/cross-cutting/agentic/claude-agents-power-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/cross-cutting/agentic/claude-agents-power-mcp/ffi/cartridge_shim.zig +++ b/cartridges/cross-cutting/agentic/claude-agents-power-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/cross-cutting/agentic/claude-ai-mcp/ffi/cartridge_shim.zig b/cartridges/cross-cutting/agentic/claude-ai-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/cross-cutting/agentic/claude-ai-mcp/ffi/cartridge_shim.zig +++ b/cartridges/cross-cutting/agentic/claude-ai-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/cross-cutting/agentic/model-router-mcp/ffi/cartridge_shim.zig b/cartridges/cross-cutting/agentic/model-router-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/cross-cutting/agentic/model-router-mcp/ffi/cartridge_shim.zig +++ b/cartridges/cross-cutting/agentic/model-router-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/cross-cutting/build/bsp-mcp/ffi/cartridge_shim.zig b/cartridges/cross-cutting/build/bsp-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/cross-cutting/build/bsp-mcp/ffi/cartridge_shim.zig +++ b/cartridges/cross-cutting/build/bsp-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/cross-cutting/debug/dap-mcp/ffi/cartridge_shim.zig b/cartridges/cross-cutting/debug/dap-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/cross-cutting/debug/dap-mcp/ffi/cartridge_shim.zig +++ b/cartridges/cross-cutting/debug/dap-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/cross-cutting/fleet/fleet-mcp/ffi/cartridge_shim.zig b/cartridges/cross-cutting/fleet/fleet-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/cross-cutting/fleet/fleet-mcp/ffi/cartridge_shim.zig +++ b/cartridges/cross-cutting/fleet/fleet-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/cross-cutting/health/boj-health-mcp/ffi/cartridge_shim.zig b/cartridges/cross-cutting/health/boj-health-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/cross-cutting/health/boj-health-mcp/ffi/cartridge_shim.zig +++ b/cartridges/cross-cutting/health/boj-health-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/cross-cutting/nesy/ml-mcp/ffi/cartridge_shim.zig b/cartridges/cross-cutting/nesy/ml-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/cross-cutting/nesy/ml-mcp/ffi/cartridge_shim.zig +++ b/cartridges/cross-cutting/nesy/ml-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/cross-cutting/nesy/nesy-mcp/ffi/cartridge_shim.zig b/cartridges/cross-cutting/nesy/nesy-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/cross-cutting/nesy/nesy-mcp/ffi/cartridge_shim.zig +++ b/cartridges/cross-cutting/nesy/nesy-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/automation/browser-mcp/ffi/cartridge_shim.zig b/cartridges/domains/automation/browser-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/automation/browser-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/automation/browser-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/bioinformatics/origene-mcp/ffi/cartridge_shim.zig b/cartridges/domains/bioinformatics/origene-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/bioinformatics/origene-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/bioinformatics/origene-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/ci-cd/buildkite-mcp/ffi/cartridge_shim.zig b/cartridges/domains/ci-cd/buildkite-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/ci-cd/buildkite-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/ci-cd/buildkite-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/ci-cd/circleci-mcp/ffi/cartridge_shim.zig b/cartridges/domains/ci-cd/circleci-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/ci-cd/circleci-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/ci-cd/circleci-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/ci-cd/github-actions-mcp/ffi/cartridge_shim.zig b/cartridges/domains/ci-cd/github-actions-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/ci-cd/github-actions-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/ci-cd/github-actions-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/ci-cd/hypatia-mcp/ffi/cartridge_shim.zig b/cartridges/domains/ci-cd/hypatia-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/ci-cd/hypatia-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/ci-cd/hypatia-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/ci-cd/laminar-mcp/ffi/cartridge_shim.zig b/cartridges/domains/ci-cd/laminar-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/ci-cd/laminar-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/ci-cd/laminar-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/cloud/aws-mcp/ffi/cartridge_shim.zig b/cartridges/domains/cloud/aws-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/cloud/aws-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/cloud/aws-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/cloud/cloud-mcp/ffi/cartridge_shim.zig b/cartridges/domains/cloud/cloud-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/cloud/cloud-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/cloud/cloud-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/cloud/cloudflare-mcp/ffi/cartridge_shim.zig b/cartridges/domains/cloud/cloudflare-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/cloud/cloudflare-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/cloud/cloudflare-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/cloud/digitalocean-mcp/ffi/cartridge_shim.zig b/cartridges/domains/cloud/digitalocean-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/cloud/digitalocean-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/cloud/digitalocean-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/cloud/fly-mcp/ffi/cartridge_shim.zig b/cartridges/domains/cloud/fly-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/cloud/fly-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/cloud/fly-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/cloud/gcp-mcp/ffi/cartridge_shim.zig b/cartridges/domains/cloud/gcp-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/cloud/gcp-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/cloud/gcp-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/cloud/hetzner-mcp/ffi/cartridge_shim.zig b/cartridges/domains/cloud/hetzner-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/cloud/hetzner-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/cloud/hetzner-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/cloud/linode-mcp/ffi/cartridge_shim.zig b/cartridges/domains/cloud/linode-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/cloud/linode-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/cloud/linode-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/cloud/railway-mcp/ffi/cartridge_shim.zig b/cartridges/domains/cloud/railway-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/cloud/railway-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/cloud/railway-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/cloud/render-mcp/ffi/cartridge_shim.zig b/cartridges/domains/cloud/render-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/cloud/render-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/cloud/render-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/code-quality/coderag-mcp/ffi/cartridge_shim.zig b/cartridges/domains/code-quality/coderag-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/code-quality/coderag-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/code-quality/coderag-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/code-quality/sanctify-mcp/ffi/cartridge_shim.zig b/cartridges/domains/code-quality/sanctify-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/code-quality/sanctify-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/code-quality/sanctify-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/communications/burble-admin-mcp/ffi/cartridge_shim.zig b/cartridges/domains/communications/burble-admin-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/communications/burble-admin-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/communications/burble-admin-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/communications/comms-mcp/ffi/cartridge_shim.zig b/cartridges/domains/communications/comms-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/communications/comms-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/communications/comms-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/communications/discord-mcp/ffi/cartridge_shim.zig b/cartridges/domains/communications/discord-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/communications/discord-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/communications/discord-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/communications/matrix-mcp/ffi/cartridge_shim.zig b/cartridges/domains/communications/matrix-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/communications/matrix-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/communications/matrix-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/communications/notifyhub-mcp/ffi/cartridge_shim.zig b/cartridges/domains/communications/notifyhub-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/communications/notifyhub-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/communications/notifyhub-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/communications/slack-mcp/ffi/cartridge_shim.zig b/cartridges/domains/communications/slack-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/communications/slack-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/communications/slack-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/communications/telegram-mcp/ffi/cartridge_shim.zig b/cartridges/domains/communications/telegram-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/communications/telegram-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/communications/telegram-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/community/civic-connect-mcp/ffi/cartridge_shim.zig b/cartridges/domains/community/civic-connect-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/community/civic-connect-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/community/civic-connect-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/community/feedback-mcp/ffi/cartridge_shim.zig b/cartridges/domains/community/feedback-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/community/feedback-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/community/feedback-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/config/conflow-mcp/ffi/cartridge_shim.zig b/cartridges/domains/config/conflow-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/config/conflow-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/config/conflow-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/config/k9iser-mcp/ffi/cartridge_shim.zig b/cartridges/domains/config/k9iser-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/config/k9iser-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/config/k9iser-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/container/container-mcp/ffi/cartridge_shim.zig b/cartridges/domains/container/container-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/container/container-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/container/container-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/container/docker-hub-mcp/ffi/cartridge_shim.zig b/cartridges/domains/container/docker-hub-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/container/docker-hub-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/container/docker-hub-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/container/k8s-mcp/ffi/cartridge_shim.zig b/cartridges/domains/container/k8s-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/container/k8s-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/container/k8s-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/container/stapeln-mcp/ffi/cartridge_shim.zig b/cartridges/domains/container/stapeln-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/container/stapeln-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/container/stapeln-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/database/arango-mcp/ffi/cartridge_shim.zig b/cartridges/domains/database/arango-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/database/arango-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/database/arango-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/database/clickhouse-mcp/ffi/cartridge_shim.zig b/cartridges/domains/database/clickhouse-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/database/clickhouse-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/database/clickhouse-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/database/database-mcp/ffi/cartridge_shim.zig b/cartridges/domains/database/database-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/database/database-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/database/database-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/database/duckdb-mcp/ffi/cartridge_shim.zig b/cartridges/domains/database/duckdb-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/database/duckdb-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/database/duckdb-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/database/mongodb-mcp/ffi/cartridge_shim.zig b/cartridges/domains/database/mongodb-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/database/mongodb-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/database/mongodb-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/database/neo4j-mcp/ffi/cartridge_shim.zig b/cartridges/domains/database/neo4j-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/database/neo4j-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/database/neo4j-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/database/neon-mcp/ffi/cartridge_shim.zig b/cartridges/domains/database/neon-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/database/neon-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/database/neon-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/database/postgresql-mcp/ffi/cartridge_shim.zig b/cartridges/domains/database/postgresql-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/database/postgresql-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/database/postgresql-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/database/redis-mcp/ffi/cartridge_shim.zig b/cartridges/domains/database/redis-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/database/redis-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/database/redis-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/database/supabase-mcp/ffi/cartridge_shim.zig b/cartridges/domains/database/supabase-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/database/supabase-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/database/supabase-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/database/turso-mcp/ffi/cartridge_shim.zig b/cartridges/domains/database/turso-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/database/turso-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/database/turso-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/database/verisimdb-mcp/ffi/cartridge_shim.zig b/cartridges/domains/database/verisimdb-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/database/verisimdb-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/database/verisimdb-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/development/bug-filing-mcp/ffi/cartridge_shim.zig b/cartridges/domains/development/bug-filing-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/development/bug-filing-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/development/bug-filing-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/development/codeseeker-mcp/ffi/cartridge_shim.zig b/cartridges/domains/development/codeseeker-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/development/codeseeker-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/development/codeseeker-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/development/fireflag-mcp/ffi/cartridge_shim.zig b/cartridges/domains/development/fireflag-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/development/fireflag-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/development/fireflag-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/development/git-mcp/ffi/cartridge_shim.zig b/cartridges/domains/development/git-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/development/git-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/development/git-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/development/github-api-mcp/ffi/cartridge_shim.zig b/cartridges/domains/development/github-api-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/development/github-api-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/development/github-api-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/development/gitlab-api-mcp/ffi/cartridge_shim.zig b/cartridges/domains/development/gitlab-api-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/development/gitlab-api-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/development/gitlab-api-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/education/kategoria-mcp/ffi/cartridge_shim.zig b/cartridges/domains/education/kategoria-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/education/kategoria-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/education/kategoria-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/formal-verification/ephapax-mcp/ffi/cartridge_shim.zig b/cartridges/domains/formal-verification/ephapax-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/formal-verification/ephapax-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/formal-verification/ephapax-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/formal-verification/proof-mcp/ffi/cartridge_shim.zig b/cartridges/domains/formal-verification/proof-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/formal-verification/proof-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/formal-verification/proof-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/gaming/game-admin-mcp/ffi/cartridge_shim.zig b/cartridges/domains/gaming/game-admin-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/gaming/game-admin-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/gaming/game-admin-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/gaming/idaptik-admin-mcp/ffi/cartridge_shim.zig b/cartridges/domains/gaming/idaptik-admin-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/gaming/idaptik-admin-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/gaming/idaptik-admin-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/gaming/npc-mcp/ffi/cartridge_shim.zig b/cartridges/domains/gaming/npc-mcp/ffi/cartridge_shim.zig index d01f135..7599fcb 100644 --- a/cartridges/domains/gaming/npc-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/gaming/npc-mcp/ffi/cartridge_shim.zig @@ -37,8 +37,12 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string literal. /// Caller must have already verified `tool_name` is non-null. +/// +/// Implementation note (CWE-704 fix): uses `std.mem.sliceTo(ptr, 0)` which +/// scans the C string up to the first NUL — no `@ptrCast` and no `[*:0]` +/// re-typing. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -83,18 +87,18 @@ test "writeResult: too small returns -3 and sets required length" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/gaming/ums-mcp/ffi/cartridge_shim.zig b/cartridges/domains/gaming/ums-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/gaming/ums-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/gaming/ums-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/infrastructure/aerie-mcp/ffi/cartridge_shim.zig b/cartridges/domains/infrastructure/aerie-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/infrastructure/aerie-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/infrastructure/aerie-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/infrastructure/hesiod-mcp/ffi/cartridge_shim.zig b/cartridges/domains/infrastructure/hesiod-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/infrastructure/hesiod-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/infrastructure/hesiod-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/infrastructure/iac-mcp/ffi/cartridge_shim.zig b/cartridges/domains/infrastructure/iac-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/infrastructure/iac-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/infrastructure/iac-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/knowledge/local-memory-mcp/ffi/cartridge_shim.zig b/cartridges/domains/knowledge/local-memory-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/knowledge/local-memory-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/knowledge/local-memory-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/knowledge/obsidian-mcp/ffi/cartridge_shim.zig b/cartridges/domains/knowledge/obsidian-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/knowledge/obsidian-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/knowledge/obsidian-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/languages/affinescript-mcp/ffi/cartridge_shim.zig b/cartridges/domains/languages/affinescript-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/languages/affinescript-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/languages/affinescript-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/languages/lang-mcp/ffi/cartridge_shim.zig b/cartridges/domains/languages/lang-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/languages/lang-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/languages/lang-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/languages/lsp-mcp/ffi/cartridge_shim.zig b/cartridges/domains/languages/lsp-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/languages/lsp-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/languages/lsp-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/languages/toolchain-mcp/ffi/cartridge_shim.zig b/cartridges/domains/languages/toolchain-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/languages/toolchain-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/languages/toolchain-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/languages/typed-wasm-mcp/ffi/cartridge_shim.zig b/cartridges/domains/languages/typed-wasm-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/languages/typed-wasm-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/languages/typed-wasm-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/legal/pmpl-mcp/ffi/cartridge_shim.zig b/cartridges/domains/legal/pmpl-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/legal/pmpl-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/legal/pmpl-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/messaging/queues-mcp/ffi/cartridge_shim.zig b/cartridges/domains/messaging/queues-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/messaging/queues-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/messaging/queues-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/observability/grafana-mcp/ffi/cartridge_shim.zig b/cartridges/domains/observability/grafana-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/observability/grafana-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/observability/grafana-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/observability/observe-mcp/ffi/cartridge_shim.zig b/cartridges/domains/observability/observe-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/observability/observe-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/observability/observe-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/observability/prometheus-mcp/ffi/cartridge_shim.zig b/cartridges/domains/observability/prometheus-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/observability/prometheus-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/observability/prometheus-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/observability/sentry-mcp/ffi/cartridge_shim.zig b/cartridges/domains/observability/sentry-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/observability/sentry-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/observability/sentry-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/open-data/opendata-mcp/ffi/cartridge_shim.zig b/cartridges/domains/open-data/opendata-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/open-data/opendata-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/open-data/opendata-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/productivity/airtable-mcp/ffi/cartridge_shim.zig b/cartridges/domains/productivity/airtable-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/productivity/airtable-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/productivity/airtable-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/productivity/google-docs-mcp/ffi/cartridge_shim.zig b/cartridges/domains/productivity/google-docs-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/productivity/google-docs-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/productivity/google-docs-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/productivity/google-sheets-mcp/ffi/cartridge_shim.zig b/cartridges/domains/productivity/google-sheets-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/productivity/google-sheets-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/productivity/google-sheets-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/productivity/notion-mcp/ffi/cartridge_shim.zig b/cartridges/domains/productivity/notion-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/productivity/notion-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/productivity/notion-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/productivity/todoist-mcp/ffi/cartridge_shim.zig b/cartridges/domains/productivity/todoist-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/productivity/todoist-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/productivity/todoist-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/project-management/jira-mcp/ffi/cartridge_shim.zig b/cartridges/domains/project-management/jira-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/project-management/jira-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/project-management/jira-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/project-management/linear-mcp/ffi/cartridge_shim.zig b/cartridges/domains/project-management/linear-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/project-management/linear-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/project-management/linear-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/registry/crates-mcp/ffi/cartridge_shim.zig b/cartridges/domains/registry/crates-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/registry/crates-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/registry/crates-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/registry/hackage-mcp/ffi/cartridge_shim.zig b/cartridges/domains/registry/hackage-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/registry/hackage-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/registry/hackage-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/registry/hex-mcp/ffi/cartridge_shim.zig b/cartridges/domains/registry/hex-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/registry/hex-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/registry/hex-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/registry/npm-registry-mcp/ffi/cartridge_shim.zig b/cartridges/domains/registry/npm-registry-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/registry/npm-registry-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/registry/npm-registry-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/registry/opam-mcp/ffi/cartridge_shim.zig b/cartridges/domains/registry/opam-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/registry/opam-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/registry/opam-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/registry/opsm-mcp/ffi/cartridge_shim.zig b/cartridges/domains/registry/opsm-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/registry/opsm-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/registry/opsm-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/registry/pypi-mcp/ffi/cartridge_shim.zig b/cartridges/domains/registry/pypi-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/registry/pypi-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/registry/pypi-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/repository-management/reposystem-mcp/ffi/cartridge_shim.zig b/cartridges/domains/repository-management/reposystem-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/repository-management/reposystem-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/repository-management/reposystem-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/research/academic-workflow-mcp/ffi/cartridge_shim.zig b/cartridges/domains/research/academic-workflow-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/research/academic-workflow-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/research/academic-workflow-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/research/bofig-mcp/ffi/cartridge_shim.zig b/cartridges/domains/research/bofig-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/research/bofig-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/research/bofig-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/research/research-mcp/ffi/cartridge_shim.zig b/cartridges/domains/research/research-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/research/research-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/research/research-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/research/zotero-mcp/ffi/cartridge_shim.zig b/cartridges/domains/research/zotero-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/research/zotero-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/research/zotero-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/security/dns-shield-mcp/ffi/cartridge_shim.zig b/cartridges/domains/security/dns-shield-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/security/dns-shield-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/security/dns-shield-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/security/panic-attack-mcp/ffi/cartridge_shim.zig b/cartridges/domains/security/panic-attack-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/security/panic-attack-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/security/panic-attack-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/security/rokur-mcp/ffi/cartridge_shim.zig b/cartridges/domains/security/rokur-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/security/rokur-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/security/rokur-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/security/secrets-mcp/ffi/cartridge_shim.zig b/cartridges/domains/security/secrets-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/security/secrets-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/security/secrets-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/security/vault-mcp/ffi/cartridge_shim.zig b/cartridges/domains/security/vault-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/security/vault-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/security/vault-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/security/vext-mcp/ffi/cartridge_shim.zig b/cartridges/domains/security/vext-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/security/vext-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/security/vext-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/security/vordr-mcp/ffi/cartridge_shim.zig b/cartridges/domains/security/vordr-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/security/vordr-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/security/vordr-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/utilities/textkit-mcp/ffi/cartridge_shim.zig b/cartridges/domains/utilities/textkit-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/utilities/textkit-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/utilities/textkit-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/domains/web/ssg-mcp/ffi/cartridge_shim.zig b/cartridges/domains/web/ssg-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/domains/web/ssg-mcp/ffi/cartridge_shim.zig +++ b/cartridges/domains/web/ssg-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/templates/gossamer-mcp/ffi/cartridge_shim.zig b/cartridges/templates/gossamer-mcp/ffi/cartridge_shim.zig index 0e399db..5b0fac8 100644 --- a/cartridges/templates/gossamer-mcp/ffi/cartridge_shim.zig +++ b/cartridges/templates/gossamer-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); }