Skip to content
Closed
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ follows [Semantic Versioning](https://semver.org).
Run `dune migrate:config` (core) to rewrite `config/system.yaml`. A config that
still carries an old key is refused by core at load time, so this cannot be
silently ignored. Requires `@dune/core` 0.36 or newer.
- **The workflow, scheduler, staging, machine-translation and audit engines come
from core's `services.engines`**, and admin tuples are seeded through
`services.authz.seedAdminTuples()` instead of importing `bootstrapAdminTuples`.
Core builds them once per site under `admin.runtime_dir`; the admin no longer
calls their factories. Requires `@dune/core` 0.36 or newer.
- **Security policy, sessions, users and passwords come from core's `services`**
(`MountApi.services`, `@dune/core/plugin-api`) instead of imports from
`@dune/core`: HTML sanitising, SSRF-guarded fetch, body limits, client IP, the
Expand Down
47 changes: 6 additions & 41 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,13 @@ import { createSessionManager } from "./src/admin/auth/sessions.ts";
import { createAuthMiddleware } from "./src/admin/auth/middleware.ts";
import { LocalAuthProvider } from "./src/admin/auth/local-provider.ts";
import type { AuthProvider } from "./src/admin/auth/provider.ts";
import { createWorkflowEngine } from "@dune/core/workflow";
import { createScheduler } from "@dune/core/workflow";
import type { ScheduledAction } from "@dune/core/workflow";
import { applyWorkflowTransition, SCHEDULED_ACTION_STATUS } from "./src/admin/workflow-actions.ts";
import { resolveDataDir } from "@dune/core/forms";
import { createStagingEngine } from "@dune/core/staging";
import { createCommentManager } from "./src/admin/comments.ts";
import { createCollabManager } from "./src/collab/mod.ts";
import { createMachineTranslator } from "@dune/core/mt";
import type { MachineTranslator } from "@dune/core/mt";
import { AuditLogger } from "@dune/core/audit";
import { bootstrapAdminTuples } from "@dune/core/auth/authz";
import type { AuditLogger } from "@dune/core/audit";
import type { DuneAuthSystem } from "@dune/core/auth/authz";
import type { AuthzLocalAdapter } from "@dune/core/auth/authz-adapter-local";
import type { AuthzDbAdapter } from "@dune/core/auth/authz-adapter-db";
Expand Down Expand Up @@ -120,7 +115,7 @@ export function createAdminPlugin(
mountDuneAdminEarly(app as any, bootstrap, () => liveAdminContext);
},

async setup(_api) {
async setup(api) {
const adminCfg = config.admin ?? {
path: "/admin",
session_lifetime: 86400,
Expand All @@ -132,31 +127,8 @@ export function createAdminPlugin(
return;
}

// Audit logger — created in setup() so it can init() its file handle early.
let auditLogger: AuditLogger | null = null;
if (adminCfg.audit?.enabled !== false) {
const configuredPath = adminCfg.audit?.log_file;
const runtimeDir = adminCfg.runtime_dir ?? ".dune/admin";
const auditLogFile = configuredPath
? join(opts.root, configuredPath)
: join(opts.root, runtimeDir, "audit.log");
const containmentRoot = opts.root.endsWith("/") || opts.root.endsWith("\\")
? opts.root
: opts.root + "/";
if (!auditLogFile.startsWith(containmentRoot)) {
throw new Error(
`[dune] admin.audit.log_file must resolve under the site root. ` +
`Got: ${configuredPath} -> ${auditLogFile}`,
);
}
auditLogger = new AuditLogger({ logFile: auditLogFile });
await auditLogger.init();
}

// Machine translation provider.
const mt: MachineTranslator | null = config.site.machine_translation
? createMachineTranslator(config.site.machine_translation)
: null;
// Audit trail and machine translator are built by core.
const { audit: auditLogger, mt } = api.services.engines;

setupState = { config, storage, opts, auditLogger, mt };
},
Expand Down Expand Up @@ -236,12 +208,7 @@ export function createAdminPlugin(
security: services.security,
});

const workflow = createWorkflowEngine(
{ storage, dataDir: runtimeDir },
config.site.workflow ?? undefined,
);

const scheduler = createScheduler({ storage, dataDir: runtimeDir });
const { workflow, scheduler, staging: stagingEngine } = services.engines;

// scheduler on its own only supports CRUD (schedule/cancel/list) — it
// never executes anything by itself. Whichever long-running process
Expand Down Expand Up @@ -269,8 +236,6 @@ export function createAdminPlugin(
}
};

const stagingEngine = createStagingEngine({ storage, runtimeDir });

const commentManager = createCommentManager({ dataDir, runtimeDir });

const collabManager = createCollabManager({
Expand Down Expand Up @@ -397,7 +362,7 @@ export function createAdminPlugin(
.filter((u) => u.enabled !== false)
.map((u) => ({ id: u.id, role: highestValidRole(u.roles) }))
.filter((u) => u.role !== undefined) as { id: string; role: string }[];
await bootstrapAdminTuples(bootstrap.authz, bootstrap.authzAdapter, enabledAdminUsers);
await services.authz.seedAdminTuples(enabledAdminUsers);
} catch (err) {
console.warn(
"[dune/authz] Admin tuple bootstrap failed — authz is up but tuples were not seeded; admin access will deny (403) until bootstrap succeeds:",
Expand Down
Loading