@forgezero/vault 0.1.2 → 0.1.3
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 +9 -6
- package/dist/index.d.ts +15 -21
- package/dist/index.js +18 -4
- package/dist/providers.js +18 -4
- package/dist/schema.d.ts +1 -3
- package/dist/schema.js +24 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
**Read your secrets at runtime instead of shipping them in a file.**
|
|
4
4
|
|
|
5
|
-
The client discovers its own credential and
|
|
6
|
-
|
|
7
|
-
a
|
|
8
|
-
|
|
5
|
+
The client discovers its own credential and uses one stable API origin. Node
|
|
6
|
+
routing and failover stay behind that edge contract; the SDK never discovers or
|
|
7
|
+
stores a node hostname. The same code runs on a laptop and in production:
|
|
8
|
+
outside managed compute the key is a local signing seed; on managed compute
|
|
9
|
+
there is no remote credential in the application.
|
|
9
10
|
|
|
10
11
|
This one talks to a ForgeZero vault, so it needs an account. The other three
|
|
11
12
|
packages do not.
|
|
@@ -56,8 +57,10 @@ An entry can declare fields the tenant never holds. Two custody modes:
|
|
|
56
57
|
exists in plaintext only inside a signing call.
|
|
57
58
|
- **supplied** — you generate it, the vault seals it.
|
|
58
59
|
|
|
59
|
-
Either way there is no call that returns a private key.
|
|
60
|
-
|
|
60
|
+
Either way there is no call that returns a private key. Derivation and signing
|
|
61
|
+
stay inside explicit trusted platform workflows; the general application
|
|
62
|
+
credential remains a read-only secret client and is not a transaction-signing
|
|
63
|
+
oracle.
|
|
61
64
|
|
|
62
65
|
## Subpaths
|
|
63
66
|
|
package/dist/index.d.ts
CHANGED
|
@@ -156,41 +156,35 @@ export declare class ForgeZero {
|
|
|
156
156
|
*/
|
|
157
157
|
getAll(): Promise<Record<string, string>>;
|
|
158
158
|
/**
|
|
159
|
-
*
|
|
159
|
+
* Custody derivation is intentionally not a general application-key action.
|
|
160
160
|
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
* activated, the platform derives from the seed, and an ADDRESS is the only
|
|
166
|
-
* thing that crosses back.
|
|
161
|
+
* Kept as a typed refusal for compatibility with the early package preview,
|
|
162
|
+
* which exposed this method before a secured custody workflow existed. A
|
|
163
|
+
* compromised secret-reading process must not silently become a transaction
|
|
164
|
+
* signer merely because both operations happen to involve the vault.
|
|
167
165
|
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
166
|
+
* @deprecated Use an explicit platform custody workflow with its own policy,
|
|
167
|
+
* approval and audit contract.
|
|
170
168
|
*/
|
|
171
169
|
derived(name: string, field: string): Promise<{
|
|
172
170
|
address: string;
|
|
173
171
|
path: string;
|
|
174
172
|
}>;
|
|
175
173
|
/**
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
* The tenant builds the unsigned transaction, hashes it, and sends the
|
|
179
|
-
* digest. What comes back is a signature. A compromised tenant process can
|
|
180
|
-
* ASK for signatures — which is bounded, logged and revocable — and cannot
|
|
181
|
-
* take the key, which would be none of those things.
|
|
182
|
-
*
|
|
183
|
-
* A digest rather than a transaction on purpose: the platform is not a
|
|
184
|
-
* transaction builder for every chain a tenant might use, and pretending
|
|
185
|
-
* otherwise would make ForgeZero the thing that has to understand every
|
|
186
|
-
* chain format before a tenant can support one.
|
|
174
|
+
* @deprecated A general application vault credential is not a signing oracle.
|
|
187
175
|
*/
|
|
188
176
|
sign(name: string, field: string, digest: string): Promise<{
|
|
189
177
|
signature: string;
|
|
190
178
|
recovery?: number;
|
|
191
179
|
path: string;
|
|
192
180
|
}>;
|
|
193
|
-
/**
|
|
181
|
+
/**
|
|
182
|
+
* List schemas represented by reserved vault entries.
|
|
183
|
+
*
|
|
184
|
+
* Kept for compatibility; `managedSchemas(vault).list()` is the higher-level
|
|
185
|
+
* interface. It deliberately uses `list` and `get`, so both the local agent
|
|
186
|
+
* and signed HTTPS transports follow the same contract.
|
|
187
|
+
*/
|
|
194
188
|
schemas(): Promise<readonly {
|
|
195
189
|
name: string;
|
|
196
190
|
version: number;
|
package/dist/index.js
CHANGED
|
@@ -254,14 +254,28 @@ class ForgeZero {
|
|
|
254
254
|
return result.values;
|
|
255
255
|
}
|
|
256
256
|
async derived(name, field) {
|
|
257
|
-
|
|
257
|
+
throw new VaultError("CUSTODY_WORKFLOW_REQUIRED", "Derived custody keys require an explicit platform custody workflow; an application vault credential cannot request them.");
|
|
258
258
|
}
|
|
259
259
|
async sign(name, field, digest) {
|
|
260
|
-
|
|
260
|
+
throw new VaultError("CUSTODY_WORKFLOW_REQUIRED", "Signing requires an explicit platform custody workflow with its own policy, approval and audit contract.");
|
|
261
261
|
}
|
|
262
262
|
async schemas() {
|
|
263
|
-
const
|
|
264
|
-
|
|
263
|
+
const entries = await this.list();
|
|
264
|
+
const names = entries.map((entry) => entry.name).filter((name) => name.startsWith("__schema__")).map((name) => name.slice("__schema__".length)).filter(Boolean);
|
|
265
|
+
return Promise.all(names.map(async (name) => {
|
|
266
|
+
let value;
|
|
267
|
+
try {
|
|
268
|
+
value = JSON.parse(await this.get(`__schema__${name}`));
|
|
269
|
+
} catch (cause) {
|
|
270
|
+
if (cause instanceof VaultError)
|
|
271
|
+
throw cause;
|
|
272
|
+
throw new VaultError("SCHEMA_MALFORMED", `The schema for ${name} is not JSON.`);
|
|
273
|
+
}
|
|
274
|
+
if (!Number.isInteger(value.version) || Number(value.version) < 1) {
|
|
275
|
+
throw new VaultError("SCHEMA_MALFORMED", `The schema for ${name} has no valid version.`);
|
|
276
|
+
}
|
|
277
|
+
return { name, version: Number(value.version) };
|
|
278
|
+
}));
|
|
265
279
|
}
|
|
266
280
|
async list() {
|
|
267
281
|
const result = await this.request(`/v1/vault/${this.scope()}/list`);
|
package/dist/providers.js
CHANGED
|
@@ -254,14 +254,28 @@ class ForgeZero {
|
|
|
254
254
|
return result.values;
|
|
255
255
|
}
|
|
256
256
|
async derived(name, field) {
|
|
257
|
-
|
|
257
|
+
throw new VaultError("CUSTODY_WORKFLOW_REQUIRED", "Derived custody keys require an explicit platform custody workflow; an application vault credential cannot request them.");
|
|
258
258
|
}
|
|
259
259
|
async sign(name, field, digest) {
|
|
260
|
-
|
|
260
|
+
throw new VaultError("CUSTODY_WORKFLOW_REQUIRED", "Signing requires an explicit platform custody workflow with its own policy, approval and audit contract.");
|
|
261
261
|
}
|
|
262
262
|
async schemas() {
|
|
263
|
-
const
|
|
264
|
-
|
|
263
|
+
const entries = await this.list();
|
|
264
|
+
const names = entries.map((entry) => entry.name).filter((name) => name.startsWith("__schema__")).map((name) => name.slice("__schema__".length)).filter(Boolean);
|
|
265
|
+
return Promise.all(names.map(async (name) => {
|
|
266
|
+
let value;
|
|
267
|
+
try {
|
|
268
|
+
value = JSON.parse(await this.get(`__schema__${name}`));
|
|
269
|
+
} catch (cause) {
|
|
270
|
+
if (cause instanceof VaultError)
|
|
271
|
+
throw cause;
|
|
272
|
+
throw new VaultError("SCHEMA_MALFORMED", `The schema for ${name} is not JSON.`);
|
|
273
|
+
}
|
|
274
|
+
if (!Number.isInteger(value.version) || Number(value.version) < 1) {
|
|
275
|
+
throw new VaultError("SCHEMA_MALFORMED", `The schema for ${name} has no valid version.`);
|
|
276
|
+
}
|
|
277
|
+
return { name, version: Number(value.version) };
|
|
278
|
+
}));
|
|
265
279
|
}
|
|
266
280
|
async list() {
|
|
267
281
|
const result = await this.request(`/v1/vault/${this.scope()}/list`);
|
package/dist/schema.d.ts
CHANGED
|
@@ -49,9 +49,7 @@ export interface SchemaSource {
|
|
|
49
49
|
* platform being up. `refresh` exists so a long-lived process can pick up a
|
|
50
50
|
* change without restarting.
|
|
51
51
|
*/
|
|
52
|
-
export declare function managedSchemas(vault: Pick<ForgeZero, 'get'
|
|
53
|
-
schemas?: () => Promise<readonly SchemaRef[]>;
|
|
54
|
-
}, options?: {
|
|
52
|
+
export declare function managedSchemas(vault: Pick<ForgeZero, 'get' | 'list'>, options?: {
|
|
55
53
|
ttlMs?: number;
|
|
56
54
|
now?: () => number;
|
|
57
55
|
}): SchemaSource & {
|
package/dist/schema.js
CHANGED
|
@@ -254,14 +254,28 @@ class ForgeZero {
|
|
|
254
254
|
return result.values;
|
|
255
255
|
}
|
|
256
256
|
async derived(name, field) {
|
|
257
|
-
|
|
257
|
+
throw new VaultError("CUSTODY_WORKFLOW_REQUIRED", "Derived custody keys require an explicit platform custody workflow; an application vault credential cannot request them.");
|
|
258
258
|
}
|
|
259
259
|
async sign(name, field, digest) {
|
|
260
|
-
|
|
260
|
+
throw new VaultError("CUSTODY_WORKFLOW_REQUIRED", "Signing requires an explicit platform custody workflow with its own policy, approval and audit contract.");
|
|
261
261
|
}
|
|
262
262
|
async schemas() {
|
|
263
|
-
const
|
|
264
|
-
|
|
263
|
+
const entries = await this.list();
|
|
264
|
+
const names = entries.map((entry) => entry.name).filter((name) => name.startsWith("__schema__")).map((name) => name.slice("__schema__".length)).filter(Boolean);
|
|
265
|
+
return Promise.all(names.map(async (name) => {
|
|
266
|
+
let value;
|
|
267
|
+
try {
|
|
268
|
+
value = JSON.parse(await this.get(`__schema__${name}`));
|
|
269
|
+
} catch (cause) {
|
|
270
|
+
if (cause instanceof VaultError)
|
|
271
|
+
throw cause;
|
|
272
|
+
throw new VaultError("SCHEMA_MALFORMED", `The schema for ${name} is not JSON.`);
|
|
273
|
+
}
|
|
274
|
+
if (!Number.isInteger(value.version) || Number(value.version) < 1) {
|
|
275
|
+
throw new VaultError("SCHEMA_MALFORMED", `The schema for ${name} has no valid version.`);
|
|
276
|
+
}
|
|
277
|
+
return { name, version: Number(value.version) };
|
|
278
|
+
}));
|
|
265
279
|
}
|
|
266
280
|
async list() {
|
|
267
281
|
const result = await this.request(`/v1/vault/${this.scope()}/list`);
|
|
@@ -362,7 +376,12 @@ function managedSchemas(vault, options = {}) {
|
|
|
362
376
|
return value;
|
|
363
377
|
},
|
|
364
378
|
async list() {
|
|
365
|
-
|
|
379
|
+
const entries = await vault.list();
|
|
380
|
+
const names = entries.map((entry) => entry.name).filter((name) => name.startsWith("__schema__")).map((name) => name.slice("__schema__".length)).filter(Boolean);
|
|
381
|
+
return Promise.all(names.map(async (name) => {
|
|
382
|
+
const resolved = await this.get(name);
|
|
383
|
+
return { name, version: resolved.version };
|
|
384
|
+
}));
|
|
366
385
|
}
|
|
367
386
|
};
|
|
368
387
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"//": "Publishing happens from an operator's machine, not CI \u2014 CLAUDE.md records that the absence of CI is deliberate. npm's `provenance` attests a tarball was built by a recognised CI provider from a named commit, so it cannot be produced here: it was set, and the first publish failed with `Automatic provenance generation not supported for provider: null`. A setting that can never be satisfied is worse than none, because it reads as a guarantee nobody is getting. Restore it the day this publishes from CI, and not before.",
|
|
3
3
|
"name": "@forgezero/vault",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|