@sunaiva/gate 1.0.0 → 1.1.2
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/BUSINESS_LICENSE.md +70 -0
- package/CHANGELOG.md +254 -0
- package/LICENSE +0 -0
- package/README.md +451 -67
- package/README.md.bak-v1.0.0-stale-MIT +59 -0
- package/SUPPORT.md +75 -0
- package/TIER_DEFINITIONS.md +161 -0
- package/dist/config/defaults.d.ts +22 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +56 -8
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/loader.d.ts +0 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +23 -5
- package/dist/config/loader.js.map +1 -1
- package/dist/engine/backend-client.d.ts +58 -0
- package/dist/engine/backend-client.d.ts.map +1 -0
- package/dist/engine/backend-client.js +287 -0
- package/dist/engine/backend-client.js.map +1 -0
- package/dist/engine/hmac-verifier.d.ts +52 -0
- package/dist/engine/hmac-verifier.d.ts.map +1 -0
- package/dist/engine/hmac-verifier.js +159 -0
- package/dist/engine/hmac-verifier.js.map +1 -0
- package/dist/engine/immutability.d.ts +59 -0
- package/dist/engine/immutability.d.ts.map +1 -0
- package/dist/engine/immutability.js +129 -0
- package/dist/engine/immutability.js.map +1 -0
- package/dist/engine/pattern-matcher.d.ts +13 -0
- package/dist/engine/pattern-matcher.d.ts.map +1 -1
- package/dist/engine/pattern-matcher.js +85 -17
- package/dist/engine/pattern-matcher.js.map +1 -1
- package/dist/engine/rule-engine.d.ts +62 -1
- package/dist/engine/rule-engine.d.ts.map +1 -1
- package/dist/engine/rule-engine.js +224 -12
- package/dist/engine/rule-engine.js.map +1 -1
- package/dist/engine/session-state.d.ts +0 -0
- package/dist/engine/session-state.d.ts.map +1 -1
- package/dist/engine/session-state.js +8 -2
- package/dist/engine/session-state.js.map +1 -1
- package/dist/engine/ship-confidence-gate.d.ts +232 -0
- package/dist/engine/ship-confidence-gate.d.ts.map +1 -0
- package/dist/engine/ship-confidence-gate.js +768 -0
- package/dist/engine/ship-confidence-gate.js.map +1 -0
- package/dist/index.d.ts +0 -0
- package/dist/index.js +293 -2
- package/dist/rules/categories.json +0 -0
- package/dist/rules/presets.json +0 -0
- package/dist/rules/rules.json +132 -64
- package/dist/tools/audit.d.ts +6 -0
- package/dist/tools/audit.d.ts.map +1 -1
- package/dist/tools/audit.js +43 -6
- package/dist/tools/audit.js.map +1 -1
- package/dist/tools/bypass.d.ts +0 -0
- package/dist/tools/bypass.d.ts.map +1 -1
- package/dist/tools/bypass.js +50 -6
- package/dist/tools/bypass.js.map +1 -1
- package/dist/tools/export-attestation.d.ts +45 -0
- package/dist/tools/export-attestation.d.ts.map +1 -0
- package/dist/tools/export-attestation.js +152 -0
- package/dist/tools/export-attestation.js.map +1 -0
- package/dist/tools/rules.d.ts +0 -0
- package/dist/tools/rules.d.ts.map +0 -0
- package/dist/tools/rules.js +0 -0
- package/dist/tools/rules.js.map +0 -0
- package/dist/tools/ship-confidence.d.ts +17 -0
- package/dist/tools/ship-confidence.d.ts.map +1 -0
- package/dist/tools/ship-confidence.js +42 -0
- package/dist/tools/ship-confidence.js.map +1 -0
- package/dist/tools/update.d.ts +0 -0
- package/dist/tools/update.d.ts.map +1 -1
- package/dist/tools/update.js +45 -9
- package/dist/tools/update.js.map +1 -1
- package/dist/tools/validate.d.ts +0 -0
- package/dist/tools/validate.d.ts.map +1 -1
- package/dist/tools/validate.js +56 -4
- package/dist/tools/validate.js.map +1 -1
- package/dist/types/backend.d.ts +69 -0
- package/dist/types/backend.d.ts.map +1 -0
- package/dist/types/backend.js +18 -0
- package/dist/types/backend.js.map +1 -0
- package/package.json +83 -65
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
package/dist/tools/audit.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async-style audit write. The file I/O is deferred to setImmediate so the hot
|
|
3
|
+
* path (the validate_action response) returns before the syscall. Errors are
|
|
4
|
+
* swallowed because the audit log is informational and must never break
|
|
5
|
+
* enforcement.
|
|
6
|
+
*/
|
|
1
7
|
export declare function appendAudit(entry: Record<string, unknown>): void;
|
|
2
8
|
export declare function handleGetAuditLog(args: {
|
|
3
9
|
limit?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"AAgCA;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAYhE;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;GAejF"}
|
package/dist/tools/audit.js
CHANGED
|
@@ -1,16 +1,53 @@
|
|
|
1
|
-
import { readFileSync, appendFileSync, existsSync, mkdirSync } from "node:fs";
|
|
1
|
+
import { readFileSync, appendFileSync, existsSync, mkdirSync, statSync, renameSync } from "node:fs";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
3
|
import { getConfig } from "../config/loader.js";
|
|
4
|
+
// Rotate audit log when it crosses this size (bytes).
|
|
5
|
+
const AUDIT_ROTATE_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
6
|
+
// Throttle rotation checks: only stat the file at most every 60s.
|
|
7
|
+
const ROTATE_CHECK_MS = 60_000;
|
|
8
|
+
let _lastRotateCheck = 0;
|
|
4
9
|
function getLogPath() {
|
|
5
10
|
return getConfig().audit_log_path;
|
|
6
11
|
}
|
|
7
|
-
|
|
12
|
+
function maybeRotate(logPath) {
|
|
13
|
+
const now = Date.now();
|
|
14
|
+
if (now - _lastRotateCheck < ROTATE_CHECK_MS)
|
|
15
|
+
return;
|
|
16
|
+
_lastRotateCheck = now;
|
|
8
17
|
try {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
18
|
+
if (!existsSync(logPath))
|
|
19
|
+
return;
|
|
20
|
+
const size = statSync(logPath).size;
|
|
21
|
+
if (size < AUDIT_ROTATE_BYTES)
|
|
22
|
+
return;
|
|
23
|
+
// Rotate: audit.jsonl -> audit.jsonl.1 (best-effort). Single-slot rotation
|
|
24
|
+
// is acceptable for an informational audit ledger.
|
|
25
|
+
const rotated = `${logPath}.1`;
|
|
26
|
+
renameSync(logPath, rotated);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// Fail-OPEN: never let rotation block writes.
|
|
12
30
|
}
|
|
13
|
-
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Async-style audit write. The file I/O is deferred to setImmediate so the hot
|
|
34
|
+
* path (the validate_action response) returns before the syscall. Errors are
|
|
35
|
+
* swallowed because the audit log is informational and must never break
|
|
36
|
+
* enforcement.
|
|
37
|
+
*/
|
|
38
|
+
export function appendAudit(entry) {
|
|
39
|
+
const stamped = { ...entry };
|
|
40
|
+
setImmediate(() => {
|
|
41
|
+
try {
|
|
42
|
+
const logPath = getLogPath();
|
|
43
|
+
mkdirSync(dirname(logPath), { recursive: true });
|
|
44
|
+
maybeRotate(logPath);
|
|
45
|
+
appendFileSync(logPath, JSON.stringify(stamped) + "\n");
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Fail-OPEN
|
|
49
|
+
}
|
|
50
|
+
});
|
|
14
51
|
}
|
|
15
52
|
export async function handleGetAuditLog(args) {
|
|
16
53
|
const logPath = getLogPath();
|
package/dist/tools/audit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/bypass.d.ts
CHANGED
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bypass.d.ts","sourceRoot":"","sources":["../../src/tools/bypass.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bypass.d.ts","sourceRoot":"","sources":["../../src/tools/bypass.ts"],"names":[],"mappings":"AAaA,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;;;;;GAiD9E"}
|
package/dist/tools/bypass.js
CHANGED
|
@@ -1,16 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* log_bypass MCP tool — record an intentional, justified rule bypass.
|
|
3
|
+
*
|
|
4
|
+
* Constitutional rules CANNOT be bypassed (Builder B4 — Finding C3).
|
|
5
|
+
* Backed by `src/engine/immutability.ts`. A rejected bypass writes
|
|
6
|
+
* NOTHING to the audit log (per B4 brief test #8) — the entire call
|
|
7
|
+
* fails before audit is touched. This is intentional: a constitutional
|
|
8
|
+
* bypass attempt is a misuse signal, not a logged business event.
|
|
9
|
+
*/
|
|
1
10
|
import { loadAllRules } from "../engine/rule-engine.js";
|
|
11
|
+
import { assertCanBypass, ConstitutionalImmutableError } from "../engine/immutability.js";
|
|
2
12
|
import { appendAudit } from "./audit.js";
|
|
3
13
|
export async function handleLogBypass(args) {
|
|
4
14
|
const rules = loadAllRules();
|
|
5
|
-
const rule = rules.find(r => r.id === args.rule_id);
|
|
15
|
+
const rule = rules.find((r) => r.id === args.rule_id);
|
|
6
16
|
if (!rule) {
|
|
7
|
-
return {
|
|
17
|
+
return {
|
|
18
|
+
content: [{
|
|
19
|
+
type: "text",
|
|
20
|
+
text: JSON.stringify({ error: `Rule not found: ${args.rule_id}` }),
|
|
21
|
+
}],
|
|
22
|
+
};
|
|
8
23
|
}
|
|
9
|
-
|
|
10
|
-
|
|
24
|
+
try {
|
|
25
|
+
assertCanBypass(args.rule_id);
|
|
11
26
|
}
|
|
12
|
-
|
|
27
|
+
catch (err) {
|
|
28
|
+
if (err instanceof ConstitutionalImmutableError) {
|
|
29
|
+
return {
|
|
30
|
+
content: [{
|
|
31
|
+
type: "text",
|
|
32
|
+
text: JSON.stringify({
|
|
33
|
+
error: "CONSTITUTIONAL_RULE_CANNOT_BE_BYPASSED",
|
|
34
|
+
rule_id: err.rule_id,
|
|
35
|
+
message: "Constitutional rules cannot be bypassed via log_bypass",
|
|
36
|
+
}),
|
|
37
|
+
}],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
const entry = {
|
|
43
|
+
timestamp: new Date().toISOString(),
|
|
44
|
+
type: "bypass",
|
|
45
|
+
rule_id: args.rule_id,
|
|
46
|
+
reason: args.reason,
|
|
47
|
+
};
|
|
13
48
|
appendAudit(entry);
|
|
14
|
-
return {
|
|
49
|
+
return {
|
|
50
|
+
content: [{
|
|
51
|
+
type: "text",
|
|
52
|
+
text: JSON.stringify({
|
|
53
|
+
logged: true,
|
|
54
|
+
bypass_id: `byp_${Date.now()}`,
|
|
55
|
+
rule_id: args.rule_id,
|
|
56
|
+
}),
|
|
57
|
+
}],
|
|
58
|
+
};
|
|
15
59
|
}
|
|
16
60
|
//# sourceMappingURL=bypass.js.map
|
package/dist/tools/bypass.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bypass.js","sourceRoot":"","sources":["../../src/tools/bypass.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAyC;IAC7E,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"bypass.js","sourceRoot":"","sources":["../../src/tools/bypass.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAC1F,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAyC;IAC7E,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC;IAEtD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mBAAmB,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;iBACnE,CAAC;SACH,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,4BAA4B,EAAE,CAAC;YAChD,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,KAAK,EAAE,wCAAwC;4BAC/C,OAAO,EAAE,GAAG,CAAC,OAAO;4BACpB,OAAO,EAAE,wDAAwD;yBAClE,CAAC;qBACH,CAAC;aACH,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAG;QACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC;IACF,WAAW,CAAC,KAAK,CAAC,CAAC;IAEnB,OAAO;QACL,OAAO,EAAE,CAAC;gBACR,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,MAAM,EAAE,IAAI;oBACZ,SAAS,EAAE,OAAO,IAAI,CAAC,GAAG,EAAE,EAAE;oBAC9B,OAAO,EAAE,IAAI,CAAC,OAAO;iBACtB,CAAC;aACH,CAAC;KACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export interface ExportAttestationArgs {
|
|
2
|
+
/** The verdict_id (preferred) OR an artifact_id we can resolve to a verdict file. */
|
|
3
|
+
verdict_id: string;
|
|
4
|
+
/** Optional artifact name override (defaults to verdict.artifact_id). */
|
|
5
|
+
artifact_name?: string;
|
|
6
|
+
/** Optional artifact sha256 override (defaults to deterministic-derived). */
|
|
7
|
+
artifact_sha256?: string;
|
|
8
|
+
/** Optional output path. If omitted, the envelope is returned in-band only. */
|
|
9
|
+
output_path?: string;
|
|
10
|
+
/** Optional keyid label. Defaults to "sunaiva-gate-hmac-v1.2". */
|
|
11
|
+
keyid?: string;
|
|
12
|
+
/** Optional verdict directory override (test fixtures). */
|
|
13
|
+
verdict_dir?: string;
|
|
14
|
+
/** Optional env override (test fixtures). */
|
|
15
|
+
env?: NodeJS.ProcessEnv;
|
|
16
|
+
}
|
|
17
|
+
export interface ExportAttestationResult {
|
|
18
|
+
/** True iff the envelope was successfully produced. */
|
|
19
|
+
ok: boolean;
|
|
20
|
+
/** Path on disk if output_path was provided. */
|
|
21
|
+
output_path?: string;
|
|
22
|
+
/** The JSONL envelope content (one line). */
|
|
23
|
+
envelope_jsonl?: string;
|
|
24
|
+
/** Reason on failure. */
|
|
25
|
+
reason?: string;
|
|
26
|
+
/** Verdict id resolved during lookup. */
|
|
27
|
+
verdict_id?: string;
|
|
28
|
+
/** The keyid used to sign. */
|
|
29
|
+
keyid?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Programmatic entry point (used by the MCP handler + CLI flag).
|
|
33
|
+
*/
|
|
34
|
+
export declare function exportAttestation(args: ExportAttestationArgs): Promise<ExportAttestationResult>;
|
|
35
|
+
/**
|
|
36
|
+
* MCP tool handler — wraps {@link exportAttestation} in the
|
|
37
|
+
* {content:[{type:'text', text}]} response shape.
|
|
38
|
+
*/
|
|
39
|
+
export declare function handleExportAttestation(args: ExportAttestationArgs): Promise<{
|
|
40
|
+
content: {
|
|
41
|
+
type: "text";
|
|
42
|
+
text: string;
|
|
43
|
+
}[];
|
|
44
|
+
}>;
|
|
45
|
+
//# sourceMappingURL=export-attestation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export-attestation.d.ts","sourceRoot":"","sources":["../../src/tools/export-attestation.ts"],"names":[],"mappings":"AAmCA,MAAM,WAAW,qBAAqB;IACpC,qFAAqF;IACrF,UAAU,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,uBAAuB;IACtC,uDAAuD;IACvD,EAAE,EAAE,OAAO,CAAC;IACZ,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yBAAyB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmFD;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,uBAAuB,CAAC,CA6ClC;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CAUxD"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool + CLI handler: export_attestation (W2-B3 / T03).
|
|
3
|
+
*
|
|
4
|
+
* Given a verdict_id (or path to a `.signed.json`), build a SLSA
|
|
5
|
+
* Provenance v1.0 in-toto Statement, sign with HMAC-SHA256 over the
|
|
6
|
+
* canonical JSON, and emit the JSONL envelope.
|
|
7
|
+
*
|
|
8
|
+
* Default behaviour:
|
|
9
|
+
* - Look up the verdict by sanitized verdict_id in
|
|
10
|
+
* <genesisRoot>/data/ship_confidence_verdicts/<id>.signed.json.
|
|
11
|
+
* - Sign with $SHIP_CONFIDENCE_SIGNING_KEY (same key the verdict was
|
|
12
|
+
* signed with — symmetry keeps the bundle a single key surface).
|
|
13
|
+
* - Subject artifact name defaults to verdict.artifact_id; sha256
|
|
14
|
+
* defaults to a deterministic placeholder derived from the verdict
|
|
15
|
+
* id (caller can override with --artifact-sha256).
|
|
16
|
+
*
|
|
17
|
+
* Strict shape per §5.3 of SPRINT_1_2_0_PLAN.md.
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
20
|
+
import { join, resolve } from "node:path";
|
|
21
|
+
import { createHash } from "node:crypto";
|
|
22
|
+
import { buildInTotoStatement, envelopeToJsonl, signStatementHmac, } from "../installer/attestation/intoto.js";
|
|
23
|
+
import { sanitizeArtifactId } from "../engine/ship-confidence-gate.js";
|
|
24
|
+
const SIGNING_KEY_ENV = "SHIP_CONFIDENCE_SIGNING_KEY";
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Internals
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
/**
|
|
29
|
+
* Resolve a verdict file by id-or-artifact-id. Returns the parsed
|
|
30
|
+
* verdict payload or null if no matching file is found.
|
|
31
|
+
*/
|
|
32
|
+
function resolveVerdictFile(idOrArtifact, verdictDir) {
|
|
33
|
+
if (!existsSync(verdictDir))
|
|
34
|
+
return null;
|
|
35
|
+
const sanitized = sanitizeArtifactId(idOrArtifact);
|
|
36
|
+
const direct = join(verdictDir, `${sanitized}.signed.json`);
|
|
37
|
+
if (existsSync(direct)) {
|
|
38
|
+
try {
|
|
39
|
+
const v = JSON.parse(readFileSync(direct, "utf-8"));
|
|
40
|
+
return { path: direct, verdict: v };
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
/* fall through to scan */
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Scan for matching verdict_id OR artifact_id.
|
|
47
|
+
try {
|
|
48
|
+
const files = readdirSync(verdictDir).filter((f) => f.endsWith(".signed.json"));
|
|
49
|
+
for (const f of files) {
|
|
50
|
+
const p = join(verdictDir, f);
|
|
51
|
+
try {
|
|
52
|
+
const v = JSON.parse(readFileSync(p, "utf-8"));
|
|
53
|
+
if (v.verdict_id === idOrArtifact || v.artifact_id === idOrArtifact) {
|
|
54
|
+
return { path: p, verdict: v };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
/* skip malformed files */
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
/* dir read failure */
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
/** Deterministic sha256 hex derived from verdict_id — placeholder when caller
|
|
68
|
+
* has no real artifact bytes available. The output is byte-stable so audit
|
|
69
|
+
* consumers can verify the same verdict produces the same subject digest. */
|
|
70
|
+
function deterministicSubjectSha(verdictId) {
|
|
71
|
+
return createHash("sha256")
|
|
72
|
+
.update(`sunaiva-subject-${verdictId}`, "utf-8")
|
|
73
|
+
.digest("hex");
|
|
74
|
+
}
|
|
75
|
+
/** Detect the genesis-system root, matching the Python convention. */
|
|
76
|
+
function detectGenesisRoot(env) {
|
|
77
|
+
for (const k of ["GENESIS_ROOT", "CLAUDE_PROJECT_DIR"]) {
|
|
78
|
+
const v = (env[k] ?? "").trim();
|
|
79
|
+
if (v && existsSync(v))
|
|
80
|
+
return v;
|
|
81
|
+
}
|
|
82
|
+
if (existsSync("E:/genesis-system"))
|
|
83
|
+
return "E:/genesis-system";
|
|
84
|
+
if (existsSync("/mnt/e/genesis-system"))
|
|
85
|
+
return "/mnt/e/genesis-system";
|
|
86
|
+
return "E:/genesis-system";
|
|
87
|
+
}
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// Public API
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
/**
|
|
92
|
+
* Programmatic entry point (used by the MCP handler + CLI flag).
|
|
93
|
+
*/
|
|
94
|
+
export async function exportAttestation(args) {
|
|
95
|
+
const env = args.env ?? process.env;
|
|
96
|
+
const verdictDir = args.verdict_dir ??
|
|
97
|
+
join(detectGenesisRoot(env), "data", "ship_confidence_verdicts");
|
|
98
|
+
const resolved = resolveVerdictFile(args.verdict_id, verdictDir);
|
|
99
|
+
if (!resolved) {
|
|
100
|
+
return {
|
|
101
|
+
ok: false,
|
|
102
|
+
reason: `no verdict found for '${args.verdict_id}' in ${verdictDir}`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const { verdict } = resolved;
|
|
106
|
+
const signingKey = env[SIGNING_KEY_ENV];
|
|
107
|
+
if (!signingKey) {
|
|
108
|
+
return {
|
|
109
|
+
ok: false,
|
|
110
|
+
reason: `${SIGNING_KEY_ENV} env var not set — cannot sign attestation`,
|
|
111
|
+
verdict_id: verdict.verdict_id,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const artifact = {
|
|
115
|
+
name: args.artifact_name ?? verdict.artifact_id,
|
|
116
|
+
sha256: (args.artifact_sha256 ??
|
|
117
|
+
deterministicSubjectSha(verdict.verdict_id)).toLowerCase(),
|
|
118
|
+
};
|
|
119
|
+
const statement = buildInTotoStatement(verdict, artifact);
|
|
120
|
+
const keyBuffer = Buffer.from(signingKey, "utf-8");
|
|
121
|
+
const signature = signStatementHmac(statement, keyBuffer);
|
|
122
|
+
const keyid = args.keyid ?? "sunaiva-gate-hmac-v1.2";
|
|
123
|
+
const envelopeLine = envelopeToJsonl(statement, signature, keyid);
|
|
124
|
+
let outputPath;
|
|
125
|
+
if (args.output_path) {
|
|
126
|
+
outputPath = resolve(args.output_path);
|
|
127
|
+
writeFileSync(outputPath, envelopeLine, "utf-8");
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
ok: true,
|
|
131
|
+
output_path: outputPath,
|
|
132
|
+
envelope_jsonl: envelopeLine,
|
|
133
|
+
verdict_id: verdict.verdict_id,
|
|
134
|
+
keyid,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* MCP tool handler — wraps {@link exportAttestation} in the
|
|
139
|
+
* {content:[{type:'text', text}]} response shape.
|
|
140
|
+
*/
|
|
141
|
+
export async function handleExportAttestation(args) {
|
|
142
|
+
const result = await exportAttestation(args);
|
|
143
|
+
return {
|
|
144
|
+
content: [
|
|
145
|
+
{
|
|
146
|
+
type: "text",
|
|
147
|
+
text: JSON.stringify(result, null, 2),
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=export-attestation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export-attestation.js","sourceRoot":"","sources":["../../src/tools/export-attestation.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/rules.d.ts
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/tools/rules.js
CHANGED
|
File without changes
|
package/dist/tools/rules.js.map
CHANGED
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: ship_confidence_check
|
|
3
|
+
*
|
|
4
|
+
* Invokes the ShipConfidenceGate for a given artifact_id and returns a
|
|
5
|
+
* structured result. The audit ledger is written by the gate itself.
|
|
6
|
+
*/
|
|
7
|
+
export declare function handleShipConfidenceCheck(args: {
|
|
8
|
+
artifact_id: string;
|
|
9
|
+
command_preview?: string;
|
|
10
|
+
label?: string;
|
|
11
|
+
}): Promise<{
|
|
12
|
+
content: {
|
|
13
|
+
type: "text";
|
|
14
|
+
text: string;
|
|
15
|
+
}[];
|
|
16
|
+
}>;
|
|
17
|
+
//# sourceMappingURL=ship-confidence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ship-confidence.d.ts","sourceRoot":"","sources":["../../src/tools/ship-confidence.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,wBAAsB,yBAAyB,CAAC,IAAI,EAAE;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CAmCzD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: ship_confidence_check
|
|
3
|
+
*
|
|
4
|
+
* Invokes the ShipConfidenceGate for a given artifact_id and returns a
|
|
5
|
+
* structured result. The audit ledger is written by the gate itself.
|
|
6
|
+
*/
|
|
7
|
+
import { ShipConfidenceGate } from "../engine/ship-confidence-gate.js";
|
|
8
|
+
export async function handleShipConfidenceCheck(args) {
|
|
9
|
+
// Lazy single-instance — picks up env at call time (test-friendly).
|
|
10
|
+
const gate = new ShipConfidenceGate();
|
|
11
|
+
const result = await gate.check(args.artifact_id, {
|
|
12
|
+
commandPreview: args.command_preview,
|
|
13
|
+
label: args.label,
|
|
14
|
+
});
|
|
15
|
+
const responseBody = {
|
|
16
|
+
allowed: result.decision === "allow",
|
|
17
|
+
decision: result.decision,
|
|
18
|
+
tier: result.tier,
|
|
19
|
+
reason: result.reason,
|
|
20
|
+
evidence: result.evidence,
|
|
21
|
+
verdict_id: result.verdict_id,
|
|
22
|
+
level: result.level,
|
|
23
|
+
signed_at: result.signed_at,
|
|
24
|
+
age_minutes: result.age_minutes,
|
|
25
|
+
would_have_been: result.would_have_been,
|
|
26
|
+
bypassed: result.bypassed ?? false,
|
|
27
|
+
stamp: result.stamp,
|
|
28
|
+
hook_name: result.stamp.hook_name,
|
|
29
|
+
hook_version: result.stamp.hook_version,
|
|
30
|
+
rule_name: result.stamp.rule_name,
|
|
31
|
+
rule_version: result.stamp.rule_version,
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
content: [
|
|
35
|
+
{
|
|
36
|
+
type: "text",
|
|
37
|
+
text: JSON.stringify(responseBody, null, 2),
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=ship-confidence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ship-confidence.js","sourceRoot":"","sources":["../../src/tools/ship-confidence.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,IAI/C;IACC,oEAAoE;IACpE,MAAM,IAAI,GAAG,IAAI,kBAAkB,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE;QAChD,cAAc,EAAE,IAAI,CAAC,eAAe;QACpC,KAAK,EAAE,IAAI,CAAC,KAAK;KAClB,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG;QACnB,OAAO,EAAE,MAAM,CAAC,QAAQ,KAAK,OAAO;QACpC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,KAAK;QAClC,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS;QACjC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,YAAY;QACvC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS;QACjC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,YAAY;KACxC,CAAC;IAEF,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;aAC5C;SACF;KACF,CAAC;AACJ,CAAC"}
|
package/dist/tools/update.d.ts
CHANGED
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/tools/update.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/tools/update.ts"],"names":[],"mappings":"AAgBA,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE;;;;;GA2CtF"}
|
package/dist/tools/update.js
CHANGED
|
@@ -1,24 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* update_rules MCP tool — enable/disable rules.
|
|
3
|
+
*
|
|
4
|
+
* Constitutional rules CANNOT be disabled (Builder B4 — Finding C2).
|
|
5
|
+
* Backed by `src/engine/immutability.ts` whose source of truth is the
|
|
6
|
+
* frozen CONSTITUTIONAL_RULE_IDS array in defaults.ts plus any rule
|
|
7
|
+
* with `enforcement === "constitutional"` in rules.json.
|
|
8
|
+
*
|
|
9
|
+
* Atomicity: if ANY disable target is constitutional, the WHOLE call
|
|
10
|
+
* rejects — no partial commits (per B4 brief test #5). This prevents
|
|
11
|
+
* a caller from sneaking a real disable past the guard by mixing
|
|
12
|
+
* constitutional and non-constitutional IDs.
|
|
13
|
+
*/
|
|
1
14
|
import { getConfig, saveConfig } from "../config/loader.js";
|
|
2
|
-
import {
|
|
15
|
+
import { assertCanDisable, ConstitutionalImmutableError } from "../engine/immutability.js";
|
|
3
16
|
export async function handleUpdateRules(args) {
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
17
|
+
const blocked = [];
|
|
18
|
+
if (args.disable) {
|
|
19
|
+
for (const id of args.disable) {
|
|
20
|
+
try {
|
|
21
|
+
assertCanDisable(id);
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
if (err instanceof ConstitutionalImmutableError) {
|
|
25
|
+
blocked.push(err.rule_id);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
throw err;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (blocked.length > 0) {
|
|
8
34
|
return {
|
|
9
35
|
content: [{
|
|
10
36
|
type: "text",
|
|
11
|
-
text: JSON.stringify({
|
|
37
|
+
text: JSON.stringify({
|
|
38
|
+
error: "CONSTITUTIONAL_RULE_IMMUTABLE",
|
|
39
|
+
rule_ids: blocked,
|
|
40
|
+
message: "Constitutional rules cannot be disabled via update_rules",
|
|
41
|
+
}),
|
|
12
42
|
}],
|
|
13
43
|
};
|
|
14
44
|
}
|
|
45
|
+
const cfg = getConfig();
|
|
15
46
|
const active = new Set(cfg.active_rules);
|
|
16
47
|
if (args.enable)
|
|
17
|
-
args.enable.forEach(id => active.add(id));
|
|
48
|
+
args.enable.forEach((id) => active.add(id));
|
|
18
49
|
if (args.disable)
|
|
19
|
-
args.disable.forEach(id => active.delete(id));
|
|
50
|
+
args.disable.forEach((id) => active.delete(id));
|
|
20
51
|
cfg.active_rules = [...active];
|
|
21
52
|
saveConfig(cfg);
|
|
22
|
-
return {
|
|
53
|
+
return {
|
|
54
|
+
content: [{
|
|
55
|
+
type: "text",
|
|
56
|
+
text: JSON.stringify({ updated: true, active_count: cfg.active_rules.length }),
|
|
57
|
+
}],
|
|
58
|
+
};
|
|
23
59
|
}
|
|
24
60
|
//# sourceMappingURL=update.js.map
|
package/dist/tools/update.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/tools/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/tools/update.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAE3F,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAA+C;IACrF,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,gBAAgB,CAAC,EAAE,CAAC,CAAC;YACvB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,4BAA4B,EAAE,CAAC;oBAChD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC5B,CAAC;qBAAM,CAAC;oBACN,MAAM,GAAG,CAAC;gBACZ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,KAAK,EAAE,+BAA+B;wBACtC,QAAQ,EAAE,OAAO;wBACjB,OAAO,EAAE,0DAA0D;qBACpE,CAAC;iBACH,CAAC;SACH,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACzC,IAAI,IAAI,CAAC,MAAM;QAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,IAAI,IAAI,CAAC,OAAO;QAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAClE,GAAG,CAAC,YAAY,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAC/B,UAAU,CAAC,GAAG,CAAC,CAAC;IAEhB,OAAO;QACL,OAAO,EAAE,CAAC;gBACR,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;aAC/E,CAAC;KACH,CAAC;AACJ,CAAC"}
|
package/dist/tools/validate.d.ts
CHANGED
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/tools/validate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/tools/validate.ts"],"names":[],"mappings":"AAQA,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;GA6EpF"}
|