@super-protocol/pki-sync-client 0.0.0-nvidia-local-verifier

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,372 @@
1
+ # PKI Sync Client
2
+
3
+ A secure client utility for synchronizing secrets from a PKI (Public Key Infrastructure) server with support for Trusted Execution Environments (TEE) including Intel TDX and AMD SEV-SNP.
4
+
5
+ ## Features
6
+
7
+ - **Secure Secret Synchronization**: Fetch and save secrets from PKI servers with mutual TLS authentication
8
+ - **TEE Support**: Automatic detection and support for Intel TDX and AMD SEV-SNP environments
9
+ - **High Availability**: Automatic failover across multiple PKI servers
10
+ - **Certificate Management**: Optionally save client certificates for external use
11
+ - **Flexible Configuration**: YAML-based configuration for secrets and server endpoints
12
+ - **CLI & Programmatic API**: Use as a command-line tool or integrate into your application
13
+
14
+ ## Installation
15
+
16
+ ### As a CLI Tool
17
+
18
+ ```bash
19
+ npm install -g @super-protocol/pki-sync-client
20
+ ```
21
+
22
+ ### As a Library
23
+
24
+ ```bash
25
+ npm install @super-protocol/pki-sync-client
26
+ ```
27
+
28
+ ## Configuration
29
+
30
+ ### Secrets Configuration File
31
+
32
+ Create a YAML file (e.g., `secrets.yaml`) that defines which secrets to sync and where to save them:
33
+
34
+ ```yaml
35
+ secrets:
36
+ - secretName: database-password
37
+ saveTo: /etc/app/db-password.txt
38
+ - secretName: api-key
39
+ saveTo: /var/secrets/api-key.txt
40
+ - secretName: tls-certificate
41
+ saveTo: /etc/app/certs/server.crt
42
+ ```
43
+
44
+ **Schema:**
45
+ - `secretName` (string, required): Name of the secret on the PKI server
46
+ - `saveTo` (string, required): Absolute path where the secret should be saved
47
+
48
+ ### Swarm Environment File
49
+
50
+ Create a YAML file (e.g., `swarm-env.yaml`) that defines PKI server connection details:
51
+
52
+ ```yaml
53
+ pki_authority:
54
+ networkID: my-network-id
55
+ caBundle: |
56
+ -----BEGIN CERTIFICATE-----
57
+ MIIDXTCCAkWgAwIBAgIJAKL0UG+mRkSvMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
58
+ ... (certificate content) ...
59
+ -----END CERTIFICATE-----
60
+ servers:
61
+ - pki-server-1.example.com
62
+ - pki-server-2.example.com
63
+ ```
64
+
65
+ **Schema:**
66
+ - `pki_authority.networkID` (string, required): Network identifier for PKI authentication
67
+ - `pki_authority.caBundle` (string, required): PEM-encoded CA certificate bundle for server verification
68
+ - `pki_authority.servers` (array of strings, required): List of PKI server addresses (with automatic failover)
69
+
70
+ `pki-sync-client` uses only certificates from `pki_authority.caBundle` as
71
+ trusted CAs. System root certificates are never added to the TLS trust store.
72
+
73
+ ## CLI Usage
74
+
75
+ ### Basic Sync Command
76
+
77
+ ```bash
78
+ pki-sync-client sync --config secrets.yaml --swarm-env swarm-env.yaml
79
+ ```
80
+
81
+ ### Complete Options
82
+
83
+ ```bash
84
+ pki-sync-client sync [options]
85
+ ```
86
+
87
+ #### Options
88
+
89
+ | Option | Alias | Type | Default | Description |
90
+ |--------|-------|------|---------|-------------|
91
+ | `--config` | `-c` | string | *required* | Path to secrets configuration file (YAML) |
92
+ | `--swarm-env` | | string | `/sp/swarm/swarm-env.yaml` | Path to swarm environment config (YAML) |
93
+ | `--own-challenge` | | string | `auto` | Authentication challenge type: `auto`, `tdx`, `sev-snp`, or `untrusted` |
94
+ | `--log-level` | `-l` | string | | Log level: `fatal`, `error`, `warn`, `info`, `debug`, `trace` |
95
+ | `--retry-attempts` | | number | `3` | Number of retry attempts per server for retryable network/DNS errors |
96
+ | `--retry-timeout` | | number | `10` | Timeout between retries in seconds for retryable network/DNS errors |
97
+ | `--disable-server-identity-check` | | boolean | `false` | Disable server identity verification (not recommended) |
98
+ | `--network-type-file` | | string | | Path to file containing local network type (`trusted` or `untrusted`). Defaults to `untrusted` when omitted |
99
+ | `--save-certs-to-dir` | | string | | Directory to save client certificates (`key.pem`, `ca.pem`, `cert.pem`) |
100
+ | `--save-certs-prefix` | | string | | Prefix for certificate filenames (e.g., `client` → `client_key.pem`) |
101
+
102
+ By default, if `--log-level` is not provided, `SyncClient` runs with logging disabled.
103
+
104
+ ### Examples
105
+
106
+ **Simple sync (no logs):**
107
+ ```bash
108
+ pki-sync-client sync -c secrets.yaml
109
+ ```
110
+
111
+ **Simple sync with explicit log level:**
112
+ ```bash
113
+ pki-sync-client sync -c secrets.yaml --log-level info
114
+ ```
115
+
116
+ **Sync with custom swarm environment:**
117
+ ```bash
118
+ pki-sync-client sync -c secrets.yaml --swarm-env /custom/path/swarm-env.yaml
119
+ ```
120
+
121
+ **Sync with custom retry policy:**
122
+ ```bash
123
+ pki-sync-client sync -c secrets.yaml --retry-attempts 5 --retry-timeout 3
124
+ ```
125
+
126
+ **Sync with explicit local network type file:**
127
+ ```bash
128
+ pki-sync-client sync -c secrets.yaml --network-type-file /sp/swarm/network-type
129
+ ```
130
+
131
+ **Sync and save client certificates:**
132
+ ```bash
133
+ pki-sync-client sync -c secrets.yaml --save-certs-to-dir /etc/app/certs
134
+ ```
135
+
136
+ **Sync with certificate prefix:**
137
+ ```bash
138
+ pki-sync-client sync -c secrets.yaml \
139
+ --save-certs-to-dir /etc/app/certs \
140
+ --save-certs-prefix myapp
141
+ # Creates: myapp_key.pem, myapp_ca.pem, myapp_cert.pem
142
+ ```
143
+
144
+ **Force specific challenge type:**
145
+ ```bash
146
+ pki-sync-client sync -c secrets.yaml --own-challenge tdx
147
+ ```
148
+
149
+ **Development/testing (untrusted mode):**
150
+ ```bash
151
+ pki-sync-client sync -c secrets.yaml --own-challenge untrusted
152
+ ```
153
+
154
+ ## Programmatic API
155
+
156
+ ### Basic Usage
157
+
158
+ ```typescript
159
+ import { SyncClient, parseConfig, parseSwarmEnv } from '@super-protocol/pki-sync-client';
160
+
161
+ async function syncSecrets() {
162
+ // Parse configuration files
163
+ const config = parseConfig('./secrets.yaml');
164
+ const swarmEnv = parseSwarmEnv('./swarm-env.yaml');
165
+
166
+ // Create sync client
167
+ const client = new SyncClient({
168
+ servers: swarmEnv.pki_authority.servers,
169
+ networkID: swarmEnv.pki_authority.networkID,
170
+ caBundle: swarmEnv.pki_authority.caBundle,
171
+ ownChallenge: 'auto',
172
+ logLevel: 'info',
173
+ });
174
+
175
+ // Perform sync
176
+ await client.sync(config);
177
+ console.log('Secrets synced successfully');
178
+ }
179
+
180
+ syncSecrets().catch(console.error);
181
+ ```
182
+
183
+ ### Advanced Usage with Certificate Saving
184
+
185
+ ```typescript
186
+ import { SyncClient, SyncConfig } from '@super-protocol/pki-sync-client';
187
+
188
+ const client = new SyncClient({
189
+ servers: ['pki1.example.com', 'pki2.example.com'],
190
+ networkID: 'my-network',
191
+ caBundle: fs.readFileSync('./ca-bundle.pem', 'utf-8'),
192
+ ownChallenge: 'tdx',
193
+ logLevel: 'debug',
194
+ disableServerIdentityCheck: false,
195
+ saveCertsToDir: '/etc/app/certs',
196
+ saveCertsPrefix: 'myapp',
197
+ });
198
+
199
+ const config: SyncConfig = {
200
+ secrets: [
201
+ { secretName: 'db-password', saveTo: '/etc/app/db-password' },
202
+ { secretName: 'api-key', saveTo: '/etc/app/api-key' },
203
+ ],
204
+ };
205
+
206
+ await client.sync(config);
207
+ ```
208
+
209
+ ### API Reference
210
+
211
+ #### `SyncClient`
212
+
213
+ **Constructor Options:**
214
+
215
+ ```typescript
216
+ interface SyncClientOptions {
217
+ servers: string[]; // List of PKI server addresses
218
+ networkID: string; // Network identifier
219
+ caBundle: string; // PEM-encoded CA certificate bundle
220
+ ownChallenge: string; // Challenge type: 'auto', 'tdx', 'sev-snp', 'untrusted'
221
+ retryAttempts?: number; // Retry attempts per server (default: 3)
222
+ retryDelaySec?: number; // Delay between retries in seconds (default: 10)
223
+ logLevel?: LogLevel; // Log level: fatal | error | warn | info | debug | trace; if omitted logs are disabled
224
+ disableServerIdentityCheck?: boolean; // Disable server identity verification (default: false)
225
+ networkTypeFile?: string; // File containing local network type: trusted | untrusted; defaults to untrusted
226
+ saveCertsToDir?: string; // Directory to save certificates
227
+ saveCertsPrefix?: string; // Prefix for certificate filenames
228
+ }
229
+ ```
230
+
231
+ **Methods:**
232
+
233
+ - `async sync(config: SyncConfig): Promise<void>` - Synchronize secrets from PKI server
234
+
235
+ #### `parseConfig(configPath: string): SyncConfig`
236
+
237
+ Parse and validate a secrets configuration file.
238
+
239
+ **Throws:**
240
+ - Error if file not found
241
+ - Error if configuration schema is invalid
242
+
243
+ #### `parseSwarmEnv(swarmEnvPath: string): SwarmEnv`
244
+
245
+ Parse and validate a swarm environment configuration file.
246
+
247
+ **Throws:**
248
+ - Error if file not found
249
+ - Error if configuration schema is invalid
250
+
251
+ ## Challenge Types
252
+
253
+ The sync client supports different authentication challenge types:
254
+
255
+ ### `auto` (Default)
256
+ Automatically detects the environment by checking for:
257
+ - `/dev/tdx_guest` → Uses TDX challenge
258
+ - `/dev/sev-guest` → Uses SEV-SNP challenge
259
+ - If the VM is running in Google Cloud and the GCE metadata endpoint responds, TDX/SEV-SNP is temporarily downgraded to `untrusted`
260
+ - Neither found → Falls back to untrusted mode
261
+
262
+ ### `tdx`
263
+ Explicitly use Intel TDX attestation for authentication.
264
+
265
+ ### `sev-snp`
266
+ Explicitly use AMD SEV-SNP attestation for authentication.
267
+
268
+ ### `untrusted`
269
+ Use a static identifier for non-TEE environments (development/testing only).
270
+
271
+ ## How It Works
272
+
273
+ 1. **Configuration Loading**: Parses YAML configuration files for secrets and server details
274
+ 2. **Challenge Selection**: Determines authentication method based on environment or user specification
275
+ 3. **PKI Client Creation**: Establishes mutual TLS connection with PKI server
276
+ 4. **Secret Retrieval**: Requests specified secrets via authenticated API call
277
+ 5. **Secret Storage**: Saves Base64-decoded secrets to specified file paths with secure permissions (0600)
278
+ 6. **Certificate Export** (optional): Saves client certificates for external use
279
+ 7. **Failover**: Automatically tries next server if connection fails
280
+
281
+ Retry behavior details:
282
+ - Retries are performed for retryable network/DNS errors (for example: `ECONNRESET`, `ECONNREFUSED`, `ETIMEDOUT`, `EAI_AGAIN`, `ENOTFOUND`) and for HTTP `429`/`502` responses (e.g. throttling or temporary upstream failure behind OpenResty)
283
+ - Retries are performed against the original hostname (SNI-safe), without replacing hostname with direct IPs
284
+
285
+ ## Error Handling
286
+
287
+ The sync client provides clear error messages for common issues:
288
+
289
+ ```typescript
290
+ try {
291
+ await client.sync(config);
292
+ } catch (error) {
293
+ if (error.message.includes('not found')) {
294
+ // Secret doesn't exist on server
295
+ } else if (error.message.includes('Failed to sync from all servers')) {
296
+ // All servers unreachable
297
+ } else {
298
+ // Other errors (network, authentication, etc.)
299
+ }
300
+ }
301
+ ```
302
+
303
+ ### Common Exit Codes (CLI)
304
+
305
+ - `0`: Success
306
+ - `1`: Sync failed (configuration error, network error, authentication failure, etc.)
307
+
308
+ ## File Permissions
309
+
310
+ - **Secrets**: Saved with mode `0600` (read/write for owner only)
311
+ - **Private keys**: Saved with mode `0600` (read/write for owner only)
312
+ - **Certificates**: Saved with mode `0644` (readable by all, writable by owner)
313
+
314
+ ## Security Considerations
315
+
316
+ 1. **Server Identity Verification**: Always enabled by default. Only disable with `--disable-server-identity-check` in trusted development environments.
317
+ 2. **Root Certificate Trust Verification**: The root certificate network type extension must match the local network type. Trusted roots must include hardware evidence whose mrEnclave is present in the Super Protocol trusted registry.
318
+ 3. **Certificate Validation**: CA bundle is used to verify server certificates during TLS handshake.
319
+ 4. **Mutual TLS**: Both client and server authenticate each other using certificates.
320
+ 5. **TEE Attestation**: In TDX/SEV environments, hardware-backed attestation proves client identity.
321
+ 6. **Secure Storage**: Secrets are saved with restrictive file permissions to prevent unauthorized access.
322
+
323
+ ## Development
324
+
325
+ ### Building from Source
326
+
327
+ ```bash
328
+ npm install
329
+ npm run build
330
+ ```
331
+
332
+ ### Running Without Building
333
+
334
+ ```bash
335
+ npm start -- sync -c conf/secrets-example.yaml
336
+ ```
337
+
338
+ ### Linting
339
+
340
+ ```bash
341
+ npm run lint
342
+ npm run lint:fix
343
+ ```
344
+
345
+ ## Example Configuration Files
346
+
347
+ Example files are provided in the `conf/` directory:
348
+
349
+ - [`conf/secrets-example.yaml`](conf/secrets-example.yaml) - Example secrets configuration
350
+ - [`conf/swarm-env.example.yaml`](conf/swarm-env.example.yaml) - Example swarm environment configuration
351
+
352
+ ## Dependencies
353
+
354
+ - **[@super-protocol/pki-client](https://www.npmjs.com/package/@super-protocol/pki-client)** - PKI client library with TEE support
355
+ - **[@super-protocol/pki-common](https://www.npmjs.com/package/@super-protocol/pki-common)** - Common PKI utilities and types
356
+ - **axios** - HTTP client for API requests
357
+ - **js-yaml** - YAML parser for configuration files
358
+ - **yargs** - Command-line argument parser
359
+
360
+ ## License
361
+
362
+ ISC
363
+
364
+ ## Author
365
+
366
+ Super Protocol
367
+
368
+ ## Related Packages
369
+
370
+ - [@super-protocol/pki-client](../pki-client) - PKI client library
371
+ - [@super-protocol/pki-common](../pki-common) - Common PKI utilities
372
+ - [@super-protocol/pki-authority-service](../pki-authority-service) - PKI Authority Service
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const yargs_1 = __importDefault(require("yargs"));
8
+ const helpers_1 = require("yargs/helpers");
9
+ const config_1 = require("./config");
10
+ const sync_client_1 = require("./sync-client");
11
+ const pki_common_1 = require("@super-protocol/pki-common");
12
+ const DEFAULT_SWARM_ENV_PATH = '/sp/swarm/swarm-env.yaml';
13
+ async function sync(argv) {
14
+ try {
15
+ const config = (0, config_1.parseConfig)(argv.config);
16
+ const swarmEnv = (0, config_1.parseSwarmEnv)(argv.swarmEnv);
17
+ const client = new sync_client_1.SyncClient({
18
+ servers: swarmEnv.pki_authority.servers,
19
+ networkID: swarmEnv.pki_authority.networkID,
20
+ caBundle: swarmEnv.pki_authority.caBundle,
21
+ ownChallenge: argv.ownChallenge,
22
+ retryAttempts: argv.retryAttempts,
23
+ retryDelaySec: argv.retryTimeout,
24
+ logLevel: argv.logLevel,
25
+ disableServerIdentityCheck: argv.disableServerIdentityCheck,
26
+ saveCertsToDir: argv.saveCertsToDir,
27
+ saveCertsPrefix: argv.saveCertsPrefix,
28
+ networkTypeFile: argv.networkTypeFile,
29
+ nvtrust: swarmEnv.nvtrust,
30
+ });
31
+ await client.sync(config);
32
+ console.log('Sync completed successfully');
33
+ }
34
+ catch (error) {
35
+ console.error('Sync failed:', error.message);
36
+ process.exit(1);
37
+ }
38
+ }
39
+ async function main() {
40
+ await (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
41
+ .usage('Usage: $0 sync [options]')
42
+ .command('sync', 'Sync secrets from PKI server', (yargs) => {
43
+ return yargs
44
+ .option('swarm-env', {
45
+ describe: 'Path to swarm environment config (YAML)',
46
+ type: 'string',
47
+ default: DEFAULT_SWARM_ENV_PATH,
48
+ })
49
+ .option('config', {
50
+ alias: 'c',
51
+ describe: 'Path to secrets config file (YAML)',
52
+ type: 'string',
53
+ demandOption: true,
54
+ })
55
+ .option('own-challenge', {
56
+ describe: 'Own challenge string for authentication (auto, tdx, tdx-google, tdx-azure, sev-snp, sev-snp-azure, untrusted)',
57
+ type: 'string',
58
+ default: 'auto',
59
+ })
60
+ .option('log-level', {
61
+ alias: 'l',
62
+ describe: 'Log level',
63
+ choices: Object.values(pki_common_1.LogLevel),
64
+ type: 'string',
65
+ })
66
+ .option('retry-attempts', {
67
+ describe: 'Number of retry attempts per server for retryable network/DNS errors',
68
+ type: 'number',
69
+ default: sync_client_1.SyncClient.DEFAULT_RETRY_ATTEMPTS,
70
+ })
71
+ .option('retry-timeout', {
72
+ describe: 'Timeout between retries in seconds for retryable network/DNS errors',
73
+ type: 'number',
74
+ default: sync_client_1.SyncClient.DEFAULT_RETRY_DELAY_SEC,
75
+ })
76
+ .option('disable-server-identity-check', {
77
+ describe: 'Disable server identity verification',
78
+ type: 'boolean',
79
+ default: false,
80
+ })
81
+ .option('network-type-file', {
82
+ describe: 'Path to file containing local network type (trusted or untrusted)',
83
+ type: 'string',
84
+ })
85
+ .option('save-certs-to-dir', {
86
+ describe: 'Directory to save client certificates (key.pem, ca.pem, cert.pem)',
87
+ type: 'string',
88
+ })
89
+ .option('save-certs-prefix', {
90
+ describe: 'Prefix for certificate filenames (e.g., "client" -> client_key.pem)',
91
+ type: 'string',
92
+ });
93
+ }, sync)
94
+ .demandCommand(1, 'You must provide a command')
95
+ .help()
96
+ .alias('help', 'h')
97
+ .version()
98
+ .alias('version', 'V')
99
+ .parse();
100
+ }
101
+ main().catch((error) => {
102
+ console.error('Error:', error.message);
103
+ process.exit(1);
104
+ });
105
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFDQSxrREFBMEI7QUFDMUIsMkNBQXdDO0FBQ3hDLHFDQUFzRDtBQUN0RCwrQ0FBMkM7QUFDM0MsMkRBQXNEO0FBRXRELE1BQU0sc0JBQXNCLEdBQUcsMEJBQTBCLENBQUM7QUFFMUQsS0FBSyxVQUFVLElBQUksQ0FBQyxJQUFTO0lBQ3pCLElBQUksQ0FBQztRQUNELE1BQU0sTUFBTSxHQUFHLElBQUEsb0JBQVcsRUFBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDeEMsTUFBTSxRQUFRLEdBQUcsSUFBQSxzQkFBYSxFQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUU5QyxNQUFNLE1BQU0sR0FBRyxJQUFJLHdCQUFVLENBQUM7WUFDMUIsT0FBTyxFQUFFLFFBQVEsQ0FBQyxhQUFhLENBQUMsT0FBTztZQUN2QyxTQUFTLEVBQUUsUUFBUSxDQUFDLGFBQWEsQ0FBQyxTQUFTO1lBQzNDLFFBQVEsRUFBRSxRQUFRLENBQUMsYUFBYSxDQUFDLFFBQVE7WUFDekMsWUFBWSxFQUFFLElBQUksQ0FBQyxZQUFZO1lBQy9CLGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYTtZQUNqQyxhQUFhLEVBQUUsSUFBSSxDQUFDLFlBQVk7WUFDaEMsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRO1lBQ3ZCLDBCQUEwQixFQUFFLElBQUksQ0FBQywwQkFBMEI7WUFDM0QsY0FBYyxFQUFFLElBQUksQ0FBQyxjQUFjO1lBQ25DLGVBQWUsRUFBRSxJQUFJLENBQUMsZUFBZTtZQUNyQyxlQUFlLEVBQUUsSUFBSSxDQUFDLGVBQWU7WUFDckMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxPQUFPO1NBQzVCLENBQUMsQ0FBQztRQUVILE1BQU0sTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUUxQixPQUFPLENBQUMsR0FBRyxDQUFD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
@@ -0,0 +1,29 @@
1
+ import { Static } from '@sinclair/typebox';
2
+ declare const SecretEntrySchema: import("@sinclair/typebox").TObject<{
3
+ secretName: import("@sinclair/typebox").TString;
4
+ saveTo: import("@sinclair/typebox").TString;
5
+ }>;
6
+ declare const SyncConfigSchema: import("@sinclair/typebox").TObject<{
7
+ secrets: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
8
+ secretName: import("@sinclair/typebox").TString;
9
+ saveTo: import("@sinclair/typebox").TString;
10
+ }>>;
11
+ }>;
12
+ declare const SwarmEnvSchema: import("@sinclair/typebox").TObject<{
13
+ pki_authority: import("@sinclair/typebox").TObject<{
14
+ networkID: import("@sinclair/typebox").TString;
15
+ caBundle: import("@sinclair/typebox").TString;
16
+ servers: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
17
+ }>;
18
+ nvtrust: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
19
+ verifier: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"remote">, import("@sinclair/typebox").TLiteral<"local">]>>;
20
+ rimUrl: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
21
+ ocspUrl: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
22
+ }>>;
23
+ }>;
24
+ export type SecretEntry = Static<typeof SecretEntrySchema>;
25
+ export type SyncConfig = Static<typeof SyncConfigSchema>;
26
+ export type SwarmEnv = Static<typeof SwarmEnvSchema>;
27
+ export declare function parseConfig(configPath: string): SyncConfig;
28
+ export declare function parseSwarmEnv(swarmEnvPath: string): SwarmEnv;
29
+ export {};
package/dist/config.js ADDED
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.parseSwarmEnv = exports.parseConfig = void 0;
27
+ const typebox_1 = require("@sinclair/typebox");
28
+ const value_1 = require("@sinclair/typebox/value");
29
+ const fs = __importStar(require("fs"));
30
+ const yaml = __importStar(require("js-yaml"));
31
+ const SecretEntrySchema = typebox_1.Type.Object({
32
+ secretName: typebox_1.Type.String(),
33
+ saveTo: typebox_1.Type.String(),
34
+ });
35
+ const SyncConfigSchema = typebox_1.Type.Object({
36
+ secrets: typebox_1.Type.Array(SecretEntrySchema),
37
+ });
38
+ const SwarmEnvSchema = typebox_1.Type.Object({
39
+ pki_authority: typebox_1.Type.Object({
40
+ networkID: typebox_1.Type.String(),
41
+ caBundle: typebox_1.Type.String(),
42
+ servers: typebox_1.Type.Array(typebox_1.Type.String()),
43
+ }),
44
+ nvtrust: typebox_1.Type.Optional(typebox_1.Type.Object({
45
+ verifier: typebox_1.Type.Optional(typebox_1.Type.Union([typebox_1.Type.Literal('remote'), typebox_1.Type.Literal('local')])),
46
+ rimUrl: typebox_1.Type.Optional(typebox_1.Type.String({ minLength: 1 })),
47
+ ocspUrl: typebox_1.Type.Optional(typebox_1.Type.String({ minLength: 1 })),
48
+ })),
49
+ });
50
+ function parseConfig(configPath) {
51
+ if (!fs.existsSync(configPath)) {
52
+ throw new Error(`Config file not found: ${configPath}`);
53
+ }
54
+ const fileContent = fs.readFileSync(configPath, 'utf-8');
55
+ const parsed = yaml.load(fileContent, { schema: yaml.JSON_SCHEMA });
56
+ if (!value_1.Value.Check(SyncConfigSchema, parsed)) {
57
+ const errors = [...value_1.Value.Errors(SyncConfigSchema, parsed)];
58
+ throw new Error(`Invalid config file: ${errors.map((e) => `${e.path}: ${e.message}`).join(', ')}`);
59
+ }
60
+ return parsed;
61
+ }
62
+ exports.parseConfig = parseConfig;
63
+ function parseSwarmEnv(swarmEnvPath) {
64
+ if (!fs.existsSync(swarmEnvPath)) {
65
+ throw new Error(`Swarm env file not found: ${swarmEnvPath}`);
66
+ }
67
+ const fileContent = fs.readFileSync(swarmEnvPath, 'utf-8');
68
+ const parsed = yaml.load(fileContent, { schema: yaml.JSON_SCHEMA });
69
+ if (!value_1.Value.Check(SwarmEnvSchema, parsed)) {
70
+ const errors = [...value_1.Value.Errors(SwarmEnvSchema, parsed)];
71
+ throw new Error(`Invalid swarm env file: ${errors.map((e) => `${e.path}: ${e.message}`).join(', ')}`);
72
+ }
73
+ return parsed;
74
+ }
75
+ exports.parseSwarmEnv = parseSwarmEnv;
76
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLCtDQUFpRDtBQUNqRCxtREFBZ0Q7QUFDaEQsdUNBQXlCO0FBQ3pCLDhDQUFnQztBQUVoQyxNQUFNLGlCQUFpQixHQUFHLGNBQUksQ0FBQyxNQUFNLENBQUM7SUFDbEMsVUFBVSxFQUFFLGNBQUksQ0FBQyxNQUFNLEVBQUU7SUFDekIsTUFBTSxFQUFFLGNBQUksQ0FBQyxNQUFNLEVBQUU7Q0FDeEIsQ0FBQyxDQUFDO0FBRUgsTUFBTSxnQkFBZ0IsR0FBRyxjQUFJLENBQUMsTUFBTSxDQUFDO0lBQ2pDLE9BQU8sRUFBRSxjQUFJLENBQUMsS0FBSyxDQUFDLGlCQUFpQixDQUFDO0NBQ3pDLENBQUMsQ0FBQztBQUVILE1BQU0sY0FBYyxHQUFHLGNBQUksQ0FBQyxNQUFNLENBQUM7SUFDL0IsYUFBYSxFQUFFLGNBQUksQ0FBQyxNQUFNLENBQUM7UUFDdkIsU0FBUyxFQUFFLGNBQUksQ0FBQyxNQUFNLEVBQUU7UUFDeEIsUUFBUSxFQUFFLGNBQUksQ0FBQyxNQUFNLEVBQUU7UUFDdkIsT0FBTyxFQUFFLGNBQUksQ0FBQyxLQUFLLENBQUMsY0FBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO0tBQ3JDLENBQUM7SUFDRixPQUFPLEVBQUUsY0FBSSxDQUFDLFFBQVEsQ0FDbEIsY0FBSSxDQUFDLE1BQU0sQ0FBQztRQUNSLFFBQVEsRUFBRSxjQUFJLENBQUMsUUFBUSxDQUNuQixjQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsY0FBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFBRSxjQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FDOUQ7UUFDRCxNQUFNLEVBQUUsY0FBSSxDQUFDLFFBQVEsQ0FBQyxjQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsU0FBUyxF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
@@ -0,0 +1,2 @@
1
+ export * from './sync-client';
2
+ export * from './config';
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./sync-client"), exports);
18
+ __exportStar(require("./config"), exports);
19
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLGdEQUE4QjtBQUM5QiwyQ0FBeUIifQ==
@@ -0,0 +1,26 @@
1
+ /// <reference types="node" />
2
+ import { Log, NetworkType } from '@super-protocol/pki-common';
3
+ import { TeeEvidenceType, type SNPReport } from '@super-protocol/attestation-common';
4
+ import { buildAzureVerifyOptions, type AttestationWasmAzure } from '@super-protocol/pki-attestation-engine';
5
+ interface AttestationWasmNode extends Pick<AttestationWasmAzure, 'describeTdxTcbStatus'> {
6
+ verifyTeeEvidence(serialized: Uint8Array | ArrayBuffer, options?: ReturnType<typeof buildAzureVerifyOptions>): Promise<{
7
+ evidenceType: TeeEvidenceType;
8
+ }>;
9
+ calculateMrEnclave(serialized: Uint8Array | ArrayBuffer): Promise<{
10
+ mrEnclave: Uint8Array;
11
+ }>;
12
+ calculateSnpSingleCoreMrEnclave(report: SNPReport): Promise<Uint8Array>;
13
+ }
14
+ export interface RootCertificateVerifierOptions {
15
+ caBundle: string;
16
+ networkTypeFile?: string;
17
+ log?: Log;
18
+ getExtensionValue?: (certPem: string, oid: string) => Buffer | undefined;
19
+ loadAttestationModule?: () => Promise<AttestationWasmNode>;
20
+ verifySignature?: (mrEnclave: Uint8Array, evidenceType: TeeEvidenceType) => Promise<void>;
21
+ }
22
+ export declare function resolveLocalNetworkType(networkTypeFile?: string): Promise<NetworkType>;
23
+ export declare const getRootCertificate: (caBundle: string) => string;
24
+ export declare const verifyRootCertificatesMatch: (trustedCaBundle: string, receivedCaBundle: string, log?: Log) => void;
25
+ export declare function verifyRootCertificateTrust(options: RootCertificateVerifierOptions): Promise<void>;
26
+ export {};