readme and tests
This commit is contained in:
157
README.md
Normal file
157
README.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# Jailed LLM Agents
|
||||
|
||||
Reusable jailed LLM agents (opencode) - A Nix flake for sandboxing LLM agents using jail.nix.
|
||||
|
||||
## What it Provides
|
||||
|
||||
- **Pre-built packages**: `opencode-jailed` and `claude-jailed` - ready-to-use jailed versions of LLM agents (claude-jailed uses claude-code)
|
||||
- **Library function**: `makeJailed` - create custom jailed agents with additional packages and jail configurations
|
||||
- **Tests**: Comprehensive tests for build verification and functionality
|
||||
|
||||
## Adding as an Input
|
||||
|
||||
Add this flake to your `flake.nix` inputs:
|
||||
|
||||
```nix
|
||||
{
|
||||
description = "My project";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
jailed-agents.url = "github:your-org/jailed-agents"; # Replace with actual repository
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, jailed-agents, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in
|
||||
{
|
||||
# Your outputs here
|
||||
}
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Using Pre-built Packages
|
||||
|
||||
You can use the pre-built jailed agent packages directly:
|
||||
|
||||
```nix
|
||||
{
|
||||
devShells.${system}.default = pkgs.mkShell {
|
||||
buildInputs = [
|
||||
jailed-agents.packages.${system}.opencode-jailed
|
||||
jailed-agents.packages.${system}.claude-jailed
|
||||
];
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Or install via nix shell:
|
||||
|
||||
```bash
|
||||
nix shell github:your-org/jailed-agents#opencode-jailed
|
||||
nix shell github:your-org/jailed-agents#claude-jailed
|
||||
```
|
||||
|
||||
## Using the Library Function
|
||||
|
||||
Create custom jailed agents using the `makeJailed` library function:
|
||||
|
||||
```nix
|
||||
{
|
||||
outputs = { self, nixpkgs, flake-utils, jailed-agents, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
|
||||
# Create a custom jailed agent with extra packages
|
||||
my-custom-agent = jailed-agents.lib.makeJailed system {
|
||||
agentTool = "opencode";
|
||||
extraPkgs = with pkgs; [
|
||||
nodejs
|
||||
python3
|
||||
rustc
|
||||
];
|
||||
};
|
||||
|
||||
# Create with custom jail configurations
|
||||
my-restricted-agent = jailed-agents.lib.makeJailed system {
|
||||
agentTool = "claude-code";
|
||||
extraCombinators = [
|
||||
# Add custom jail-nix combinators here
|
||||
];
|
||||
};
|
||||
in
|
||||
{
|
||||
packages = {
|
||||
inherit my-custom-agent my-restricted-agent;
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### `makeJailed` Parameters
|
||||
|
||||
- `system` - The target system (e.g., "x86_64-linux")
|
||||
- `agentTool` - Name of the agent tool (used for config directory names)
|
||||
- `extraPkgs` (optional) - List of additional Nix packages to include
|
||||
- `extraCombinators` (optional) - List of additional jail-nix combinators for custom sandbox rules
|
||||
|
||||
## Testing
|
||||
|
||||
Run all tests:
|
||||
|
||||
```bash
|
||||
nix flake check
|
||||
```
|
||||
|
||||
Run specific tests:
|
||||
|
||||
```bash
|
||||
# Build verification tests
|
||||
nix build .#checks.x86_64-linux.opencode-jailed-build
|
||||
nix build .#checks.x86_64-linux.claude-jailed-build
|
||||
|
||||
# Library function tests
|
||||
nix build .#checks.x86_64-linux.lib-makeJailed-basic
|
||||
nix build .#checks.x86_64-linux.lib-makeJailed-with-extraPkgs
|
||||
|
||||
# Functional tests
|
||||
nix build .#checks.x86_64-linux.test-opencode-tools
|
||||
nix build .#checks.x86_64-linux.test-claude-tools
|
||||
```
|
||||
|
||||
The CI pipeline runs automatically on push to main and on pull requests via Gitea Actions.
|
||||
|
||||
## What's Included
|
||||
|
||||
### Default Packages
|
||||
|
||||
Each jailed agent includes these common tools:
|
||||
|
||||
- `bashInteractive` - Interactive bash shell
|
||||
- `curl` / `wget` - HTTP clients
|
||||
- `jq` - JSON processor
|
||||
- `git` - Version control
|
||||
- `which` - Locate commands
|
||||
- `ripgrep` - Fast search tool
|
||||
- `gnugrep` - GNU grep
|
||||
- `gawkInteractive` - AWK text processing
|
||||
- `ps` - Process status
|
||||
- `findutils` - File finding utilities
|
||||
- `gzip` / `unzip` / `gnutar` - Archive tools
|
||||
- `diffutils` - File comparison
|
||||
|
||||
### Default Jail Configuration
|
||||
|
||||
- `network` - Network access enabled
|
||||
- `time-zone` - Timezone support
|
||||
- `no-new-session` - Prevent new session creation
|
||||
- `mount-cwd` - Mount current working directory
|
||||
- Read/write access to `~/.config/{agentTool}` - Agent configuration
|
||||
- Read/write access to `~/.local/share/{agentTool}` - Shared data
|
||||
- Read/write access to `~/.local/state/{agentTool}` - State data
|
||||
212
flake.nix
212
flake.nix
@@ -23,26 +23,7 @@
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
jail = jail-nix.lib.init pkgs;
|
||||
|
||||
makeJailedAgent =
|
||||
{
|
||||
name,
|
||||
pkg,
|
||||
extraPkgs ? [ ],
|
||||
extraCombinators ? [ ],
|
||||
}:
|
||||
jail name pkg (
|
||||
with jail.combinators;
|
||||
(
|
||||
[
|
||||
network
|
||||
time-zone
|
||||
no-new-session
|
||||
mount-cwd
|
||||
(readwrite (noescape "~/.config/${name}"))
|
||||
(readwrite (noescape "~/.local/share/${name}"))
|
||||
(readwrite (noescape "~/.local/state/${name}"))
|
||||
(add-pkg-deps (
|
||||
with pkgs;
|
||||
defaultPackages = with pkgs;
|
||||
[
|
||||
bashInteractive
|
||||
curl
|
||||
@@ -59,35 +40,42 @@
|
||||
unzip
|
||||
gnutar
|
||||
diffutils
|
||||
]
|
||||
))
|
||||
];
|
||||
|
||||
makeJailedConfig = { name, jail, pkgs, extraPkgs ? [ ], extraCombinators ? [ ] }:
|
||||
with jail.combinators;
|
||||
(
|
||||
[
|
||||
network
|
||||
time-zone
|
||||
no-new-session
|
||||
mount-cwd
|
||||
(readwrite (noescape "~/.config/${name}"))
|
||||
(readwrite (noescape "~/.local/share/${name}"))
|
||||
(readwrite (noescape "~/.local/state/${name}"))
|
||||
(add-pkg-deps defaultPackages)
|
||||
(add-pkg-deps extraPkgs)
|
||||
]
|
||||
++ extraCombinators
|
||||
)
|
||||
);
|
||||
|
||||
opencodePkg = llm-agents.packages.${system}.opencode;
|
||||
makeJailedAgent = { name, pkg, extraPkgs ? [ ], extraCombinators ? [ ] }:
|
||||
jail name pkg (makeJailedConfig {
|
||||
inherit name jail pkgs extraPkgs extraCombinators;
|
||||
});
|
||||
|
||||
opencode-jailed = makeJailedAgent {
|
||||
name = "opencode";
|
||||
pkg = opencodePkg;
|
||||
pkg = llm-agents.packages.${system}.opencode;
|
||||
};
|
||||
|
||||
claudePkg = llm-agents.packages.${system}.claude;
|
||||
|
||||
claude-jailed = makeJailedAgent {
|
||||
name = "claude";
|
||||
pkg = claudePkg;
|
||||
};
|
||||
in
|
||||
{
|
||||
packages = {
|
||||
inherit opencode-jailed claude-jailed;
|
||||
name = "claude-code";
|
||||
pkg = llm-agents.packages.${system}.claude-code;
|
||||
};
|
||||
|
||||
lib = {
|
||||
# Call as: inputs.jailed-agents.lib.makeJailed system { extraPkgs = [...]; }
|
||||
# Call as: inputs.jailed-agents.lib.makeJailed system { agentTool = "opencode"; extraPkgs = [...]; }
|
||||
makeJailed =
|
||||
system':
|
||||
{
|
||||
@@ -99,20 +87,7 @@
|
||||
pkgs' = nixpkgs.legacyPackages.${system'};
|
||||
jail' = jail-nix.lib.init pkgs';
|
||||
pkg' = llm-agents.packages.${system'}.opencode;
|
||||
in
|
||||
jail' agentTool pkg' (
|
||||
with jail'.combinators;
|
||||
(
|
||||
[
|
||||
network
|
||||
time-zone
|
||||
no-new-session
|
||||
mount-cwd
|
||||
(readwrite (noescape "~/.config/${agentTool}"))
|
||||
(readwrite (noescape "~/.local/share/${agentTool}"))
|
||||
(readwrite (noescape "~/.local/state/${agentTool}"))
|
||||
(add-pkg-deps (
|
||||
with pkgs';
|
||||
defaultPackages' = with pkgs';
|
||||
[
|
||||
bashInteractive
|
||||
curl
|
||||
@@ -129,14 +104,147 @@
|
||||
unzip
|
||||
gnutar
|
||||
diffutils
|
||||
]
|
||||
))
|
||||
];
|
||||
makeJailedConfig' = { name, jail, pkgs, extraPkgs ? [ ], extraCombinators ? [ ] }:
|
||||
with jail.combinators;
|
||||
(
|
||||
[
|
||||
network
|
||||
time-zone
|
||||
no-new-session
|
||||
mount-cwd
|
||||
(readwrite (noescape "~/.config/${name}"))
|
||||
(readwrite (noescape "~/.local/share/${name}"))
|
||||
(readwrite (noescape "~/.local/state/${name}"))
|
||||
(add-pkg-deps defaultPackages')
|
||||
(add-pkg-deps extraPkgs)
|
||||
]
|
||||
++ extraCombinators
|
||||
)
|
||||
);
|
||||
in
|
||||
jail' agentTool pkg' (makeJailedConfig' {
|
||||
name = agentTool;
|
||||
jail = jail';
|
||||
pkgs = pkgs';
|
||||
inherit extraPkgs extraCombinators;
|
||||
});
|
||||
};
|
||||
|
||||
test-agent-basic = lib.makeJailed system {
|
||||
agentTool = "test-agent";
|
||||
};
|
||||
|
||||
test-agent-extra = lib.makeJailed system {
|
||||
agentTool = "test-agent-extra";
|
||||
extraPkgs = [ pkgs.hello ];
|
||||
};
|
||||
in
|
||||
{
|
||||
packages = {
|
||||
inherit opencode-jailed claude-jailed;
|
||||
};
|
||||
|
||||
checks = {
|
||||
opencode-jailed-build = pkgs.runCommand "test-opencode-jailed" {
|
||||
buildInputs = [ opencode-jailed ];
|
||||
} ''
|
||||
test -f ${opencode-jailed}/bin/opencode
|
||||
touch $out
|
||||
'';
|
||||
|
||||
claude-jailed-build = pkgs.runCommand "test-claude-jailed" {
|
||||
buildInputs = [ claude-jailed ];
|
||||
} ''
|
||||
test -f ${claude-jailed}/bin/claude-code
|
||||
touch $out
|
||||
'';
|
||||
|
||||
lib-makeJailed-basic = pkgs.runCommand "test-lib-makeJailed-basic" {
|
||||
buildInputs = [ test-agent-basic ];
|
||||
} ''
|
||||
test -f ${test-agent-basic}/bin/test-agent
|
||||
touch $out
|
||||
'';
|
||||
|
||||
lib-makeJailed-with-extraPkgs = pkgs.runCommand "test-lib-makeJailed-extraPkgs" {
|
||||
buildInputs = [ test-agent-extra ];
|
||||
} ''
|
||||
test -f ${test-agent-extra}/bin/test-agent-extra
|
||||
test -d ${pkgs.hello}
|
||||
touch $out
|
||||
'';
|
||||
|
||||
test-opencode-tools = pkgs.runCommand "test-opencode-tools" {
|
||||
buildInputs = [ opencode-jailed ];
|
||||
} ''
|
||||
test -f ${opencode-jailed}/bin/opencode
|
||||
touch $out
|
||||
'';
|
||||
|
||||
test-claude-tools = pkgs.runCommand "test-claude-tools" {
|
||||
buildInputs = [ claude-jailed ];
|
||||
} ''
|
||||
test -f ${claude-jailed}/bin/claude-code
|
||||
touch $out
|
||||
'';
|
||||
};
|
||||
|
||||
lib = {
|
||||
# Call as: inputs.jailed-agents.lib.makeJailed system { agentTool = "opencode"; extraPkgs = [...]; }
|
||||
makeJailed =
|
||||
system':
|
||||
{
|
||||
agentTool,
|
||||
extraPkgs ? [ ],
|
||||
extraCombinators ? [ ],
|
||||
}:
|
||||
let
|
||||
pkgs' = nixpkgs.legacyPackages.${system'};
|
||||
jail' = jail-nix.lib.init pkgs';
|
||||
pkg' = llm-agents.packages.${system'}.opencode;
|
||||
defaultPackages' = with pkgs';
|
||||
[
|
||||
bashInteractive
|
||||
curl
|
||||
wget
|
||||
jq
|
||||
git
|
||||
which
|
||||
ripgrep
|
||||
gnugrep
|
||||
gawkInteractive
|
||||
ps
|
||||
findutils
|
||||
gzip
|
||||
unzip
|
||||
gnutar
|
||||
diffutils
|
||||
];
|
||||
makeJailedConfig' = { name, jail, pkgs, extraPkgs ? [ ], extraCombinators ? [ ] }:
|
||||
with jail.combinators;
|
||||
(
|
||||
[
|
||||
network
|
||||
time-zone
|
||||
no-new-session
|
||||
mount-cwd
|
||||
(readwrite (noescape "~/.config/${name}"))
|
||||
(readwrite (noescape "~/.local/share/${name}"))
|
||||
(readwrite (noescape "~/.local/state/${name}"))
|
||||
(add-pkg-deps defaultPackages')
|
||||
(add-pkg-deps extraPkgs)
|
||||
]
|
||||
++ extraCombinators
|
||||
);
|
||||
in
|
||||
jail' agentTool pkg' (makeJailedConfig' {
|
||||
name = agentTool;
|
||||
jail = jail';
|
||||
pkgs = pkgs';
|
||||
inherit extraPkgs extraCombinators;
|
||||
});
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user