@volter/twin-catalog 0.2.27 → 0.2.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/catalog.json +27 -2
- package/docs/contributing.md +29 -6
- package/docs/process.md +21 -2
- package/evidence/fa756dfc21662a70679a660dd88fcb2b4f8bad30f408f1134cd87b0668289fc6.json +3958 -0
- package/lib/browse.d.mts +13 -0
- package/lib/browse.mjs +10 -0
- package/lib/runner.mjs +6 -2
- package/package.json +3 -3
- package/policy.json +5 -4
- package/runner/Dockerfile +7 -2
- package/runner/evaluate.mjs +3 -2
- package/runner/prepare.mjs +13 -1
- package/vendors/clerk.json +20 -0
package/lib/browse.d.mts
CHANGED
|
@@ -7,6 +7,19 @@ export type Coverage = {
|
|
|
7
7
|
};
|
|
8
8
|
export type Replay = { equal: boolean; runs: number; firstSha256: string; secondSha256: string };
|
|
9
9
|
export type Measurements = {
|
|
10
|
+
consumer: null | {
|
|
11
|
+
measured: boolean;
|
|
12
|
+
passed: boolean;
|
|
13
|
+
scope: string | null;
|
|
14
|
+
fixture: string | null;
|
|
15
|
+
sdkDependencies: Record<string, string> | null;
|
|
16
|
+
tools: Record<string, string> | null;
|
|
17
|
+
clock: Record<string, unknown> | null;
|
|
18
|
+
retainedReadback: boolean | null;
|
|
19
|
+
retentionNotApplicable: string | null;
|
|
20
|
+
teardownVerified: boolean | null;
|
|
21
|
+
failures: string[] | null;
|
|
22
|
+
};
|
|
10
23
|
scope: string | null;
|
|
11
24
|
surface: { total: number; served: number; gap: number } | null;
|
|
12
25
|
operationCoverage: Coverage | null;
|
package/lib/browse.mjs
CHANGED
|
@@ -130,6 +130,16 @@ export function browse(root, { vendor, package: packageName, integrity = null }
|
|
|
130
130
|
operationCoverage: quick?.operationCoverage ?? null, servedOperations: quick?.servedOperations ?? null,
|
|
131
131
|
steps: quick?.steps ?? null, answered: quick?.answered ?? null, failures: quick?.failures ?? null,
|
|
132
132
|
replay: quick?.replay ?? null, conformance: bound.report.conformance ?? null,
|
|
133
|
+
consumer: bound.report.consumer ? {
|
|
134
|
+
measured: bound.report.consumer.measured === true, passed: bound.report.consumer.passed === true,
|
|
135
|
+
scope: bound.report.consumer.scope ?? null, fixture: bound.report.consumer.fixture ?? null,
|
|
136
|
+
sdkDependencies: bound.envelope.prepared?.consumerFixture?.dependencies ?? null,
|
|
137
|
+
tools: bound.report.consumer.tools ?? null, clock: bound.report.consumer.clock ?? null,
|
|
138
|
+
retainedReadback: bound.report.consumer.retainedReadback ?? null,
|
|
139
|
+
retentionNotApplicable: bound.report.consumer.retentionNotApplicable ?? null,
|
|
140
|
+
teardownVerified: bound.report.consumer.teardownVerified ?? null,
|
|
141
|
+
failures: bound.report.consumer.failures ?? null,
|
|
142
|
+
} : null,
|
|
133
143
|
browser: browser?.measured === true ? browser : null,
|
|
134
144
|
codeCoverage: quick?.codeCoverage ?? null, stateTransitionCoverage: quick?.stateTransitionCoverage ?? null,
|
|
135
145
|
domCoverage: browser?.domCoverage ?? null, comparison: bound.report.comparison ?? null } : null };
|
package/lib/runner.mjs
CHANGED
|
@@ -25,7 +25,8 @@ export function withContainer(root, input, output, execute, { spawn = spawnSync
|
|
|
25
25
|
let volume = false;
|
|
26
26
|
try {
|
|
27
27
|
const tools = input.policy.tools;
|
|
28
|
-
|
|
28
|
+
requireThat(tools['@volter/world'], 'policy must pin the product CLI for installed customer workflows');
|
|
29
|
+
run(['build', '--iidfile', imageFile, '--build-arg', `NODE_IMAGE=${input.policy.nodeImage}`, '--build-arg', `BUN_VERSION=${input.policy.bun}`, '--build-arg', `STANDARD_VERSION=${tools['@volter/twin-standard']}`, '--build-arg', `CORE_VERSION=${tools['@volter/world-core']}`, '--build-arg', `RUNTIME_VERSION=${tools['@volter/world-runtime']}`, '--build-arg', `CLI_VERSION=${tools['@volter/world']}`, '--build-arg', `PLAYWRIGHT_VERSION=${tools.playwright}`, '-f', join(root, 'runner/Dockerfile'), root]);
|
|
29
30
|
const image = readFileSync(imageFile, 'utf8').trim();
|
|
30
31
|
requireThat(/^sha256:[a-f0-9]{64}$/.test(image), 'container image has no immutable identity');
|
|
31
32
|
run(['volume', 'create', '--label', `twin-catalog.owner=${id}`, '--label', `twin-catalog.run=${runOwner}`, id]); volume = true;
|
|
@@ -56,12 +57,15 @@ export function evaluate(root, input, output, options = {}) {
|
|
|
56
57
|
const lock = run([...common, '--network', 'none', image, '-e', 'process.stdout.write(require("fs").readFileSync("/work/package-lock.json","utf8"))']).stdout;
|
|
57
58
|
requireThat(digest(lock) === prepared.dependencyLockSha256, 'dependency lock identity changed');
|
|
58
59
|
write(`${output}.lock.json`, JSON.parse(lock));
|
|
60
|
+
const consumerLock = run([...common, '--network', 'none', image, '-e', 'process.stdout.write(require("fs").readFileSync("/work/customer-app/package-lock.json","utf8"))']).stdout;
|
|
61
|
+
requireThat(digest(consumerLock) === prepared.consumerDependencyLockSha256, 'customer SDK lock identity changed');
|
|
62
|
+
write(`${output}.consumer-lock.json`, JSON.parse(consumerLock));
|
|
59
63
|
phase = 'offline-assessment';
|
|
60
64
|
const result = run([...common, '--network', 'none', '--entrypoint', 'bun', image, '/opt/catalog/node_modules/@volter/world-runtime/src/cli.ts', 'run', '/work/world.json', '--root', '/work', '--env-out', '/work/world.env', '--owner', owner, '--', 'bun', '/opt/catalog/runner/evaluate.mjs'], true);
|
|
61
65
|
const reportRead = run([...common, '--network', 'none', image, '-e', 'process.stdout.write(require("fs").readFileSync("/work/report.json","utf8"))'], true);
|
|
62
66
|
const report = reportRead.status === 0 ? JSON.parse(reportRead.stdout) : null;
|
|
63
67
|
requireThat(!report || (report.schemaVersion === 1 && report.package === input.submission.package && report.version === input.submission.version && report.integrity === input.submission.integrity), 'evaluator returned a mismatched report');
|
|
64
|
-
const envelope = { schemaVersion: 1, inputSha256: digest(input), input, image, prepared, dependencyLock: JSON.parse(lock), status: result.status === 0 && report?.ready === true ? 'ready' : 'changes-needed', report, evaluatedAt: new Date().toISOString() };
|
|
68
|
+
const envelope = { schemaVersion: 1, inputSha256: digest(input), input, image, prepared, dependencyLock: JSON.parse(lock), consumerDependencyLock: JSON.parse(consumerLock), status: result.status === 0 && report?.ready === true ? 'ready' : 'changes-needed', report, evaluatedAt: new Date().toISOString() };
|
|
65
69
|
write(output, envelope);
|
|
66
70
|
return envelope;
|
|
67
71
|
}, options);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/twin-catalog",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.29",
|
|
4
4
|
"description": "The moderated twin distribution: approved versions and submission tooling for independent publishers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"evidence"
|
|
39
39
|
],
|
|
40
40
|
"catalog": {
|
|
41
|
-
"sourceCommit": "
|
|
42
|
-
"digest": "
|
|
41
|
+
"sourceCommit": "251b4771b7e0f8f262041cc47f436d8b4f785537",
|
|
42
|
+
"digest": "3195c901d6068ef7be8e9e23676b9b6ec58fb4e50c2d5604bbea390fefec9fdb"
|
|
43
43
|
}
|
|
44
44
|
}
|
package/policy.json
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"registry": "https://registry.npmjs.org",
|
|
4
4
|
"tools": {
|
|
5
|
-
"@volter/world-core": "3.0.
|
|
6
|
-
"@volter/world-runtime": "3.0.
|
|
7
|
-
"@volter/twin-standard": "1.0.
|
|
8
|
-
"playwright": "1.63.0"
|
|
5
|
+
"@volter/world-core": "3.0.100",
|
|
6
|
+
"@volter/world-runtime": "3.0.100",
|
|
7
|
+
"@volter/twin-standard": "1.0.92",
|
|
8
|
+
"playwright": "1.63.0",
|
|
9
|
+
"@volter/world": "3.0.100"
|
|
9
10
|
},
|
|
10
11
|
"bun": "1.4.2",
|
|
11
12
|
"nodeImage": "node:24-bookworm-slim",
|
package/runner/Dockerfile
CHANGED
|
@@ -4,13 +4,18 @@ ARG BUN_VERSION=1.3.11
|
|
|
4
4
|
ARG STANDARD_VERSION=1.0.37
|
|
5
5
|
ARG CORE_VERSION=3.0.45
|
|
6
6
|
ARG RUNTIME_VERSION=3.0.45
|
|
7
|
+
ARG CLI_VERSION
|
|
7
8
|
ARG PLAYWRIGHT_VERSION=1.63.0
|
|
8
9
|
ENV PLAYWRIGHT_BROWSERS_PATH=/opt/playwright
|
|
9
|
-
|
|
10
|
+
# Install native PostgreSQL tools without a distribution-owned cluster; each World owns its own data and lifetime.
|
|
11
|
+
# https://manpages.debian.org/bookworm/postgresql-common/pg_createcluster.1.en.html#DEFAULT_VALUES
|
|
12
|
+
RUN mkdir -p /etc/postgresql-common && printf 'create_main_cluster = false\n' > /etc/postgresql-common/createcluster.conf \
|
|
13
|
+
&& apt-get update && apt-get install -y --no-install-recommends git openssl ca-certificates libfaketime postgresql-15 && rm -rf /var/lib/apt/lists/*
|
|
14
|
+
ENV VOLTER_WORLD_POSTGRES_BIN=/usr/lib/postgresql/15/bin
|
|
10
15
|
WORKDIR /opt/catalog
|
|
11
16
|
RUN npm install --ignore-scripts --no-audit --no-fund --save-exact \
|
|
12
17
|
@oven/bun-linux-x64@${BUN_VERSION} @volter/twin-standard@${STANDARD_VERSION} \
|
|
13
|
-
@volter/world-core@${CORE_VERSION} @volter/world-runtime@${RUNTIME_VERSION} tar@7.5.7 semver@7.8.5 sigstore@4.1.1 playwright@${PLAYWRIGHT_VERSION}
|
|
18
|
+
@volter/world-core@${CORE_VERSION} @volter/world-runtime@${RUNTIME_VERSION} @volter/world@${CLI_VERSION} tar@7.5.7 semver@7.8.5 sigstore@4.1.1 playwright@${PLAYWRIGHT_VERSION}
|
|
14
19
|
ENV PATH="/opt/catalog/node_modules/@oven/bun-linux-x64/bin:/opt/catalog/node_modules/.bin:${PATH}"
|
|
15
20
|
RUN ./node_modules/.bin/playwright install --with-deps chromium
|
|
16
21
|
COPY lib /opt/catalog/lib
|
package/runner/evaluate.mjs
CHANGED
|
@@ -7,9 +7,10 @@ requireThat(Boolean(process.env.VOLTER_WORLD), 'evaluation must run inside a Wor
|
|
|
7
7
|
const { submission: s } = read('/input/input.json');
|
|
8
8
|
const requireFromPack = createRequire('/work/package.json');
|
|
9
9
|
const { assessPack } = await import(requireFromPack.resolve('@volter/twin-standard'));
|
|
10
|
-
const
|
|
10
|
+
const prepared = read('/work/prepared.json');
|
|
11
|
+
const assessment = await assessPack(join('/work/packs', s.vendor), { browser: true, consumer: prepared.consumer });
|
|
11
12
|
requireThat(assessment.package === s.package && assessment.version === s.version && assessment.vendor === s.vendor, 'assessment returned a different artifact identity');
|
|
12
|
-
const report = { ...assessment, integrity: s.integrity, prepared
|
|
13
|
+
const report = { ...assessment, integrity: s.integrity, prepared };
|
|
13
14
|
report.comparison = compareReports(report, existsSync('/input/baseline.json') ? read('/input/baseline.json') : null);
|
|
14
15
|
write('/work/report.json', report);
|
|
15
16
|
process.exit(report.ready ? 0 : 1);
|
package/runner/prepare.mjs
CHANGED
|
@@ -81,6 +81,18 @@ const provenance = await verifiedProvenance(await response.json(), source, bytes
|
|
|
81
81
|
// Keep a vendor-named package directory for the standard's public directory API; preserve the installed artifact.
|
|
82
82
|
mkdirSync('/work/packs', { recursive: true });
|
|
83
83
|
cpSync(join('/work/node_modules', s.package), join('/work/packs', s.vendor), { recursive: true });
|
|
84
|
+
const { prepareConsumerApp } = await import(evaluatorRequire.resolve('@volter/twin-standard'));
|
|
85
|
+
const appDir = '/work/customer-app';
|
|
86
|
+
const consumerFixture = prepareConsumerApp(join('/work/packs', s.vendor), appDir);
|
|
87
|
+
const appInstall = spawnSync('npm', ['install', '--ignore-scripts', '--no-audit', '--no-fund', '--registry', policy.registry], { cwd: appDir, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 });
|
|
88
|
+
requireThat(appInstall.status === 0, `customer SDK preparation failed: ${appInstall.stderr}`);
|
|
89
|
+
const consumerLock = read(join(appDir, 'package-lock.json'));
|
|
90
|
+
for (const [path, entry] of Object.entries(consumerLock.packages ?? {})) {
|
|
91
|
+
if (!path) continue;
|
|
92
|
+
requireThat(!entry.link && entry.resolved && entry.integrity, `${path}: customer dependency is not a locked registry artifact`);
|
|
93
|
+
registryURL(entry.resolved, policy.registry);
|
|
94
|
+
}
|
|
95
|
+
const consumer = { appDir, cli: '/work/node_modules/.bin/volter', artifactIntegrity: s.integrity };
|
|
84
96
|
// Retain listing facts from these exact bytes, never the registry's moving latest metadata.
|
|
85
97
|
const packageMetadata = {
|
|
86
98
|
description: typeof pack.description === 'string' ? pack.description : null,
|
|
@@ -90,5 +102,5 @@ const packageMetadata = {
|
|
|
90
102
|
repositoryDirectory: typeof pack.repository === 'object' ? pack.repository.directory ?? null : null,
|
|
91
103
|
bugs: typeof pack.bugs === 'string' ? pack.bugs : pack.bugs?.url ?? null,
|
|
92
104
|
};
|
|
93
|
-
write('/work/prepared.json', { schemaVersion: 1, submission: s, integrity: s.integrity, provenance, packageMetadata, dependencyLockSha256: digest(readFileSync('/work/package-lock.json', 'utf8')), clientSdkLocks, clientDependencyChoices, tools: policy.tools });
|
|
105
|
+
write('/work/prepared.json', { schemaVersion: 1, submission: s, integrity: s.integrity, provenance, packageMetadata, dependencyLockSha256: digest(readFileSync('/work/package-lock.json', 'utf8')), clientSdkLocks, clientDependencyChoices, tools: policy.tools, consumer, consumerFixture, consumerDependencyLockSha256: digest(readFileSync(join(appDir, 'package-lock.json'), 'utf8')) });
|
|
94
106
|
write('/work/world.json', { id: 'catalog-assessment', network: { egress: [] }, services: [] });
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"vendor": "clerk",
|
|
3
|
+
"packages": [
|
|
4
|
+
{
|
|
5
|
+
"name": "@volter/twin-clerk",
|
|
6
|
+
"source": "twin-packs-open",
|
|
7
|
+
"versions": [
|
|
8
|
+
{
|
|
9
|
+
"version": "1.0.2",
|
|
10
|
+
"status": "live",
|
|
11
|
+
"integrity": "sha512-3HZEt5czGpF/wEWcoDk+1/2Ln6J4Tg00kqFbgWTJ6VP8th5myZ1c9x2QowBmFcSdmdp0U00HMMxD7VJ4ucSkxw==",
|
|
12
|
+
"submission": "fa756dfc21662a70679a660dd88fcb2b4f8bad30f408f1134cd87b0668289fc6",
|
|
13
|
+
"commit": "c7c9a81cfb79e7410ddf7b26a51c2359647cd1a8",
|
|
14
|
+
"at": "2026-10-07T01:03:20Z",
|
|
15
|
+
"by": "moderated-merge"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|