Files
Ekklesia/packages/module-pack/tests/cli.test.ts
ekklesiaandClaude Opus 5.5 85fae9e07e
CI / verify (pull_request) Successful in 58s
CI / infrastructure-smoke (pull_request) Successful in 35s
CI / migration-smoke (pull_request) Successful in 1m53s
CI / image-build (pull_request) Successful in 30s
CI / deploy-smoke (same-origin) (pull_request) Successful in 50s
CI / deploy-smoke (split) (pull_request) Successful in 1m32s
feat: Module Package v1 carries the module's own license (ADR 0051)
Every Module Package v1 now declares the module's license and carries its
text. packageFormat stays 1; pre-ADR-0051 metadata fails closed.

- Contracts: ekklesia.package.json requires an SPDX `license` expression,
  validated with spdx-expression-parse, with UNLICENSED and non-expressions
  refused. The `files` list must hold exactly one non-empty root LICENSE.
  The package contracts move to the @ekklesia/contracts/module-package
  subpath, so the SPDX parser and its data (spdx-exceptions and
  spdx-license-ids ship no licence files) never reach a module bundle
  through the SDK's re-export of the contracts root.
- Packager: reads the source package.json's string SPDX declaration and
  never invents one. It requires an explicit --license-file (a non-empty
  regular file, no symlink, no parent search, no download) and copies its
  bytes unchanged to LICENSE, listed with size and SHA-256 and covered by
  the archive digest. THIRD_PARTY_NOTICES stays third-party only, and
  bundled Ekklesia code stays in `incorporates`.
- Verifier: rejects missing or invalid license metadata, and a missing,
  unlisted, duplicated, or corrupted LICENSE, through the schema and the
  existing strict inventory.
- Template: packaged as AGPL-3.0-or-later with the repository's canonical
  LICENSE, passed explicitly (Dockerfile, smoke, docs). Packing it twice
  gives byte-identical archives.

Started by Codex; reviewed and completed in Claude Code (empty license-text
refusal, schema non-empty LICENSE, symlink and empty-file tests).

ADR 0051 is Accepted.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 18:51:03 -05:00

84 lines
2.1 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { parsePackModuleArguments } from "../src/cli.js";
const revision = "86ae907f59458508e3277666cdd214f5bd7c1078";
describe("ekklesia-pack-module arguments", () => {
it("takes the module, the target, the output directory, and the source revision", () => {
expect(
parsePackModuleArguments([
"--module",
"templates/module",
"--target",
"any",
"--out",
"dist/packages",
"--license-file",
"LICENSE",
"--source-revision",
revision,
]),
).toEqual({
moduleDirectory: "templates/module",
licenseFile: "LICENSE",
outDirectory: "dist/packages",
sourceRevision: revision,
target: "any",
});
});
it("records a repository only when one is given", () => {
expect(
parsePackModuleArguments([
"--module",
".",
"--target",
"any",
"--out",
"out",
"--license-file",
"LICENSE",
"--source-revision",
revision,
"--repository",
"https://example.org/acme/example.git",
]).repository,
).toBe("https://example.org/acme/example.git");
});
it.each([
["no arguments", []],
["a missing target", ["--module", ".", "--out", "o", "--source-revision", revision]],
[
"a missing license file",
["--module", ".", "--target", "any", "--out", "o", "--source-revision", revision],
],
["a missing revision", ["--module", ".", "--target", "any", "--out", "o"]],
[
"an unknown option",
["--module", ".", "--target", "any", "--out", "o", "--source-revision", revision, "--legacy"],
],
[
"a repeated option",
[
"--module",
".",
"--module",
"..",
"--target",
"any",
"--out",
"o",
"--source-revision",
revision,
],
],
[
"a stray positional argument",
["module", "--target", "any", "--out", "o", "--source-revision", revision],
],
])("refuses %s", (_label, argv) => {
expect(() => parsePackModuleArguments(argv)).toThrow();
});
});