@forgezero/access 0.1.13 → 0.1.15
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 +57 -1
- package/dist/conditions.js +35 -3
- package/dist/effects.js +35 -3
- package/dist/elysia.js +35 -3
- package/dist/fetch.js +35 -3
- package/dist/header.js +35 -3
- package/dist/index.d.ts +29 -1
- package/dist/index.js +36 -3
- package/dist/pipeline.js +35 -3
- package/dist/principal-session.js +35 -3
- package/dist/principal.js +35 -3
- package/dist/schema.d.ts +78 -0
- package/dist/schema.js +171 -0
- package/dist/testing.js +35 -3
- package/dist/vault.d.ts +177 -0
- package/dist/vault.js +264 -0
- package/package.json +9 -1
package/dist/vault.js
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
// src/schema.ts
|
|
2
|
+
var contractType = Symbol("forgezero.contract.type");
|
|
3
|
+
var optionalProperty = Symbol("forgezero.contract.optional");
|
|
4
|
+
function freeze(schema) {
|
|
5
|
+
return Object.freeze(schema);
|
|
6
|
+
}
|
|
7
|
+
var schema = Object.freeze({
|
|
8
|
+
unknown: () => freeze({}),
|
|
9
|
+
string: (options = {}) => freeze({ type: "string", ...options }),
|
|
10
|
+
number: (options = {}) => freeze({ type: "number", ...options }),
|
|
11
|
+
integer: (options = {}) => freeze({ type: "integer", ...options }),
|
|
12
|
+
boolean: () => freeze({ type: "boolean" }),
|
|
13
|
+
null: () => freeze({ type: "null" }),
|
|
14
|
+
literal: (value) => freeze({ const: value }),
|
|
15
|
+
optional: (value) => Object.freeze({ ...value, [optionalProperty]: true }),
|
|
16
|
+
array: (items, options = {}) => freeze({ type: "array", items, ...options }),
|
|
17
|
+
union: (...members) => freeze({ anyOf: members }),
|
|
18
|
+
object: (properties, options = { additionalProperties: false }) => {
|
|
19
|
+
const required = Object.entries(properties).filter(([, value]) => !(optionalProperty in value)).map(([key]) => key);
|
|
20
|
+
const cleanProperties = Object.fromEntries(Object.entries(properties).map(([key, value]) => {
|
|
21
|
+
if (!(optionalProperty in value))
|
|
22
|
+
return [key, value];
|
|
23
|
+
const { [optionalProperty]: _, ...clean } = value;
|
|
24
|
+
return [key, clean];
|
|
25
|
+
}));
|
|
26
|
+
return freeze({ type: "object", properties: cleanProperties, required, ...options });
|
|
27
|
+
},
|
|
28
|
+
record: (values, options = {}) => freeze({
|
|
29
|
+
type: "object",
|
|
30
|
+
properties: {},
|
|
31
|
+
additionalProperties: values,
|
|
32
|
+
...options.minProperties === undefined ? {} : { minProperties: options.minProperties },
|
|
33
|
+
...options.maxProperties === undefined ? {} : { maxProperties: options.maxProperties },
|
|
34
|
+
...options.keyPattern === undefined ? {} : { propertyNames: { pattern: options.keyPattern } }
|
|
35
|
+
})
|
|
36
|
+
});
|
|
37
|
+
function extend(base, extension) {
|
|
38
|
+
const baseProperties = base.properties ?? {};
|
|
39
|
+
const extensionProperties = extension.properties ?? {};
|
|
40
|
+
const required = [...new Set([
|
|
41
|
+
...base.required ?? [],
|
|
42
|
+
...extension.required ?? []
|
|
43
|
+
])];
|
|
44
|
+
return freeze({
|
|
45
|
+
type: "object",
|
|
46
|
+
properties: { ...baseProperties, ...extensionProperties },
|
|
47
|
+
required,
|
|
48
|
+
additionalProperties: false
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function pick(source, keys) {
|
|
52
|
+
const sourceProperties = source.properties ?? {};
|
|
53
|
+
const selected = Object.fromEntries(keys.map((key) => [key, sourceProperties[key]]));
|
|
54
|
+
const required = (source.required ?? []).filter((key) => keys.includes(key));
|
|
55
|
+
return freeze({ type: "object", properties: selected, required, additionalProperties: false });
|
|
56
|
+
}
|
|
57
|
+
function omit(source, keys) {
|
|
58
|
+
const omitted = new Set(keys);
|
|
59
|
+
const sourceProperties = source.properties ?? {};
|
|
60
|
+
const selected = Object.fromEntries(Object.entries(sourceProperties).filter(([key]) => !omitted.has(key)));
|
|
61
|
+
const required = (source.required ?? []).filter((key) => !omitted.has(key));
|
|
62
|
+
return freeze({ type: "object", properties: selected, required, additionalProperties: false });
|
|
63
|
+
}
|
|
64
|
+
var record = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
65
|
+
function validate(current, value, path, issues) {
|
|
66
|
+
if (issues.length >= 32)
|
|
67
|
+
return false;
|
|
68
|
+
if ("const" in current) {
|
|
69
|
+
const valid = value === current.const;
|
|
70
|
+
if (!valid)
|
|
71
|
+
issues.push({ path, expected: JSON.stringify(current.const) });
|
|
72
|
+
return valid;
|
|
73
|
+
}
|
|
74
|
+
if (Array.isArray(current.anyOf)) {
|
|
75
|
+
for (const member of current.anyOf) {
|
|
76
|
+
const candidate = [];
|
|
77
|
+
if (validate(member, value, path, candidate))
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
issues.push({ path, expected: "one declared union member" });
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
if (current.type === "string") {
|
|
84
|
+
const valid = typeof value === "string" && (typeof current.minLength !== "number" || value.length >= current.minLength) && (typeof current.maxLength !== "number" || value.length <= current.maxLength) && (typeof current.pattern !== "string" || new RegExp(current.pattern).test(value));
|
|
85
|
+
if (!valid)
|
|
86
|
+
issues.push({ path, expected: "declared string" });
|
|
87
|
+
return valid;
|
|
88
|
+
}
|
|
89
|
+
if (current.type === "number" || current.type === "integer") {
|
|
90
|
+
const valid = typeof value === "number" && Number.isFinite(value) && (current.type !== "integer" || Number.isSafeInteger(value)) && (typeof current.minimum !== "number" || value >= current.minimum) && (typeof current.maximum !== "number" || value <= current.maximum);
|
|
91
|
+
if (!valid)
|
|
92
|
+
issues.push({ path, expected: `declared ${String(current.type)}` });
|
|
93
|
+
return valid;
|
|
94
|
+
}
|
|
95
|
+
if (current.type === "boolean" || current.type === "null") {
|
|
96
|
+
const valid = current.type === "boolean" ? typeof value === "boolean" : value === null;
|
|
97
|
+
if (!valid)
|
|
98
|
+
issues.push({ path, expected: String(current.type) });
|
|
99
|
+
return valid;
|
|
100
|
+
}
|
|
101
|
+
if (current.type === "array") {
|
|
102
|
+
if (!Array.isArray(value)) {
|
|
103
|
+
issues.push({ path, expected: "array" });
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
let valid = (typeof current.minItems !== "number" || value.length >= current.minItems) && (typeof current.maxItems !== "number" || value.length <= current.maxItems);
|
|
107
|
+
if (current.uniqueItems === true && new Set(value.map((entry) => JSON.stringify(entry))).size !== value.length)
|
|
108
|
+
valid = false;
|
|
109
|
+
if (!valid)
|
|
110
|
+
issues.push({ path, expected: "bounded declared array" });
|
|
111
|
+
for (let index = 0;index < value.length && issues.length < 32; index += 1) {
|
|
112
|
+
valid = validate(current.items, value[index], `${path}[${index}]`, issues) && valid;
|
|
113
|
+
}
|
|
114
|
+
return valid;
|
|
115
|
+
}
|
|
116
|
+
if (current.type === "object") {
|
|
117
|
+
if (!record(value)) {
|
|
118
|
+
issues.push({ path, expected: "object" });
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
const properties = current.properties ?? {};
|
|
122
|
+
const required = new Set(current.required ?? []);
|
|
123
|
+
let valid = (typeof current.minProperties !== "number" || Object.keys(value).length >= current.minProperties) && (typeof current.maxProperties !== "number" || Object.keys(value).length <= current.maxProperties);
|
|
124
|
+
if (!valid)
|
|
125
|
+
issues.push({ path, expected: "bounded property count" });
|
|
126
|
+
const keyPattern = current.propertyNames?.pattern;
|
|
127
|
+
if (typeof keyPattern === "string") {
|
|
128
|
+
for (const key of Object.keys(value))
|
|
129
|
+
if (!new RegExp(keyPattern).test(key)) {
|
|
130
|
+
issues.push({ path: `${path}.${key}`, expected: "declared property name" });
|
|
131
|
+
valid = false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
for (const key of required) {
|
|
135
|
+
if (!(key in value)) {
|
|
136
|
+
issues.push({ path: `${path}.${key}`, expected: "required property" });
|
|
137
|
+
valid = false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (current.additionalProperties === false) {
|
|
141
|
+
for (const key of Object.keys(value)) {
|
|
142
|
+
if (!(key in properties)) {
|
|
143
|
+
issues.push({ path: `${path}.${key}`, expected: "no additional property" });
|
|
144
|
+
valid = false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
} else if (record(current.additionalProperties)) {
|
|
148
|
+
for (const [key, child] of Object.entries(value)) {
|
|
149
|
+
if (!(key in properties))
|
|
150
|
+
valid = validate(current.additionalProperties, child, `${path}.${key}`, issues) && valid;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
for (const [key, child] of Object.entries(properties)) {
|
|
154
|
+
if (key in value)
|
|
155
|
+
valid = validate(child, value[key], `${path}.${key}`, issues) && valid;
|
|
156
|
+
}
|
|
157
|
+
return valid;
|
|
158
|
+
}
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
function parse(contract, value) {
|
|
162
|
+
const issues = [];
|
|
163
|
+
return validate(contract, value, "$", issues) ? { ok: true, value } : { ok: false, issues };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/vault.ts
|
|
167
|
+
var KeySchema = schema.string({ minLength: 1, maxLength: 128, pattern: "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$" });
|
|
168
|
+
var EnvironmentKeySchema = schema.string({ minLength: 1, maxLength: 64, pattern: "^[A-Za-z0-9_][A-Za-z0-9_.-]{0,63}$" });
|
|
169
|
+
var SchemaCoordinateSchema = schema.string({ minLength: 1, maxLength: 192, pattern: "^[A-Za-z0-9][A-Za-z0-9._:/-]*@[1-9][0-9]{0,8}$" });
|
|
170
|
+
var VaultDomainSchema = schema.union(schema.literal("service"), schema.literal("platform-authority"), schema.literal("deployment"));
|
|
171
|
+
var VaultEntryScopeSchema = schema.union(schema.object({ kind: schema.literal("account") }), schema.object({ kind: schema.literal("project"), projectKey: KeySchema }), schema.object({ kind: schema.literal("deployment"), projectKey: KeySchema, deploymentKey: KeySchema }));
|
|
172
|
+
var VaultAccessTargetSchema = schema.object({
|
|
173
|
+
projectKey: KeySchema,
|
|
174
|
+
deploymentKey: schema.optional(schema.union(KeySchema, schema.null()))
|
|
175
|
+
});
|
|
176
|
+
var DeploymentCredentialPurposeSchema = schema.union(schema.literal("deployment-infrastructure"), schema.literal("runtime-secret"));
|
|
177
|
+
var DeploymentCredentialRequirementSchema = schema.object({
|
|
178
|
+
alias: KeySchema,
|
|
179
|
+
purpose: DeploymentCredentialPurposeSchema,
|
|
180
|
+
schema: schema.optional(SchemaCoordinateSchema),
|
|
181
|
+
defaultEntryKey: KeySchema
|
|
182
|
+
});
|
|
183
|
+
var DeploymentVaultBindingSchema = schema.object({
|
|
184
|
+
alias: KeySchema,
|
|
185
|
+
purpose: DeploymentCredentialPurposeSchema,
|
|
186
|
+
projectKey: KeySchema,
|
|
187
|
+
deploymentKey: KeySchema,
|
|
188
|
+
vaultEntryRef: KeySchema,
|
|
189
|
+
environmentKey: EnvironmentKeySchema,
|
|
190
|
+
entryKey: KeySchema,
|
|
191
|
+
schema: SchemaCoordinateSchema
|
|
192
|
+
});
|
|
193
|
+
var DeploymentVaultBindingsSchema = schema.record(DeploymentVaultBindingSchema, {
|
|
194
|
+
maxProperties: 128,
|
|
195
|
+
keyPattern: "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$"
|
|
196
|
+
});
|
|
197
|
+
var DeploymentVaultEntryTypeSchema = schema.union(schema.literal("text"), schema.literal("secret"), schema.literal("json"));
|
|
198
|
+
var DeploymentVaultEntryBaseSchema = schema.object({
|
|
199
|
+
projectKey: KeySchema,
|
|
200
|
+
deploymentKey: KeySchema,
|
|
201
|
+
environmentKey: EnvironmentKeySchema,
|
|
202
|
+
entryKey: KeySchema,
|
|
203
|
+
schema: schema.optional(SchemaCoordinateSchema),
|
|
204
|
+
description: schema.optional(schema.string({ minLength: 1, maxLength: 512 }))
|
|
205
|
+
});
|
|
206
|
+
var ManualDeploymentVaultEntryInputSchema = schema.union(extend(DeploymentVaultEntryBaseSchema, schema.object({
|
|
207
|
+
entryType: schema.literal("text"),
|
|
208
|
+
value: schema.string({ minLength: 1, maxLength: 262144 })
|
|
209
|
+
})), extend(DeploymentVaultEntryBaseSchema, schema.object({
|
|
210
|
+
entryType: schema.literal("secret"),
|
|
211
|
+
value: schema.string({ minLength: 1, maxLength: 262144 })
|
|
212
|
+
})), extend(DeploymentVaultEntryBaseSchema, schema.object({
|
|
213
|
+
entryType: schema.literal("json"),
|
|
214
|
+
value: schema.string({ minLength: 1, maxLength: 262144 })
|
|
215
|
+
})));
|
|
216
|
+
var DeploymentVaultEntryInputSchema = schema.union(ManualDeploymentVaultEntryInputSchema, extend(DeploymentVaultEntryBaseSchema, schema.object({
|
|
217
|
+
schema: SchemaCoordinateSchema,
|
|
218
|
+
value: schema.unknown()
|
|
219
|
+
})));
|
|
220
|
+
var PipelineVaultBindRequestSchema = schema.object({
|
|
221
|
+
pipelineKey: KeySchema,
|
|
222
|
+
alias: KeySchema,
|
|
223
|
+
environmentKey: EnvironmentKeySchema,
|
|
224
|
+
entryKey: KeySchema
|
|
225
|
+
});
|
|
226
|
+
var PipelineVaultUnbindRequestSchema = schema.object({
|
|
227
|
+
pipelineKey: KeySchema,
|
|
228
|
+
alias: KeySchema
|
|
229
|
+
});
|
|
230
|
+
var DeploymentVaultCreateAndBindRequestSchema = schema.object({
|
|
231
|
+
pipelineKey: KeySchema,
|
|
232
|
+
alias: KeySchema,
|
|
233
|
+
entry: DeploymentVaultEntryInputSchema
|
|
234
|
+
});
|
|
235
|
+
function validVaultEntryScope(value) {
|
|
236
|
+
return parse(VaultEntryScopeSchema, value).ok;
|
|
237
|
+
}
|
|
238
|
+
function vaultScopeAllows(scope, target) {
|
|
239
|
+
if (scope.kind === "account")
|
|
240
|
+
return true;
|
|
241
|
+
if (scope.projectKey !== target.projectKey)
|
|
242
|
+
return false;
|
|
243
|
+
return scope.kind === "project" || scope.deploymentKey === target.deploymentKey;
|
|
244
|
+
}
|
|
245
|
+
function deploymentBindingAllows(binding, target) {
|
|
246
|
+
return binding.projectKey === target.projectKey && binding.deploymentKey === target.deploymentKey && binding.alias === target.alias;
|
|
247
|
+
}
|
|
248
|
+
export {
|
|
249
|
+
vaultScopeAllows,
|
|
250
|
+
validVaultEntryScope,
|
|
251
|
+
deploymentBindingAllows,
|
|
252
|
+
VaultEntryScopeSchema,
|
|
253
|
+
VaultDomainSchema,
|
|
254
|
+
VaultAccessTargetSchema,
|
|
255
|
+
PipelineVaultUnbindRequestSchema,
|
|
256
|
+
PipelineVaultBindRequestSchema,
|
|
257
|
+
DeploymentVaultEntryTypeSchema,
|
|
258
|
+
DeploymentVaultEntryInputSchema,
|
|
259
|
+
DeploymentVaultCreateAndBindRequestSchema,
|
|
260
|
+
DeploymentVaultBindingsSchema,
|
|
261
|
+
DeploymentVaultBindingSchema,
|
|
262
|
+
DeploymentCredentialRequirementSchema,
|
|
263
|
+
DeploymentCredentialPurposeSchema
|
|
264
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgezero/access",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -66,6 +66,14 @@
|
|
|
66
66
|
"./ceremony-modes": {
|
|
67
67
|
"types": "./dist/ceremony-modes.d.ts",
|
|
68
68
|
"default": "./dist/ceremony-modes.js"
|
|
69
|
+
},
|
|
70
|
+
"./schema": {
|
|
71
|
+
"types": "./dist/schema.d.ts",
|
|
72
|
+
"default": "./dist/schema.js"
|
|
73
|
+
},
|
|
74
|
+
"./vault": {
|
|
75
|
+
"types": "./dist/vault.d.ts",
|
|
76
|
+
"default": "./dist/vault.js"
|
|
69
77
|
}
|
|
70
78
|
},
|
|
71
79
|
"scripts": {
|