@attest-it/core 0.0.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.
- package/README.md +126 -0
- package/dist/chunk-UWYR7JNE.js +212 -0
- package/dist/chunk-UWYR7JNE.js.map +1 -0
- package/dist/core-alpha.d.ts +711 -0
- package/dist/core-beta.d.ts +711 -0
- package/dist/core-public.d.ts +711 -0
- package/dist/core-unstripped.d.ts +711 -0
- package/dist/crypto-ITLMIMRJ.js +3 -0
- package/dist/crypto-ITLMIMRJ.js.map +1 -0
- package/dist/index.cjs +915 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +691 -0
- package/dist/index.d.ts +691 -0
- package/dist/index.js +629 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,915 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var child_process = require('child_process');
|
|
4
|
+
var fs2 = require('fs/promises');
|
|
5
|
+
var path2 = require('path');
|
|
6
|
+
var os = require('os');
|
|
7
|
+
var fs = require('fs');
|
|
8
|
+
var yaml = require('yaml');
|
|
9
|
+
var zod = require('zod');
|
|
10
|
+
var crypto = require('crypto');
|
|
11
|
+
var tinyglobby = require('tinyglobby');
|
|
12
|
+
var canonicalizeNamespace = require('canonicalize');
|
|
13
|
+
|
|
14
|
+
function _interopNamespace(e) {
|
|
15
|
+
if (e && e.__esModule) return e;
|
|
16
|
+
var n = Object.create(null);
|
|
17
|
+
if (e) {
|
|
18
|
+
Object.keys(e).forEach(function (k) {
|
|
19
|
+
if (k !== 'default') {
|
|
20
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
21
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () { return e[k]; }
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
n.default = e;
|
|
29
|
+
return Object.freeze(n);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var fs2__namespace = /*#__PURE__*/_interopNamespace(fs2);
|
|
33
|
+
var path2__namespace = /*#__PURE__*/_interopNamespace(path2);
|
|
34
|
+
var os__namespace = /*#__PURE__*/_interopNamespace(os);
|
|
35
|
+
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
36
|
+
var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
|
|
37
|
+
var canonicalizeNamespace__namespace = /*#__PURE__*/_interopNamespace(canonicalizeNamespace);
|
|
38
|
+
|
|
39
|
+
var __defProp = Object.defineProperty;
|
|
40
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
41
|
+
var __esm = (fn, res) => function __init() {
|
|
42
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
43
|
+
};
|
|
44
|
+
var __export = (target, all) => {
|
|
45
|
+
for (var name in all)
|
|
46
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// src/crypto.ts
|
|
50
|
+
var crypto_exports = {};
|
|
51
|
+
__export(crypto_exports, {
|
|
52
|
+
checkOpenSSL: () => checkOpenSSL,
|
|
53
|
+
generateKeyPair: () => generateKeyPair,
|
|
54
|
+
getDefaultPrivateKeyPath: () => getDefaultPrivateKeyPath,
|
|
55
|
+
getDefaultPublicKeyPath: () => getDefaultPublicKeyPath,
|
|
56
|
+
setKeyPermissions: () => setKeyPermissions,
|
|
57
|
+
sign: () => sign,
|
|
58
|
+
verify: () => verify
|
|
59
|
+
});
|
|
60
|
+
async function runOpenSSL(args, stdin) {
|
|
61
|
+
return new Promise((resolve3, reject) => {
|
|
62
|
+
const child = child_process.spawn("openssl", args, {
|
|
63
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
64
|
+
});
|
|
65
|
+
const stdoutChunks = [];
|
|
66
|
+
let stderr = "";
|
|
67
|
+
child.stdout.on("data", (chunk) => {
|
|
68
|
+
stdoutChunks.push(chunk);
|
|
69
|
+
});
|
|
70
|
+
child.stderr.on("data", (chunk) => {
|
|
71
|
+
stderr += chunk.toString();
|
|
72
|
+
});
|
|
73
|
+
child.on("error", (err) => {
|
|
74
|
+
reject(new Error(`Failed to spawn OpenSSL: ${err.message}`));
|
|
75
|
+
});
|
|
76
|
+
child.on("close", (code) => {
|
|
77
|
+
resolve3({
|
|
78
|
+
exitCode: code ?? 1,
|
|
79
|
+
stdout: Buffer.concat(stdoutChunks),
|
|
80
|
+
stderr
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
child.stdin.end();
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
async function checkOpenSSL() {
|
|
87
|
+
const result = await runOpenSSL(["version"]);
|
|
88
|
+
if (result.exitCode !== 0) {
|
|
89
|
+
throw new Error(`OpenSSL check failed: ${result.stderr}`);
|
|
90
|
+
}
|
|
91
|
+
return result.stdout.toString().trim();
|
|
92
|
+
}
|
|
93
|
+
async function ensureOpenSSLAvailable() {
|
|
94
|
+
if (openSSLChecked) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
await checkOpenSSL();
|
|
99
|
+
openSSLChecked = true;
|
|
100
|
+
} catch {
|
|
101
|
+
throw new Error(
|
|
102
|
+
"OpenSSL is not installed or not in PATH. Please install OpenSSL to use attest-it. On macOS: brew install openssl. On Ubuntu: apt-get install openssl"
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function getDefaultPrivateKeyPath() {
|
|
107
|
+
const homeDir = os__namespace.homedir();
|
|
108
|
+
if (process.platform === "win32") {
|
|
109
|
+
const appData = process.env.APPDATA ?? path2__namespace.join(homeDir, "AppData", "Roaming");
|
|
110
|
+
return path2__namespace.join(appData, "attest-it", "private.pem");
|
|
111
|
+
}
|
|
112
|
+
return path2__namespace.join(homeDir, ".config", "attest-it", "private.pem");
|
|
113
|
+
}
|
|
114
|
+
function getDefaultPublicKeyPath() {
|
|
115
|
+
return path2__namespace.join(process.cwd(), "attest-it-public.pem");
|
|
116
|
+
}
|
|
117
|
+
async function ensureDir(dirPath) {
|
|
118
|
+
try {
|
|
119
|
+
await fs2__namespace.mkdir(dirPath, { recursive: true });
|
|
120
|
+
} catch (err) {
|
|
121
|
+
if (err instanceof Error && "code" in err && err.code !== "EEXIST") {
|
|
122
|
+
throw err;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async function fileExists(filePath) {
|
|
127
|
+
try {
|
|
128
|
+
await fs2__namespace.access(filePath);
|
|
129
|
+
return true;
|
|
130
|
+
} catch {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async function cleanupFiles(...paths) {
|
|
135
|
+
for (const filePath of paths) {
|
|
136
|
+
try {
|
|
137
|
+
await fs2__namespace.unlink(filePath);
|
|
138
|
+
} catch {
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async function generateKeyPair(options = {}) {
|
|
143
|
+
await ensureOpenSSLAvailable();
|
|
144
|
+
const {
|
|
145
|
+
algorithm = "ed25519",
|
|
146
|
+
privatePath = getDefaultPrivateKeyPath(),
|
|
147
|
+
publicPath = getDefaultPublicKeyPath(),
|
|
148
|
+
force = false
|
|
149
|
+
} = options;
|
|
150
|
+
const privateExists = await fileExists(privatePath);
|
|
151
|
+
const publicExists = await fileExists(publicPath);
|
|
152
|
+
if ((privateExists || publicExists) && !force) {
|
|
153
|
+
const existing = [privateExists ? privatePath : null, publicExists ? publicPath : null].filter(
|
|
154
|
+
Boolean
|
|
155
|
+
);
|
|
156
|
+
throw new Error(
|
|
157
|
+
`Key files already exist: ${existing.join(", ")}. Use force: true to overwrite.`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
await ensureDir(path2__namespace.dirname(privatePath));
|
|
161
|
+
await ensureDir(path2__namespace.dirname(publicPath));
|
|
162
|
+
try {
|
|
163
|
+
const genArgs = algorithm === "ed25519" ? ["genpkey", "-algorithm", "Ed25519", "-out", privatePath] : ["genpkey", "-algorithm", "RSA", "-pkeyopt", "rsa_keygen_bits:2048", "-out", privatePath];
|
|
164
|
+
const genResult = await runOpenSSL(genArgs);
|
|
165
|
+
if (genResult.exitCode !== 0) {
|
|
166
|
+
throw new Error(`Failed to generate private key: ${genResult.stderr}`);
|
|
167
|
+
}
|
|
168
|
+
await setKeyPermissions(privatePath);
|
|
169
|
+
const pubResult = await runOpenSSL(["pkey", "-in", privatePath, "-pubout", "-out", publicPath]);
|
|
170
|
+
if (pubResult.exitCode !== 0) {
|
|
171
|
+
throw new Error(`Failed to extract public key: ${pubResult.stderr}`);
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
privatePath,
|
|
175
|
+
publicPath
|
|
176
|
+
};
|
|
177
|
+
} catch (err) {
|
|
178
|
+
await cleanupFiles(privatePath, publicPath);
|
|
179
|
+
throw err;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async function sign(options) {
|
|
183
|
+
await ensureOpenSSLAvailable();
|
|
184
|
+
const { privateKeyPath, data } = options;
|
|
185
|
+
if (!await fileExists(privateKeyPath)) {
|
|
186
|
+
throw new Error(`Private key not found: ${privateKeyPath}`);
|
|
187
|
+
}
|
|
188
|
+
const dataBuffer = typeof data === "string" ? Buffer.from(data, "utf8") : data;
|
|
189
|
+
const processBuffer = dataBuffer.length === 0 ? Buffer.from([0]) : dataBuffer;
|
|
190
|
+
const tmpDir = await fs2__namespace.mkdtemp(path2__namespace.join(os__namespace.tmpdir(), "attest-it-"));
|
|
191
|
+
const dataFile = path2__namespace.join(tmpDir, "data.bin");
|
|
192
|
+
const sigFile = path2__namespace.join(tmpDir, "sig.bin");
|
|
193
|
+
try {
|
|
194
|
+
await fs2__namespace.writeFile(dataFile, processBuffer);
|
|
195
|
+
const result = await runOpenSSL([
|
|
196
|
+
"pkeyutl",
|
|
197
|
+
"-sign",
|
|
198
|
+
"-inkey",
|
|
199
|
+
privateKeyPath,
|
|
200
|
+
"-in",
|
|
201
|
+
dataFile,
|
|
202
|
+
"-out",
|
|
203
|
+
sigFile
|
|
204
|
+
]);
|
|
205
|
+
if (result.exitCode !== 0) {
|
|
206
|
+
throw new Error(`Failed to sign data: ${result.stderr}`);
|
|
207
|
+
}
|
|
208
|
+
const sigBuffer = await fs2__namespace.readFile(sigFile);
|
|
209
|
+
return sigBuffer.toString("base64");
|
|
210
|
+
} finally {
|
|
211
|
+
try {
|
|
212
|
+
await fs2__namespace.rm(tmpDir, { recursive: true, force: true });
|
|
213
|
+
} catch {
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
async function verify(options) {
|
|
218
|
+
await ensureOpenSSLAvailable();
|
|
219
|
+
const { publicKeyPath, data, signature } = options;
|
|
220
|
+
if (!await fileExists(publicKeyPath)) {
|
|
221
|
+
throw new Error(`Public key not found: ${publicKeyPath}`);
|
|
222
|
+
}
|
|
223
|
+
const dataBuffer = typeof data === "string" ? Buffer.from(data, "utf8") : data;
|
|
224
|
+
const processBuffer = dataBuffer.length === 0 ? Buffer.from([0]) : dataBuffer;
|
|
225
|
+
const sigBuffer = Buffer.from(signature, "base64");
|
|
226
|
+
const tmpDir = await fs2__namespace.mkdtemp(path2__namespace.join(os__namespace.tmpdir(), "attest-it-"));
|
|
227
|
+
const dataFile = path2__namespace.join(tmpDir, "data.bin");
|
|
228
|
+
const sigFile = path2__namespace.join(tmpDir, "sig.bin");
|
|
229
|
+
try {
|
|
230
|
+
await fs2__namespace.writeFile(dataFile, processBuffer);
|
|
231
|
+
await fs2__namespace.writeFile(sigFile, sigBuffer);
|
|
232
|
+
const result = await runOpenSSL([
|
|
233
|
+
"pkeyutl",
|
|
234
|
+
"-verify",
|
|
235
|
+
"-pubin",
|
|
236
|
+
"-inkey",
|
|
237
|
+
publicKeyPath,
|
|
238
|
+
"-sigfile",
|
|
239
|
+
sigFile,
|
|
240
|
+
"-in",
|
|
241
|
+
dataFile
|
|
242
|
+
]);
|
|
243
|
+
if (result.exitCode !== 0 && result.exitCode !== 1) {
|
|
244
|
+
throw new Error(`Verification error: ${result.stderr}`);
|
|
245
|
+
}
|
|
246
|
+
return result.exitCode === 0;
|
|
247
|
+
} finally {
|
|
248
|
+
try {
|
|
249
|
+
await fs2__namespace.rm(tmpDir, { recursive: true, force: true });
|
|
250
|
+
} catch {
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
async function setKeyPermissions(keyPath) {
|
|
255
|
+
if (process.platform === "win32") {
|
|
256
|
+
await fs2__namespace.chmod(keyPath, 384);
|
|
257
|
+
} else {
|
|
258
|
+
await fs2__namespace.chmod(keyPath, 384);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
var openSSLChecked;
|
|
262
|
+
var init_crypto = __esm({
|
|
263
|
+
"src/crypto.ts"() {
|
|
264
|
+
openSSLChecked = false;
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
var settingsSchema = zod.z.object({
|
|
268
|
+
maxAgeDays: zod.z.number().int().positive().default(30),
|
|
269
|
+
publicKeyPath: zod.z.string().default(".attest-it/pubkey.pem"),
|
|
270
|
+
attestationsPath: zod.z.string().default(".attest-it/attestations.json"),
|
|
271
|
+
defaultCommand: zod.z.string().optional(),
|
|
272
|
+
algorithm: zod.z.enum(["ed25519", "rsa"]).default("ed25519")
|
|
273
|
+
}).strict();
|
|
274
|
+
var suiteSchema = zod.z.object({
|
|
275
|
+
description: zod.z.string().optional(),
|
|
276
|
+
packages: zod.z.array(zod.z.string().min(1, "Package path cannot be empty")).min(1, "At least one package pattern is required"),
|
|
277
|
+
files: zod.z.array(zod.z.string().min(1, "File path cannot be empty")).optional(),
|
|
278
|
+
ignore: zod.z.array(zod.z.string().min(1, "Ignore pattern cannot be empty")).optional(),
|
|
279
|
+
command: zod.z.string().optional(),
|
|
280
|
+
invalidates: zod.z.array(zod.z.string().min(1, "Invalidated suite name cannot be empty")).optional()
|
|
281
|
+
}).strict();
|
|
282
|
+
var configSchema = zod.z.object({
|
|
283
|
+
version: zod.z.literal(1),
|
|
284
|
+
settings: settingsSchema.default({}),
|
|
285
|
+
suites: zod.z.record(zod.z.string(), suiteSchema).refine((suites) => Object.keys(suites).length >= 1, {
|
|
286
|
+
message: "At least one suite must be defined"
|
|
287
|
+
})
|
|
288
|
+
}).strict();
|
|
289
|
+
var ConfigValidationError = class extends Error {
|
|
290
|
+
constructor(message, issues) {
|
|
291
|
+
super(message);
|
|
292
|
+
this.issues = issues;
|
|
293
|
+
this.name = "ConfigValidationError";
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
var ConfigNotFoundError = class extends Error {
|
|
297
|
+
constructor(message) {
|
|
298
|
+
super(message);
|
|
299
|
+
this.name = "ConfigNotFoundError";
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
function parseConfigContent(content, format) {
|
|
303
|
+
let rawConfig;
|
|
304
|
+
try {
|
|
305
|
+
if (format === "yaml") {
|
|
306
|
+
rawConfig = yaml.parse(content);
|
|
307
|
+
} else {
|
|
308
|
+
rawConfig = JSON.parse(content);
|
|
309
|
+
}
|
|
310
|
+
} catch (error) {
|
|
311
|
+
throw new ConfigValidationError(
|
|
312
|
+
`Failed to parse ${format.toUpperCase()}: ${error instanceof Error ? error.message : String(error)}`,
|
|
313
|
+
[]
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
const result = configSchema.safeParse(rawConfig);
|
|
317
|
+
if (!result.success) {
|
|
318
|
+
throw new ConfigValidationError(
|
|
319
|
+
"Configuration validation failed:\n" + result.error.issues.map((issue) => ` - ${issue.path.join(".")}: ${issue.message}`).join("\n"),
|
|
320
|
+
result.error.issues
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
return result.data;
|
|
324
|
+
}
|
|
325
|
+
function getConfigFormat(filePath) {
|
|
326
|
+
const ext = filePath.toLowerCase();
|
|
327
|
+
if (ext.endsWith(".yaml") || ext.endsWith(".yml")) {
|
|
328
|
+
return "yaml";
|
|
329
|
+
}
|
|
330
|
+
if (ext.endsWith(".json")) {
|
|
331
|
+
return "json";
|
|
332
|
+
}
|
|
333
|
+
return "yaml";
|
|
334
|
+
}
|
|
335
|
+
function findConfigPath(startDir = process.cwd()) {
|
|
336
|
+
const configDir = path2.join(startDir, ".attest-it");
|
|
337
|
+
const candidates = ["config.yaml", "config.yml", "config.json"];
|
|
338
|
+
for (const candidate of candidates) {
|
|
339
|
+
const configPath = path2.join(configDir, candidate);
|
|
340
|
+
try {
|
|
341
|
+
fs.readFileSync(configPath, "utf8");
|
|
342
|
+
return configPath;
|
|
343
|
+
} catch {
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
async function loadConfig(configPath) {
|
|
350
|
+
const resolvedPath = configPath ?? findConfigPath();
|
|
351
|
+
if (!resolvedPath) {
|
|
352
|
+
throw new ConfigNotFoundError(
|
|
353
|
+
"Configuration file not found. Expected .attest-it/config.yaml, .attest-it/config.yml, or .attest-it/config.json"
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
try {
|
|
357
|
+
const content = await fs2.readFile(resolvedPath, "utf8");
|
|
358
|
+
const format = getConfigFormat(resolvedPath);
|
|
359
|
+
return parseConfigContent(content, format);
|
|
360
|
+
} catch (error) {
|
|
361
|
+
if (error instanceof ConfigValidationError) {
|
|
362
|
+
throw error;
|
|
363
|
+
}
|
|
364
|
+
throw new ConfigNotFoundError(
|
|
365
|
+
`Failed to read configuration file at ${resolvedPath}: ${String(error)}`
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
function loadConfigSync(configPath) {
|
|
370
|
+
const resolvedPath = configPath ?? findConfigPath();
|
|
371
|
+
if (!resolvedPath) {
|
|
372
|
+
throw new ConfigNotFoundError(
|
|
373
|
+
"Configuration file not found. Expected .attest-it/config.yaml, .attest-it/config.yml, or .attest-it/config.json"
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
try {
|
|
377
|
+
const content = fs.readFileSync(resolvedPath, "utf8");
|
|
378
|
+
const format = getConfigFormat(resolvedPath);
|
|
379
|
+
return parseConfigContent(content, format);
|
|
380
|
+
} catch (error) {
|
|
381
|
+
if (error instanceof ConfigValidationError) {
|
|
382
|
+
throw error;
|
|
383
|
+
}
|
|
384
|
+
throw new ConfigNotFoundError(
|
|
385
|
+
`Failed to read configuration file at ${resolvedPath}: ${String(error)}`
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
function resolveConfigPaths(config, repoRoot) {
|
|
390
|
+
return {
|
|
391
|
+
...config,
|
|
392
|
+
settings: {
|
|
393
|
+
...config.settings,
|
|
394
|
+
publicKeyPath: path2.resolve(repoRoot, config.settings.publicKeyPath),
|
|
395
|
+
attestationsPath: path2.resolve(repoRoot, config.settings.attestationsPath)
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
function toAttestItConfig(config) {
|
|
400
|
+
return {
|
|
401
|
+
version: config.version,
|
|
402
|
+
settings: {
|
|
403
|
+
maxAgeDays: config.settings.maxAgeDays,
|
|
404
|
+
publicKeyPath: config.settings.publicKeyPath,
|
|
405
|
+
attestationsPath: config.settings.attestationsPath,
|
|
406
|
+
algorithm: config.settings.algorithm,
|
|
407
|
+
...config.settings.defaultCommand !== void 0 && {
|
|
408
|
+
defaultCommand: config.settings.defaultCommand
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
suites: Object.fromEntries(
|
|
412
|
+
Object.entries(config.suites).map(([name, suite]) => [
|
|
413
|
+
name,
|
|
414
|
+
{
|
|
415
|
+
packages: suite.packages,
|
|
416
|
+
...suite.description !== void 0 && { description: suite.description },
|
|
417
|
+
...suite.files !== void 0 && { files: suite.files },
|
|
418
|
+
...suite.ignore !== void 0 && { ignore: suite.ignore },
|
|
419
|
+
...suite.command !== void 0 && { command: suite.command },
|
|
420
|
+
...suite.invalidates !== void 0 && { invalidates: suite.invalidates }
|
|
421
|
+
}
|
|
422
|
+
])
|
|
423
|
+
)
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
var LARGE_FILE_THRESHOLD = 50 * 1024 * 1024;
|
|
427
|
+
function sortFiles(files) {
|
|
428
|
+
return [...files].sort((a, b) => {
|
|
429
|
+
if (a < b) return -1;
|
|
430
|
+
if (a > b) return 1;
|
|
431
|
+
return 0;
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
function normalizePath(filePath) {
|
|
435
|
+
return filePath.split(path2__namespace.sep).join("/");
|
|
436
|
+
}
|
|
437
|
+
function computeFinalFingerprint(fileHashes) {
|
|
438
|
+
const sorted = [...fileHashes].sort((a, b) => {
|
|
439
|
+
if (a.relativePath < b.relativePath) return -1;
|
|
440
|
+
if (a.relativePath > b.relativePath) return 1;
|
|
441
|
+
return 0;
|
|
442
|
+
});
|
|
443
|
+
const hashes = sorted.map((input) => input.hash);
|
|
444
|
+
const concatenated = Buffer.concat(hashes);
|
|
445
|
+
const finalHash = crypto__namespace.createHash("sha256").update(concatenated).digest();
|
|
446
|
+
return `sha256:${finalHash.toString("hex")}`;
|
|
447
|
+
}
|
|
448
|
+
async function hashFileAsync(realPath, normalizedPath, stats) {
|
|
449
|
+
if (stats.size > LARGE_FILE_THRESHOLD) {
|
|
450
|
+
return new Promise((resolve3, reject) => {
|
|
451
|
+
const hash2 = crypto__namespace.createHash("sha256");
|
|
452
|
+
hash2.update(normalizedPath);
|
|
453
|
+
hash2.update("\0");
|
|
454
|
+
const stream = fs__namespace.createReadStream(realPath);
|
|
455
|
+
stream.on("data", (chunk) => {
|
|
456
|
+
hash2.update(chunk);
|
|
457
|
+
});
|
|
458
|
+
stream.on("end", () => {
|
|
459
|
+
resolve3(hash2.digest());
|
|
460
|
+
});
|
|
461
|
+
stream.on("error", reject);
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
const content = await fs__namespace.promises.readFile(realPath);
|
|
465
|
+
const hash = crypto__namespace.createHash("sha256");
|
|
466
|
+
hash.update(normalizedPath);
|
|
467
|
+
hash.update("\0");
|
|
468
|
+
hash.update(content);
|
|
469
|
+
return hash.digest();
|
|
470
|
+
}
|
|
471
|
+
function hashFileSync(realPath, normalizedPath) {
|
|
472
|
+
const content = fs__namespace.readFileSync(realPath);
|
|
473
|
+
const hash = crypto__namespace.createHash("sha256");
|
|
474
|
+
hash.update(normalizedPath);
|
|
475
|
+
hash.update("\0");
|
|
476
|
+
hash.update(content);
|
|
477
|
+
return hash.digest();
|
|
478
|
+
}
|
|
479
|
+
function validateOptions(options) {
|
|
480
|
+
if (options.packages.length === 0) {
|
|
481
|
+
throw new Error("packages array must not be empty");
|
|
482
|
+
}
|
|
483
|
+
const baseDir = options.baseDir ?? process.cwd();
|
|
484
|
+
for (const pkg of options.packages) {
|
|
485
|
+
const pkgPath = path2__namespace.resolve(baseDir, pkg);
|
|
486
|
+
if (!fs__namespace.existsSync(pkgPath)) {
|
|
487
|
+
throw new Error(`Package path does not exist: ${pkgPath}`);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return baseDir;
|
|
491
|
+
}
|
|
492
|
+
async function computeFingerprint(options) {
|
|
493
|
+
const baseDir = validateOptions(options);
|
|
494
|
+
const files = await listPackageFiles(options.packages, options.ignore, baseDir);
|
|
495
|
+
const sortedFiles = sortFiles(files);
|
|
496
|
+
const fileHashCache = /* @__PURE__ */ new Map();
|
|
497
|
+
const fileHashInputs = [];
|
|
498
|
+
for (const file of sortedFiles) {
|
|
499
|
+
const filePath = path2__namespace.resolve(baseDir, file);
|
|
500
|
+
let realPath = filePath;
|
|
501
|
+
let stats = await fs__namespace.promises.lstat(filePath);
|
|
502
|
+
if (stats.isSymbolicLink()) {
|
|
503
|
+
try {
|
|
504
|
+
realPath = await fs__namespace.promises.realpath(filePath);
|
|
505
|
+
} catch {
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
try {
|
|
509
|
+
stats = await fs__namespace.promises.stat(realPath);
|
|
510
|
+
} catch {
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (!stats.isFile()) {
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
const normalizedPath = normalizePath(file);
|
|
518
|
+
let hash;
|
|
519
|
+
const cachedHash = fileHashCache.get(realPath);
|
|
520
|
+
if (cachedHash !== void 0) {
|
|
521
|
+
hash = cachedHash;
|
|
522
|
+
} else {
|
|
523
|
+
hash = await hashFileAsync(realPath, normalizedPath, stats);
|
|
524
|
+
fileHashCache.set(realPath, hash);
|
|
525
|
+
}
|
|
526
|
+
fileHashInputs.push({ relativePath: normalizedPath, hash });
|
|
527
|
+
}
|
|
528
|
+
const fingerprint = computeFinalFingerprint(fileHashInputs);
|
|
529
|
+
return {
|
|
530
|
+
fingerprint,
|
|
531
|
+
files: sortedFiles,
|
|
532
|
+
fileCount: sortedFiles.length
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
function computeFingerprintSync(options) {
|
|
536
|
+
const baseDir = validateOptions(options);
|
|
537
|
+
const files = listPackageFilesSync(options.packages, options.ignore, baseDir);
|
|
538
|
+
const sortedFiles = sortFiles(files);
|
|
539
|
+
const fileHashCache = /* @__PURE__ */ new Map();
|
|
540
|
+
const fileHashInputs = [];
|
|
541
|
+
for (const file of sortedFiles) {
|
|
542
|
+
const filePath = path2__namespace.resolve(baseDir, file);
|
|
543
|
+
let realPath = filePath;
|
|
544
|
+
let stats = fs__namespace.lstatSync(filePath);
|
|
545
|
+
if (stats.isSymbolicLink()) {
|
|
546
|
+
try {
|
|
547
|
+
realPath = fs__namespace.realpathSync(filePath);
|
|
548
|
+
} catch {
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
551
|
+
try {
|
|
552
|
+
stats = fs__namespace.statSync(realPath);
|
|
553
|
+
} catch {
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
if (!stats.isFile()) {
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
const normalizedPath = normalizePath(file);
|
|
561
|
+
let hash;
|
|
562
|
+
const cachedHash = fileHashCache.get(realPath);
|
|
563
|
+
if (cachedHash !== void 0) {
|
|
564
|
+
hash = cachedHash;
|
|
565
|
+
} else {
|
|
566
|
+
hash = hashFileSync(realPath, normalizedPath);
|
|
567
|
+
fileHashCache.set(realPath, hash);
|
|
568
|
+
}
|
|
569
|
+
fileHashInputs.push({ relativePath: normalizedPath, hash });
|
|
570
|
+
}
|
|
571
|
+
const fingerprint = computeFinalFingerprint(fileHashInputs);
|
|
572
|
+
return {
|
|
573
|
+
fingerprint,
|
|
574
|
+
files: sortedFiles,
|
|
575
|
+
fileCount: sortedFiles.length
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
async function listPackageFiles(packages, ignore = [], baseDir = process.cwd()) {
|
|
579
|
+
const allFiles = [];
|
|
580
|
+
for (const pkg of packages) {
|
|
581
|
+
const patterns = [`${pkg}/**/*`];
|
|
582
|
+
const files = await tinyglobby.glob(patterns, {
|
|
583
|
+
cwd: baseDir,
|
|
584
|
+
ignore,
|
|
585
|
+
onlyFiles: true,
|
|
586
|
+
dot: true,
|
|
587
|
+
// Include dotfiles
|
|
588
|
+
absolute: false
|
|
589
|
+
// Return relative paths
|
|
590
|
+
});
|
|
591
|
+
allFiles.push(...files);
|
|
592
|
+
}
|
|
593
|
+
return allFiles;
|
|
594
|
+
}
|
|
595
|
+
function listPackageFilesSync(packages, ignore = [], baseDir = process.cwd()) {
|
|
596
|
+
const allFiles = [];
|
|
597
|
+
for (const pkg of packages) {
|
|
598
|
+
const patterns = [`${pkg}/**/*`];
|
|
599
|
+
const files = tinyglobby.globSync(patterns, {
|
|
600
|
+
cwd: baseDir,
|
|
601
|
+
ignore,
|
|
602
|
+
onlyFiles: true,
|
|
603
|
+
dot: true,
|
|
604
|
+
// Include dotfiles
|
|
605
|
+
absolute: false
|
|
606
|
+
// Return relative paths
|
|
607
|
+
});
|
|
608
|
+
allFiles.push(...files);
|
|
609
|
+
}
|
|
610
|
+
return allFiles;
|
|
611
|
+
}
|
|
612
|
+
var canonicalize = canonicalizeNamespace__namespace;
|
|
613
|
+
var serialize = canonicalize.default;
|
|
614
|
+
var attestationSchema = zod.z.object({
|
|
615
|
+
suite: zod.z.string().min(1),
|
|
616
|
+
fingerprint: zod.z.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
617
|
+
attestedAt: zod.z.string().datetime(),
|
|
618
|
+
attestedBy: zod.z.string().min(1),
|
|
619
|
+
command: zod.z.string().min(1),
|
|
620
|
+
exitCode: zod.z.literal(0)
|
|
621
|
+
});
|
|
622
|
+
var attestationsFileSchema = zod.z.object({
|
|
623
|
+
schemaVersion: zod.z.literal("1"),
|
|
624
|
+
attestations: zod.z.array(attestationSchema),
|
|
625
|
+
signature: zod.z.string()
|
|
626
|
+
// Will be validated by crypto module
|
|
627
|
+
});
|
|
628
|
+
function isNodeError(error) {
|
|
629
|
+
if (error === null || typeof error !== "object") {
|
|
630
|
+
return false;
|
|
631
|
+
}
|
|
632
|
+
if (!("code" in error)) {
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
635
|
+
const errorObj = error;
|
|
636
|
+
return typeof errorObj.code === "string";
|
|
637
|
+
}
|
|
638
|
+
async function readAttestations(filePath) {
|
|
639
|
+
try {
|
|
640
|
+
const content = await fs__namespace.promises.readFile(filePath, "utf-8");
|
|
641
|
+
const parsed = JSON.parse(content);
|
|
642
|
+
return attestationsFileSchema.parse(parsed);
|
|
643
|
+
} catch (error) {
|
|
644
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
645
|
+
return null;
|
|
646
|
+
}
|
|
647
|
+
throw error;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
function readAttestationsSync(filePath) {
|
|
651
|
+
try {
|
|
652
|
+
const content = fs__namespace.readFileSync(filePath, "utf-8");
|
|
653
|
+
const parsed = JSON.parse(content);
|
|
654
|
+
return attestationsFileSchema.parse(parsed);
|
|
655
|
+
} catch (error) {
|
|
656
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
657
|
+
return null;
|
|
658
|
+
}
|
|
659
|
+
throw error;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
async function writeAttestations(filePath, attestations, signature) {
|
|
663
|
+
const fileContent = {
|
|
664
|
+
schemaVersion: "1",
|
|
665
|
+
attestations,
|
|
666
|
+
signature
|
|
667
|
+
};
|
|
668
|
+
attestationsFileSchema.parse(fileContent);
|
|
669
|
+
const dir = path2__namespace.dirname(filePath);
|
|
670
|
+
await fs__namespace.promises.mkdir(dir, { recursive: true });
|
|
671
|
+
const json = JSON.stringify(fileContent, null, 2);
|
|
672
|
+
await fs__namespace.promises.writeFile(filePath, json, "utf-8");
|
|
673
|
+
}
|
|
674
|
+
function writeAttestationsSync(filePath, attestations, signature) {
|
|
675
|
+
const fileContent = {
|
|
676
|
+
schemaVersion: "1",
|
|
677
|
+
attestations,
|
|
678
|
+
signature
|
|
679
|
+
};
|
|
680
|
+
attestationsFileSchema.parse(fileContent);
|
|
681
|
+
const dir = path2__namespace.dirname(filePath);
|
|
682
|
+
fs__namespace.mkdirSync(dir, { recursive: true });
|
|
683
|
+
const json = JSON.stringify(fileContent, null, 2);
|
|
684
|
+
fs__namespace.writeFileSync(filePath, json, "utf-8");
|
|
685
|
+
}
|
|
686
|
+
function findAttestation(attestations, suite) {
|
|
687
|
+
return attestations.attestations.find((a) => a.suite === suite);
|
|
688
|
+
}
|
|
689
|
+
function upsertAttestation(attestations, newAttestation) {
|
|
690
|
+
attestationSchema.parse(newAttestation);
|
|
691
|
+
const existingIndex = attestations.findIndex((a) => a.suite === newAttestation.suite);
|
|
692
|
+
if (existingIndex === -1) {
|
|
693
|
+
return [...attestations, newAttestation];
|
|
694
|
+
} else {
|
|
695
|
+
const updated = [...attestations];
|
|
696
|
+
updated[existingIndex] = newAttestation;
|
|
697
|
+
return updated;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
function removeAttestation(attestations, suite) {
|
|
701
|
+
return attestations.filter((a) => a.suite !== suite);
|
|
702
|
+
}
|
|
703
|
+
function canonicalizeAttestations(attestations) {
|
|
704
|
+
const canonical = serialize(attestations);
|
|
705
|
+
if (canonical === void 0) {
|
|
706
|
+
throw new Error("Failed to canonicalize attestations");
|
|
707
|
+
}
|
|
708
|
+
return canonical;
|
|
709
|
+
}
|
|
710
|
+
function createAttestation(params) {
|
|
711
|
+
const attestation = {
|
|
712
|
+
suite: params.suite,
|
|
713
|
+
fingerprint: params.fingerprint,
|
|
714
|
+
attestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
715
|
+
attestedBy: params.attestedBy ?? os__namespace.userInfo().username,
|
|
716
|
+
command: params.command,
|
|
717
|
+
exitCode: 0
|
|
718
|
+
};
|
|
719
|
+
attestationSchema.parse(attestation);
|
|
720
|
+
return attestation;
|
|
721
|
+
}
|
|
722
|
+
async function writeSignedAttestations(options) {
|
|
723
|
+
const { sign: sign2 } = await Promise.resolve().then(() => (init_crypto(), crypto_exports));
|
|
724
|
+
const canonical = canonicalizeAttestations(options.attestations);
|
|
725
|
+
const signature = await sign2({
|
|
726
|
+
privateKeyPath: options.privateKeyPath,
|
|
727
|
+
data: canonical
|
|
728
|
+
});
|
|
729
|
+
await writeAttestations(options.filePath, options.attestations, signature);
|
|
730
|
+
}
|
|
731
|
+
async function readAndVerifyAttestations(options) {
|
|
732
|
+
const { verify: verify2 } = await Promise.resolve().then(() => (init_crypto(), crypto_exports));
|
|
733
|
+
const file = await readAttestations(options.filePath);
|
|
734
|
+
if (!file) {
|
|
735
|
+
throw new Error(`Attestations file not found: ${options.filePath}`);
|
|
736
|
+
}
|
|
737
|
+
const canonical = canonicalizeAttestations(file.attestations);
|
|
738
|
+
const isValid = await verify2({
|
|
739
|
+
publicKeyPath: options.publicKeyPath,
|
|
740
|
+
data: canonical,
|
|
741
|
+
signature: file.signature
|
|
742
|
+
});
|
|
743
|
+
if (!isValid) {
|
|
744
|
+
throw new SignatureInvalidError(options.filePath);
|
|
745
|
+
}
|
|
746
|
+
return file;
|
|
747
|
+
}
|
|
748
|
+
var SignatureInvalidError = class extends Error {
|
|
749
|
+
/**
|
|
750
|
+
* Create a new SignatureInvalidError.
|
|
751
|
+
* @param filePath - Path to the file that failed verification
|
|
752
|
+
*/
|
|
753
|
+
constructor(filePath) {
|
|
754
|
+
super(`Signature verification failed for: ${filePath}`);
|
|
755
|
+
this.name = "SignatureInvalidError";
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
|
|
759
|
+
// src/index.ts
|
|
760
|
+
init_crypto();
|
|
761
|
+
async function verifyAttestations(options) {
|
|
762
|
+
const { config, repoRoot = process.cwd() } = options;
|
|
763
|
+
const errors = [];
|
|
764
|
+
const suiteResults = [];
|
|
765
|
+
let signatureValid = true;
|
|
766
|
+
let attestationsFile = null;
|
|
767
|
+
const attestationsPath = resolvePath(config.settings.attestationsPath, repoRoot);
|
|
768
|
+
const publicKeyPath = resolvePath(config.settings.publicKeyPath, repoRoot);
|
|
769
|
+
try {
|
|
770
|
+
if (!fs__namespace.existsSync(attestationsPath)) {
|
|
771
|
+
attestationsFile = null;
|
|
772
|
+
} else if (!fs__namespace.existsSync(publicKeyPath)) {
|
|
773
|
+
errors.push(`Public key not found: ${publicKeyPath}`);
|
|
774
|
+
signatureValid = false;
|
|
775
|
+
} else {
|
|
776
|
+
attestationsFile = await readAndVerifyAttestations({
|
|
777
|
+
filePath: attestationsPath,
|
|
778
|
+
publicKeyPath
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
} catch (err) {
|
|
782
|
+
if (err instanceof SignatureInvalidError) {
|
|
783
|
+
signatureValid = false;
|
|
784
|
+
errors.push(err.message);
|
|
785
|
+
} else if (err instanceof Error) {
|
|
786
|
+
errors.push(err.message);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
const attestations = attestationsFile?.attestations ?? [];
|
|
790
|
+
for (const [suiteName, suiteConfig] of Object.entries(config.suites)) {
|
|
791
|
+
const result = await verifySuite({
|
|
792
|
+
suiteName,
|
|
793
|
+
suiteConfig,
|
|
794
|
+
attestations,
|
|
795
|
+
maxAgeDays: config.settings.maxAgeDays,
|
|
796
|
+
repoRoot
|
|
797
|
+
});
|
|
798
|
+
suiteResults.push(result);
|
|
799
|
+
}
|
|
800
|
+
checkInvalidationChains(config, suiteResults);
|
|
801
|
+
const allValid = signatureValid && suiteResults.every((r) => r.status === "VALID") && errors.length === 0;
|
|
802
|
+
return {
|
|
803
|
+
success: allValid,
|
|
804
|
+
signatureValid,
|
|
805
|
+
suites: suiteResults,
|
|
806
|
+
errors
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
async function verifySuite(options) {
|
|
810
|
+
const { suiteName, suiteConfig, attestations, maxAgeDays, repoRoot } = options;
|
|
811
|
+
const fingerprintOptions = {
|
|
812
|
+
packages: suiteConfig.packages.map((p) => resolvePath(p, repoRoot)),
|
|
813
|
+
baseDir: repoRoot,
|
|
814
|
+
...suiteConfig.ignore && { ignore: suiteConfig.ignore }
|
|
815
|
+
};
|
|
816
|
+
const fingerprintResult = await computeFingerprint(fingerprintOptions);
|
|
817
|
+
const attestation = attestations.find((a) => a.suite === suiteName);
|
|
818
|
+
if (!attestation) {
|
|
819
|
+
return {
|
|
820
|
+
suite: suiteName,
|
|
821
|
+
status: "NEEDS_ATTESTATION",
|
|
822
|
+
fingerprint: fingerprintResult.fingerprint,
|
|
823
|
+
message: "No attestation found for this suite"
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
if (attestation.fingerprint !== fingerprintResult.fingerprint) {
|
|
827
|
+
return {
|
|
828
|
+
suite: suiteName,
|
|
829
|
+
status: "FINGERPRINT_CHANGED",
|
|
830
|
+
fingerprint: fingerprintResult.fingerprint,
|
|
831
|
+
attestation,
|
|
832
|
+
message: `Fingerprint changed from ${attestation.fingerprint.slice(0, 20)}... to ${fingerprintResult.fingerprint.slice(0, 20)}...`
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
const attestedAt = new Date(attestation.attestedAt);
|
|
836
|
+
const ageMs = Date.now() - attestedAt.getTime();
|
|
837
|
+
const ageDays = Math.floor(ageMs / (1e3 * 60 * 60 * 24));
|
|
838
|
+
if (ageDays > maxAgeDays) {
|
|
839
|
+
return {
|
|
840
|
+
suite: suiteName,
|
|
841
|
+
status: "EXPIRED",
|
|
842
|
+
fingerprint: fingerprintResult.fingerprint,
|
|
843
|
+
attestation,
|
|
844
|
+
age: ageDays,
|
|
845
|
+
message: `Attestation expired (${String(ageDays)} days old, max ${String(maxAgeDays)} days)`
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
return {
|
|
849
|
+
suite: suiteName,
|
|
850
|
+
status: "VALID",
|
|
851
|
+
fingerprint: fingerprintResult.fingerprint,
|
|
852
|
+
attestation,
|
|
853
|
+
age: ageDays
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
function checkInvalidationChains(config, results) {
|
|
857
|
+
for (const [parentName, parentConfig] of Object.entries(config.suites)) {
|
|
858
|
+
const invalidates = parentConfig.invalidates ?? [];
|
|
859
|
+
const parentResult = results.find((r) => r.suite === parentName);
|
|
860
|
+
if (!parentResult?.attestation) continue;
|
|
861
|
+
const parentTime = new Date(parentResult.attestation.attestedAt).getTime();
|
|
862
|
+
for (const childName of invalidates) {
|
|
863
|
+
const childResult = results.find((r) => r.suite === childName);
|
|
864
|
+
if (!childResult?.attestation) continue;
|
|
865
|
+
const childTime = new Date(childResult.attestation.attestedAt).getTime();
|
|
866
|
+
if (parentTime > childTime && childResult.status === "VALID") {
|
|
867
|
+
childResult.status = "INVALIDATED_BY_PARENT";
|
|
868
|
+
childResult.message = `Invalidated by ${parentName} (attested later)`;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
function resolvePath(relativePath, baseDir) {
|
|
874
|
+
if (path2__namespace.isAbsolute(relativePath)) {
|
|
875
|
+
return relativePath;
|
|
876
|
+
}
|
|
877
|
+
return path2__namespace.join(baseDir, relativePath);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// src/index.ts
|
|
881
|
+
var version = "0.0.0";
|
|
882
|
+
|
|
883
|
+
exports.ConfigNotFoundError = ConfigNotFoundError;
|
|
884
|
+
exports.ConfigValidationError = ConfigValidationError;
|
|
885
|
+
exports.SignatureInvalidError = SignatureInvalidError;
|
|
886
|
+
exports.canonicalizeAttestations = canonicalizeAttestations;
|
|
887
|
+
exports.checkOpenSSL = checkOpenSSL;
|
|
888
|
+
exports.computeFingerprint = computeFingerprint;
|
|
889
|
+
exports.computeFingerprintSync = computeFingerprintSync;
|
|
890
|
+
exports.createAttestation = createAttestation;
|
|
891
|
+
exports.findAttestation = findAttestation;
|
|
892
|
+
exports.findConfigPath = findConfigPath;
|
|
893
|
+
exports.generateKeyPair = generateKeyPair;
|
|
894
|
+
exports.getDefaultPrivateKeyPath = getDefaultPrivateKeyPath;
|
|
895
|
+
exports.getDefaultPublicKeyPath = getDefaultPublicKeyPath;
|
|
896
|
+
exports.listPackageFiles = listPackageFiles;
|
|
897
|
+
exports.loadConfig = loadConfig;
|
|
898
|
+
exports.loadConfigSync = loadConfigSync;
|
|
899
|
+
exports.readAndVerifyAttestations = readAndVerifyAttestations;
|
|
900
|
+
exports.readAttestations = readAttestations;
|
|
901
|
+
exports.readAttestationsSync = readAttestationsSync;
|
|
902
|
+
exports.removeAttestation = removeAttestation;
|
|
903
|
+
exports.resolveConfigPaths = resolveConfigPaths;
|
|
904
|
+
exports.setKeyPermissions = setKeyPermissions;
|
|
905
|
+
exports.sign = sign;
|
|
906
|
+
exports.toAttestItConfig = toAttestItConfig;
|
|
907
|
+
exports.upsertAttestation = upsertAttestation;
|
|
908
|
+
exports.verify = verify;
|
|
909
|
+
exports.verifyAttestations = verifyAttestations;
|
|
910
|
+
exports.version = version;
|
|
911
|
+
exports.writeAttestations = writeAttestations;
|
|
912
|
+
exports.writeAttestationsSync = writeAttestationsSync;
|
|
913
|
+
exports.writeSignedAttestations = writeSignedAttestations;
|
|
914
|
+
//# sourceMappingURL=index.cjs.map
|
|
915
|
+
//# sourceMappingURL=index.cjs.map
|