comber 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -0
- package/README.md +732 -0
- package/action.yml +279 -0
- package/comber.config.example.json +64 -0
- package/dist/api/classify.js +99 -0
- package/dist/api/classify.js.map +1 -0
- package/dist/api/driver.js +235 -0
- package/dist/api/driver.js.map +1 -0
- package/dist/api/graphql-driver.js +150 -0
- package/dist/api/graphql-driver.js.map +1 -0
- package/dist/api/graphql.js +115 -0
- package/dist/api/graphql.js.map +1 -0
- package/dist/api/har-driver.js +167 -0
- package/dist/api/har-driver.js.map +1 -0
- package/dist/api/har.js +100 -0
- package/dist/api/har.js.map +1 -0
- package/dist/api/load.js +83 -0
- package/dist/api/load.js.map +1 -0
- package/dist/api/openapi.js +159 -0
- package/dist/api/openapi.js.map +1 -0
- package/dist/api/request.js +141 -0
- package/dist/api/request.js.map +1 -0
- package/dist/api/schema.js +126 -0
- package/dist/api/schema.js.map +1 -0
- package/dist/cli.js +352 -0
- package/dist/cli.js.map +1 -0
- package/dist/comment.js +164 -0
- package/dist/comment.js.map +1 -0
- package/dist/config.js +664 -0
- package/dist/config.js.map +1 -0
- package/dist/connectors/builtin/discord.js +55 -0
- package/dist/connectors/builtin/github-checks.js +53 -0
- package/dist/connectors/builtin/junit.js +70 -0
- package/dist/connectors/builtin/linear.js +58 -0
- package/dist/connectors/builtin/slack.js +60 -0
- package/dist/connectors/builtin/webhook.js +39 -0
- package/dist/connectors/index.js +3 -0
- package/dist/connectors/loader.js +72 -0
- package/dist/connectors/registry.js +28 -0
- package/dist/connectors/types.js +23 -0
- package/dist/core/action-gate.js +48 -0
- package/dist/core/baseline.js +85 -0
- package/dist/core/baseline.js.map +1 -0
- package/dist/core/blind-spots.js +22 -0
- package/dist/core/blind-spots.js.map +1 -0
- package/dist/core/contract-extras.js +1 -0
- package/dist/core/contract-extras.js.map +1 -0
- package/dist/core/contract.js +1 -0
- package/dist/core/contract.js.map +1 -0
- package/dist/core/coverage.js +70 -0
- package/dist/core/coverage.js.map +1 -0
- package/dist/core/crawl.js +229 -0
- package/dist/core/crawl.js.map +1 -0
- package/dist/core/egress.js +128 -0
- package/dist/core/egress.js.map +1 -0
- package/dist/core/ledger.js +41 -0
- package/dist/core/ledger.js.map +1 -0
- package/dist/core/net.js +39 -0
- package/dist/core/pipeline.js +191 -0
- package/dist/core/pipeline.js.map +1 -0
- package/dist/core/plan.js +121 -0
- package/dist/core/plan.js.map +1 -0
- package/dist/core/redact.js +240 -0
- package/dist/core/redact.js.map +1 -0
- package/dist/core/replay.js +263 -0
- package/dist/core/replay.js.map +1 -0
- package/dist/core/report.js +253 -0
- package/dist/core/report.js.map +1 -0
- package/dist/core/safety-judge.js +116 -0
- package/dist/core/safety.js +92 -0
- package/dist/core/safety.js.map +1 -0
- package/dist/core/signal-normalize.js +190 -0
- package/dist/core/signal-normalize.js.map +1 -0
- package/dist/core/signals.js +5 -0
- package/dist/core/signals.js.map +1 -0
- package/dist/core/triage.js +104 -0
- package/dist/core/triage.js.map +1 -0
- package/dist/core/types.js +1 -0
- package/dist/core/types.js.map +1 -0
- package/dist/desktop/desktop-profile.js +6 -0
- package/dist/desktop/desktop-profile.js.map +1 -0
- package/dist/desktop/driver.js +433 -0
- package/dist/desktop/driver.js.map +1 -0
- package/dist/desktop/evidence.js +206 -0
- package/dist/desktop/evidence.js.map +1 -0
- package/dist/desktop/macos/accessibility-runner.js +118 -0
- package/dist/desktop/macos/accessibility-runner.js.map +1 -0
- package/dist/desktop/macos/types.js +1 -0
- package/dist/desktop/macos/types.js.map +1 -0
- package/dist/desktop/preflight.js +107 -0
- package/dist/desktop/preflight.js.map +1 -0
- package/dist/desktop/proxy-proof.js +185 -0
- package/dist/desktop/proxy-proof.js.map +1 -0
- package/dist/desktop/view.js +348 -0
- package/dist/desktop/view.js.map +1 -0
- package/dist/desktop/windows/types.js +1 -0
- package/dist/desktop/windows/types.js.map +1 -0
- package/dist/desktop/windows/uia-runner.js +127 -0
- package/dist/desktop/windows/uia-runner.js.map +1 -0
- package/dist/native/apple.js +14 -0
- package/dist/native/apple.js.map +1 -0
- package/dist/native/device-profile.js +6 -0
- package/dist/native/device-profile.js.map +1 -0
- package/dist/native/driver.js +416 -0
- package/dist/native/driver.js.map +1 -0
- package/dist/native/evidence.js +164 -0
- package/dist/native/evidence.js.map +1 -0
- package/dist/native/load.js +9 -0
- package/dist/native/load.js.map +1 -0
- package/dist/native/maestro.js +153 -0
- package/dist/native/maestro.js.map +1 -0
- package/dist/native/preflight.js +72 -0
- package/dist/native/preflight.js.map +1 -0
- package/dist/native/proxy-proof.js +182 -0
- package/dist/native/proxy-proof.js.map +1 -0
- package/dist/native/samsung.js +34 -0
- package/dist/native/samsung.js.map +1 -0
- package/dist/native/signals.js +50 -0
- package/dist/native/signals.js.map +1 -0
- package/dist/native/view.js +139 -0
- package/dist/native/view.js.map +1 -0
- package/dist/profile.js +237 -0
- package/dist/profile.js.map +1 -0
- package/dist/sink.js +134 -0
- package/dist/sink.js.map +1 -0
- package/dist/sinks/file.js +49 -0
- package/dist/sinks/file.js.map +1 -0
- package/dist/sinks/http.js +38 -0
- package/dist/sinks/http.js.map +1 -0
- package/dist/sinks/index.js +5 -0
- package/dist/sinks/index.js.map +1 -0
- package/dist/sinks/multi.js +40 -0
- package/dist/sinks/multi.js.map +1 -0
- package/dist/sinks/paths.js +32 -0
- package/dist/sinks/paths.js.map +1 -0
- package/dist/sinks/record.js +58 -0
- package/dist/sinks/record.js.map +1 -0
- package/dist/sinks/types.js +1 -0
- package/dist/sinks/types.js.map +1 -0
- package/dist/web/breakage.js +210 -0
- package/dist/web/breakage.js.map +1 -0
- package/dist/web/controls.js +102 -0
- package/dist/web/controls.js.map +1 -0
- package/dist/web/driver.js +803 -0
- package/dist/web/driver.js.map +1 -0
- package/dist/web/elements.js +151 -0
- package/dist/web/elements.js.map +1 -0
- package/dist/web/fingerprint.js +13 -0
- package/dist/web/fingerprint.js.map +1 -0
- package/dist/web/forms.js +74 -0
- package/dist/web/forms.js.map +1 -0
- package/dist/web/links.js +194 -0
- package/dist/web/links.js.map +1 -0
- package/dist/web/types.js +1 -0
- package/dist/web/types.js.map +1 -0
- package/package.json +80 -0
- package/runtime/macos-accessibility-runner.js +275 -0
- package/runtime/windows-uia-runner.ps1 +539 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { requireEnv } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Discord connector — post a run summary to a channel via a Discord webhook. URL is a secret from
|
|
4
|
+
* env (COMBER_DISCORD_WEBHOOK_URL). The message is a single rich embed coloured by outcome. The
|
|
5
|
+
* record is already redacted, so nothing sensitive reaches Discord.
|
|
6
|
+
*/
|
|
7
|
+
export const manifest = {
|
|
8
|
+
name: "discord",
|
|
9
|
+
title: "Discord",
|
|
10
|
+
version: "1.0.0",
|
|
11
|
+
kind: "notifier",
|
|
12
|
+
summary: "Post a run summary to a Discord channel via a webhook.",
|
|
13
|
+
env: ["COMBER_DISCORD_WEBHOOK_URL"],
|
|
14
|
+
config: [{ key: "on", description: "Severity gate: always | warn | fail", example: "fail" }],
|
|
15
|
+
source: "builtin",
|
|
16
|
+
author: "RADLAB LLC",
|
|
17
|
+
};
|
|
18
|
+
const COLOR = { fail: 0xd7263d, warn: 0xf0a202, ok: 0x2fbf71 };
|
|
19
|
+
export const create = (ctx) => {
|
|
20
|
+
const url = requireEnv(ctx, "COMBER_DISCORD_WEBHOOK_URL");
|
|
21
|
+
const fetchImpl = ctx.fetchImpl ?? fetch;
|
|
22
|
+
return {
|
|
23
|
+
manifest,
|
|
24
|
+
async deliver(record, _meta) {
|
|
25
|
+
const color = record.failCount > 0 ? COLOR.fail : record.warnCount > 0 ? COLOR.warn : COLOR.ok;
|
|
26
|
+
const fields = [
|
|
27
|
+
{ name: "Findings", value: `${record.failCount} fail / ${record.warnCount} warn / ${record.infoCount} info`, inline: true },
|
|
28
|
+
{ name: "Scope", value: `${record.states} states · ${record.actions} actions`, inline: true },
|
|
29
|
+
];
|
|
30
|
+
if (record.coverage) {
|
|
31
|
+
fields.push({ name: "Coverage", value: `${record.coverage.elementCoveragePct}%`, inline: true });
|
|
32
|
+
}
|
|
33
|
+
const topFails = record.findings
|
|
34
|
+
.filter((f) => f.severity === "fail")
|
|
35
|
+
.slice(0, 5)
|
|
36
|
+
.map((f) => `• **${f.kind}** — ${f.message.slice(0, 180)}`)
|
|
37
|
+
.join("\n");
|
|
38
|
+
const embed = {
|
|
39
|
+
title: `Comber — ${record.target}`,
|
|
40
|
+
description: topFails || "No failures.",
|
|
41
|
+
color,
|
|
42
|
+
fields,
|
|
43
|
+
footer: { text: record.cappedBy ? `capped by ${record.cappedBy}` : "comber" },
|
|
44
|
+
};
|
|
45
|
+
const res = await fetchImpl(url, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: { "Content-Type": "application/json" },
|
|
48
|
+
body: JSON.stringify({ embeds: [embed] }),
|
|
49
|
+
signal: AbortSignal.timeout(15_000),
|
|
50
|
+
});
|
|
51
|
+
if (!res.ok)
|
|
52
|
+
throw new Error(`discord webhook ${res.status}`);
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { requireEnv } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* GitHub connector — set a COMMIT STATUS on the checked SHA so a Comber run shows up as a green/red
|
|
4
|
+
* check on the PR (and can be a required check). Uses the Statuses API, which works with the plain
|
|
5
|
+
* GITHUB_TOKEN an Action already has (the Checks API needs a GitHub App). In an Action, repo + sha
|
|
6
|
+
* come from the standard GITHUB_REPOSITORY / GITHUB_SHA env; both are overridable via config.
|
|
7
|
+
*/
|
|
8
|
+
export const manifest = {
|
|
9
|
+
name: "github",
|
|
10
|
+
title: "GitHub commit status",
|
|
11
|
+
version: "1.0.0",
|
|
12
|
+
kind: "report",
|
|
13
|
+
summary: "Set a pass/fail commit status on the checked SHA (shows as a PR check).",
|
|
14
|
+
env: ["GITHUB_TOKEN", "GITHUB_REPOSITORY", "GITHUB_SHA", "GITHUB_API_URL"],
|
|
15
|
+
config: [
|
|
16
|
+
{ key: "context", description: "Status context label", example: "comber" },
|
|
17
|
+
{ key: "repository", description: "owner/repo override (defaults to GITHUB_REPOSITORY)", example: "acme/site" },
|
|
18
|
+
{ key: "sha", description: "Commit SHA override (defaults to GITHUB_SHA)" },
|
|
19
|
+
],
|
|
20
|
+
source: "builtin",
|
|
21
|
+
author: "RADLAB LLC",
|
|
22
|
+
};
|
|
23
|
+
export const create = (ctx) => {
|
|
24
|
+
const token = requireEnv(ctx, "GITHUB_TOKEN");
|
|
25
|
+
const repo = (typeof ctx.config.repository === "string" ? ctx.config.repository : ctx.env.GITHUB_REPOSITORY) ?? "";
|
|
26
|
+
const sha = (typeof ctx.config.sha === "string" ? ctx.config.sha : ctx.env.GITHUB_SHA) ?? "";
|
|
27
|
+
if (!repo || !sha)
|
|
28
|
+
throw new Error(`connector "github" needs GITHUB_REPOSITORY + GITHUB_SHA (or config repository/sha)`);
|
|
29
|
+
const apiBase = ctx.env.GITHUB_API_URL?.trim() || "https://api.github.com";
|
|
30
|
+
const context = typeof ctx.config.context === "string" ? ctx.config.context : "comber";
|
|
31
|
+
const fetchImpl = ctx.fetchImpl ?? fetch;
|
|
32
|
+
return {
|
|
33
|
+
manifest,
|
|
34
|
+
async deliver(record, _meta) {
|
|
35
|
+
const state = record.failCount > 0 ? "failure" : "success";
|
|
36
|
+
const description = `${record.failCount} fail / ${record.warnCount} warn / ${record.infoCount} info` +
|
|
37
|
+
(record.coverage ? ` · ${record.coverage.elementCoveragePct}% coverage` : "");
|
|
38
|
+
const res = await fetchImpl(`${apiBase}/repos/${repo}/statuses/${sha}`, {
|
|
39
|
+
method: "POST",
|
|
40
|
+
headers: {
|
|
41
|
+
Authorization: `Bearer ${token}`,
|
|
42
|
+
Accept: "application/vnd.github+json",
|
|
43
|
+
"Content-Type": "application/json",
|
|
44
|
+
"User-Agent": "comber",
|
|
45
|
+
},
|
|
46
|
+
body: JSON.stringify({ state, context, description: description.slice(0, 140) }),
|
|
47
|
+
signal: AbortSignal.timeout(15_000),
|
|
48
|
+
});
|
|
49
|
+
if (!res.ok)
|
|
50
|
+
throw new Error(`github status ${res.status}`);
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* JUnit connector — write the run as a JUnit XML report so any CI test-summary UI (GitHub Actions
|
|
5
|
+
* test report, GitLab, Jenkins, CircleCI, Buildkite) renders Comber findings as test results.
|
|
6
|
+
* Each finding becomes a <testcase>; a `fail` finding is a <failure>, a `warn` a <flakyFailure>-ish
|
|
7
|
+
* skip note, `info` a passing case. Fully generic + secret-free — the highest-leverage CI connector.
|
|
8
|
+
*/
|
|
9
|
+
export const manifest = {
|
|
10
|
+
name: "junit",
|
|
11
|
+
title: "JUnit report",
|
|
12
|
+
version: "1.0.0",
|
|
13
|
+
kind: "report",
|
|
14
|
+
summary: "Write findings as a JUnit XML report any CI test-summary UI can render.",
|
|
15
|
+
config: [
|
|
16
|
+
{ key: "outFile", description: "Path to write the JUnit XML", required: true, example: "comber-junit.xml" },
|
|
17
|
+
],
|
|
18
|
+
source: "builtin",
|
|
19
|
+
author: "RADLAB LLC",
|
|
20
|
+
};
|
|
21
|
+
function xmlEscape(s) {
|
|
22
|
+
return s
|
|
23
|
+
.replace(/&/g, "&")
|
|
24
|
+
.replace(/</g, "<")
|
|
25
|
+
.replace(/>/g, ">")
|
|
26
|
+
.replace(/"/g, """)
|
|
27
|
+
.replace(/'/g, "'");
|
|
28
|
+
}
|
|
29
|
+
function testcase(f) {
|
|
30
|
+
const name = xmlEscape(`${f.kind}: ${f.signature}`.slice(0, 200));
|
|
31
|
+
const cls = xmlEscape(f.url || "comber");
|
|
32
|
+
if (f.severity === "fail") {
|
|
33
|
+
return ` <testcase name="${name}" classname="${cls}"><failure message="${xmlEscape(f.message.slice(0, 300))}">${xmlEscape(f.message)}</failure></testcase>`;
|
|
34
|
+
}
|
|
35
|
+
if (f.severity === "warn") {
|
|
36
|
+
return ` <testcase name="${name}" classname="${cls}"><skipped message="${xmlEscape(f.message.slice(0, 300))}"/></testcase>`;
|
|
37
|
+
}
|
|
38
|
+
return ` <testcase name="${name}" classname="${cls}"/>`;
|
|
39
|
+
}
|
|
40
|
+
function toJUnitXml(record) {
|
|
41
|
+
const tests = record.findings.length;
|
|
42
|
+
const failures = record.failCount;
|
|
43
|
+
const skipped = record.warnCount;
|
|
44
|
+
const time = (record.durationMs / 1000).toFixed(3);
|
|
45
|
+
const cases = record.findings.map(testcase).join("\n");
|
|
46
|
+
return (`<?xml version="1.0" encoding="UTF-8"?>\n` +
|
|
47
|
+
`<testsuites name="comber" tests="${tests}" failures="${failures}" skipped="${skipped}" time="${time}">\n` +
|
|
48
|
+
` <testsuite name="${xmlEscape(record.target)}" tests="${tests}" failures="${failures}" skipped="${skipped}" time="${time}">\n` +
|
|
49
|
+
`${cases}\n` +
|
|
50
|
+
` </testsuite>\n` +
|
|
51
|
+
`</testsuites>\n`);
|
|
52
|
+
}
|
|
53
|
+
export const create = (ctx) => {
|
|
54
|
+
const outFile = ctx.config.outFile;
|
|
55
|
+
if (typeof outFile !== "string" || outFile.length === 0) {
|
|
56
|
+
throw new Error(`connector "junit" requires an "outFile" path in its config`);
|
|
57
|
+
}
|
|
58
|
+
if (outFile.replace(/\\/g, "/").split("/").includes("..")) {
|
|
59
|
+
throw new Error(`connector "junit" outFile must not contain '..' path traversal: ${outFile}`);
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
manifest,
|
|
63
|
+
async deliver(record, _meta) {
|
|
64
|
+
await mkdir(dirname(outFile), { recursive: true }).catch(() => { });
|
|
65
|
+
await writeFile(outFile, toJUnitXml(record));
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
// Exported for tests.
|
|
70
|
+
export { toJUnitXml };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { requireConfigString, requireEnv } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Linear connector — file a Linear issue for a run that has failures (default gate: `fail`). API
|
|
4
|
+
* key is a secret from env (COMBER_LINEAR_API_KEY); `teamId` (non-secret) comes from config. Uses
|
|
5
|
+
* the Linear GraphQL API. Deliberately conservative: only creates an issue when there is a `fail`
|
|
6
|
+
* to avoid issue spam — pair with `on: "fail"` in config for the intended behaviour.
|
|
7
|
+
*/
|
|
8
|
+
export const manifest = {
|
|
9
|
+
name: "linear",
|
|
10
|
+
title: "Linear",
|
|
11
|
+
version: "1.0.0",
|
|
12
|
+
kind: "issue-tracker",
|
|
13
|
+
summary: "File a Linear issue for a run with failures.",
|
|
14
|
+
env: ["COMBER_LINEAR_API_KEY"],
|
|
15
|
+
config: [
|
|
16
|
+
{ key: "teamId", description: "Linear team id to file the issue under", required: true, example: "TEAM_abc123" },
|
|
17
|
+
{ key: "on", description: "Severity gate (recommend fail)", example: "fail" },
|
|
18
|
+
],
|
|
19
|
+
source: "builtin",
|
|
20
|
+
author: "RADLAB LLC",
|
|
21
|
+
};
|
|
22
|
+
const CREATE_ISSUE = `mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { identifier url } } }`;
|
|
23
|
+
function issueBody(record) {
|
|
24
|
+
const top = record.findings
|
|
25
|
+
.filter((f) => f.severity === "fail")
|
|
26
|
+
.slice(0, 20)
|
|
27
|
+
.map((f) => `- **${f.kind}** — ${f.message.slice(0, 200)}${f.count > 1 ? ` (×${f.count})` : ""}\n \`${f.url}\``)
|
|
28
|
+
.join("\n");
|
|
29
|
+
return (`Comber found **${record.failCount} failing** finding(s) on \`${record.target}\`.\n\n` +
|
|
30
|
+
`States: ${record.states} · Actions: ${record.actions}` +
|
|
31
|
+
(record.coverage ? ` · Coverage: ${record.coverage.elementCoveragePct}%` : "") +
|
|
32
|
+
`\n\n### Failures\n${top || "_none_"}\n`);
|
|
33
|
+
}
|
|
34
|
+
export const create = (ctx) => {
|
|
35
|
+
const apiKey = requireEnv(ctx, "COMBER_LINEAR_API_KEY");
|
|
36
|
+
const teamId = requireConfigString(ctx, "teamId");
|
|
37
|
+
const fetchImpl = ctx.fetchImpl ?? fetch;
|
|
38
|
+
return {
|
|
39
|
+
manifest,
|
|
40
|
+
async deliver(record, _meta) {
|
|
41
|
+
// Only file for a run with real failures; a clean/warn-only run is a no-op (no issue spam).
|
|
42
|
+
if (record.failCount === 0)
|
|
43
|
+
return;
|
|
44
|
+
const title = `Comber: ${record.failCount} failure(s) on ${record.target}`.slice(0, 200);
|
|
45
|
+
const res = await fetchImpl("https://api.linear.app/graphql", {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: { Authorization: apiKey, "Content-Type": "application/json" },
|
|
48
|
+
body: JSON.stringify({ query: CREATE_ISSUE, variables: { input: { teamId, title, description: issueBody(record) } } }),
|
|
49
|
+
signal: AbortSignal.timeout(15_000),
|
|
50
|
+
});
|
|
51
|
+
if (!res.ok)
|
|
52
|
+
throw new Error(`linear api ${res.status}`);
|
|
53
|
+
const json = (await res.json());
|
|
54
|
+
if (!json.data?.issueCreate?.success)
|
|
55
|
+
throw new Error(`linear issueCreate failed`);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { requireEnv } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Slack connector — post a run summary to a channel via an Incoming Webhook. The webhook URL is
|
|
4
|
+
* a secret from env (COMBER_SLACK_WEBHOOK_URL); no other config is required. The message is a
|
|
5
|
+
* compact Block Kit summary: a headline (pass/fail), the target, the counts, coverage, and the
|
|
6
|
+
* top few findings. The record is already redacted, so nothing sensitive reaches Slack.
|
|
7
|
+
*/
|
|
8
|
+
export const manifest = {
|
|
9
|
+
name: "slack",
|
|
10
|
+
title: "Slack",
|
|
11
|
+
version: "1.0.0",
|
|
12
|
+
kind: "notifier",
|
|
13
|
+
summary: "Post a run summary to a Slack channel via an Incoming Webhook.",
|
|
14
|
+
env: ["COMBER_SLACK_WEBHOOK_URL"],
|
|
15
|
+
config: [
|
|
16
|
+
{ key: "on", description: "Severity gate: always | warn | fail", example: "fail" },
|
|
17
|
+
{ key: "mentionOnFail", description: "Text to prepend when the run has failures (e.g. <!here>)", example: "<!here>" },
|
|
18
|
+
],
|
|
19
|
+
source: "builtin",
|
|
20
|
+
author: "RADLAB LLC",
|
|
21
|
+
};
|
|
22
|
+
function summaryText(record) {
|
|
23
|
+
const icon = record.failCount > 0 ? "❌" : record.warnCount > 0 ? "⚠️" : "✅";
|
|
24
|
+
const cov = record.coverage ? ` · ${record.coverage.elementCoveragePct}% coverage` : "";
|
|
25
|
+
return (`${icon} *Comber* — ${record.failCount} fail / ${record.warnCount} warn / ${record.infoCount} info` +
|
|
26
|
+
`\n\`${record.target}\` · ${record.states} states, ${record.actions} actions${cov}` +
|
|
27
|
+
(record.cappedBy ? ` · capped by ${record.cappedBy}` : ""));
|
|
28
|
+
}
|
|
29
|
+
function topFindings(record) {
|
|
30
|
+
const top = record.findings
|
|
31
|
+
.filter((f) => f.severity === "fail")
|
|
32
|
+
.slice(0, 5)
|
|
33
|
+
.map((f) => `• *${f.kind}* — ${f.message.slice(0, 140)}${f.count > 1 ? ` (×${f.count})` : ""}`);
|
|
34
|
+
return top.length ? top.join("\n") : "";
|
|
35
|
+
}
|
|
36
|
+
export const create = (ctx) => {
|
|
37
|
+
const url = requireEnv(ctx, "COMBER_SLACK_WEBHOOK_URL");
|
|
38
|
+
const fetchImpl = ctx.fetchImpl ?? fetch;
|
|
39
|
+
const mention = typeof ctx.config.mentionOnFail === "string" ? ctx.config.mentionOnFail : "";
|
|
40
|
+
return {
|
|
41
|
+
manifest,
|
|
42
|
+
async deliver(record, _meta) {
|
|
43
|
+
const lead = record.failCount > 0 && mention ? `${mention} ` : "";
|
|
44
|
+
const findings = topFindings(record);
|
|
45
|
+
const blocks = [
|
|
46
|
+
{ type: "section", text: { type: "mrkdwn", text: lead + summaryText(record) } },
|
|
47
|
+
];
|
|
48
|
+
if (findings)
|
|
49
|
+
blocks.push({ type: "section", text: { type: "mrkdwn", text: findings } });
|
|
50
|
+
const res = await fetchImpl(url, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: { "Content-Type": "application/json" },
|
|
53
|
+
body: JSON.stringify({ text: summaryText(record), blocks }),
|
|
54
|
+
signal: AbortSignal.timeout(15_000),
|
|
55
|
+
});
|
|
56
|
+
if (!res.ok)
|
|
57
|
+
throw new Error(`slack webhook ${res.status}`);
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { requireEnv } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Generic webhook connector — POST the redacted run record as JSON to any URL. The universal
|
|
4
|
+
* fallback: a backend, an internal collector, a Zapier/Make hook, or a Sentry-style ingest all
|
|
5
|
+
* consume the same shape. The URL comes from env (COMBER_WEBHOOK_URL); an optional bearer token
|
|
6
|
+
* (COMBER_WEBHOOK_TOKEN) rides as a header only — never in the body, never logged.
|
|
7
|
+
*/
|
|
8
|
+
export const manifest = {
|
|
9
|
+
name: "webhook",
|
|
10
|
+
title: "Webhook",
|
|
11
|
+
version: "1.0.0",
|
|
12
|
+
kind: "webhook",
|
|
13
|
+
summary: "POST the redacted run record (JSON) to any URL, with an optional bearer token.",
|
|
14
|
+
env: ["COMBER_WEBHOOK_URL", "COMBER_WEBHOOK_TOKEN"],
|
|
15
|
+
source: "builtin",
|
|
16
|
+
author: "RADLAB LLC",
|
|
17
|
+
};
|
|
18
|
+
export const create = (ctx) => {
|
|
19
|
+
const url = requireEnv(ctx, "COMBER_WEBHOOK_URL");
|
|
20
|
+
const token = ctx.env.COMBER_WEBHOOK_TOKEN?.trim();
|
|
21
|
+
const fetchImpl = ctx.fetchImpl ?? fetch;
|
|
22
|
+
const timeoutMs = typeof ctx.config.timeoutMs === "number" ? ctx.config.timeoutMs : 15_000;
|
|
23
|
+
return {
|
|
24
|
+
manifest,
|
|
25
|
+
async deliver(record, _meta) {
|
|
26
|
+
const headers = { "Content-Type": "application/json" };
|
|
27
|
+
if (token)
|
|
28
|
+
headers.Authorization = `Bearer ${token}`;
|
|
29
|
+
const res = await fetchImpl(url, {
|
|
30
|
+
method: "POST",
|
|
31
|
+
headers,
|
|
32
|
+
body: JSON.stringify(record),
|
|
33
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
34
|
+
});
|
|
35
|
+
if (!res.ok)
|
|
36
|
+
throw new Error(`webhook POST ${res.status}`); // never echo url/token
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { buildRunRecord } from "../sinks/record.js";
|
|
2
|
+
import { builtinConnector } from "./registry.js";
|
|
3
|
+
import { passesGate, } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Resolve one connector config to a live instance. A `use:` that names a built-in loads from the
|
|
6
|
+
* registry; anything else is treated as an EXTERNAL MODULE SPECIFIER (an installed marketplace
|
|
7
|
+
* package like "@acme/comber-teams" or a local "./my-connector.js") and dynamically imported. An
|
|
8
|
+
* external module exports the same shape as a built-in: a `create` factory (+ optional `manifest`),
|
|
9
|
+
* or a default export that is the factory. This is the whole marketplace loading mechanism — a
|
|
10
|
+
* third-party connector is just an npm package that satisfies the contract.
|
|
11
|
+
*/
|
|
12
|
+
async function resolveFactory(use) {
|
|
13
|
+
const builtin = builtinConnector(use);
|
|
14
|
+
if (builtin)
|
|
15
|
+
return builtin.create;
|
|
16
|
+
let mod;
|
|
17
|
+
try {
|
|
18
|
+
mod = (await import(use));
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
throw new Error(`connector "${use}" could not be loaded — install it or check the name: ${String(err).slice(0, 160)}`);
|
|
22
|
+
}
|
|
23
|
+
const factory = (mod.create ?? mod.default);
|
|
24
|
+
if (typeof factory !== "function") {
|
|
25
|
+
throw new Error(`connector "${use}" does not export a create() factory (or default)`);
|
|
26
|
+
}
|
|
27
|
+
return factory;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A fan-out over configured connectors. Building it resolves + instantiates every connector (so a
|
|
31
|
+
* misconfigured connector fails fast, at load, with a clear error — not silently at delivery). At
|
|
32
|
+
* delivery it builds the redacted RunRecord ONCE and hands it to each connector, gated by the
|
|
33
|
+
* connector's `on` severity bar, with each delivery isolated so one failure never breaks the run
|
|
34
|
+
* or another connector.
|
|
35
|
+
*/
|
|
36
|
+
export class ConnectorFanout {
|
|
37
|
+
entries;
|
|
38
|
+
constructor(entries) {
|
|
39
|
+
this.entries = entries;
|
|
40
|
+
}
|
|
41
|
+
static async load(configs, env = process.env, fetchImpl) {
|
|
42
|
+
const entries = [];
|
|
43
|
+
for (const config of configs ?? []) {
|
|
44
|
+
if (!config || typeof config.use !== "string" || config.use.length === 0) {
|
|
45
|
+
throw new Error(`each connector needs a "use" (a built-in name or a module specifier)`);
|
|
46
|
+
}
|
|
47
|
+
const factory = await resolveFactory(config.use);
|
|
48
|
+
const ctx = { config, env, fetchImpl };
|
|
49
|
+
entries.push({ connector: await factory(ctx), on: config.on });
|
|
50
|
+
}
|
|
51
|
+
return new ConnectorFanout(entries);
|
|
52
|
+
}
|
|
53
|
+
/** Names of the loaded connectors, for the CLI banner. */
|
|
54
|
+
get active() {
|
|
55
|
+
return this.entries.map((e) => e.connector.manifest.name);
|
|
56
|
+
}
|
|
57
|
+
async deliver(result, meta) {
|
|
58
|
+
if (this.entries.length === 0)
|
|
59
|
+
return;
|
|
60
|
+
const record = buildRunRecord(result, meta); // redacted once, shared by all connectors
|
|
61
|
+
await Promise.all(this.entries.map(async ({ connector, on }) => {
|
|
62
|
+
if (!passesGate(record, on))
|
|
63
|
+
return;
|
|
64
|
+
try {
|
|
65
|
+
await connector.deliver(record, meta);
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
console.error(`[connector:${connector.manifest.name}] ${String(e).slice(0, 200)}`);
|
|
69
|
+
}
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as webhook from "./builtin/webhook.js";
|
|
2
|
+
import * as slack from "./builtin/slack.js";
|
|
3
|
+
import * as discord from "./builtin/discord.js";
|
|
4
|
+
import * as githubChecks from "./builtin/github-checks.js";
|
|
5
|
+
import * as junit from "./builtin/junit.js";
|
|
6
|
+
import * as linear from "./builtin/linear.js";
|
|
7
|
+
const BUILTINS = {
|
|
8
|
+
[webhook.manifest.name]: webhook,
|
|
9
|
+
[slack.manifest.name]: slack,
|
|
10
|
+
[discord.manifest.name]: discord,
|
|
11
|
+
[githubChecks.manifest.name]: githubChecks,
|
|
12
|
+
[junit.manifest.name]: junit,
|
|
13
|
+
[linear.manifest.name]: linear,
|
|
14
|
+
};
|
|
15
|
+
/** Look up a built-in connector by name. */
|
|
16
|
+
export function builtinConnector(name) {
|
|
17
|
+
return BUILTINS[name];
|
|
18
|
+
}
|
|
19
|
+
/** True if `name` names a built-in connector (vs. an external module specifier). */
|
|
20
|
+
export function isBuiltinConnector(name) {
|
|
21
|
+
return name in BUILTINS;
|
|
22
|
+
}
|
|
23
|
+
/** Every built-in connector's manifest — powers `comber connectors` + the marketplace listing. */
|
|
24
|
+
export function builtinManifests() {
|
|
25
|
+
return Object.values(BUILTINS)
|
|
26
|
+
.map((c) => c.manifest)
|
|
27
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
28
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** True when a run at these counts clears the connector's severity gate. */
|
|
2
|
+
export function passesGate(record, on = "always") {
|
|
3
|
+
if (on === "fail")
|
|
4
|
+
return record.failCount > 0;
|
|
5
|
+
if (on === "warn")
|
|
6
|
+
return record.failCount > 0 || record.warnCount > 0;
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
/** Read a required string setting from a connector's config, with a clear error if missing. */
|
|
10
|
+
export function requireConfigString(ctx, key) {
|
|
11
|
+
const v = ctx.config[key];
|
|
12
|
+
if (typeof v !== "string" || v.length === 0) {
|
|
13
|
+
throw new Error(`connector "${ctx.config.use}" requires a "${key}" string in its config`);
|
|
14
|
+
}
|
|
15
|
+
return v;
|
|
16
|
+
}
|
|
17
|
+
/** Read a required secret from env, with a clear error naming the missing var. */
|
|
18
|
+
export function requireEnv(ctx, name) {
|
|
19
|
+
const v = ctx.env[name]?.trim();
|
|
20
|
+
if (!v)
|
|
21
|
+
throw new Error(`connector "${ctx.config.use}" requires the ${name} environment variable`);
|
|
22
|
+
return v;
|
|
23
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { deniedName } from "./safety.js";
|
|
2
|
+
/** A state mutation by EFFECT — the driver said so, or the wire method is write-family.
|
|
3
|
+
* Unknown effect (`e === undefined`) is deliberately NOT mutation: the floor must not newly
|
|
4
|
+
* deny nodes whose effect a driver has not yet populated (that keeps this change additive;
|
|
5
|
+
* the driver-population increment then makes `strict` mode bite). */
|
|
6
|
+
function isMutating(e) {
|
|
7
|
+
if (!e)
|
|
8
|
+
return false;
|
|
9
|
+
if (e.mutates === true)
|
|
10
|
+
return true;
|
|
11
|
+
if (e.method && /^(POST|PUT|PATCH|DELETE)$/i.test(e.method))
|
|
12
|
+
return true;
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
export function evaluateAction(node, cfg) {
|
|
16
|
+
const e = node.effect;
|
|
17
|
+
// 1 — Hard deny by EFFECT, independent of the (author/attacker-controlled) label. This is
|
|
18
|
+
// the label↔effect-decoupling fix: a "Delete account" control mislabeled "Continue" is
|
|
19
|
+
// denied on its effect, not waved through on its name.
|
|
20
|
+
if (e?.irreversible)
|
|
21
|
+
return { verdict: "deny", reason: `effect-irreversible-${e.irreversible}` };
|
|
22
|
+
if (e?.offOrigin)
|
|
23
|
+
return { verdict: "deny", reason: "effect-off-origin" };
|
|
24
|
+
if (e?.crossOrigin && isMutating(e))
|
|
25
|
+
return { verdict: "deny", reason: "effect-cross-origin-write" };
|
|
26
|
+
// 2 — Name/id denylist, DEMOTED from primary gate to one signal. Delegated to the shared
|
|
27
|
+
// `deniedName` chokepoint (label match + icon-only-id fallback) so the two paths cannot
|
|
28
|
+
// drift — an icon-only destructive control (empty label, id like `button#delete-item`)
|
|
29
|
+
// must still be caught, exactly as before this floor existed.
|
|
30
|
+
const denied = deniedName(node, cfg);
|
|
31
|
+
if (denied)
|
|
32
|
+
return { verdict: "deny", reason: denied };
|
|
33
|
+
const mutating = isMutating(e);
|
|
34
|
+
// 3 — Observe-only invariant: in dry-run NO mutation may fire, in either mode.
|
|
35
|
+
if (mutating && cfg.dryRun)
|
|
36
|
+
return { verdict: "deny", reason: "mutation-observe-only" };
|
|
37
|
+
// 4 — A known mutation that is not clearly destructive → ESCALATE to the out-of-band LLM
|
|
38
|
+
// safety-judge (both modes). The pipeline resolves the escalation: the judge's allow/deny,
|
|
39
|
+
// or — when no judge is configured — advisory proceeds (permissive) and strict fails
|
|
40
|
+
// closed. A confirm()-guarded mutation is a stronger signal, carried in the reason.
|
|
41
|
+
if (mutating) {
|
|
42
|
+
return { verdict: "escalate", reason: e?.requiresConfirm ? "mutation-requires-confirm" : "mutation-escalate" };
|
|
43
|
+
}
|
|
44
|
+
// 5 — Provably read-only, or unknown effect on a non-denylisted name → allow (unchanged
|
|
45
|
+
// from today's behavior, so this floor is additive: it only ADDS denies/escalations for
|
|
46
|
+
// effect-bearing nodes, never newly blocks an unknown-effect node).
|
|
47
|
+
return { verdict: "allow", reason: "safe" };
|
|
48
|
+
}
|