@varde-flyt/vfac 0.3.0 → 0.3.2
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/vfac.mjs +84 -49
- package/package.json +1 -1
package/dist/vfac.mjs
CHANGED
|
@@ -12673,6 +12673,58 @@ function matches(pattern, value) {
|
|
|
12673
12673
|
}
|
|
12674
12674
|
}
|
|
12675
12675
|
|
|
12676
|
+
// ../product-configuration/dist/resource-api-version.js
|
|
12677
|
+
var RESOURCE_API_VERSION = "resources.vardeflyt.no/v1";
|
|
12678
|
+
var PRODUCT_INSTANCE_KIND = "ProductInstance";
|
|
12679
|
+
|
|
12680
|
+
// ../product-configuration/dist/product-instance-example.js
|
|
12681
|
+
function isSecret(declaration) {
|
|
12682
|
+
return declaration.writeOnly === true || declaration["x-secret"] === true;
|
|
12683
|
+
}
|
|
12684
|
+
function seedConfiguration(configuration) {
|
|
12685
|
+
const properties = configuration?.properties ?? {};
|
|
12686
|
+
const required = new Set(configuration?.required ?? []);
|
|
12687
|
+
const values = {};
|
|
12688
|
+
const open = [];
|
|
12689
|
+
const requiredSecrets = [];
|
|
12690
|
+
for (const [name, declaration] of Object.entries(properties)) {
|
|
12691
|
+
if (isSecret(declaration)) {
|
|
12692
|
+
if (required.has(name))
|
|
12693
|
+
requiredSecrets.push(name);
|
|
12694
|
+
continue;
|
|
12695
|
+
}
|
|
12696
|
+
if (declaration.default !== void 0) {
|
|
12697
|
+
values[name] = declaration.default;
|
|
12698
|
+
continue;
|
|
12699
|
+
}
|
|
12700
|
+
if (required.has(name)) {
|
|
12701
|
+
values[name] = "";
|
|
12702
|
+
open.push({ name, type: declaration.type ?? null });
|
|
12703
|
+
}
|
|
12704
|
+
}
|
|
12705
|
+
return { values, open, requiredSecrets };
|
|
12706
|
+
}
|
|
12707
|
+
function productInstanceExample(input) {
|
|
12708
|
+
return {
|
|
12709
|
+
apiVersion: RESOURCE_API_VERSION,
|
|
12710
|
+
kind: PRODUCT_INSTANCE_KIND,
|
|
12711
|
+
// The key is spread rather than set, so an underivable one is ABSENT from
|
|
12712
|
+
// the document instead of present and empty.
|
|
12713
|
+
metadata: { name: input.name, ...input.key ? { key: input.key } : {} },
|
|
12714
|
+
spec: {
|
|
12715
|
+
productId: input.productId,
|
|
12716
|
+
productVersion: input.productVersion,
|
|
12717
|
+
region: input.region,
|
|
12718
|
+
profile: input.profile,
|
|
12719
|
+
configuration: input.configuration
|
|
12720
|
+
}
|
|
12721
|
+
};
|
|
12722
|
+
}
|
|
12723
|
+
function exampleResourceKey(name) {
|
|
12724
|
+
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^[^a-z]+/, "").replace(/-+$/, "").slice(0, 63);
|
|
12725
|
+
return /^[a-z][a-z0-9-]{1,61}[a-z0-9]$/.test(slug) ? slug : "";
|
|
12726
|
+
}
|
|
12727
|
+
|
|
12676
12728
|
// ../platform-schemas/dist/index.js
|
|
12677
12729
|
var TENANT_KEY_REGEX = /^[a-z][a-z0-9-]{2,23}[a-z0-9]$/;
|
|
12678
12730
|
var RESERVED_TENANT_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -12763,10 +12815,8 @@ var OperationStatusSchema = external_exports.enum([
|
|
|
12763
12815
|
|
|
12764
12816
|
// ../product-contracts/dist/api-version.js
|
|
12765
12817
|
var PRODUCT_API_VERSION = "products.vardeflyt.no/v1";
|
|
12766
|
-
var RESOURCE_API_VERSION = "resources.vardeflyt.no/v1";
|
|
12767
12818
|
var PRODUCT_DEFINITION_KIND = "ProductDefinition";
|
|
12768
12819
|
var DEPLOYMENT_BLUEPRINT_KIND = "DeploymentBlueprint";
|
|
12769
|
-
var PRODUCT_INSTANCE_KIND = "ProductInstance";
|
|
12770
12820
|
var ProductApiVersionSchema = external_exports.literal(PRODUCT_API_VERSION, {
|
|
12771
12821
|
errorMap: () => ({
|
|
12772
12822
|
message: `apiVersion must be "${PRODUCT_API_VERSION}". An unrecognized contract format is refused rather than ignored.`
|
|
@@ -15954,6 +16004,9 @@ async function runDoctor(parsed) {
|
|
|
15954
16004
|
}
|
|
15955
16005
|
const access = who.data.access;
|
|
15956
16006
|
const projects = access.projects.map((project) => project.projectId);
|
|
16007
|
+
const mutating = access.projects.filter(
|
|
16008
|
+
(project) => project.permissions.some((permission) => !permission.endsWith(".read"))
|
|
16009
|
+
);
|
|
15957
16010
|
checks.push(
|
|
15958
16011
|
access.tenantWide ? {
|
|
15959
16012
|
name: "Access",
|
|
@@ -15980,7 +16033,15 @@ async function runDoctor(parsed) {
|
|
|
15980
16033
|
// members, other Tenants' resources. An agent read the warning,
|
|
15981
16034
|
// ran the listing, watched it succeed, and learned to distrust the
|
|
15982
16035
|
// line — which is the worst outcome for a diagnostic.
|
|
15983
|
-
|
|
16036
|
+
// AND WHAT IT MAY DO THERE, which this also got wrong. "You can
|
|
16037
|
+
// deploy in those Projects" is false for a gate granted *Project
|
|
16038
|
+
// Read* — `project.read` and `resource.read`, no writes at all —
|
|
16039
|
+
// and `doctor` is the FIRST command an agent is told to run, so it
|
|
16040
|
+
// was the first sentence an observing agent read. An agent that
|
|
16041
|
+
// believes it can deploy and is then refused reports a platform
|
|
16042
|
+
// defect, which is precisely the outcome the guide now tells it not
|
|
16043
|
+
// to reach for. Scope and role are two questions; this answers both.
|
|
16044
|
+
detail: `${projects.join(", ")} \u2014 and nothing organization-wide. ` + (mutating.length > 0 ? "You can deploy in those Projects, read their catalogue, and list them. " : "Read-only there: catalogue, manifests, resources and operations. An apply or a lifecycle command is refused, and that is what was granted rather than a fault. ") + "Anything ACROSS the organization \u2014 a Project you hold nothing in, or its members \u2014 is refused."
|
|
15984
16045
|
}
|
|
15985
16046
|
);
|
|
15986
16047
|
checks.push({
|
|
@@ -16159,13 +16220,13 @@ async function runGet(parsed) {
|
|
|
16159
16220
|
const declared = Array.isArray(resource["outputDeclarations"]) ? resource["outputDeclarations"] : [];
|
|
16160
16221
|
const declaredNames = declared.map((entry) => entry["key"]).filter((key2) => typeof key2 === "string");
|
|
16161
16222
|
const names = [.../* @__PURE__ */ new Set([...Object.keys(outputs), ...declaredNames])].sort();
|
|
16162
|
-
const
|
|
16223
|
+
const isSecret2 = (name) => declared.find((entry) => entry["key"] === name)?.["secret"] === true;
|
|
16163
16224
|
if (names.length > 0) {
|
|
16164
16225
|
lines.push("", " Outputs");
|
|
16165
16226
|
const width = Math.max(...names.map((name) => name.length));
|
|
16166
16227
|
for (const name of names) {
|
|
16167
16228
|
lines.push(
|
|
16168
|
-
` ${name.padEnd(width)} ${
|
|
16229
|
+
` ${name.padEnd(width)} ${isSecret2(name) ? "[secret]" : String(outputs[name] ?? "")}`
|
|
16169
16230
|
);
|
|
16170
16231
|
const meaning = declared.find((entry) => entry["key"] === name);
|
|
16171
16232
|
const description = meaning?.["description"];
|
|
@@ -16586,7 +16647,7 @@ async function runManifestInit(parsed) {
|
|
|
16586
16647
|
if (!result.ok) return printError(result.error, parsed.flags["output"] === "json");
|
|
16587
16648
|
const product = result.data;
|
|
16588
16649
|
const notes = [];
|
|
16589
|
-
const key = parsed.flags["key"] ??
|
|
16650
|
+
const key = parsed.flags["key"] ?? exampleResourceKey(name);
|
|
16590
16651
|
if (!key) {
|
|
16591
16652
|
notes.push(
|
|
16592
16653
|
"metadata.key \u2014 a stable identity, 3 to 63 characters, lower case. Required before apply"
|
|
@@ -16652,43 +16713,24 @@ Product Deployment as Code v1 cannot express yet. Deploy it from the portal.
|
|
|
16652
16713
|
offered.length === 0 ? `${product.productId} ${product.version} declares no service profile. Ask the publisher.` : `This Product offers several service profiles. Pass --profile <${offered.join("|")}>.`
|
|
16653
16714
|
);
|
|
16654
16715
|
}
|
|
16655
|
-
const
|
|
16656
|
-
const
|
|
16657
|
-
|
|
16658
|
-
for (const [property, declaration] of Object.entries(properties)) {
|
|
16659
|
-
const secret = declaration.writeOnly === true || declaration["x-secret"] === true;
|
|
16660
|
-
if (secret) {
|
|
16661
|
-
if (required.includes(property)) {
|
|
16662
|
-
notes.push(`--secret ${property}=env:VAR \u2014 required, and never written to this file`);
|
|
16663
|
-
}
|
|
16664
|
-
continue;
|
|
16665
|
-
}
|
|
16666
|
-
if (declaration.default !== void 0) {
|
|
16667
|
-
configuration[property] = declaration.default;
|
|
16668
|
-
continue;
|
|
16669
|
-
}
|
|
16670
|
-
if (required.includes(property)) {
|
|
16671
|
-
configuration[property] = "";
|
|
16672
|
-
notes.push(`spec.configuration.${property} \u2014 required${typeOf(declaration)}`);
|
|
16673
|
-
}
|
|
16716
|
+
const seed = seedConfiguration(product.configuration);
|
|
16717
|
+
for (const property of seed.requiredSecrets) {
|
|
16718
|
+
notes.push(`--secret ${property}=env:VAR \u2014 required, and never written to this file`);
|
|
16674
16719
|
}
|
|
16675
|
-
const
|
|
16676
|
-
|
|
16677
|
-
|
|
16678
|
-
|
|
16679
|
-
|
|
16680
|
-
|
|
16681
|
-
|
|
16682
|
-
|
|
16683
|
-
|
|
16684
|
-
|
|
16685
|
-
|
|
16686
|
-
|
|
16687
|
-
|
|
16688
|
-
|
|
16689
|
-
configuration
|
|
16690
|
-
}
|
|
16691
|
-
};
|
|
16720
|
+
for (const setting of seed.open) {
|
|
16721
|
+
notes.push(
|
|
16722
|
+
`spec.configuration.${setting.name} \u2014 required${setting.type ? ` (${setting.type})` : ""}`
|
|
16723
|
+
);
|
|
16724
|
+
}
|
|
16725
|
+
const document = productInstanceExample({
|
|
16726
|
+
name,
|
|
16727
|
+
...key ? { key } : {},
|
|
16728
|
+
productId: product.productId,
|
|
16729
|
+
productVersion: product.version,
|
|
16730
|
+
region,
|
|
16731
|
+
profile,
|
|
16732
|
+
configuration: seed.values
|
|
16733
|
+
});
|
|
16692
16734
|
const checked = ProductInstanceTemplateSchema.safeParse(document);
|
|
16693
16735
|
if (!checked.success) {
|
|
16694
16736
|
const where = checked.error.issues.map((issue) => ` ${issue.path.join(".") || "(document)"}: ${issue.message}`).join("\n");
|
|
@@ -16712,13 +16754,6 @@ function refuse(message) {
|
|
|
16712
16754
|
`);
|
|
16713
16755
|
return 1;
|
|
16714
16756
|
}
|
|
16715
|
-
function typeOf(declaration) {
|
|
16716
|
-
return declaration.type ? ` (${declaration.type})` : "";
|
|
16717
|
-
}
|
|
16718
|
-
function keyFrom(name) {
|
|
16719
|
-
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^[^a-z]+/, "").replace(/-+$/, "").slice(0, 63);
|
|
16720
|
-
return /^[a-z][a-z0-9-]{1,61}[a-z0-9]$/.test(slug) ? slug : "";
|
|
16721
|
-
}
|
|
16722
16757
|
|
|
16723
16758
|
// src/commands/guide.ts
|
|
16724
16759
|
async function runGuide(parsed) {
|