fix(secrets): preserve Windows ACL diagnostics (#120211)

* fix(secrets): preserve Windows ACL diagnostics

* fix(secrets): make Windows path security proof deterministic

* test(secrets): isolate Windows ACL tool failures

* test(secrets): preserve ACL preload process contract

* test(ci): route Doctor ACL proof to Windows

* test(qa): normalize Clack note borders

* test(ci): register Windows ACL preload for deadcode checks
This commit is contained in:
Vincent Koc
2026-08-09 03:48:42 +08:00
committed by GitHub
parent 1889764369
commit 38039f5ea8
14 changed files with 618 additions and 25 deletions
@@ -1,10 +1,14 @@
// QA Lab product proof for doctor gateway auth and SecretRef behavior.
import { execFile } from "node:child_process";
import fs from "node:fs/promises";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { promisify } from "node:util";
import { afterEach, describe, expect, it } from "vitest";
import { stripAnsiSequences } from "../../../../packages/terminal-core/src/ansi.js";
import type { OpenClawConfig } from "../../../../src/config/types.openclaw.js";
import { withSecureTestNodeCommand } from "../../../../src/secrets/test-node-command.test-support.js";
import { forceNativeWindowsAclToolsUnavailable } from "../../../../src/test-utils/vitest-spies.js";
import {
createOpenClawTestInstance,
type OpenClawTestInstance,
@@ -12,6 +16,7 @@ import {
let instance: OpenClawTestInstance | undefined;
type GatewayToken = NonNullable<NonNullable<OpenClawConfig["gateway"]>["auth"]>["token"];
const execFileAsync = promisify(execFile);
afterEach(async () => {
await instance?.cleanup();
@@ -23,7 +28,7 @@ function outputOf(result: { stderr: string; stdout: string }): string {
}
function normalizedOutputOf(result: { stderr: string; stdout: string }): string {
return stripAnsiSequences(outputOf(result)).replace(/\s+/g, " ").trim();
return stripAnsiSequences(outputOf(result)).replaceAll("│", " ").replace(/\s+/g, " ").trim();
}
async function writeConfig(config: OpenClawConfig): Promise<void> {
@@ -45,6 +50,24 @@ function localGatewayConfig(token?: GatewayToken): OpenClawConfig {
};
}
async function expectAclFixturePreservesExecFileContract(preloadUrl: string): Promise<void> {
const probe = [
'import { execFile } from "node:child_process";',
'import { promisify } from "node:util";',
'const promise = promisify(execFile)(process.execPath, ["--version"], { encoding: "utf8" });',
'if (!promise.child || typeof promise.child.kill !== "function") process.exit(2);',
"const result = await promise;",
'if (!result || typeof result.stdout !== "string" || typeof result.stderr !== "string") process.exit(3);',
'process.stdout.write("ok");',
].join("");
const result = await execFileAsync(
process.execPath,
[`--import=${preloadUrl}`, "--input-type=module", "--eval", probe],
{ encoding: "utf8" },
);
expect(result).toEqual({ stdout: "ok", stderr: "" });
}
describe("doctor auth and SecretRef product proof", () => {
it(
"preserves SecretRef ownership while proving resolution, fallback, exec gating, and token generation",
@@ -103,6 +126,50 @@ describe("doctor auth and SecretRef product proof", () => {
};
expect(unresolvedConfig.gateway?.auth?.token).toEqual(unresolvedRef);
const aclFixtureUrl = pathToFileURL(
path.resolve("test/fixtures/windows-acl-tools-unavailable.mjs"),
).href;
await expectAclFixturePreservesExecFileContract(aclFixtureUrl);
if (process.platform === "win32") {
forceNativeWindowsAclToolsUnavailable(instance.env, aclFixtureUrl);
}
const filePath = path.join(instance.stateDir, "doctor-file-secretref.json");
const fileSecret = "qa-file-token";
await fs.writeFile(filePath, JSON.stringify({ gateway: { token: fileSecret } }), {
mode: 0o600,
});
await writeConfig({
...localGatewayConfig({
source: "file",
provider: "filemain",
id: "/gateway/token",
}),
secrets: {
providers: {
filemain: {
source: "file",
path: filePath,
},
},
},
});
const fileResult = await instance.cli(
["doctor", "--non-interactive", "--no-workspace-suggestions"],
{ timeoutMs: 120_000 },
);
expect(fileResult.code).toBe(0);
const fileOutput = normalizedOutputOf(fileResult);
if (process.platform === "win32") {
expect(fileOutput).toMatch(
/Gateway token SecretRef could not be resolved: .*Windows path security could not be verified\. Restore Windows path security verification, or use an existing secret file whose owner and ACLs OpenClaw can verify\./,
);
expect(fileOutput).not.toContain(filePath);
} else {
expect(fileOutput).not.toContain("Gateway token SecretRef could not be resolved");
}
expect(fileOutput).not.toContain(fileSecret);
const execMarker = path.join(instance.stateDir, "doctor-exec-secretref.marker");
const execScript = [
"const fs = require('node:fs');",
@@ -146,8 +213,10 @@ describe("doctor auth and SecretRef product proof", () => {
const execAllowedOutput = normalizedOutputOf(execAllowed);
if (process.platform === "win32") {
expect(execAllowedOutput).toMatch(
/Gateway token SecretRef could not be resolved: .*ACL verification unavailable on Windows/,
/Gateway token SecretRef could not be resolved: .*Windows path security could not be verified\. Restore Windows path security verification, or use an existing provider command whose owner and ACLs OpenClaw can verify\./,
);
expect(execAllowedOutput).not.toContain(command);
expect(execAllowedOutput).not.toContain(execMarker);
await expect(fs.access(execMarker)).rejects.toThrow();
} else {
await expect(fs.readFile(execMarker, "utf8")).resolves.toBe("executed");
@@ -183,6 +252,8 @@ describe("doctor auth and SecretRef product proof", () => {
execRefGated: true,
execRefAllowed: process.platform !== "win32",
execRefWindowsAclBlocked: process.platform === "win32",
fileRefAllowed: process.platform !== "win32",
fileRefWindowsAclBlocked: process.platform === "win32",
generatedTokenPersisted: true,
})}`,
);