From a5b9c6f8a2cdf23d4053186a198068c4f1408f33 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Fri, 17 Jul 2026 10:37:28 +0100 Subject: [PATCH] fix(cartridges): drop unchecked @ptrCast from all cartridge shims MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hypatia code_safety/zig_ptr_cast flagged 8 unchecked pointer conversions (CWE-704) in bug-filing-mcp's cartridge_shim.zig (alert 550, raised on #85). The shim is vendored byte-identical into 116 cartridges, so the same latent flaw sat in every copy and would have surfaced as a fresh alert each time one was touched. The casts were redundant rather than unsafe: std.mem.sliceTo(ptr, 0) takes the [*c]const u8 directly and scans to the NUL, and typing the test locals as [*c]const u8 removes the need to cast at the call sites. Behaviour is unchanged — the non-null precondition documented on toolIs still holds and is still enforced by invokeArgsNull. local-coord-mcp already carried exactly this fix (post-#146); this adopts that as the canonical form rather than inventing a second one, which also collapses the shim from three divergent variants to two. npc-mcp keeps its trimmed layout and takes the same transform. Verified under the CI toolchain (zig 0.15.2): all 116 shims pass zig test, and 115/116 cartridges build clean. database-mcp fails only for a missing local libsqlite3 — it fails identically on pristine main, so it is environmental and unrelated. Co-Authored-By: Claude Opus 4.8 --- .../agentic/agent-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../ffi/cartridge_shim.zig | 26 ++++++++++++------- .../claude-ai-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../model-router-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../build/bsp-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../debug/dap-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../fleet/fleet-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../boj-health-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../nesy/ml-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../nesy/nesy-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../browser-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../origene-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../buildkite-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../ci-cd/circleci-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../github-actions-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../ci-cd/hypatia-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../ci-cd/laminar-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../cloud/aws-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../cloud/cloud-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../cloudflare-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../digitalocean-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../cloud/fly-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../cloud/gcp-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../cloud/hetzner-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../cloud/linode-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../cloud/railway-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../cloud/render-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../coderag-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../sanctify-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../burble-admin-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../comms-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../discord-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../matrix-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../notifyhub-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../slack-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../telegram-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../civic-connect-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../feedback-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../config/conflow-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../config/k9iser-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../container-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../docker-hub-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../container/k8s-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../stapeln-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../arango-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../clickhouse-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../database-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../duckdb-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../mongodb-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../database/neo4j-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../database/neon-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../postgresql-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../database/redis-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../supabase-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../database/turso-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../verisimdb-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../bug-filing-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../codeseeker-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../fireflag-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../git-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../github-api-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../gitlab-api-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../kategoria-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../ephapax-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../proof-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../game-admin-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../idaptik-admin-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../gaming/npc-mcp/ffi/cartridge_shim.zig | 22 +++++++++------- .../gaming/ums-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../aerie-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../hesiod-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../iac-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../local-memory-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../obsidian-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../affinescript-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../languages/lang-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../languages/lsp-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../toolchain-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../typed-wasm-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../legal/pmpl-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../queues-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../grafana-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../observe-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../prometheus-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../sentry-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../opendata-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../airtable-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../google-docs-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../google-sheets-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../notion-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../todoist-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../jira-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../linear-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../crates-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../hackage-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../registry/hex-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../npm-registry-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../registry/opam-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../registry/opsm-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../registry/pypi-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../reposystem-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../ffi/cartridge_shim.zig | 26 ++++++++++++------- .../research/bofig-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../research-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../zotero-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../dns-shield-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../panic-attack-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../security/rokur-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../secrets-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../security/vault-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../security/vext-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../security/vordr-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../textkit-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../web/ssg-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../gossamer-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- 115 files changed, 1837 insertions(+), 1149 deletions(-) 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)); }