mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-23 00:53:38 +02:00
Reconcile Pi prerequisites with the integrated runtime while holding admission
This commit is contained in:
1 parent
20ce062701
commit
f620e7157b
313 files changed
+13086
-2187
No files matched your search
@@ -38,6 +38,33 @@ test('only the scripts-disabled dependency download gets network access', () =>
|
||||
assert.ok(values(args, '--env').includes('npm_config_ignore_scripts=true'));
|
||||
});
|
||||
|
||||
test('Pi assembly gets bounded scratch capacity while preserving sandbox restrictions', () => {
|
||||
const args = grokConsumerDockerArgs({ ...paths, download: true, temporarySizeMiB: 2048, command: ['node', '/consumer/node_modules/paperclipai/dist/index.js', 'runtime', 'setup', 'pi'] });
|
||||
assert.deepEqual(values(args, '--tmpfs'), ['/tmp:rw,nosuid,nodev,noexec,size=2048m,mode=1777']);
|
||||
assert.deepEqual(values(args, '--memory'), ['3g']);
|
||||
assert.ok(args.includes('--read-only'));
|
||||
assert.deepEqual(values(args, '--cap-drop'), ['ALL']);
|
||||
assert.deepEqual(values(args, '--security-opt'), ['no-new-privileges']);
|
||||
for (const temporarySizeMiB of [0, 255, 2049, Infinity, '2048']) {
|
||||
assert.throws(() => grokConsumerDockerArgs({ ...paths, temporarySizeMiB, command: ['node'] }), /bounded/);
|
||||
}
|
||||
});
|
||||
|
||||
test('only an offline runtime probe can execute its verified scratch snapshot', () => {
|
||||
const command = ['node', '/packages/pi-public-install-probe.mjs', '/consumer/node_modules/@paperclipai/server'];
|
||||
const args = grokConsumerDockerArgs({ ...paths, command, temporarySizeMiB: 2048, temporaryExecutable: true });
|
||||
assert.deepEqual(values(args, '--tmpfs'), ['/tmp:rw,nosuid,nodev,exec,size=2048m,mode=1777']);
|
||||
assert.deepEqual(values(args, '--network'), ['none']);
|
||||
assert.deepEqual(values(args, '--user'), ['1001:1001']);
|
||||
assert.ok(args.includes('--read-only'));
|
||||
assert.deepEqual(values(args, '--cap-drop'), ['ALL']);
|
||||
assert.deepEqual(values(args, '--security-opt'), ['no-new-privileges']);
|
||||
assert.throws(() => grokConsumerDockerArgs({ ...paths, command, download: true, temporaryExecutable: true }), /offline/);
|
||||
assert.throws(() => grokConsumerDockerArgs({ ...paths, command, temporaryExecutable: 'true' }), /offline/);
|
||||
const source = readFileSync(new URL('../verify-grok-npm-install.mjs', import.meta.url), 'utf8');
|
||||
assert.ok(source.includes("temporarySizeMiB: 2048, temporaryExecutable: true"));
|
||||
});
|
||||
|
||||
test('the separately provisioned executable is exposed read-only to the offline probe', () => {
|
||||
const prerequisite = '/private/staging/native/grok';
|
||||
const args = grokConsumerDockerArgs({ ...paths, prerequisite, command: ['node', '/packages/probe.mjs', 'present'] });
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import test from 'node:test';
|
||||
import { retainRunnerQualificationPackages } from '../retain-runner-qualification-packages.mjs';
|
||||
|
||||
test('retention preserves public archives and runs the normal plugin prepack without modifying source', () => {
|
||||
const root = mkdtempSync(join(tmpdir(), 'qualification-retention-test-'));
|
||||
const sourceRevision = '1'.repeat(40), releaseVersion = '0.0.0-qualification.test';
|
||||
const put = (relative, content) => {
|
||||
const file = join(root, relative); mkdirSync(join(file, '..'), { recursive: true });
|
||||
writeFileSync(file, content); return file;
|
||||
};
|
||||
const json = (relative, value) => put(relative, JSON.stringify(value));
|
||||
try {
|
||||
json('server/dist/build-info.json', { commit: sourceRevision });
|
||||
const originalPlugin = JSON.parse(readFileSync(new URL('../../packages/plugins/sandbox-providers/daytona/package.json', import.meta.url)));
|
||||
const pluginManifest = json('packages/plugins/sandbox-providers/daytona/package.json', originalPlugin);
|
||||
put('packages/plugins/sandbox-providers/daytona/dist/index.js', 'export const retained = true;\n');
|
||||
json('packages/plugins/sdk/package.json', { name: '@paperclipai/plugin-sdk', version: '0.3.1' });
|
||||
put('scripts/generate-plugin-package-json.mjs', readFileSync(new URL('../generate-plugin-package-json.mjs', import.meta.url)));
|
||||
json('packages/paperclip-runner/package.json', { name: '@paperclipai/paperclip-runner', version: '0.0.0', private: true, files: ['dist'] });
|
||||
put('packages/paperclip-runner/dist/cli/eval-session.js', 'export const evaluation = true;\n');
|
||||
const publicArchives = ['@paperclipai/server', 'paperclipai', '@paperclipai/plugin-sdk'].map((name, i) => ({ name, file: put(`public-${i}.tgz`, `unchanged archive ${name}`) }));
|
||||
const output = join(root, 'retained');
|
||||
const result = retainRunnerQualificationPackages({ repo: root, output, sourceRevision, releaseVersion, publicArchives });
|
||||
assert.equal(result.archives.length, 5);
|
||||
for (const archive of result.archives) assert.equal(createHash('sha256').update(readFileSync(join(output, archive.file))).digest('hex'), archive.sha256);
|
||||
for (const archive of publicArchives) assert.deepEqual(readFileSync(join(output, archive.file.split('/').at(-1))), readFileSync(archive.file));
|
||||
const plugin = result.archives.find(a => a.name === '@paperclipai/plugin-daytona');
|
||||
const packedManifest = JSON.parse(execFileSync('tar', ['-xOf', join(output, plugin.file), 'package/package.json']));
|
||||
assert.equal(packedManifest.dependencies['@paperclipai/plugin-sdk'], releaseVersion);
|
||||
assert.equal(packedManifest.exports['.'].import, './dist/index.js');
|
||||
assert.equal(execFileSync('tar', ['-xOf', join(output, plugin.file), 'package/dist/index.js'], { encoding: 'utf8' }), 'export const retained = true;\n');
|
||||
assert.deepEqual(JSON.parse(readFileSync(pluginManifest)), originalPlugin);
|
||||
assert.equal(existsSync(join(root, 'packages/plugins/sandbox-providers/daytona/package.dev.json')), false);
|
||||
assert.throws(() => retainRunnerQualificationPackages({ repo: root, output, sourceRevision, releaseVersion, publicArchives }), /Never replace/);
|
||||
assert.throws(() => retainRunnerQualificationPackages({ repo: root, output: join(root, 'wrong-source'), sourceRevision: '2'.repeat(40), releaseVersion, publicArchives }));
|
||||
assert.equal(existsSync(join(root, 'wrong-source')), false);
|
||||
} finally { rmSync(root, { recursive: true, force: true }); }
|
||||
});
|
||||
Reference in new issue
Block a user