@varde-flyt/vfac 0.16.0 → 0.18.0
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 +32 -7
- package/dist/vfac.mjs +55 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -228,13 +228,38 @@ holding on to:
|
|
|
228
228
|
| `valueFrom.resourceOutput` | read a value another resource publishes |
|
|
229
229
|
| `dependencyBindings` | use that resource as the PROVIDER for a declared dependency |
|
|
230
230
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
231
|
+
An entry means one of three things, and only one of them releases anything:
|
|
232
|
+
|
|
233
|
+
| The manifest says | What `vfac apply` does |
|
|
234
|
+
| --- | --- |
|
|
235
|
+
| nothing for the key | leaves that connection exactly as it is |
|
|
236
|
+
| `resourceKey: …` | connects to that resource, or keeps the connection it has |
|
|
237
|
+
| `state: disconnected` | releases the connection, in the same apply as your settings |
|
|
238
|
+
|
|
239
|
+
```yaml
|
|
240
|
+
spec:
|
|
241
|
+
configuration:
|
|
242
|
+
signIn: Disabled # whatever setting made the connection necessary
|
|
243
|
+
dependencyBindings:
|
|
244
|
+
<dependency-key>:
|
|
245
|
+
state: disconnected
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Leaving a key out never releases anything, so a manifest written before this
|
|
249
|
+
field existed re-applies unchanged. `vfac plan` lists a release under
|
|
250
|
+
`connections to disconnect` before you approve it. A dependency the Product
|
|
251
|
+
requires cannot be disconnected; one a setting makes required can be, in the same
|
|
252
|
+
file that turns the setting off. A released connection is torn down by its
|
|
253
|
+
provider afterwards, and the providing resource can only be deleted once that
|
|
254
|
+
teardown is done.
|
|
255
|
+
|
|
256
|
+
**A manifest never moves a connection in one apply**: pointing an existing
|
|
257
|
+
connection at a different resource is refused rather than performed, because a
|
|
258
|
+
file you re-apply on every push must not be able to silently move a running
|
|
259
|
+
service onto a different identity provider. Disconnect it and apply, then name
|
|
260
|
+
the new resource and apply again. The credential the connection delivers never
|
|
261
|
+
appears in your manifest, in a plan, or in any `vfac` output — the providing
|
|
262
|
+
service issues it and the platform stores it.
|
|
238
263
|
|
|
239
264
|
## For an agent or a pipeline
|
|
240
265
|
|
package/dist/vfac.mjs
CHANGED
|
@@ -14216,7 +14216,7 @@ function exampleResourceKey(name) {
|
|
|
14216
14216
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^[^a-z]+/, "").replace(/-+$/, "").slice(0, 63);
|
|
14217
14217
|
return RESOURCE_KEY_PATTERN.test(slug) ? slug : "";
|
|
14218
14218
|
}
|
|
14219
|
-
var DEPLOYMENT_EXAMPLE_GUARANTEE = "Product-owned configuration is complete and E2E-proven; tenant-specific secrets and Resource/provider selections are supplied by the tenant.";
|
|
14219
|
+
var DEPLOYMENT_EXAMPLE_GUARANTEE = "Product-owned configuration is complete and E2E-proven; tenant-specific secrets, tenant-specific values and Resource/provider selections are supplied by the tenant.";
|
|
14220
14220
|
|
|
14221
14221
|
// ../product-configuration/dist/configuration-requirements.js
|
|
14222
14222
|
function configurationRequirements(configuration) {
|
|
@@ -15077,6 +15077,7 @@ function isBlockedHost(hostname) {
|
|
|
15077
15077
|
}
|
|
15078
15078
|
|
|
15079
15079
|
// ../product-contracts/dist/deployment-example.schema.js
|
|
15080
|
+
var MAX_TENANT_INPUTS = 8;
|
|
15080
15081
|
var DeploymentExampleSchema = external_exports.object({
|
|
15081
15082
|
/** The heading a customer reads above the example. */
|
|
15082
15083
|
title: external_exports.string().min(3).max(80),
|
|
@@ -15105,12 +15106,29 @@ var DeploymentExampleSchema = external_exports.object({
|
|
|
15105
15106
|
* created and again only to set a new one — and never written into a
|
|
15106
15107
|
* manifest. A secret resent on an unchanged re-apply is written again.
|
|
15107
15108
|
*/
|
|
15108
|
-
secretInputs: external_exports.array(external_exports.string().regex(CONFIGURATION_PROPERTY_NAME_REGEX)).max(MAX_CONFIGURATION_CHILDREN).optional()
|
|
15109
|
-
|
|
15109
|
+
secretInputs: external_exports.array(external_exports.string().regex(CONFIGURATION_PROPERTY_NAME_REGEX)).max(MAX_CONFIGURATION_CHILDREN).optional(),
|
|
15110
|
+
/**
|
|
15111
|
+
* The ordinary — NOT secret — settings the tenant answers, BY NAME.
|
|
15112
|
+
*
|
|
15113
|
+
* A value only the tenant can know and nothing may default: the address of
|
|
15114
|
+
* the person who administers the Resource first. The example carries NO
|
|
15115
|
+
* value for one — the document a reader copies carries it present and
|
|
15116
|
+
* empty, and the tenant types it — so an example applied unchanged is
|
|
15117
|
+
* refused for that setting by name rather than deployed with a placeholder.
|
|
15118
|
+
* Unlike a secret, the value belongs in the manifest.
|
|
15119
|
+
*
|
|
15120
|
+
* Each must be a setting every deployment must answer, with no default, that
|
|
15121
|
+
* no other rule reads: whether the example is complete cannot depend on a
|
|
15122
|
+
* value the publisher never gave.
|
|
15123
|
+
*/
|
|
15124
|
+
tenantInputs: external_exports.array(external_exports.string().regex(CONFIGURATION_PROPERTY_NAME_REGEX)).max(MAX_TENANT_INPUTS).optional()
|
|
15125
|
+
}).strict().describe("The recommended deployment for this release. Required for a NEW release; optional in the schema because releases published before the field existed are immutable. " + DEPLOYMENT_EXAMPLE_GUARANTEE + " Secret settings are named in secretInputs and never given a value here; so are the ordinary settings the tenant answers, named in tenantInputs.");
|
|
15110
15126
|
var SECRET_INPUT_SEGMENT = CONFIGURATION_PROPERTY_NAME_REGEX.source.slice(1, -1);
|
|
15111
|
-
var
|
|
15112
|
-
message:
|
|
15127
|
+
var settingInputV2Schema = (what) => external_exports.string().regex(new RegExp(`^(?:${SECRET_INPUT_SEGMENT}|(?:/${SECRET_INPUT_SEGMENT}){2,${MAX_CONFIGURATION_DEPTH}})$`)).refine((raw) => secretPathOf(raw) !== null, {
|
|
15128
|
+
message: `A ${what} is a root setting name, or a configuration path such as "/group/setting" with no list index.`
|
|
15113
15129
|
});
|
|
15130
|
+
var SecretInputV2Schema = settingInputV2Schema("secret input");
|
|
15131
|
+
var TenantInputV2Schema = settingInputV2Schema("tenant input");
|
|
15114
15132
|
var DeploymentExampleV2Schema = DeploymentExampleSchema.extend({
|
|
15115
15133
|
/**
|
|
15116
15134
|
* The secret settings a deployment of this example supplies, BY CANONICAL
|
|
@@ -15120,7 +15138,12 @@ var DeploymentExampleV2Schema = DeploymentExampleSchema.extend({
|
|
|
15120
15138
|
* here, so a reader knows every `--secret` flag the create needs before
|
|
15121
15139
|
* running it. The values are the tenant's and never written into a manifest.
|
|
15122
15140
|
*/
|
|
15123
|
-
secretInputs: external_exports.array(SecretInputV2Schema).max(MAX_CONFIGURATION_CHILDREN).optional()
|
|
15141
|
+
secretInputs: external_exports.array(SecretInputV2Schema).max(MAX_CONFIGURATION_CHILDREN).optional(),
|
|
15142
|
+
/**
|
|
15143
|
+
* The ordinary settings the tenant answers, BY CANONICAL PATH —
|
|
15144
|
+
* `/administrator/email`. See the v1 field; only the spelling differs.
|
|
15145
|
+
*/
|
|
15146
|
+
tenantInputs: external_exports.array(TenantInputV2Schema).max(MAX_TENANT_INPUTS).optional()
|
|
15124
15147
|
});
|
|
15125
15148
|
|
|
15126
15149
|
// ../product-contracts/dist/portfolio.js
|
|
@@ -16473,7 +16496,7 @@ function looksLikeReference(value) {
|
|
|
16473
16496
|
}
|
|
16474
16497
|
|
|
16475
16498
|
// ../product-contracts/dist/dependency-binding.js
|
|
16476
|
-
var
|
|
16499
|
+
var DependencyBindingConnectSchema = external_exports.object({
|
|
16477
16500
|
/** The providing Resource's `metadata.key`. */
|
|
16478
16501
|
resourceKey: ResourceKeySchema,
|
|
16479
16502
|
/**
|
|
@@ -16492,6 +16515,11 @@ var DependencyBindingSelectorSchema = external_exports.object({
|
|
|
16492
16515
|
*/
|
|
16493
16516
|
projectId: external_exports.string().min(1).max(64).optional()
|
|
16494
16517
|
}).strict();
|
|
16518
|
+
var DependencyBindingDisconnectSchema = external_exports.object({ state: external_exports.literal("disconnected") }).strict();
|
|
16519
|
+
var DependencyBindingSelectorSchema = external_exports.union([
|
|
16520
|
+
DependencyBindingConnectSchema,
|
|
16521
|
+
DependencyBindingDisconnectSchema
|
|
16522
|
+
]);
|
|
16495
16523
|
var DependencyBindingsSchema = external_exports.record(ServiceBindingKeySchema, DependencyBindingSelectorSchema);
|
|
16496
16524
|
|
|
16497
16525
|
// ../product-contracts/dist/product-instance-template.schema.js
|
|
@@ -16593,10 +16621,17 @@ var ProductInstanceTemplateSchema = external_exports.object({
|
|
|
16593
16621
|
* schema; this names another Resource, and the create envelope made the
|
|
16594
16622
|
* identical split for the identical reason.
|
|
16595
16623
|
*
|
|
16624
|
+
* THREE MEANINGS, AND ONLY ONE OF THEM RELEASES ANYTHING:
|
|
16625
|
+
*
|
|
16626
|
+
* key omitted leave that connection alone
|
|
16627
|
+
* { resourceKey, … } connect to (or keep) this provider
|
|
16628
|
+
* { state: disconnected } release the connection it holds
|
|
16629
|
+
*
|
|
16596
16630
|
* OPTIONAL, PERMANENTLY. Every manifest written before this field
|
|
16597
16631
|
* existed omits it, and absence has to keep meaning "leave the
|
|
16598
16632
|
* connections alone" — otherwise re-applying an unchanged file would
|
|
16599
|
-
* release a binding somebody made in the portal.
|
|
16633
|
+
* release a binding somebody made in the portal. A release is
|
|
16634
|
+
* therefore never inferred from a missing key; it is stated.
|
|
16600
16635
|
*
|
|
16601
16636
|
* The keys the platform will ACCEPT here are narrower than the shape:
|
|
16602
16637
|
* only a dependency whose interface the registry calls
|
|
@@ -19227,6 +19262,18 @@ function printPlan(plan, json) {
|
|
|
19227
19262
|
}
|
|
19228
19263
|
}
|
|
19229
19264
|
}
|
|
19265
|
+
const disconnects = plan.dependencyDisconnects ?? [];
|
|
19266
|
+
if (disconnects.length > 0) {
|
|
19267
|
+
lines.push(" connections to disconnect:");
|
|
19268
|
+
for (const disconnect of disconnects) {
|
|
19269
|
+
lines.push(` ${disconnect.dependencyKey}`);
|
|
19270
|
+
if (disconnect.interfaceId !== void 0) {
|
|
19271
|
+
lines.push(
|
|
19272
|
+
` interface: ${disconnect.interfaceId}${disconnect.interfaceVersion ? `/${disconnect.interfaceVersion}` : ""}`
|
|
19273
|
+
);
|
|
19274
|
+
}
|
|
19275
|
+
}
|
|
19276
|
+
}
|
|
19230
19277
|
if ((plan.secretsToWrite ?? []).length > 0) {
|
|
19231
19278
|
lines.push(` secrets to set: ${plan.secretsToWrite.join(", ")}`);
|
|
19232
19279
|
for (const line of secretWriteConsequence(plan)) lines.push(` ${line}`);
|