@attest-it/core 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -94,6 +94,15 @@ export declare function canonicalizeAttestations(attestations: Attestation[]): s
94
94
  */
95
95
  export declare function checkOpenSSL(): Promise<string>;
96
96
 
97
+ /**
98
+ * CLI experience preferences (UX-related settings).
99
+ * @public
100
+ */
101
+ export declare interface CliExperiencePreferences {
102
+ /** Whether the user has declined shell completion installation */
103
+ declinedCompletionInstall?: boolean;
104
+ }
105
+
97
106
  /**
98
107
  * Compute a deterministic fingerprint for a set of packages (async).
99
108
  *
@@ -829,6 +838,23 @@ export declare function getGate(config: AttestItConfig, gateId: string): GateCon
829
838
  */
830
839
  export declare function getLocalConfigPath(): string;
831
840
 
841
+ /**
842
+ * Get a single preference value.
843
+ *
844
+ * @param key - Preference key to get
845
+ * @returns Preference value, or undefined if not set
846
+ * @public
847
+ */
848
+ export declare function getPreference<K extends keyof UserPreferences>(key: K): Promise<undefined | UserPreferences[K]>;
849
+
850
+ /**
851
+ * Get the path to the preferences file.
852
+ *
853
+ * @returns Path to the preferences file
854
+ * @public
855
+ */
856
+ export declare function getPreferencesPath(): string;
857
+
832
858
  /**
833
859
  * Extract the public key from an Ed25519 private key.
834
860
  *
@@ -1086,6 +1112,16 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1086
1112
  */
1087
1113
  export declare function loadLocalConfigSync(configPath?: string): LocalConfig | null;
1088
1114
 
1115
+ /**
1116
+ * Load user preferences from file.
1117
+ * Validates the file contents against the schema and returns
1118
+ * only valid, known preferences.
1119
+ *
1120
+ * @returns User preferences, or empty object if file doesn't exist
1121
+ * @public
1122
+ */
1123
+ export declare function loadPreferences(): Promise<UserPreferences>;
1124
+
1089
1125
  /**
1090
1126
  * The local config file structure at ~/.config/attest-it/config.yaml.
1091
1127
  * @public
@@ -1187,6 +1223,32 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1187
1223
  keychain?: string;
1188
1224
  }
1189
1225
 
1226
+ /**
1227
+ * Merges policy and operational configurations into a single AttestItConfig.
1228
+ *
1229
+ * The merge strategy prioritizes security-critical fields from the policy
1230
+ * configuration while combining operational fields from both sources:
1231
+ *
1232
+ * - **Policy settings** (maxAgeDays, publicKeyPath, attestationsPath) are used as-is
1233
+ * - **Operational settings** (defaultCommand, keyProvider) are added from operational config
1234
+ * - **Team and gates** come exclusively from policy config
1235
+ * - **Suites and groups** come exclusively from operational config
1236
+ *
1237
+ * @param policy - The policy configuration containing security-critical settings
1238
+ * @param operational - The operational configuration containing suites and execution settings
1239
+ * @returns A complete AttestItConfig ready for use in attestation operations
1240
+ *
1241
+ * @example
1242
+ * ```typescript
1243
+ * const policy = parsePolicyContent(policyYaml, 'yaml')
1244
+ * const operational = parseOperationalContent(operationalYaml, 'yaml')
1245
+ * const config = mergeConfigs(policy, operational)
1246
+ * ```
1247
+ *
1248
+ * @public
1249
+ */
1250
+ export declare function mergeConfigs(policy: PolicyConfig, operational: OperationalConfig): AttestItConfig;
1251
+
1190
1252
  /**
1191
1253
  * Information about a 1Password account.
1192
1254
  * @public
@@ -1293,557 +1355,1162 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1293
1355
  }
1294
1356
 
1295
1357
  /**
1296
- * Parse a duration string to milliseconds.
1297
- * Uses the ms library to parse strings like "30d", "7d", "24h".
1298
- *
1299
- * @param duration - Duration string (e.g., "30d", "7d", "24h")
1300
- * @returns Duration in milliseconds
1301
- * @throws {Error} If duration string is invalid
1302
- * @public
1303
- */
1304
- export declare function parseDuration(duration: string): number;
1305
-
1306
- /**
1307
- * Private key reference - points to where the key is stored.
1308
- * @public
1309
- */
1310
- export declare type PrivateKeyRef = {
1311
- account: string;
1312
- keychain?: string;
1313
- service: string;
1314
- type: 'keychain';
1315
- } | {
1316
- account?: string;
1317
- field?: string;
1318
- item: string;
1319
- type: '1password';
1320
- vault: string;
1321
- } | {
1322
- path: string;
1323
- type: 'file';
1324
- };
1325
-
1326
- /**
1327
- * Read attestations and verify the signature.
1328
- *
1329
- * This function reads the attestations file, canonicalizes the attestations,
1330
- * and verifies the signature using the public key. It throws an error if the
1331
- * file doesn't exist or if signature verification fails.
1332
- *
1333
- * @param options - Options for reading and verifying attestations
1334
- * @returns The attestations file if signature is valid
1335
- * @throws Error if attestations file not found
1336
- * @throws SignatureInvalidError if signature verification fails
1337
- * @public
1338
- */
1339
- export declare function readAndVerifyAttestations(options: ReadSignedAttestationsOptions): Promise<AttestationsFile>;
1340
-
1341
- /**
1342
- * Read attestations file from disk (async).
1343
- *
1344
- * @param filePath - Absolute path to the attestations JSON file
1345
- * @returns Parsed attestations file, or null if the file doesn't exist
1346
- * @throws Error on parse or validation errors
1347
- * @public
1348
- */
1349
- export declare function readAttestations(filePath: string): Promise<AttestationsFile | null>;
1350
-
1351
- /**
1352
- * Read attestations file from disk (sync).
1353
- *
1354
- * @param filePath - Absolute path to the attestations JSON file
1355
- * @returns Parsed attestations file, or null if the file doesn't exist
1356
- * @throws Error on parse or validation errors
1357
- * @public
1358
- */
1359
- export declare function readAttestationsSync(filePath: string): AttestationsFile | null;
1360
-
1361
- /**
1362
- * Read seals from the seals.json file (async).
1363
- *
1364
- * @param dir - Directory containing .attest-it/seals.json
1365
- * @returns The seals file contents, or an empty seals file if the file doesn't exist
1366
- * @throws Error if file exists but cannot be read or parsed
1367
- * @public
1368
- */
1369
- export declare function readSeals(dir: string): Promise<SealsFile>;
1370
-
1371
- /**
1372
- * Read seals from the seals.json file (sync).
1373
- *
1374
- * @param dir - Directory containing .attest-it/seals.json
1375
- * @returns The seals file contents, or an empty seals file if the file doesn't exist
1376
- * @throws Error if file exists but cannot be read or parsed
1377
- * @public
1378
- */
1379
- export declare function readSealsSync(dir: string): SealsFile;
1380
-
1381
- /**
1382
- * Options for reading and verifying signed attestations.
1383
- * @public
1384
- */
1385
- export declare interface ReadSignedAttestationsOptions {
1386
- /** Path to read the attestations file from */
1387
- filePath: string;
1388
- /** Path to the public key for verification */
1389
- publicKeyPath: string;
1390
- }
1391
-
1392
- /**
1393
- * Remove attestations for a suite.
1394
- *
1395
- * This is an immutable operation that returns a new array.
1396
- *
1397
- * @param attestations - Current array of attestations
1398
- * @param suite - Name of the suite to remove
1399
- * @returns New attestations array without the specified suite
1358
+ * Operational configuration type inferred from the Zod schema.
1400
1359
  * @public
1401
1360
  */
1402
- export declare function removeAttestation(attestations: Attestation[], suite: string): Attestation[];
1361
+ export declare type OperationalConfig = z.infer<typeof operationalSchema>;
1403
1362
 
1404
1363
  /**
1405
- * Resolve relative paths in the configuration against the repository root.
1364
+ * Zod schema for the operational configuration file.
1406
1365
  *
1407
- * This converts relative paths in settings.publicKeyPath and settings.attestationsPath
1408
- * to absolute paths relative to the repository root.
1366
+ * Operational files define:
1367
+ * - Command execution settings (default command, key provider)
1368
+ * - Suite definitions with command execution details
1369
+ * - Suite groups for organizational purposes
1409
1370
  *
1410
- * @param config - The configuration object
1411
- * @param repoRoot - Absolute path to the repository root
1412
- * @returns Configuration with resolved absolute paths
1413
1371
  * @public
1414
1372
  */
1415
- export declare function resolveConfigPaths(config: Config, repoRoot: string): Config;
1416
-
1417
- /**
1418
- * Save local config to file (async).
1419
- *
1420
- * @param config - LocalConfig object to save
1421
- * @param configPath - Optional path to config file. If not provided, uses default location.
1422
- * @throws {Error} If write fails
1423
- * @public
1424
- */
1425
- export declare function saveLocalConfig(config: LocalConfig, configPath?: string): Promise<void>;
1426
-
1427
- /**
1428
- * Save local config to file (sync).
1429
- *
1430
- * @param config - LocalConfig object to save
1431
- * @param configPath - Optional path to config file. If not provided, uses default location.
1432
- * @throws {Error} If write fails
1433
- * @public
1434
- */
1435
- export declare function saveLocalConfigSync(config: LocalConfig, configPath?: string): void;
1436
-
1437
- /**
1438
- * A seal represents a cryptographic attestation that a gate's fingerprint
1439
- * was signed by an authorized team member.
1440
- * @public
1441
- */
1442
- export declare interface Seal {
1443
- /** Gate identifier (slug) */
1444
- gateId: string;
1445
- /** SHA-256 fingerprint of the gate's content in format "sha256:..." */
1446
- fingerprint: string;
1447
- /** ISO 8601 timestamp when the seal was created */
1448
- timestamp: string;
1449
- /** Team member slug who created the seal */
1450
- sealedBy: string;
1451
- /** Base64-encoded Ed25519 signature of gateId:fingerprint:timestamp */
1452
- signature: string;
1453
- }
1454
-
1455
- /**
1456
- * The seals file structure stored at .attest-it/seals.json.
1457
- * @public
1458
- */
1459
- export declare interface SealsFile {
1460
- /** Schema version for forward compatibility */
1373
+ export declare const operationalSchema: z.ZodObject<{
1374
+ groups: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString, "many">>>;
1375
+ settings: z.ZodDefault<z.ZodObject<{
1376
+ defaultCommand: z.ZodOptional<z.ZodString>;
1377
+ keyProvider: z.ZodOptional<z.ZodObject<{
1378
+ options: z.ZodOptional<z.ZodObject<{
1379
+ account: z.ZodOptional<z.ZodString>;
1380
+ itemName: z.ZodOptional<z.ZodString>;
1381
+ privateKeyPath: z.ZodOptional<z.ZodString>;
1382
+ vault: z.ZodOptional<z.ZodString>;
1383
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
1384
+ account: z.ZodOptional<z.ZodString>;
1385
+ itemName: z.ZodOptional<z.ZodString>;
1386
+ privateKeyPath: z.ZodOptional<z.ZodString>;
1387
+ vault: z.ZodOptional<z.ZodString>;
1388
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
1389
+ account: z.ZodOptional<z.ZodString>;
1390
+ itemName: z.ZodOptional<z.ZodString>;
1391
+ privateKeyPath: z.ZodOptional<z.ZodString>;
1392
+ vault: z.ZodOptional<z.ZodString>;
1393
+ }, z.ZodTypeAny, "passthrough">>>;
1394
+ type: z.ZodUnion<[z.ZodEnum<["filesystem", "1password"]>, z.ZodString]>;
1395
+ }, "strict", z.ZodTypeAny, {
1396
+ options?: undefined | z.objectOutputType<{
1397
+ account: z.ZodOptional<z.ZodString>;
1398
+ itemName: z.ZodOptional<z.ZodString>;
1399
+ privateKeyPath: z.ZodOptional<z.ZodString>;
1400
+ vault: z.ZodOptional<z.ZodString>;
1401
+ }, z.ZodTypeAny, "passthrough">;
1402
+ type: string;
1403
+ }, {
1404
+ options?: undefined | z.objectInputType<{
1405
+ account: z.ZodOptional<z.ZodString>;
1406
+ itemName: z.ZodOptional<z.ZodString>;
1407
+ privateKeyPath: z.ZodOptional<z.ZodString>;
1408
+ vault: z.ZodOptional<z.ZodString>;
1409
+ }, z.ZodTypeAny, "passthrough">;
1410
+ type: string;
1411
+ }>>;
1412
+ }, "strict", z.ZodTypeAny, {
1413
+ defaultCommand?: string | undefined;
1414
+ keyProvider?: {
1415
+ options?: undefined | z.objectOutputType<{
1416
+ account: z.ZodOptional<z.ZodString>;
1417
+ itemName: z.ZodOptional<z.ZodString>;
1418
+ privateKeyPath: z.ZodOptional<z.ZodString>;
1419
+ vault: z.ZodOptional<z.ZodString>;
1420
+ }, z.ZodTypeAny, "passthrough">;
1421
+ type: string;
1422
+ } | undefined;
1423
+ }, {
1424
+ defaultCommand?: string | undefined;
1425
+ keyProvider?: {
1426
+ options?: undefined | z.objectInputType<{
1427
+ account: z.ZodOptional<z.ZodString>;
1428
+ itemName: z.ZodOptional<z.ZodString>;
1429
+ privateKeyPath: z.ZodOptional<z.ZodString>;
1430
+ vault: z.ZodOptional<z.ZodString>;
1431
+ }, z.ZodTypeAny, "passthrough">;
1432
+ type: string;
1433
+ } | undefined;
1434
+ }>>;
1435
+ suites: z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodObject<{
1436
+ command: z.ZodOptional<z.ZodString>;
1437
+ depends_on: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1438
+ description: z.ZodOptional<z.ZodString>;
1439
+ files: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1440
+ gate: z.ZodOptional<z.ZodString>;
1441
+ ignore: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1442
+ interactive: z.ZodOptional<z.ZodBoolean>;
1443
+ invalidates: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1444
+ packages: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1445
+ timeout: z.ZodOptional<z.ZodString>;
1446
+ }, "strict", z.ZodTypeAny, {
1447
+ command?: string | undefined;
1448
+ depends_on?: string[] | undefined;
1449
+ description?: string | undefined;
1450
+ files?: string[] | undefined;
1451
+ gate?: string | undefined;
1452
+ ignore?: string[] | undefined;
1453
+ interactive?: boolean | undefined;
1454
+ invalidates?: string[] | undefined;
1455
+ packages?: string[] | undefined;
1456
+ timeout?: string | undefined;
1457
+ }, {
1458
+ command?: string | undefined;
1459
+ depends_on?: string[] | undefined;
1460
+ description?: string | undefined;
1461
+ files?: string[] | undefined;
1462
+ gate?: string | undefined;
1463
+ ignore?: string[] | undefined;
1464
+ interactive?: boolean | undefined;
1465
+ invalidates?: string[] | undefined;
1466
+ packages?: string[] | undefined;
1467
+ timeout?: string | undefined;
1468
+ }>, {
1469
+ command?: string | undefined;
1470
+ depends_on?: string[] | undefined;
1471
+ description?: string | undefined;
1472
+ files?: string[] | undefined;
1473
+ gate?: string | undefined;
1474
+ ignore?: string[] | undefined;
1475
+ interactive?: boolean | undefined;
1476
+ invalidates?: string[] | undefined;
1477
+ packages?: string[] | undefined;
1478
+ timeout?: string | undefined;
1479
+ }, {
1480
+ command?: string | undefined;
1481
+ depends_on?: string[] | undefined;
1482
+ description?: string | undefined;
1483
+ files?: string[] | undefined;
1484
+ gate?: string | undefined;
1485
+ ignore?: string[] | undefined;
1486
+ interactive?: boolean | undefined;
1487
+ invalidates?: string[] | undefined;
1488
+ packages?: string[] | undefined;
1489
+ timeout?: string | undefined;
1490
+ }>>, Record<string, {
1491
+ command?: string | undefined;
1492
+ depends_on?: string[] | undefined;
1493
+ description?: string | undefined;
1494
+ files?: string[] | undefined;
1495
+ gate?: string | undefined;
1496
+ ignore?: string[] | undefined;
1497
+ interactive?: boolean | undefined;
1498
+ invalidates?: string[] | undefined;
1499
+ packages?: string[] | undefined;
1500
+ timeout?: string | undefined;
1501
+ }>, Record<string, {
1502
+ command?: string | undefined;
1503
+ depends_on?: string[] | undefined;
1504
+ description?: string | undefined;
1505
+ files?: string[] | undefined;
1506
+ gate?: string | undefined;
1507
+ ignore?: string[] | undefined;
1508
+ interactive?: boolean | undefined;
1509
+ invalidates?: string[] | undefined;
1510
+ packages?: string[] | undefined;
1511
+ timeout?: string | undefined;
1512
+ }>>;
1513
+ version: z.ZodLiteral<1>;
1514
+ }, "strict", z.ZodTypeAny, {
1515
+ groups?: Record<string, string[]> | undefined;
1516
+ settings: {
1517
+ defaultCommand?: string | undefined;
1518
+ keyProvider?: {
1519
+ options?: undefined | z.objectOutputType<{
1520
+ account: z.ZodOptional<z.ZodString>;
1521
+ itemName: z.ZodOptional<z.ZodString>;
1522
+ privateKeyPath: z.ZodOptional<z.ZodString>;
1523
+ vault: z.ZodOptional<z.ZodString>;
1524
+ }, z.ZodTypeAny, "passthrough">;
1525
+ type: string;
1526
+ } | undefined;
1527
+ };
1528
+ suites: Record<string, {
1529
+ command?: string | undefined;
1530
+ depends_on?: string[] | undefined;
1531
+ description?: string | undefined;
1532
+ files?: string[] | undefined;
1533
+ gate?: string | undefined;
1534
+ ignore?: string[] | undefined;
1535
+ interactive?: boolean | undefined;
1536
+ invalidates?: string[] | undefined;
1537
+ packages?: string[] | undefined;
1538
+ timeout?: string | undefined;
1539
+ }>;
1461
1540
  version: 1;
1462
- /** Map of gate slugs to their seals */
1463
- seals: Record<string, Seal>;
1464
- }
1541
+ }, {
1542
+ groups?: Record<string, string[]> | undefined;
1543
+ settings?: {
1544
+ defaultCommand?: string | undefined;
1545
+ keyProvider?: {
1546
+ options?: undefined | z.objectInputType<{
1547
+ account: z.ZodOptional<z.ZodString>;
1548
+ itemName: z.ZodOptional<z.ZodString>;
1549
+ privateKeyPath: z.ZodOptional<z.ZodString>;
1550
+ vault: z.ZodOptional<z.ZodString>;
1551
+ }, z.ZodTypeAny, "passthrough">;
1552
+ type: string;
1553
+ } | undefined;
1554
+ } | undefined;
1555
+ suites: Record<string, {
1556
+ command?: string | undefined;
1557
+ depends_on?: string[] | undefined;
1558
+ description?: string | undefined;
1559
+ files?: string[] | undefined;
1560
+ gate?: string | undefined;
1561
+ ignore?: string[] | undefined;
1562
+ interactive?: boolean | undefined;
1563
+ invalidates?: string[] | undefined;
1564
+ packages?: string[] | undefined;
1565
+ timeout?: string | undefined;
1566
+ }>;
1567
+ version: 1;
1568
+ }>;
1465
1569
 
1466
1570
  /**
1467
- * Result of verifying a single gate's seal.
1571
+ * Error thrown when operational configuration is invalid.
1468
1572
  * @public
1469
1573
  */
1470
- export declare interface SealVerificationResult {
1471
- /** Gate identifier */
1472
- gateId: string;
1473
- /** Verification state */
1474
- state: VerificationState;
1475
- /** The seal, if one exists */
1476
- seal?: Seal;
1477
- /** Human-readable message explaining the state */
1478
- message?: string;
1574
+ export declare class OperationalValidationError extends Error {
1575
+ readonly issues: z.ZodIssue[];
1576
+ constructor(message: string, issues: z.ZodIssue[]);
1479
1577
  }
1480
1578
 
1481
1579
  /**
1482
- * Set a custom home directory for attest-it configuration.
1483
- * This is useful for testing or running with isolated state.
1580
+ * Parse a duration string to milliseconds.
1581
+ * Uses the ms library to parse strings like "30d", "7d", "24h".
1484
1582
  *
1485
- * @param dir - The directory to use, or null to reset to default
1486
- * @public
1487
- */
1488
- export declare function setAttestItHomeDir(dir: null | string): void;
1489
-
1490
- /**
1491
- * Set restrictive permissions on a private key file.
1492
- * @param keyPath - Path to the private key
1583
+ * @param duration - Duration string (e.g., "30d", "7d", "24h")
1584
+ * @returns Duration in milliseconds
1585
+ * @throws {Error} If duration string is invalid
1493
1586
  * @public
1494
1587
  */
1495
- export declare function setKeyPermissions(keyPath: string): Promise<void>;
1588
+ export declare function parseDuration(duration: string): number;
1496
1589
 
1497
1590
  /**
1498
- * Sign data using an RSA private key with SHA-256.
1591
+ * Parse operational configuration content from a string.
1499
1592
  *
1500
- * Uses `openssl dgst -sha256 -sign` which is universally supported across
1501
- * all OpenSSL and LibreSSL versions.
1502
- *
1503
- * @param options - Signing options
1504
- * @returns Base64-encoded signature
1505
- * @throws Error if signing fails
1506
- * @public
1507
- */
1508
- export declare function sign(options: SignOptions): Promise<string>;
1509
-
1510
- /**
1511
- * Error thrown when signature verification fails.
1512
- * @public
1513
- */
1514
- export declare class SignatureInvalidError extends Error {
1515
- /**
1516
- * Create a new SignatureInvalidError.
1517
- * @param filePath - Path to the file that failed verification
1593
+ * @param content - The operational config file content
1594
+ * @param format - The format of the content ('yaml' or 'json')
1595
+ * @returns Parsed and validated operational configuration
1596
+ * @throws {@link OperationalValidationError} If validation fails
1597
+ * @public
1518
1598
  */
1519
- constructor(filePath: string);
1520
- }
1521
-
1522
- /**
1523
- * Result of seal signature verification.
1524
- * @public
1525
- */
1526
- export declare interface SignatureVerificationResult {
1527
- /** Whether the seal signature is valid */
1528
- valid: boolean;
1529
- /** Error message if verification failed */
1530
- error?: string;
1531
- }
1532
-
1533
- /**
1534
- * Sign data with an Ed25519 private key.
1535
- *
1536
- * @param data - Data to sign (Buffer or UTF-8 string)
1537
- * @param privateKeyPem - PEM-encoded private key
1538
- * @returns Base64-encoded signature
1539
- * @throws Error if signing fails
1540
- * @public
1541
- */
1542
- export declare function signEd25519(data: Buffer | string, privateKeyPem: string): string;
1543
-
1544
- /**
1545
- * Options for signing data.
1546
- * @public
1547
- */
1548
- export declare interface SignOptions {
1549
- /** Path to the private key file (legacy) */
1550
- privateKeyPath?: string;
1551
- /** Key provider to use for retrieving the private key */
1552
- keyProvider?: KeyProvider;
1553
- /** Key reference for the provider */
1554
- keyRef?: string;
1555
- /** Data to sign (string or Buffer) */
1556
- data: Buffer | string;
1557
- }
1558
-
1559
- /**
1560
- * Suite definition from the configuration file.
1561
- * Suites are CLI-layer extensions of gates with command execution capabilities.
1562
- * @public
1563
- */
1564
- export declare interface SuiteConfig {
1565
- /** Reference to a gate (if present, inherits gate configuration) */
1566
- gate?: string;
1567
- /** Human-readable description of what this suite tests */
1568
- description?: string;
1569
- /** Glob patterns for npm packages to include in fingerprint (legacy/backward compatibility) */
1570
- packages?: string[];
1571
- /** Additional file patterns to include in fingerprint */
1572
- files?: string[];
1573
- /** Patterns to ignore when computing fingerprint */
1574
- ignore?: string[];
1575
- /** Command to execute for this suite (overrides defaultCommand) */
1576
- command?: string;
1577
- /** Timeout for command execution (duration string) */
1578
- timeout?: string;
1579
- /** Whether the command is interactive */
1580
- interactive?: boolean;
1581
- /** Other suite names that, when changed, invalidate this suite's attestation */
1582
- invalidates?: string[];
1583
- /** Array of suite names this suite depends on */
1584
- depends_on?: string[];
1585
- }
1586
-
1587
- /**
1588
- * Result of verifying a single suite's attestation.
1589
- * @public
1590
- */
1591
- export declare interface SuiteVerificationResult {
1592
- /** Name of the suite being verified */
1593
- suite: string;
1594
- /** Current verification status */
1595
- status: VerificationStatus;
1596
- /** Current computed fingerprint for the suite */
1597
- fingerprint: string;
1598
- /** The attestation record, if one exists */
1599
- attestation?: Attestation;
1600
- /** List of files that changed (if status is FINGERPRINT_CHANGED) */
1601
- changedFiles?: string[];
1602
- /** Age of the attestation in days (if expired) */
1603
- age?: number;
1604
- /** Human-readable message explaining the status */
1605
- message?: string;
1606
- }
1607
-
1608
- /**
1609
- * Team member configuration.
1610
- * @public
1611
- */
1612
- export declare interface TeamMember {
1613
- /** Display name for the team member */
1614
- name: string;
1615
- /** Email address (optional) */
1616
- email?: string | undefined;
1617
- /** GitHub username (optional) */
1618
- github?: string | undefined;
1619
- /** Base64-encoded Ed25519 public key */
1620
- publicKey: string;
1621
- }
1622
-
1623
- /**
1624
- * Convert Zod-validated Config to AttestItConfig by removing undefined values.
1625
- *
1626
- * The Config type (from Zod) has optional fields as `T | undefined`,
1627
- * while AttestItConfig has optional fields as `T?` (can be absent, not undefined).
1628
- *
1629
- * This adapter removes any undefined values to match the AttestItConfig interface
1630
- * that the core functions expect.
1631
- *
1632
- * @param config - The Zod-validated configuration from loadConfig()
1633
- * @returns Configuration compatible with AttestItConfig
1634
- * @public
1635
- */
1636
- export declare function toAttestItConfig(config: Config): AttestItConfig;
1637
-
1638
- /**
1639
- * Add or update an attestation for a suite.
1640
- *
1641
- * This is an immutable operation that returns a new array.
1642
- *
1643
- * @param attestations - Current array of attestations
1644
- * @param newAttestation - Attestation to add or update
1645
- * @returns New attestations array with the upserted attestation
1646
- * @throws Error if the new attestation fails validation
1647
- * @public
1648
- */
1649
- export declare function upsertAttestation(attestations: Attestation[], newAttestation: Attestation): Attestation[];
1650
-
1651
- /**
1652
- * Verification state for a gate's seal.
1653
- * @public
1654
- */
1655
- export declare type VerificationState = 'FINGERPRINT_MISMATCH' | 'INVALID_SIGNATURE' | 'MISSING' | 'STALE' | 'UNKNOWN_SIGNER' | 'VALID';
1656
-
1657
- /**
1658
- * Verification status codes for suite attestations.
1659
- * @public
1660
- */
1661
- export declare type VerificationStatus = 'EXPIRED' | 'FINGERPRINT_CHANGED' | 'INVALIDATED_BY_PARENT' | 'NEEDS_ATTESTATION' | 'SIGNATURE_INVALID' | 'VALID';
1662
-
1663
- /**
1664
- * Verify a signature using an RSA public key with SHA-256.
1665
- *
1666
- * Uses `openssl dgst -sha256 -verify` which is universally supported across
1667
- * all OpenSSL and LibreSSL versions.
1668
- *
1669
- * @param options - Verification options
1670
- * @returns true if signature is valid
1671
- * @throws Error if verification fails (not just invalid signature)
1672
- * @public
1673
- */
1674
- export declare function verify(options: CryptoVerifyOptions): Promise<boolean>;
1675
-
1676
- /**
1677
- * Verify all gates' seals.
1678
- *
1679
- * @param config - The attest-it configuration
1680
- * @param seals - The seals file containing all seals
1681
- * @param fingerprints - Map of gate IDs to their current fingerprints
1682
- * @returns Array of verification results for all gates
1683
- * @public
1684
- */
1685
- export declare function verifyAllSeals(config: AttestItConfig, seals: SealsFile, fingerprints: Record<string, string>): SealVerificationResult[];
1686
-
1687
- /**
1688
- * Verify all attestations against current code state.
1689
- *
1690
- * Verification algorithm:
1691
- * 1. Load and verify attestations file signature
1692
- * 2. For each suite in config:
1693
- * a. Compute current fingerprint
1694
- * b. Find matching attestation
1695
- * c. Compare fingerprints
1696
- * d. Check age
1697
- * 3. Check invalidation chains
1698
- * 4. Return aggregated results
1699
- *
1700
- * @param options - Verification options
1701
- * @returns Verification result with status for each suite
1702
- * @public
1703
- */
1704
- export declare function verifyAttestations(options: VerifyOptions): Promise<VerifyResult>;
1705
-
1706
- /**
1707
- * Verify an Ed25519 signature.
1708
- *
1709
- * @param data - Original data that was signed
1710
- * @param signature - Base64-encoded signature to verify
1711
- * @param publicKeyBase64 - Base64-encoded public key (raw 32 bytes)
1712
- * @returns true if signature is valid, false otherwise
1713
- * @throws Error if verification fails (not just invalid signature)
1714
- * @public
1715
- */
1716
- export declare function verifyEd25519(data: Buffer | string, signature: string, publicKeyBase64: string): boolean;
1717
-
1718
- /**
1719
- * Verify a single gate's seal.
1720
- *
1721
- * @param config - The attest-it configuration
1722
- * @param gateId - Gate identifier to verify
1723
- * @param seals - The seals file containing all seals
1724
- * @param currentFingerprint - Current computed fingerprint for the gate
1725
- * @returns Verification result for the gate
1726
- * @public
1727
- */
1728
- export declare function verifyGateSeal(config: AttestItConfig, gateId: string, seals: SealsFile, currentFingerprint: string): SealVerificationResult;
1729
-
1730
- /**
1731
- * Options for verifying attestations.
1732
- * @public
1733
- */
1734
- export declare interface VerifyOptions {
1735
- /** Configuration object */
1736
- config: AttestItConfig;
1737
- /** Repository root directory (defaults to process.cwd()) */
1738
- repoRoot?: string;
1739
- }
1740
-
1741
- /**
1742
- * Result of verifying all attestations.
1743
- * @public
1744
- */
1745
- export declare interface VerifyResult {
1746
- /** Overall success - true if all attestations are valid */
1747
- success: boolean;
1748
- /** Whether the attestations file signature is valid */
1749
- signatureValid: boolean;
1750
- /** Verification results for each suite */
1751
- suites: SuiteVerificationResult[];
1752
- /** Error messages encountered during verification */
1753
- errors: string[];
1754
- }
1755
-
1756
- /**
1757
- * Verify a seal's signature against the team member's public key.
1758
- *
1759
- * @param seal - The seal to verify
1760
- * @param config - The attest-it configuration containing team members
1761
- * @returns Verification result with success status and optional error message
1762
- * @public
1763
- */
1764
- export declare function verifySeal(seal: Seal, config: AttestItConfig): SignatureVerificationResult;
1765
-
1766
- /**
1767
- * Package version
1768
- * @public
1769
- */
1770
- export declare const version = "0.0.0";
1771
-
1772
- /**
1773
- * Write attestations file to disk (async).
1774
- *
1775
- * Creates parent directories if needed. The signature should be computed
1776
- * separately and passed in.
1777
- *
1778
- * @param filePath - Absolute path to write the attestations file
1779
- * @param attestations - Array of attestation entries
1780
- * @param signature - Cryptographic signature of the attestations
1781
- * @throws Error on validation or write errors
1782
- * @public
1783
- */
1784
- export declare function writeAttestations(filePath: string, attestations: Attestation[], signature: string): Promise<void>;
1785
-
1786
- /**
1787
- * Write attestations file to disk (sync).
1788
- *
1789
- * Creates parent directories if needed. The signature should be computed
1790
- * separately and passed in.
1791
- *
1792
- * @param filePath - Absolute path to write the attestations file
1793
- * @param attestations - Array of attestation entries
1794
- * @param signature - Cryptographic signature of the attestations
1795
- * @throws Error on validation or write errors
1796
- * @public
1797
- */
1798
- export declare function writeAttestationsSync(filePath: string, attestations: Attestation[], signature: string): void;
1799
-
1800
- /**
1801
- * Write seals to the seals.json file (async).
1802
- *
1803
- * @param dir - Directory containing .attest-it/seals.json
1804
- * @param sealsFile - The seals file to write
1805
- * @throws Error if file cannot be written
1806
- * @public
1807
- */
1808
- export declare function writeSeals(dir: string, sealsFile: SealsFile): Promise<void>;
1809
-
1810
- /**
1811
- * Write seals to the seals.json file (sync).
1812
- *
1813
- * @param dir - Directory containing .attest-it/seals.json
1814
- * @param sealsFile - The seals file to write
1815
- * @throws Error if file cannot be written
1816
- * @public
1817
- */
1818
- export declare function writeSealsSync(dir: string, sealsFile: SealsFile): void;
1819
-
1820
- /**
1821
- * Write attestations with a cryptographic signature.
1822
- *
1823
- * This function canonicalizes the attestations, signs them with the private key,
1824
- * and writes the attestations file with the signature.
1825
- *
1826
- * @param options - Options for writing signed attestations
1827
- * @throws Error if signing or writing fails
1828
- * @public
1829
- */
1830
- export declare function writeSignedAttestations(options: WriteSignedAttestationsOptions): Promise<void>;
1831
-
1832
- /**
1833
- * Options for writing signed attestations.
1834
- * @public
1835
- */
1836
- export declare interface WriteSignedAttestationsOptions {
1837
- /** Path to write the attestations file */
1838
- filePath: string;
1839
- /** Array of attestations to write */
1840
- attestations: Attestation[];
1841
- /** Path to the private key for signing (legacy) */
1842
- privateKeyPath?: string;
1843
- /** Key provider for signing */
1844
- keyProvider?: KeyProvider;
1845
- /** Key reference for the provider */
1846
- keyRef?: string;
1847
- }
1848
-
1849
- export { }
1599
+ export declare function parseOperationalContent(content: string, format: 'json' | 'yaml'): OperationalConfig;
1600
+
1601
+ /**
1602
+ * Parse policy configuration content from a string.
1603
+ *
1604
+ * @param content - The policy file content
1605
+ * @param format - The format of the content ('yaml' or 'json')
1606
+ * @returns Parsed and validated policy configuration
1607
+ * @throws {@link PolicyValidationError} If validation fails
1608
+ * @public
1609
+ */
1610
+ export declare function parsePolicyContent(content: string, format: 'json' | 'yaml'): PolicyConfig;
1611
+
1612
+ /**
1613
+ * Policy configuration type inferred from the Zod schema.
1614
+ * @public
1615
+ */
1616
+ export declare type PolicyConfig = z.infer<typeof policySchema>;
1617
+
1618
+ /**
1619
+ * Zod schema for the policy configuration file.
1620
+ *
1621
+ * Policy files define:
1622
+ * - Security settings (key paths, attestation storage, max age)
1623
+ * - Team members and their public keys
1624
+ * - Gates with authorization rules
1625
+ *
1626
+ * @public
1627
+ */
1628
+ export declare const policySchema: z.ZodObject<{
1629
+ gates: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
1630
+ authorizedSigners: z.ZodArray<z.ZodString, "many">;
1631
+ description: z.ZodString;
1632
+ fingerprint: z.ZodObject<{
1633
+ exclude: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1634
+ paths: z.ZodArray<z.ZodString, "many">;
1635
+ }, "strict", z.ZodTypeAny, {
1636
+ exclude?: string[] | undefined;
1637
+ paths: string[];
1638
+ }, {
1639
+ exclude?: string[] | undefined;
1640
+ paths: string[];
1641
+ }>;
1642
+ maxAge: z.ZodEffects<z.ZodString, string, string>;
1643
+ name: z.ZodString;
1644
+ }, "strict", z.ZodTypeAny, {
1645
+ authorizedSigners: string[];
1646
+ description: string;
1647
+ fingerprint: {
1648
+ exclude?: string[] | undefined;
1649
+ paths: string[];
1650
+ };
1651
+ maxAge: string;
1652
+ name: string;
1653
+ }, {
1654
+ authorizedSigners: string[];
1655
+ description: string;
1656
+ fingerprint: {
1657
+ exclude?: string[] | undefined;
1658
+ paths: string[];
1659
+ };
1660
+ maxAge: string;
1661
+ name: string;
1662
+ }>>>;
1663
+ settings: z.ZodDefault<z.ZodObject<{
1664
+ attestationsPath: z.ZodDefault<z.ZodString>;
1665
+ maxAgeDays: z.ZodDefault<z.ZodNumber>;
1666
+ publicKeyPath: z.ZodDefault<z.ZodString>;
1667
+ }, "strict", z.ZodTypeAny, {
1668
+ attestationsPath: string;
1669
+ maxAgeDays: number;
1670
+ publicKeyPath: string;
1671
+ }, {
1672
+ attestationsPath?: string | undefined;
1673
+ maxAgeDays?: number | undefined;
1674
+ publicKeyPath?: string | undefined;
1675
+ }>>;
1676
+ team: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
1677
+ email: z.ZodOptional<z.ZodString>;
1678
+ github: z.ZodOptional<z.ZodString>;
1679
+ name: z.ZodString;
1680
+ publicKey: z.ZodString;
1681
+ }, "strict", z.ZodTypeAny, {
1682
+ email?: string | undefined;
1683
+ github?: string | undefined;
1684
+ name: string;
1685
+ publicKey: string;
1686
+ }, {
1687
+ email?: string | undefined;
1688
+ github?: string | undefined;
1689
+ name: string;
1690
+ publicKey: string;
1691
+ }>>>;
1692
+ version: z.ZodLiteral<1>;
1693
+ }, "strict", z.ZodTypeAny, {
1694
+ gates?: Record<string, {
1695
+ authorizedSigners: string[];
1696
+ description: string;
1697
+ fingerprint: {
1698
+ exclude?: string[] | undefined;
1699
+ paths: string[];
1700
+ };
1701
+ maxAge: string;
1702
+ name: string;
1703
+ }> | undefined;
1704
+ settings: {
1705
+ attestationsPath: string;
1706
+ maxAgeDays: number;
1707
+ publicKeyPath: string;
1708
+ };
1709
+ team?: Record<string, {
1710
+ email?: string | undefined;
1711
+ github?: string | undefined;
1712
+ name: string;
1713
+ publicKey: string;
1714
+ }> | undefined;
1715
+ version: 1;
1716
+ }, {
1717
+ gates?: Record<string, {
1718
+ authorizedSigners: string[];
1719
+ description: string;
1720
+ fingerprint: {
1721
+ exclude?: string[] | undefined;
1722
+ paths: string[];
1723
+ };
1724
+ maxAge: string;
1725
+ name: string;
1726
+ }> | undefined;
1727
+ settings?: {
1728
+ attestationsPath?: string | undefined;
1729
+ maxAgeDays?: number | undefined;
1730
+ publicKeyPath?: string | undefined;
1731
+ } | undefined;
1732
+ team?: Record<string, {
1733
+ email?: string | undefined;
1734
+ github?: string | undefined;
1735
+ name: string;
1736
+ publicKey: string;
1737
+ }> | undefined;
1738
+ version: 1;
1739
+ }>;
1740
+
1741
+ /**
1742
+ * Error thrown when policy configuration is invalid.
1743
+ * @public
1744
+ */
1745
+ export declare class PolicyValidationError extends Error {
1746
+ readonly issues: z.ZodIssue[];
1747
+ constructor(message: string, issues: z.ZodIssue[]);
1748
+ }
1749
+
1750
+ /**
1751
+ * Private key reference - points to where the key is stored.
1752
+ * @public
1753
+ */
1754
+ export declare type PrivateKeyRef = {
1755
+ account: string;
1756
+ keychain?: string;
1757
+ service: string;
1758
+ type: 'keychain';
1759
+ } | {
1760
+ account?: string;
1761
+ field?: string;
1762
+ item: string;
1763
+ type: '1password';
1764
+ vault: string;
1765
+ } | {
1766
+ encryptedKeyPath: string;
1767
+ serial?: string;
1768
+ slot?: 1 | 2;
1769
+ type: 'yubikey';
1770
+ } | {
1771
+ path: string;
1772
+ type: 'file';
1773
+ };
1774
+
1775
+ /**
1776
+ * Read attestations and verify the signature.
1777
+ *
1778
+ * This function reads the attestations file, canonicalizes the attestations,
1779
+ * and verifies the signature using the public key. It throws an error if the
1780
+ * file doesn't exist or if signature verification fails.
1781
+ *
1782
+ * @param options - Options for reading and verifying attestations
1783
+ * @returns The attestations file if signature is valid
1784
+ * @throws Error if attestations file not found
1785
+ * @throws SignatureInvalidError if signature verification fails
1786
+ * @public
1787
+ */
1788
+ export declare function readAndVerifyAttestations(options: ReadSignedAttestationsOptions): Promise<AttestationsFile>;
1789
+
1790
+ /**
1791
+ * Read attestations file from disk (async).
1792
+ *
1793
+ * @param filePath - Absolute path to the attestations JSON file
1794
+ * @returns Parsed attestations file, or null if the file doesn't exist
1795
+ * @throws Error on parse or validation errors
1796
+ * @public
1797
+ */
1798
+ export declare function readAttestations(filePath: string): Promise<AttestationsFile | null>;
1799
+
1800
+ /**
1801
+ * Read attestations file from disk (sync).
1802
+ *
1803
+ * @param filePath - Absolute path to the attestations JSON file
1804
+ * @returns Parsed attestations file, or null if the file doesn't exist
1805
+ * @throws Error on parse or validation errors
1806
+ * @public
1807
+ */
1808
+ export declare function readAttestationsSync(filePath: string): AttestationsFile | null;
1809
+
1810
+ /**
1811
+ * Read seals from the seals.json file (async).
1812
+ *
1813
+ * @param dir - Directory containing .attest-it/seals.json
1814
+ * @returns The seals file contents, or an empty seals file if the file doesn't exist
1815
+ * @throws Error if file exists but cannot be read or parsed
1816
+ * @public
1817
+ */
1818
+ export declare function readSeals(dir: string): Promise<SealsFile>;
1819
+
1820
+ /**
1821
+ * Read seals from the seals.json file (sync).
1822
+ *
1823
+ * @param dir - Directory containing .attest-it/seals.json
1824
+ * @returns The seals file contents, or an empty seals file if the file doesn't exist
1825
+ * @throws Error if file exists but cannot be read or parsed
1826
+ * @public
1827
+ */
1828
+ export declare function readSealsSync(dir: string): SealsFile;
1829
+
1830
+ /**
1831
+ * Options for reading and verifying signed attestations.
1832
+ * @public
1833
+ */
1834
+ export declare interface ReadSignedAttestationsOptions {
1835
+ /** Path to read the attestations file from */
1836
+ filePath: string;
1837
+ /** Path to the public key for verification */
1838
+ publicKeyPath: string;
1839
+ }
1840
+
1841
+ /**
1842
+ * Remove attestations for a suite.
1843
+ *
1844
+ * This is an immutable operation that returns a new array.
1845
+ *
1846
+ * @param attestations - Current array of attestations
1847
+ * @param suite - Name of the suite to remove
1848
+ * @returns New attestations array without the specified suite
1849
+ * @public
1850
+ */
1851
+ export declare function removeAttestation(attestations: Attestation[], suite: string): Attestation[];
1852
+
1853
+ /**
1854
+ * Resolve relative paths in the configuration against the repository root.
1855
+ *
1856
+ * This converts relative paths in settings.publicKeyPath and settings.attestationsPath
1857
+ * to absolute paths relative to the repository root.
1858
+ *
1859
+ * @param config - The configuration object
1860
+ * @param repoRoot - Absolute path to the repository root
1861
+ * @returns Configuration with resolved absolute paths
1862
+ * @public
1863
+ */
1864
+ export declare function resolveConfigPaths(config: Config, repoRoot: string): Config;
1865
+
1866
+ /**
1867
+ * Save local config to file (async).
1868
+ *
1869
+ * @param config - LocalConfig object to save
1870
+ * @param configPath - Optional path to config file. If not provided, uses default location.
1871
+ * @throws {Error} If write fails
1872
+ * @public
1873
+ */
1874
+ export declare function saveLocalConfig(config: LocalConfig, configPath?: string): Promise<void>;
1875
+
1876
+ /**
1877
+ * Save local config to file (sync).
1878
+ *
1879
+ * @param config - LocalConfig object to save
1880
+ * @param configPath - Optional path to config file. If not provided, uses default location.
1881
+ * @throws {Error} If write fails
1882
+ * @public
1883
+ */
1884
+ export declare function saveLocalConfigSync(config: LocalConfig, configPath?: string): void;
1885
+
1886
+ /**
1887
+ * Save user preferences to file.
1888
+ *
1889
+ * @param preferences - Preferences to save
1890
+ * @public
1891
+ */
1892
+ export declare function savePreferences(preferences: UserPreferences): Promise<void>;
1893
+
1894
+ /**
1895
+ * A seal represents a cryptographic attestation that a gate's fingerprint
1896
+ * was signed by an authorized team member.
1897
+ * @public
1898
+ */
1899
+ export declare interface Seal {
1900
+ /** Gate identifier (slug) */
1901
+ gateId: string;
1902
+ /** SHA-256 fingerprint of the gate's content in format "sha256:..." */
1903
+ fingerprint: string;
1904
+ /** ISO 8601 timestamp when the seal was created */
1905
+ timestamp: string;
1906
+ /** Team member slug who created the seal */
1907
+ sealedBy: string;
1908
+ /** Base64-encoded Ed25519 signature of gateId:fingerprint:timestamp */
1909
+ signature: string;
1910
+ }
1911
+
1912
+ /**
1913
+ * The seals file structure stored at .attest-it/seals.json.
1914
+ * @public
1915
+ */
1916
+ export declare interface SealsFile {
1917
+ /** Schema version for forward compatibility */
1918
+ version: 1;
1919
+ /** Map of gate slugs to their seals */
1920
+ seals: Record<string, Seal>;
1921
+ }
1922
+
1923
+ /**
1924
+ * Result of verifying a single gate's seal.
1925
+ * @public
1926
+ */
1927
+ export declare interface SealVerificationResult {
1928
+ /** Gate identifier */
1929
+ gateId: string;
1930
+ /** Verification state */
1931
+ state: VerificationState;
1932
+ /** The seal, if one exists */
1933
+ seal?: Seal;
1934
+ /** Human-readable message explaining the state */
1935
+ message?: string;
1936
+ }
1937
+
1938
+ /**
1939
+ * Set a custom home directory for attest-it configuration.
1940
+ * This is useful for testing or running with isolated state.
1941
+ *
1942
+ * @param dir - The directory to use, or null to reset to default
1943
+ * @public
1944
+ */
1945
+ export declare function setAttestItHomeDir(dir: null | string): void;
1946
+
1947
+ /**
1948
+ * Set restrictive permissions on a private key file.
1949
+ * @param keyPath - Path to the private key
1950
+ * @public
1951
+ */
1952
+ export declare function setKeyPermissions(keyPath: string): Promise<void>;
1953
+
1954
+ /**
1955
+ * Update a single preference value.
1956
+ *
1957
+ * @param key - Preference key to update
1958
+ * @param value - New value
1959
+ * @public
1960
+ */
1961
+ export declare function setPreference<K extends keyof UserPreferences>(key: K, value: UserPreferences[K]): Promise<void>;
1962
+
1963
+ /**
1964
+ * Sign data using an RSA private key with SHA-256.
1965
+ *
1966
+ * Uses `openssl dgst -sha256 -sign` which is universally supported across
1967
+ * all OpenSSL and LibreSSL versions.
1968
+ *
1969
+ * @param options - Signing options
1970
+ * @returns Base64-encoded signature
1971
+ * @throws Error if signing fails
1972
+ * @public
1973
+ */
1974
+ export declare function sign(options: SignOptions): Promise<string>;
1975
+
1976
+ /**
1977
+ * Error thrown when signature verification fails.
1978
+ * @public
1979
+ */
1980
+ export declare class SignatureInvalidError extends Error {
1981
+ /**
1982
+ * Create a new SignatureInvalidError.
1983
+ * @param filePath - Path to the file that failed verification
1984
+ */
1985
+ constructor(filePath: string);
1986
+ }
1987
+
1988
+ /**
1989
+ * Result of seal signature verification.
1990
+ * @public
1991
+ */
1992
+ export declare interface SignatureVerificationResult {
1993
+ /** Whether the seal signature is valid */
1994
+ valid: boolean;
1995
+ /** Error message if verification failed */
1996
+ error?: string;
1997
+ }
1998
+
1999
+ /**
2000
+ * Sign data with an Ed25519 private key.
2001
+ *
2002
+ * @param data - Data to sign (Buffer or UTF-8 string)
2003
+ * @param privateKeyPem - PEM-encoded private key
2004
+ * @returns Base64-encoded signature
2005
+ * @throws Error if signing fails
2006
+ * @public
2007
+ */
2008
+ export declare function signEd25519(data: Buffer | string, privateKeyPem: string): string;
2009
+
2010
+ /**
2011
+ * Options for signing data.
2012
+ * @public
2013
+ */
2014
+ export declare interface SignOptions {
2015
+ /** Path to the private key file (legacy) */
2016
+ privateKeyPath?: string;
2017
+ /** Key provider to use for retrieving the private key */
2018
+ keyProvider?: KeyProvider;
2019
+ /** Key reference for the provider */
2020
+ keyRef?: string;
2021
+ /** Data to sign (string or Buffer) */
2022
+ data: Buffer | string;
2023
+ }
2024
+
2025
+ /**
2026
+ * Suite definition from the configuration file.
2027
+ * Suites are CLI-layer extensions of gates with command execution capabilities.
2028
+ * @public
2029
+ */
2030
+ export declare interface SuiteConfig {
2031
+ /** Reference to a gate (if present, inherits gate configuration) */
2032
+ gate?: string;
2033
+ /** Human-readable description of what this suite tests */
2034
+ description?: string;
2035
+ /** Glob patterns for npm packages to include in fingerprint (legacy/backward compatibility) */
2036
+ packages?: string[];
2037
+ /** Additional file patterns to include in fingerprint */
2038
+ files?: string[];
2039
+ /** Patterns to ignore when computing fingerprint */
2040
+ ignore?: string[];
2041
+ /** Command to execute for this suite (overrides defaultCommand) */
2042
+ command?: string;
2043
+ /** Timeout for command execution (duration string) */
2044
+ timeout?: string;
2045
+ /** Whether the command is interactive */
2046
+ interactive?: boolean;
2047
+ /** Other suite names that, when changed, invalidate this suite's attestation */
2048
+ invalidates?: string[];
2049
+ /** Array of suite names this suite depends on */
2050
+ depends_on?: string[];
2051
+ }
2052
+
2053
+ /**
2054
+ * Result of verifying a single suite's attestation.
2055
+ * @public
2056
+ */
2057
+ export declare interface SuiteVerificationResult {
2058
+ /** Name of the suite being verified */
2059
+ suite: string;
2060
+ /** Current verification status */
2061
+ status: VerificationStatus;
2062
+ /** Current computed fingerprint for the suite */
2063
+ fingerprint: string;
2064
+ /** The attestation record, if one exists */
2065
+ attestation?: Attestation;
2066
+ /** List of files that changed (if status is FINGERPRINT_CHANGED) */
2067
+ changedFiles?: string[];
2068
+ /** Age of the attestation in days (if expired) */
2069
+ age?: number;
2070
+ /** Human-readable message explaining the status */
2071
+ message?: string;
2072
+ }
2073
+
2074
+ /**
2075
+ * Team member configuration.
2076
+ * @public
2077
+ */
2078
+ export declare interface TeamMember {
2079
+ /** Display name for the team member */
2080
+ name: string;
2081
+ /** Email address (optional) */
2082
+ email?: string | undefined;
2083
+ /** GitHub username (optional) */
2084
+ github?: string | undefined;
2085
+ /** Base64-encoded Ed25519 public key */
2086
+ publicKey: string;
2087
+ }
2088
+
2089
+ /**
2090
+ * Convert Zod-validated Config to AttestItConfig by removing undefined values.
2091
+ *
2092
+ * The Config type (from Zod) has optional fields as `T | undefined`,
2093
+ * while AttestItConfig has optional fields as `T?` (can be absent, not undefined).
2094
+ *
2095
+ * This adapter removes any undefined values to match the AttestItConfig interface
2096
+ * that the core functions expect.
2097
+ *
2098
+ * @param config - The Zod-validated configuration from loadConfig()
2099
+ * @returns Configuration compatible with AttestItConfig
2100
+ * @public
2101
+ */
2102
+ export declare function toAttestItConfig(config: Config): AttestItConfig;
2103
+
2104
+ /**
2105
+ * Add or update an attestation for a suite.
2106
+ *
2107
+ * This is an immutable operation that returns a new array.
2108
+ *
2109
+ * @param attestations - Current array of attestations
2110
+ * @param newAttestation - Attestation to add or update
2111
+ * @returns New attestations array with the upserted attestation
2112
+ * @throws Error if the new attestation fails validation
2113
+ * @public
2114
+ */
2115
+ export declare function upsertAttestation(attestations: Attestation[], newAttestation: Attestation): Attestation[];
2116
+
2117
+ /**
2118
+ * User preferences stored in ~/.config/attest-it/preferences.yaml
2119
+ * @public
2120
+ */
2121
+ export declare interface UserPreferences {
2122
+ /** CLI experience and UX settings */
2123
+ cliExperience?: CliExperiencePreferences;
2124
+ }
2125
+
2126
+ /**
2127
+ * Validates that all suite-gate references and authorized signers are valid.
2128
+ *
2129
+ * This function performs cross-configuration validation to ensure:
2130
+ * 1. Every suite that references a gate refers to an existing gate in the policy
2131
+ * 2. Every authorized signer in each referenced gate is defined in the policy team
2132
+ *
2133
+ * These validations are critical because:
2134
+ * - Operational config (suites) can come from PR branches
2135
+ * - Policy config (gates, team) comes from the default branch
2136
+ * - We must ensure PR authors cannot reference non-existent gates or signers
2137
+ *
2138
+ * @param policy - The policy configuration containing gates and team definitions
2139
+ * @param operational - The operational configuration containing suite definitions
2140
+ * @returns An array of validation errors (empty if validation passes)
2141
+ *
2142
+ * @example
2143
+ * ```typescript
2144
+ * const errors = validateSuiteGateReferences(policy, operational)
2145
+ * if (errors.length > 0) {
2146
+ * console.error('Validation failed:')
2147
+ * for (const error of errors) {
2148
+ * console.error(` - ${error.message}`)
2149
+ * }
2150
+ * throw new Error('Configuration validation failed')
2151
+ * }
2152
+ * ```
2153
+ *
2154
+ * @public
2155
+ */
2156
+ export declare function validateSuiteGateReferences(policy: PolicyConfig, operational: OperationalConfig): ValidationError[];
2157
+
2158
+ /**
2159
+ * Represents a validation error found during cross-configuration validation.
2160
+ * @public
2161
+ */
2162
+ export declare interface ValidationError {
2163
+ /** The type of validation error */
2164
+ type: ValidationErrorType;
2165
+ /** The suite name where the error was found (if applicable) */
2166
+ suite?: string;
2167
+ /** The gate name involved in the error (if applicable) */
2168
+ gate?: string;
2169
+ /** The signer slug that is missing (if applicable) */
2170
+ signer?: string;
2171
+ /** Human-readable error message explaining the issue */
2172
+ message: string;
2173
+ }
2174
+
2175
+ /**
2176
+ * Validation error types for cross-configuration validation.
2177
+ * @public
2178
+ */
2179
+ export declare type ValidationErrorType = 'MISSING_TEAM_MEMBER' | 'UNKNOWN_GATE';
2180
+
2181
+ /**
2182
+ * Verification state for a gate's seal.
2183
+ * @public
2184
+ */
2185
+ export declare type VerificationState = 'FINGERPRINT_MISMATCH' | 'INVALID_SIGNATURE' | 'MISSING' | 'STALE' | 'UNKNOWN_SIGNER' | 'VALID';
2186
+
2187
+ /**
2188
+ * Verification status codes for suite attestations.
2189
+ * @public
2190
+ */
2191
+ export declare type VerificationStatus = 'EXPIRED' | 'FINGERPRINT_CHANGED' | 'INVALIDATED_BY_PARENT' | 'NEEDS_ATTESTATION' | 'SIGNATURE_INVALID' | 'VALID';
2192
+
2193
+ /**
2194
+ * Verify a signature using an RSA public key with SHA-256.
2195
+ *
2196
+ * Uses `openssl dgst -sha256 -verify` which is universally supported across
2197
+ * all OpenSSL and LibreSSL versions.
2198
+ *
2199
+ * @param options - Verification options
2200
+ * @returns true if signature is valid
2201
+ * @throws Error if verification fails (not just invalid signature)
2202
+ * @public
2203
+ */
2204
+ export declare function verify(options: CryptoVerifyOptions): Promise<boolean>;
2205
+
2206
+ /**
2207
+ * Verify all gates' seals.
2208
+ *
2209
+ * @param config - The attest-it configuration
2210
+ * @param seals - The seals file containing all seals
2211
+ * @param fingerprints - Map of gate IDs to their current fingerprints
2212
+ * @returns Array of verification results for all gates
2213
+ * @public
2214
+ */
2215
+ export declare function verifyAllSeals(config: AttestItConfig, seals: SealsFile, fingerprints: Record<string, string>): SealVerificationResult[];
2216
+
2217
+ /**
2218
+ * Verify all attestations against current code state.
2219
+ *
2220
+ * Verification algorithm:
2221
+ * 1. Load and verify attestations file signature
2222
+ * 2. For each suite in config:
2223
+ * a. Compute current fingerprint
2224
+ * b. Find matching attestation
2225
+ * c. Compare fingerprints
2226
+ * d. Check age
2227
+ * 3. Check invalidation chains
2228
+ * 4. Return aggregated results
2229
+ *
2230
+ * @param options - Verification options
2231
+ * @returns Verification result with status for each suite
2232
+ * @public
2233
+ */
2234
+ export declare function verifyAttestations(options: VerifyOptions): Promise<VerifyResult>;
2235
+
2236
+ /**
2237
+ * Verify an Ed25519 signature.
2238
+ *
2239
+ * @param data - Original data that was signed
2240
+ * @param signature - Base64-encoded signature to verify
2241
+ * @param publicKeyBase64 - Base64-encoded public key (raw 32 bytes)
2242
+ * @returns true if signature is valid, false otherwise
2243
+ * @throws Error if verification fails (not just invalid signature)
2244
+ * @public
2245
+ */
2246
+ export declare function verifyEd25519(data: Buffer | string, signature: string, publicKeyBase64: string): boolean;
2247
+
2248
+ /**
2249
+ * Verify a single gate's seal.
2250
+ *
2251
+ * @param config - The attest-it configuration
2252
+ * @param gateId - Gate identifier to verify
2253
+ * @param seals - The seals file containing all seals
2254
+ * @param currentFingerprint - Current computed fingerprint for the gate
2255
+ * @returns Verification result for the gate
2256
+ * @public
2257
+ */
2258
+ export declare function verifyGateSeal(config: AttestItConfig, gateId: string, seals: SealsFile, currentFingerprint: string): SealVerificationResult;
2259
+
2260
+ /**
2261
+ * Options for verifying attestations.
2262
+ * @public
2263
+ */
2264
+ export declare interface VerifyOptions {
2265
+ /** Configuration object */
2266
+ config: AttestItConfig;
2267
+ /** Repository root directory (defaults to process.cwd()) */
2268
+ repoRoot?: string;
2269
+ }
2270
+
2271
+ /**
2272
+ * Result of verifying all attestations.
2273
+ * @public
2274
+ */
2275
+ export declare interface VerifyResult {
2276
+ /** Overall success - true if all attestations are valid */
2277
+ success: boolean;
2278
+ /** Whether the attestations file signature is valid */
2279
+ signatureValid: boolean;
2280
+ /** Verification results for each suite */
2281
+ suites: SuiteVerificationResult[];
2282
+ /** Error messages encountered during verification */
2283
+ errors: string[];
2284
+ }
2285
+
2286
+ /**
2287
+ * Verify a seal's signature against the team member's public key.
2288
+ *
2289
+ * @param seal - The seal to verify
2290
+ * @param config - The attest-it configuration containing team members
2291
+ * @returns Verification result with success status and optional error message
2292
+ * @public
2293
+ */
2294
+ export declare function verifySeal(seal: Seal, config: AttestItConfig): SignatureVerificationResult;
2295
+
2296
+ /**
2297
+ * Package version
2298
+ * @public
2299
+ */
2300
+ export declare const version = "0.0.0";
2301
+
2302
+ /**
2303
+ * Write attestations file to disk (async).
2304
+ *
2305
+ * Creates parent directories if needed. The signature should be computed
2306
+ * separately and passed in.
2307
+ *
2308
+ * @param filePath - Absolute path to write the attestations file
2309
+ * @param attestations - Array of attestation entries
2310
+ * @param signature - Cryptographic signature of the attestations
2311
+ * @throws Error on validation or write errors
2312
+ * @public
2313
+ */
2314
+ export declare function writeAttestations(filePath: string, attestations: Attestation[], signature: string): Promise<void>;
2315
+
2316
+ /**
2317
+ * Write attestations file to disk (sync).
2318
+ *
2319
+ * Creates parent directories if needed. The signature should be computed
2320
+ * separately and passed in.
2321
+ *
2322
+ * @param filePath - Absolute path to write the attestations file
2323
+ * @param attestations - Array of attestation entries
2324
+ * @param signature - Cryptographic signature of the attestations
2325
+ * @throws Error on validation or write errors
2326
+ * @public
2327
+ */
2328
+ export declare function writeAttestationsSync(filePath: string, attestations: Attestation[], signature: string): void;
2329
+
2330
+ /**
2331
+ * Write seals to the seals.json file (async).
2332
+ *
2333
+ * @param dir - Directory containing .attest-it/seals.json
2334
+ * @param sealsFile - The seals file to write
2335
+ * @throws Error if file cannot be written
2336
+ * @public
2337
+ */
2338
+ export declare function writeSeals(dir: string, sealsFile: SealsFile): Promise<void>;
2339
+
2340
+ /**
2341
+ * Write seals to the seals.json file (sync).
2342
+ *
2343
+ * @param dir - Directory containing .attest-it/seals.json
2344
+ * @param sealsFile - The seals file to write
2345
+ * @throws Error if file cannot be written
2346
+ * @public
2347
+ */
2348
+ export declare function writeSealsSync(dir: string, sealsFile: SealsFile): void;
2349
+
2350
+ /**
2351
+ * Write attestations with a cryptographic signature.
2352
+ *
2353
+ * This function canonicalizes the attestations, signs them with the private key,
2354
+ * and writes the attestations file with the signature.
2355
+ *
2356
+ * @param options - Options for writing signed attestations
2357
+ * @throws Error if signing or writing fails
2358
+ * @public
2359
+ */
2360
+ export declare function writeSignedAttestations(options: WriteSignedAttestationsOptions): Promise<void>;
2361
+
2362
+ /**
2363
+ * Options for writing signed attestations.
2364
+ * @public
2365
+ */
2366
+ export declare interface WriteSignedAttestationsOptions {
2367
+ /** Path to write the attestations file */
2368
+ filePath: string;
2369
+ /** Array of attestations to write */
2370
+ attestations: Attestation[];
2371
+ /** Path to the private key for signing (legacy) */
2372
+ privateKeyPath?: string;
2373
+ /** Key provider for signing */
2374
+ keyProvider?: KeyProvider;
2375
+ /** Key reference for the provider */
2376
+ keyRef?: string;
2377
+ }
2378
+
2379
+ /**
2380
+ * Information about a connected YubiKey.
2381
+ * @public
2382
+ */
2383
+ export declare interface YubiKeyInfo {
2384
+ /** Device serial number */
2385
+ serial: string;
2386
+ /** Device type (e.g., "YubiKey 5 NFC") */
2387
+ type: string;
2388
+ /** Firmware version */
2389
+ firmware: string;
2390
+ }
2391
+
2392
+ /**
2393
+ * Key provider that encrypts private keys using YubiKey HMAC challenge-response.
2394
+ *
2395
+ * @remarks
2396
+ * This provider uses the YubiKey HMAC-SHA1 challenge-response feature (typically slot 2)
2397
+ * to derive an encryption key. The Ed25519 private key is encrypted with AES-256-GCM,
2398
+ * and can only be decrypted when the correct YubiKey is present.
2399
+ *
2400
+ * This approach:
2401
+ * - Works with all YubiKeys that support HMAC-SHA1 challenge-response
2402
+ * - Preserves Ed25519 compatibility (signing happens in software)
2403
+ * - Requires physical YubiKey presence to decrypt and use the key
2404
+ *
2405
+ * **Security Note**: Always use the `serial` option to bind keys to a specific YubiKey.
2406
+ * Without serial verification, any YubiKey with the same HMAC secret could decrypt the key.
2407
+ *
2408
+ * @public
2409
+ */
2410
+ export declare class YubiKeyProvider implements KeyProvider {
2411
+ readonly type = "yubikey";
2412
+ readonly displayName = "YubiKey";
2413
+ private readonly encryptedKeyPath;
2414
+ private readonly slot;
2415
+ private readonly serial?;
2416
+ /**
2417
+ * Create a new YubiKeyProvider.
2418
+ * @param options - Provider options
2419
+ * @throws Error if encryptedKeyPath is outside the attest-it config directory
2420
+ */
2421
+ constructor(options: YubiKeyProviderOptions);
2422
+ /**
2423
+ * Check if ykman CLI is installed and available.
2424
+ * @returns true if ykman is available
2425
+ */
2426
+ static isInstalled(): Promise<boolean>;
2427
+ /**
2428
+ * Check if any YubiKey is connected.
2429
+ * @returns true if at least one YubiKey is connected
2430
+ */
2431
+ static isConnected(): Promise<boolean>;
2432
+ /**
2433
+ * Check if HMAC challenge-response is configured on a slot.
2434
+ * @param slot - Slot number (1 or 2)
2435
+ * @param serial - Optional YubiKey serial number
2436
+ * @returns true if challenge-response is configured
2437
+ */
2438
+ static isChallengeResponseConfigured(slot?: 1 | 2, serial?: string): Promise<boolean>;
2439
+ /**
2440
+ * List connected YubiKeys.
2441
+ * @returns Array of YubiKey information
2442
+ */
2443
+ static listDevices(): Promise<YubiKeyInfo[]>;
2444
+ /**
2445
+ * Check if this provider is available on the current system.
2446
+ * Requires ykman to be installed.
2447
+ */
2448
+ isAvailable(): Promise<boolean>;
2449
+ /**
2450
+ * Check if an encrypted key file exists.
2451
+ * @param keyRef - Path to encrypted key file
2452
+ */
2453
+ keyExists(keyRef: string): Promise<boolean>;
2454
+ /**
2455
+ * Get the private key by decrypting with YubiKey.
2456
+ * Downloads to a temporary file and returns a cleanup function.
2457
+ *
2458
+ * **Important**: Always call the cleanup function when done to securely delete
2459
+ * the temporary key file. The cleanup is also registered for process exit handlers.
2460
+ *
2461
+ * @param keyRef - Path to encrypted key file
2462
+ * @throws Error if the key cannot be decrypted
2463
+ */
2464
+ getPrivateKey(keyRef: string): Promise<KeyRetrievalResult>;
2465
+ /**
2466
+ * Generate a new keypair and store encrypted with YubiKey.
2467
+ * Public key is written to filesystem for repository commit.
2468
+ *
2469
+ * **Security Note**: Always specify a serial number to bind the key to a specific YubiKey.
2470
+ *
2471
+ * @param options - Key generation options
2472
+ */
2473
+ generateKeyPair(options: KeygenProviderOptions): Promise<KeyGenerationResult>;
2474
+ /**
2475
+ * Encrypt an existing private key with YubiKey challenge-response.
2476
+ *
2477
+ * @remarks
2478
+ * This static method allows encrypting a private key that was generated
2479
+ * elsewhere (e.g., by the CLI) without having to create a provider instance first.
2480
+ *
2481
+ * **Security Note**: Always specify a serial number to bind the key to a specific YubiKey.
2482
+ * The serial provides defense-in-depth by ensuring only the intended YubiKey can decrypt.
2483
+ *
2484
+ * @param options - Encryption options
2485
+ * @returns Path to the encrypted key file and storage description
2486
+ * @public
2487
+ */
2488
+ static encryptPrivateKey(options: {
2489
+ encryptedKeyPath: string;
2490
+ privateKey: string;
2491
+ serial?: string;
2492
+ slot?: 1 | 2;
2493
+ }): Promise<{
2494
+ encryptedKeyPath: string;
2495
+ storageDescription: string;
2496
+ }>;
2497
+ /**
2498
+ * Get the configuration for this provider.
2499
+ */
2500
+ getConfig(): KeyProviderConfig;
2501
+ }
2502
+
2503
+ /**
2504
+ * Options for creating a YubiKeyProvider.
2505
+ * @public
2506
+ */
2507
+ export declare interface YubiKeyProviderOptions {
2508
+ /** Path to the encrypted key file */
2509
+ encryptedKeyPath: string;
2510
+ /** YubiKey slot to use for challenge-response (default: 2) */
2511
+ slot?: 1 | 2;
2512
+ /** Serial number of specific YubiKey to use (optional but recommended) */
2513
+ serial?: string;
2514
+ }
2515
+
2516
+ export { }