Files
ECC/scripts/lib/path-safety.js
T
754b8dd76c fix: make the installer runtime pass strict supply-chain vetting (#2503)
* fix: make the installer runtime pass strict supply-chain vetting

Remediate the four enterprise supply-chain vetting blockers from
affaan-m/ECC#2502 so the installer runtime (package.json + manifests +
scripts/lib/**) passes strict exact-pin evidence policy:

1. Remove the package.json `postinstall` lifecycle script (it only echoed a
   post-install banner) and move that banner to an explicit opt-in
   `npm run welcome` command. No install-time lifecycle script remains.
2. Exact-pin every dependency in package.json (dependencies + devDependencies)
   to the versions already resolved in package-lock.json; no ^/~ ranges.
3. Replace non-ASCII characters on the installer runtime script/config surface:
   em-dashes (U+2014) in scripts/lib/{path-safety,install-executor,
   install/link-rewrite}.js comments and the two "Itô" (U+00F4) occurrences in
   manifests/{install-components,install-modules}.json descriptions become
   ASCII, so strict-surface Unicode scanners are clean.
4. Drop the bare `require("ajv")` from scripts/lib/install-state.js; the file
   already carries a complete hand-rolled validator enforcing the same
   schemas/install-state.schema.json (ecc.install.v1) constraints, so the
   installer closure is dependency-free (zero non-builtin bare requires).

Refs affaan-m/ECC#2502

* fix: avoid unpinned welcome invocations

Signed-off-by: Samar Tomar <samar_tomar@hotmail.com>

* fix: validate translated skill frontmatter

Signed-off-by: Samar Tomar <samar_tomar@hotmail.com>

* fix: repair skill frontmatter YAML

Signed-off-by: Samar Tomar <samar_tomar@hotmail.com>

* fix: add MIT license to core skill manifests; pin verification-loop tsc invocation

* fix: preserve tsc/pyright exit status in verification-loop type-check (set -o pipefail)

* chore(deps): sync lockfiles with exact-pinned package.json

Regenerate package-lock.json and yarn.lock so the pinned dependency
specs are reflected in both lockfiles. npm ci and Yarn's --immutable
install now pass the sync check. The resolution tree is unchanged
(231 yarn resolutions, byte-identical set; zero npm transitive drift);
only the root descriptor strings move from ranges to the versions
already resolved in the committed lockfiles.

Addresses the Codex P1 on #2503.

---------

Signed-off-by: Samar Tomar <samar_tomar@hotmail.com>
Co-authored-by: Samarjeet Singh Tomar <samartomar@gmail.com>
2026-07-17 17:13:49 -04:00

83 lines
2.4 KiB
JavaScript

'use strict';
const fs = require('fs');
const path = require('path');
/**
* Path containment helpers for install-state-driven file operations.
*
* Install-state files are project-local and therefore attacker-controllable
* (a cloned/forked repo can ship a crafted `.cursor/ecc-install-state.json`).
* `repair`/`uninstall`/`auto-update` replay recorded operations, so every
* write/delete destination MUST be confined to the adapter-derived trusted
* root - never trusted from the state file itself (GHSA-hfpv-w6mp-5g95).
*/
function safeRealpath(target) {
try {
return fs.realpathSync(path.resolve(target));
} catch {
return path.resolve(target);
}
}
/**
* Canonicalize a path that may not exist yet: realpath its nearest existing
* ancestor, then re-append the missing tail. This defeats symlink escapes
* where an intermediate directory is a symlink pointing out of the root.
*/
function realpathNearestExisting(target) {
let current = path.resolve(target);
const tail = [];
while (!fs.existsSync(current)) {
const parent = path.dirname(current);
if (parent === current) {
break;
}
tail.unshift(path.basename(current));
current = parent;
}
const real = safeRealpath(current);
return tail.length > 0 ? path.join(real, ...tail) : real;
}
/**
* True when `target` resolves to `root` itself or a path beneath it, with
* symlinks resolved on both sides.
*/
function isWithinRoot(target, root) {
if (!root) {
return false;
}
const realRoot = safeRealpath(root);
const realTarget = realpathNearestExisting(target);
if (realTarget === realRoot) {
return true;
}
const rel = path.relative(realRoot, realTarget);
return rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel);
}
/**
* Fail-closed guard: throw unless `target` is contained within `root`.
* Returns the canonicalized target path on success.
*/
function assertWithinTrustedRoot(target, root, action = 'write') {
if (!target || typeof target !== 'string') {
throw new Error(`Refusing to ${action}: missing destination path.`);
}
if (!root) {
throw new Error(`Refusing to ${action} '${target}': no trusted install root resolved.`);
}
if (!isWithinRoot(target, root)) {
throw new Error(`Refusing to ${action} outside the install root: '${target}' is not within '${root}'.`);
}
return realpathNearestExisting(target);
}
module.exports = {
realpathNearestExisting,
isWithinRoot,
assertWithinTrustedRoot
};