@treeseed/sdk 0.13.0-rc.85 → 0.13.0-rc.87

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.
Files changed (29) hide show
  1. package/dist/.treeseed-build-complete.json +1 -1
  2. package/dist/configuration/secrets-capability.d.ts +2 -2
  3. package/dist/configuration/secrets-capability.js +2 -2
  4. package/dist/content/validation/content-model-schemas.d.ts +1 -1
  5. package/dist/deployment/hosted-topology-template.d.ts +6 -6
  6. package/dist/deployment/hosted-topology-template.js +1 -1
  7. package/dist/deployment/hosted-topology.d.ts +73 -214
  8. package/dist/deployment/hosted-topology.js +30 -64
  9. package/dist/operator-contracts/canonical-command-tree.js +2 -2
  10. package/dist/operator-contracts/catalog/hosted-topology-operations.d.ts +4 -31
  11. package/dist/operator-contracts/catalog/hosted-topology-operations.js +7 -12
  12. package/dist/operator-contracts/catalog/services/secret-operations.d.ts +62 -0
  13. package/dist/operator-contracts/catalog/services/secret-operations.js +51 -0
  14. package/dist/operator-contracts/control-plane-operations.d.ts +61 -48
  15. package/dist/operator-contracts/control-plane-operations.js +3 -4
  16. package/dist/secrets-capability/github-actions-encryption.d.ts +2 -0
  17. package/dist/secrets-capability/github-actions-encryption.js +11 -0
  18. package/dist/secrets-capability/provider-operation-contracts.d.ts +1 -1
  19. package/dist/secrets-capability/secret-contracts.d.ts +33 -0
  20. package/dist/secrets-capability/secret-contracts.js +49 -0
  21. package/dist/secrets-capability/service-provider-contracts.d.ts +2 -2
  22. package/dist/secrets-capability/service-provider-contracts.js +15 -31
  23. package/package.json +1 -1
  24. package/dist/operator-contracts/catalog/services/service-vault-operations.d.ts +0 -17
  25. package/dist/operator-contracts/catalog/services/service-vault-operations.js +0 -158
  26. package/dist/secrets-capability/service-vault-contracts.d.ts +0 -108
  27. package/dist/secrets-capability/service-vault-contracts.js +0 -74
  28. package/dist/secrets-capability/service-vault-crypto.d.ts +0 -20
  29. package/dist/secrets-capability/service-vault-crypto.js +0 -210
@@ -1,210 +0,0 @@
1
- import sodium from "libsodium-wrappers-sumo";
2
- import {
3
- SERVICE_VAULT_AEAD_ALGORITHM,
4
- SERVICE_VAULT_ENCRYPTION_VERSION,
5
- SERVICE_VAULT_KDF,
6
- SERVICE_VAULT_KEY_AGREEMENT
7
- } from "@treeseed/sdk/secrets-capability";
8
- const b64 = () => sodium.base64_variants.ORIGINAL;
9
- const encode = (value) => sodium.to_base64(value, b64());
10
- const decode = (value) => sodium.from_base64(value, b64());
11
- const hash = (value, key = null) => encode(sodium.crypto_generichash(32, value, key));
12
- async function ready() {
13
- await sodium.ready;
14
- return sodium;
15
- }
16
- function validKey(value, length, label) {
17
- if (!(value instanceof Uint8Array) || value.length !== length) throw new Error(`${label} is invalid.`);
18
- return value;
19
- }
20
- async function createServiceVaultKey() {
21
- const crypto = await ready();
22
- return crypto.randombytes_buf(crypto.crypto_aead_xchacha20poly1305_ietf_KEYBYTES);
23
- }
24
- async function createServiceVaultUserKeyPair() {
25
- const crypto = await ready(), pair = crypto.crypto_box_keypair();
26
- return { publicKey: encode(pair.publicKey), privateKey: pair.privateKey };
27
- }
28
- async function encryptServiceVaultPrivateKey(privateKey, publicKey, passphrase, options = {}) {
29
- const crypto = await ready();
30
- validKey(privateKey, crypto.crypto_box_SECRETKEYBYTES, "Service-vault private key");
31
- validKey(decode(publicKey), crypto.crypto_box_PUBLICKEYBYTES, "Service-vault public key");
32
- if (passphrase.length < 12) throw new Error("Service-vault passphrase must contain at least 12 characters.");
33
- const salt = crypto.randombytes_buf(crypto.crypto_pwhash_SALTBYTES);
34
- const opsLimit = options.opsLimit ?? crypto.crypto_pwhash_OPSLIMIT_MODERATE;
35
- const memLimit = options.memLimit ?? crypto.crypto_pwhash_MEMLIMIT_MODERATE;
36
- const key = crypto.crypto_pwhash(
37
- crypto.crypto_aead_xchacha20poly1305_ietf_KEYBYTES,
38
- passphrase,
39
- salt,
40
- opsLimit,
41
- memLimit,
42
- crypto.crypto_pwhash_ALG_ARGON2ID13
43
- );
44
- const nonce = crypto.randombytes_buf(crypto.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
45
- try {
46
- return {
47
- version: SERVICE_VAULT_ENCRYPTION_VERSION,
48
- algorithm: SERVICE_VAULT_AEAD_ALGORITHM,
49
- kdf: { algorithm: SERVICE_VAULT_KDF, opsLimit, memLimit, salt: encode(salt) },
50
- nonce: encode(nonce),
51
- ciphertext: encode(crypto.crypto_aead_xchacha20poly1305_ietf_encrypt(privateKey, publicKey, null, nonce, key)),
52
- publicKey
53
- };
54
- } finally {
55
- crypto.memzero(key);
56
- }
57
- }
58
- async function decryptServiceVaultPrivateKey(envelope, passphrase) {
59
- const crypto = await ready();
60
- if (envelope.version !== SERVICE_VAULT_ENCRYPTION_VERSION || envelope.algorithm !== SERVICE_VAULT_AEAD_ALGORITHM || envelope.kdf.algorithm !== SERVICE_VAULT_KDF) throw new Error("Service-vault private-key envelope is unsupported.");
61
- if (!Number.isSafeInteger(envelope.kdf.opsLimit) || !Number.isSafeInteger(envelope.kdf.memLimit) || envelope.kdf.opsLimit < crypto.crypto_pwhash_OPSLIMIT_INTERACTIVE || envelope.kdf.opsLimit > crypto.crypto_pwhash_OPSLIMIT_SENSITIVE || envelope.kdf.memLimit < crypto.crypto_pwhash_MEMLIMIT_INTERACTIVE || envelope.kdf.memLimit > crypto.crypto_pwhash_MEMLIMIT_SENSITIVE)
62
- throw new Error("Service-vault private-key KDF parameters are invalid.");
63
- const key = crypto.crypto_pwhash(
64
- crypto.crypto_aead_xchacha20poly1305_ietf_KEYBYTES,
65
- passphrase,
66
- decode(envelope.kdf.salt),
67
- envelope.kdf.opsLimit,
68
- envelope.kdf.memLimit,
69
- crypto.crypto_pwhash_ALG_ARGON2ID13
70
- );
71
- try {
72
- return validKey(crypto.crypto_aead_xchacha20poly1305_ietf_decrypt(
73
- null,
74
- decode(envelope.ciphertext),
75
- envelope.publicKey,
76
- decode(envelope.nonce),
77
- key
78
- ), crypto.crypto_box_SECRETKEYBYTES, "Decrypted service-vault private key");
79
- } catch {
80
- throw new Error("Service-vault passphrase or private-key envelope is invalid.");
81
- } finally {
82
- crypto.memzero(key);
83
- }
84
- }
85
- async function createTeamVaultGrant(teamVaultKey, recipientPublicKey) {
86
- const crypto = await ready();
87
- validKey(teamVaultKey, crypto.crypto_aead_xchacha20poly1305_ietf_KEYBYTES, "Team vault key");
88
- const publicKey = validKey(decode(recipientPublicKey), crypto.crypto_box_PUBLICKEYBYTES, "Recipient public key");
89
- return {
90
- version: SERVICE_VAULT_ENCRYPTION_VERSION,
91
- algorithm: SERVICE_VAULT_KEY_AGREEMENT,
92
- recipientPublicKey,
93
- wrappedTeamVaultKey: encode(crypto.crypto_box_seal(teamVaultKey, publicKey))
94
- };
95
- }
96
- async function openTeamVaultGrant(grant, recipientPrivateKey) {
97
- const crypto = await ready();
98
- if (grant.version !== SERVICE_VAULT_ENCRYPTION_VERSION || grant.algorithm !== SERVICE_VAULT_KEY_AGREEMENT)
99
- throw new Error("Team vault grant is unsupported.");
100
- const publicKey = validKey(decode(grant.recipientPublicKey), crypto.crypto_box_PUBLICKEYBYTES, "Recipient public key");
101
- validKey(recipientPrivateKey, crypto.crypto_box_SECRETKEYBYTES, "Recipient private key");
102
- try {
103
- return validKey(
104
- crypto.crypto_box_seal_open(decode(grant.wrappedTeamVaultKey), publicKey, recipientPrivateKey),
105
- crypto.crypto_aead_xchacha20poly1305_ietf_KEYBYTES,
106
- "Unwrapped team vault key"
107
- );
108
- } catch {
109
- throw new Error("Team vault grant cannot be opened by this user key.");
110
- }
111
- }
112
- async function encryptServiceCredential(plaintext, teamVaultKey, associatedData) {
113
- const crypto = await ready();
114
- validKey(teamVaultKey, crypto.crypto_aead_xchacha20poly1305_ietf_KEYBYTES, "Team vault key");
115
- if (!plaintext || !associatedData) throw new Error("Credential value and associated data are required.");
116
- const dataKey = crypto.crypto_aead_xchacha20poly1305_ietf_keygen();
117
- const nonce = crypto.randombytes_buf(crypto.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
118
- const wrappedKeyNonce = crypto.randombytes_buf(crypto.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
119
- try {
120
- return {
121
- version: SERVICE_VAULT_ENCRYPTION_VERSION,
122
- algorithm: SERVICE_VAULT_AEAD_ALGORITHM,
123
- ciphertext: encode(crypto.crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, associatedData, null, nonce, dataKey)),
124
- nonce: encode(nonce),
125
- wrappedKey: encode(crypto.crypto_aead_xchacha20poly1305_ietf_encrypt(dataKey, associatedData, null, wrappedKeyNonce, teamVaultKey)),
126
- wrappedKeyNonce: encode(wrappedKeyNonce),
127
- associatedData,
128
- associatedDataDigest: hash(associatedData),
129
- fingerprint: hash(plaintext, teamVaultKey)
130
- };
131
- } finally {
132
- crypto.memzero(dataKey);
133
- }
134
- }
135
- async function decryptServiceCredential(envelope, teamVaultKey, expectedAssociatedData) {
136
- const crypto = await ready();
137
- validKey(teamVaultKey, crypto.crypto_aead_xchacha20poly1305_ietf_KEYBYTES, "Team vault key");
138
- if (envelope.version !== SERVICE_VAULT_ENCRYPTION_VERSION || envelope.algorithm !== SERVICE_VAULT_AEAD_ALGORITHM || envelope.associatedData !== expectedAssociatedData || envelope.associatedDataDigest !== hash(expectedAssociatedData))
139
- throw new Error("Credential envelope binding is invalid.");
140
- let dataKey;
141
- try {
142
- dataKey = crypto.crypto_aead_xchacha20poly1305_ietf_decrypt(
143
- null,
144
- decode(envelope.wrappedKey),
145
- expectedAssociatedData,
146
- decode(envelope.wrappedKeyNonce),
147
- teamVaultKey
148
- );
149
- return crypto.crypto_aead_xchacha20poly1305_ietf_decrypt(
150
- null,
151
- decode(envelope.ciphertext),
152
- expectedAssociatedData,
153
- decode(envelope.nonce),
154
- dataKey,
155
- "text"
156
- );
157
- } catch {
158
- throw new Error("Credential envelope cannot be decrypted.");
159
- } finally {
160
- if (dataKey) crypto.memzero(dataKey);
161
- }
162
- }
163
- async function rewrapServiceCredential(envelope, currentTeamVaultKey, replacementTeamVaultKey) {
164
- const plaintext = await decryptServiceCredential(envelope, currentTeamVaultKey, envelope.associatedData);
165
- return encryptServiceCredential(plaintext, replacementTeamVaultKey, envelope.associatedData);
166
- }
167
- async function sealSecretOperationPayload(values, operationPublicKey) {
168
- const crypto = await ready();
169
- if (!Object.keys(values).length || Object.values(values).some((value) => typeof value !== "string" || !value))
170
- throw new Error("Secret operation payload must contain only non-empty string values.");
171
- const payload = JSON.stringify(Object.fromEntries(Object.entries(values).sort(([left], [right]) => left.localeCompare(right))));
172
- return encode(crypto.crypto_box_seal(payload, validKey(decode(operationPublicKey), crypto.crypto_box_PUBLICKEYBYTES, "Operation public key")));
173
- }
174
- async function encryptGitHubActionsSecret(value, providerPublicKey) {
175
- const crypto = await ready();
176
- if (!value) throw new Error("GitHub Actions secret value is required.");
177
- return encode(crypto.crypto_box_seal(
178
- value,
179
- validKey(decode(providerPublicKey), crypto.crypto_box_PUBLICKEYBYTES, "GitHub public key")
180
- ));
181
- }
182
- async function openSecretOperationPayload(sealedPayload, operationPublicKey, operationPrivateKey) {
183
- const crypto = await ready();
184
- try {
185
- const plaintext = crypto.crypto_box_seal_open(decode(sealedPayload), decode(operationPublicKey), operationPrivateKey, "text");
186
- const parsed = JSON.parse(plaintext);
187
- if (!parsed || Array.isArray(parsed) || Object.values(parsed).some((value) => typeof value !== "string" || !value)) throw new Error();
188
- return parsed;
189
- } catch {
190
- throw new Error("Secret operation payload cannot be opened.");
191
- }
192
- }
193
- function clearServiceVaultKey(value) {
194
- value?.fill(0);
195
- }
196
- export {
197
- clearServiceVaultKey,
198
- createServiceVaultKey,
199
- createServiceVaultUserKeyPair,
200
- createTeamVaultGrant,
201
- decryptServiceCredential,
202
- decryptServiceVaultPrivateKey,
203
- encryptGitHubActionsSecret,
204
- encryptServiceCredential,
205
- encryptServiceVaultPrivateKey,
206
- openSecretOperationPayload,
207
- openTeamVaultGrant,
208
- rewrapServiceCredential,
209
- sealSecretOperationPayload
210
- };