@quint-security/core 0.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/dist/auth-db.d.ts +17 -0
- package/dist/auth-db.d.ts.map +1 -0
- package/dist/auth-db.js +112 -0
- package/dist/auth-db.js.map +1 -0
- package/dist/auth.d.ts +41 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +101 -0
- package/dist/auth.js.map +1 -0
- package/dist/config.d.ts +20 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +143 -0
- package/dist/config.js.map +1 -0
- package/dist/crypto.d.ts +11 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +89 -0
- package/dist/crypto.js.map +1 -0
- package/dist/db.d.ts +31 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +157 -0
- package/dist/db.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/log.d.ts +15 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +36 -0
- package/dist/log.js.map +1 -0
- package/dist/risk.d.ts +72 -0
- package/dist/risk.d.ts.map +1 -0
- package/dist/risk.js +177 -0
- package/dist/risk.js.map +1 -0
- package/dist/types.d.ts +89 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +35 -0
- package/dist/types.js.map +1 -0
- package/package.json +25 -0
- package/src/auth-db.ts +130 -0
- package/src/auth.ts +113 -0
- package/src/config.ts +163 -0
- package/src/crypto.ts +96 -0
- package/src/db.ts +184 -0
- package/src/index.ts +8 -0
- package/src/log.ts +32 -0
- package/src/risk.ts +228 -0
- package/src/types.ts +133 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ApiKey, Session } from "./types.js";
|
|
2
|
+
export declare class AuthDb {
|
|
3
|
+
private db;
|
|
4
|
+
constructor(dbPath: string);
|
|
5
|
+
insertApiKey(key: ApiKey): void;
|
|
6
|
+
getApiKeyByHash(keyHash: string): ApiKey | undefined;
|
|
7
|
+
getApiKeyById(id: string): ApiKey | undefined;
|
|
8
|
+
listApiKeys(ownerId?: string): ApiKey[];
|
|
9
|
+
revokeApiKey(id: string): boolean;
|
|
10
|
+
insertSession(session: Session): void;
|
|
11
|
+
getSession(id: string): Session | undefined;
|
|
12
|
+
revokeSession(id: string): boolean;
|
|
13
|
+
revokeSessionsBySubject(subjectId: string): number;
|
|
14
|
+
close(): void;
|
|
15
|
+
}
|
|
16
|
+
export declare function openAuthDb(dataDir: string): AuthDb;
|
|
17
|
+
//# sourceMappingURL=auth-db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-db.d.ts","sourceRoot":"","sources":["../src/auth-db.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA6BlD,qBAAa,MAAM;IACjB,OAAO,CAAC,EAAE,CAAoB;gBAElB,MAAM,EAAE,MAAM;IAS1B,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAU/B,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAQpD,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAQ7C,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE;IAWvC,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IASjC,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAUrC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAQ3C,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAOlC,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAOlD,KAAK,IAAI,IAAI;CAGd;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElD"}
|
package/dist/auth-db.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AuthDb = void 0;
|
|
7
|
+
exports.openAuthDb = openAuthDb;
|
|
8
|
+
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
9
|
+
const node_fs_1 = require("node:fs");
|
|
10
|
+
const node_path_1 = require("node:path");
|
|
11
|
+
const AUTH_SCHEMA = `
|
|
12
|
+
CREATE TABLE IF NOT EXISTS api_keys (
|
|
13
|
+
id TEXT PRIMARY KEY,
|
|
14
|
+
key_hash TEXT NOT NULL UNIQUE,
|
|
15
|
+
owner_id TEXT NOT NULL,
|
|
16
|
+
label TEXT NOT NULL,
|
|
17
|
+
scopes TEXT NOT NULL DEFAULT '',
|
|
18
|
+
created_at TEXT NOT NULL,
|
|
19
|
+
expires_at TEXT,
|
|
20
|
+
revoked INTEGER NOT NULL DEFAULT 0
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
24
|
+
id TEXT PRIMARY KEY,
|
|
25
|
+
subject_id TEXT NOT NULL,
|
|
26
|
+
auth_method TEXT NOT NULL,
|
|
27
|
+
scopes TEXT NOT NULL DEFAULT '',
|
|
28
|
+
issued_at TEXT NOT NULL,
|
|
29
|
+
expires_at TEXT NOT NULL,
|
|
30
|
+
revoked INTEGER NOT NULL DEFAULT 0
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
CREATE INDEX IF NOT EXISTS idx_api_keys_hash ON api_keys(key_hash);
|
|
34
|
+
CREATE INDEX IF NOT EXISTS idx_api_keys_owner ON api_keys(owner_id);
|
|
35
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_subject ON sessions(subject_id);
|
|
36
|
+
`;
|
|
37
|
+
class AuthDb {
|
|
38
|
+
db;
|
|
39
|
+
constructor(dbPath) {
|
|
40
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(dbPath), { recursive: true });
|
|
41
|
+
this.db = new better_sqlite3_1.default(dbPath);
|
|
42
|
+
this.db.pragma("journal_mode = WAL");
|
|
43
|
+
this.db.exec(AUTH_SCHEMA);
|
|
44
|
+
}
|
|
45
|
+
// ── API Keys ──────────────────────────────────────────────────
|
|
46
|
+
insertApiKey(key) {
|
|
47
|
+
this.db.prepare(`
|
|
48
|
+
INSERT INTO api_keys (id, key_hash, owner_id, label, scopes, created_at, expires_at, revoked)
|
|
49
|
+
VALUES (@id, @key_hash, @owner_id, @label, @scopes, @created_at, @expires_at, @revoked)
|
|
50
|
+
`).run({
|
|
51
|
+
...key,
|
|
52
|
+
revoked: key.revoked ? 1 : 0,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
getApiKeyByHash(keyHash) {
|
|
56
|
+
const row = this.db.prepare("SELECT * FROM api_keys WHERE key_hash = ?").get(keyHash);
|
|
57
|
+
if (!row)
|
|
58
|
+
return undefined;
|
|
59
|
+
return { ...row, revoked: row.revoked === 1 };
|
|
60
|
+
}
|
|
61
|
+
getApiKeyById(id) {
|
|
62
|
+
const row = this.db.prepare("SELECT * FROM api_keys WHERE id = ?").get(id);
|
|
63
|
+
if (!row)
|
|
64
|
+
return undefined;
|
|
65
|
+
return { ...row, revoked: row.revoked === 1 };
|
|
66
|
+
}
|
|
67
|
+
listApiKeys(ownerId) {
|
|
68
|
+
const query = ownerId
|
|
69
|
+
? "SELECT * FROM api_keys WHERE owner_id = ? ORDER BY created_at DESC"
|
|
70
|
+
: "SELECT * FROM api_keys ORDER BY created_at DESC";
|
|
71
|
+
const rows = (ownerId
|
|
72
|
+
? this.db.prepare(query).all(ownerId)
|
|
73
|
+
: this.db.prepare(query).all());
|
|
74
|
+
return rows.map((r) => ({ ...r, revoked: r.revoked === 1 }));
|
|
75
|
+
}
|
|
76
|
+
revokeApiKey(id) {
|
|
77
|
+
const result = this.db.prepare("UPDATE api_keys SET revoked = 1 WHERE id = ?").run(id);
|
|
78
|
+
return result.changes > 0;
|
|
79
|
+
}
|
|
80
|
+
// ── Sessions ──────────────────────────────────────────────────
|
|
81
|
+
insertSession(session) {
|
|
82
|
+
this.db.prepare(`
|
|
83
|
+
INSERT INTO sessions (id, subject_id, auth_method, scopes, issued_at, expires_at, revoked)
|
|
84
|
+
VALUES (@id, @subject_id, @auth_method, @scopes, @issued_at, @expires_at, @revoked)
|
|
85
|
+
`).run({
|
|
86
|
+
...session,
|
|
87
|
+
revoked: session.revoked ? 1 : 0,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
getSession(id) {
|
|
91
|
+
const row = this.db.prepare("SELECT * FROM sessions WHERE id = ?").get(id);
|
|
92
|
+
if (!row)
|
|
93
|
+
return undefined;
|
|
94
|
+
return { ...row, revoked: row.revoked === 1 };
|
|
95
|
+
}
|
|
96
|
+
revokeSession(id) {
|
|
97
|
+
const result = this.db.prepare("UPDATE sessions SET revoked = 1 WHERE id = ?").run(id);
|
|
98
|
+
return result.changes > 0;
|
|
99
|
+
}
|
|
100
|
+
revokeSessionsBySubject(subjectId) {
|
|
101
|
+
const result = this.db.prepare("UPDATE sessions SET revoked = 1 WHERE subject_id = ? AND revoked = 0").run(subjectId);
|
|
102
|
+
return result.changes;
|
|
103
|
+
}
|
|
104
|
+
close() {
|
|
105
|
+
this.db.close();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
exports.AuthDb = AuthDb;
|
|
109
|
+
function openAuthDb(dataDir) {
|
|
110
|
+
return new AuthDb((0, node_path_1.join)(dataDir, "auth.db"));
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=auth-db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-db.js","sourceRoot":"","sources":["../src/auth-db.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ApiKey, Session } from "./types.js";
|
|
2
|
+
import type { AuthDb } from "./auth-db.js";
|
|
3
|
+
/**
|
|
4
|
+
* Generate a new API key. Returns the raw key (shown once) and the stored record.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateApiKey(db: AuthDb, opts: {
|
|
7
|
+
label: string;
|
|
8
|
+
ownerId?: string;
|
|
9
|
+
scopes?: string[];
|
|
10
|
+
ttlSeconds?: number;
|
|
11
|
+
}): {
|
|
12
|
+
rawKey: string;
|
|
13
|
+
apiKey: ApiKey;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Verify a raw API key. Returns the key record if valid, undefined otherwise.
|
|
17
|
+
*/
|
|
18
|
+
export declare function verifyApiKey(db: AuthDb, rawKey: string): ApiKey | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Create a session after successful authentication.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createSession(db: AuthDb, opts: {
|
|
23
|
+
subjectId: string;
|
|
24
|
+
authMethod: string;
|
|
25
|
+
scopes?: string;
|
|
26
|
+
ttlMs?: number;
|
|
27
|
+
}): Session;
|
|
28
|
+
/**
|
|
29
|
+
* Validate a session token. Returns the session if valid, undefined otherwise.
|
|
30
|
+
*/
|
|
31
|
+
export declare function validateSession(db: AuthDb, token: string): Session | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Authenticate a bearer token — could be a raw API key or a session token.
|
|
34
|
+
* Returns { type, subject, scopes } if valid, undefined otherwise.
|
|
35
|
+
*/
|
|
36
|
+
export declare function authenticateBearer(db: AuthDb, token: string): {
|
|
37
|
+
type: "api_key" | "session";
|
|
38
|
+
subjectId: string;
|
|
39
|
+
scopes: string;
|
|
40
|
+
} | undefined;
|
|
41
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAW3C;;GAEG;AACH,wBAAgB,cAAc,CAC5B,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAChF;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAqBpC;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAO3E;AAID;;GAEG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/E,OAAO,CAgBT;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAM9E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,GACZ;IAAE,IAAI,EAAE,SAAS,GAAG,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAchF"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateApiKey = generateApiKey;
|
|
4
|
+
exports.verifyApiKey = verifyApiKey;
|
|
5
|
+
exports.createSession = createSession;
|
|
6
|
+
exports.validateSession = validateSession;
|
|
7
|
+
exports.authenticateBearer = authenticateBearer;
|
|
8
|
+
const node_crypto_1 = require("node:crypto");
|
|
9
|
+
const API_KEY_PREFIX = "qk_";
|
|
10
|
+
const DEFAULT_SESSION_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
11
|
+
// ── API Key management ──────────────────────────────────────────
|
|
12
|
+
function hashKey(rawKey) {
|
|
13
|
+
return (0, node_crypto_1.createHash)("sha256").update(rawKey, "utf-8").digest("hex");
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Generate a new API key. Returns the raw key (shown once) and the stored record.
|
|
17
|
+
*/
|
|
18
|
+
function generateApiKey(db, opts) {
|
|
19
|
+
const rawKey = API_KEY_PREFIX + (0, node_crypto_1.randomBytes)(32).toString("hex");
|
|
20
|
+
const id = API_KEY_PREFIX + (0, node_crypto_1.randomUUID)().replace(/-/g, "").substring(0, 16);
|
|
21
|
+
const now = new Date().toISOString();
|
|
22
|
+
const expiresAt = opts.ttlSeconds && opts.ttlSeconds > 0
|
|
23
|
+
? new Date(Date.now() + opts.ttlSeconds * 1000).toISOString()
|
|
24
|
+
: null;
|
|
25
|
+
const apiKey = {
|
|
26
|
+
id,
|
|
27
|
+
key_hash: hashKey(rawKey),
|
|
28
|
+
owner_id: opts.ownerId ?? "local",
|
|
29
|
+
label: opts.label,
|
|
30
|
+
scopes: (opts.scopes ?? []).join(","),
|
|
31
|
+
created_at: now,
|
|
32
|
+
expires_at: expiresAt,
|
|
33
|
+
revoked: false,
|
|
34
|
+
};
|
|
35
|
+
db.insertApiKey(apiKey);
|
|
36
|
+
return { rawKey, apiKey };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Verify a raw API key. Returns the key record if valid, undefined otherwise.
|
|
40
|
+
*/
|
|
41
|
+
function verifyApiKey(db, rawKey) {
|
|
42
|
+
const hash = hashKey(rawKey);
|
|
43
|
+
const key = db.getApiKeyByHash(hash);
|
|
44
|
+
if (!key)
|
|
45
|
+
return undefined;
|
|
46
|
+
if (key.revoked)
|
|
47
|
+
return undefined;
|
|
48
|
+
if (key.expires_at && new Date(key.expires_at) < new Date())
|
|
49
|
+
return undefined;
|
|
50
|
+
return key;
|
|
51
|
+
}
|
|
52
|
+
// ── Session management ──────────────────────────────────────────
|
|
53
|
+
/**
|
|
54
|
+
* Create a session after successful authentication.
|
|
55
|
+
*/
|
|
56
|
+
function createSession(db, opts) {
|
|
57
|
+
const now = new Date();
|
|
58
|
+
const ttl = opts.ttlMs ?? DEFAULT_SESSION_TTL_MS;
|
|
59
|
+
const session = {
|
|
60
|
+
id: (0, node_crypto_1.randomUUID)(),
|
|
61
|
+
subject_id: opts.subjectId,
|
|
62
|
+
auth_method: opts.authMethod,
|
|
63
|
+
scopes: opts.scopes ?? "",
|
|
64
|
+
issued_at: now.toISOString(),
|
|
65
|
+
expires_at: new Date(now.getTime() + ttl).toISOString(),
|
|
66
|
+
revoked: false,
|
|
67
|
+
};
|
|
68
|
+
db.insertSession(session);
|
|
69
|
+
return session;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Validate a session token. Returns the session if valid, undefined otherwise.
|
|
73
|
+
*/
|
|
74
|
+
function validateSession(db, token) {
|
|
75
|
+
const session = db.getSession(token);
|
|
76
|
+
if (!session)
|
|
77
|
+
return undefined;
|
|
78
|
+
if (session.revoked)
|
|
79
|
+
return undefined;
|
|
80
|
+
if (new Date(session.expires_at) < new Date())
|
|
81
|
+
return undefined;
|
|
82
|
+
return session;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Authenticate a bearer token — could be a raw API key or a session token.
|
|
86
|
+
* Returns { type, subject, scopes } if valid, undefined otherwise.
|
|
87
|
+
*/
|
|
88
|
+
function authenticateBearer(db, token) {
|
|
89
|
+
// Try as session first (UUIDs are shorter, faster lookup)
|
|
90
|
+
const session = validateSession(db, token);
|
|
91
|
+
if (session) {
|
|
92
|
+
return { type: "session", subjectId: session.subject_id, scopes: session.scopes };
|
|
93
|
+
}
|
|
94
|
+
// Try as raw API key
|
|
95
|
+
const key = verifyApiKey(db, token);
|
|
96
|
+
if (key) {
|
|
97
|
+
return { type: "api_key", subjectId: key.id, scopes: key.scopes };
|
|
98
|
+
}
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PolicyConfig, Verdict } from "./types.js";
|
|
2
|
+
export declare function resolveDataDir(raw: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* Load policy from either:
|
|
5
|
+
* - a direct file path ending in .json
|
|
6
|
+
* - a data directory containing policy.json
|
|
7
|
+
* - QUINT_DATA_DIR env var
|
|
8
|
+
* - default ~/.quint
|
|
9
|
+
*/
|
|
10
|
+
export declare function loadPolicy(pathOrDir?: string): PolicyConfig;
|
|
11
|
+
export declare function initPolicy(dataDir?: string): string;
|
|
12
|
+
export declare function validatePolicy(config: PolicyConfig): string[];
|
|
13
|
+
/**
|
|
14
|
+
* Match a string against a pattern with glob wildcards.
|
|
15
|
+
* Supports: * (any chars), ? (single char).
|
|
16
|
+
* Examples: "write_*" matches "write_file", "Mechanic*" matches "MechanicRunTool"
|
|
17
|
+
*/
|
|
18
|
+
export declare function globMatch(pattern: string, value: string): boolean;
|
|
19
|
+
export declare function evaluatePolicy(config: PolicyConfig, serverName: string, toolName: string | null): Verdict;
|
|
20
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAwB,OAAO,EAAE,MAAM,YAAY,CAAC;AAe9E,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKlD;AAID;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,CAyB3D;AAID,wBAAgB,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAWnD;AAID,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,EAAE,CAiC7D;AAID;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CASjE;AAID,wBAAgB,cAAc,CAC5B,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,GACtB,OAAO,CAyBT"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveDataDir = resolveDataDir;
|
|
4
|
+
exports.loadPolicy = loadPolicy;
|
|
5
|
+
exports.initPolicy = initPolicy;
|
|
6
|
+
exports.validatePolicy = validatePolicy;
|
|
7
|
+
exports.globMatch = globMatch;
|
|
8
|
+
exports.evaluatePolicy = evaluatePolicy;
|
|
9
|
+
const node_fs_1 = require("node:fs");
|
|
10
|
+
const node_path_1 = require("node:path");
|
|
11
|
+
const node_os_1 = require("node:os");
|
|
12
|
+
const DEFAULT_DATA_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), ".quint");
|
|
13
|
+
const DEFAULT_POLICY = {
|
|
14
|
+
version: 1,
|
|
15
|
+
data_dir: "~/.quint",
|
|
16
|
+
log_level: "info",
|
|
17
|
+
servers: [
|
|
18
|
+
{ server: "*", default_action: "allow", tools: [] },
|
|
19
|
+
],
|
|
20
|
+
};
|
|
21
|
+
// ── Resolve ~ in paths ──────────────────────────────────────────
|
|
22
|
+
function resolveDataDir(raw) {
|
|
23
|
+
if (raw.startsWith("~/")) {
|
|
24
|
+
return (0, node_path_1.join)((0, node_os_1.homedir)(), raw.slice(2));
|
|
25
|
+
}
|
|
26
|
+
return raw;
|
|
27
|
+
}
|
|
28
|
+
// ── Load policy ─────────────────────────────────────────────────
|
|
29
|
+
/**
|
|
30
|
+
* Load policy from either:
|
|
31
|
+
* - a direct file path ending in .json
|
|
32
|
+
* - a data directory containing policy.json
|
|
33
|
+
* - QUINT_DATA_DIR env var
|
|
34
|
+
* - default ~/.quint
|
|
35
|
+
*/
|
|
36
|
+
function loadPolicy(pathOrDir) {
|
|
37
|
+
const envDir = process.env.QUINT_DATA_DIR;
|
|
38
|
+
let policyPath;
|
|
39
|
+
let dir;
|
|
40
|
+
if (pathOrDir && pathOrDir.endsWith(".json")) {
|
|
41
|
+
// Direct path to a policy file
|
|
42
|
+
policyPath = pathOrDir;
|
|
43
|
+
dir = (0, node_path_1.dirname)(policyPath);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
dir = pathOrDir ?? envDir ?? DEFAULT_DATA_DIR;
|
|
47
|
+
policyPath = (0, node_path_1.join)(dir, "policy.json");
|
|
48
|
+
}
|
|
49
|
+
if (!(0, node_fs_1.existsSync)(policyPath)) {
|
|
50
|
+
return { ...DEFAULT_POLICY, data_dir: dir };
|
|
51
|
+
}
|
|
52
|
+
const raw = (0, node_fs_1.readFileSync)(policyPath, "utf-8");
|
|
53
|
+
const parsed = JSON.parse(raw);
|
|
54
|
+
return {
|
|
55
|
+
...parsed,
|
|
56
|
+
data_dir: resolveDataDir(parsed.data_dir ?? dir),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// ── Save/init policy ────────────────────────────────────────────
|
|
60
|
+
function initPolicy(dataDir) {
|
|
61
|
+
const dir = dataDir ?? DEFAULT_DATA_DIR;
|
|
62
|
+
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
63
|
+
const policyPath = (0, node_path_1.join)(dir, "policy.json");
|
|
64
|
+
if ((0, node_fs_1.existsSync)(policyPath)) {
|
|
65
|
+
return policyPath;
|
|
66
|
+
}
|
|
67
|
+
(0, node_fs_1.writeFileSync)(policyPath, JSON.stringify(DEFAULT_POLICY, null, 2) + "\n");
|
|
68
|
+
return policyPath;
|
|
69
|
+
}
|
|
70
|
+
// ── Validate policy ─────────────────────────────────────────────
|
|
71
|
+
function validatePolicy(config) {
|
|
72
|
+
const errors = [];
|
|
73
|
+
if (config.version !== 1) {
|
|
74
|
+
errors.push(`Unsupported policy version: ${config.version}`);
|
|
75
|
+
}
|
|
76
|
+
if (!Array.isArray(config.servers)) {
|
|
77
|
+
errors.push("'servers' must be an array");
|
|
78
|
+
return errors;
|
|
79
|
+
}
|
|
80
|
+
for (const srv of config.servers) {
|
|
81
|
+
if (!srv.server || typeof srv.server !== "string") {
|
|
82
|
+
errors.push("Each server entry must have a 'server' name string");
|
|
83
|
+
}
|
|
84
|
+
if (!["allow", "deny"].includes(srv.default_action)) {
|
|
85
|
+
errors.push(`Invalid default_action '${srv.default_action}' for server '${srv.server}'`);
|
|
86
|
+
}
|
|
87
|
+
if (!Array.isArray(srv.tools)) {
|
|
88
|
+
errors.push(`'tools' must be an array for server '${srv.server}'`);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
for (const rule of srv.tools) {
|
|
92
|
+
if (!rule.tool || typeof rule.tool !== "string") {
|
|
93
|
+
errors.push(`Tool rule missing 'tool' name in server '${srv.server}'`);
|
|
94
|
+
}
|
|
95
|
+
if (!["allow", "deny"].includes(rule.action)) {
|
|
96
|
+
errors.push(`Invalid action '${rule.action}' for tool '${rule.tool}' in server '${srv.server}'`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return errors;
|
|
101
|
+
}
|
|
102
|
+
// ── Glob matching ───────────────────────────────────────────────
|
|
103
|
+
/**
|
|
104
|
+
* Match a string against a pattern with glob wildcards.
|
|
105
|
+
* Supports: * (any chars), ? (single char).
|
|
106
|
+
* Examples: "write_*" matches "write_file", "Mechanic*" matches "MechanicRunTool"
|
|
107
|
+
*/
|
|
108
|
+
function globMatch(pattern, value) {
|
|
109
|
+
if (pattern === value || pattern === "*")
|
|
110
|
+
return true;
|
|
111
|
+
// Convert glob to regex: escape special chars, then replace * and ?
|
|
112
|
+
const escaped = pattern
|
|
113
|
+
.replace(/[.+^${}()|[\]\\]/g, "\\$&")
|
|
114
|
+
.replace(/\*/g, ".*")
|
|
115
|
+
.replace(/\?/g, ".");
|
|
116
|
+
return new RegExp(`^${escaped}$`).test(value);
|
|
117
|
+
}
|
|
118
|
+
// ── Evaluate policy for a tool call ─────────────────────────────
|
|
119
|
+
function evaluatePolicy(config, serverName, toolName) {
|
|
120
|
+
// Find matching server policy (first match wins, * is wildcard)
|
|
121
|
+
let serverPolicy;
|
|
122
|
+
for (const sp of config.servers) {
|
|
123
|
+
if (globMatch(sp.server, serverName)) {
|
|
124
|
+
serverPolicy = sp;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// No server match = fail closed
|
|
129
|
+
if (!serverPolicy)
|
|
130
|
+
return "deny";
|
|
131
|
+
// If no tool name (not a tools/call), passthrough
|
|
132
|
+
if (!toolName)
|
|
133
|
+
return "passthrough";
|
|
134
|
+
// Check tool-specific rules (first match wins, supports glob patterns)
|
|
135
|
+
for (const rule of serverPolicy.tools) {
|
|
136
|
+
if (globMatch(rule.tool, toolName)) {
|
|
137
|
+
return rule.action;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Fall back to server default
|
|
141
|
+
return serverPolicy.default_action;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { KeyPair } from "./types.js";
|
|
2
|
+
export declare function generateKeyPair(): KeyPair;
|
|
3
|
+
export declare function saveKeyPair(dataDir: string, kp: KeyPair): void;
|
|
4
|
+
export declare function loadKeyPair(dataDir: string): KeyPair | null;
|
|
5
|
+
export declare function ensureKeyPair(dataDir: string): KeyPair;
|
|
6
|
+
export declare function signData(data: string, privateKeyPem: string): string;
|
|
7
|
+
export declare function verifySignature(data: string, signatureHex: string, publicKeyPem: string): boolean;
|
|
8
|
+
export declare function canonicalize(obj: Record<string, unknown>): string;
|
|
9
|
+
export declare function sha256(data: string): string;
|
|
10
|
+
export declare function publicKeyFingerprint(publicKeyPem: string): string;
|
|
11
|
+
//# sourceMappingURL=crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAM1C,wBAAgB,eAAe,IAAI,OAAO,CAMzC;AAID,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CAW9D;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAU3D;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAMtD;AAID,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAIpE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAIjG;AAYD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAEjE;AAID,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3C;AAID,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAOjE"}
|
package/dist/crypto.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateKeyPair = generateKeyPair;
|
|
4
|
+
exports.saveKeyPair = saveKeyPair;
|
|
5
|
+
exports.loadKeyPair = loadKeyPair;
|
|
6
|
+
exports.ensureKeyPair = ensureKeyPair;
|
|
7
|
+
exports.signData = signData;
|
|
8
|
+
exports.verifySignature = verifySignature;
|
|
9
|
+
exports.canonicalize = canonicalize;
|
|
10
|
+
exports.sha256 = sha256;
|
|
11
|
+
exports.publicKeyFingerprint = publicKeyFingerprint;
|
|
12
|
+
const node_crypto_1 = require("node:crypto");
|
|
13
|
+
const node_fs_1 = require("node:fs");
|
|
14
|
+
const node_path_1 = require("node:path");
|
|
15
|
+
const ALGORITHM = "Ed25519";
|
|
16
|
+
// ── Key generation ──────────────────────────────────────────────
|
|
17
|
+
function generateKeyPair() {
|
|
18
|
+
const { publicKey, privateKey } = (0, node_crypto_1.generateKeyPairSync)("ed25519", {
|
|
19
|
+
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
20
|
+
privateKeyEncoding: { type: "pkcs8", format: "pem" },
|
|
21
|
+
});
|
|
22
|
+
return { publicKey, privateKey };
|
|
23
|
+
}
|
|
24
|
+
// ── Key persistence ─────────────────────────────────────────────
|
|
25
|
+
function saveKeyPair(dataDir, kp) {
|
|
26
|
+
const keysDir = (0, node_path_1.join)(dataDir, "keys");
|
|
27
|
+
(0, node_fs_1.mkdirSync)(keysDir, { recursive: true });
|
|
28
|
+
const privPath = (0, node_path_1.join)(keysDir, "quint.key");
|
|
29
|
+
const pubPath = (0, node_path_1.join)(keysDir, "quint.pub");
|
|
30
|
+
(0, node_fs_1.writeFileSync)(privPath, kp.privateKey, { mode: 0o600 });
|
|
31
|
+
// Ensure permission is set even if file existed
|
|
32
|
+
(0, node_fs_1.chmodSync)(privPath, 0o600);
|
|
33
|
+
(0, node_fs_1.writeFileSync)(pubPath, kp.publicKey, { mode: 0o644 });
|
|
34
|
+
}
|
|
35
|
+
function loadKeyPair(dataDir) {
|
|
36
|
+
const privPath = (0, node_path_1.join)(dataDir, "keys", "quint.key");
|
|
37
|
+
const pubPath = (0, node_path_1.join)(dataDir, "keys", "quint.pub");
|
|
38
|
+
if (!(0, node_fs_1.existsSync)(privPath) || !(0, node_fs_1.existsSync)(pubPath))
|
|
39
|
+
return null;
|
|
40
|
+
return {
|
|
41
|
+
privateKey: (0, node_fs_1.readFileSync)(privPath, "utf-8"),
|
|
42
|
+
publicKey: (0, node_fs_1.readFileSync)(pubPath, "utf-8"),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function ensureKeyPair(dataDir) {
|
|
46
|
+
const existing = loadKeyPair(dataDir);
|
|
47
|
+
if (existing)
|
|
48
|
+
return existing;
|
|
49
|
+
const kp = generateKeyPair();
|
|
50
|
+
saveKeyPair(dataDir, kp);
|
|
51
|
+
return kp;
|
|
52
|
+
}
|
|
53
|
+
// ── Signing ─────────────────────────────────────────────────────
|
|
54
|
+
function signData(data, privateKeyPem) {
|
|
55
|
+
const key = (0, node_crypto_1.createPrivateKey)(privateKeyPem);
|
|
56
|
+
const signature = (0, node_crypto_1.sign)(null, Buffer.from(data, "utf-8"), key);
|
|
57
|
+
return signature.toString("hex");
|
|
58
|
+
}
|
|
59
|
+
function verifySignature(data, signatureHex, publicKeyPem) {
|
|
60
|
+
const key = (0, node_crypto_1.createPublicKey)(publicKeyPem);
|
|
61
|
+
const sigBuf = Buffer.from(signatureHex, "hex");
|
|
62
|
+
return (0, node_crypto_1.verify)(null, Buffer.from(data, "utf-8"), key, sigBuf);
|
|
63
|
+
}
|
|
64
|
+
// ── Canonical JSON for signing ──────────────────────────────────
|
|
65
|
+
// NOTE: This is NOT RFC 8785 (JCS) compliant. It uses simple sorted-key
|
|
66
|
+
// JSON.stringify which works correctly for ASCII strings, numbers, booleans,
|
|
67
|
+
// and null values. It may produce non-deterministic output for:
|
|
68
|
+
// - Unicode strings with special escape sequences
|
|
69
|
+
// - Numbers requiring special IEEE 754 formatting
|
|
70
|
+
// This is sufficient for the current use case where all values are ASCII
|
|
71
|
+
// strings/numbers. If interoperability with external verifiers is needed,
|
|
72
|
+
// replace with a proper RFC 8785 implementation.
|
|
73
|
+
function canonicalize(obj) {
|
|
74
|
+
return JSON.stringify(obj, Object.keys(obj).sort());
|
|
75
|
+
}
|
|
76
|
+
// ── Hashing ─────────────────────────────────────────────────────
|
|
77
|
+
function sha256(data) {
|
|
78
|
+
return (0, node_crypto_1.createHash)("sha256").update(data, "utf-8").digest("hex");
|
|
79
|
+
}
|
|
80
|
+
// ── Public key fingerprint (first 16 hex chars of key hash) ─────
|
|
81
|
+
function publicKeyFingerprint(publicKeyPem) {
|
|
82
|
+
// Use a simple approach: take first 16 chars of the base64 key body
|
|
83
|
+
const body = publicKeyPem
|
|
84
|
+
.replace(/-----BEGIN PUBLIC KEY-----/, "")
|
|
85
|
+
.replace(/-----END PUBLIC KEY-----/, "")
|
|
86
|
+
.replace(/\s/g, "");
|
|
87
|
+
return body.substring(0, 16);
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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"}
|
package/dist/db.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { AuditEntry } from "./types.js";
|
|
2
|
+
export declare class AuditDb {
|
|
3
|
+
private db;
|
|
4
|
+
constructor(dbPath: string);
|
|
5
|
+
private migrate;
|
|
6
|
+
/** Get the signature of the last entry (for hash chaining) */
|
|
7
|
+
getLastSignature(): string | null;
|
|
8
|
+
/**
|
|
9
|
+
* Atomically read the last signature and insert a new entry.
|
|
10
|
+
* This prevents chain breaks when multiple proxy instances share a DB.
|
|
11
|
+
*/
|
|
12
|
+
insertAtomic(buildEntry: (prevSignature: string | null) => Omit<AuditEntry, "id">): number;
|
|
13
|
+
insert(entry: Omit<AuditEntry, "id">): number;
|
|
14
|
+
getById(id: number): AuditEntry | undefined;
|
|
15
|
+
/** Get entries in ID order (ascending) for chain verification */
|
|
16
|
+
getRange(startId: number, endId: number): AuditEntry[];
|
|
17
|
+
/** Get all entries in ID order (ascending) for chain verification */
|
|
18
|
+
getAll(): AuditEntry[];
|
|
19
|
+
query(opts?: {
|
|
20
|
+
server?: string;
|
|
21
|
+
tool?: string;
|
|
22
|
+
verdict?: string;
|
|
23
|
+
since?: string;
|
|
24
|
+
limit?: number;
|
|
25
|
+
}): AuditEntry[];
|
|
26
|
+
getLast(n: number): AuditEntry[];
|
|
27
|
+
count(): number;
|
|
28
|
+
close(): void;
|
|
29
|
+
}
|
|
30
|
+
export declare function openAuditDb(dataDir: string): AuditDb;
|
|
31
|
+
//# sourceMappingURL=db.d.ts.map
|
package/dist/db.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAsC7C,qBAAa,OAAO;IAClB,OAAO,CAAC,EAAE,CAAoB;gBAElB,MAAM,EAAE,MAAM;IAQ1B,OAAO,CAAC,OAAO;IAUf,8DAA8D;IAC9D,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAOjC;;;OAGG;IACH,YAAY,CAAC,UAAU,EAAE,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,MAAM;IAyB1F,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,MAAM;IAe7C,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI3C,iEAAiE;IACjE,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE;IAMtD,qEAAqE;IACrE,MAAM,IAAI,UAAU,EAAE;IAItB,KAAK,CAAC,IAAI,GAAE;QACV,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KACX,GAAG,UAAU,EAAE;IA6BrB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE;IAMhC,KAAK,IAAI,MAAM;IAKf,KAAK,IAAI,IAAI;CAGd;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEpD"}
|