mirror of
https://github.com/Heretek-AI/GDevelop-Unlocked.git
synced 2026-11-07 10:55:58 -10:00
- Delete scripts/extract-tier2.mjs; remove fork clone from seam-tests CI. - Tier-2 tests self-contained: MANIFEST hash/size pins replace donor byte-identity; glue tests assert dry-run + anti-revert + additive (no regen-from-fork). - MANIFEST provenance rekeyed (donor->origin, historical note only); UPSTREAM_BASELINE drops the donor pin (upstream pin only). - Docs: ai-studio/README, RETIREMENT (independence done in-repo; archival stays owner-side), root README, AGENTS.md. - Local fork fixture (~2GB) deleted; suite 97/97 green without it.
93 lines
2.7 KiB
JavaScript
93 lines
2.7 KiB
JavaScript
// Tier-2 package tests: packages/ai-studio/ is self-contained and intact.
|
|
// Tamper-evidence comes from MANIFEST.json hashes pinned in THIS repo —
|
|
// no donor checkout, no fork clone, nothing outside this tree.
|
|
import { describe, it } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import crypto from 'node:crypto';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
const ROOT = path.resolve(here, '..', '..');
|
|
const PACKAGE = path.join(ROOT, 'packages', 'ai-studio');
|
|
|
|
function sha256(abs) {
|
|
return crypto.createHash('sha256').update(fs.readFileSync(abs)).digest('hex');
|
|
}
|
|
|
|
describe('tier-2: self-contained package integrity', () => {
|
|
const manifest = JSON.parse(
|
|
fs.readFileSync(path.join(PACKAGE, 'MANIFEST.json'), 'utf8')
|
|
);
|
|
|
|
it('every manifest file exists with pinned bytes and hash', () => {
|
|
assert.ok(
|
|
Object.keys(manifest.files).length >= 19,
|
|
'manifest looks truncated'
|
|
);
|
|
for (const [pkgRel, meta] of Object.entries(manifest.files)) {
|
|
const pkgAbs = path.join(PACKAGE, pkgRel);
|
|
assert.ok(fs.existsSync(pkgAbs), `package file missing: ${pkgRel}`);
|
|
assert.equal(
|
|
fs.statSync(pkgAbs).size,
|
|
meta.bytes,
|
|
`size drift (tamper?): ${pkgRel}`
|
|
);
|
|
assert.equal(
|
|
sha256(pkgAbs),
|
|
meta.sha256,
|
|
`hash drift (tamper?): ${pkgRel}`
|
|
);
|
|
}
|
|
});
|
|
|
|
it('CustomAIClient has zero hosted-generation references', () => {
|
|
const text = fs.readFileSync(
|
|
path.join(PACKAGE, 'AI', 'CustomAIClient.js'),
|
|
'utf8'
|
|
);
|
|
assert.ok(
|
|
!text.includes('api.gdevelop.io'),
|
|
'BYOK client must not hardcode the hosted API'
|
|
);
|
|
assert.ok(
|
|
text.includes('GDEVELOP_OPENAI_TOOLS'),
|
|
'tool schema missing from extraction'
|
|
);
|
|
assert.ok(
|
|
text.includes('gd-custom-ai-config'),
|
|
'localStorage config key missing from extraction'
|
|
);
|
|
});
|
|
|
|
it('all 12 Studio prod modules extracted (no silent drops)', () => {
|
|
const expected = [
|
|
'EditApprovalLabel',
|
|
'FinalizeSubAgents',
|
|
'LoopGuard',
|
|
'NudgePolicy',
|
|
'PlanStore',
|
|
'RequestWriteGate',
|
|
'Roles',
|
|
'RoleToolPolicy',
|
|
'SafeTruncation',
|
|
'SpawnSubAgents',
|
|
'UseStudioNudge',
|
|
'UseStudioRuntime',
|
|
];
|
|
for (const name of expected) {
|
|
assert.ok(
|
|
fs.existsSync(path.join(PACKAGE, 'AiGeneration', 'Studio', `${name}.js`)),
|
|
`Studio module missing: ${name}`
|
|
);
|
|
}
|
|
});
|
|
|
|
it('offline E2E harness extracted', () => {
|
|
assert.ok(
|
|
fs.existsSync(path.join(PACKAGE, 'dev-harness', 'mock-ai-provider.js'))
|
|
);
|
|
});
|
|
});
|