ci: shard control ui codeql quality

Adds a narrow CodeQL Critical Quality shard for the Control UI/control-plane surface and fixes the custom-theme font-family ReDoS finding discovered by the new shard.
This commit is contained in:
Vincent Koc
2026-04-28 20:24:19 -07:00
committed by GitHub
parent c20a3f548f
commit e53c45ba94
5 changed files with 95 additions and 3 deletions

View File

@@ -0,0 +1,36 @@
name: openclaw-codeql-ui-control-plane-critical-quality
disable-default-queries: true
queries:
- uses: security-and-quality
query-filters:
- include:
problem.severity:
- error
- exclude:
tags:
- security
paths:
- ui/src/main.ts
- ui/src/local-storage.ts
- ui/src/ui
- src/tasks/task-registry-control*.ts
paths-ignore:
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"
- "**/*.e2e.test.tsx"
- "**/*test-support*"
- "**/*test-helper*"
- "**/*mock*"
- "**/*fixture*"
- "**/*bench*"

View File

@@ -123,6 +123,27 @@ jobs:
with:
category: "/codeql-critical-quality/agent-runtime-boundary"
ui-control-plane:
name: Critical Quality (ui-control-plane)
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
submodules: false
- name: Initialize CodeQL
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
config-file: ./.github/codeql/codeql-ui-control-plane-critical-quality.yml
- name: Analyze
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/codeql-critical-quality/ui-control-plane"
plugin-boundary:
name: Critical Quality (plugin-boundary)
runs-on: blacksmith-4vcpu-ubuntu-2404

View File

@@ -273,11 +273,14 @@ the separate `/codeql-critical-quality/channel-runtime-boundary` category. The
agent-runtime-boundary job scans command execution, model/provider dispatch,
auto-reply dispatch and queues, and ACP control-plane runtime contracts under
the separate `/codeql-critical-quality/agent-runtime-boundary` category. The
ui-control-plane job scans Control UI bootstrap, local persistence, gateway
control flows, and task control-plane runtime contracts under the separate
`/codeql-critical-quality/ui-control-plane` category. The
plugin-boundary job scans loader, registry, public-surface, and Plugin SDK
entrypoint contracts under a separate `/codeql-critical-quality/plugin-boundary`
category. Keep the workflow separate from security so quality findings can be
scheduled, measured, disabled, or expanded without obscuring security signal.
Swift, Python, UI, and bundled-plugin CodeQL expansion should be added back as
Swift, Python, and bundled-plugin CodeQL expansion should be added back as
scoped or sharded follow-up work only after the narrow profiles have stable
runtime and signal.

View File

@@ -254,6 +254,27 @@ describe("custom theme import helpers", () => {
).toThrow("Unsupported tweakcn token");
});
it("validates imported font families without regex backtracking", () => {
const payload = createTweakcnPayload();
payload.cssVars.theme["font-sans"] =
'"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
expect(
normalizeImportedCustomTheme(payload, {
sourceUrl: "https://tweakcn.com/themes/cmlhfpjhw000004l4f4ax3m7z",
themeId: "cmlhfpjhw000004l4f4ax3m7z",
}).light["font-body"],
).toBe('"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif');
payload.cssVars.theme["font-sans"] = `${"Inter, ".repeat(20)}@bad`;
expect(() =>
normalizeImportedCustomTheme(payload, {
sourceUrl: "https://tweakcn.com/themes/cmlhfpjhw000004l4f4ax3m7z",
themeId: "cmlhfpjhw000004l4f4ax3m7z",
}),
).toThrow("Unsupported tweakcn token");
});
it("builds stable CSS blocks for custom dark and light themes", () => {
const css = buildCustomThemeStyles(createImportedTheme());

View File

@@ -27,7 +27,7 @@ const SAFE_COLOR_KEYWORDS = new Set(["black", "white", "transparent", "currentco
const SAFE_COLOR_FUNCTION_PATTERN =
/^(?:rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch)\([a-z0-9+\-.,/%\s]+\)$/i;
const SAFE_HEX_COLOR_PATTERN = /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
const SAFE_FONT_FAMILY_PATTERN = /^[a-z0-9\s,'"._-]+(?:,\s*[a-z0-9\s'"._-]+)*$/i;
const SAFE_FONT_FAMILY_PUNCTUATION = new Set([",", "'", '"', ".", "_", "-"]);
const MODE_TOKEN_ORDER = [
"bg",
@@ -261,12 +261,23 @@ function requireSafeExternalColorValue(value: unknown, label: string) {
throw new Error(`Unsupported tweakcn token: ${label}`);
}
function isSafeFontFamilyCharacter(char: string) {
const code = char.charCodeAt(0);
return (
(code >= 0x30 && code <= 0x39) ||
(code >= 0x41 && code <= 0x5a) ||
(code >= 0x61 && code <= 0x7a) ||
char === " " ||
SAFE_FONT_FAMILY_PUNCTUATION.has(char)
);
}
function requireSafeFontFamilyValue(value: unknown, label: string) {
const normalized = requireSafeCssValue(value, label);
if (
normalized.includes("(") ||
normalized.includes(")") ||
!SAFE_FONT_FAMILY_PATTERN.test(normalized)
!Array.from(normalized).every(isSafeFontFamilyCharacter)
) {
throw new Error(`Unsupported tweakcn token: ${label}`);
}