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>
This commit is contained in:
Samarjeet Singh Tomar 2026-07-17 16:13:49 -05:00 committed by GitHub
parent 5da21c2b66
commit 754b8dd76c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 144 additions and 99 deletions

View file

@ -695,8 +695,8 @@ function dedupeCopyFileOperations(operations) {
// actually determines the installed content. Recording the shadowed earlier
// writes in install-state makes `doctor` report perpetual drift and drives
// `repair` to clobber the override with the generic source (issue #2414).
// Keep only the last `copy-file` per destination matching the sequential
// apply order in applyInstallPlan and leave every other operation kind
// Keep only the last `copy-file` per destination - matching the sequential
// apply order in applyInstallPlan - and leave every other operation kind
// (e.g. accumulating `merge-json` writes into a shared config) untouched and
// in order.
const lastCopyIndexByDestination = new Map();

View file

@ -1,17 +1,11 @@
const fs = require('fs');
const path = require('path');
let Ajv = null;
try {
// Prefer schema-backed validation when dependencies are installed.
// The fallback validator below keeps source checkouts usable in bare environments.
const ajvModule = require('ajv');
Ajv = ajvModule.default || ajvModule;
} catch (_error) {
Ajv = null;
}
const SCHEMA_PATH = path.join(__dirname, '..', '..', 'schemas', 'install-state.schema.json');
// Dependency-free, self-contained validation. The installer closure must not
// require any non-builtin package (enterprise supply-chain vetting: the vetted
// bytes must be the installed bytes). install-state is validated by the
// hand-rolled validator below, which enforces the same constraints as
// schemas/install-state.schema.json (ecc.install.v1).
let cachedValidator = null;
@ -36,13 +30,6 @@ function getValidator() {
return cachedValidator;
}
if (Ajv) {
const schema = readJson(SCHEMA_PATH, 'install-state schema');
const ajv = new Ajv({ allErrors: true });
cachedValidator = ajv.compile(schema);
return cachedValidator;
}
cachedValidator = createFallbackValidator();
return cachedValidator;
}

View file

@ -159,8 +159,8 @@ function rewriteRelativeLinks(content, options) {
}
// If the recomputed link points to the same place as the original
// (e.g. an intra-namespace `./sibling.md` whose endpoints both shift by
// the same prefix), keep the original text verbatim including any
// leading `./` so the rewrite stays a strict no-op where it must.
// the same prefix), keep the original text verbatim - including any
// leading `./` - so the rewrite stays a strict no-op where it must.
if (posix.normalize(rewritten) === posix.normalize(pathPart)) {
return match;
}

View file

@ -10,7 +10,7 @@ const path = require('path');
* (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).
* root - never trusted from the state file itself (GHSA-hfpv-w6mp-5g95).
*/
function safeRealpath(target) {