@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/fingerprint.ts","../src/attestation.ts","../src/verify.ts","../src/index.ts"],"names":["parseYaml","resolve","hash","z","fs2","path2","sign","verify","fs3","path3"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Configuration loading and validation for attest-it.\n */\n\nimport { readFileSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport { join, resolve } from 'node:path'\nimport { parse as parseYaml } from 'yaml'\nimport { z } from 'zod'\n\n/**\n * Zod schema for settings with defaults applied.\n */\nconst settingsSchema = z\n .object({\n maxAgeDays: z.number().int().positive().default(30),\n publicKeyPath: z.string().default('.attest-it/pubkey.pem'),\n attestationsPath: z.string().default('.attest-it/attestations.json'),\n defaultCommand: z.string().optional(),\n algorithm: z.enum(['ed25519', 'rsa']).default('ed25519'),\n })\n .strict()\n\n/**\n * Zod schema for a suite configuration.\n */\nconst suiteSchema = z\n .object({\n description: z.string().optional(),\n packages: z\n .array(z.string().min(1, 'Package path cannot be empty'))\n .min(1, 'At least one package pattern is required'),\n files: z.array(z.string().min(1, 'File path cannot be empty')).optional(),\n ignore: z.array(z.string().min(1, 'Ignore pattern cannot be empty')).optional(),\n command: z.string().optional(),\n invalidates: z.array(z.string().min(1, 'Invalidated suite name cannot be empty')).optional(),\n })\n .strict()\n\n/**\n * Zod schema for the full configuration file.\n */\nconst configSchema = z\n .object({\n version: z.literal(1),\n settings: settingsSchema.default({}),\n suites: z.record(z.string(), suiteSchema).refine((suites) => Object.keys(suites).length >= 1, {\n message: 'At least one suite must be defined',\n }),\n })\n .strict()\n\n/**\n * Type inference from Zod schema (should match AttestItConfig).\n * This is the same as AttestItConfig but with defaults applied.\n * @public\n */\nexport type Config = z.infer<typeof configSchema>\n\n/**\n * Error thrown when configuration is invalid.\n * @public\n */\nexport class ConfigValidationError extends Error {\n constructor(\n message: string,\n public readonly issues: z.ZodIssue[],\n ) {\n super(message)\n this.name = 'ConfigValidationError'\n }\n}\n\n/**\n * Error thrown when configuration file cannot be found.\n * @public\n */\nexport class ConfigNotFoundError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'ConfigNotFoundError'\n }\n}\n\n/**\n * Parse configuration content from a string.\n *\n * @param content - The configuration file content\n * @param format - The format of the content ('yaml' or 'json')\n * @returns Parsed and validated configuration\n * @throws {ConfigValidationError} If validation fails\n */\nfunction parseConfigContent(content: string, format: 'yaml' | 'json'): Config {\n let rawConfig: unknown\n\n try {\n if (format === 'yaml') {\n rawConfig = parseYaml(content)\n } else {\n rawConfig = JSON.parse(content)\n }\n } catch (error) {\n throw new ConfigValidationError(\n `Failed to parse ${format.toUpperCase()}: ${error instanceof Error ? error.message : String(error)}`,\n [],\n )\n }\n\n const result = configSchema.safeParse(rawConfig)\n\n if (!result.success) {\n throw new ConfigValidationError(\n 'Configuration validation failed:\\n' +\n result.error.issues\n .map((issue) => ` - ${issue.path.join('.')}: ${issue.message}`)\n .join('\\n'),\n result.error.issues,\n )\n }\n\n return result.data\n}\n\n/**\n * Determine the format of a config file from its extension.\n *\n * @param filePath - Path to the config file\n * @returns 'yaml' or 'json'\n */\nfunction getConfigFormat(filePath: string): 'yaml' | 'json' {\n const ext = filePath.toLowerCase()\n if (ext.endsWith('.yaml') || ext.endsWith('.yml')) {\n return 'yaml'\n }\n if (ext.endsWith('.json')) {\n return 'json'\n }\n // Default to yaml for extensionless files\n return 'yaml'\n}\n\n/**\n * Find the configuration file in default locations.\n *\n * Searches in this order:\n * 1. .attest-it/config.yaml\n * 2. .attest-it/config.yml\n * 3. .attest-it/config.json\n *\n * @param startDir - Directory to start searching from (defaults to cwd)\n * @returns Absolute path to the config file, or null if not found\n * @public\n */\nexport function findConfigPath(startDir: string = process.cwd()): string | null {\n const configDir = join(startDir, '.attest-it')\n const candidates = ['config.yaml', 'config.yml', 'config.json']\n\n for (const candidate of candidates) {\n const configPath = join(configDir, candidate)\n try {\n readFileSync(configPath, 'utf8')\n return configPath\n } catch {\n // File doesn't exist or can't be read, try next candidate\n continue\n }\n }\n\n return null\n}\n\n/**\n * Load and validate configuration from a file (async).\n *\n * @param configPath - Optional path to config file. If not provided, searches default locations.\n * @returns Validated configuration object\n * @throws {@link ConfigNotFoundError} If config file cannot be found\n * @throws {@link ConfigValidationError} If validation fails\n * @public\n */\nexport async function loadConfig(configPath?: string): Promise<Config> {\n const resolvedPath = configPath ?? findConfigPath()\n\n if (!resolvedPath) {\n throw new ConfigNotFoundError(\n 'Configuration file not found. Expected .attest-it/config.yaml, .attest-it/config.yml, or .attest-it/config.json',\n )\n }\n\n try {\n const content = await readFile(resolvedPath, 'utf8')\n const format = getConfigFormat(resolvedPath)\n return parseConfigContent(content, format)\n } catch (error) {\n if (error instanceof ConfigValidationError) {\n throw error\n }\n throw new ConfigNotFoundError(\n `Failed to read configuration file at ${resolvedPath}: ${String(error)}`,\n )\n }\n}\n\n/**\n * Load and validate configuration from a file (sync).\n *\n * @param configPath - Optional path to config file. If not provided, searches default locations.\n * @returns Validated configuration object\n * @throws {@link ConfigNotFoundError} If config file cannot be found\n * @throws {@link ConfigValidationError} If validation fails\n * @public\n */\nexport function loadConfigSync(configPath?: string): Config {\n const resolvedPath = configPath ?? findConfigPath()\n\n if (!resolvedPath) {\n throw new ConfigNotFoundError(\n 'Configuration file not found. Expected .attest-it/config.yaml, .attest-it/config.yml, or .attest-it/config.json',\n )\n }\n\n try {\n const content = readFileSync(resolvedPath, 'utf8')\n const format = getConfigFormat(resolvedPath)\n return parseConfigContent(content, format)\n } catch (error) {\n if (error instanceof ConfigValidationError) {\n throw error\n }\n throw new ConfigNotFoundError(\n `Failed to read configuration file at ${resolvedPath}: ${String(error)}`,\n )\n }\n}\n\n/**\n * Resolve relative paths in the configuration against the repository root.\n *\n * This converts relative paths in settings.publicKeyPath and settings.attestationsPath\n * to absolute paths relative to the repository root.\n *\n * @param config - The configuration object\n * @param repoRoot - Absolute path to the repository root\n * @returns Configuration with resolved absolute paths\n * @public\n */\nexport function resolveConfigPaths(config: Config, repoRoot: string): Config {\n return {\n ...config,\n settings: {\n ...config.settings,\n publicKeyPath: resolve(repoRoot, config.settings.publicKeyPath),\n attestationsPath: resolve(repoRoot, config.settings.attestationsPath),\n },\n }\n}\n\n/**\n * Convert Zod-validated Config to AttestItConfig by removing undefined values.\n *\n * The Config type (from Zod) has optional fields as `T | undefined`,\n * while AttestItConfig has optional fields as `T?` (can be absent, not undefined).\n *\n * This adapter removes any undefined values to match the AttestItConfig interface\n * that the core functions expect.\n *\n * @param config - The Zod-validated configuration from loadConfig()\n * @returns Configuration compatible with AttestItConfig\n * @public\n */\nexport function toAttestItConfig(config: Config): import('./types.js').AttestItConfig {\n return {\n version: config.version,\n settings: {\n maxAgeDays: config.settings.maxAgeDays,\n publicKeyPath: config.settings.publicKeyPath,\n attestationsPath: config.settings.attestationsPath,\n algorithm: config.settings.algorithm,\n ...(config.settings.defaultCommand !== undefined && {\n defaultCommand: config.settings.defaultCommand,\n }),\n },\n suites: Object.fromEntries(\n Object.entries(config.suites).map(([name, suite]) => [\n name,\n {\n packages: suite.packages,\n ...(suite.description !== undefined && { description: suite.description }),\n ...(suite.files !== undefined && { files: suite.files }),\n ...(suite.ignore !== undefined && { ignore: suite.ignore }),\n ...(suite.command !== undefined && { command: suite.command }),\n ...(suite.invalidates !== undefined && { invalidates: suite.invalidates }),\n },\n ]),\n ),\n }\n}\n","import * as crypto from 'node:crypto'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { glob, globSync } from 'tinyglobby'\n\n/**\n * Threshold for streaming large files instead of reading into memory.\n * Files larger than this will be hashed via streaming to avoid memory issues.\n */\nconst LARGE_FILE_THRESHOLD = 50 * 1024 * 1024 // 50MB\n\n/**\n * Options for computing a package fingerprint.\n * @public\n */\nexport interface FingerprintOptions {\n /** Package directories to include */\n packages: string[]\n /** Glob patterns to exclude from fingerprint */\n ignore?: string[]\n /** Base directory for resolving paths */\n baseDir?: string\n}\n\n/**\n * Result of computing a package fingerprint.\n * @public\n */\nexport interface FingerprintResult {\n /** The fingerprint in \"sha256:...\" format */\n fingerprint: string\n /** List of files included in fingerprint calculation */\n files: string[]\n /** Number of files processed */\n fileCount: number\n}\n\n/**\n * Internal representation of a file hash for fingerprint computation.\n */\ninterface FileHashInput {\n /** The normalized relative path of the file */\n relativePath: string\n /** The computed hash of the file content */\n hash: Buffer\n}\n\n/**\n * Sort files lexicographically (locale-independent).\n */\nfunction sortFiles(files: string[]): string[] {\n return [...files].sort((a, b) => {\n if (a < b) return -1\n if (a > b) return 1\n return 0\n })\n}\n\n/**\n * Normalize path separators to forward slashes.\n */\nfunction normalizePath(filePath: string): string {\n return filePath.split(path.sep).join('/')\n}\n\n/**\n * Compute final fingerprint from file hashes.\n */\nfunction computeFinalFingerprint(fileHashes: FileHashInput[]): string {\n // Sort by relative path\n const sorted = [...fileHashes].sort((a, b) => {\n if (a.relativePath < b.relativePath) return -1\n if (a.relativePath > b.relativePath) return 1\n return 0\n })\n\n // Concatenate all file hashes\n const hashes = sorted.map((input) => input.hash)\n const concatenated = Buffer.concat(hashes)\n\n // Compute final hash\n const finalHash = crypto.createHash('sha256').update(concatenated).digest()\n return `sha256:${finalHash.toString('hex')}`\n}\n\n/**\n * Hash a file's content using streaming for large files (async).\n * For files larger than LARGE_FILE_THRESHOLD, uses streaming to avoid memory issues.\n */\nasync function hashFileAsync(\n realPath: string,\n normalizedPath: string,\n stats: fs.Stats,\n): Promise<Buffer> {\n if (stats.size > LARGE_FILE_THRESHOLD) {\n // Stream large files to avoid memory issues\n return new Promise((resolve, reject) => {\n const hash = crypto.createHash('sha256')\n hash.update(normalizedPath)\n hash.update('\\0')\n\n const stream = fs.createReadStream(realPath)\n stream.on('data', (chunk: string | Buffer) => {\n hash.update(chunk)\n })\n stream.on('end', () => {\n resolve(hash.digest())\n })\n stream.on('error', reject)\n })\n }\n\n // Read small files into memory (faster than streaming)\n const content = await fs.promises.readFile(realPath)\n const hash = crypto.createHash('sha256')\n hash.update(normalizedPath)\n hash.update('\\0')\n hash.update(content)\n return hash.digest()\n}\n\n/**\n * Hash a file's content synchronously.\n * Note: Cannot stream synchronously, so large files are read into memory.\n */\nfunction hashFileSync(realPath: string, normalizedPath: string): Buffer {\n const content = fs.readFileSync(realPath)\n const hash = crypto.createHash('sha256')\n hash.update(normalizedPath)\n hash.update('\\0')\n hash.update(content)\n return hash.digest()\n}\n\n/**\n * Validate fingerprint options and return base directory.\n */\nfunction validateOptions(options: FingerprintOptions): string {\n if (options.packages.length === 0) {\n throw new Error('packages array must not be empty')\n }\n\n const baseDir = options.baseDir ?? process.cwd()\n\n // Verify all package paths exist\n for (const pkg of options.packages) {\n const pkgPath = path.resolve(baseDir, pkg)\n if (!fs.existsSync(pkgPath)) {\n throw new Error(`Package path does not exist: ${pkgPath}`)\n }\n }\n\n return baseDir\n}\n\n/**\n * Compute a deterministic fingerprint for a set of packages (async).\n *\n * Algorithm:\n * 1. List all files in packages (respecting ignore globs)\n * 2. Sort files lexicographically by relative path\n * 3. For each file: compute SHA256(relativePath + \"\\0\" + content)\n * 4. Concatenate all file hashes in sorted order\n * 5. Compute final SHA256 of concatenated hashes\n * 6. Return \"sha256:\" + hex(fingerprint)\n *\n * @param options - Configuration for fingerprint computation\n * @returns Result containing the fingerprint hash and list of files processed\n * @throws Error if packages array is empty or if package paths don't exist\n * @public\n */\nexport async function computeFingerprint(options: FingerprintOptions): Promise<FingerprintResult> {\n const baseDir = validateOptions(options)\n\n // List all files in packages\n const files = await listPackageFiles(options.packages, options.ignore, baseDir)\n\n // Sort files lexicographically\n const sortedFiles = sortFiles(files)\n\n // Track visited files to handle multiple symlinks pointing to the same file\n // Key: realpath, Value: file hash\n const fileHashCache = new Map<string, Buffer>()\n\n // Compute individual file hashes\n const fileHashInputs: FileHashInput[] = []\n for (const file of sortedFiles) {\n const filePath = path.resolve(baseDir, file)\n\n // Handle symlinks\n let realPath = filePath\n let stats = await fs.promises.lstat(filePath)\n\n if (stats.isSymbolicLink()) {\n try {\n realPath = await fs.promises.realpath(filePath)\n } catch {\n // Skip broken symlinks\n continue\n }\n\n // Get stats of the target\n try {\n stats = await fs.promises.stat(realPath)\n } catch {\n // Skip broken symlinks\n continue\n }\n }\n\n // Skip if not a file (e.g., directories)\n if (!stats.isFile()) {\n continue\n }\n\n // Normalize path separators to forward slashes\n const normalizedPath = normalizePath(file)\n\n // Check if we've already hashed this file (via symlinks)\n let hash: Buffer\n const cachedHash = fileHashCache.get(realPath)\n if (cachedHash !== undefined) {\n // Reuse cached hash for files we've already seen (via symlinks)\n hash = cachedHash\n } else {\n // Hash the file content\n hash = await hashFileAsync(realPath, normalizedPath, stats)\n fileHashCache.set(realPath, hash)\n }\n\n fileHashInputs.push({ relativePath: normalizedPath, hash })\n }\n\n // Compute final fingerprint\n const fingerprint = computeFinalFingerprint(fileHashInputs)\n\n return {\n fingerprint,\n files: sortedFiles,\n fileCount: sortedFiles.length,\n }\n}\n\n/**\n * Compute a deterministic fingerprint for a set of packages (sync).\n *\n * @param options - Configuration for fingerprint computation\n * @returns Result containing the fingerprint hash and list of files processed\n * @throws Error if packages array is empty or if package paths don't exist\n * @public\n * @see {@link computeFingerprint} for the async version\n */\nexport function computeFingerprintSync(options: FingerprintOptions): FingerprintResult {\n const baseDir = validateOptions(options)\n\n // List all files in packages (sync version)\n const files = listPackageFilesSync(options.packages, options.ignore, baseDir)\n\n // Sort files lexicographically\n const sortedFiles = sortFiles(files)\n\n // Track visited files to handle multiple symlinks pointing to the same file\n // Key: realpath, Value: file hash\n const fileHashCache = new Map<string, Buffer>()\n\n // Compute individual file hashes\n const fileHashInputs: FileHashInput[] = []\n for (const file of sortedFiles) {\n const filePath = path.resolve(baseDir, file)\n\n // Handle symlinks\n let realPath = filePath\n let stats = fs.lstatSync(filePath)\n\n if (stats.isSymbolicLink()) {\n try {\n realPath = fs.realpathSync(filePath)\n } catch {\n // Skip broken symlinks\n continue\n }\n\n // Get stats of the target\n try {\n stats = fs.statSync(realPath)\n } catch {\n // Skip broken symlinks\n continue\n }\n }\n\n // Skip if not a file (e.g., directories)\n if (!stats.isFile()) {\n continue\n }\n\n // Normalize path separators to forward slashes\n const normalizedPath = normalizePath(file)\n\n // Check if we've already hashed this file (via symlinks)\n let hash: Buffer\n const cachedHash = fileHashCache.get(realPath)\n if (cachedHash !== undefined) {\n // Reuse cached hash for files we've already seen (via symlinks)\n hash = cachedHash\n } else {\n // Hash the file content (sync version cannot stream)\n hash = hashFileSync(realPath, normalizedPath)\n fileHashCache.set(realPath, hash)\n }\n\n fileHashInputs.push({ relativePath: normalizedPath, hash })\n }\n\n // Compute final fingerprint\n const fingerprint = computeFinalFingerprint(fileHashInputs)\n\n return {\n fingerprint,\n files: sortedFiles,\n fileCount: sortedFiles.length,\n }\n}\n\n/**\n * List files in packages, respecting ignore patterns (async).\n *\n * @param packages - Array of package directory paths\n * @param ignore - Optional glob patterns to exclude\n * @param baseDir - Base directory for resolving paths (defaults to cwd)\n * @returns Array of relative file paths\n * @public\n */\nexport async function listPackageFiles(\n packages: string[],\n ignore: string[] = [],\n baseDir: string = process.cwd(),\n): Promise<string[]> {\n const allFiles: string[] = []\n\n for (const pkg of packages) {\n // Build glob patterns for this package\n const patterns = [`${pkg}/**/*`]\n\n // Use tinyglobby to find files\n const files = await glob(patterns, {\n cwd: baseDir,\n ignore,\n onlyFiles: true,\n dot: true, // Include dotfiles\n absolute: false, // Return relative paths\n })\n\n allFiles.push(...files)\n }\n\n return allFiles\n}\n\n/**\n * Synchronous version of listPackageFiles\n */\nfunction listPackageFilesSync(\n packages: string[],\n ignore: string[] = [],\n baseDir: string = process.cwd(),\n): string[] {\n const allFiles: string[] = []\n\n for (const pkg of packages) {\n // Build glob patterns for this package\n const patterns = [`${pkg}/**/*`]\n\n // Use tinyglobby to find files (sync version)\n const files = globSync(patterns, {\n cwd: baseDir,\n ignore,\n onlyFiles: true,\n dot: true, // Include dotfiles\n absolute: false, // Return relative paths\n })\n\n allFiles.push(...files)\n }\n\n return allFiles\n}\n","/**\n * Attestation file I/O module with JSON canonicalization.\n */\n\nimport * as fs from 'node:fs'\nimport * as os from 'node:os'\nimport * as path from 'node:path'\nimport * as canonicalizeNamespace from 'canonicalize'\nimport { z } from 'zod'\nimport type { Attestation, AttestationsFile } from './types.js'\n\n/**\n * Extract the serialize function from the canonicalize CommonJS module.\n *\n * Context: The canonicalize package uses `module.exports = function(...)`, which is\n * a CommonJS pattern. With `esModuleInterop: false` (required for library code to\n * avoid leaking tsconfig options to consumers), TypeScript treats the namespace import\n * as the module object itself, not as an object with a default export.\n *\n * The package's type definitions declare `export default function serialize(...)`,\n * which TypeScript interprets as `{ default: function }` when esModuleInterop is off.\n * However, at runtime with NodeNext module resolution, the actual value is just the\n * function itself.\n *\n * This type assertion is safe because:\n * 1. We verified the runtime export structure of the canonicalize module\n * 2. The type matches the published @types signature\n * 3. This is the standard pattern for importing CommonJS modules in strict ESM\n */\n// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\nconst canonicalize = canonicalizeNamespace as unknown as {\n default: (input: unknown) => string | undefined\n}\nconst serialize = canonicalize.default\n\n// Zod schema for attestation validation\nconst attestationSchema = z.object({\n suite: z.string().min(1),\n fingerprint: z.string().regex(/^sha256:[a-f0-9]{64}$/),\n attestedAt: z.string().datetime(),\n attestedBy: z.string().min(1),\n command: z.string().min(1),\n exitCode: z.literal(0),\n})\n\nconst attestationsFileSchema = z.object({\n schemaVersion: z.literal('1'),\n attestations: z.array(attestationSchema),\n signature: z.string(), // Will be validated by crypto module\n})\n\n/**\n * Type guard to check if an error is a Node.js file system error with code.\n * We need to disable the type assertion rule here because TypeScript doesn't\n * provide a way to narrow an object type after checking for a property without\n * using type assertions or indexed access. This is a safe assertion because we\n * check for the property existence and type before using it.\n */\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n if (error === null || typeof error !== 'object') {\n return false\n }\n if (!('code' in error)) {\n return false\n }\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n const errorObj = error as Record<string, unknown>\n return typeof errorObj.code === 'string'\n}\n\n/**\n * Read attestations file from disk (async).\n *\n * @param filePath - Absolute path to the attestations JSON file\n * @returns Parsed attestations file, or null if the file doesn't exist\n * @throws Error on parse or validation errors\n * @public\n */\nexport async function readAttestations(filePath: string): Promise<AttestationsFile | null> {\n try {\n const content = await fs.promises.readFile(filePath, 'utf-8')\n const parsed: unknown = JSON.parse(content)\n // Zod validates and returns the correct type\n return attestationsFileSchema.parse(parsed)\n } catch (error) {\n if (isNodeError(error) && error.code === 'ENOENT') {\n return null\n }\n throw error\n }\n}\n\n/**\n * Read attestations file from disk (sync).\n *\n * @param filePath - Absolute path to the attestations JSON file\n * @returns Parsed attestations file, or null if the file doesn't exist\n * @throws Error on parse or validation errors\n * @public\n */\nexport function readAttestationsSync(filePath: string): AttestationsFile | null {\n try {\n const content = fs.readFileSync(filePath, 'utf-8')\n const parsed: unknown = JSON.parse(content)\n // Zod validates and returns the correct type\n return attestationsFileSchema.parse(parsed)\n } catch (error) {\n if (isNodeError(error) && error.code === 'ENOENT') {\n return null\n }\n throw error\n }\n}\n\n/**\n * Write attestations file to disk (async).\n *\n * Creates parent directories if needed. The signature should be computed\n * separately and passed in.\n *\n * @param filePath - Absolute path to write the attestations file\n * @param attestations - Array of attestation entries\n * @param signature - Cryptographic signature of the attestations\n * @throws Error on validation or write errors\n * @public\n */\nexport async function writeAttestations(\n filePath: string,\n attestations: Attestation[],\n signature: string,\n): Promise<void> {\n const fileContent: AttestationsFile = {\n schemaVersion: '1',\n attestations,\n signature,\n }\n\n // Validate before writing\n attestationsFileSchema.parse(fileContent)\n\n // Create parent directories if needed\n const dir = path.dirname(filePath)\n await fs.promises.mkdir(dir, { recursive: true })\n\n // Write with pretty formatting for readability\n const json = JSON.stringify(fileContent, null, 2)\n await fs.promises.writeFile(filePath, json, 'utf-8')\n}\n\n/**\n * Write attestations file to disk (sync).\n *\n * Creates parent directories if needed. The signature should be computed\n * separately and passed in.\n *\n * @param filePath - Absolute path to write the attestations file\n * @param attestations - Array of attestation entries\n * @param signature - Cryptographic signature of the attestations\n * @throws Error on validation or write errors\n * @public\n */\nexport function writeAttestationsSync(\n filePath: string,\n attestations: Attestation[],\n signature: string,\n): void {\n const fileContent: AttestationsFile = {\n schemaVersion: '1',\n attestations,\n signature,\n }\n\n // Validate before writing\n attestationsFileSchema.parse(fileContent)\n\n // Create parent directories if needed\n const dir = path.dirname(filePath)\n fs.mkdirSync(dir, { recursive: true })\n\n // Write with pretty formatting for readability\n const json = JSON.stringify(fileContent, null, 2)\n fs.writeFileSync(filePath, json, 'utf-8')\n}\n\n/**\n * Find an attestation for a specific suite.\n *\n * @param attestations - Attestations file containing all attestations\n * @param suite - Name of the suite to find\n * @returns The attestation if found, undefined otherwise\n * @public\n */\nexport function findAttestation(\n attestations: AttestationsFile,\n suite: string,\n): Attestation | undefined {\n return attestations.attestations.find((a) => a.suite === suite)\n}\n\n/**\n * Add or update an attestation for a suite.\n *\n * This is an immutable operation that returns a new array.\n *\n * @param attestations - Current array of attestations\n * @param newAttestation - Attestation to add or update\n * @returns New attestations array with the upserted attestation\n * @throws Error if the new attestation fails validation\n * @public\n */\nexport function upsertAttestation(\n attestations: Attestation[],\n newAttestation: Attestation,\n): Attestation[] {\n // Validate the new attestation\n attestationSchema.parse(newAttestation)\n\n const existingIndex = attestations.findIndex((a) => a.suite === newAttestation.suite)\n\n if (existingIndex === -1) {\n // Add new attestation\n return [...attestations, newAttestation]\n } else {\n // Update existing attestation\n const updated = [...attestations]\n // eslint-disable-next-line security/detect-object-injection -- False positive: existingIndex is a safe number from findIndex\n updated[existingIndex] = newAttestation\n return updated\n }\n}\n\n/**\n * Remove attestations for a suite.\n *\n * This is an immutable operation that returns a new array.\n *\n * @param attestations - Current array of attestations\n * @param suite - Name of the suite to remove\n * @returns New attestations array without the specified suite\n * @public\n */\nexport function removeAttestation(attestations: Attestation[], suite: string): Attestation[] {\n return attestations.filter((a) => a.suite !== suite)\n}\n\n/**\n * Compute canonical JSON representation for signing.\n *\n * Implements RFC 8785 JSON Canonicalization Scheme. The canonicalize package provides:\n * 1. Keys sorted lexicographically (Unicode code point order)\n * 2. No whitespace between tokens\n * 3. No trailing commas\n * 4. Strings escaped using \\uXXXX for control characters\n * 5. Numbers: no leading zeros, no +, use lowercase 'e' for exponent\n * 6. UTF-8 encoding\n *\n * @param attestations - Array of attestations to canonicalize\n * @returns Canonical JSON string representation\n * @throws Error if canonicalization fails\n * @public\n */\nexport function canonicalizeAttestations(attestations: Attestation[]): string {\n const canonical = serialize(attestations)\n if (canonical === undefined) {\n throw new Error('Failed to canonicalize attestations')\n }\n return canonical\n}\n\n/**\n * Create a new attestation entry.\n *\n * @param params - Parameters for creating the attestation\n * @param params.suite - Name of the test suite\n * @param params.fingerprint - Fingerprint of the packages in sha256 format\n * @param params.command - Command that was executed\n * @param params.attestedBy - Optional username (defaults to current OS user)\n * @returns Validated attestation object\n * @throws Error if attestation validation fails\n * @public\n */\nexport function createAttestation(params: {\n suite: string\n fingerprint: string\n command: string\n attestedBy?: string\n}): Attestation {\n const attestation: Attestation = {\n suite: params.suite,\n fingerprint: params.fingerprint,\n attestedAt: new Date().toISOString(),\n attestedBy: params.attestedBy ?? os.userInfo().username,\n command: params.command,\n exitCode: 0,\n }\n\n // Validate before returning\n attestationSchema.parse(attestation)\n\n return attestation\n}\n\n/**\n * Options for writing signed attestations.\n * @public\n */\nexport interface WriteSignedAttestationsOptions {\n /** Path to write the attestations file */\n filePath: string\n /** Array of attestations to write */\n attestations: Attestation[]\n /** Path to the private key for signing */\n privateKeyPath: string\n}\n\n/**\n * Options for reading and verifying signed attestations.\n * @public\n */\nexport interface ReadSignedAttestationsOptions {\n /** Path to read the attestations file from */\n filePath: string\n /** Path to the public key for verification */\n publicKeyPath: string\n}\n\n/**\n * Write attestations with a cryptographic signature.\n *\n * This function canonicalizes the attestations, signs them with the private key,\n * and writes the attestations file with the signature.\n *\n * @param options - Options for writing signed attestations\n * @throws Error if signing or writing fails\n * @public\n */\nexport async function writeSignedAttestations(\n options: WriteSignedAttestationsOptions,\n): Promise<void> {\n // Import sign function here to avoid circular dependency\n const { sign } = await import('./crypto.js')\n\n const canonical = canonicalizeAttestations(options.attestations)\n const signature = await sign({\n privateKeyPath: options.privateKeyPath,\n data: canonical,\n })\n await writeAttestations(options.filePath, options.attestations, signature)\n}\n\n/**\n * Read attestations and verify the signature.\n *\n * This function reads the attestations file, canonicalizes the attestations,\n * and verifies the signature using the public key. It throws an error if the\n * file doesn't exist or if signature verification fails.\n *\n * @param options - Options for reading and verifying attestations\n * @returns The attestations file if signature is valid\n * @throws Error if attestations file not found\n * @throws SignatureInvalidError if signature verification fails\n * @public\n */\nexport async function readAndVerifyAttestations(\n options: ReadSignedAttestationsOptions,\n): Promise<AttestationsFile> {\n // Import verify function here to avoid circular dependency\n const { verify } = await import('./crypto.js')\n\n const file = await readAttestations(options.filePath)\n if (!file) {\n throw new Error(`Attestations file not found: ${options.filePath}`)\n }\n\n const canonical = canonicalizeAttestations(file.attestations)\n const isValid = await verify({\n publicKeyPath: options.publicKeyPath,\n data: canonical,\n signature: file.signature,\n })\n\n if (!isValid) {\n throw new SignatureInvalidError(options.filePath)\n }\n\n return file\n}\n\n/**\n * Error thrown when signature verification fails.\n * @public\n */\nexport class SignatureInvalidError extends Error {\n /**\n * Create a new SignatureInvalidError.\n * @param filePath - Path to the file that failed verification\n */\n constructor(filePath: string) {\n super(`Signature verification failed for: ${filePath}`)\n this.name = 'SignatureInvalidError'\n }\n}\n","/**\n * Verification logic for attestations.\n * @packageDocumentation\n */\n\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type {\n AttestItConfig,\n Attestation,\n AttestationsFile,\n SuiteVerificationResult,\n} from './types.js'\nimport { computeFingerprint } from './fingerprint.js'\nimport { readAndVerifyAttestations, SignatureInvalidError } from './attestation.js'\n\n/**\n * Options for verifying attestations.\n * @public\n */\nexport interface VerifyOptions {\n /** Configuration object */\n config: AttestItConfig\n /** Repository root directory (defaults to process.cwd()) */\n repoRoot?: string\n}\n\n/**\n * Result of verifying all attestations.\n * @public\n */\nexport interface VerifyResult {\n /** Overall success - true if all attestations are valid */\n success: boolean\n /** Whether the attestations file signature is valid */\n signatureValid: boolean\n /** Verification results for each suite */\n suites: SuiteVerificationResult[]\n /** Error messages encountered during verification */\n errors: string[]\n}\n\n/**\n * Verify all attestations against current code state.\n *\n * Verification algorithm:\n * 1. Load and verify attestations file signature\n * 2. For each suite in config:\n * a. Compute current fingerprint\n * b. Find matching attestation\n * c. Compare fingerprints\n * d. Check age\n * 3. Check invalidation chains\n * 4. Return aggregated results\n *\n * @param options - Verification options\n * @returns Verification result with status for each suite\n * @public\n */\nexport async function verifyAttestations(options: VerifyOptions): Promise<VerifyResult> {\n const { config, repoRoot = process.cwd() } = options\n const errors: string[] = []\n const suiteResults: SuiteVerificationResult[] = []\n let signatureValid = true\n let attestationsFile: AttestationsFile | null = null\n\n // Resolve paths\n const attestationsPath = resolvePath(config.settings.attestationsPath, repoRoot)\n const publicKeyPath = resolvePath(config.settings.publicKeyPath, repoRoot)\n\n // Step 1: Load and verify attestations\n try {\n if (!fs.existsSync(attestationsPath)) {\n // No attestations file - all suites need attestation\n attestationsFile = null\n } else if (!fs.existsSync(publicKeyPath)) {\n errors.push(`Public key not found: ${publicKeyPath}`)\n signatureValid = false\n } else {\n attestationsFile = await readAndVerifyAttestations({\n filePath: attestationsPath,\n publicKeyPath,\n })\n }\n } catch (err) {\n if (err instanceof SignatureInvalidError) {\n signatureValid = false\n errors.push(err.message)\n } else if (err instanceof Error) {\n errors.push(err.message)\n }\n }\n\n const attestations = attestationsFile?.attestations ?? []\n\n // Step 2: Check each suite\n for (const [suiteName, suiteConfig] of Object.entries(config.suites)) {\n const result = await verifySuite({\n suiteName,\n suiteConfig,\n attestations,\n maxAgeDays: config.settings.maxAgeDays,\n repoRoot,\n })\n suiteResults.push(result)\n }\n\n // Step 3: Check invalidation chains\n checkInvalidationChains(config, suiteResults)\n\n // Step 4: Aggregate results\n const allValid =\n signatureValid && suiteResults.every((r) => r.status === 'VALID') && errors.length === 0\n\n return {\n success: allValid,\n signatureValid,\n suites: suiteResults,\n errors,\n }\n}\n\n/**\n * Options for verifying a single suite.\n * @internal\n */\ninterface VerifySuiteOptions {\n /** Name of the suite */\n suiteName: string\n /** Suite configuration */\n suiteConfig: { packages: string[]; ignore?: string[] }\n /** All attestations from the attestations file */\n attestations: Attestation[]\n /** Maximum age in days before attestation expires */\n maxAgeDays: number\n /** Repository root directory */\n repoRoot: string\n}\n\n/**\n * Verify a single suite's attestation.\n * @internal\n */\nasync function verifySuite(options: VerifySuiteOptions): Promise<SuiteVerificationResult> {\n const { suiteName, suiteConfig, attestations, maxAgeDays, repoRoot } = options\n\n // Compute current fingerprint\n const fingerprintOptions = {\n packages: suiteConfig.packages.map((p) => resolvePath(p, repoRoot)),\n baseDir: repoRoot,\n ...(suiteConfig.ignore && { ignore: suiteConfig.ignore }),\n }\n const fingerprintResult = await computeFingerprint(fingerprintOptions)\n\n // Find attestation for this suite\n const attestation = attestations.find((a) => a.suite === suiteName)\n\n // No attestation found\n if (!attestation) {\n return {\n suite: suiteName,\n status: 'NEEDS_ATTESTATION',\n fingerprint: fingerprintResult.fingerprint,\n message: 'No attestation found for this suite',\n }\n }\n\n // Check fingerprint\n if (attestation.fingerprint !== fingerprintResult.fingerprint) {\n return {\n suite: suiteName,\n status: 'FINGERPRINT_CHANGED',\n fingerprint: fingerprintResult.fingerprint,\n attestation,\n message: `Fingerprint changed from ${attestation.fingerprint.slice(0, 20)}... to ${fingerprintResult.fingerprint.slice(0, 20)}...`,\n }\n }\n\n // Check age\n const attestedAt = new Date(attestation.attestedAt)\n const ageMs = Date.now() - attestedAt.getTime()\n const ageDays = Math.floor(ageMs / (1000 * 60 * 60 * 24))\n\n if (ageDays > maxAgeDays) {\n return {\n suite: suiteName,\n status: 'EXPIRED',\n fingerprint: fingerprintResult.fingerprint,\n attestation,\n age: ageDays,\n message: `Attestation expired (${String(ageDays)} days old, max ${String(maxAgeDays)} days)`,\n }\n }\n\n // All checks passed\n return {\n suite: suiteName,\n status: 'VALID',\n fingerprint: fingerprintResult.fingerprint,\n attestation,\n age: ageDays,\n }\n}\n\n/**\n * Check invalidation chains.\n *\n * If suite A invalidates suite B, and A's attestation is newer than B's,\n * then B should be marked as INVALIDATED_BY_PARENT.\n *\n * @param config - Full configuration\n * @param results - Array of suite verification results to mutate\n * @internal\n */\nfunction checkInvalidationChains(config: AttestItConfig, results: SuiteVerificationResult[]): void {\n for (const [parentName, parentConfig] of Object.entries(config.suites)) {\n const invalidates = parentConfig.invalidates ?? []\n const parentResult = results.find((r) => r.suite === parentName)\n\n if (!parentResult?.attestation) continue\n\n const parentTime = new Date(parentResult.attestation.attestedAt).getTime()\n\n for (const childName of invalidates) {\n const childResult = results.find((r) => r.suite === childName)\n if (!childResult?.attestation) continue\n\n const childTime = new Date(childResult.attestation.attestedAt).getTime()\n\n // If parent was attested AFTER child, child is invalidated\n if (parentTime > childTime && childResult.status === 'VALID') {\n childResult.status = 'INVALIDATED_BY_PARENT'\n childResult.message = `Invalidated by ${parentName} (attested later)`\n }\n }\n }\n}\n\n/**\n * Resolve a path relative to a base directory.\n * @param relativePath - Path that may be relative or absolute\n * @param baseDir - Base directory for resolving relative paths\n * @returns Absolute path\n * @internal\n */\nfunction resolvePath(relativePath: string, baseDir: string): string {\n if (path.isAbsolute(relativePath)) {\n return relativePath\n }\n return path.join(baseDir, relativePath)\n}\n","/**\n * @attest-it/core\n *\n * Core functionality for the attest-it testing framework.\n * @packageDocumentation\n */\n\n/**\n * Package version\n * @public\n */\nexport const version = '0.0.0'\n\n// Types\nexport type {\n AttestItSettings,\n SuiteConfig,\n AttestItConfig,\n Attestation,\n AttestationsFile,\n VerificationStatus,\n SuiteVerificationResult,\n} from './types.js'\n\n// Config\nexport {\n loadConfig,\n loadConfigSync,\n findConfigPath,\n resolveConfigPaths,\n toAttestItConfig,\n ConfigValidationError,\n ConfigNotFoundError,\n type Config,\n} from './config.js'\n\n// Fingerprinting\nexport { computeFingerprint, computeFingerprintSync, listPackageFiles } from './fingerprint.js'\nexport type { FingerprintOptions, FingerprintResult } from './fingerprint.js'\n\n// Attestations\nexport {\n readAttestations,\n readAttestationsSync,\n writeAttestations,\n writeAttestationsSync,\n findAttestation,\n upsertAttestation,\n removeAttestation,\n canonicalizeAttestations,\n createAttestation,\n writeSignedAttestations,\n readAndVerifyAttestations,\n SignatureInvalidError,\n} from './attestation.js'\nexport type {\n WriteSignedAttestationsOptions,\n ReadSignedAttestationsOptions,\n} from './attestation.js'\n\n// Cryptography\nexport {\n checkOpenSSL,\n getDefaultPrivateKeyPath,\n getDefaultPublicKeyPath,\n generateKeyPair,\n sign,\n verify,\n setKeyPermissions,\n} from './crypto.js'\nexport type {\n Algorithm,\n KeyPaths,\n KeygenOptions,\n SignOptions,\n VerifyOptions as CryptoVerifyOptions,\n} from './crypto.js'\n\n// Verification\nexport { verifyAttestations } from './verify.js'\nexport type { VerifyOptions, VerifyResult } from './verify.js'\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@attest-it/core",
|
|
3
|
+
"description": "Core functionality for attest-it",
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"author": "Mike North <michael.l.north@gmail.com>",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"canonicalize": "^2.0.0",
|
|
8
|
+
"tinyglobby": "^0.2.0",
|
|
9
|
+
"yaml": "^2.8.2",
|
|
10
|
+
"zod": "^3.23.8"
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@types/node": "~22.19.3",
|
|
14
|
+
"tsup": "^8.3.5",
|
|
15
|
+
"typescript": "5.8.3",
|
|
16
|
+
"vitest": "^3.0.0"
|
|
17
|
+
},
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"import": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"default": "./dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"require": {
|
|
25
|
+
"types": "./dist/index.d.cts",
|
|
26
|
+
"default": "./dist/index.cjs"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist"
|
|
32
|
+
],
|
|
33
|
+
"keywords": [
|
|
34
|
+
"attestation",
|
|
35
|
+
"testing"
|
|
36
|
+
],
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"main": "./dist/index.js",
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsup && declaration-file-normalizer dist/index.d.ts",
|
|
41
|
+
"check": "pnpm run check:api-report && pnpm run check:eslint && pnpm run check:types",
|
|
42
|
+
"check:api-report": "api-extractor run",
|
|
43
|
+
"check:eslint": "eslint .",
|
|
44
|
+
"check:types": "tsc --noEmit",
|
|
45
|
+
"generate:api-report": "api-extractor run --local",
|
|
46
|
+
"test": "vitest run",
|
|
47
|
+
"test:watch": "vitest"
|
|
48
|
+
},
|
|
49
|
+
"type": "module",
|
|
50
|
+
"types": "./dist/index.d.ts"
|
|
51
|
+
}
|