CI / verify (pull_request) Failing after 47s
CI / infrastructure-smoke (pull_request) Skipped
CI / migration-smoke (pull_request) Skipped
CI / image-build (pull_request) Skipped
CI / deploy-smoke (same-origin) (pull_request) Skipped
CI / deploy-smoke (split) (pull_request) Skipped
The production image now contains zero feature modules and is the same for every installation. Installed modules live in module storage that one Core resolver selects from EKKLESIA_MODULES_DIR: the checkout's modules/ when unset, an absolute path that must exist when set (/var/lib/ekklesia/modules in the image). A relative, blank, missing, or unreadable configured directory fails closed with a sanitized error that never contains the value. - Host configuration reads EKKLESIA_MODULES_DIR. The API, migration plan, apply and validate, module validation, module enablement, and Doctor all resolve it the same way; the test-only API override still takes precedence. - Doctor receives Core's migrations directory explicitly instead of deriving it from the modules directory's parent. - The migration runner retains and reports the applied history of a module that is not installed, and plans and applies Core's and present modules' migrations around it. Core's history and every installed module's history stay strict: a missing or changed applied migration, or a downgrade, still fails. No down migrations, no data deletion. - deploy/Dockerfile copies no module and installs nothing for the module template; .dockerignore excludes modules/ and the build refuses a context that contains it; the runtime has an empty root-owned /var/lib/ekklesia/modules and sets EKKLESIA_MODULES_DIR. - deploy/compose.yaml bind-mounts EKKLESIA_MODULES_HOST_DIR read-only into api and migrate, with create_host_path disabled. - scripts/check-image.sh proves the image holds no modules and that a populated modules/ directory leaves its runtime file system identical; CI runs it. - The split deploy smoke now uses the same generic image: it boots with no modules, installs a self-contained test module packaged from the template (test-only), migrates and restarts, removes it (Core runs, planning reports the retained history, data survives), and restores it with its data. Docs: deploy README (module storage, install/update/remove/restore, the runtime modules target), .env.example, API configuration, module development guide, testing, workflow, security, and the architecture overview. Co-Authored-By: Claude Opus 5.5 <[email protected]>
44 lines
1.6 KiB
TypeScript
44 lines
1.6 KiB
TypeScript
import { readFile } from "node:fs/promises";
|
|
import path from "node:path";
|
|
import type { HostEnvironment } from "../host/index.js";
|
|
import { discoverAllMigrations } from "../migrations/index.js";
|
|
import type { ModuleMigrationAggregate } from "../modules/index.js";
|
|
import { resolveCommandModulesDirectory } from "./modules-directory-environment.js";
|
|
|
|
interface PackageVersion {
|
|
readonly version?: unknown;
|
|
}
|
|
|
|
async function readPackageVersion(packagePath: string): Promise<string> {
|
|
const packageData = JSON.parse(await readFile(packagePath, "utf8")) as PackageVersion;
|
|
if (typeof packageData.version !== "string") {
|
|
throw new TypeError("A required workspace package does not declare a version.");
|
|
}
|
|
return packageData.version;
|
|
}
|
|
|
|
/**
|
|
* Core's migrations come from the platform (`<repositoryRoot>/core/drizzle`); installed modules'
|
|
* come from the configured modules directory, wherever it is (ADR 0048). Neither is ever derived
|
|
* from the other.
|
|
*/
|
|
export async function discoverRepositoryMigrations(
|
|
repositoryRoot = process.cwd(),
|
|
environment: HostEnvironment = process.env,
|
|
): Promise<ModuleMigrationAggregate> {
|
|
const modulesDirectory = resolveCommandModulesDirectory(environment, repositoryRoot);
|
|
const [platformVersion, moduleSdkVersion] = await Promise.all([
|
|
readPackageVersion(path.join(repositoryRoot, "package.json")),
|
|
readPackageVersion(path.join(repositoryRoot, "packages/module-sdk/package.json")),
|
|
]);
|
|
|
|
return discoverAllMigrations({
|
|
coreMigrationsDirectory: path.join(repositoryRoot, "core", "drizzle"),
|
|
moduleDiscovery: {
|
|
moduleSdkVersion,
|
|
...modulesDirectory,
|
|
platformVersion,
|
|
},
|
|
});
|
|
}
|