mirror of
https://github.com/affaan-m/ECC.git
synced 2026-08-17 21:15:40 +02:00
Make Antigravity 2.0 installs native and safely migrate legacy state. Ensure doctor, repair, status projection, repeat installs, legacy Codex sync, and uninstall converge without losing user files. Exclude Python bytecode and harden repo-scan bootstrap guidance. Gate publishing and pull-request merges on one exact packed artifact completing install, repeat, drift, repair, status, and uninstall across Linux, macOS, and Windows. Co-authored-by: lorencifernando-coder <lorenci.fernando@gmail.com> Co-authored-by: Suliman Abdulrazzaq <suliman9000a@gmail.com> Co-authored-by: Wu Shuwen <mikewushuwen@outlook.com>
131 lines
4.3 KiB
JavaScript
131 lines
4.3 KiB
JavaScript
'use strict';
|
|
|
|
const assert = require('assert');
|
|
const crypto = require('crypto');
|
|
const fs = require('fs');
|
|
const os = require('os');
|
|
const path = require('path');
|
|
|
|
const lifecycle = require('./packed-artifact-lifecycle');
|
|
|
|
let passed = 0;
|
|
let failed = 0;
|
|
|
|
function test(name, fn) {
|
|
try {
|
|
fn();
|
|
console.log(` ✓ ${name}`);
|
|
passed += 1;
|
|
} catch (error) {
|
|
console.log(` ✗ ${name}`);
|
|
console.log(` Error: ${error.message}`);
|
|
failed += 1;
|
|
}
|
|
}
|
|
|
|
console.log('\n=== Testing packed-artifact lifecycle runner ===\n');
|
|
|
|
test('resolves package and hash from explicit environment variables', () => {
|
|
const options = lifecycle.parseEnvironment({
|
|
ECC_RELEASE_PACKAGE: 'release-artifacts/ecc-universal-2.2.0.tgz',
|
|
ECC_RELEASE_SHA256: 'a'.repeat(64),
|
|
}, '/workspace');
|
|
|
|
assert.strictEqual(
|
|
options.packagePath,
|
|
path.resolve('/workspace', 'release-artifacts/ecc-universal-2.2.0.tgz')
|
|
);
|
|
assert.strictEqual(options.expectedSha256, 'a'.repeat(64));
|
|
});
|
|
|
|
test('rejects missing, malformed, and non-tgz release inputs', () => {
|
|
assert.throws(() => lifecycle.parseEnvironment({}, '/workspace'), /ECC_RELEASE_PACKAGE/);
|
|
assert.throws(() => lifecycle.parseEnvironment({
|
|
ECC_RELEASE_PACKAGE: 'package.zip',
|
|
ECC_RELEASE_SHA256: 'a'.repeat(64),
|
|
}, '/workspace'), /\.tgz/);
|
|
assert.throws(() => lifecycle.parseEnvironment({
|
|
ECC_RELEASE_PACKAGE: 'release-artifacts/ecc-universal-2.2.0.tgz',
|
|
ECC_RELEASE_SHA256: 'not-a-hash',
|
|
}, '/workspace'), /SHA-256/);
|
|
assert.throws(() => lifecycle.parseEnvironment({
|
|
ECC_RELEASE_PACKAGE: '../release-artifacts/ecc-universal-2.2.0.tgz',
|
|
ECC_RELEASE_SHA256: 'a'.repeat(64),
|
|
}, '/workspace'), /release-artifacts/);
|
|
assert.throws(() => lifecycle.parseEnvironment({
|
|
ECC_RELEASE_PACKAGE: '/tmp/ecc-universal-2.2.0.tgz',
|
|
ECC_RELEASE_SHA256: 'a'.repeat(64),
|
|
}, '/workspace'), /release-artifacts/);
|
|
});
|
|
|
|
test('hashFile computes a lowercase SHA-256 digest', () => {
|
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-packed-hash-'));
|
|
const filePath = path.join(tempDir, 'package.tgz');
|
|
|
|
try {
|
|
fs.writeFileSync(filePath, 'exact packed bytes');
|
|
const expected = crypto.createHash('sha256').update('exact packed bytes').digest('hex');
|
|
assert.strictEqual(lifecycle.hashFile(filePath), expected);
|
|
} finally {
|
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test('assertHash rejects an artifact whose bytes do not match', () => {
|
|
assert.throws(
|
|
() => lifecycle.assertHash('a'.repeat(64), 'b'.repeat(64)),
|
|
/does not match/
|
|
);
|
|
});
|
|
|
|
test('lifecycle child processes receive no inherited credentials', () => {
|
|
const environment = lifecycle.createLifecycleEnvironment({
|
|
PATH: '/tools',
|
|
GITHUB_TOKEN: 'github-secret',
|
|
NODE_AUTH_TOKEN: 'npm-secret',
|
|
ACTIONS_RUNTIME_TOKEN: 'actions-secret',
|
|
AWS_SECRET_ACCESS_KEY: 'cloud-secret',
|
|
}, '/isolated-home');
|
|
|
|
assert.strictEqual(environment.PATH, '/tools');
|
|
assert.strictEqual(environment.HOME, '/isolated-home');
|
|
assert.strictEqual(environment.USERPROFILE, '/isolated-home');
|
|
assert.strictEqual(environment.GITHUB_TOKEN, undefined);
|
|
assert.strictEqual(environment.NODE_AUTH_TOKEN, undefined);
|
|
assert.strictEqual(environment.ACTIONS_RUNTIME_TOKEN, undefined);
|
|
assert.strictEqual(environment.AWS_SECRET_ACCESS_KEY, undefined);
|
|
});
|
|
|
|
test('public CLI invocations use npm exec instead of internal package paths', () => {
|
|
const invocation = lifecycle.getNpmExecInvocation(
|
|
['ecc-universal', 'setup', '--help'],
|
|
{ ComSpec: 'C:\\Windows\\System32\\cmd.exe' },
|
|
'win32'
|
|
);
|
|
|
|
assert.strictEqual(invocation.command, 'C:\\Windows\\System32\\cmd.exe');
|
|
assert.deepStrictEqual(invocation.args, [
|
|
'/d',
|
|
'/s',
|
|
'/c',
|
|
'npm exec --offline --yes=false -- ecc-universal setup --help',
|
|
]);
|
|
|
|
const unixInvocation = lifecycle.getNpmExecInvocation(
|
|
['ecc', 'doctor', '--target', 'cursor', '--json'],
|
|
{},
|
|
'linux'
|
|
);
|
|
assert.strictEqual(unixInvocation.command, 'npm');
|
|
assert.deepStrictEqual(
|
|
unixInvocation.args.slice(0, 4),
|
|
['exec', '--offline', '--yes=false', '--']
|
|
);
|
|
assert.strictEqual(unixInvocation.args[4], 'ecc');
|
|
assert.ok(!unixInvocation.args.some(argument => argument.includes('node_modules')));
|
|
});
|
|
|
|
console.log(`\nPassed: ${passed}`);
|
|
console.log(`Failed: ${failed}`);
|
|
process.exit(failed > 0 ? 1 : 0);
|