Skip to content

Commit a29694c

Browse files
authored
feat: pass through zero data retention opt-in (CMD_ZDR) (#8)
Command Code exposes ZDR as x-cmd-zdr: 1, the same opt-in its CLI reads from CMD_ZDR=1. Mirror it for plugin users and strip any caller-supplied header when the opt-in is absent, so a session that never asked for ZDR cannot emit the flag by accident. Applied on the strict Command Code host only, never on a lookalike that merely shares the request path.
1 parent 49104df commit a29694c

8 files changed

Lines changed: 206 additions & 3 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) - SemVer.
55

66
## [Unreleased]
77

8+
## [1.0.7] - 2026-10-31
9+
10+
### Added
11+
- Zero data retention passthrough. With `CMD_ZDR=1` every request to
12+
`api.commandcode.ai` carries `x-cmd-zdr: 1`, mirroring the Command Code CLI.
13+
When the opt-in is absent, any caller-supplied `x-cmd-zdr` header is stripped
14+
so a session that never asked for ZDR cannot emit the flag by accident. The
15+
header is applied on the strict Command Code host only, never on a lookalike
16+
that merely shares the request path.
17+
818
## [1.0.6] - 2026-10-25
919

1020
### Added

‎README.es.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,18 @@ un request):
9494
- **Registro de reintentos** - persiste los reintentos de transporte solo de Command
9595
Code, para poder diagnosticar una caida upstream a posteriori.
9696

97+
### Zero data retention (opt-in)
98+
99+
Command Code expone ZDR como cabecera de peticion (`x-cmd-zdr: 1`), el mismo
100+
opt-in que su CLI lee de `CMD_ZDR=1`. El plugin lo replica:
101+
102+
- `CMD_ZDR=1` - toda peticion a `api.commandcode.ai` lleva `x-cmd-zdr: 1`.
103+
- En cualquier otro caso - se elimina cualquier `x-cmd-zdr` enviada por el
104+
cliente, para que una sesion sin opt-in no pueda emitir la cabecera por error.
105+
106+
La cabecera solo se aplica en el host estricto de Command Code, nunca en un host
107+
parecido que solo comparta `/provider/v1/...` en la ruta.
108+
97109
### Telemetria de cuota
98110

99111
- Herramienta `commandcode_quota` y comando `/commandcode-quota`: plan, estado,

‎README.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,18 @@ request):
8989
- **Retry logger** - persists transport retries for Command Code only, so an
9090
upstream outage can be diagnosed after the fact.
9191

92+
### Zero data retention (opt-in)
93+
94+
Command Code exposes ZDR as a request header (`x-cmd-zdr: 1`), the same opt-in
95+
its CLI reads from `CMD_ZDR=1`. The plugin mirrors it:
96+
97+
- `CMD_ZDR=1` - every request to `api.commandcode.ai` carries `x-cmd-zdr: 1`.
98+
- Otherwise - any caller-supplied `x-cmd-zdr` header is stripped, so a session
99+
that never opted in cannot emit the flag by accident.
100+
101+
The header is applied only on the strict Command Code host, never on a lookalike
102+
that merely shares `/provider/v1/...` in its path.
103+
92104
### Quota telemetry
93105

94106
- Tool `commandcode_quota` and command `/commandcode-quota`: plan, status,

‎index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export default plugin;
44
export * from "./src/auth/resolver.ts";
55
export * from "./src/client/api.ts";
66
export * from "./src/hooks/resilience.ts";
7+
export * from "./src/hooks/zdr.ts";
78
export * from "./src/tools/quota.ts";

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "opencode-commandcode",
3-
"version": "1.0.6",
3+
"version": "1.0.7",
44
"description": "Production-grade OpenCode plugin for Command Code: dynamic model discovery, stability hooks and quota telemetry",
55
"main": "index.ts",
66
"type": "module",

‎src/hooks/zdr.ts‎

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Zero data retention (ZDR) passthrough.
3+
*
4+
* Command Code exposes ZDR as a request header (`x-cmd-zdr: 1`), the same
5+
* opt-in its CLI reads from `CMD_ZDR=1`. The header is only emitted when the
6+
* user explicitly opts in:
7+
*
8+
* - `CMD_ZDR=1` -> every Command Code request carries `x-cmd-zdr: 1`
9+
* - anything else -> any caller-supplied `x-cmd-zdr` header is stripped, so
10+
* a session that did not opt in can never emit it by accident
11+
*
12+
* Stripping (instead of ignoring) matters because the header is a policy
13+
* control: a lookalike client or a stale config must not be able to turn it on
14+
* for a user who never asked for it.
15+
*/
16+
17+
export const ZDR_HEADER = "x-cmd-zdr";
18+
19+
/** True only for the explicit opt-in value documented by the CLI. */
20+
export function isZdrEnabled(env: Record<string, string | undefined> = process.env): boolean {
21+
return env.CMD_ZDR === "1";
22+
}
23+
24+
/**
25+
* Applies the ZDR policy to a request's headers.
26+
*
27+
* Headers is case-insensitive, so `get`/`delete`/`set` cover every casing the
28+
* caller may have used.
29+
*/
30+
export function applyZdrHeader(
31+
headers: Headers,
32+
env: Record<string, string | undefined> = process.env
33+
): void {
34+
if (headers.get(ZDR_HEADER) !== null) {
35+
headers.delete(ZDR_HEADER);
36+
}
37+
if (isZdrEnabled(env)) {
38+
headers.set(ZDR_HEADER, "1");
39+
}
40+
}

‎src/index.ts‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
supportsChatCompletions,
1414
supportsVision,
1515
} from "./hooks/resilience.ts";
16+
import { applyZdrHeader } from "./hooks/zdr.ts";
1617
import { getQuotaReport } from "./tools/quota.ts";
1718
import { describeRetryEvent } from "./telemetry.ts";
1819
import { buildReleaseDate, freeCostEntry } from "./catalog.ts";
@@ -166,7 +167,18 @@ export default {
166167
}
167168
}
168169

169-
// B. Credential injection, STRICT origin only (no lookalike hosts,
170+
// B. Zero data retention policy (opt-in only, spoofed headers stripped).
171+
// Strict origin: the header is a Command Code policy flag and must
172+
// never be sent to a host that only happens to share the path.
173+
if (isCommandCodeHost(url)) {
174+
try {
175+
applyZdrHeader(req.headers);
176+
} catch {
177+
// immutable headers in this runtime
178+
}
179+
}
180+
181+
// C. Credential injection, STRICT origin only (no lookalike hosts,
170182
// no path-based matching: this is where the API key travels).
171183
if (isCommandCodeHost(url) && !req.headers.has("authorization")) {
172184
const key = resolveApiKey();
@@ -179,7 +191,7 @@ export default {
179191
}
180192
}
181193

182-
// C. Payload sanitizer (no credentials involved).
194+
// D. Payload sanitizer (no credentials involved).
183195
try {
184196
const method = String(req.method || "GET").toUpperCase();
185197
if (method === "GET" || method === "HEAD") return;

‎tests/zdr.test.ts‎

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
2+
import plugin from "../src/index.ts";
3+
import { applyZdrHeader, isZdrEnabled, ZDR_HEADER } from "../src/hooks/zdr.ts";
4+
5+
const URL_CC = "https://api.commandcode.ai/provider/v1/chat/completions";
6+
7+
function makeCtx() {
8+
const hooks: Record<string, ((event: any) => Promise<void>)[]> = {
9+
"http.request": [],
10+
"http.response": [],
11+
retry: [],
12+
};
13+
const ctx: any = {
14+
session: {
15+
hook: async (name: any, cb: any) => {
16+
hooks[name]?.push(cb);
17+
return { dispose: async () => {} };
18+
},
19+
synthetic: async () => ({}),
20+
},
21+
model: { transform: async () => {} },
22+
tool: { transform: async () => {} },
23+
command: { transform: async () => {} },
24+
};
25+
return { ctx, hooks };
26+
}
27+
28+
async function runHook(hooks: Record<string, ((event: any) => Promise<void>)[]>, request: Request) {
29+
const event: any = { request, sessionID: "ses_test" };
30+
for (const cb of hooks["http.request"] ?? []) {
31+
await cb(event);
32+
}
33+
return event.request as Request;
34+
}
35+
36+
describe("isZdrEnabled", () => {
37+
test("only the documented opt-in value enables ZDR", () => {
38+
expect(isZdrEnabled({ CMD_ZDR: "1" })).toBe(true);
39+
expect(isZdrEnabled({ CMD_ZDR: "0" })).toBe(false);
40+
expect(isZdrEnabled({ CMD_ZDR: "true" })).toBe(false);
41+
expect(isZdrEnabled({})).toBe(false);
42+
});
43+
});
44+
45+
describe("applyZdrHeader", () => {
46+
test("sets the header when opted in", () => {
47+
const headers = new Headers();
48+
applyZdrHeader(headers, { CMD_ZDR: "1" });
49+
expect(headers.get(ZDR_HEADER)).toBe("1");
50+
});
51+
52+
test("strips a caller-supplied header when not opted in", () => {
53+
const headers = new Headers({ "x-cmd-zdr": "1" });
54+
applyZdrHeader(headers, {});
55+
expect(headers.get(ZDR_HEADER)).toBeNull();
56+
});
57+
58+
test("strips any casing of the header when not opted in", () => {
59+
const headers = new Headers({ "X-CMD-ZDR": "1" });
60+
applyZdrHeader(headers, { CMD_ZDR: "0" });
61+
expect(headers.get(ZDR_HEADER)).toBeNull();
62+
});
63+
64+
test("keeps exactly one header value when opted in", () => {
65+
const headers = new Headers();
66+
headers.set("x-cmd-zdr", "0");
67+
applyZdrHeader(headers, { CMD_ZDR: "1" });
68+
expect(headers.get(ZDR_HEADER)).toBe("1");
69+
});
70+
});
71+
72+
describe("plugin ZDR hook", () => {
73+
const previous = process.env.CMD_ZDR;
74+
75+
afterEach(() => {
76+
if (previous === undefined) delete process.env.CMD_ZDR;
77+
else process.env.CMD_ZDR = previous;
78+
});
79+
80+
test("emits x-cmd-zdr on Command Code requests when CMD_ZDR=1", async () => {
81+
process.env.CMD_ZDR = "1";
82+
const { ctx, hooks } = makeCtx();
83+
await plugin.setup(ctx);
84+
85+
const request = new Request(URL_CC, { method: "POST", body: "{}" });
86+
const outgoing = await runHook(hooks, request);
87+
expect(outgoing.headers.get(ZDR_HEADER)).toBe("1");
88+
});
89+
90+
test("strips a spoofed header when CMD_ZDR is not set", async () => {
91+
delete process.env.CMD_ZDR;
92+
const { ctx, hooks } = makeCtx();
93+
await plugin.setup(ctx);
94+
95+
const request = new Request(URL_CC, {
96+
method: "POST",
97+
body: "{}",
98+
headers: { "x-cmd-zdr": "1" },
99+
});
100+
const outgoing = await runHook(hooks, request);
101+
expect(outgoing.headers.get(ZDR_HEADER)).toBeNull();
102+
});
103+
104+
test("never touches a lookalike host that only shares the path", async () => {
105+
process.env.CMD_ZDR = "1";
106+
const { ctx, hooks } = makeCtx();
107+
await plugin.setup(ctx);
108+
109+
const request = new Request("https://api.commandcode.ai.evil.com/provider/v1/chat/completions", {
110+
method: "POST",
111+
body: "{}",
112+
});
113+
const outgoing = await runHook(hooks, request);
114+
expect(outgoing.headers.get(ZDR_HEADER)).toBeNull();
115+
});
116+
});

0 commit comments

Comments
 (0)