Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion appl/cmd/webfs.b
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ init(nil: ref Draw->Context, args: list of string)
args = arg->argv();
arg = nil;

mountpt := "/n/web";
mountpt := "/mnt/web";
if(args != nil)
mountpt = hd args;

Expand Down
2 changes: 1 addition & 1 deletion appl/veltro/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@ be explicit:
namespace surface supports that distinction.

The same rule applies to other fixed-function service trees. `/mnt/matrix` is
derived only from the `matrix` tool, `/n/git` only from the `git` tool,
derived only from the `matrix` tool, `/mnt/git` only from the `git` tool,
`/mnt/gpu` only from `gpu` or local `vision`, `/n/wikia` only from `wiki`,
`/mnt/video` only from video presentation tools, and `/phone` only from `sms`,
`dial`, or `contacts`.
Expand Down
22 changes: 11 additions & 11 deletions appl/veltro/nsconstruct.b
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,6 @@ restrictns(caps: ref Capabilities): string
# /n is the IMPORT YARD — foreign trees imported intact (docs/NAMESPACE-LAYOUT.md).
# All /n/ entries are capability-driven — never auto-exposed by existence:
# /n/speech — "/n/speech" in caps.paths
# /n/git — fixed git tool
# /n/wallet — "/n/wallet" in caps.paths
# /n/pres-* — caps.xenith != 0
# /n/local — /n/local/ subpaths in caps.paths
Expand All @@ -231,15 +230,6 @@ restrictns(caps: ref Capabilities): string
nallow = "speech" :: nallow;
}

# /n/git — fixed-function git service. The git tool mounts git/fs here
# during trusted init; generic path grants cannot expose gitfs ctl/raw
# repository state to unrelated tools.
if(inlist("git", caps.tools)) {
(gitok, nil) := sys->stat("/n/git");
if(gitok >= 0)
nallow = "git" :: nallow;
}

# /n/wallet — only if explicitly granted via caps.paths
if(inlist("/n/wallet", caps.paths)) {
(walletok, nil) := sys->stat("/n/wallet");
Expand Down Expand Up @@ -338,6 +328,15 @@ restrictns(caps: ref Capabilities): string
if(gpuok >= 0 && !inlist("gpu", mntpaths))
mntpaths = "gpu" :: mntpaths;
}
# /mnt/git — fixed-function git service (git/fs, mounted by the git tool
# during trusted init; migrated from /n/git per docs/NAMESPACE-LAYOUT.md,
# INFR-401). Derived only from the git tool; generic path grants cannot
# expose gitfs ctl/raw repository state to unrelated tools.
if(inlist("git", caps.tools)) {
(gitok, nil) := sys->stat("/mnt/git");
if(gitok >= 0 && !inlist("git", mntpaths))
mntpaths = "git" :: mntpaths;
}
# /mnt/ui — presentation surface (luciuisrv), granted only to fixed-function
# UI tools. Per-invocation caps prevent unrelated tools from inheriting it.
# Capability-gated exactly as before, now under /mnt. The grant exposes the
Expand Down Expand Up @@ -1103,6 +1102,7 @@ calendarcontrolpath(path: string): int
fixedservicecontrolpath(path: string): int
{
return path == "/mnt/matrix" || prefix(path, "/mnt/matrix/") ||
path == "/mnt/git" || prefix(path, "/mnt/git/") ||
path == "/n/git" || prefix(path, "/n/git/") ||
path == "/mnt/gpu" || prefix(path, "/mnt/gpu/") ||
path == "/mnt/web" || prefix(path, "/mnt/web/") ||
Expand Down Expand Up @@ -1258,7 +1258,6 @@ emitmanifest(caps: ref Capabilities, mpath: string)
# /n entries — capability-driven (import yard)
nentries := array[] of {
("/n/speech", "Speech", "rw"),
("/n/git", "Git", "rw"),
("/n/wikia", "Wiki Agent", "rw"),
("/phone", "Phone Bridge", "rw"),
# The LLM (llm9p), UI surface (luciuisrv) and MCP providers live under
Expand All @@ -1269,6 +1268,7 @@ emitmanifest(caps: ref Capabilities, mpath: string)
("/mnt/mcp", "MCP Providers", "rw"),
("/mnt/matrix", "Matrix Runtime", "rw"),
("/mnt/gpu", "GPU Service", "rw"),
("/mnt/git", "Git", "rw"),
("/mnt/web", "Web Service", "rw"),
("/mnt/wiki", "Wiki Store", "rw"),
("/mnt/registry", "Registry", "rw"),
Expand Down
48 changes: 24 additions & 24 deletions appl/veltro/tools/git.b
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ implement ToolGit;
#
# git - Git repository access for Veltro agents
#
# Read operations go through git/fs mounted at /n/git.
# Read operations go through git/fs mounted at /mnt/git.
# Write operations go through a worker thread that retains
# the unrestricted namespace (spawned before restriction).
#
Expand Down Expand Up @@ -69,7 +69,7 @@ init(): string
if(ok < 0)
return nil; # No repo; exec() will return errors

# Mount git/fs at /n/git before namespace restriction
# Mount git/fs at /mnt/git before namespace restriction
ready := chan of int;
spawn mountgitfs(ready);
result := <-ready;
Expand All @@ -96,7 +96,7 @@ mountgitfs(ready: chan of int)
}

{
gitfs->init(nil, "git/fs" :: "-m" :: "/n/git" :: "/.git" :: nil);
gitfs->init(nil, "git/fs" :: "-m" :: "/mnt/git" :: "/.git" :: nil);
ready <-= 1;
} exception {
"*" =>
Expand Down Expand Up @@ -299,15 +299,15 @@ workercall(cmdline: string): string

gitstatus(): string
{
branch := strip(readfile("/n/git/ctl"));
branch := strip(readfile("/mnt/git/ctl"));
if(branch == "")
branch = "(unknown)";

headhash := strip(readfile("/n/git/HEAD/hash"));
headhash := strip(readfile("/mnt/git/HEAD/hash"));
if(headhash == "")
return "On branch " + branch + "\n(no commits)";

headmsg := strip(readfile("/n/git/HEAD/msg"));
headmsg := strip(readfile("/mnt/git/HEAD/msg"));
(firstline, nil) := splitline(headmsg);

return "On branch " + branch + "\n" +
Expand All @@ -318,20 +318,20 @@ gitlog(n: int): string
{
result := "";

hash := strip(readfile("/n/git/HEAD/hash"));
hash := strip(readfile("/mnt/git/HEAD/hash"));
if(hash == "")
return "(no commits)";

author := strip(readfile("/n/git/HEAD/author"));
msg := strip(readfile("/n/git/HEAD/msg"));
author := strip(readfile("/mnt/git/HEAD/author"));
msg := strip(readfile("/mnt/git/HEAD/msg"));
(firstline, nil) := splitline(msg);
result = shorthash(hash) + " " + firstline + "\n";
result += " Author: " + author + "\n";

parent := strip(readfile("/n/git/HEAD/parent"));
parent := strip(readfile("/mnt/git/HEAD/parent"));

for(i := 1; i < n && parent != "" && parent != "nil"; i++) {
objdir := "/n/git/object/" + parent;
objdir := "/mnt/git/object/" + parent;

author = strip(readfile(objdir + "/author"));
msg = strip(readfile(objdir + "/msg"));
Expand All @@ -351,16 +351,16 @@ gitshow(gitref: string): string
objdir: string;

if(len gitref == 40) {
objdir = "/n/git/object/" + gitref;
objdir = "/mnt/git/object/" + gitref;
} else {
hash := strip(readfile("/n/git/branch/heads/" + gitref + "/hash"));
hash := strip(readfile("/mnt/git/branch/heads/" + gitref + "/hash"));
if(hash != "") {
objdir = "/n/git/object/" + hash;
objdir = "/mnt/git/object/" + hash;
gitref = hash;
} else {
hash = strip(readfile("/n/git/tag/" + gitref + "/hash"));
hash = strip(readfile("/mnt/git/tag/" + gitref + "/hash"));
if(hash != "") {
objdir = "/n/git/object/" + hash;
objdir = "/mnt/git/object/" + hash;
gitref = hash;
} else
return "error: cannot find ref: " + gitref;
Expand Down Expand Up @@ -413,9 +413,9 @@ gitshow(gitref: string): string

gitbranch(): string
{
current := strip(readfile("/n/git/ctl"));
current := strip(readfile("/mnt/git/ctl"));

entries := listdir("/n/git/branch/heads");
entries := listdir("/mnt/git/branch/heads");
if(entries == nil)
return "(no branches)";

Expand All @@ -428,10 +428,10 @@ gitbranch(): string
result += " " + bname + "\n";
}

remotes := listdir("/n/git/branch/remotes");
remotes := listdir("/mnt/git/branch/remotes");
for(; remotes != nil; remotes = tl remotes) {
remote := hd remotes;
rbranches := listdir("/n/git/branch/remotes/" + remote);
rbranches := listdir("/mnt/git/branch/remotes/" + remote);
for(; rbranches != nil; rbranches = tl rbranches)
result += " remotes/" + remote + "/" + hd rbranches + "\n";
}
Expand All @@ -441,7 +441,7 @@ gitbranch(): string

gittag(): string
{
entries := listdir("/n/git/tag");
entries := listdir("/mnt/git/tag");
if(entries == nil)
return "(no tags)";

Expand All @@ -462,16 +462,16 @@ gitcat(args: string): string

treepath: string;
if(gitref == "") {
treepath = "/n/git/HEAD/tree/" + fpath;
treepath = "/mnt/git/HEAD/tree/" + fpath;
} else {
hash := strip(readfile("/n/git/branch/heads/" + gitref + "/hash"));
hash := strip(readfile("/mnt/git/branch/heads/" + gitref + "/hash"));
if(hash == "") {
if(len gitref == 40)
hash = gitref;
else
return "error: cannot find ref: " + gitref;
}
treepath = "/n/git/object/" + hash + "/tree/" + fpath;
treepath = "/mnt/git/object/" + hash + "/tree/" + fpath;
}

content := readfile(treepath);
Expand Down
1 change: 1 addition & 0 deletions appl/veltro/tools9p.b
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,7 @@ calendarcontrolpath(path: string): int
fixedservicecontrolpath(path: string): int
{
return path == "/mnt/matrix" || prefix(path, "/mnt/matrix/") ||
path == "/mnt/git" || prefix(path, "/mnt/git/") ||
path == "/n/git" || prefix(path, "/n/git/") ||
path == "/mnt/gpu" || prefix(path, "/mnt/gpu/") ||
path == "/mnt/web" || prefix(path, "/mnt/web/") ||
Expand Down
Binary file modified dis/tests/veltro_security_test.dis
Binary file not shown.
Binary file modified dis/veltro/nsconstruct.dis
Binary file not shown.
Binary file modified dis/veltro/tools/git.dis
Binary file not shown.
Binary file modified dis/veltro/tools9p.dis
Binary file not shown.
Binary file modified dis/webfs.dis
Binary file not shown.
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ Policy applied after `FORKNS`:
- `/dis` → reduced to `lib/`, `veltro/` (+ `sh.dis` if `exec` tool active)
- `/dis/veltro/tools/` → only registered tool `.dis` files visible
- `/dev` → reduced to `cons`, `null`, `time`
- `/n` → capability-gated foreign imports: `/n/speech` only if in `caps.paths`; `/n/git` only for the fixed `git` tool
- `/n` → capability-gated foreign imports: `/n/speech` only if in `caps.paths` (`/mnt/git` is derived only for the fixed `git` tool — migrated from `/n/git`, INFR-401)
- `/tmp` → writable only at `/tmp/veltro/scratch/`

### wallet9p (`appl/veltro/wallet9p.b`)
Expand Down
2 changes: 1 addition & 1 deletion docs/OPERATIONAL-OVERVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ When an agent session starts, `nsconstruct` restricts the namespace:
- `/dis` reduced to `lib/`, `veltro/` (+ `sh.dis` if exec is active)
- `/dis/veltro/tools/` reduced to only the registered tool `.dis` files
- `/dev` reduced to `cons`, `null`, `time`
- `/n` reduced to capability-gated foreign imports (`/n/speech` only if explicitly granted via paths; `/n/git` only for the fixed `git` tool)
- `/n` reduced to capability-gated foreign imports (`/n/speech` only if explicitly granted via paths); `/mnt/git` is derived only for the fixed `git` tool (migrated from `/n/git`, INFR-401)
- `/tmp` writable only at `/tmp/veltro/scratch/`

The agent cannot see files it wasn't granted. Subagents can only narrow further.
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture-review-veltro-unification.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ The pieces already exist:
- **Phase 2**: A dedicated `compose` or `create` tool that handles the compile-register lifecycle, with appropriate sandboxing (the new tool's namespace is restricted by the creating agent's capabilities -- you can't escalate privileges by writing code).
- **Phase 3**: The AI can introspect available modules, read their interfaces, and generate correct Limbo code that type-checks. The module system provides the contracts; the AI provides the composition.

The security model handles this naturally: a composed tool inherits the creating agent's namespace restrictions. You can't write a tool that accesses `/n/git` if your namespace doesn't include it. Capability attenuation is preserved even through code generation.
The security model handles this naturally: a composed tool inherits the creating agent's namespace restrictions. You can't write a tool that accesses `/mnt/git` if your namespace doesn't include it. Capability attenuation is preserved even through code generation.

## Design Note: The Semantic Shim as Temporary Adapter

Expand Down
2 changes: 1 addition & 1 deletion lib/veltro/meta.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ If you cannot fulfill a request — missing tools, unclear intent, or a failed d
<capability_construction>
When creating a task, you construct its entire world:
- tools= grants additional capabilities beyond the base set
- paths= grants filesystem visibility (/n/local/Users/pdfinn, /n/git, etc.)
- paths= grants filesystem visibility (/n/local/Users/pdfinn, /mnt/git, etc.)
- instructions= provides procedural guidance for the task agent

Put authority-bearing attrs (tools=, paths=, model=, agenttype=) before
Expand Down
4 changes: 2 additions & 2 deletions lib/veltro/nsaudit/authorities/git
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
tool=git
description='Git repository access via git/fs at /n/git'
description='Git repository access via git/fs at /mnt/git'
authorities='reads_fs writes_fs'
irreversible='writes_fs'
notes='Read goes through /n/git. The WRITE path runs in a worker that retained the UNRESTRICTED namespace (spawned before restriction) — durable host mutation is reachable regardless of caps.paths. High-trust.'
notes='Read goes through /mnt/git. The WRITE path runs in a worker that retained the UNRESTRICTED namespace (spawned before restriction) — durable host mutation is reachable regardless of caps.paths. High-trust.'
2 changes: 1 addition & 1 deletion lib/veltro/tools/git.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
git - Git repository access and management

Provides full git repository access. Read operations use the native
git filesystem (git/fs at /n/git). Write operations use a worker
git filesystem (git/fs at /mnt/git). Write operations use a worker
thread with direct repository access.

Read commands:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@
/mnt/video
/mnt/video/0/ctl
/phone
/mnt/git
/mnt/git/ctl
39 changes: 20 additions & 19 deletions tests/veltro_security_test.b
Original file line number Diff line number Diff line change
Expand Up @@ -827,29 +827,30 @@ mntLlmWorker(result: chan of string)
result <-= "";
}

# The git service is a fixed tool-derived /n import. The git tool must see
# /n/git without a raw path grant, while generic tools must not.
# The git service is a fixed tool-derived /mnt application mount (migrated
# from /n/git per docs/NAMESPACE-LAYOUT.md, INFR-401). The git tool must see
# /mnt/git without a raw path grant, while generic tools must not.
testRestrictNsGitToolDerived(t: ref T)
{
createdn := 0;
(ok, nil) := sys->stat("/n");
createdmnt := 0;
(ok, nil) := sys->stat("/mnt");
if(ok < 0) {
fd := sys->create("/n", Sys->OREAD, Sys->DMDIR | 8r755);
fd := sys->create("/mnt", Sys->OREAD, Sys->DMDIR | 8r755);
if(fd == nil) {
t.skip("cannot create /n test fixture");
t.skip("cannot create /mnt test fixture");
return;
}
fd = nil;
createdn = 1;
createdmnt = 1;
}
createdgit := 0;
(ok, nil) = sys->stat("/n/git");
(ok, nil) = sys->stat("/mnt/git");
if(ok < 0) {
fd := sys->create("/n/git", Sys->OREAD, Sys->DMDIR | 8r755);
fd := sys->create("/mnt/git", Sys->OREAD, Sys->DMDIR | 8r755);
if(fd == nil) {
if(createdn)
sys->remove("/n");
t.skip("cannot create /n/git test fixture");
if(createdmnt)
sys->remove("/mnt");
t.skip("cannot create /mnt/git test fixture");
return;
}
fd = nil;
Expand All @@ -865,9 +866,9 @@ testRestrictNsGitToolDerived(t: ref T)
}

if(createdgit)
sys->remove("/n/git");
if(createdn)
sys->remove("/n");
sys->remove("/mnt/git");
if(createdmnt)
sys->remove("/mnt");
if(r != "")
t.error(r);
}
Expand All @@ -886,9 +887,9 @@ gitToolDerivedWorker(result: chan of string)
result <-= sys->sprint("restrictns (git tool) failed: %s", err);
return;
}
(gitok, nil) := sys->stat("/n/git");
(gitok, nil) := sys->stat("/mnt/git");
if(gitok < 0) {
result <-= "/n/git missing for git tool without raw path grant";
result <-= "/mnt/git missing for git tool without raw path grant";
return;
}
result <-= "";
Expand All @@ -908,9 +909,9 @@ gitGenericHiddenWorker(result: chan of string)
result <-= sys->sprint("restrictns (generic tool) failed: %s", err);
return;
}
(gitok, nil) := sys->stat("/n/git");
(gitok, nil) := sys->stat("/mnt/git");
if(gitok >= 0) {
result <-= "/n/git visible to generic tool without git capability";
result <-= "/mnt/git visible to generic tool without git capability";
return;
}
result <-= "";
Expand Down
Loading