@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/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.13",
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": {