763759189f
- Folder browser (the Browse fallback for a remote browser): back/forward/up, a clickable breadcrumb that becomes a path field (Ctrl+L), Places (Home, the user's workspaces, recent picks), a filter, Name/Modified columns, Show hidden and New folder. A click selects; a double-click or Enter opens a folder or picks a file; Backspace goes up; typing jumps to a name. - GET /api/lanes/browse: `hidden=1` (never the dot entries at the top of a non-admin's own folder), each entry's `mtime`, the answer's `home`. - POST /api/lanes/browse/mkdir: one plain folder name inside an existing folder; a non-admin only in their own folder, none in server mode without one; under S3 a member's folder is made as the member. - scope.ownFolder falls back to server.conf's USERS_ROOT under S3, so a settings file without AGENTHUB_USERS_ROOT no longer opens the host's home to every developer. - Passwords: any non-empty password is accepted (no 8-character minimum). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
59 lines
2.1 KiB
JavaScript
59 lines
2.1 KiB
JavaScript
/**
|
|
* @file scope-users-root.test.js
|
|
* @description A non-admin's own folder comes from `AGENTHUB_USERS_ROOT`, and
|
|
* under S3 from server.conf's `USERS_ROOT` when that variable is missing — a
|
|
* server with S3 installed but no variable in its settings file let every
|
|
* developer browse the host account's whole home.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
const { describe, it, before, after, afterEach } = require("node:test");
|
|
const assert = require("node:assert/strict");
|
|
const path = require("node:path");
|
|
const fs = require("node:fs");
|
|
const os = require("node:os");
|
|
|
|
const TMP = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "scope-users-root-")));
|
|
const CONF = path.join(TMP, "server.conf");
|
|
process.env.AGENTHUB_SERVER_CONF = CONF;
|
|
process.env.AGENTHUB_MODE = "server";
|
|
delete process.env.AGENTHUB_USERS_ROOT;
|
|
|
|
const scope = require("../lib/scope");
|
|
const linux = require("../lib/linux-accounts");
|
|
|
|
const dev = { user: { id: 2, username: "vinnt", role: "developer" } };
|
|
const admin = { user: { id: 1, username: "boss", role: "admin" } };
|
|
|
|
describe("scope.ownFolder", () => {
|
|
before(() => {
|
|
fs.writeFileSync(CONF, "HOST_USER=host\nHOST_UID=1000\nUSERS_ROOT=/srv/agenthub/users\n");
|
|
linux.__resetConfCache();
|
|
});
|
|
afterEach(() => {
|
|
delete process.env.AGENTHUB_USERS_ROOT;
|
|
});
|
|
after(() => fs.rmSync(TMP, { recursive: true, force: true }));
|
|
|
|
it("falls back to server.conf's USERS_ROOT under S3", () => {
|
|
assert.equal(scope.ownFolder(dev), "/srv/agenthub/users/vinnt");
|
|
assert.equal(scope.folderAllowed(dev, os.homedir()), false);
|
|
assert.equal(scope.folderAllowed(dev, "/srv/agenthub/users/vinnt/proj"), true);
|
|
});
|
|
|
|
it("prefers AGENTHUB_USERS_ROOT when it is set", () => {
|
|
process.env.AGENTHUB_USERS_ROOT = "/data/users";
|
|
assert.equal(scope.ownFolder(dev), "/data/users/vinnt");
|
|
});
|
|
|
|
it("never limits an admin", () => {
|
|
assert.equal(scope.ownFolder(admin), null);
|
|
});
|
|
|
|
it("has no folder without S3 or the variable", () => {
|
|
fs.rmSync(CONF);
|
|
linux.__resetConfCache();
|
|
assert.equal(scope.ownFolder(dev), null);
|
|
});
|
|
});
|