Files
Termix/plugins/ai/tests/backend/permissions.test.ts
T
ZacharyZcR bf817d8bd1 feat(ai): add remote coding agent sessions for SSH hosts (#1545)
* feat(ai): add host coding agent sessions with configured providers

* Wait for agent initialization and shutdown before resuming sessions

* Keep Pi transcripts outside its configuration migration directory

* Cover Pi session directory separation

* Update core permission catalog expectations for remote agents

* Install remote agent runtimes from verified official sources

* Wait for the identity panel credentials request in its test

* Add scoped SSH forwarding setup for remote agents

* Verify forwarding setup through a fresh SSH connection

* Bound the SSH forwarding verification timeout

* Return the forwarding verification callback result

* fix(ai): support agent send and interrupt keyboard shortcuts

* feat(ai): add agent queues attachments worktrees and session recovery

* fix(ai): handle deleted workspace paths and duplicate status events

* fix(ai): accept file references in root workspaces

* fix(ai): refresh paused queues after agent errors

* fix(ai): store agent sessions in plugin tables and lock down OpenCode

Agent sessions lived in a single ctx.kv value holding up to 2000 events,
which passed the 256 KB kv limit within minutes of a normal run. Every
save after that failed, so history, nativeId, queue and archive changes
were lost and every event wrote a kv audit row.

Sessions, events and queued prompts now have their own tables. A running
agent appends events in batches at most once a second with a lazy save;
session and queue changes save immediately. Prompts, drafts and stored
event text are capped in UTF-8 bytes to fit MySQL TEXT. kv:own is no
longer requested.

The OpenCode server now requires a per-session password, so other local
accounts on the host cannot drive the agent through its loopback port.

* test(upgrade): include agent session tables in the reviewed upgrade SQL
2026-10-03 16:01:47 -05:00

64 lines
1.8 KiB
TypeScript

import { describe, it, expect } from "vitest";
import fs from "node:fs";
import path from "node:path";
import { parseManifest, qualifyPermission } from "@termix/plugin-sdk/manifest";
/**
* The permission ids an admin grants.
*
* Core registers each declared name as `<pluginId>.<name>`, so these strings
* are what end up stored in a role. They have to keep matching what ai
* shipped before the permissions moved out of the core catalog, or every role
* holding one would silently stop working.
*/
const EXPECTED = [
"ai.use",
"ai.manage_providers",
"ai.apply_proposals",
"ai.services.use",
"ai.secrets.share",
"ai.agents",
];
describe("ai permissions", () => {
const manifest = parseManifest(
JSON.parse(
fs.readFileSync(
path.resolve(import.meta.dirname, "../../manifest.json"),
"utf8",
),
),
);
it("parses cleanly", () => {
expect(manifest.errors).toEqual([]);
});
it("registers exactly the ids roles already hold", () => {
const ids = (manifest.manifest?.contributes?.permissions ?? []).map(
(permission) => qualifyPermission("ai", permission.name),
);
expect(ids).toEqual(EXPECTED);
});
it("declares a title and description for every permission", () => {
for (const permission of manifest.manifest?.contributes?.permissions ??
[]) {
expect(permission.titleKey).toBeTruthy();
expect(permission.descriptionKey).toBeTruthy();
}
});
// Core used to grant these through SYSTEM_ROLE_DEFAULTS, so a fresh install
// has to keep giving them to the user role.
it("keeps the fresh-install defaults core used to seed", () => {
for (const permission of manifest.manifest?.contributes?.permissions ??
[]) {
expect(permission.defaultRoles).toEqual([
permission.name === "agents" ? "admin" : "user",
]);
}
});
});