feat(device-pod-cli): v0.2 hwpod prefers HWLAB_API_KEY over legacy key

- authHeaders now reads HWLAB_API_KEY (env or --apiKey/--bearerToken) first; only when hwl_live_ prefix is present
- when both are set, HWLAB_API_KEY wins and x-hwlab-device-pod-api-key is suppressed
- new test asserts the precedence using a fake API key against a local http server
- help auth hint updated to mention the preferred credential
This commit is contained in:
Codex
2026-06-04 02:16:17 +08:00
committed by Codex Agent
parent ad53ff6ffb
commit bcec7e6934
2 changed files with 47 additions and 2 deletions
+41
View File
@@ -699,3 +699,44 @@ function serverUrl(server: ReturnType<typeof createServer>) {
if (!address || typeof address === "string") throw new Error("server address is unavailable");
return `http://127.0.0.1:${address.port}`;
}
test("device-pod-cli prefers HWLAB_API_KEY over HWLAB_DEVICE_POD_API_KEY when both are set", async () => {
const seen: any[] = [];
const server = createServer((request, response) => {
let chunks: Buffer[] = [];
request.on("data", (chunk) => chunks.push(chunk));
request.on("end", () => {
const body = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
seen.push({
url: request.url,
method: request.method,
devicePodKey: request.headers["x-hwlab-device-pod-api-key"] ?? null,
authorization: request.headers["authorization"] ?? null
});
response.writeHead(200, { "content-type": "application/json" });
response.end(JSON.stringify({ ok: true, status: "ok", devicePods: [], count: 0 }));
});
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const port = server.address().port;
const result = await runDevicePodCli(["profile", "list"], {
env: {
HWLAB_RUNTIME_API_URL: `http://127.0.0.1:${port}`,
HWLAB_RUNTIME_NAMESPACE: "hwlab-v02",
HWLAB_RUNTIME_LANE: "v02",
HWLAB_RUNTIME_ENDPOINT_LOCKED: "1",
HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME: "1",
HWLAB_DEVICE_POD_API_KEY: "device-pod-api-key-a",
HWLAB_API_KEY: "hwl_live_user-default-key-1234567890"
},
now: () => "2026-06-03T00:00:00.000Z"
});
assert.equal(result.exitCode, 0);
assert.equal(seen.length, 1);
assert.equal(seen[0].devicePodKey, null);
assert.equal(seen[0].authorization, "Bearer hwl_live_user-default-key-1234567890");
} finally {
await new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())));
}
});
+6 -2
View File
@@ -60,7 +60,7 @@ function help() {
localProfileAuthority: false,
configuration: {
apiBaseUrl: "auto-located from assembled HWLAB_RUNTIME_* / HWLAB_DEVICE_POD_* env; manual endpoint arguments are rejected when HWLAB_RUNTIME_ENDPOINT_LOCKED=1",
auth: "assembled HWLAB_DEVICE_POD_API_KEY for AgentRun; browser cookie or explicit user session for local debug"
auth: "preferred HWLAB_API_KEY (hwl_live_...) for AgentRun and CLI; legacy HWLAB_DEVICE_POD_API_KEY or cookie session for transition",
},
usage: [
"hwpod profile list",
@@ -565,7 +565,10 @@ const uartJsonRpcOptionKeys = [
];
function defaultOperation(surface: string) { return surface === "workspace" ? "ls" : surface === "debug-probe" ? "status" : "read"; }
async function authHeaders(parsed: ParsedArgs, env: EnvLike, endpoint: any) {
const apiKey = text(parsed.devicePodApiKey ?? env.HWLAB_DEVICE_POD_API_KEY);
const userApiKey = text(parsed.apiKey ?? parsed.bearerToken ?? env.HWLAB_API_KEY ?? env.HWLAB_BEARER_TOKEN);
const legacyDevicePodApiKey = text(parsed.devicePodApiKey ?? env.HWLAB_DEVICE_POD_API_KEY);
const useUserApiKey = userApiKey.startsWith("hwl_live_");
const apiKey = useUserApiKey ? "" : legacyDevicePodApiKey;
const explicitCookie = text(parsed.cookie ?? env.HWLAB_SESSION_COOKIE);
const sessionToken = text(parsed.sessionToken ?? env.HWLAB_CLOUD_API_SESSION_TOKEN ?? env.HWLAB_SESSION_TOKEN);
const bearer = text(parsed.bearerToken ?? env.HWLAB_BEARER_TOKEN);
@@ -573,6 +576,7 @@ async function authHeaders(parsed: ParsedArgs, env: EnvLike, endpoint: any) {
const cookie = explicitCookie || stateCookie;
return clean({
...(apiKey ? { "x-hwlab-device-pod-api-key": apiKey } : {}),
...(useUserApiKey ? { authorization: `Bearer ${userApiKey}` } : {}),
...(cookie ? { cookie: cookie.includes("=") ? cookie : `hwlab_session=${encodeURIComponent(cookie)}` } : {}),
...(sessionToken ? { "x-hwlab-session-token": sessionToken } : {}),
...(bearer ? { authorization: `Bearer ${bearer}` } : {})