@attest-it/core 0.4.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
  *
@@ -765,6 +774,25 @@ export declare function generateKeyPair(options?: KeygenOptions): Promise<KeyPat
765
774
  */
766
775
  export declare function getActiveIdentity(config: LocalConfig): Identity | undefined;
767
776
 
777
+ /**
778
+ * Get the attest-it configuration directory.
779
+ *
780
+ * If a home directory override is set via setAttestItHomeDir(),
781
+ * returns that directory. Otherwise returns ~/.config/attest-it.
782
+ *
783
+ * @returns Path to the configuration directory
784
+ * @public
785
+ */
786
+ export declare function getAttestItConfigDir(): string;
787
+
788
+ /**
789
+ * Get the current attest-it home directory override.
790
+ *
791
+ * @returns The override directory, or null if using default
792
+ * @public
793
+ */
794
+ export declare function getAttestItHomeDir(): null | string;
795
+
768
796
  /**
769
797
  * Get all team members authorized to sign for a gate.
770
798
  *
@@ -802,11 +830,31 @@ export declare function getGate(config: AttestItConfig, gateId: string): GateCon
802
830
  /**
803
831
  * Get the path to the local config file.
804
832
  *
805
- * @returns Path to ~/.config/attest-it/config.yaml
833
+ * If a home directory override is set via setAttestItHomeDir(),
834
+ * returns {homeDir}/config.yaml. Otherwise returns ~/.config/attest-it/config.yaml.
835
+ *
836
+ * @returns Path to the local config file
806
837
  * @public
807
838
  */
808
839
  export declare function getLocalConfigPath(): string;
809
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
+
810
858
  /**
811
859
  * Extract the public key from an Ed25519 private key.
812
860
  *
@@ -1064,6 +1112,16 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1064
1112
  */
1065
1113
  export declare function loadLocalConfigSync(configPath?: string): LocalConfig | null;
1066
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
+
1067
1125
  /**
1068
1126
  * The local config file structure at ~/.config/attest-it/config.yaml.
1069
1127
  * @public
@@ -1084,6 +1142,17 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1084
1142
  constructor(message: string, issues: z.ZodIssue[]);
1085
1143
  }
1086
1144
 
1145
+ /**
1146
+ * Information about a macOS keychain.
1147
+ * @public
1148
+ */
1149
+ export declare interface MacOSKeychain {
1150
+ /** Full path to the keychain file */
1151
+ path: string;
1152
+ /** Display name (filename without extension) */
1153
+ name: string;
1154
+ }
1155
+
1087
1156
  /**
1088
1157
  * Key provider that stores private keys in macOS Keychain.
1089
1158
  *
@@ -1098,6 +1167,7 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1098
1167
  readonly type = "macos-keychain";
1099
1168
  readonly displayName = "macOS Keychain";
1100
1169
  private readonly itemName;
1170
+ private readonly keychain?;
1101
1171
  private static readonly ACCOUNT;
1102
1172
  /**
1103
1173
  * Create a new MacOSKeychainKeyProvider.
@@ -1109,6 +1179,11 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1109
1179
  * Only available on macOS platforms.
1110
1180
  */
1111
1181
  static isAvailable(): boolean;
1182
+ /**
1183
+ * List available keychains on the system.
1184
+ * @returns Array of keychain information
1185
+ */
1186
+ static listKeychains(): Promise<MacOSKeychain[]>;
1112
1187
  /**
1113
1188
  * Check if this provider is available on the current system.
1114
1189
  */
@@ -1144,8 +1219,36 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1144
1219
  export declare interface MacOSKeychainKeyProviderOptions {
1145
1220
  /** Item name in keychain (e.g., "attest-it-private-key") */
1146
1221
  itemName: string;
1222
+ /** Path to the keychain file (optional, uses default keychain if not specified) */
1223
+ keychain?: string;
1147
1224
  }
1148
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
+
1149
1252
  /**
1150
1253
  * Information about a 1Password account.
1151
1254
  * @public
@@ -1252,547 +1355,1162 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1252
1355
  }
1253
1356
 
1254
1357
  /**
1255
- * Parse a duration string to milliseconds.
1256
- * Uses the ms library to parse strings like "30d", "7d", "24h".
1257
- *
1258
- * @param duration - Duration string (e.g., "30d", "7d", "24h")
1259
- * @returns Duration in milliseconds
1260
- * @throws {Error} If duration string is invalid
1261
- * @public
1262
- */
1263
- export declare function parseDuration(duration: string): number;
1264
-
1265
- /**
1266
- * Private key reference - points to where the key is stored.
1267
- * @public
1268
- */
1269
- export declare type PrivateKeyRef = {
1270
- account: string;
1271
- service: string;
1272
- type: 'keychain';
1273
- } | {
1274
- account?: string;
1275
- field?: string;
1276
- item: string;
1277
- type: '1password';
1278
- vault: string;
1279
- } | {
1280
- path: string;
1281
- type: 'file';
1282
- };
1283
-
1284
- /**
1285
- * Read attestations and verify the signature.
1286
- *
1287
- * This function reads the attestations file, canonicalizes the attestations,
1288
- * and verifies the signature using the public key. It throws an error if the
1289
- * file doesn't exist or if signature verification fails.
1290
- *
1291
- * @param options - Options for reading and verifying attestations
1292
- * @returns The attestations file if signature is valid
1293
- * @throws Error if attestations file not found
1294
- * @throws SignatureInvalidError if signature verification fails
1295
- * @public
1296
- */
1297
- export declare function readAndVerifyAttestations(options: ReadSignedAttestationsOptions): Promise<AttestationsFile>;
1298
-
1299
- /**
1300
- * Read attestations file from disk (async).
1301
- *
1302
- * @param filePath - Absolute path to the attestations JSON file
1303
- * @returns Parsed attestations file, or null if the file doesn't exist
1304
- * @throws Error on parse or validation errors
1305
- * @public
1306
- */
1307
- export declare function readAttestations(filePath: string): Promise<AttestationsFile | null>;
1308
-
1309
- /**
1310
- * Read attestations file from disk (sync).
1311
- *
1312
- * @param filePath - Absolute path to the attestations JSON file
1313
- * @returns Parsed attestations file, or null if the file doesn't exist
1314
- * @throws Error on parse or validation errors
1315
- * @public
1316
- */
1317
- export declare function readAttestationsSync(filePath: string): AttestationsFile | null;
1318
-
1319
- /**
1320
- * Read seals from the seals.json file (async).
1321
- *
1322
- * @param dir - Directory containing .attest-it/seals.json
1323
- * @returns The seals file contents, or an empty seals file if the file doesn't exist
1324
- * @throws Error if file exists but cannot be read or parsed
1325
- * @public
1326
- */
1327
- export declare function readSeals(dir: string): Promise<SealsFile>;
1328
-
1329
- /**
1330
- * Read seals from the seals.json file (sync).
1331
- *
1332
- * @param dir - Directory containing .attest-it/seals.json
1333
- * @returns The seals file contents, or an empty seals file if the file doesn't exist
1334
- * @throws Error if file exists but cannot be read or parsed
1335
- * @public
1336
- */
1337
- export declare function readSealsSync(dir: string): SealsFile;
1338
-
1339
- /**
1340
- * Options for reading and verifying signed attestations.
1341
- * @public
1342
- */
1343
- export declare interface ReadSignedAttestationsOptions {
1344
- /** Path to read the attestations file from */
1345
- filePath: string;
1346
- /** Path to the public key for verification */
1347
- publicKeyPath: string;
1348
- }
1349
-
1350
- /**
1351
- * Remove attestations for a suite.
1352
- *
1353
- * This is an immutable operation that returns a new array.
1354
- *
1355
- * @param attestations - Current array of attestations
1356
- * @param suite - Name of the suite to remove
1357
- * @returns New attestations array without the specified suite
1358
+ * Operational configuration type inferred from the Zod schema.
1358
1359
  * @public
1359
1360
  */
1360
- export declare function removeAttestation(attestations: Attestation[], suite: string): Attestation[];
1361
+ export declare type OperationalConfig = z.infer<typeof operationalSchema>;
1361
1362
 
1362
1363
  /**
1363
- * Resolve relative paths in the configuration against the repository root.
1364
+ * Zod schema for the operational configuration file.
1364
1365
  *
1365
- * This converts relative paths in settings.publicKeyPath and settings.attestationsPath
1366
- * 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
1367
1370
  *
1368
- * @param config - The configuration object
1369
- * @param repoRoot - Absolute path to the repository root
1370
- * @returns Configuration with resolved absolute paths
1371
1371
  * @public
1372
1372
  */
1373
- export declare function resolveConfigPaths(config: Config, repoRoot: string): Config;
1374
-
1375
- /**
1376
- * Save local config to file (async).
1377
- *
1378
- * @param config - LocalConfig object to save
1379
- * @param configPath - Optional path to config file. If not provided, uses default location.
1380
- * @throws {Error} If write fails
1381
- * @public
1382
- */
1383
- export declare function saveLocalConfig(config: LocalConfig, configPath?: string): Promise<void>;
1384
-
1385
- /**
1386
- * Save local config to file (sync).
1387
- *
1388
- * @param config - LocalConfig object to save
1389
- * @param configPath - Optional path to config file. If not provided, uses default location.
1390
- * @throws {Error} If write fails
1391
- * @public
1392
- */
1393
- export declare function saveLocalConfigSync(config: LocalConfig, configPath?: string): void;
1394
-
1395
- /**
1396
- * A seal represents a cryptographic attestation that a gate's fingerprint
1397
- * was signed by an authorized team member.
1398
- * @public
1399
- */
1400
- export declare interface Seal {
1401
- /** Gate identifier (slug) */
1402
- gateId: string;
1403
- /** SHA-256 fingerprint of the gate's content in format "sha256:..." */
1404
- fingerprint: string;
1405
- /** ISO 8601 timestamp when the seal was created */
1406
- timestamp: string;
1407
- /** Team member slug who created the seal */
1408
- sealedBy: string;
1409
- /** Base64-encoded Ed25519 signature of gateId:fingerprint:timestamp */
1410
- signature: string;
1411
- }
1412
-
1413
- /**
1414
- * The seals file structure stored at .attest-it/seals.json.
1415
- * @public
1416
- */
1417
- export declare interface SealsFile {
1418
- /** 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
+ }>;
1419
1540
  version: 1;
1420
- /** Map of gate slugs to their seals */
1421
- seals: Record<string, Seal>;
1422
- }
1423
-
1424
- /**
1425
- * Result of verifying a single gate's seal.
1426
- * @public
1427
- */
1428
- export declare interface SealVerificationResult {
1429
- /** Gate identifier */
1430
- gateId: string;
1431
- /** Verification state */
1432
- state: VerificationState;
1433
- /** The seal, if one exists */
1434
- seal?: Seal;
1435
- /** Human-readable message explaining the state */
1436
- message?: string;
1437
- }
1438
-
1439
- /**
1440
- * Set restrictive permissions on a private key file.
1441
- * @param keyPath - Path to the private key
1442
- * @public
1443
- */
1444
- export declare function setKeyPermissions(keyPath: string): Promise<void>;
1445
-
1446
- /**
1447
- * Sign data using an RSA private key with SHA-256.
1448
- *
1449
- * Uses `openssl dgst -sha256 -sign` which is universally supported across
1450
- * all OpenSSL and LibreSSL versions.
1451
- *
1452
- * @param options - Signing options
1453
- * @returns Base64-encoded signature
1454
- * @throws Error if signing fails
1455
- * @public
1456
- */
1457
- export declare function sign(options: SignOptions): Promise<string>;
1458
-
1459
- /**
1460
- * Error thrown when signature verification fails.
1461
- * @public
1462
- */
1463
- export declare class SignatureInvalidError extends Error {
1464
- /**
1465
- * Create a new SignatureInvalidError.
1466
- * @param filePath - Path to the file that failed verification
1467
- */
1468
- constructor(filePath: string);
1469
- }
1470
-
1471
- /**
1472
- * Result of seal signature verification.
1473
- * @public
1474
- */
1475
- export declare interface SignatureVerificationResult {
1476
- /** Whether the seal signature is valid */
1477
- valid: boolean;
1478
- /** Error message if verification failed */
1479
- error?: string;
1480
- }
1481
-
1482
- /**
1483
- * Sign data with an Ed25519 private key.
1484
- *
1485
- * @param data - Data to sign (Buffer or UTF-8 string)
1486
- * @param privateKeyPem - PEM-encoded private key
1487
- * @returns Base64-encoded signature
1488
- * @throws Error if signing fails
1489
- * @public
1490
- */
1491
- export declare function signEd25519(data: Buffer | string, privateKeyPem: string): string;
1492
-
1493
- /**
1494
- * Options for signing data.
1495
- * @public
1496
- */
1497
- export declare interface SignOptions {
1498
- /** Path to the private key file (legacy) */
1499
- privateKeyPath?: string;
1500
- /** Key provider to use for retrieving the private key */
1501
- keyProvider?: KeyProvider;
1502
- /** Key reference for the provider */
1503
- keyRef?: string;
1504
- /** Data to sign (string or Buffer) */
1505
- data: Buffer | string;
1506
- }
1507
-
1508
- /**
1509
- * Suite definition from the configuration file.
1510
- * Suites are CLI-layer extensions of gates with command execution capabilities.
1511
- * @public
1512
- */
1513
- export declare interface SuiteConfig {
1514
- /** Reference to a gate (if present, inherits gate configuration) */
1515
- gate?: string;
1516
- /** Human-readable description of what this suite tests */
1517
- description?: string;
1518
- /** Glob patterns for npm packages to include in fingerprint (legacy/backward compatibility) */
1519
- packages?: string[];
1520
- /** Additional file patterns to include in fingerprint */
1521
- files?: string[];
1522
- /** Patterns to ignore when computing fingerprint */
1523
- ignore?: string[];
1524
- /** Command to execute for this suite (overrides defaultCommand) */
1525
- command?: string;
1526
- /** Timeout for command execution (duration string) */
1527
- timeout?: string;
1528
- /** Whether the command is interactive */
1529
- interactive?: boolean;
1530
- /** Other suite names that, when changed, invalidate this suite's attestation */
1531
- invalidates?: string[];
1532
- /** Array of suite names this suite depends on */
1533
- depends_on?: string[];
1534
- }
1535
-
1536
- /**
1537
- * Result of verifying a single suite's attestation.
1538
- * @public
1539
- */
1540
- export declare interface SuiteVerificationResult {
1541
- /** Name of the suite being verified */
1542
- suite: string;
1543
- /** Current verification status */
1544
- status: VerificationStatus;
1545
- /** Current computed fingerprint for the suite */
1546
- fingerprint: string;
1547
- /** The attestation record, if one exists */
1548
- attestation?: Attestation;
1549
- /** List of files that changed (if status is FINGERPRINT_CHANGED) */
1550
- changedFiles?: string[];
1551
- /** Age of the attestation in days (if expired) */
1552
- age?: number;
1553
- /** Human-readable message explaining the status */
1554
- message?: string;
1555
- }
1556
-
1557
- /**
1558
- * Team member configuration.
1559
- * @public
1560
- */
1561
- export declare interface TeamMember {
1562
- /** Display name for the team member */
1563
- name: string;
1564
- /** Email address (optional) */
1565
- email?: string | undefined;
1566
- /** GitHub username (optional) */
1567
- github?: string | undefined;
1568
- /** Base64-encoded Ed25519 public key */
1569
- publicKey: string;
1570
- }
1571
-
1572
- /**
1573
- * Convert Zod-validated Config to AttestItConfig by removing undefined values.
1574
- *
1575
- * The Config type (from Zod) has optional fields as `T | undefined`,
1576
- * while AttestItConfig has optional fields as `T?` (can be absent, not undefined).
1577
- *
1578
- * This adapter removes any undefined values to match the AttestItConfig interface
1579
- * that the core functions expect.
1580
- *
1581
- * @param config - The Zod-validated configuration from loadConfig()
1582
- * @returns Configuration compatible with AttestItConfig
1583
- * @public
1584
- */
1585
- export declare function toAttestItConfig(config: Config): AttestItConfig;
1586
-
1587
- /**
1588
- * Add or update an attestation for a suite.
1589
- *
1590
- * This is an immutable operation that returns a new array.
1591
- *
1592
- * @param attestations - Current array of attestations
1593
- * @param newAttestation - Attestation to add or update
1594
- * @returns New attestations array with the upserted attestation
1595
- * @throws Error if the new attestation fails validation
1596
- * @public
1597
- */
1598
- export declare function upsertAttestation(attestations: Attestation[], newAttestation: Attestation): Attestation[];
1599
-
1600
- /**
1601
- * Verification state for a gate's seal.
1602
- * @public
1603
- */
1604
- export declare type VerificationState = 'FINGERPRINT_MISMATCH' | 'INVALID_SIGNATURE' | 'MISSING' | 'STALE' | 'UNKNOWN_SIGNER' | 'VALID';
1605
-
1606
- /**
1607
- * Verification status codes for suite attestations.
1608
- * @public
1609
- */
1610
- export declare type VerificationStatus = 'EXPIRED' | 'FINGERPRINT_CHANGED' | 'INVALIDATED_BY_PARENT' | 'NEEDS_ATTESTATION' | 'SIGNATURE_INVALID' | 'VALID';
1611
-
1612
- /**
1613
- * Verify a signature using an RSA public key with SHA-256.
1614
- *
1615
- * Uses `openssl dgst -sha256 -verify` which is universally supported across
1616
- * all OpenSSL and LibreSSL versions.
1617
- *
1618
- * @param options - Verification options
1619
- * @returns true if signature is valid
1620
- * @throws Error if verification fails (not just invalid signature)
1621
- * @public
1622
- */
1623
- export declare function verify(options: CryptoVerifyOptions): Promise<boolean>;
1624
-
1625
- /**
1626
- * Verify all gates' seals.
1627
- *
1628
- * @param config - The attest-it configuration
1629
- * @param seals - The seals file containing all seals
1630
- * @param fingerprints - Map of gate IDs to their current fingerprints
1631
- * @returns Array of verification results for all gates
1632
- * @public
1633
- */
1634
- export declare function verifyAllSeals(config: AttestItConfig, seals: SealsFile, fingerprints: Record<string, string>): SealVerificationResult[];
1635
-
1636
- /**
1637
- * Verify all attestations against current code state.
1638
- *
1639
- * Verification algorithm:
1640
- * 1. Load and verify attestations file signature
1641
- * 2. For each suite in config:
1642
- * a. Compute current fingerprint
1643
- * b. Find matching attestation
1644
- * c. Compare fingerprints
1645
- * d. Check age
1646
- * 3. Check invalidation chains
1647
- * 4. Return aggregated results
1648
- *
1649
- * @param options - Verification options
1650
- * @returns Verification result with status for each suite
1651
- * @public
1652
- */
1653
- export declare function verifyAttestations(options: VerifyOptions): Promise<VerifyResult>;
1654
-
1655
- /**
1656
- * Verify an Ed25519 signature.
1657
- *
1658
- * @param data - Original data that was signed
1659
- * @param signature - Base64-encoded signature to verify
1660
- * @param publicKeyBase64 - Base64-encoded public key (raw 32 bytes)
1661
- * @returns true if signature is valid, false otherwise
1662
- * @throws Error if verification fails (not just invalid signature)
1663
- * @public
1664
- */
1665
- export declare function verifyEd25519(data: Buffer | string, signature: string, publicKeyBase64: string): boolean;
1666
-
1667
- /**
1668
- * Verify a single gate's seal.
1669
- *
1670
- * @param config - The attest-it configuration
1671
- * @param gateId - Gate identifier to verify
1672
- * @param seals - The seals file containing all seals
1673
- * @param currentFingerprint - Current computed fingerprint for the gate
1674
- * @returns Verification result for the gate
1675
- * @public
1676
- */
1677
- export declare function verifyGateSeal(config: AttestItConfig, gateId: string, seals: SealsFile, currentFingerprint: string): SealVerificationResult;
1678
-
1679
- /**
1680
- * Options for verifying attestations.
1681
- * @public
1682
- */
1683
- export declare interface VerifyOptions {
1684
- /** Configuration object */
1685
- config: AttestItConfig;
1686
- /** Repository root directory (defaults to process.cwd()) */
1687
- repoRoot?: string;
1688
- }
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
+ }>;
1689
1569
 
1690
1570
  /**
1691
- * Result of verifying all attestations.
1571
+ * Error thrown when operational configuration is invalid.
1692
1572
  * @public
1693
1573
  */
1694
- export declare interface VerifyResult {
1695
- /** Overall success - true if all attestations are valid */
1696
- success: boolean;
1697
- /** Whether the attestations file signature is valid */
1698
- signatureValid: boolean;
1699
- /** Verification results for each suite */
1700
- suites: SuiteVerificationResult[];
1701
- /** Error messages encountered during verification */
1702
- errors: string[];
1574
+ export declare class OperationalValidationError extends Error {
1575
+ readonly issues: z.ZodIssue[];
1576
+ constructor(message: string, issues: z.ZodIssue[]);
1703
1577
  }
1704
1578
 
1705
1579
  /**
1706
- * Verify a seal's signature against the team member's public key.
1707
- *
1708
- * @param seal - The seal to verify
1709
- * @param config - The attest-it configuration containing team members
1710
- * @returns Verification result with success status and optional error message
1711
- * @public
1712
- */
1713
- export declare function verifySeal(seal: Seal, config: AttestItConfig): SignatureVerificationResult;
1714
-
1715
- /**
1716
- * Package version
1717
- * @public
1718
- */
1719
- export declare const version = "0.0.0";
1720
-
1721
- /**
1722
- * Write attestations file to disk (async).
1723
- *
1724
- * Creates parent directories if needed. The signature should be computed
1725
- * separately and passed in.
1726
- *
1727
- * @param filePath - Absolute path to write the attestations file
1728
- * @param attestations - Array of attestation entries
1729
- * @param signature - Cryptographic signature of the attestations
1730
- * @throws Error on validation or write errors
1731
- * @public
1732
- */
1733
- export declare function writeAttestations(filePath: string, attestations: Attestation[], signature: string): Promise<void>;
1734
-
1735
- /**
1736
- * Write attestations file to disk (sync).
1737
- *
1738
- * Creates parent directories if needed. The signature should be computed
1739
- * separately and passed in.
1740
- *
1741
- * @param filePath - Absolute path to write the attestations file
1742
- * @param attestations - Array of attestation entries
1743
- * @param signature - Cryptographic signature of the attestations
1744
- * @throws Error on validation or write errors
1745
- * @public
1746
- */
1747
- export declare function writeAttestationsSync(filePath: string, attestations: Attestation[], signature: string): void;
1748
-
1749
- /**
1750
- * Write seals to the seals.json file (async).
1751
- *
1752
- * @param dir - Directory containing .attest-it/seals.json
1753
- * @param sealsFile - The seals file to write
1754
- * @throws Error if file cannot be written
1755
- * @public
1756
- */
1757
- export declare function writeSeals(dir: string, sealsFile: SealsFile): Promise<void>;
1758
-
1759
- /**
1760
- * Write seals to the seals.json file (sync).
1580
+ * Parse a duration string to milliseconds.
1581
+ * Uses the ms library to parse strings like "30d", "7d", "24h".
1761
1582
  *
1762
- * @param dir - Directory containing .attest-it/seals.json
1763
- * @param sealsFile - The seals file to write
1764
- * @throws Error if file cannot be written
1583
+ * @param duration - Duration string (e.g., "30d", "7d", "24h")
1584
+ * @returns Duration in milliseconds
1585
+ * @throws {Error} If duration string is invalid
1765
1586
  * @public
1766
1587
  */
1767
- export declare function writeSealsSync(dir: string, sealsFile: SealsFile): void;
1588
+ export declare function parseDuration(duration: string): number;
1768
1589
 
1769
1590
  /**
1770
- * Write attestations with a cryptographic signature.
1591
+ * Parse operational configuration content from a string.
1771
1592
  *
1772
- * This function canonicalizes the attestations, signs them with the private key,
1773
- * and writes the attestations file with the signature.
1774
- *
1775
- * @param options - Options for writing signed attestations
1776
- * @throws Error if signing or writing fails
1777
- * @public
1778
- */
1779
- export declare function writeSignedAttestations(options: WriteSignedAttestationsOptions): Promise<void>;
1780
-
1781
- /**
1782
- * Options for writing signed attestations.
1783
- * @public
1784
- */
1785
- export declare interface WriteSignedAttestationsOptions {
1786
- /** Path to write the attestations file */
1787
- filePath: string;
1788
- /** Array of attestations to write */
1789
- attestations: Attestation[];
1790
- /** Path to the private key for signing (legacy) */
1791
- privateKeyPath?: string;
1792
- /** Key provider for signing */
1793
- keyProvider?: KeyProvider;
1794
- /** Key reference for the provider */
1795
- keyRef?: string;
1796
- }
1797
-
1798
- export { }
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
1598
+ */
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 { }