Matrix: align default account secret handling

This commit is contained in:
Gustavo Madeira Santana
2026-03-28 00:34:35 -04:00
parent 411494faa8
commit 59535e3414
4 changed files with 157 additions and 7 deletions

View File

@@ -92,6 +92,59 @@ describe("resolveMatrixAccount", () => {
expect(account.configured).toBe(true);
});
it("treats accounts.default SecretRef access-token config as configured", () => {
const cfg: CoreConfig = {
channels: {
matrix: {
accounts: {
default: {
homeserver: "https://matrix.example.org",
accessToken: { source: "file", provider: "matrix-file", id: "value" },
},
},
},
},
secrets: {
providers: {
"matrix-file": {
source: "file",
path: "/tmp/matrix-token",
},
},
},
};
const account = resolveMatrixAccount({ cfg });
expect(account.configured).toBe(true);
});
it("treats accounts.default SecretRef password config as configured", () => {
const cfg: CoreConfig = {
channels: {
matrix: {
accounts: {
default: {
homeserver: "https://matrix.example.org",
userId: "@bot:example.org",
password: { source: "file", provider: "matrix-file", id: "value" },
},
},
},
},
secrets: {
providers: {
"matrix-file": {
source: "file",
path: "/tmp/matrix-password",
},
},
},
};
const account = resolveMatrixAccount({ cfg });
expect(account.configured).toBe(true);
});
it("requires userId + password when no access token is set", () => {
const cfg: CoreConfig = {
channels: {

View File

@@ -98,21 +98,21 @@ export function resolveMatrixAccount(params: {
const env = params.env ?? process.env;
const accountId = normalizeAccountId(params.accountId);
const matrixBase = resolveMatrixBaseConfig(params.cfg);
const explicitAccountConfig =
accountId === DEFAULT_ACCOUNT_ID
? matrixBase
: (findMatrixAccountConfig(params.cfg, accountId) ?? {});
const base = resolveMatrixAccountConfig({ cfg: params.cfg, accountId });
const explicitAuthConfig =
accountId === DEFAULT_ACCOUNT_ID
? base
: (findMatrixAccountConfig(params.cfg, accountId) ?? {});
const enabled = base.enabled !== false && matrixBase.enabled !== false;
const resolved = resolveMatrixConfigForAccount(params.cfg, accountId, env);
const hasHomeserver = Boolean(resolved.homeserver);
const hasUserId = Boolean(resolved.userId);
const hasAccessToken =
Boolean(resolved.accessToken) || hasConfiguredSecretInput(explicitAccountConfig.accessToken);
Boolean(resolved.accessToken) || hasConfiguredSecretInput(explicitAuthConfig.accessToken);
const hasPassword = Boolean(resolved.password);
const hasPasswordAuth =
hasUserId && (hasPassword || hasConfiguredSecretInput(explicitAccountConfig.password));
hasUserId && (hasPassword || hasConfiguredSecretInput(explicitAuthConfig.password));
const stored = loadMatrixCredentials(env, accountId);
const hasStored =
stored && resolved.homeserver

View File

@@ -688,13 +688,21 @@ function collectMatrixAssignments(params: {
normalizeSecretStringValue(
params.context.env[getMatrixScopedEnvVarNames(accountId).accessToken],
).length > 0;
const inheritedDefaultAccountAccessTokenConfigured =
accountId === "default" && (baseAccessTokenConfigured || envAccessTokenConfigured);
collectSecretInputAssignment({
value: account.password,
path: `channels.matrix.accounts.${accountId}.password`,
expected: "string",
defaults: params.defaults,
context: params.context,
active: enabled && !(accountAccessTokenConfigured || scopedEnvAccessTokenConfigured),
active:
enabled &&
!(
accountAccessTokenConfigured ||
scopedEnvAccessTokenConfigured ||
inheritedDefaultAccountAccessTokenConfigured
),
inactiveReason: "Matrix account is disabled or this account has an accessToken configured.",
apply: (value) => {
account.password = value;

View File

@@ -396,6 +396,95 @@ describe("secrets runtime snapshot", () => {
);
});
it.each([
{
name: "top-level Matrix accessToken config",
config: {
channels: {
matrix: {
accessToken: "default-token",
accounts: {
default: {
password: {
source: "env",
provider: "default",
id: "MATRIX_DEFAULT_PASSWORD",
},
},
},
},
},
},
env: {},
},
{
name: "top-level Matrix accessToken SecretRef config",
config: {
channels: {
matrix: {
accessToken: {
source: "env",
provider: "default",
id: "MATRIX_ACCESS_TOKEN_REF",
},
accounts: {
default: {
password: {
source: "env",
provider: "default",
id: "MATRIX_DEFAULT_PASSWORD",
},
},
},
},
},
},
env: {
MATRIX_ACCESS_TOKEN_REF: "default-token",
},
},
{
name: "MATRIX_ACCESS_TOKEN env auth",
config: {
channels: {
matrix: {
accounts: {
default: {
password: {
source: "env",
provider: "default",
id: "MATRIX_DEFAULT_PASSWORD",
},
},
},
},
},
},
env: {
MATRIX_ACCESS_TOKEN: "default-token",
},
},
])("ignores default-account Matrix password refs shadowed by $name", async ({ config, env }) => {
const snapshot = await prepareSecretsRuntimeSnapshot({
config: asConfig(config),
env,
agentDirs: ["/tmp/openclaw-agent-main"],
loadAuthStore: () => ({ version: 1, profiles: {} }),
});
expect(snapshot.config.channels?.matrix?.accounts?.default?.password).toEqual({
source: "env",
provider: "default",
id: "MATRIX_DEFAULT_PASSWORD",
});
expect(snapshot.warnings).toContainEqual(
expect.objectContaining({
code: "SECRETS_REF_IGNORED_INACTIVE_SURFACE",
path: "channels.matrix.accounts.default.password",
}),
);
});
it("resolves sandbox ssh secret refs for active ssh backends", async () => {
const snapshot = await prepareSecretsRuntimeSnapshot({
config: asConfig({