fix(matrix): accept documented automatic approval mode (#115676)

Restore the explicitly shipped Matrix approval mode without changing omitted, boolean, invalid, or non-strict configuration behavior. Regenerate the canonical channel metadata and prove native Matrix approvals against a real homeserver.

Co-authored-by: mingdideng <deng.mingdi@xydigit.com>
This commit is contained in:
Peter Steinberger
2026-07-29 03:37:19 -04:00
committed by GitHub
parent 18535626ed
commit d37fd8f2d4
6 changed files with 99 additions and 15 deletions
@@ -187,3 +187,71 @@ describe("MatrixConfigSchema SecretInput", () => {
expect(result.success).toBe(true);
});
});
describe("MatrixConfigSchema exec approvals", () => {
it.each([true, false, "auto"] as const)("accepts the shipped enabled mode %s", (enabled) => {
const result = MatrixConfigSchema.safeParse({
homeserver: "https://matrix.example.org",
accessToken: "token",
execApprovals: {
enabled,
approvers: ["@owner:example.org"],
},
});
expect(result.success).toBe(true);
if (result.success) {
expect(result.data).toMatchObject({ execApprovals: { enabled } });
}
});
it("preserves omitted approval enablement without introducing a default", () => {
const result = MatrixConfigSchema.safeParse({
homeserver: "https://matrix.example.org",
accessToken: "token",
execApprovals: { approvers: ["@owner:example.org"] },
});
expect(result.success).toBe(true);
if (result.success) {
expect(result.data).toMatchObject({
execApprovals: { approvers: ["@owner:example.org"] },
});
expect(result.data).not.toMatchObject({
execApprovals: { enabled: expect.anything() },
});
}
});
it("preserves the existing non-strict approval object", () => {
const result = MatrixConfigSchema.safeParse({
homeserver: "https://matrix.example.org",
accessToken: "token",
execApprovals: {
enabled: "auto",
approvers: ["@owner:example.org"],
unknownApprovalField: true,
},
});
expect(result.success).toBe(true);
if (result.success) {
expect(result.data).toMatchObject({
execApprovals: { enabled: "auto", approvers: ["@owner:example.org"] },
});
expect(result.data).not.toMatchObject({
execApprovals: { unknownApprovalField: true },
});
}
});
it.each(["on", "AUTO", 1, null])("rejects the invalid enabled mode %s", (enabled) => {
const result = MatrixConfigSchema.safeParse({
homeserver: "https://matrix.example.org",
accessToken: "token",
execApprovals: { enabled, approvers: ["@owner:example.org"] },
});
expect(result.success).toBe(false);
});
});
+1 -1
View File
@@ -38,7 +38,7 @@ const matrixThreadBindingsSchema = z
const matrixExecApprovalsSchema = z
.object({
enabled: z.boolean().optional(),
enabled: z.union([z.boolean(), z.literal("auto")]).optional(),
approvers: AllowFromListSchema,
agentFilter: z.array(z.string()).optional(),
sessionFilter: z.array(z.string()).optional(),
@@ -154,6 +154,22 @@ describe("matrix exec approvals", () => {
).toBe(true);
});
it("enables explicit auto mode only when Matrix approvers can be resolved", () => {
expect(isMatrixExecApprovalClientEnabled({ cfg: buildConfig({ enabled: "auto" }) })).toBe(
false,
);
expect(
isMatrixExecApprovalClientEnabled({
cfg: buildConfig({ enabled: "auto" }, { dm: { allowFrom: ["@owner:example.org"] } }),
}),
).toBe(true);
expect(
isMatrixExecApprovalClientEnabled({
cfg: buildConfig({ enabled: "auto", approvers: ["@owner:example.org"] }),
}),
).toBe(true);
});
it("prefers explicit approvers when configured", () => {
const cfg = buildConfig(
{ enabled: true, approvers: ["user:@override:example.org"] },
+2 -2
View File
@@ -77,8 +77,8 @@ type MatrixThreadBindingsConfig = {
type MatrixExecApprovalTarget = "dm" | "channel" | "both";
type MatrixExecApprovalConfig = {
/** If true, deliver exec approvals through Matrix-native prompts. */
enabled?: boolean;
/** Explicitly enable Matrix-native approval prompts when approvers are available. */
enabled?: boolean | "auto";
/** Optional approver Matrix user IDs. Falls back to dm.allowFrom. */
approvers?: Array<string | number>;
/** Optional agent allowlist for approval delivery. */
@@ -17,7 +17,7 @@ scenario:
dm:
enabled: true
execApprovals:
enabled: true
enabled: auto
target: channel
flow:
File diff suppressed because one or more lines are too long