cli4ai 1.0.1 → 1.0.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cli4ai",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "The package manager for AI CLI tools - cli4ai.com",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,9 +16,8 @@ import {
16
16
  LOCAL_PACKAGES_DIR,
17
17
  loadConfig
18
18
  } from '../core/config.js';
19
- import { lockPackage, computeDirectoryIntegrity, type LockedPackage } from '../core/lockfile.js';
19
+ import { lockPackage, type LockedPackage } from '../core/lockfile.js';
20
20
  import { linkPackageDirect, isBinInPath, getPathInstructions } from '../core/link.js';
21
- import { getRegistryIntegrity, verifyPackageIntegrity } from '../core/registry.js';
22
21
 
23
22
  interface AddOptions {
24
23
  local?: boolean;
@@ -417,27 +416,6 @@ export async function addCommand(packages: string[], options: AddOptions): Promi
417
416
  await installNpmDependencies(result.path, plan.manifest.dependencies);
418
417
  }
419
418
 
420
- // SECURITY: Verify integrity against registry
421
- let integrity: string | undefined;
422
- try {
423
- const verification = await verifyPackageIntegrity(result.name, result.path);
424
- integrity = verification.actual;
425
-
426
- if (verification.expected) {
427
- if (verification.valid) {
428
- log(` integrity: ${integrity.slice(0, 20)}... ✓`);
429
- } else {
430
- log(` ⚠️ Integrity mismatch!`);
431
- log(` Expected: ${verification.expected.slice(0, 30)}...`);
432
- log(` Actual: ${verification.actual.slice(0, 30)}...`);
433
- }
434
- } else {
435
- log(` integrity: ${integrity.slice(0, 20)}...`);
436
- }
437
- } catch (err) {
438
- log(` warning: could not compute integrity hash`);
439
- }
440
-
441
419
  // Link to PATH for global installs
442
420
  if (options.global) {
443
421
  result.binPath = linkPackageDirect(plan.manifest, result.path);
@@ -449,8 +427,7 @@ export async function addCommand(packages: string[], options: AddOptions): Promi
449
427
  const lockedPkg: LockedPackage = {
450
428
  name: result.name,
451
429
  version: result.version,
452
- resolved: result.source === 'local' ? result.path : result.path,
453
- integrity
430
+ resolved: result.source === 'local' ? result.path : result.path
454
431
  };
455
432
  lockPackage(projectDir, lockedPkg);
456
433
  }
@@ -15,7 +15,6 @@ import { log } from '../lib/cli.js';
15
15
  import { findPackage } from './config.js';
16
16
  import { loadManifest, type Manifest } from './manifest.js';
17
17
  import { getSecret } from './secrets.js';
18
- import { checkPackageIntegrity } from './lockfile.js';
19
18
 
20
19
  /**
21
20
  * Expand ~ to home directory in paths
@@ -389,27 +388,6 @@ export async function executeTool(options: ExecuteToolOptions): Promise<ExecuteT
389
388
 
390
389
  const manifest = loadManifest(pkg.path);
391
390
 
392
- const integrityCheck = checkPackageIntegrity(invocationDir, options.packageName, pkg.path);
393
- if (!integrityCheck.valid) {
394
- log(`\n⚠️ SECURITY WARNING: Package integrity check failed for ${options.packageName}`);
395
- if (integrityCheck.error) log(` ${integrityCheck.error}`);
396
- if (integrityCheck.expected && integrityCheck.actual) {
397
- log(` Expected: ${integrityCheck.expected.slice(0, 30)}...`);
398
- log(` Actual: ${integrityCheck.actual.slice(0, 30)}...`);
399
- }
400
- log(`\n The package may have been tampered with or modified since installation.`);
401
- log(` To fix: reinstall with "cli4ai remove ${options.packageName} && cli4ai add ${options.packageName}"\n`);
402
-
403
- const shouldContinue = await confirm('Continue anyway? (NOT RECOMMENDED)');
404
- if (!shouldContinue) {
405
- throw new ExecuteToolError('INTEGRITY_ERROR', 'Package integrity verification failed', {
406
- package: options.packageName,
407
- hint: `Reinstall the package with: cli4ai remove ${options.packageName} && cli4ai add ${options.packageName}`
408
- });
409
- }
410
- log('');
411
- }
412
-
413
391
  await ensureRuntimeAvailable();
414
392
 
415
393
  await checkPeerDependencies(pkg.path);
@@ -3,14 +3,10 @@
3
3
  *
4
4
  * Tracks installed packages with exact versions and sources
5
5
  * for reproducible installations.
6
- *
7
- * SECURITY: Includes SRI (Subresource Integrity) hash verification
8
- * to detect tampered packages.
9
6
  */
10
7
 
11
- import { readFileSync, writeFileSync, renameSync, existsSync, readdirSync, statSync } from 'fs';
12
- import { resolve, join, relative } from 'path';
13
- import { createHash } from 'crypto';
8
+ import { readFileSync, writeFileSync, renameSync, existsSync } from 'fs';
9
+ import { resolve } from 'path';
14
10
 
15
11
  // ═══════════════════════════════════════════════════════════════════════════
16
12
  // TYPES
@@ -36,125 +32,6 @@ export interface Lockfile {
36
32
  export const LOCKFILE_NAME = 'cli4ai.lock';
37
33
  export const LOCKFILE_VERSION = 1;
38
34
 
39
- // ═══════════════════════════════════════════════════════════════════════════
40
- // INTEGRITY HASHING (SRI - Subresource Integrity)
41
- // ═══════════════════════════════════════════════════════════════════════════
42
-
43
- /**
44
- * Compute SHA-512 hash of a file and return SRI format string
45
- */
46
- export function computeFileIntegrity(filePath: string): string {
47
- const content = readFileSync(filePath);
48
- const hash = createHash('sha512').update(content).digest('base64');
49
- return `sha512-${hash}`;
50
- }
51
-
52
- /**
53
- * Compute SHA-512 hash of a directory's contents (deterministic).
54
- * Hashes all files in sorted order to produce a reproducible hash.
55
- */
56
- export function computeDirectoryIntegrity(dirPath: string): string {
57
- const hash = createHash('sha512');
58
- const files: string[] = [];
59
-
60
- // Recursively collect all files
61
- function collectFiles(dir: string): void {
62
- const entries = readdirSync(dir, { withFileTypes: true });
63
- for (const entry of entries) {
64
- // Skip node_modules and hidden directories
65
- if (entry.name === 'node_modules' || entry.name.startsWith('.')) continue;
66
-
67
- const fullPath = join(dir, entry.name);
68
- if (entry.isDirectory()) {
69
- collectFiles(fullPath);
70
- } else if (entry.isFile()) {
71
- files.push(fullPath);
72
- }
73
- }
74
- }
75
-
76
- collectFiles(dirPath);
77
-
78
- // Sort files for deterministic ordering
79
- files.sort();
80
-
81
- // Hash each file's relative path and content
82
- for (const filePath of files) {
83
- const relativePath = relative(dirPath, filePath);
84
- const content = readFileSync(filePath);
85
-
86
- // Include path in hash for structural integrity
87
- hash.update(relativePath);
88
- hash.update(content);
89
- }
90
-
91
- return `sha512-${hash.digest('base64')}`;
92
- }
93
-
94
- /**
95
- * Verify a package's integrity against stored hash
96
- */
97
- export function verifyIntegrity(dirPath: string, expectedIntegrity: string): boolean {
98
- if (!expectedIntegrity) return true; // No integrity check if not stored
99
-
100
- try {
101
- const actualIntegrity = computeDirectoryIntegrity(dirPath);
102
- return actualIntegrity === expectedIntegrity;
103
- } catch {
104
- return false;
105
- }
106
- }
107
-
108
- /**
109
- * Result of integrity verification
110
- */
111
- export interface IntegrityCheckResult {
112
- valid: boolean;
113
- expected?: string;
114
- actual?: string;
115
- error?: string;
116
- }
117
-
118
- /**
119
- * Check integrity of a locked package
120
- */
121
- export function checkPackageIntegrity(
122
- projectDir: string,
123
- packageName: string,
124
- packagePath: string
125
- ): IntegrityCheckResult {
126
- const locked = getLockedPackage(projectDir, packageName);
127
-
128
- if (!locked) {
129
- return { valid: true }; // No lock entry, can't verify
130
- }
131
-
132
- if (!locked.integrity) {
133
- return { valid: true }; // No integrity hash stored
134
- }
135
-
136
- try {
137
- const actualIntegrity = computeDirectoryIntegrity(packagePath);
138
-
139
- if (actualIntegrity === locked.integrity) {
140
- return { valid: true, expected: locked.integrity, actual: actualIntegrity };
141
- }
142
-
143
- return {
144
- valid: false,
145
- expected: locked.integrity,
146
- actual: actualIntegrity,
147
- error: 'Integrity mismatch - package may have been tampered with'
148
- };
149
- } catch (err) {
150
- return {
151
- valid: false,
152
- expected: locked.integrity,
153
- error: `Failed to compute integrity: ${err instanceof Error ? err.message : String(err)}`
154
- };
155
- }
156
- }
157
-
158
35
  // ═══════════════════════════════════════════════════════════════════════════
159
36
  // FUNCTIONS
160
37
  // ═══════════════════════════════════════════════════════════════════════════