jorgex-stack 1.5.0 → 1.6.0

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.
@@ -0,0 +1,150 @@
1
+ declare const QUALITY_PROFILES: readonly ["routine", "elevated", "high", "release"];
2
+ type QualityProfile = (typeof QUALITY_PROFILES)[number];
3
+
4
+ declare const QUALITY_RECEIPT_NAMESPACE: "jorgex.quality.receipt";
5
+ declare const QUALITY_RECEIPT_VERSION: 1;
6
+ type QualityReceiptResultStatus = "pass" | "fail" | "incomplete" | "not-applicable";
7
+ interface QualityReceiptIdentity {
8
+ profile: QualityProfile;
9
+ baseSha: string;
10
+ headSha: string;
11
+ policyDigest: string;
12
+ }
13
+ interface QualityReceiptProvenance {
14
+ issuer: string;
15
+ executionId: string;
16
+ evidenceLocator: string;
17
+ evidenceDigest: string;
18
+ }
19
+ interface QualityReceiptPassResult {
20
+ controlId: string;
21
+ status: "pass";
22
+ evidence: string;
23
+ reason?: string;
24
+ }
25
+ interface QualityReceiptNonPassResult {
26
+ controlId: string;
27
+ status: Exclude<QualityReceiptResultStatus, "pass">;
28
+ evidence?: string;
29
+ reason?: string;
30
+ }
31
+ type QualityReceiptResult = QualityReceiptPassResult | QualityReceiptNonPassResult;
32
+ interface QualityReceiptCommand {
33
+ commandId: string;
34
+ executable: string;
35
+ argv: string[];
36
+ exitCode: number;
37
+ durationMs: number;
38
+ excerpt: string;
39
+ outputDigest: string;
40
+ }
41
+ interface QualityReceiptBase {
42
+ namespace: typeof QUALITY_RECEIPT_NAMESPACE;
43
+ version: typeof QUALITY_RECEIPT_VERSION;
44
+ identity: QualityReceiptIdentity;
45
+ commands: QualityReceiptCommand[];
46
+ results: QualityReceiptResult[];
47
+ }
48
+ interface QualityReceiptLocal extends QualityReceiptBase {
49
+ authority: "local";
50
+ provenance?: QualityReceiptProvenance;
51
+ }
52
+ interface QualityReceiptEnforced extends QualityReceiptBase {
53
+ authority: "enforced";
54
+ provenance: QualityReceiptProvenance;
55
+ }
56
+ type QualityReceipt = QualityReceiptLocal | QualityReceiptEnforced;
57
+
58
+ type ProtectedReference = {
59
+ ref: string;
60
+ sha: string;
61
+ };
62
+ type ExternalDecision = "pass" | "fail" | "incomplete";
63
+ type ExternalAttestation = {
64
+ issuer: string;
65
+ executionId: string;
66
+ identity: QualityReceipt["identity"];
67
+ policyDigest: string;
68
+ protectedRef: ProtectedReference;
69
+ producer: {
70
+ processId: string;
71
+ worktree: string;
72
+ };
73
+ decision: ExternalDecision;
74
+ subjectDigest: string;
75
+ evidenceDigest: string;
76
+ expiresAt: string;
77
+ proof: string;
78
+ };
79
+ type ExternalEvidence = {
80
+ locator: string;
81
+ bytes: Uint8Array;
82
+ attestation: ExternalAttestation;
83
+ };
84
+ type ExternalEvidenceResolution = {
85
+ status: "available";
86
+ evidence: ExternalEvidence;
87
+ } | {
88
+ status: "expired" | "unavailable";
89
+ retryable: boolean;
90
+ };
91
+ type AttestationVerification = {
92
+ authenticated: boolean;
93
+ };
94
+ type ExternalQualityVerifierInput = {
95
+ receipt: QualityReceipt;
96
+ expected: {
97
+ identity: QualityReceipt["identity"];
98
+ policy: Record<string, unknown>;
99
+ protectedRef: ProtectedReference;
100
+ evidenceLocator: string;
101
+ issuer: string;
102
+ executionId: string;
103
+ subjectDigest: string;
104
+ verifier: {
105
+ processId: string;
106
+ worktree: string;
107
+ };
108
+ };
109
+ };
110
+ type ExternalQualityVerifierDeps = {
111
+ /**
112
+ * Resolves evidence under the caller's own network and resource-safety policy.
113
+ * This verifier does not fetch, cap, or sandbox the returned bytes; the
114
+ * implementation must enforce size, timeout, redirect, host, DNS, and SSRF limits.
115
+ */
116
+ resolveEvidence(locator: string): Promise<ExternalEvidenceResolution>;
117
+ /**
118
+ * Must authenticate the proof and issuer and bind that authentication to all
119
+ * attestation claims. A true flag based only on shape or the issuer string is
120
+ * not sufficient because this result is the verifier's authentication gate.
121
+ */
122
+ authenticateAttestation(attestation: ExternalAttestation): Promise<AttestationVerification>;
123
+ now(): string;
124
+ };
125
+ /**
126
+ * Consumers must treat `incomplete` as a non-pass. `rerunRequired` is only a
127
+ * retry hint for evidence-resolution failure, not a general approval signal.
128
+ */
129
+ type ExternalQualityVerifierResult = {
130
+ status: "pass";
131
+ rerunRequired: false;
132
+ } | {
133
+ status: "fail";
134
+ rerunRequired: false;
135
+ } | {
136
+ status: "incomplete";
137
+ rerunRequired: boolean;
138
+ };
139
+ declare function subjectDigestFor(receipt: QualityReceipt): string;
140
+ /**
141
+ * Verifies an externally enforced receipt against caller-supplied expectations.
142
+ * A `pass` requires authenticated evidence, all receipt, evidence-binding,
143
+ * protected-reference, identity, policy, digest, and producer-boundary checks,
144
+ * a valid expiry, and an attestation decision of `pass`.
145
+ * This module does not track execution IDs or provide replay protection; callers
146
+ * must enforce any one-time-use requirement outside this function.
147
+ */
148
+ declare function verifyExternalQualityReceipt(input: ExternalQualityVerifierInput, deps: ExternalQualityVerifierDeps): Promise<ExternalQualityVerifierResult>;
149
+
150
+ export { type AttestationVerification, type ExternalAttestation, type ExternalDecision, type ExternalEvidence, type ExternalEvidenceResolution, type ExternalQualityVerifierDeps, type ExternalQualityVerifierInput, type ExternalQualityVerifierResult, type ProtectedReference, subjectDigestFor, verifyExternalQualityReceipt };
@@ -0,0 +1,249 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ QUALITY_PROFILES,
4
+ canonicalJson,
5
+ evaluateQualityPolicy,
6
+ samePath,
7
+ sha256,
8
+ validateQualityReceipt
9
+ } from "./chunk-IO2FFZOH.js";
10
+
11
+ // src/lib/quality-verifier.ts
12
+ import { createHash } from "crypto";
13
+ var COMMIT_SHA_PATTERN = /^[0-9a-f]{40}$/i;
14
+ var SHA256_PATTERN = /^[0-9a-f]{64}$/i;
15
+ var STANDARD_OBJECT_PROTOTYPE_KEYS = new Set(Reflect.ownKeys(Object.prototype));
16
+ function isRecord(value) {
17
+ return value !== null && typeof value === "object" && !Array.isArray(value);
18
+ }
19
+ function hasOwn(value, key) {
20
+ return Object.prototype.hasOwnProperty.call(value, key);
21
+ }
22
+ function hasSafePrototype(value) {
23
+ const prototype = Object.getPrototypeOf(value);
24
+ return prototype === null || prototype === Object.prototype && Reflect.ownKeys(prototype).every((key) => STANDARD_OBJECT_PROTOTYPE_KEYS.has(key));
25
+ }
26
+ function hasOnlyKeys(value, keys) {
27
+ const allowed = new Set(keys);
28
+ return Reflect.ownKeys(value).every((key) => allowed.has(key));
29
+ }
30
+ function hasExactKeys(value, keys) {
31
+ const ownKeys = Reflect.ownKeys(value);
32
+ if (ownKeys.length !== keys.length) return false;
33
+ const allowed = new Set(keys);
34
+ return ownKeys.every((key) => allowed.has(key));
35
+ }
36
+ function hasText(value) {
37
+ return typeof value === "string" && value.trim() !== "";
38
+ }
39
+ function isSha(value, pattern) {
40
+ return typeof value === "string" && pattern.test(value);
41
+ }
42
+ function hexEqual(left, right) {
43
+ return typeof left === "string" && typeof right === "string" && left.toLowerCase() === right.toLowerCase();
44
+ }
45
+ function isQualityProfile(value) {
46
+ return typeof value === "string" && QUALITY_PROFILES.includes(value);
47
+ }
48
+ function isQualityReceiptIdentity(value) {
49
+ if (!isRecord(value) || !hasExactKeys(value, ["profile", "baseSha", "headSha", "policyDigest"])) return false;
50
+ return isQualityProfile(value.profile) && isSha(value.baseSha, COMMIT_SHA_PATTERN) && isSha(value.headSha, COMMIT_SHA_PATTERN) && isSha(value.policyDigest, SHA256_PATTERN);
51
+ }
52
+ function sameQualityReceiptIdentity(left, right) {
53
+ return left.profile === right.profile && hexEqual(left.baseSha, right.baseSha) && hexEqual(left.headSha, right.headSha) && hexEqual(left.policyDigest, right.policyDigest);
54
+ }
55
+ function sameProtectedReference(left, right) {
56
+ return left.ref === right.ref && hexEqual(left.sha, right.sha);
57
+ }
58
+ function isProtectedReference(value) {
59
+ return isRecord(value) && hasExactKeys(value, ["ref", "sha"]) && hasText(value.ref) && isSha(value.sha, COMMIT_SHA_PATTERN);
60
+ }
61
+ function isVerifierBoundary(value) {
62
+ return isRecord(value) && hasExactKeys(value, ["processId", "worktree"]) && hasText(value.processId) && hasText(value.worktree);
63
+ }
64
+ function sha256Bytes(bytes) {
65
+ return createHash("sha256").update(bytes).digest("hex");
66
+ }
67
+ function subjectDigestFor(receipt) {
68
+ return sha256(canonicalJson({
69
+ namespace: receipt.namespace,
70
+ version: receipt.version,
71
+ authority: receipt.authority,
72
+ identity: receipt.identity,
73
+ commands: receipt.commands,
74
+ results: receipt.results
75
+ }));
76
+ }
77
+ function isQualityPolicy(value) {
78
+ if (!isRecord(value) || !hasSafePrototype(value) || !hasOnlyKeys(value, ["profile", "controls"]) || !hasOwn(value, "controls") || !Array.isArray(value.controls)) return false;
79
+ if (!hasOwn(value, "profile") && "profile" in value) return false;
80
+ if (hasOwn(value, "profile") && !isQualityProfile(value.profile)) return false;
81
+ const ids = /* @__PURE__ */ new Set();
82
+ for (const control of value.controls) {
83
+ if (!isRecord(control) || !hasSafePrototype(control) || !hasOnlyKeys(control, ["id", "requirement", "notApplicable"]) || !hasOwn(control, "id") || !hasOwn(control, "requirement") || !hasOwn(control, "notApplicable") && "notApplicable" in control || !hasText(control.id) || control.requirement !== "required" && control.requirement !== "optional" || ids.has(control.id) || hasOwn(control, "notApplicable") && typeof control.notApplicable !== "boolean") {
84
+ return false;
85
+ }
86
+ ids.add(control.id);
87
+ }
88
+ return true;
89
+ }
90
+ function isAttestation(value) {
91
+ return isRecord(value) && hasExactKeys(value, [
92
+ "issuer",
93
+ "executionId",
94
+ "identity",
95
+ "policyDigest",
96
+ "protectedRef",
97
+ "producer",
98
+ "decision",
99
+ "subjectDigest",
100
+ "evidenceDigest",
101
+ "expiresAt",
102
+ "proof"
103
+ ]) && hasText(value.issuer) && hasText(value.executionId) && isQualityReceiptIdentity(value.identity) && isSha(value.policyDigest, SHA256_PATTERN) && isProtectedReference(value.protectedRef) && isVerifierBoundary(value.producer) && (value.decision === "pass" || value.decision === "fail" || value.decision === "incomplete") && isSha(value.subjectDigest, SHA256_PATTERN) && isSha(value.evidenceDigest, SHA256_PATTERN) && hasText(value.expiresAt) && hasText(value.proof);
104
+ }
105
+ function isExternalEvidence(value) {
106
+ return isRecord(value) && hasExactKeys(value, ["locator", "bytes", "attestation"]) && hasText(value.locator) && value.bytes instanceof Uint8Array && isAttestation(value.attestation);
107
+ }
108
+ function isAttestationVerification(value) {
109
+ return isRecord(value) && Object.prototype.hasOwnProperty.call(value, "authenticated") && typeof value.authenticated === "boolean";
110
+ }
111
+ function isAvailableResolution(value) {
112
+ return isRecord(value) && hasExactKeys(value, ["status", "evidence"]) && value.status === "available" && isExternalEvidence(value.evidence);
113
+ }
114
+ function isRetryableResolution(value) {
115
+ return isRecord(value) && hasExactKeys(value, ["status", "retryable"]) && (value.status === "expired" || value.status === "unavailable") && typeof value.retryable === "boolean";
116
+ }
117
+ function prepareVerification(input) {
118
+ try {
119
+ const receipt = input.receipt;
120
+ const expected = input.expected;
121
+ if (!isRecord(expected) || !isQualityReceiptIdentity(expected.identity) || !isQualityPolicy(expected.policy) || !isProtectedReference(expected.protectedRef) || !isVerifierBoundary(expected.verifier) || !hasText(expected.evidenceLocator) || !hasText(expected.issuer) || !hasText(expected.executionId) || !isSha(expected.subjectDigest, SHA256_PATTERN)) {
122
+ return null;
123
+ }
124
+ validateQualityReceipt(receipt);
125
+ if (!sameQualityReceiptIdentity(receipt.identity, expected.identity)) return null;
126
+ if (receipt.authority !== "enforced" || receipt.provenance === void 0) return null;
127
+ if (receipt.provenance.issuer !== expected.issuer || receipt.provenance.executionId !== expected.executionId || receipt.provenance.evidenceLocator !== expected.evidenceLocator) {
128
+ return null;
129
+ }
130
+ if (!hexEqual(expected.protectedRef.sha, receipt.identity.baseSha)) return null;
131
+ const policyDigest = sha256(canonicalJson(expected.policy));
132
+ if (!hexEqual(policyDigest, expected.identity.policyDigest) || !hexEqual(policyDigest, receipt.identity.policyDigest)) {
133
+ return null;
134
+ }
135
+ const policyProfile = expected.policy.profile ?? "routine";
136
+ if (expected.identity.profile !== policyProfile) return null;
137
+ const policyEvaluation = evaluateQualityPolicy({
138
+ profile: expected.policy.profile,
139
+ controls: expected.policy.controls,
140
+ results: receipt.results
141
+ });
142
+ if (policyEvaluation.status !== "pass") {
143
+ return {
144
+ receipt,
145
+ expected,
146
+ policyDigest,
147
+ subjectDigest: expected.subjectDigest,
148
+ policyStatus: policyEvaluation.status
149
+ };
150
+ }
151
+ const subjectDigest = subjectDigestFor(receipt);
152
+ if (!hexEqual(subjectDigest, expected.subjectDigest)) return null;
153
+ return {
154
+ receipt,
155
+ expected,
156
+ policyDigest,
157
+ subjectDigest,
158
+ policyStatus: policyEvaluation.status
159
+ };
160
+ } catch {
161
+ return null;
162
+ }
163
+ }
164
+ function verifyEvidenceBinding(evidence, attestation, prepared) {
165
+ const { receipt, expected } = prepared;
166
+ const provenance = receipt.provenance;
167
+ if (provenance === void 0) return false;
168
+ const evidenceDigest = sha256Bytes(evidence.bytes);
169
+ return evidence.locator === expected.evidenceLocator && evidence.locator === provenance.evidenceLocator && hexEqual(evidenceDigest, provenance.evidenceDigest) && hexEqual(evidenceDigest, attestation.evidenceDigest) && hexEqual(attestation.subjectDigest, prepared.subjectDigest) && sameQualityReceiptIdentity(attestation.identity, receipt.identity) && sameQualityReceiptIdentity(attestation.identity, expected.identity) && hexEqual(attestation.policyDigest, prepared.policyDigest) && hexEqual(attestation.policyDigest, receipt.identity.policyDigest) && sameProtectedReference(attestation.protectedRef, expected.protectedRef) && hexEqual(attestation.protectedRef.sha, receipt.identity.baseSha) && attestation.issuer === expected.issuer && attestation.issuer === provenance.issuer && attestation.executionId === expected.executionId && attestation.executionId === provenance.executionId && attestation.producer.processId !== expected.verifier.processId && !samePath(attestation.producer.worktree, expected.verifier.worktree);
170
+ }
171
+ async function verifyAttestation(evidence, prepared, deps) {
172
+ try {
173
+ const attestation = snapshotAttestation(evidence.attestation);
174
+ let verification;
175
+ try {
176
+ verification = await deps.authenticateAttestation(attestation);
177
+ } catch {
178
+ return null;
179
+ }
180
+ if (!isAttestationVerification(verification) || !verification.authenticated) return null;
181
+ if (!verifyEvidenceBinding(evidence, attestation, prepared)) return null;
182
+ const nowMs = Date.parse(deps.now());
183
+ const expiresAtMs = Date.parse(attestation.expiresAt);
184
+ if (!Number.isFinite(nowMs) || !Number.isFinite(expiresAtMs) || expiresAtMs <= nowMs) return null;
185
+ return attestation.decision;
186
+ } catch {
187
+ return null;
188
+ }
189
+ }
190
+ function snapshotAttestation(attestation) {
191
+ const identity = Object.freeze({ ...attestation.identity });
192
+ const protectedRef = Object.freeze({ ...attestation.protectedRef });
193
+ const producer = Object.freeze({ ...attestation.producer });
194
+ return Object.freeze({
195
+ issuer: attestation.issuer,
196
+ executionId: attestation.executionId,
197
+ identity,
198
+ policyDigest: attestation.policyDigest,
199
+ protectedRef,
200
+ producer,
201
+ decision: attestation.decision,
202
+ subjectDigest: attestation.subjectDigest,
203
+ evidenceDigest: attestation.evidenceDigest,
204
+ expiresAt: attestation.expiresAt,
205
+ proof: attestation.proof
206
+ });
207
+ }
208
+ function failureResult() {
209
+ return { status: "fail", rerunRequired: false };
210
+ }
211
+ async function verifyExternalQualityReceipt(input, deps) {
212
+ try {
213
+ const prepared = prepareVerification(input);
214
+ if (prepared === null) return failureResult();
215
+ if (prepared.policyStatus === "fail") return failureResult();
216
+ if (prepared.policyStatus === "incomplete") {
217
+ return { status: "incomplete", rerunRequired: false };
218
+ }
219
+ if (typeof deps?.resolveEvidence !== "function" || typeof deps.authenticateAttestation !== "function" || typeof deps.now !== "function") {
220
+ return failureResult();
221
+ }
222
+ let resolution;
223
+ try {
224
+ resolution = await deps.resolveEvidence(prepared.expected.evidenceLocator);
225
+ } catch {
226
+ return { status: "incomplete", rerunRequired: true };
227
+ }
228
+ if (isRetryableResolution(resolution)) {
229
+ return { status: "incomplete", rerunRequired: resolution.retryable };
230
+ }
231
+ if (!isAvailableResolution(resolution)) return failureResult();
232
+ const { evidence } = resolution;
233
+ const decision = await verifyAttestation(evidence, prepared, deps);
234
+ if (decision === null) return failureResult();
235
+ if (decision === "incomplete") {
236
+ return { status: "incomplete", rerunRequired: false };
237
+ }
238
+ return {
239
+ status: decision,
240
+ rerunRequired: false
241
+ };
242
+ } catch {
243
+ return failureResult();
244
+ }
245
+ }
246
+ export {
247
+ subjectDigestFor,
248
+ verifyExternalQualityReceipt
249
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jorgex-stack",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Harness multi-agente portable: instala la config JorgeX (agentes, skills, hooks, Engram, MCPs) en Claude Code, Codex CLI, OpenCode y Pi",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -27,6 +27,12 @@
27
27
  "upstreams.json",
28
28
  "PRD.md"
29
29
  ],
30
+ "exports": {
31
+ "./quality-verifier": {
32
+ "types": "./dist/quality-verifier.d.ts",
33
+ "import": "./dist/quality-verifier.js"
34
+ }
35
+ },
30
36
  "engines": {
31
37
  "node": ">=22.5"
32
38
  },