Add MFE sidecar manifest validation and pin-file catalog
What does this MR do and why?
Pure file-parsing layer for MFE delivery, no runtime behavior:
Gitlab::Mfe::Manifest— strict validation of thegitlab-mfe-manifest.jsonsidecar (JSON schema: per-file SHA-256 digest map, declared capabilities, Module Federation runtime version). The sidecar is published next to each MFE's build artifacts and is what the bake task verifies against.Gitlab::Mfe::Catalog— loader for the committedconfig/mfe.ymlpin file with lockfile semantics (exact name, project, version, sidecar digest per app).
The pin file ships empty (apps: []), so this is inert until an app is pinned.
The sidecar format (gitlab-mfe-manifest.json)
Every published MFE version ships two manifests. The standard mf-manifest.json is emitted by the rspack ModuleFederationPlugin and consumed exclusively by the Module Federation runtime — its schema belongs to the bundler ecosystem, changes with toolchain versions, and carries no integrity information; we never modify or interpret it. The sidecar is a separate, GitLab-owned file published next to it, carrying exactly what the toolchain manifest cannot:
interface GitlabMfeManifest {
/** Sidecar schema version — owned by GitLab, currently always 1 */
schemaVersion: 1;
/** Application name; must match the registry package name (`^[a-z0-9_]+$`) */
name: string;
/** Published version; must match the registry package version */
version: string;
/** `@module-federation` runtime the remote was built with — compatibility input for the host */
mfRuntime?: string;
/** Host capabilities the application requires — explicit and auditable instead of ambient */
requires?: string[];
/**
* Every shipped file: dist-relative POSIX path → digest.
* Must include `mf-manifest.json`. Paths must be relative,
* without `..` segments or backslashes.
*/
files: Record<string, { sha256: string }>;
}Two properties follow from the files map:
- One digest pins the whole tree. The release pin (
config/mfe.yml, next MRs in the stack) records a single SHA-256 — the sidecar's own. Since the sidecar lists a digest for every file, that one hash committed to git transitively vouches for every byte the application ships: publish-time content and serve-time content are provably identical. mf-manifest.jsonmust be listed. A sidecar that omits the standard MF manifest fails validation outright — an application that cannot fully describe itself cannot be delivered.
Prior art: Zephyr Cloud (a deployment platform from the Module Federation ecosystem) hashes every asset in its deploy metadata for the same reasons — verifiable integrity, immutable versioned deploys with instant rollback, and content-addressed storage (only changed files need re-uploading, an optimization the per-file digests keep open for us). Their format is coupled to their platform's deploy model, hence a minimal schema under our own control.
Note: shared tooling that generates, validates, and publishes this manifest from application repos is tracked separately in #605803 (closed) — for now each app repo carries its own script.
How to verify
bin/rspec spec/lib/gitlab/mfe/manifest_spec.rb spec/lib/gitlab/mfe/catalog_spec.rbmanifest_spec.rb runs on fast_spec_helper (no Rails boot); catalog_spec.rb needs Rails (Rails.root, ActiveSupport) and uses spec_helper.
The sidecar manifest in detail
Every published MFE version ships a gitlab-mfe-manifest.json next to the standard Module Federation manifest — never instead of it. The standard mf-manifest.json belongs to the bundler toolchain (its schema changes with toolchain versions, the federation runtime consumes it, and it carries no integrity data), so we treat it as an opaque asset. The sidecar carries what it cannot:
{
"schemaVersion": 1,
"name": "duo_chat",
"version": "0.2.0",
"mfRuntime": "^2.3.0",
"requires": [],
"files": {
"mf-manifest.json": { "sha256": "…" },
"remoteEntry.js": { "sha256": "…" },
"…every dist file…": { "sha256": "…" }
}
}files— a SHA-256 digest of every dist-relative file the app ships. The bake task (next MR in the stack) verifies every digest before writing a single byte. Because the release pin records the digest of the sidecar itself, one hash committed to git transitively vouches for the whole file tree.mfRuntime— the Module Federation runtime line the remote was built with, so host/remote runtime compatibility is validated before activation rather than discovered in production.requires— declared host capabilities (feature detection instead of ambient access); empty for now, validated at bake/activation as the platform grows.schemaVersion— the schema is ours and evolves deliberately, decoupled from bundler upgrades.
Validation is strict (JSON schema): unknown or missing fields are rejected, and a sidecar that does not list mf-manifest.json in its digest map is a hard error — an application that cannot fully describe itself cannot be delivered. The sidecar is not listed in its own files map; its integrity is covered by the pin.
Prior art: Zephyr Cloud (a deployment platform from the Module Federation ecosystem) uses the same per-asset hashing technique in its deploy metadata, for the same goals — verifiable integrity, immutable versioned deploys with instant rollback, and content-addressed storage. We define our own minimal schema instead of adopting theirs because their format is coupled to their deploy/edge model.
Stack
This is part of a stacked series extracted from a single 1700+ line MR for reviewability. Each part is independently verifiable and leaves master inert: nothing is user-reachable until an application is pinned.
| # | Scope | MR |
|---|---|---|
| 1 | Config plumbing + instance kill switch | !245043 (closed) |
| 2 | Sidecar manifest validation + pin-file catalog | !245044 (closed) |
| 3 | Verified bake task + baked manifest | !245045 (closed) |
| 4 | Same-origin delivery endpoint | !245046 (closed) |
| 5 | Dev-mode proxy for local development | !245301 (closed) |
Merging bottom-up; when a part merges, GitLab retargets the next one to master automatically.
A separate demonstration MR shows the whole stack working end to end with the real Duo Chat MFE (production bake + dev-mode HMR): !245014.
Related
- Phase 1 issue: #605798
- Epic: gitlab-org#22777
Related to #605798.