refactor: hard-fork GSD -> MSD (Make Software Done)

Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD
across contents and paths, upstream package/repo coordinates -> @golem15/msd-core
and golem15com/msd-core. Deep links into upstream history, sibling upstream
packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is.

Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line,
package/plugin identity, regenerated lockfile, install-tree fixtures, derived
registries and benchmark baseline; migration checksum baseline re-locked
(MSD keeps its own install state, so no install had applied the old sums);
sort-order and regex-escaped expectations in tests adjusted.
This commit is contained in:
Jakub Zych
2026-10-06 01:47:40 +02:00
parent fe069b2a56
commit a9a7a328e6
2763 changed files with 78465 additions and 78434 deletions

View File

@@ -1,7 +1,7 @@
/**
* Capability consent store — issue #1459 (capability trust model bypassable).
*
* A USER-OWNED store, living OUTSIDE any repository at `${GSD_HOME||homedir()}/.gsd/consent.json`,
* A USER-OWNED store, living OUTSIDE any repository at `${MSD_HOME||homedir()}/.msd/consent.json`,
* that binds each PROJECT-scope third-party capability activation to a decision the user made on
* THIS machine. Before #1459 a project's in-repo ledger entry was treated as the consent signal —
* but a project ledger is repo-plantable, so cloning/forging a repo activated executable surfaces
@@ -29,9 +29,9 @@
* (no migration/back-compat shims needed); the only version is "1".
*
* Exports:
* consentStorePath(gsdHome?) — resolve the store path (GSD_HOME||homedir() rule).
* consentStorePath(msdHome?) — resolve the store path (MSD_HOME||homedir() rule).
* bundleContentHash(capDir) — recomputed sha512 over the whole bundle (the binding).
* readConsentStore(gsdHome?) — bounded, NON-THROWING read; bad input → { records: {} }.
* readConsentStore(msdHome?) — bounded, NON-THROWING read; bad input → { records: {} }.
* hasProjectConsent({...}) — true iff a record matches the recomputed contentHash.
* recordProjectConsent({...}) — atomic+durable+LOCKED write of a project-scope record.
* revokeProjectConsent({...}) — atomic+LOCKED delete of a project-scope record (no-op if absent).
@@ -78,7 +78,7 @@ const CONSENT_LOCK_MAX_ATTEMPTS = 50;
// ---------------------------------------------------------------------------
const CONSENT_SCHEMA_VERSION = '1';
const CONSENT_DIRNAME = '.gsd';
const CONSENT_DIRNAME = '.msd';
const CONSENT_FILE_NAME = 'consent.json';
/**
@@ -212,12 +212,12 @@ function realpathProject(projectRoot: string): string {
// ---------------------------------------------------------------------------
/**
* Resolve the consent store path. Uses the SAME `gsdHome || GSD_HOME || homedir()` rule the loader
* Resolve the consent store path. Uses the SAME `msdHome || MSD_HOME || homedir()` rule the loader
* and CLI use, so a consent record written by the CLI is found by the loader. The store NEVER lives
* under a repository — it is user-owned, machine-local config.
*/
function consentStorePath(gsdHome?: string): string {
const home = gsdHome || process.env['GSD_HOME'] || os.homedir();
function consentStorePath(msdHome?: string): string {
const home = msdHome || process.env['MSD_HOME'] || os.homedir();
return path.join(home, CONSENT_DIRNAME, CONSENT_FILE_NAME);
}
@@ -619,9 +619,9 @@ function isValidConsentRecord(rec: unknown): rec is ConsentRecord {
* (FIFO/device), or wrong-shape store yields an empty `{ records: {} }`. Invalid individual records
* are dropped. A store whose record count exceeds MAX_RECORDS is refused wholesale (hostile DoS).
*/
function readConsentStore(gsdHome?: string): ConsentStore {
function readConsentStore(msdHome?: string): ConsentStore {
const empty: ConsentStore = { records: {} };
const filePath = consentStorePath(gsdHome);
const filePath = consentStorePath(msdHome);
let raw: string | null;
try {
raw = ledgerMod.readSmallRegularFile(filePath, CONSENT_MAX_BYTES);
@@ -667,15 +667,15 @@ function readConsentStore(gsdHome?: string): ConsentStore {
* hasOwnProperty).
*/
function hasProjectConsent(args: {
gsdHome?: string;
msdHome?: string;
projectRoot: string;
id: string;
contentHash: string;
}): boolean {
const { gsdHome, projectRoot, id, contentHash } = args;
const { msdHome, projectRoot, id, contentHash } = args;
if (isUnsafeCapabilityId(id)) return false;
if (typeof contentHash !== 'string' || !contentHash) return false;
const store = readConsentStore(gsdHome);
const store = readConsentStore(msdHome);
const key = consentKey(realpathProject(projectRoot), id);
if (!Object.prototype.hasOwnProperty.call(store.records, key)) return false;
const rec = store.records[key];
@@ -689,8 +689,8 @@ function hasProjectConsent(args: {
type ConsentLock = { path: string; token: string; dev: number | null; ino: number | null };
/** The consent-store lock path — keyed on the consent store DIRECTORY (one lock per machine store). */
function consentLockPath(gsdHome?: string): string {
return path.join(path.dirname(consentStorePath(gsdHome)), '.consent.lock');
function consentLockPath(msdHome?: string): string {
return path.join(path.dirname(consentStorePath(msdHome)), '.consent.lock');
}
/**
@@ -769,8 +769,8 @@ function renameBackoff(): void {
* The on-disk JSON uses the unambiguous JSON-object disk key (WIN-3); the in-memory store is keyed by
* the canonical NUL key, so we re-key here.
*/
function writeConsentStore(gsdHome: string | undefined, store: ConsentStore): void {
const filePath = consentStorePath(gsdHome);
function writeConsentStore(msdHome: string | undefined, store: ConsentStore): void {
const filePath = consentStorePath(msdHome);
const dir = path.dirname(filePath);
fs.mkdirSync(dir, { recursive: true });
@@ -848,7 +848,7 @@ function writeConsentStore(gsdHome: string | undefined, store: ConsentStore): vo
* written. (The OLD code returned a null handle and proceeded unlocked — that is the bug.)
*/
function recordProjectConsent(args: {
gsdHome?: string;
msdHome?: string;
projectRoot: string;
id: string;
integrity: string;
@@ -856,7 +856,7 @@ function recordProjectConsent(args: {
contentHash: string;
reviewerHost?: string;
}): void {
const { gsdHome, projectRoot, id, integrity, disclosureSignature, contentHash, reviewerHost } = args;
const { msdHome, projectRoot, id, integrity, disclosureSignature, contentHash, reviewerHost } = args;
if (isUnsafeCapabilityId(id)) {
throw new Error(
`Invalid capability id "${String(id)}": must match /^[a-z][a-z0-9-]*$/ (kebab-case, lowercase). ` +
@@ -870,27 +870,27 @@ function recordProjectConsent(args: {
);
}
const realRoot = realpathProject(projectRoot);
const lockDir = path.dirname(consentStorePath(gsdHome));
const lockDir = path.dirname(consentStorePath(msdHome));
try { fs.mkdirSync(lockDir, { recursive: true }); } catch { /* best-effort — write also mkdirs */ }
// #1459 finding 3: never proceed UNLOCKED. A null handle (live holder / contention budget exhausted)
// → throw rather than risk a lost update.
const lock = acquireConsentLock(lockDir);
if (lock === null) {
throw new Error(
`recordProjectConsent: could not acquire the consent-store lock at ${consentLockPath(gsdHome)} ` +
`recordProjectConsent: could not acquire the consent-store lock at ${consentLockPath(msdHome)} ` +
`(another writer holds it). Refusing to write the consent store UNLOCKED (a lost-update risk). ` +
`Retry; if a stale lock persists past the deadman it is reclaimed automatically.`,
);
}
try {
const store = readConsentStore(gsdHome);
const store = readConsentStore(msdHome);
const key = consentKey(realRoot, id);
// CONSENT-MAXRECORDS-WRITE-1: enforce the cap BEFORE the write. A re-record of an EXISTING key
// does not grow the store (allowed); only ADDING a new key when already at the cap is refused.
if (!Object.prototype.hasOwnProperty.call(store.records, key) && Object.keys(store.records).length >= MAX_RECORDS) {
throw new Error(
`consent store full: already at the maximum of ${MAX_RECORDS} consent records. Revoke an ` +
`unused consent (gsd capability trust revoke) before recording a new one.`,
`unused consent (msd capability trust revoke) before recording a new one.`,
);
}
store.records[key] = {
@@ -905,7 +905,7 @@ function recordProjectConsent(args: {
// or a non-lane capability keeps a byte-identical record shape.
...(typeof reviewerHost === 'string' && reviewerHost ? { reviewerHost } : {}),
};
writeConsentStore(gsdHome, store);
writeConsentStore(msdHome, store);
} finally {
releaseConsentLock(lock);
}
@@ -920,27 +920,27 @@ function recordProjectConsent(args: {
* doing an unlocked read-modify-write (the lost-update vector). An ABSENT-record no-op still happens
* UNDER the lock (so a concurrent record cannot interleave); only a genuine lock-acquire failure throws.
*/
function revokeProjectConsent(args: { gsdHome?: string; projectRoot: string; id: string }): void {
const { gsdHome, projectRoot, id } = args;
function revokeProjectConsent(args: { msdHome?: string; projectRoot: string; id: string }): void {
const { msdHome, projectRoot, id } = args;
if (isUnsafeCapabilityId(id)) return; // an unsafe id was never stored — nothing to revoke.
const realRoot = realpathProject(projectRoot);
const lockDir = path.dirname(consentStorePath(gsdHome));
const lockDir = path.dirname(consentStorePath(msdHome));
try { fs.mkdirSync(lockDir, { recursive: true }); } catch { /* best-effort — write also mkdirs */ }
// #1459 finding 3: never proceed UNLOCKED — a null handle throws rather than deleting unlocked.
const lock = acquireConsentLock(lockDir);
if (lock === null) {
throw new Error(
`revokeProjectConsent: could not acquire the consent-store lock at ${consentLockPath(gsdHome)} ` +
`revokeProjectConsent: could not acquire the consent-store lock at ${consentLockPath(msdHome)} ` +
`(another writer holds it). Refusing to modify the consent store UNLOCKED (a lost-update risk). ` +
`Retry; if a stale lock persists past the deadman it is reclaimed automatically.`,
);
}
try {
const store = readConsentStore(gsdHome);
const store = readConsentStore(msdHome);
const key = consentKey(realRoot, id);
if (!Object.prototype.hasOwnProperty.call(store.records, key)) return; // absent — no-op.
delete store.records[key];
writeConsentStore(gsdHome, store);
writeConsentStore(msdHome, store);
} finally {
releaseConsentLock(lock);
}
@@ -962,14 +962,14 @@ function revokeProjectConsent(args: { gsdHome?: string; projectRoot: string; id:
* Non-throwing: a missing, corrupt, or oversized store yields `undefined` like any other absence.
*/
function readConsentedReviewerHost(args: {
gsdHome?: string;
msdHome?: string;
projectRoot: string;
id: string;
}): string | undefined {
const { gsdHome, projectRoot, id } = args;
const { msdHome, projectRoot, id } = args;
if (isUnsafeCapabilityId(id)) return undefined;
try {
const store = readConsentStore(gsdHome);
const store = readConsentStore(msdHome);
const key = consentKey(realpathProject(projectRoot), id);
if (!Object.prototype.hasOwnProperty.call(store.records, key)) return undefined;
const host = store.records[key].reviewerHost;