mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-08-28 07:23:06 +00:00
128 lines
5.5 KiB
TypeScript
128 lines
5.5 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import type { PermissionsService } from "@gotgenes/pi-permission-system";
|
|
import {
|
|
formatSshPermissionInput,
|
|
installSshPermissionIntegration,
|
|
type SshPermissionConnection,
|
|
} from "../permission-integration.ts";
|
|
|
|
function makeService() {
|
|
const formatters = new Map<string, (input: Record<string, unknown>) => string | undefined>();
|
|
const extractors = new Map<string, (input: Record<string, unknown>) => string | undefined>();
|
|
const service = {
|
|
registerToolInputFormatter(name: string, formatter: (input: Record<string, unknown>) => string | undefined) {
|
|
formatters.set(name, formatter);
|
|
return () => formatters.delete(name);
|
|
},
|
|
registerToolAccessExtractor(name: string, extractor: (input: Record<string, unknown>) => string | undefined) {
|
|
extractors.set(name, extractor);
|
|
return () => extractors.delete(name);
|
|
},
|
|
} as unknown as PermissionsService;
|
|
return { service, formatters, extractors };
|
|
}
|
|
|
|
function makePi() {
|
|
const hooks = new Map<string, Array<() => void>>();
|
|
const eventHooks = new Map<string, Array<() => void>>();
|
|
const add = (map: Map<string, Array<() => void>>, name: string, handler: () => void) => {
|
|
map.set(name, [...(map.get(name) ?? []), handler]);
|
|
};
|
|
return {
|
|
api: {
|
|
on: (name: string, handler: () => void) => add(hooks, name, handler),
|
|
events: { on: (name: string, handler: () => void) => add(eventHooks, name, handler) },
|
|
},
|
|
emit: (name: string) => hooks.get(name)?.forEach((handler) => handler()),
|
|
emitEvent: (name: string) => eventHooks.get(name)?.forEach((handler) => handler()),
|
|
};
|
|
}
|
|
|
|
const connection: SshPermissionConnection = {
|
|
remote: "packaging-server",
|
|
port: 2222,
|
|
remoteCwd: "/srv/build",
|
|
remoteHome: "/home/builder",
|
|
};
|
|
|
|
test("formats reviewed connection requests without exposing credentials", () => {
|
|
assert.equal(
|
|
formatSshPermissionInput("ssh_connect", { hostId: "packaging-server", remotePath: "/srv/build" }, connection),
|
|
"SSH target 'packaging-server:2222' in remote cwd '/srv/build'; establish a persistent SSH2 connection",
|
|
);
|
|
assert.equal(
|
|
formatSshPermissionInput("ssh_connect", { hostId: "unknown" }, null),
|
|
"requested imported SSH host 'unknown'; establish a persistent SSH2 connection",
|
|
);
|
|
});
|
|
|
|
test("formats the SSH target and bounded operation details", () => {
|
|
assert.equal(
|
|
formatSshPermissionInput("ssh_read", { path: "src/main.ts", offset: 5, limit: 20 }, connection),
|
|
"SSH target 'packaging-server:2222' in remote cwd '/srv/build'; read remote path '/srv/build/src/main.ts' (requested 'src/main.ts'), offset 5, limit 20",
|
|
);
|
|
assert.equal(
|
|
formatSshPermissionInput("ssh_write", { path: "dist/a.txt", content: "one\ntwo" }, connection),
|
|
"SSH target 'packaging-server:2222' in remote cwd '/srv/build'; write remote path '/srv/build/dist/a.txt' (requested 'dist/a.txt') (2 lines, 7 characters)",
|
|
);
|
|
assert.equal(
|
|
formatSshPermissionInput("ssh_grep", { pattern: "TODO", path: "src", include: "*.ts", limit: 25 }, connection),
|
|
"SSH target 'packaging-server:2222' in remote cwd '/srv/build'; search remote file contents under '/srv/build/src' (requested 'src'), for 'TODO', limit 25, file glob '*.ts'",
|
|
);
|
|
assert.equal(
|
|
formatSshPermissionInput("ssh_cd", { path: "../release" }, connection),
|
|
"SSH target 'packaging-server:2222' in remote cwd '/srv/build'; change the active remote cwd to '/srv/release' (requested '../release')",
|
|
);
|
|
assert.match(
|
|
formatSshPermissionInput("ssh_read", { path: "~/logs/app.log" }, connection),
|
|
/remote path '\/home\/builder\/logs\/app\.log' \(requested '~\/logs\/app\.log'\)/,
|
|
);
|
|
});
|
|
|
|
test("registers previews and disables local path extraction for remote path tools", () => {
|
|
const { service, formatters, extractors } = makeService();
|
|
const pi = makePi();
|
|
const dispose = installSshPermissionIntegration(
|
|
pi.api as never,
|
|
() => connection,
|
|
{
|
|
getPermissionsService: () => service,
|
|
permissionsReadyChannel: "permissions:ready",
|
|
getConnectTarget: () => connection,
|
|
},
|
|
);
|
|
|
|
assert.deepEqual([...formatters.keys()], ["ssh_connect", "ssh_cd", "ssh_read", "ssh_write", "ssh_edit", "ssh_find", "ssh_grep", "ssh_bash"]);
|
|
assert.deepEqual([...extractors.keys()], ["ssh_cd", "ssh_read", "ssh_write", "ssh_edit", "ssh_find", "ssh_grep"]);
|
|
assert.equal(extractors.get("ssh_read")?.({ path: "/remote/secret" }), undefined);
|
|
assert.equal(extractors.get("ssh_grep")?.({ path: "/remote/src" }), undefined);
|
|
assert.equal(extractors.get("ssh_cd")?.({ path: "/remote/release" }), undefined);
|
|
assert.match(formatters.get("ssh_bash")?.({ command: "git push" }) ?? "", /packaging-server:2222/);
|
|
assert.match(formatters.get("ssh_connect")?.({ hostId: "packaging-server" }) ?? "", /establish a persistent SSH2 connection/);
|
|
|
|
dispose();
|
|
assert.equal(formatters.size, 0);
|
|
assert.equal(extractors.size, 0);
|
|
});
|
|
|
|
test("registers when the permission service becomes ready and cleans up on shutdown", () => {
|
|
const { service, formatters, extractors } = makeService();
|
|
const pi = makePi();
|
|
let published: PermissionsService | undefined;
|
|
installSshPermissionIntegration(pi.api as never, () => connection, {
|
|
getPermissionsService: () => published,
|
|
permissionsReadyChannel: "permissions:ready",
|
|
});
|
|
assert.equal(formatters.size, 0);
|
|
|
|
published = service;
|
|
pi.emitEvent("permissions:ready");
|
|
assert.equal(formatters.size, 8);
|
|
assert.equal(extractors.size, 6);
|
|
|
|
pi.emit("session_shutdown");
|
|
assert.equal(formatters.size, 0);
|
|
assert.equal(extractors.size, 0);
|
|
});
|