Permissions
The PermissionManager in @cmdop/bot controls access to your bot with per-user, per-machine granularity. It uses the same five permission levels as the Python SDK: NONE, READ, EXECUTE, FILES, and ADMIN. Supports identity linking across Telegram, Discord, and Slack channels, wildcard machine grants, and custom persistent stores (JSON file or database). Integrates directly with IntegrationHub.
Control access to your CMDOP bot with the built-in permission system. Per-user, per-machine granularity with identity linking across channels.
What permission levels are available?
| Level | Value | Access |
|---|---|---|
NONE | 0 | No access |
READ | 1 | List directories, read files |
EXECUTE | 2 | Run shell commands |
FILES | 3 | Write and delete files |
ADMIN | 4 | Full access to all machines and commands |
How do I use the PermissionManager?
// Import PermissionManager and PermissionLevel from @cmdop/bot
import { PermissionManager, PermissionLevel } from '@cmdop/bot';
// Create a new permission manager instance (in-memory store by default)
const permissions = new PermissionManager();
// Add admin β grants full access to everything across all machines
permissions.addAdmin('telegram:123456789');
// Grant EXECUTE permission for a specific user on a specific machine
permissions.grant({
identity: 'discord:987654321',
machine: 'prod-server',
level: PermissionLevel.EXECUTE,
});
// Grant READ-only access to another user on a different machine
permissions.grant({
identity: 'slack:U12345678',
machine: 'logs-server',
level: PermissionLevel.READ,
});How do I integrate permissions with IntegrationHub?
// Import everything needed for hub + permissions + channel
import { IntegrationHub, PermissionManager, PermissionLevel } from '@cmdop/bot';
import { TelegramChannel } from '@cmdop/bot/telegram';
// Set up permissions before creating the hub
const permissions = new PermissionManager();
permissions.addAdmin('telegram:123456789');
permissions.grant({
identity: 'telegram:987654321',
machine: 'dev-server',
level: PermissionLevel.EXECUTE,
});
// Pass the permission manager to the hub via the permissions option
const hub = new IntegrationHub({
apiKey: process.env.CMDOP_API_KEY!,
permissions,
});
// Add channel β hub will automatically check permissions before running commands
hub.addChannel(new TelegramChannel({
token: process.env.TELEGRAM_BOT_TOKEN!,
}));
hub.start();What is the identity format?
Format: {channel}:{userId}
| Channel | Format | Example |
|---|---|---|
| Telegram | telegram:{userId} | telegram:123456789 |
| Discord | discord:{userId} | discord:987654321 |
| Slack | slack:{userId} | slack:U12345678 |
How do I link identities across channels?
Link identities across channels so users have the same permissions everywhere:
// First, grant admin to a Telegram user
permissions.addAdmin('telegram:123456789');
// Link their Discord and Slack accounts to the same Telegram identity
permissions.linkIdentity('telegram:123456789', 'discord:111222333');
permissions.linkIdentity('telegram:123456789', 'slack:U99887766');
// Now discord:111222333 and slack:U99887766 also have admin accessHow do I check permissions programmatically?
// Check if a user has permission to run a command on a machine
const canRun = permissions.check({
identity: 'telegram:123456789',
machine: 'my-server',
command: 'shell',
});
console.log(canRun); // true (admin has access to everything)
// Check a user with no permissions
const canRun2 = permissions.check({
identity: 'telegram:555555555',
machine: 'prod-server',
command: 'shell',
});
console.log(canRun2); // false (no permission granted)How do I enforce permissions with require()?
Throws PermissionDeniedError if permission denied:
// Import the error class for catching permission failures
import { PermissionDeniedError } from '@cmdop/bot';
try {
// require() throws PermissionDeniedError if the user lacks access
permissions.require({
identity: 'telegram:999999999',
machine: 'prod-server',
command: 'shell',
});
} catch (error) {
// Handle the denied case (e.g., reply with an error message)
if (error instanceof PermissionDeniedError) {
console.log('Access denied:', error.message);
}
}How do I use wildcard permissions?
// Grant EXECUTE access to all machines using the '*' wildcard
permissions.grant({
identity: 'telegram:123456789',
machine: '*',
level: PermissionLevel.EXECUTE,
});How do I revoke permissions?
// Revoke a specific user's permission on a specific machine
permissions.revoke({
identity: 'discord:987654321',
machine: 'dev-server',
});
// Remove admin status from a user
permissions.removeAdmin('telegram:123456789');How do I persist permissions with a custom store?
By default, permissions are stored in memory. Use a custom store for persistence:
// Import JsonFileStore for file-based persistence
import { PermissionManager, JsonFileStore } from '@cmdop/bot';
// Create permission manager with JSON file store
const permissions = new PermissionManager({
store: new JsonFileStore('./permissions.json'),
});
// Permissions are automatically saved to and loaded from permissions.jsonHow do I implement a custom store interface?
// The PermissionStore interface requires load() and save() methods
interface PermissionStore {
load(): Promise<PermissionData>;
save(data: PermissionData): Promise<void>;
}
// Example: implement a database-backed store
class MyDatabaseStore implements PermissionStore {
async load(): Promise<PermissionData> {
// Load permission data from your database
}
async save(data: PermissionData): Promise<void> {
// Save permission data to your database
}
}
// Use your custom store with the permission manager
const permissions = new PermissionManager({
store: new MyDatabaseStore(),
});