@firestartr/cli 2.11.0-snapshot-ghpages-01 → 2.11.0-snapshot-patch-claims
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/build/index.js +1258 -795
- package/build/packages/cdk8s_renderer/src/charts/catalog/userChart.d.ts +1 -3
- package/build/packages/cdk8s_renderer/src/claims/base/schemas/index.d.ts +1 -0
- package/build/packages/cdk8s_renderer/src/claims/github/index.d.ts +1 -0
- package/build/packages/cdk8s_renderer/src/claims/github/pages.schema.d.ts +1 -0
- package/build/packages/cdk8s_renderer/src/claims/stitching/errors.d.ts +14 -0
- package/build/packages/cdk8s_renderer/src/claims/stitching/protectedPaths.d.ts +3 -0
- package/build/packages/cdk8s_renderer/src/claims/stitching/stitching.d.ts +19 -0
- package/build/packages/cdk8s_renderer/src/overriders/featureOverride.d.ts +2 -11
- package/build/packages/cdk8s_renderer/src/validations/backstageAnnotations.d.ts +2 -0
- package/build/packages/features_preparer/src/index.d.ts +5 -2
- package/build/packages/features_preparer/src/installer.d.ts +2 -0
- package/build/packages/features_preparer/src/renderer.d.ts +2 -0
- package/build/packages/features_renderer/index.d.ts +4 -1
- package/build/packages/features_renderer/src/auxiliar.d.ts +4 -1
- package/build/packages/features_renderer/src/render.d.ts +2 -1
- package/build/packages/features_renderer/src/schema.d.ts +3 -8
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -128395,7 +128395,7 @@ function trasformLeg(leg) {
|
|
|
128395
128395
|
|
|
128396
128396
|
|
|
128397
128397
|
function getFeatureRenderedPathForEntity(entity, featureName, basePath = '/tmp') {
|
|
128398
|
-
const entityFolderName = `${entity.metadata.name}`.toLowerCase();
|
|
128398
|
+
const entityFolderName = `${entity.metadata?.name ?? entity.name}`.toLowerCase();
|
|
128399
128399
|
return external_path_default().join(basePath, entityFolderName, featureName);
|
|
128400
128400
|
}
|
|
128401
128401
|
function getFeatureRenderedConfigForComponent(entity, featureName, basePath = '/tmp/features') {
|
|
@@ -161689,6 +161689,19 @@ PolicyInitializer.applicableKinds = ['TFWorkspaceClaim'];
|
|
|
161689
161689
|
|
|
161690
161690
|
;// CONCATENATED MODULE: ../cdk8s_renderer/src/initializers/metadata.ts
|
|
161691
161691
|
|
|
161692
|
+
const BACKSTAGE_ANNOTATION_PREFIX = 'firestartr.backstage.dev/';
|
|
161693
|
+
function isCatalogEntity(cr) {
|
|
161694
|
+
return cr.apiVersion === 'backstage.io/v1alpha1';
|
|
161695
|
+
}
|
|
161696
|
+
function filterBackstageAnnotations(annotations) {
|
|
161697
|
+
const filtered = {};
|
|
161698
|
+
for (const [key, value] of Object.entries(annotations)) {
|
|
161699
|
+
if (!key.startsWith(BACKSTAGE_ANNOTATION_PREFIX)) {
|
|
161700
|
+
filtered[key] = value;
|
|
161701
|
+
}
|
|
161702
|
+
}
|
|
161703
|
+
return filtered;
|
|
161704
|
+
}
|
|
161692
161705
|
class MetadataInitializer extends InitializerPatches {
|
|
161693
161706
|
constructor() {
|
|
161694
161707
|
super(...arguments);
|
|
@@ -161707,8 +161720,11 @@ class MetadataInitializer extends InitializerPatches {
|
|
|
161707
161720
|
if ('annotations' in claim && typeof claim.annotations === 'object') {
|
|
161708
161721
|
cr.metadata = cr.metadata || {};
|
|
161709
161722
|
const crAnnotations = cr.metadata.annotations ?? {};
|
|
161723
|
+
const claimAnnotations = isCatalogEntity(cr)
|
|
161724
|
+
? claim.annotations
|
|
161725
|
+
: filterBackstageAnnotations(claim.annotations);
|
|
161710
161726
|
cr.metadata.annotations = {
|
|
161711
|
-
...
|
|
161727
|
+
...claimAnnotations,
|
|
161712
161728
|
...crAnnotations,
|
|
161713
161729
|
};
|
|
161714
161730
|
}
|
|
@@ -163661,6 +163677,7 @@ const organizationSettingsProperties = {
|
|
|
163661
163677
|
buildType: { type: 'string', enum: ['workflow', 'legacy'] },
|
|
163662
163678
|
source: {
|
|
163663
163679
|
type: 'object',
|
|
163680
|
+
required: ['branch', 'path'],
|
|
163664
163681
|
properties: {
|
|
163665
163682
|
branch: { type: 'string' },
|
|
163666
163683
|
path: { type: 'string', enum: ['/', '/docs'] },
|
|
@@ -164346,740 +164363,6 @@ const base_secrets_schema = 'firestartr.dev://common/SecretsClaim';
|
|
|
164346
164363
|
SecretsClaimSchema: base_secrets_schema,
|
|
164347
164364
|
});
|
|
164348
164365
|
|
|
164349
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/lazy_loader.ts
|
|
164350
|
-
|
|
164351
|
-
|
|
164352
|
-
|
|
164353
|
-
|
|
164354
|
-
|
|
164355
|
-
|
|
164356
|
-
|
|
164357
|
-
|
|
164358
|
-
|
|
164359
|
-
|
|
164360
|
-
|
|
164361
|
-
|
|
164362
|
-
|
|
164363
|
-
|
|
164364
|
-
|
|
164365
|
-
|
|
164366
|
-
// We need to ensure the grep command is a gnu version
|
|
164367
|
-
let IS_GNU_GREP = false;
|
|
164368
|
-
let GREP_ON_CHECK = false;
|
|
164369
|
-
// this loop is for avoid race conditions
|
|
164370
|
-
// once a check is running no more checks
|
|
164371
|
-
async function waitForCheck() {
|
|
164372
|
-
const f_wait = () => new Promise((timeOut) => setTimeout(timeOut, 10));
|
|
164373
|
-
do {
|
|
164374
|
-
await f_wait();
|
|
164375
|
-
} while (GREP_ON_CHECK);
|
|
164376
|
-
}
|
|
164377
|
-
function checkGrep() {
|
|
164378
|
-
return new Promise((ok, ko) => {
|
|
164379
|
-
// idempotency: already checked
|
|
164380
|
-
if (IS_GNU_GREP)
|
|
164381
|
-
return ok();
|
|
164382
|
-
// a check is already running no new checks
|
|
164383
|
-
if (GREP_ON_CHECK)
|
|
164384
|
-
return waitForCheck();
|
|
164385
|
-
logger.info('Checking the grep command');
|
|
164386
|
-
GREP_ON_CHECK = true;
|
|
164387
|
-
const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['--version']);
|
|
164388
|
-
handler.on('close', (code) => {
|
|
164389
|
-
GREP_ON_CHECK = false;
|
|
164390
|
-
if (code === 0) {
|
|
164391
|
-
logger.debug('Grep is a gnu grep');
|
|
164392
|
-
IS_GNU_GREP = true;
|
|
164393
|
-
ok();
|
|
164394
|
-
}
|
|
164395
|
-
else {
|
|
164396
|
-
ko('Lazy evaluation needs a gnu-grep command');
|
|
164397
|
-
}
|
|
164398
|
-
});
|
|
164399
|
-
});
|
|
164400
|
-
}
|
|
164401
|
-
async function loadClaim(claimRef, org, defaults = loadClaimDefaults(), patchClaim = loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, existingRefs = {}, postValidations = new Map()) {
|
|
164402
|
-
await checkGrep();
|
|
164403
|
-
let result = existingRefs;
|
|
164404
|
-
logger.info(`Load reference ${claimRef}`);
|
|
164405
|
-
initVirtualClaims(org);
|
|
164406
|
-
logger.info(`Load reference (parts) ${claimRef.split(/-/)[0]} ${claimRef.replace(/^[^-]+-/, '')}`);
|
|
164407
|
-
// cargas datos con grep
|
|
164408
|
-
try {
|
|
164409
|
-
const claimData = await lazyGetClaim(claimRef.split(/-/)[0], claimRef.replace(/^[^-]+-/, ''), org, cwd);
|
|
164410
|
-
const claim = patchClaim(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(claimData), defaults);
|
|
164411
|
-
let variants = [];
|
|
164412
|
-
if (claim.kind === 'TFWorkspaceClaim' &&
|
|
164413
|
-
claim.providers?.terraform?.variants) {
|
|
164414
|
-
variants = claim.providers.terraform.variants;
|
|
164415
|
-
delete claim.providers.terraform.variants;
|
|
164416
|
-
}
|
|
164417
|
-
logger.silly(`Patched claim is:
|
|
164418
|
-
---
|
|
164419
|
-
${catalog_common/* default.io.toYaml */.Z.io.toYaml(claim)}`);
|
|
164420
|
-
try {
|
|
164421
|
-
validateClaim(claim, base[`${claim.kind}Schema`]);
|
|
164422
|
-
await optionalValidation(claim);
|
|
164423
|
-
}
|
|
164424
|
-
catch (error) {
|
|
164425
|
-
let errorMsg = '';
|
|
164426
|
-
if (Array.isArray(error)) {
|
|
164427
|
-
for (const data of error) {
|
|
164428
|
-
errorMsg = `${errorMsg}
|
|
164429
|
-
- ${data.instancePath}: ${data.message}`;
|
|
164430
|
-
}
|
|
164431
|
-
}
|
|
164432
|
-
else {
|
|
164433
|
-
errorMsg = error instanceof Error ? error.message : String(error);
|
|
164434
|
-
}
|
|
164435
|
-
throw new Error(`Error when validating claim ${claimRef}: ${errorMsg}`);
|
|
164436
|
-
}
|
|
164437
|
-
result[claimRef] = {};
|
|
164438
|
-
result[claimRef]['claim'] = claim;
|
|
164439
|
-
result[claimRef]['claimPath'] = VisitedClaims[claimRef];
|
|
164440
|
-
if (VisitedClaims[claimRef] === 'virtual') {
|
|
164441
|
-
result = await setVirtualClaimAdditionalData(result, claim, claimRef);
|
|
164442
|
-
}
|
|
164443
|
-
else {
|
|
164444
|
-
result = await setNonVirtualClaimAdditionalData(result, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
|
|
164445
|
-
}
|
|
164446
|
-
const claimKind = claim.kind;
|
|
164447
|
-
const references = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(claim));
|
|
164448
|
-
for (const ref of references) {
|
|
164449
|
-
if (!result[ref]) {
|
|
164450
|
-
const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
|
|
164451
|
-
result = lodash_default().merge(result, resolvedReferences);
|
|
164452
|
-
}
|
|
164453
|
-
}
|
|
164454
|
-
if (variants.length > 0) {
|
|
164455
|
-
const parentClaimPath = VisitedClaims[claimRef];
|
|
164456
|
-
for (const variant of variants) {
|
|
164457
|
-
if (!variant.name || !variant.overrides) {
|
|
164458
|
-
throw new Error(`Variant in claim ${claimRef} is missing required field 'name' or 'overrides'`);
|
|
164459
|
-
}
|
|
164460
|
-
const prohibitedOverrideFields = ['source', 'module', 'name'];
|
|
164461
|
-
for (const field of prohibitedOverrideFields) {
|
|
164462
|
-
if (field in variant.overrides) {
|
|
164463
|
-
throw new Error(`Variant '${variant.name}' in claim ${claimRef} cannot override '${field}'`);
|
|
164464
|
-
}
|
|
164465
|
-
}
|
|
164466
|
-
const composedName = claim.providers.terraform.name + '-' + variant.name;
|
|
164467
|
-
const variantClaim = lodash_default().cloneDeep(claim);
|
|
164468
|
-
variantClaim._parentClaimName = claim.name;
|
|
164469
|
-
variantClaim.name = composedName;
|
|
164470
|
-
variantClaim.providers.terraform = lodash_default().merge({}, claim.providers.terraform, variant.overrides);
|
|
164471
|
-
variantClaim.providers.terraform.name = composedName;
|
|
164472
|
-
if (!variantClaim.annotations) {
|
|
164473
|
-
variantClaim.annotations = {};
|
|
164474
|
-
}
|
|
164475
|
-
variantClaim.annotations['firestartr.dev/variant-of'] =
|
|
164476
|
-
claim.providers.terraform.name;
|
|
164477
|
-
const variantRef = `TFWorkspaceClaim-${composedName}`;
|
|
164478
|
-
if (result[variantRef]) {
|
|
164479
|
-
throw new Error(`Variant name '${variant.name}' (composed: '${composedName}') from claim '${claimRef}' conflicts with existing claim '${variantRef}'`);
|
|
164480
|
-
}
|
|
164481
|
-
logger.info(`Creating synthetic variant claim ${variantRef}`);
|
|
164482
|
-
result[variantRef] = {};
|
|
164483
|
-
result[variantRef]['claim'] = variantClaim;
|
|
164484
|
-
result[variantRef]['claimPath'] = parentClaimPath;
|
|
164485
|
-
result = await setNonVirtualClaimAdditionalData(result, variantClaim, variantRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
|
|
164486
|
-
const variantReferences = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(variantClaim));
|
|
164487
|
-
for (const ref of variantReferences) {
|
|
164488
|
-
if (!result[ref]) {
|
|
164489
|
-
const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
|
|
164490
|
-
result = lodash_default().merge(result, resolvedReferences);
|
|
164491
|
-
}
|
|
164492
|
-
}
|
|
164493
|
-
}
|
|
164494
|
-
}
|
|
164495
|
-
}
|
|
164496
|
-
catch (err) {
|
|
164497
|
-
throw `Lazy Loading: ${err}`;
|
|
164498
|
-
}
|
|
164499
|
-
return [result, postValidations];
|
|
164500
|
-
}
|
|
164501
|
-
let LoadedClaims = {};
|
|
164502
|
-
let VisitedClaims = {};
|
|
164503
|
-
let DuplicatedClaims = {};
|
|
164504
|
-
function resetLazyLoader() {
|
|
164505
|
-
LoadedClaims = {};
|
|
164506
|
-
VisitedClaims = {};
|
|
164507
|
-
DuplicatedClaims = {};
|
|
164508
|
-
}
|
|
164509
|
-
async function lazyGetClaim(kind, name, org, cwd) {
|
|
164510
|
-
const indice = `${kind}-${name}`;
|
|
164511
|
-
logger.info(`Lazy loading ${kind}-${name} with index ${indice}`);
|
|
164512
|
-
if (indice in LoadedClaims)
|
|
164513
|
-
return LoadedClaims[indice];
|
|
164514
|
-
if (isVirtualClaim(kind, name)) {
|
|
164515
|
-
await loadVirtualClaim(kind, name, org);
|
|
164516
|
-
}
|
|
164517
|
-
else {
|
|
164518
|
-
await getClaimsByName(name, cwd);
|
|
164519
|
-
}
|
|
164520
|
-
if (indice in LoadedClaims) {
|
|
164521
|
-
return LoadedClaims[indice];
|
|
164522
|
-
}
|
|
164523
|
-
else {
|
|
164524
|
-
throw new Error(`Error: ${kind}-${name} not found`);
|
|
164525
|
-
}
|
|
164526
|
-
}
|
|
164527
|
-
async function getClaimsByName(name, cwd = '.') {
|
|
164528
|
-
return new Promise((ok, ko) => {
|
|
164529
|
-
const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['-r', '-l', '--include=*', '-E', `name: "?${name}"?`, '.'], {
|
|
164530
|
-
cwd: cwd,
|
|
164531
|
-
});
|
|
164532
|
-
logger.info(`Running ${['grep', '-r', '-l', '--include', '-E', 'name: "' + name + '"?', '.'].join(' ')}`);
|
|
164533
|
-
const entradas = [];
|
|
164534
|
-
const chunks = [];
|
|
164535
|
-
handler.stdout.on('data', (data) => {
|
|
164536
|
-
chunks.push(data.toString('utf-8'));
|
|
164537
|
-
});
|
|
164538
|
-
handler.on('close', () => {
|
|
164539
|
-
const dataFinal = chunks.join('');
|
|
164540
|
-
const fileNameList = dataFinal.split(/\n/).filter((line) => line !== '');
|
|
164541
|
-
for (const fileName of fileNameList) {
|
|
164542
|
-
// only yaml files
|
|
164543
|
-
if (!fileName.match(/\.yml$|\.yaml$/)) {
|
|
164544
|
-
continue;
|
|
164545
|
-
}
|
|
164546
|
-
// only entries not already visited
|
|
164547
|
-
if (Object.values(VisitedClaims).includes(fileName)) {
|
|
164548
|
-
continue;
|
|
164549
|
-
}
|
|
164550
|
-
entradas.push(external_path_.join(cwd, fileName));
|
|
164551
|
-
}
|
|
164552
|
-
return Promise.all(entradas.map((entrada) => {
|
|
164553
|
-
return loadRawClaim(entrada);
|
|
164554
|
-
}))
|
|
164555
|
-
.then(() => {
|
|
164556
|
-
ok();
|
|
164557
|
-
})
|
|
164558
|
-
.catch((err) => {
|
|
164559
|
-
ko(err);
|
|
164560
|
-
});
|
|
164561
|
-
});
|
|
164562
|
-
});
|
|
164563
|
-
}
|
|
164564
|
-
async function loadRawClaim(entry) {
|
|
164565
|
-
return new Promise((ok, ko) => {
|
|
164566
|
-
external_fs_.readFile(entry, 'utf-8', (error, data) => {
|
|
164567
|
-
if (error)
|
|
164568
|
-
return ko(`Reading ${entry}: ${error}`);
|
|
164569
|
-
const claim = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
|
|
164570
|
-
if (!('kind' in claim && 'name' in claim)) {
|
|
164571
|
-
logger.warn(`Invalid claim file ${entry}`);
|
|
164572
|
-
}
|
|
164573
|
-
else {
|
|
164574
|
-
const claimKey = `${claim.kind}-${claim.name}`;
|
|
164575
|
-
if (Object.keys(DuplicatedClaims).includes(claimKey) &&
|
|
164576
|
-
DuplicatedClaims[claimKey] !== entry) {
|
|
164577
|
-
return ko(`Duplicated claim ${claimKey} found files: ${DuplicatedClaims[claimKey]} and ${entry}`);
|
|
164578
|
-
}
|
|
164579
|
-
LoadedClaims[claimKey] = data;
|
|
164580
|
-
VisitedClaims[claimKey] = entry;
|
|
164581
|
-
DuplicatedClaims[claimKey] = entry;
|
|
164582
|
-
ok();
|
|
164583
|
-
}
|
|
164584
|
-
});
|
|
164585
|
-
});
|
|
164586
|
-
}
|
|
164587
|
-
async function setVirtualClaimAdditionalData(renderedData, claim, claimRef) {
|
|
164588
|
-
const virtualClaim = getVirtualClaim(claim.kind, claim.name);
|
|
164589
|
-
renderedData[claimRef]['initializers'] = [
|
|
164590
|
-
new UUIDInitializer(claim),
|
|
164591
|
-
new InitializerClaimRef(),
|
|
164592
|
-
new InitializerDefault(virtualClaim.getDefaultConfig()),
|
|
164593
|
-
];
|
|
164594
|
-
renderedData[claimRef]['globals'] = [];
|
|
164595
|
-
renderedData[claimRef]['overrides'] = [];
|
|
164596
|
-
renderedData[claimRef]['normalizers'] = [new NameNormalizer()];
|
|
164597
|
-
return renderedData;
|
|
164598
|
-
}
|
|
164599
|
-
async function setNonVirtualClaimAdditionalData(renderedData, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers) {
|
|
164600
|
-
renderedData[claimRef]['initializers'] = await loadInitializers(claim, renderedData[claimRef]['claimPath']);
|
|
164601
|
-
renderedData[claimRef]['globals'] = await loadGlobals(claim);
|
|
164602
|
-
renderedData[claimRef]['overrides'] = loadOverrides(claim);
|
|
164603
|
-
renderedData[claimRef]['normalizers'] = await loadNormalizers(claim, renderedData[claimRef]['claimPath']);
|
|
164604
|
-
return renderedData;
|
|
164605
|
-
}
|
|
164606
|
-
async function loadVirtualClaim(kind, name, org) {
|
|
164607
|
-
const virtualClaim = getVirtualClaim(kind, name);
|
|
164608
|
-
const expandedClaim = await virtualClaim.expand({ org });
|
|
164609
|
-
logger.info(`Loading virtual claim ${kind} ${name} ${org}`);
|
|
164610
|
-
LoadedClaims[`${kind}-${name}`] = catalog_common/* default.io.toYaml */.Z.io.toYaml(expandedClaim);
|
|
164611
|
-
VisitedClaims[`${kind}-${name}`] = 'virtual';
|
|
164612
|
-
}
|
|
164613
|
-
|
|
164614
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/claimsDefaulter.ts
|
|
164615
|
-
|
|
164616
|
-
|
|
164617
|
-
|
|
164618
|
-
/*
|
|
164619
|
-
* Default blocks are objects that cannot be merged but applied as a whole. Meaning:
|
|
164620
|
-
* - If the object is defined at the claim-level it is maintained *AS IT IS* (no merge)
|
|
164621
|
-
* - If the block is missing at the claim-level, the default block is applied
|
|
164622
|
-
*/
|
|
164623
|
-
const defaultBlocksPaths = ['/providers/terraform/sync'];
|
|
164624
|
-
function applyBlockAwareDefaults(claim, defaultClaim) {
|
|
164625
|
-
// we always work with a clone of the original
|
|
164626
|
-
const claimClone = JSON.parse(JSON.stringify(claim));
|
|
164627
|
-
// if the block is claim-level defined we store it here
|
|
164628
|
-
const defaultBlocks = new Map();
|
|
164629
|
-
// we remove the blocks entirely of the claim
|
|
164630
|
-
// to achieve an add copy
|
|
164631
|
-
for (const defaultBlockPath of defaultBlocksPaths) {
|
|
164632
|
-
if (claimsDefaulter_hasDeepPath(claimClone, defaultBlockPath) !== true)
|
|
164633
|
-
continue;
|
|
164634
|
-
const originalValue = fast_json_patch_default().getValueByPointer(claimClone, defaultBlockPath);
|
|
164635
|
-
if (originalValue) {
|
|
164636
|
-
logger.silly(`${claim.kind}/${claim.name}: has an original ${defaultBlockPath}: preserving`);
|
|
164637
|
-
defaultBlocks.set(defaultBlockPath, originalValue);
|
|
164638
|
-
fast_json_patch_default().applyPatch(claimClone, [{ op: 'remove', path: defaultBlockPath }]);
|
|
164639
|
-
}
|
|
164640
|
-
}
|
|
164641
|
-
// if the patch has the same path of a block
|
|
164642
|
-
// and the block was defined at claim-level
|
|
164643
|
-
// we interchange the value with the original value
|
|
164644
|
-
// otherwise we use the default
|
|
164645
|
-
const jsonPatchOps = fast_json_patch_default().compare(claimClone, defaultClaim)
|
|
164646
|
-
.filter((jp) => jp.op === 'add')
|
|
164647
|
-
.map((jp) => {
|
|
164648
|
-
if (defaultBlocks.has(jp.path)) {
|
|
164649
|
-
return {
|
|
164650
|
-
...jp,
|
|
164651
|
-
value: defaultBlocks.get(jp.path),
|
|
164652
|
-
};
|
|
164653
|
-
}
|
|
164654
|
-
else {
|
|
164655
|
-
return jp;
|
|
164656
|
-
}
|
|
164657
|
-
});
|
|
164658
|
-
return fast_json_patch_default().applyPatch(claimClone, jsonPatchOps).newDocument;
|
|
164659
|
-
}
|
|
164660
|
-
function claimsDefaulter_hasDeepPath(data, deepPath) {
|
|
164661
|
-
return lodash_default().has(data, deepPath.replace(/\//g, '.').replace(/^\./, ''));
|
|
164662
|
-
}
|
|
164663
|
-
|
|
164664
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/loader.ts
|
|
164665
|
-
|
|
164666
|
-
|
|
164667
|
-
|
|
164668
|
-
|
|
164669
|
-
|
|
164670
|
-
|
|
164671
|
-
|
|
164672
|
-
|
|
164673
|
-
|
|
164674
|
-
|
|
164675
|
-
|
|
164676
|
-
|
|
164677
|
-
|
|
164678
|
-
|
|
164679
|
-
|
|
164680
|
-
const isYamlFile = new RegExp(/\.(yaml|yml)$/);
|
|
164681
|
-
/**
|
|
164682
|
-
*
|
|
164683
|
-
* @returns Virtual Claims
|
|
164684
|
-
*/
|
|
164685
|
-
const virtualClaims = [new FirestartrAllClaim()];
|
|
164686
|
-
/*
|
|
164687
|
-
* Loads all applicable globals for a given claim and stores them into a list.
|
|
164688
|
-
*
|
|
164689
|
-
* Input:
|
|
164690
|
-
* - claim: our custom claim object, with which we check if the global is applicable
|
|
164691
|
-
*
|
|
164692
|
-
* Returns:
|
|
164693
|
-
* - A GlobalSection array promise, containing all the globals loaded for this claim
|
|
164694
|
-
*
|
|
164695
|
-
*/
|
|
164696
|
-
async function loadGlobals(claim) {
|
|
164697
|
-
const result = [];
|
|
164698
|
-
await crawl(getPath('globals'), (entry) => {
|
|
164699
|
-
return isYamlFile.test(entry);
|
|
164700
|
-
}, async (entry, data) => {
|
|
164701
|
-
const globalData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
|
|
164702
|
-
const ext = external_path_.extname(entry);
|
|
164703
|
-
const name = external_path_.basename(entry, ext);
|
|
164704
|
-
if (name in SECTIONS_BY_FILE_NAME) {
|
|
164705
|
-
const section = new SECTIONS_BY_FILE_NAME[name](globalData);
|
|
164706
|
-
if (!(await section.validate(SCHEMAS_BY_SECTION_NAME[name] || {}))) {
|
|
164707
|
-
throw new Error(`Invalid ${name} global file`);
|
|
164708
|
-
}
|
|
164709
|
-
if (globalData.kind === claim.kind) {
|
|
164710
|
-
result.push(section);
|
|
164711
|
-
}
|
|
164712
|
-
else {
|
|
164713
|
-
logger.debug(`Skipping global ${name} because it is not applicable to ${claim.kind}`);
|
|
164714
|
-
}
|
|
164715
|
-
}
|
|
164716
|
-
});
|
|
164717
|
-
logger.info(`Loaded globals ${result}`);
|
|
164718
|
-
return result;
|
|
164719
|
-
}
|
|
164720
|
-
/*
|
|
164721
|
-
* If the input claim is a GithubRepositoryClaim, it loads all it's applicable
|
|
164722
|
-
* overrides and stores them into a list. Otherwise, it returns an empty list.
|
|
164723
|
-
*
|
|
164724
|
-
* Input:
|
|
164725
|
-
* - claim: our custom claim object, which should be a GithubRepositoryClaim
|
|
164726
|
-
*
|
|
164727
|
-
* Returns:
|
|
164728
|
-
* - An Overrider array, with a GithubRepositoryOverrider if the claim
|
|
164729
|
-
* was a GithubRepositoryClaim, or empty if it was not.
|
|
164730
|
-
*
|
|
164731
|
-
*/
|
|
164732
|
-
function loadOverrides(claim) {
|
|
164733
|
-
const overrides = [];
|
|
164734
|
-
if (claim.kind === 'ComponentClaim' && claim.providers.github.overrides) {
|
|
164735
|
-
overrides.push(new GithubRepositoryOverrider());
|
|
164736
|
-
}
|
|
164737
|
-
return overrides;
|
|
164738
|
-
}
|
|
164739
|
-
/**
|
|
164740
|
-
* Load all normalizers and stores them into a list.
|
|
164741
|
-
* @param claim
|
|
164742
|
-
* @returns
|
|
164743
|
-
*/
|
|
164744
|
-
async function loadNormalizers(_claim, path) {
|
|
164745
|
-
const result = [];
|
|
164746
|
-
for (const normalizer of NORMALIZERS) {
|
|
164747
|
-
result.push(new normalizer({ path: path }));
|
|
164748
|
-
}
|
|
164749
|
-
return result;
|
|
164750
|
-
}
|
|
164751
|
-
/*
|
|
164752
|
-
* Loads all applicable initializers for a given claim and stores them into a list.
|
|
164753
|
-
*
|
|
164754
|
-
* Input:
|
|
164755
|
-
* - claim: our custom claim object, with which we check if the initializer is applicable
|
|
164756
|
-
*
|
|
164757
|
-
* Returns:
|
|
164758
|
-
* - An Initializer array promise, containing all the initializers loaded for this claim
|
|
164759
|
-
*
|
|
164760
|
-
*/
|
|
164761
|
-
let loadedInitializers = false;
|
|
164762
|
-
async function loadInitializers(claim, claimPath, initializersPath = getPath('initializers')) {
|
|
164763
|
-
const result = [];
|
|
164764
|
-
await crawl(initializersPath, (entry) => {
|
|
164765
|
-
return isYamlFile.test(entry);
|
|
164766
|
-
}, async (entry, data) => {
|
|
164767
|
-
const initializerData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
|
|
164768
|
-
const ext = external_path_.extname(entry);
|
|
164769
|
-
const name = external_path_.basename(entry, ext);
|
|
164770
|
-
if (name in INITIALIZERS_BY_FILE_NAME) {
|
|
164771
|
-
const initializerBfN = new INITIALIZERS_BY_FILE_NAME[name](initializerData);
|
|
164772
|
-
if (!(await initializerBfN.validate(SCHEMAS_BY_INITIALIZER_NAME[name] || {}))) {
|
|
164773
|
-
throw new Error(`Invalid ${name} initializer file`);
|
|
164774
|
-
}
|
|
164775
|
-
if (initializerData.kind === claim.kind) {
|
|
164776
|
-
result.push(initializerBfN);
|
|
164777
|
-
}
|
|
164778
|
-
else {
|
|
164779
|
-
logger.debug(`Skipping initializer ${name} because it is not applicable to ${claim.kind}`);
|
|
164780
|
-
}
|
|
164781
|
-
}
|
|
164782
|
-
});
|
|
164783
|
-
for (const initializer of INITIALIZERS) {
|
|
164784
|
-
if (initializer.applicableKinds.includes(claim.kind)) {
|
|
164785
|
-
result.push(new initializer({ path: claimPath }));
|
|
164786
|
-
}
|
|
164787
|
-
}
|
|
164788
|
-
logger.info(`Loaded initializers ${JSON.stringify(result)}`);
|
|
164789
|
-
loadedInitializers = result;
|
|
164790
|
-
return loadedInitializers;
|
|
164791
|
-
}
|
|
164792
|
-
function loadClaimDefaults() {
|
|
164793
|
-
try {
|
|
164794
|
-
return catalog_common/* default.io.fromYaml */.Z.io.fromYaml(external_fs_.readFileSync(`${getPath('claimsDefaults')}/claims_defaults.yaml`, 'utf-8'));
|
|
164795
|
-
}
|
|
164796
|
-
catch (error) {
|
|
164797
|
-
const errMsg = `Could not read claims defaults file in path ${getPath('claimsDefaults')}/claims_defaults.yaml: ${error}`;
|
|
164798
|
-
logger.error(errMsg);
|
|
164799
|
-
throw new Error(errMsg);
|
|
164800
|
-
}
|
|
164801
|
-
}
|
|
164802
|
-
/*
|
|
164803
|
-
* Using fast-json-patch, compares a claim to its kind's defaults, then patches it.
|
|
164804
|
-
*
|
|
164805
|
-
* Input:
|
|
164806
|
-
* - claim: our custom claim object, which we want to patch
|
|
164807
|
-
* - defaultsClaims: an object, containing the defaults for each claim kind,
|
|
164808
|
-
* with the same structure that we use for the actual claims
|
|
164809
|
-
*
|
|
164810
|
-
* Returns:
|
|
164811
|
-
* - The patched claim
|
|
164812
|
-
*
|
|
164813
|
-
*/
|
|
164814
|
-
function loader_patchClaim(claim, defaultsClaims) {
|
|
164815
|
-
if (defaultsClaims[claim.kind]) {
|
|
164816
|
-
claim = applyBlockAwareDefaults(claim, defaultsClaims[claim.kind]);
|
|
164817
|
-
}
|
|
164818
|
-
return claim;
|
|
164819
|
-
}
|
|
164820
|
-
async function loadCRsWithFullSet(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
|
|
164821
|
-
const result = {};
|
|
164822
|
-
const fullResult = {};
|
|
164823
|
-
await crawlWithExclusions(crsPath, (entry) => {
|
|
164824
|
-
return isYamlFile.test(entry);
|
|
164825
|
-
}, async (entry, data) => {
|
|
164826
|
-
const yamlData = stripKnownRelations(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data));
|
|
164827
|
-
const metadata = yamlData?.metadata;
|
|
164828
|
-
if (!(yamlData &&
|
|
164829
|
-
typeof yamlData === 'object' &&
|
|
164830
|
-
'kind' in yamlData &&
|
|
164831
|
-
metadata &&
|
|
164832
|
-
typeof metadata === 'object' &&
|
|
164833
|
-
'name' in metadata)) {
|
|
164834
|
-
logger.warn(`Invalid CR file ${entry}`);
|
|
164835
|
-
}
|
|
164836
|
-
else {
|
|
164837
|
-
const crKey = `${yamlData.kind}-${metadata.name}`;
|
|
164838
|
-
if (fullResult[crKey]) {
|
|
164839
|
-
logger.error(`Duplicate CR ${crKey}`);
|
|
164840
|
-
}
|
|
164841
|
-
// Keep the complete CR set for validations that need repository-wide context.
|
|
164842
|
-
fullResult[crKey] = yamlData;
|
|
164843
|
-
// Keep the filtered CR set for previous-CR lookup during claim rendering.
|
|
164844
|
-
if (allowedClaimReferences.length === 0 ||
|
|
164845
|
-
allowedClaimReferences.includes(yamlData.metadata?.annotations?.[catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('claim-ref')])) {
|
|
164846
|
-
result[crKey] = yamlData;
|
|
164847
|
-
}
|
|
164848
|
-
}
|
|
164849
|
-
}, excludedPaths.concat(getAdditionalPaths()));
|
|
164850
|
-
return { crs: result, fullCrs: fullResult };
|
|
164851
|
-
}
|
|
164852
|
-
async function loadCRs(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
|
|
164853
|
-
const { crs } = await loadCRsWithFullSet(crsPath, excludedPaths, allowedClaimReferences);
|
|
164854
|
-
return crs;
|
|
164855
|
-
}
|
|
164856
|
-
/*
|
|
164857
|
-
* Description: Get the renamed using claimRef annotation
|
|
164858
|
-
* Input: claims: any, crs: any
|
|
164859
|
-
* Output: renames: IRenameResult[]
|
|
164860
|
-
*/
|
|
164861
|
-
async function loadRenames(claims, crs) {
|
|
164862
|
-
/*
|
|
164863
|
-
* If checkRenames is false, we don't need to check for renames
|
|
164864
|
-
*/
|
|
164865
|
-
const renamesEnabled = getRenamesEnabled();
|
|
164866
|
-
if (!renamesEnabled)
|
|
164867
|
-
return [];
|
|
164868
|
-
const result = [];
|
|
164869
|
-
/**
|
|
164870
|
-
* For each CR, look for a claim that does not match the name with CR's firestartr.dev/claim-ref annotation
|
|
164871
|
-
*/
|
|
164872
|
-
for (const cr of Object.values(crs)) {
|
|
164873
|
-
const anyCr = cr;
|
|
164874
|
-
if (!anyCr?.metadata?.annotations)
|
|
164875
|
-
continue;
|
|
164876
|
-
// if the annotation is a claimRef
|
|
164877
|
-
const annotationName = common.generic.getFirestartrAnnotation('claim-ref');
|
|
164878
|
-
const annotations = anyCr?.metadata?.annotations || {};
|
|
164879
|
-
if (annotationName in annotations) {
|
|
164880
|
-
const claimRef = anyCr.metadata.annotations[annotationName];
|
|
164881
|
-
// split the annotation into kind and name
|
|
164882
|
-
const [kind, name] = claimRef.split('/');
|
|
164883
|
-
// if the claim exists, check if the name is different for the given provider
|
|
164884
|
-
const referencedClaim = claims[`${kind}-${name}`].claim;
|
|
164885
|
-
const oldName = anyCr.metadata.name;
|
|
164886
|
-
const newName = referencedClaim.providers[getConfiguredProvider()].name;
|
|
164887
|
-
if (oldName !== newName) {
|
|
164888
|
-
result.push({
|
|
164889
|
-
kind: referencedClaim.kind,
|
|
164890
|
-
claimPath: claims[`${kind}-${name}`].claimPath,
|
|
164891
|
-
claimName: referencedClaim.name,
|
|
164892
|
-
oldName,
|
|
164893
|
-
newName,
|
|
164894
|
-
});
|
|
164895
|
-
}
|
|
164896
|
-
}
|
|
164897
|
-
}
|
|
164898
|
-
return result;
|
|
164899
|
-
}
|
|
164900
|
-
async function loadClaimsList(claimRefList, claimsPath = getPath('claims')) {
|
|
164901
|
-
const data = {
|
|
164902
|
-
renderClaims: {},
|
|
164903
|
-
crs: {},
|
|
164904
|
-
fullCrs: {},
|
|
164905
|
-
};
|
|
164906
|
-
const defaults = loadClaimDefaults();
|
|
164907
|
-
for await (const claimRef of claimRefList) {
|
|
164908
|
-
const [renderedClaimData] = await loadClaim(claimRef, getOrg(), defaults, loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, claimsPath);
|
|
164909
|
-
data.renderClaims = lodash_default().merge(data.renderClaims, renderedClaimData);
|
|
164910
|
-
}
|
|
164911
|
-
const crClaimReferences = [];
|
|
164912
|
-
for (const ref of Object.keys(data.renderClaims)) {
|
|
164913
|
-
// Replaces only the first instance of '-'
|
|
164914
|
-
crClaimReferences.push(ref.replace('-', '/'));
|
|
164915
|
-
}
|
|
164916
|
-
const loadedCrs = await loadCRsWithFullSet(getPath('crs'), [getPath('globals'), getPath('initializers')], crClaimReferences);
|
|
164917
|
-
data['crs'] = loadedCrs.crs;
|
|
164918
|
-
data['fullCrs'] = loadedCrs.fullCrs;
|
|
164919
|
-
return data;
|
|
164920
|
-
}
|
|
164921
|
-
function getOrg() {
|
|
164922
|
-
const groupOrg = catalog_common/* default.environment.getFromEnvironmentWithDefault */.Z.environment.getFromEnvironmentWithDefault(catalog_common/* default.types.envVars.org */.Z.types.envVars.org, '');
|
|
164923
|
-
return groupOrg;
|
|
164924
|
-
}
|
|
164925
|
-
|
|
164926
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/references.ts
|
|
164927
|
-
function validateTfStateKeyUniqueness(crs) {
|
|
164928
|
-
const tfStateKeys = {};
|
|
164929
|
-
for (const crKey of Object.keys(crs)) {
|
|
164930
|
-
const cr = crs[crKey];
|
|
164931
|
-
if (!isTerraformWorkspace(cr))
|
|
164932
|
-
continue;
|
|
164933
|
-
const tfKey = cr.spec.firestartr.tfStateKey;
|
|
164934
|
-
if (tfStateKeys[tfKey]) {
|
|
164935
|
-
throw new Error(`❗❗ ❌ RENDER ERROR ❌ ❗❗
|
|
164936
|
-
|
|
164937
|
-
The tfStateKey ${tfKey} is not unique,
|
|
164938
|
-
|
|
164939
|
-
It is being used by the following CRs:
|
|
164940
|
-
|
|
164941
|
-
- ${tfStateKeys[tfKey].kind} ${tfStateKeys[tfKey].metadata.name}
|
|
164942
|
-
|
|
164943
|
-
- ${cr.kind} ${cr.metadata.name}
|
|
164944
|
-
|
|
164945
|
-
Check the following Claims to ensure that the tfStateKey is unique:
|
|
164946
|
-
|
|
164947
|
-
- ${tfStateKeys[tfKey].metadata.annotations['firestartr.dev/claim-ref']}
|
|
164948
|
-
|
|
164949
|
-
- ${cr.metadata.annotations['firestartr.dev/claim-ref']}
|
|
164950
|
-
`);
|
|
164951
|
-
}
|
|
164952
|
-
tfStateKeys[cr.spec.firestartr.tfStateKey] = cr;
|
|
164953
|
-
}
|
|
164954
|
-
}
|
|
164955
|
-
function isCatalogEntity(cr) {
|
|
164956
|
-
return [
|
|
164957
|
-
'Component',
|
|
164958
|
-
'Domain',
|
|
164959
|
-
'System',
|
|
164960
|
-
'User',
|
|
164961
|
-
'Group',
|
|
164962
|
-
'Resource',
|
|
164963
|
-
].includes(cr.kind);
|
|
164964
|
-
}
|
|
164965
|
-
function isTerraformWorkspace(cr) {
|
|
164966
|
-
return cr.kind === 'FirestartrTerraformWorkspace';
|
|
164967
|
-
}
|
|
164968
|
-
|
|
164969
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/crSize.ts
|
|
164970
|
-
|
|
164971
|
-
const K8S_OBJECT_SIZE_LIMIT = 1572864; // 1.5 MiB in bytes, etcd recommended limit: https://etcd.io/docs/latest/dev-guide/limit/
|
|
164972
|
-
function validateCrSizes(crs) {
|
|
164973
|
-
for (const key of Object.keys(crs)) {
|
|
164974
|
-
const cr = crs[key];
|
|
164975
|
-
const serialized = catalog_common/* default.io.toYaml */.Z.io.toYaml(cr);
|
|
164976
|
-
const size = Buffer.byteLength(serialized, 'utf8');
|
|
164977
|
-
if (size > K8S_OBJECT_SIZE_LIMIT) {
|
|
164978
|
-
throw new Error(`CR "${cr.kind}-${cr.metadata.name}" exceeds the Kubernetes object size limit by ${size - K8S_OBJECT_SIZE_LIMIT} bytes. Maximum allowed is ${K8S_OBJECT_SIZE_LIMIT} bytes (1.5MiB).`);
|
|
164979
|
-
}
|
|
164980
|
-
}
|
|
164981
|
-
}
|
|
164982
|
-
|
|
164983
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/permissions.ts
|
|
164984
|
-
|
|
164985
|
-
function validatePermissionsUniqueness(crs) {
|
|
164986
|
-
for (const crkey in crs) {
|
|
164987
|
-
const cr = crs[crkey];
|
|
164988
|
-
if (cr.kind === 'FirestartrGithubRepository') {
|
|
164989
|
-
const permissions = cr.spec.permissions;
|
|
164990
|
-
logger.debug(`Validating Permissions Uniqueness of ${crkey}`);
|
|
164991
|
-
if (permissions) {
|
|
164992
|
-
const rolesByIdentifier = new Map();
|
|
164993
|
-
for (const perm of permissions) {
|
|
164994
|
-
const identifier = perm.collaborator
|
|
164995
|
-
? perm.collaborator
|
|
164996
|
-
: `ref:${perm.ref.kind}:${perm.ref.name}`;
|
|
164997
|
-
const role = perm.role;
|
|
164998
|
-
const prevRole = rolesByIdentifier.get(identifier);
|
|
164999
|
-
if (prevRole === undefined) {
|
|
165000
|
-
rolesByIdentifier.set(identifier, role);
|
|
165001
|
-
}
|
|
165002
|
-
else if (prevRole !== role) {
|
|
165003
|
-
throw new Error(`Conflicting permission role in FirestartrGithubRepository ${crkey}: ${identifier} has roles "${prevRole}" and "${role}".\nFull CR: ${JSON.stringify(cr, null, 2)}`);
|
|
165004
|
-
}
|
|
165005
|
-
}
|
|
165006
|
-
}
|
|
165007
|
-
}
|
|
165008
|
-
}
|
|
165009
|
-
}
|
|
165010
|
-
|
|
165011
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/refsSorter/refsSorter.ts
|
|
165012
|
-
|
|
165013
|
-
/**
|
|
165014
|
-
* @param renderClaims renderClaims to sort
|
|
165015
|
-
* @param kinds kinds to get from renderClaims
|
|
165016
|
-
* @returns renderClaims with only the kinds specified
|
|
165017
|
-
*/
|
|
165018
|
-
function sortRenderClaimsByKind(renderClaims, kinds) {
|
|
165019
|
-
let result = {};
|
|
165020
|
-
for (const kind of kinds) {
|
|
165021
|
-
for (const key in renderClaims) {
|
|
165022
|
-
if (renderClaims[key].claim.kind === kind) {
|
|
165023
|
-
result[key] = renderClaims[key];
|
|
165024
|
-
}
|
|
165025
|
-
}
|
|
165026
|
-
result = sortSelfKindRefs(result, kind);
|
|
165027
|
-
}
|
|
165028
|
-
return result;
|
|
165029
|
-
}
|
|
165030
|
-
function sortSelfKindRefs(renderClaims, kind) {
|
|
165031
|
-
if (!hasSelfRefs(kind)) {
|
|
165032
|
-
return renderClaims;
|
|
165033
|
-
}
|
|
165034
|
-
const newRenderClaims = {};
|
|
165035
|
-
const data = extractRefs(renderClaims, kind);
|
|
165036
|
-
const ordered = [];
|
|
165037
|
-
const visiting = [];
|
|
165038
|
-
const visited = [];
|
|
165039
|
-
for (const key of Object.keys(data)) {
|
|
165040
|
-
if (!visited.find((obj) => obj.name === key)) {
|
|
165041
|
-
sortRefs(data, data[key], ordered, visiting, visited);
|
|
165042
|
-
}
|
|
165043
|
-
}
|
|
165044
|
-
for (const cr of ordered) {
|
|
165045
|
-
newRenderClaims[cr.name] = renderClaims[cr.name];
|
|
165046
|
-
}
|
|
165047
|
-
return newRenderClaims;
|
|
165048
|
-
}
|
|
165049
|
-
function sortRefs(data, claim, ordered = [], visiting = [], visited = []) {
|
|
165050
|
-
if (visiting.find((obj) => obj.name === claim.name)) {
|
|
165051
|
-
throw new Error(`Circular dependency detected for '${claim.name}'`);
|
|
165052
|
-
}
|
|
165053
|
-
if (!visited.find((obj) => obj.name === claim.name)) {
|
|
165054
|
-
visiting.push(claim);
|
|
165055
|
-
if (claim.refs) {
|
|
165056
|
-
for (const ref of claim.refs) {
|
|
165057
|
-
const referencedObject = data[ref];
|
|
165058
|
-
if (!referencedObject) {
|
|
165059
|
-
throw new Error(`Reference '${ref}' does not exist for '${claim.name}'`);
|
|
165060
|
-
}
|
|
165061
|
-
sortRefs(data, referencedObject, ordered, visiting, visited);
|
|
165062
|
-
}
|
|
165063
|
-
}
|
|
165064
|
-
visited.push(visiting.pop());
|
|
165065
|
-
ordered.push(claim);
|
|
165066
|
-
}
|
|
165067
|
-
}
|
|
165068
|
-
function hasSelfRefs(kind) {
|
|
165069
|
-
return ['TFWorkspaceClaim', 'GroupClaim'].includes(kind);
|
|
165070
|
-
}
|
|
165071
|
-
|
|
165072
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/renderer/claims-sorter.ts
|
|
165073
|
-
|
|
165074
|
-
function sortKinds(orderedKinds, claims) {
|
|
165075
|
-
const result = [];
|
|
165076
|
-
for (const kind of orderedKinds) {
|
|
165077
|
-
const kindRenderClaims = sortRenderClaimsByKind(claims, [kind]);
|
|
165078
|
-
result.push(kindRenderClaims);
|
|
165079
|
-
}
|
|
165080
|
-
return result;
|
|
165081
|
-
}
|
|
165082
|
-
|
|
165083
164366
|
;// CONCATENATED MODULE: ../features_renderer/src/common.ts
|
|
165084
164367
|
|
|
165085
164368
|
function isDirectory(path) {
|
|
@@ -165120,14 +164403,9 @@ var ajv_default = /*#__PURE__*/__nccwpck_require__.n(dist_ajv);
|
|
|
165120
164403
|
},
|
|
165121
164404
|
},
|
|
165122
164405
|
patches: {
|
|
165123
|
-
type: '
|
|
165124
|
-
|
|
165125
|
-
'
|
|
165126
|
-
type: 'array',
|
|
165127
|
-
items: {
|
|
165128
|
-
$ref: '#/definitions/Patch',
|
|
165129
|
-
},
|
|
165130
|
-
},
|
|
164406
|
+
type: 'array',
|
|
164407
|
+
items: {
|
|
164408
|
+
$ref: '#/definitions/Patch',
|
|
165131
164409
|
},
|
|
165132
164410
|
},
|
|
165133
164411
|
filesTemplates: {
|
|
@@ -165230,7 +164508,7 @@ var ajv_default = /*#__PURE__*/__nccwpck_require__.n(dist_ajv);
|
|
|
165230
164508
|
type: 'string',
|
|
165231
164509
|
},
|
|
165232
164510
|
value: {
|
|
165233
|
-
type: 'string',
|
|
164511
|
+
type: ['string', 'object', 'array', 'number', 'boolean', 'null'],
|
|
165234
164512
|
},
|
|
165235
164513
|
},
|
|
165236
164514
|
required: ['name', 'op', 'path'],
|
|
@@ -165272,6 +164550,12 @@ function __validateFeatureConfig(featurePath) {
|
|
|
165272
164550
|
}
|
|
165273
164551
|
}
|
|
165274
164552
|
function __validateFeatureConfigData(configData) {
|
|
164553
|
+
// Detect old provider-keyed patches shape for migration hint (PLAN #2648)
|
|
164554
|
+
if (configData.patches &&
|
|
164555
|
+
!Array.isArray(configData.patches) &&
|
|
164556
|
+
typeof configData.patches === 'object') {
|
|
164557
|
+
throw `Feature: config.yaml invalid patches: expected flat array of patches (claim-relative pointers like /annotations/backstage.io~1techdocs-ref), but got provider-keyed object ${JSON.stringify(Object.keys(configData.patches))}. Migrate: patches: { catalog: [...] } → patches: [{ op, path: /annotations/backstage.io~1techdocs-ref, value }]. See #2648. $ref paths also migrate: [spec, org] → [providers, github, org], [metadata, annotations, firestartr.dev/external-name] → [providers, github, name]`;
|
|
164558
|
+
}
|
|
165275
164559
|
const ajv = new (ajv_default())({
|
|
165276
164560
|
allowUnionTypes: true,
|
|
165277
164561
|
});
|
|
@@ -165293,14 +164577,12 @@ function stripAnchoringConstraints(schemaDef) {
|
|
|
165293
164577
|
return clone;
|
|
165294
164578
|
}
|
|
165295
164579
|
function __validateJsonPatches(configData) {
|
|
165296
|
-
const
|
|
165297
|
-
|
|
165298
|
-
|
|
165299
|
-
|
|
165300
|
-
|
|
165301
|
-
|
|
165302
|
-
}
|
|
165303
|
-
}
|
|
164580
|
+
const patches = configData.patches;
|
|
164581
|
+
if (!Array.isArray(patches))
|
|
164582
|
+
return;
|
|
164583
|
+
const err = fast_json_patch_default().validate(patches);
|
|
164584
|
+
if (err) {
|
|
164585
|
+
throw `Feature: config.yaml -> patches: invalid patches ${JSON.stringify(err.message ?? err)}`;
|
|
165304
164586
|
}
|
|
165305
164587
|
}
|
|
165306
164588
|
|
|
@@ -166138,10 +165420,12 @@ const renderTestsSchema = {
|
|
|
166138
165420
|
items: {
|
|
166139
165421
|
type: 'object',
|
|
166140
165422
|
additionalProperties: false,
|
|
166141
|
-
required: ['name'
|
|
165423
|
+
required: ['name'],
|
|
165424
|
+
anyOf: [{ required: ['cr'] }, { required: ['claim'] }],
|
|
166142
165425
|
properties: {
|
|
166143
165426
|
name: { type: 'string', minLength: 1 },
|
|
166144
165427
|
cr: { type: 'string', minLength: 1 },
|
|
165428
|
+
claim: { type: 'string', minLength: 1 },
|
|
166145
165429
|
args: { type: 'object' },
|
|
166146
165430
|
},
|
|
166147
165431
|
},
|
|
@@ -166196,6 +165480,9 @@ function resolveCrPath(featurePath, crRelPath) {
|
|
|
166196
165480
|
}
|
|
166197
165481
|
return resolved;
|
|
166198
165482
|
}
|
|
165483
|
+
function resolveClaimPath(featurePath, claimRelPath) {
|
|
165484
|
+
return resolveCrPath(featurePath, claimRelPath);
|
|
165485
|
+
}
|
|
166199
165486
|
function listYamlFiles(dir) {
|
|
166200
165487
|
if (!fs.existsSync(dir))
|
|
166201
165488
|
return [];
|
|
@@ -166313,6 +165600,7 @@ async function createRenderContext(prefix = 'feature-render-') {
|
|
|
166313
165600
|
buildExpectedOutput,
|
|
166314
165601
|
loadAndValidateRenderTests,
|
|
166315
165602
|
resolveCrPath,
|
|
165603
|
+
resolveClaimPath,
|
|
166316
165604
|
});
|
|
166317
165605
|
|
|
166318
165606
|
;// CONCATENATED MODULE: ../features_renderer/src/featureArgsValidation.ts
|
|
@@ -166436,19 +165724,97 @@ function render(featurePath, featureRenderPath, entity, firestartrConfig = {}, f
|
|
|
166436
165724
|
external_fs_default().writeFileSync(configFile, JSON.stringify(output));
|
|
166437
165725
|
return output;
|
|
166438
165726
|
}
|
|
166439
|
-
function
|
|
165727
|
+
function getPatches(featurePath, entity, firestartrConfig = {}, featureArgs = {}) {
|
|
165728
|
+
const configData = validate(featurePath);
|
|
165729
|
+
validateFeatureArgs(featurePath, featureArgs);
|
|
165730
|
+
const context = buildContext(entity, configData.args, firestartrConfig, featureArgs);
|
|
165731
|
+
const rendered = JSON.parse(renderContent(JSON.stringify(configData), context));
|
|
165732
|
+
return rendered.patches ?? [];
|
|
165733
|
+
}
|
|
165734
|
+
function buildContext(stitchedClaim, args, firestartrConfig, featureArgs) {
|
|
166440
165735
|
const context = {};
|
|
165736
|
+
const resolveRef = (doc, ref) => {
|
|
165737
|
+
const v = lodash_default().get(doc, ref);
|
|
165738
|
+
if (v !== undefined)
|
|
165739
|
+
return v;
|
|
165740
|
+
// Fallback for transition: try CR-shaped alternatives when stitchedClaim is CR-shaped
|
|
165741
|
+
// and vice versa. Covers the ADR 0006 table plus legacy feature_a provisioner paths.
|
|
165742
|
+
const altTable = {
|
|
165743
|
+
'providers,github,org': [
|
|
165744
|
+
['spec', 'org'],
|
|
165745
|
+
['spec', 'provisioner', 'org'],
|
|
165746
|
+
['spec', 'firestartr', 'technology', 'stack'],
|
|
165747
|
+
],
|
|
165748
|
+
'providers,github,branchStrategy,defaultBranch': [
|
|
165749
|
+
['spec', 'repo', 'defaultBranch'],
|
|
165750
|
+
['spec', 'provisioner', 'repo', 'defaultBranch'],
|
|
165751
|
+
],
|
|
165752
|
+
'providers,github,name': [
|
|
165753
|
+
['metadata', 'annotations', 'firestartr.dev/external-name'],
|
|
165754
|
+
['metadata', 'name'],
|
|
165755
|
+
],
|
|
165756
|
+
name: [['metadata', 'name']],
|
|
165757
|
+
'annotations,firestartr.dev/dest-annotation': [
|
|
165758
|
+
['metadata', 'annotations', 'firestartr.dev/dest-annotation'],
|
|
165759
|
+
],
|
|
165760
|
+
};
|
|
165761
|
+
const key = ref.join(',');
|
|
165762
|
+
const alts = altTable[key];
|
|
165763
|
+
if (alts) {
|
|
165764
|
+
for (const alt of alts) {
|
|
165765
|
+
const av = lodash_default().get(doc, alt);
|
|
165766
|
+
if (av !== undefined)
|
|
165767
|
+
return av;
|
|
165768
|
+
}
|
|
165769
|
+
}
|
|
165770
|
+
// Reverse fallback: if ref is CR-shaped, try claim-shaped
|
|
165771
|
+
const reverseTable = {
|
|
165772
|
+
'spec,org': ['providers', 'github', 'org'],
|
|
165773
|
+
'spec,provisioner,technology,stack': ['providers', 'github', 'org'],
|
|
165774
|
+
'spec,firestartr,technology,stack': ['providers', 'github', 'org'],
|
|
165775
|
+
'metadata,name': ['name'],
|
|
165776
|
+
'metadata,annotations,firestartr.dev/dest-annotation': [
|
|
165777
|
+
'annotations',
|
|
165778
|
+
'firestartr.dev/dest-annotation',
|
|
165779
|
+
],
|
|
165780
|
+
'spec,provisioner,org': ['providers', 'github', 'org'],
|
|
165781
|
+
'spec,provisioner,repo,defaultBranch': [
|
|
165782
|
+
'providers',
|
|
165783
|
+
'github',
|
|
165784
|
+
'branchStrategy',
|
|
165785
|
+
'defaultBranch',
|
|
165786
|
+
],
|
|
165787
|
+
'spec,repo,defaultBranch': [
|
|
165788
|
+
'providers',
|
|
165789
|
+
'github',
|
|
165790
|
+
'branchStrategy',
|
|
165791
|
+
'defaultBranch',
|
|
165792
|
+
],
|
|
165793
|
+
'metadata,annotations,firestartr.dev/external-name': [
|
|
165794
|
+
'providers',
|
|
165795
|
+
'github',
|
|
165796
|
+
'name',
|
|
165797
|
+
],
|
|
165798
|
+
};
|
|
165799
|
+
const rev = reverseTable[ref.join(',')];
|
|
165800
|
+
if (rev) {
|
|
165801
|
+
const rv = lodash_default().get(doc, rev);
|
|
165802
|
+
if (rv !== undefined)
|
|
165803
|
+
return rv;
|
|
165804
|
+
}
|
|
165805
|
+
return v;
|
|
165806
|
+
};
|
|
166441
165807
|
Object.entries(args).forEach(([key, arg]) => {
|
|
166442
165808
|
if ('$default' in arg) {
|
|
166443
165809
|
if (Array.isArray(arg['$default'])) {
|
|
166444
|
-
context[key] =
|
|
165810
|
+
context[key] = resolveRef(stitchedClaim, arg['$default']);
|
|
166445
165811
|
}
|
|
166446
165812
|
else {
|
|
166447
165813
|
context[key] = arg['$default'];
|
|
166448
165814
|
}
|
|
166449
165815
|
}
|
|
166450
165816
|
if ('$ref' in arg) {
|
|
166451
|
-
const refValue =
|
|
165817
|
+
const refValue = resolveRef(stitchedClaim, arg['$ref']);
|
|
166452
165818
|
context[key] = refValue;
|
|
166453
165819
|
}
|
|
166454
165820
|
else if ('$lit' in arg) {
|
|
@@ -166578,6 +165944,7 @@ function updateFileContent(featureRenderPath, filePath, content) {
|
|
|
166578
165944
|
|
|
166579
165945
|
|
|
166580
165946
|
|
|
165947
|
+
|
|
166581
165948
|
/* harmony default export */ const features_renderer = ({
|
|
166582
165949
|
validate: validate,
|
|
166583
165950
|
render: render,
|
|
@@ -166587,6 +165954,7 @@ function updateFileContent(featureRenderPath, filePath, content) {
|
|
|
166587
165954
|
renderContent: renderContent,
|
|
166588
165955
|
expandFiles: expandFiles,
|
|
166589
165956
|
validateFeatureArgs: validateFeatureArgs,
|
|
165957
|
+
getPatches: getPatches,
|
|
166590
165958
|
});
|
|
166591
165959
|
|
|
166592
165960
|
;// CONCATENATED MODULE: ../features_preparer/src/logger.ts
|
|
@@ -166611,6 +165979,13 @@ function renderFeature(featureName, version, owner, repo, featureOwner, renderPa
|
|
|
166611
165979
|
function renderFeatureFromPath(extractPath, renderedPath, featureOwner, featureArgs = {}) {
|
|
166612
165980
|
return features_renderer.render(extractPath, renderedPath, featureOwner, {}, featureArgs);
|
|
166613
165981
|
}
|
|
165982
|
+
function getFeaturePatches(featureName, version, owner, repo, featureOwner, featureArgs = {}) {
|
|
165983
|
+
const extractPath = external_path_default().join(catalog_common/* default.features.tarballs.getFeaturesExtractPath */.Z.features.tarballs.getFeaturesExtractPath(featureName, version, owner, repo), 'packages', featureName);
|
|
165984
|
+
return getPatches(extractPath, featureOwner, {}, featureArgs);
|
|
165985
|
+
}
|
|
165986
|
+
function getFeaturePatchesFromPath(extractPath, featureOwner, featureArgs = {}) {
|
|
165987
|
+
return getPatches(extractPath, featureOwner, {}, featureArgs);
|
|
165988
|
+
}
|
|
166614
165989
|
|
|
166615
165990
|
// EXTERNAL MODULE: ../../node_modules/adm-zip/adm-zip.js
|
|
166616
165991
|
var adm_zip = __nccwpck_require__(7993);
|
|
@@ -166671,6 +166046,26 @@ featureArgs = {}, repo = 'features', owner = 'prefapp') {
|
|
|
166671
166046
|
};
|
|
166672
166047
|
return renderFeature(featureName, reference, owner, repo, featureOwner, '/tmp', featureArgs);
|
|
166673
166048
|
}
|
|
166049
|
+
async function installer_getFeaturePatches(featureName, version, featureOwner, featureArgs = {}, repo = 'features', owner = 'prefapp') {
|
|
166050
|
+
const reference = `${featureName}-v${version}`;
|
|
166051
|
+
return processFeaturePatches(featureName, reference, featureOwner, featureArgs, repo, owner);
|
|
166052
|
+
}
|
|
166053
|
+
async function getFeaturePatchesFromRef(featureName, featureRef, featureOwner, featureArgs = {}, repo = 'features', owner = 'prefapp') {
|
|
166054
|
+
const reference = `${featureRef}`;
|
|
166055
|
+
return processFeaturePatches(featureName, reference, featureOwner, featureArgs, repo, owner);
|
|
166056
|
+
}
|
|
166057
|
+
async function processFeaturePatches(featureName, reference, featureOwner, featureArgs = {}, repo = 'features', owner = 'prefapp') {
|
|
166058
|
+
await downloadFeatureZip(repo, featureName, reference, owner);
|
|
166059
|
+
featureArgs['traceability'] = {
|
|
166060
|
+
version: reference,
|
|
166061
|
+
owner,
|
|
166062
|
+
repo,
|
|
166063
|
+
name: featureName,
|
|
166064
|
+
ref: reference,
|
|
166065
|
+
url: `https://github.com/${owner}/${repo}/tree/${reference}/packages/${featureName}`,
|
|
166066
|
+
};
|
|
166067
|
+
return getFeaturePatches(featureName, reference, owner, repo, featureOwner, featureArgs);
|
|
166068
|
+
}
|
|
166674
166069
|
async function prepareFeature(featureName, version, repo = 'features', owner = 'prefapp') {
|
|
166675
166070
|
await downloadFeatureZip(repo, featureName, version, owner);
|
|
166676
166071
|
}
|
|
@@ -166725,6 +166120,9 @@ async function downloadFeatureZip(repo, featureName, reference, owner = 'prefapp
|
|
|
166725
166120
|
/* harmony default export */ const src = ({
|
|
166726
166121
|
renderFeature: renderFeature,
|
|
166727
166122
|
renderFeatureFromPath: renderFeatureFromPath,
|
|
166123
|
+
getFeaturePatches: installer_getFeaturePatches,
|
|
166124
|
+
getFeaturePatchesFromRef: getFeaturePatchesFromRef,
|
|
166125
|
+
getFeaturePatchesFromPath: getFeaturePatchesFromPath,
|
|
166728
166126
|
getFeatureConfigFromRef: getFeatureConfigFromRef,
|
|
166729
166127
|
getFeatureConfig: getFeatureConfig,
|
|
166730
166128
|
prepareFeature: prepareFeature,
|
|
@@ -166741,6 +166139,1074 @@ async function downloadFeatureZip(repo, featureName, reference, owner = 'prefapp
|
|
|
166741
166139
|
getFeatureConfigFromRef: src.getFeatureConfigFromRef,
|
|
166742
166140
|
});
|
|
166743
166141
|
|
|
166142
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/claims/stitching/protectedPaths.ts
|
|
166143
|
+
// Platform-curated protected claim paths — features may not write to these.
|
|
166144
|
+
// Stored as JSON Pointers (RFC 6901). Supports wildcard `*` for a single segment.
|
|
166145
|
+
// Example: /providers/STAR/org matches /providers/github/org where STAR is *.
|
|
166146
|
+
const PROTECTED_CLAIM_PATHS = [
|
|
166147
|
+
'/kind',
|
|
166148
|
+
'/name',
|
|
166149
|
+
'/providers/*/org',
|
|
166150
|
+
'/providers/github/org',
|
|
166151
|
+
'/providers/github/name',
|
|
166152
|
+
'/metadata/name',
|
|
166153
|
+
'/metadata/namespace',
|
|
166154
|
+
];
|
|
166155
|
+
function isProtectedPath(patchPath) {
|
|
166156
|
+
const normalizedPatch = normalizePointer(patchPath);
|
|
166157
|
+
for (const protectedPath of PROTECTED_CLAIM_PATHS) {
|
|
166158
|
+
if (matchesProtected(protectedPath, normalizedPatch)) {
|
|
166159
|
+
return true;
|
|
166160
|
+
}
|
|
166161
|
+
}
|
|
166162
|
+
return false;
|
|
166163
|
+
}
|
|
166164
|
+
function normalizePointer(pointer) {
|
|
166165
|
+
if (!pointer.startsWith('/')) {
|
|
166166
|
+
return '/' + pointer;
|
|
166167
|
+
}
|
|
166168
|
+
return pointer;
|
|
166169
|
+
}
|
|
166170
|
+
function matchesProtected(protectedPointer, patchPointer) {
|
|
166171
|
+
const protectedSegments = protectedPointer
|
|
166172
|
+
.split('/')
|
|
166173
|
+
.slice(1)
|
|
166174
|
+
.map(unescapePointer);
|
|
166175
|
+
const patchSegments = patchPointer.split('/').slice(1).map(unescapePointer);
|
|
166176
|
+
// Treat ancestor/descendant as protected: a patch to a parent (e.g. /metadata)
|
|
166177
|
+
// would replace the protected child (/metadata/name), and a patch to a child
|
|
166178
|
+
// (e.g. /metadata/name/extra) is also under the protected tree. Match when
|
|
166179
|
+
// the shorter prefix equals the longer prefix (with wildcard support).
|
|
166180
|
+
const minLen = Math.min(protectedSegments.length, patchSegments.length);
|
|
166181
|
+
for (let i = 0; i < minLen; i++) {
|
|
166182
|
+
if (protectedSegments[i] === '*')
|
|
166183
|
+
continue;
|
|
166184
|
+
if (protectedSegments[i] !== patchSegments[i])
|
|
166185
|
+
return false;
|
|
166186
|
+
}
|
|
166187
|
+
return true;
|
|
166188
|
+
}
|
|
166189
|
+
function unescapePointer(segment) {
|
|
166190
|
+
return segment.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
166191
|
+
}
|
|
166192
|
+
|
|
166193
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/claims/stitching/errors.ts
|
|
166194
|
+
class StitchingError extends Error {
|
|
166195
|
+
constructor(violations) {
|
|
166196
|
+
const lines = violations.map((v) => ` - ${v.message}`).join('\n');
|
|
166197
|
+
super(`Claim stitching failed with ${violations.length} violation(s):\n${lines}`);
|
|
166198
|
+
this.name = 'StitchingError';
|
|
166199
|
+
this.violations = violations;
|
|
166200
|
+
}
|
|
166201
|
+
}
|
|
166202
|
+
function formatStitchingError(error) {
|
|
166203
|
+
return error.message;
|
|
166204
|
+
}
|
|
166205
|
+
|
|
166206
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/claims/stitching/stitching.ts
|
|
166207
|
+
|
|
166208
|
+
|
|
166209
|
+
|
|
166210
|
+
|
|
166211
|
+
let MOCK_FEATURES_FN;
|
|
166212
|
+
function MOCK_STITCHING_FEATURES(mock) {
|
|
166213
|
+
MOCK_FEATURES_FN = mock;
|
|
166214
|
+
}
|
|
166215
|
+
function pointerExists(doc, pointer) {
|
|
166216
|
+
const segments = pointer
|
|
166217
|
+
.split('/')
|
|
166218
|
+
.slice(1)
|
|
166219
|
+
.map((s) => s.replace(/~1/g, '/').replace(/~0/g, '~'));
|
|
166220
|
+
let cur = doc;
|
|
166221
|
+
for (const seg of segments) {
|
|
166222
|
+
if (cur === null || cur === undefined || typeof cur !== 'object')
|
|
166223
|
+
return false;
|
|
166224
|
+
if (!Object.prototype.hasOwnProperty.call(cur, seg))
|
|
166225
|
+
return false;
|
|
166226
|
+
cur = cur[seg];
|
|
166227
|
+
}
|
|
166228
|
+
return true;
|
|
166229
|
+
}
|
|
166230
|
+
function isAppendPointer(pointer) {
|
|
166231
|
+
return pointer.endsWith('/-');
|
|
166232
|
+
}
|
|
166233
|
+
function isRecord(value) {
|
|
166234
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
166235
|
+
}
|
|
166236
|
+
// Deduplication identity for a feature patch. Ordinary writes collide on the
|
|
166237
|
+
// normalized pointer. Array appends (`add ... /-`) collide on the pointer plus
|
|
166238
|
+
// the appended element's `name` when present, so several features can each add
|
|
166239
|
+
// a distinct label to /providers/github/labels/- while the same label name from
|
|
166240
|
+
// two features still hard-fails.
|
|
166241
|
+
function writeIdentity(patch) {
|
|
166242
|
+
const path = normalizePointer(patch.path);
|
|
166243
|
+
if (patch.op === 'add' &&
|
|
166244
|
+
isAppendPointer(path) &&
|
|
166245
|
+
isRecord(patch.value) &&
|
|
166246
|
+
typeof patch.value.name === 'string') {
|
|
166247
|
+
return `${path}#${patch.value.name}`;
|
|
166248
|
+
}
|
|
166249
|
+
return path;
|
|
166250
|
+
}
|
|
166251
|
+
// fast-json-patch does not create intermediate containers for `add`, and
|
|
166252
|
+
// appending to an array requires the array to already exist. Ensure every
|
|
166253
|
+
// ancestor segment exists before applying an `add`: missing containers are
|
|
166254
|
+
// created as objects, except the immediate parent of a `/-` append, which is
|
|
166255
|
+
// created as an array. Existing (user/default-declared) values are never
|
|
166256
|
+
// overwritten.
|
|
166257
|
+
function ensureAddParents(doc, patch) {
|
|
166258
|
+
const segments = patch.path.split('/').slice(1);
|
|
166259
|
+
let prefix = '';
|
|
166260
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
166261
|
+
prefix += '/' + segments[i];
|
|
166262
|
+
if (pointerExists(doc, prefix))
|
|
166263
|
+
continue;
|
|
166264
|
+
const isArrayParent = isAppendPointer(patch.path) && i === segments.length - 2;
|
|
166265
|
+
const value = isArrayParent ? [] : {};
|
|
166266
|
+
try {
|
|
166267
|
+
doc = fast_json_patch.applyPatch(doc, [{ op: 'add', path: prefix, value }], false, false).newDocument;
|
|
166268
|
+
}
|
|
166269
|
+
catch {
|
|
166270
|
+
// Concurrent structural conflict — let the actual patch surface the error.
|
|
166271
|
+
}
|
|
166272
|
+
}
|
|
166273
|
+
return doc;
|
|
166274
|
+
}
|
|
166275
|
+
async function stitchClaim(claimAfterDefaults, preCollectedEnvelopes) {
|
|
166276
|
+
const envelopes = preCollectedEnvelopes ?? (await collectFeaturePatches(claimAfterDefaults));
|
|
166277
|
+
if (envelopes.length === 0) {
|
|
166278
|
+
return claimAfterDefaults;
|
|
166279
|
+
}
|
|
166280
|
+
const violations = [];
|
|
166281
|
+
const seenPaths = new Map();
|
|
166282
|
+
// Collect all patches for deduplication before any gate — normalize once so all gates and apply use same pointer
|
|
166283
|
+
const normalizedEnvelopes = envelopes.map((env) => ({
|
|
166284
|
+
feature: env.feature,
|
|
166285
|
+
patches: env.patches.map((p) => ({
|
|
166286
|
+
...p,
|
|
166287
|
+
path: normalizePointer(p.path),
|
|
166288
|
+
_raw: p.path,
|
|
166289
|
+
})),
|
|
166290
|
+
}));
|
|
166291
|
+
for (const envelope of normalizedEnvelopes) {
|
|
166292
|
+
for (const patch of envelope.patches) {
|
|
166293
|
+
const path = patch.path;
|
|
166294
|
+
const raw = patch._raw ?? path;
|
|
166295
|
+
// Gate 1: protected path
|
|
166296
|
+
if (isProtectedPath(path)) {
|
|
166297
|
+
violations.push({
|
|
166298
|
+
feature: envelope.feature,
|
|
166299
|
+
op: patch.op,
|
|
166300
|
+
path,
|
|
166301
|
+
reason: 'protected-path',
|
|
166302
|
+
message: `Feature '${envelope.feature}' patch ${patch.op} ${raw} (normalized ${path}) targets protected claim path`,
|
|
166303
|
+
});
|
|
166304
|
+
// continue to collect other violations for same patch (but avoid duplicate counting)
|
|
166305
|
+
}
|
|
166306
|
+
// Gate 3: deduplication — track before overwrite so we report both.
|
|
166307
|
+
// Array appends (`/-`) dedup by element name (see writeIdentity); all
|
|
166308
|
+
// other writes dedup by normalized pointer.
|
|
166309
|
+
const identity = writeIdentity(patch);
|
|
166310
|
+
if (seenPaths.has(identity)) {
|
|
166311
|
+
violations.push({
|
|
166312
|
+
feature: envelope.feature,
|
|
166313
|
+
op: patch.op,
|
|
166314
|
+
path,
|
|
166315
|
+
reason: 'duplicate-path',
|
|
166316
|
+
conflictingFeature: seenPaths.get(identity),
|
|
166317
|
+
message: `Feature '${envelope.feature}' and '${seenPaths.get(identity)}' both write to ${path} (deduplication)`,
|
|
166318
|
+
});
|
|
166319
|
+
}
|
|
166320
|
+
else {
|
|
166321
|
+
seenPaths.set(identity, envelope.feature);
|
|
166322
|
+
}
|
|
166323
|
+
// Gate 2: overwrite protection (II-a strict: raw ∪ defaults counts as declared)
|
|
166324
|
+
if (['replace', 'remove', 'add'].includes(patch.op)) {
|
|
166325
|
+
const exists = pointerExists(claimAfterDefaults, path);
|
|
166326
|
+
if (exists) {
|
|
166327
|
+
// For strict II-a, any op to existing path is overwrite
|
|
166328
|
+
// We already reported protected if applicable; still report overwrite unless it was protected
|
|
166329
|
+
// to keep collect-all but avoid double-counting same patch as two reasons? Keep both for visibility.
|
|
166330
|
+
if (!isProtectedPath(path)) {
|
|
166331
|
+
violations.push({
|
|
166332
|
+
feature: envelope.feature,
|
|
166333
|
+
op: patch.op,
|
|
166334
|
+
path,
|
|
166335
|
+
reason: 'overwrite-protected',
|
|
166336
|
+
message: `Feature '${envelope.feature}' patch ${patch.op} ${raw} (normalized ${path}) would overwrite user/default-declared value`,
|
|
166337
|
+
});
|
|
166338
|
+
}
|
|
166339
|
+
}
|
|
166340
|
+
else {
|
|
166341
|
+
// Path absent — check intermediate parent existence? For now exact path only.
|
|
166342
|
+
// If patch is `replace` to absent path, fast-json-patch will fail; we let that be an overwrite concern too.
|
|
166343
|
+
if (['replace', 'remove'].includes(patch.op)) {
|
|
166344
|
+
violations.push({
|
|
166345
|
+
feature: envelope.feature,
|
|
166346
|
+
op: patch.op,
|
|
166347
|
+
path,
|
|
166348
|
+
reason: 'overwrite-protected',
|
|
166349
|
+
message: `Feature '${envelope.feature}' patch ${patch.op} ${raw} (normalized ${path}) targets absent path (replace/remove requires existing value)`,
|
|
166350
|
+
});
|
|
166351
|
+
}
|
|
166352
|
+
}
|
|
166353
|
+
}
|
|
166354
|
+
}
|
|
166355
|
+
}
|
|
166356
|
+
if (violations.length > 0) {
|
|
166357
|
+
throw new StitchingError(violations);
|
|
166358
|
+
}
|
|
166359
|
+
// No violations — apply patches sequentially (deduplication already ensures no conflicts)
|
|
166360
|
+
let stitched = JSON.parse(JSON.stringify(claimAfterDefaults));
|
|
166361
|
+
for (const envelope of normalizedEnvelopes) {
|
|
166362
|
+
if (envelope.patches.length === 0)
|
|
166363
|
+
continue;
|
|
166364
|
+
for (const patch of envelope.patches) {
|
|
166365
|
+
if (patch.op === 'add') {
|
|
166366
|
+
stitched = ensureAddParents(stitched, patch);
|
|
166367
|
+
}
|
|
166368
|
+
}
|
|
166369
|
+
const result = fast_json_patch.applyPatch(stitched, envelope.patches, false, false);
|
|
166370
|
+
stitched = result.newDocument;
|
|
166371
|
+
}
|
|
166372
|
+
return stitched;
|
|
166373
|
+
}
|
|
166374
|
+
async function collectFeaturePatches(claim) {
|
|
166375
|
+
if (MOCK_FEATURES_FN) {
|
|
166376
|
+
return MOCK_FEATURES_FN(claim);
|
|
166377
|
+
}
|
|
166378
|
+
const typedClaim = claim;
|
|
166379
|
+
const features = typedClaim.providers?.github?.features ?? [];
|
|
166380
|
+
if (features.length === 0)
|
|
166381
|
+
return [];
|
|
166382
|
+
// In unit tests without GitHub credentials, avoid real download — tests that care
|
|
166383
|
+
// about stitching should set MOCK_STITCHING_FEATURES explicitly.
|
|
166384
|
+
if (process.env.JEST_WORKER_ID && !process.env.GITHUB_TOKEN) {
|
|
166385
|
+
return [];
|
|
166386
|
+
}
|
|
166387
|
+
const envelopes = [];
|
|
166388
|
+
for (const feature of features) {
|
|
166389
|
+
const featureName = feature.name;
|
|
166390
|
+
const versionOrRef = feature.ref ?? feature.version ?? '';
|
|
166391
|
+
const repo = feature.repo
|
|
166392
|
+
? (feature.repo.split('/')[1] ?? 'features')
|
|
166393
|
+
: 'features';
|
|
166394
|
+
const owner = feature.repo
|
|
166395
|
+
? (feature.repo.split('/')[0] ?? 'prefapp')
|
|
166396
|
+
: 'prefapp';
|
|
166397
|
+
const args = feature.args ?? {};
|
|
166398
|
+
try {
|
|
166399
|
+
let patchesOrRendered;
|
|
166400
|
+
const preparerAny = features_preparer;
|
|
166401
|
+
if (feature.ref) {
|
|
166402
|
+
if (typeof preparerAny.getFeaturePatchesFromRef === 'function') {
|
|
166403
|
+
patchesOrRendered = await preparerAny.getFeaturePatchesFromRef(featureName, versionOrRef, claim, args, repo, owner);
|
|
166404
|
+
}
|
|
166405
|
+
else {
|
|
166406
|
+
patchesOrRendered = await preparerAny.getFeatureConfigFromRef(featureName, versionOrRef, claim, args, repo, owner);
|
|
166407
|
+
}
|
|
166408
|
+
}
|
|
166409
|
+
else {
|
|
166410
|
+
if (typeof preparerAny.getFeaturePatches === 'function') {
|
|
166411
|
+
patchesOrRendered = await preparerAny.getFeaturePatches(featureName, versionOrRef, claim, args, repo, owner);
|
|
166412
|
+
}
|
|
166413
|
+
else {
|
|
166414
|
+
patchesOrRendered = await preparerAny.getFeatureConfig(featureName, versionOrRef, claim, args, repo, owner);
|
|
166415
|
+
}
|
|
166416
|
+
}
|
|
166417
|
+
const patches = Array.isArray(patchesOrRendered)
|
|
166418
|
+
? patchesOrRendered
|
|
166419
|
+
: extractClaimPatches(patchesOrRendered);
|
|
166420
|
+
envelopes.push({ feature: featureName, patches });
|
|
166421
|
+
}
|
|
166422
|
+
catch (err) {
|
|
166423
|
+
throw new Error(`Failed to collect patches for feature '${featureName}': ${err instanceof Error ? err.message : String(err)}`);
|
|
166424
|
+
}
|
|
166425
|
+
}
|
|
166426
|
+
return envelopes;
|
|
166427
|
+
}
|
|
166428
|
+
function extractClaimPatches(rendered) {
|
|
166429
|
+
const patches = rendered.patches;
|
|
166430
|
+
if (!patches)
|
|
166431
|
+
return [];
|
|
166432
|
+
if (Array.isArray(patches))
|
|
166433
|
+
return patches;
|
|
166434
|
+
throw new Error(`Feature patches must be a flat array (claim-relative pointers like /annotations/...), got ${typeof patches}: ${JSON.stringify(patches).slice(0, 200)}. See #2648`);
|
|
166435
|
+
}
|
|
166436
|
+
|
|
166437
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/lazy_loader.ts
|
|
166438
|
+
|
|
166439
|
+
|
|
166440
|
+
|
|
166441
|
+
|
|
166442
|
+
|
|
166443
|
+
|
|
166444
|
+
|
|
166445
|
+
|
|
166446
|
+
|
|
166447
|
+
|
|
166448
|
+
|
|
166449
|
+
|
|
166450
|
+
|
|
166451
|
+
|
|
166452
|
+
|
|
166453
|
+
|
|
166454
|
+
|
|
166455
|
+
// We need to ensure the grep command is a gnu version
|
|
166456
|
+
let IS_GNU_GREP = false;
|
|
166457
|
+
let GREP_ON_CHECK = false;
|
|
166458
|
+
// this loop is for avoid race conditions
|
|
166459
|
+
// once a check is running no more checks
|
|
166460
|
+
async function waitForCheck() {
|
|
166461
|
+
const f_wait = () => new Promise((timeOut) => setTimeout(timeOut, 10));
|
|
166462
|
+
do {
|
|
166463
|
+
await f_wait();
|
|
166464
|
+
} while (GREP_ON_CHECK);
|
|
166465
|
+
}
|
|
166466
|
+
function checkGrep() {
|
|
166467
|
+
return new Promise((ok, ko) => {
|
|
166468
|
+
// idempotency: already checked
|
|
166469
|
+
if (IS_GNU_GREP)
|
|
166470
|
+
return ok();
|
|
166471
|
+
// a check is already running no new checks
|
|
166472
|
+
if (GREP_ON_CHECK)
|
|
166473
|
+
return waitForCheck();
|
|
166474
|
+
logger.info('Checking the grep command');
|
|
166475
|
+
GREP_ON_CHECK = true;
|
|
166476
|
+
const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['--version']);
|
|
166477
|
+
handler.on('close', (code) => {
|
|
166478
|
+
GREP_ON_CHECK = false;
|
|
166479
|
+
if (code === 0) {
|
|
166480
|
+
logger.debug('Grep is a gnu grep');
|
|
166481
|
+
IS_GNU_GREP = true;
|
|
166482
|
+
ok();
|
|
166483
|
+
}
|
|
166484
|
+
else {
|
|
166485
|
+
ko('Lazy evaluation needs a gnu-grep command');
|
|
166486
|
+
}
|
|
166487
|
+
});
|
|
166488
|
+
});
|
|
166489
|
+
}
|
|
166490
|
+
async function loadClaim(claimRef, org, defaults = loadClaimDefaults(), patchClaim = loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, existingRefs = {}, postValidations = new Map()) {
|
|
166491
|
+
await checkGrep();
|
|
166492
|
+
let result = existingRefs;
|
|
166493
|
+
logger.info(`Load reference ${claimRef}`);
|
|
166494
|
+
initVirtualClaims(org);
|
|
166495
|
+
logger.info(`Load reference (parts) ${claimRef.split(/-/)[0]} ${claimRef.replace(/^[^-]+-/, '')}`);
|
|
166496
|
+
// cargas datos con grep
|
|
166497
|
+
try {
|
|
166498
|
+
const claimData = await lazyGetClaim(claimRef.split(/-/)[0], claimRef.replace(/^[^-]+-/, ''), org, cwd);
|
|
166499
|
+
let claim = patchClaim(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(claimData), defaults);
|
|
166500
|
+
// Claim stitching: feature claim-patches with three gates before AJV
|
|
166501
|
+
try {
|
|
166502
|
+
claim = await stitchClaim(claim);
|
|
166503
|
+
}
|
|
166504
|
+
catch (e) {
|
|
166505
|
+
throw new Error(`Error when stitching claim ${claimRef}: ${e instanceof Error ? e.message : String(e)}`);
|
|
166506
|
+
}
|
|
166507
|
+
let variants = [];
|
|
166508
|
+
if (claim.kind === 'TFWorkspaceClaim' &&
|
|
166509
|
+
claim.providers?.terraform?.variants) {
|
|
166510
|
+
variants = claim.providers.terraform.variants;
|
|
166511
|
+
delete claim.providers.terraform.variants;
|
|
166512
|
+
}
|
|
166513
|
+
logger.silly(`Patched claim is:
|
|
166514
|
+
---
|
|
166515
|
+
${catalog_common/* default.io.toYaml */.Z.io.toYaml(claim)}`);
|
|
166516
|
+
try {
|
|
166517
|
+
validateClaim(claim, base[`${claim.kind}Schema`]);
|
|
166518
|
+
await optionalValidation(claim);
|
|
166519
|
+
}
|
|
166520
|
+
catch (error) {
|
|
166521
|
+
let errorMsg = '';
|
|
166522
|
+
if (Array.isArray(error)) {
|
|
166523
|
+
for (const data of error) {
|
|
166524
|
+
errorMsg = `${errorMsg}
|
|
166525
|
+
- ${data.instancePath}: ${data.message}`;
|
|
166526
|
+
}
|
|
166527
|
+
}
|
|
166528
|
+
else {
|
|
166529
|
+
errorMsg = error instanceof Error ? error.message : String(error);
|
|
166530
|
+
}
|
|
166531
|
+
throw new Error(`Error when validating claim ${claimRef}: ${errorMsg}`);
|
|
166532
|
+
}
|
|
166533
|
+
result[claimRef] = {};
|
|
166534
|
+
result[claimRef]['claim'] = claim;
|
|
166535
|
+
result[claimRef]['claimPath'] = VisitedClaims[claimRef];
|
|
166536
|
+
if (VisitedClaims[claimRef] === 'virtual') {
|
|
166537
|
+
result = await setVirtualClaimAdditionalData(result, claim, claimRef);
|
|
166538
|
+
}
|
|
166539
|
+
else {
|
|
166540
|
+
result = await setNonVirtualClaimAdditionalData(result, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
|
|
166541
|
+
}
|
|
166542
|
+
const claimKind = claim.kind;
|
|
166543
|
+
const references = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(claim));
|
|
166544
|
+
for (const ref of references) {
|
|
166545
|
+
if (!result[ref]) {
|
|
166546
|
+
const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
|
|
166547
|
+
result = lodash_default().merge(result, resolvedReferences);
|
|
166548
|
+
}
|
|
166549
|
+
}
|
|
166550
|
+
if (variants.length > 0) {
|
|
166551
|
+
const parentClaimPath = VisitedClaims[claimRef];
|
|
166552
|
+
for (const variant of variants) {
|
|
166553
|
+
if (!variant.name || !variant.overrides) {
|
|
166554
|
+
throw new Error(`Variant in claim ${claimRef} is missing required field 'name' or 'overrides'`);
|
|
166555
|
+
}
|
|
166556
|
+
const prohibitedOverrideFields = ['source', 'module', 'name'];
|
|
166557
|
+
for (const field of prohibitedOverrideFields) {
|
|
166558
|
+
if (field in variant.overrides) {
|
|
166559
|
+
throw new Error(`Variant '${variant.name}' in claim ${claimRef} cannot override '${field}'`);
|
|
166560
|
+
}
|
|
166561
|
+
}
|
|
166562
|
+
const composedName = claim.providers.terraform.name + '-' + variant.name;
|
|
166563
|
+
const variantClaim = lodash_default().cloneDeep(claim);
|
|
166564
|
+
variantClaim._parentClaimName = claim.name;
|
|
166565
|
+
variantClaim.name = composedName;
|
|
166566
|
+
variantClaim.providers.terraform = lodash_default().merge({}, claim.providers.terraform, variant.overrides);
|
|
166567
|
+
variantClaim.providers.terraform.name = composedName;
|
|
166568
|
+
if (!variantClaim.annotations) {
|
|
166569
|
+
variantClaim.annotations = {};
|
|
166570
|
+
}
|
|
166571
|
+
variantClaim.annotations['firestartr.dev/variant-of'] =
|
|
166572
|
+
claim.providers.terraform.name;
|
|
166573
|
+
const variantRef = `TFWorkspaceClaim-${composedName}`;
|
|
166574
|
+
if (result[variantRef]) {
|
|
166575
|
+
throw new Error(`Variant name '${variant.name}' (composed: '${composedName}') from claim '${claimRef}' conflicts with existing claim '${variantRef}'`);
|
|
166576
|
+
}
|
|
166577
|
+
logger.info(`Creating synthetic variant claim ${variantRef}`);
|
|
166578
|
+
result[variantRef] = {};
|
|
166579
|
+
result[variantRef]['claim'] = variantClaim;
|
|
166580
|
+
result[variantRef]['claimPath'] = parentClaimPath;
|
|
166581
|
+
result = await setNonVirtualClaimAdditionalData(result, variantClaim, variantRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
|
|
166582
|
+
const variantReferences = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(variantClaim));
|
|
166583
|
+
for (const ref of variantReferences) {
|
|
166584
|
+
if (!result[ref]) {
|
|
166585
|
+
const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
|
|
166586
|
+
result = lodash_default().merge(result, resolvedReferences);
|
|
166587
|
+
}
|
|
166588
|
+
}
|
|
166589
|
+
}
|
|
166590
|
+
}
|
|
166591
|
+
}
|
|
166592
|
+
catch (err) {
|
|
166593
|
+
throw `Lazy Loading: ${err}`;
|
|
166594
|
+
}
|
|
166595
|
+
return [result, postValidations];
|
|
166596
|
+
}
|
|
166597
|
+
let LoadedClaims = {};
|
|
166598
|
+
let VisitedClaims = {};
|
|
166599
|
+
let DuplicatedClaims = {};
|
|
166600
|
+
function resetLazyLoader() {
|
|
166601
|
+
LoadedClaims = {};
|
|
166602
|
+
VisitedClaims = {};
|
|
166603
|
+
DuplicatedClaims = {};
|
|
166604
|
+
}
|
|
166605
|
+
async function lazyGetClaim(kind, name, org, cwd) {
|
|
166606
|
+
const indice = `${kind}-${name}`;
|
|
166607
|
+
logger.info(`Lazy loading ${kind}-${name} with index ${indice}`);
|
|
166608
|
+
if (indice in LoadedClaims)
|
|
166609
|
+
return LoadedClaims[indice];
|
|
166610
|
+
if (isVirtualClaim(kind, name)) {
|
|
166611
|
+
await loadVirtualClaim(kind, name, org);
|
|
166612
|
+
}
|
|
166613
|
+
else {
|
|
166614
|
+
await getClaimsByName(name, cwd);
|
|
166615
|
+
}
|
|
166616
|
+
if (indice in LoadedClaims) {
|
|
166617
|
+
return LoadedClaims[indice];
|
|
166618
|
+
}
|
|
166619
|
+
else {
|
|
166620
|
+
throw new Error(`Error: ${kind}-${name} not found`);
|
|
166621
|
+
}
|
|
166622
|
+
}
|
|
166623
|
+
async function getClaimsByName(name, cwd = '.') {
|
|
166624
|
+
return new Promise((ok, ko) => {
|
|
166625
|
+
const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['-r', '-l', '--include=*', '-E', `name: "?${name}"?`, '.'], {
|
|
166626
|
+
cwd: cwd,
|
|
166627
|
+
});
|
|
166628
|
+
logger.info(`Running ${['grep', '-r', '-l', '--include', '-E', 'name: "' + name + '"?', '.'].join(' ')}`);
|
|
166629
|
+
const entradas = [];
|
|
166630
|
+
const chunks = [];
|
|
166631
|
+
handler.stdout.on('data', (data) => {
|
|
166632
|
+
chunks.push(data.toString('utf-8'));
|
|
166633
|
+
});
|
|
166634
|
+
handler.on('close', () => {
|
|
166635
|
+
const dataFinal = chunks.join('');
|
|
166636
|
+
const fileNameList = dataFinal.split(/\n/).filter((line) => line !== '');
|
|
166637
|
+
for (const fileName of fileNameList) {
|
|
166638
|
+
// only yaml files
|
|
166639
|
+
if (!fileName.match(/\.yml$|\.yaml$/)) {
|
|
166640
|
+
continue;
|
|
166641
|
+
}
|
|
166642
|
+
// only entries not already visited
|
|
166643
|
+
if (Object.values(VisitedClaims).includes(fileName)) {
|
|
166644
|
+
continue;
|
|
166645
|
+
}
|
|
166646
|
+
entradas.push(external_path_.join(cwd, fileName));
|
|
166647
|
+
}
|
|
166648
|
+
return Promise.all(entradas.map((entrada) => {
|
|
166649
|
+
return loadRawClaim(entrada);
|
|
166650
|
+
}))
|
|
166651
|
+
.then(() => {
|
|
166652
|
+
ok();
|
|
166653
|
+
})
|
|
166654
|
+
.catch((err) => {
|
|
166655
|
+
ko(err);
|
|
166656
|
+
});
|
|
166657
|
+
});
|
|
166658
|
+
});
|
|
166659
|
+
}
|
|
166660
|
+
async function loadRawClaim(entry) {
|
|
166661
|
+
return new Promise((ok, ko) => {
|
|
166662
|
+
external_fs_.readFile(entry, 'utf-8', (error, data) => {
|
|
166663
|
+
if (error)
|
|
166664
|
+
return ko(`Reading ${entry}: ${error}`);
|
|
166665
|
+
const claim = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
|
|
166666
|
+
if (!('kind' in claim && 'name' in claim)) {
|
|
166667
|
+
logger.warn(`Invalid claim file ${entry}`);
|
|
166668
|
+
}
|
|
166669
|
+
else {
|
|
166670
|
+
const claimKey = `${claim.kind}-${claim.name}`;
|
|
166671
|
+
if (Object.keys(DuplicatedClaims).includes(claimKey) &&
|
|
166672
|
+
DuplicatedClaims[claimKey] !== entry) {
|
|
166673
|
+
return ko(`Duplicated claim ${claimKey} found files: ${DuplicatedClaims[claimKey]} and ${entry}`);
|
|
166674
|
+
}
|
|
166675
|
+
LoadedClaims[claimKey] = data;
|
|
166676
|
+
VisitedClaims[claimKey] = entry;
|
|
166677
|
+
DuplicatedClaims[claimKey] = entry;
|
|
166678
|
+
ok();
|
|
166679
|
+
}
|
|
166680
|
+
});
|
|
166681
|
+
});
|
|
166682
|
+
}
|
|
166683
|
+
async function setVirtualClaimAdditionalData(renderedData, claim, claimRef) {
|
|
166684
|
+
const virtualClaim = getVirtualClaim(claim.kind, claim.name);
|
|
166685
|
+
renderedData[claimRef]['initializers'] = [
|
|
166686
|
+
new UUIDInitializer(claim),
|
|
166687
|
+
new InitializerClaimRef(),
|
|
166688
|
+
new InitializerDefault(virtualClaim.getDefaultConfig()),
|
|
166689
|
+
];
|
|
166690
|
+
renderedData[claimRef]['globals'] = [];
|
|
166691
|
+
renderedData[claimRef]['overrides'] = [];
|
|
166692
|
+
renderedData[claimRef]['normalizers'] = [new NameNormalizer()];
|
|
166693
|
+
return renderedData;
|
|
166694
|
+
}
|
|
166695
|
+
async function setNonVirtualClaimAdditionalData(renderedData, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers) {
|
|
166696
|
+
renderedData[claimRef]['initializers'] = await loadInitializers(claim, renderedData[claimRef]['claimPath']);
|
|
166697
|
+
renderedData[claimRef]['globals'] = await loadGlobals(claim);
|
|
166698
|
+
renderedData[claimRef]['overrides'] = loadOverrides(claim);
|
|
166699
|
+
renderedData[claimRef]['normalizers'] = await loadNormalizers(claim, renderedData[claimRef]['claimPath']);
|
|
166700
|
+
return renderedData;
|
|
166701
|
+
}
|
|
166702
|
+
async function loadVirtualClaim(kind, name, org) {
|
|
166703
|
+
const virtualClaim = getVirtualClaim(kind, name);
|
|
166704
|
+
const expandedClaim = await virtualClaim.expand({ org });
|
|
166705
|
+
logger.info(`Loading virtual claim ${kind} ${name} ${org}`);
|
|
166706
|
+
LoadedClaims[`${kind}-${name}`] = catalog_common/* default.io.toYaml */.Z.io.toYaml(expandedClaim);
|
|
166707
|
+
VisitedClaims[`${kind}-${name}`] = 'virtual';
|
|
166708
|
+
}
|
|
166709
|
+
|
|
166710
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/claimsDefaulter.ts
|
|
166711
|
+
|
|
166712
|
+
|
|
166713
|
+
|
|
166714
|
+
/*
|
|
166715
|
+
* Default blocks are objects that cannot be merged but applied as a whole. Meaning:
|
|
166716
|
+
* - If the object is defined at the claim-level it is maintained *AS IT IS* (no merge)
|
|
166717
|
+
* - If the block is missing at the claim-level, the default block is applied
|
|
166718
|
+
*/
|
|
166719
|
+
const defaultBlocksPaths = ['/providers/terraform/sync'];
|
|
166720
|
+
function applyBlockAwareDefaults(claim, defaultClaim) {
|
|
166721
|
+
// we always work with a clone of the original
|
|
166722
|
+
const claimClone = JSON.parse(JSON.stringify(claim));
|
|
166723
|
+
// if the block is claim-level defined we store it here
|
|
166724
|
+
const defaultBlocks = new Map();
|
|
166725
|
+
// we remove the blocks entirely of the claim
|
|
166726
|
+
// to achieve an add copy
|
|
166727
|
+
for (const defaultBlockPath of defaultBlocksPaths) {
|
|
166728
|
+
if (claimsDefaulter_hasDeepPath(claimClone, defaultBlockPath) !== true)
|
|
166729
|
+
continue;
|
|
166730
|
+
const originalValue = fast_json_patch_default().getValueByPointer(claimClone, defaultBlockPath);
|
|
166731
|
+
if (originalValue) {
|
|
166732
|
+
logger.silly(`${claim.kind}/${claim.name}: has an original ${defaultBlockPath}: preserving`);
|
|
166733
|
+
defaultBlocks.set(defaultBlockPath, originalValue);
|
|
166734
|
+
fast_json_patch_default().applyPatch(claimClone, [{ op: 'remove', path: defaultBlockPath }]);
|
|
166735
|
+
}
|
|
166736
|
+
}
|
|
166737
|
+
// if the patch has the same path of a block
|
|
166738
|
+
// and the block was defined at claim-level
|
|
166739
|
+
// we interchange the value with the original value
|
|
166740
|
+
// otherwise we use the default
|
|
166741
|
+
const jsonPatchOps = fast_json_patch_default().compare(claimClone, defaultClaim)
|
|
166742
|
+
.filter((jp) => jp.op === 'add')
|
|
166743
|
+
.map((jp) => {
|
|
166744
|
+
if (defaultBlocks.has(jp.path)) {
|
|
166745
|
+
return {
|
|
166746
|
+
...jp,
|
|
166747
|
+
value: defaultBlocks.get(jp.path),
|
|
166748
|
+
};
|
|
166749
|
+
}
|
|
166750
|
+
else {
|
|
166751
|
+
return jp;
|
|
166752
|
+
}
|
|
166753
|
+
});
|
|
166754
|
+
return fast_json_patch_default().applyPatch(claimClone, jsonPatchOps).newDocument;
|
|
166755
|
+
}
|
|
166756
|
+
function claimsDefaulter_hasDeepPath(data, deepPath) {
|
|
166757
|
+
return lodash_default().has(data, deepPath.replace(/\//g, '.').replace(/^\./, ''));
|
|
166758
|
+
}
|
|
166759
|
+
|
|
166760
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/loader.ts
|
|
166761
|
+
|
|
166762
|
+
|
|
166763
|
+
|
|
166764
|
+
|
|
166765
|
+
|
|
166766
|
+
|
|
166767
|
+
|
|
166768
|
+
|
|
166769
|
+
|
|
166770
|
+
|
|
166771
|
+
|
|
166772
|
+
|
|
166773
|
+
|
|
166774
|
+
|
|
166775
|
+
|
|
166776
|
+
const isYamlFile = new RegExp(/\.(yaml|yml)$/);
|
|
166777
|
+
/**
|
|
166778
|
+
*
|
|
166779
|
+
* @returns Virtual Claims
|
|
166780
|
+
*/
|
|
166781
|
+
const virtualClaims = [new FirestartrAllClaim()];
|
|
166782
|
+
/*
|
|
166783
|
+
* Loads all applicable globals for a given claim and stores them into a list.
|
|
166784
|
+
*
|
|
166785
|
+
* Input:
|
|
166786
|
+
* - claim: our custom claim object, with which we check if the global is applicable
|
|
166787
|
+
*
|
|
166788
|
+
* Returns:
|
|
166789
|
+
* - A GlobalSection array promise, containing all the globals loaded for this claim
|
|
166790
|
+
*
|
|
166791
|
+
*/
|
|
166792
|
+
async function loadGlobals(claim) {
|
|
166793
|
+
const result = [];
|
|
166794
|
+
await crawl(getPath('globals'), (entry) => {
|
|
166795
|
+
return isYamlFile.test(entry);
|
|
166796
|
+
}, async (entry, data) => {
|
|
166797
|
+
const globalData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
|
|
166798
|
+
const ext = external_path_.extname(entry);
|
|
166799
|
+
const name = external_path_.basename(entry, ext);
|
|
166800
|
+
if (name in SECTIONS_BY_FILE_NAME) {
|
|
166801
|
+
const section = new SECTIONS_BY_FILE_NAME[name](globalData);
|
|
166802
|
+
if (!(await section.validate(SCHEMAS_BY_SECTION_NAME[name] || {}))) {
|
|
166803
|
+
throw new Error(`Invalid ${name} global file`);
|
|
166804
|
+
}
|
|
166805
|
+
if (globalData.kind === claim.kind) {
|
|
166806
|
+
result.push(section);
|
|
166807
|
+
}
|
|
166808
|
+
else {
|
|
166809
|
+
logger.debug(`Skipping global ${name} because it is not applicable to ${claim.kind}`);
|
|
166810
|
+
}
|
|
166811
|
+
}
|
|
166812
|
+
});
|
|
166813
|
+
logger.info(`Loaded globals ${result}`);
|
|
166814
|
+
return result;
|
|
166815
|
+
}
|
|
166816
|
+
/*
|
|
166817
|
+
* If the input claim is a GithubRepositoryClaim, it loads all it's applicable
|
|
166818
|
+
* overrides and stores them into a list. Otherwise, it returns an empty list.
|
|
166819
|
+
*
|
|
166820
|
+
* Input:
|
|
166821
|
+
* - claim: our custom claim object, which should be a GithubRepositoryClaim
|
|
166822
|
+
*
|
|
166823
|
+
* Returns:
|
|
166824
|
+
* - An Overrider array, with a GithubRepositoryOverrider if the claim
|
|
166825
|
+
* was a GithubRepositoryClaim, or empty if it was not.
|
|
166826
|
+
*
|
|
166827
|
+
*/
|
|
166828
|
+
function loadOverrides(claim) {
|
|
166829
|
+
const overrides = [];
|
|
166830
|
+
if (claim.kind === 'ComponentClaim' && claim.providers.github.overrides) {
|
|
166831
|
+
overrides.push(new GithubRepositoryOverrider());
|
|
166832
|
+
}
|
|
166833
|
+
return overrides;
|
|
166834
|
+
}
|
|
166835
|
+
/**
|
|
166836
|
+
* Load all normalizers and stores them into a list.
|
|
166837
|
+
* @param claim
|
|
166838
|
+
* @returns
|
|
166839
|
+
*/
|
|
166840
|
+
async function loadNormalizers(_claim, path) {
|
|
166841
|
+
const result = [];
|
|
166842
|
+
for (const normalizer of NORMALIZERS) {
|
|
166843
|
+
result.push(new normalizer({ path: path }));
|
|
166844
|
+
}
|
|
166845
|
+
return result;
|
|
166846
|
+
}
|
|
166847
|
+
/*
|
|
166848
|
+
* Loads all applicable initializers for a given claim and stores them into a list.
|
|
166849
|
+
*
|
|
166850
|
+
* Input:
|
|
166851
|
+
* - claim: our custom claim object, with which we check if the initializer is applicable
|
|
166852
|
+
*
|
|
166853
|
+
* Returns:
|
|
166854
|
+
* - An Initializer array promise, containing all the initializers loaded for this claim
|
|
166855
|
+
*
|
|
166856
|
+
*/
|
|
166857
|
+
let loadedInitializers = false;
|
|
166858
|
+
async function loadInitializers(claim, claimPath, initializersPath = getPath('initializers')) {
|
|
166859
|
+
const result = [];
|
|
166860
|
+
await crawl(initializersPath, (entry) => {
|
|
166861
|
+
return isYamlFile.test(entry);
|
|
166862
|
+
}, async (entry, data) => {
|
|
166863
|
+
const initializerData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
|
|
166864
|
+
const ext = external_path_.extname(entry);
|
|
166865
|
+
const name = external_path_.basename(entry, ext);
|
|
166866
|
+
if (name in INITIALIZERS_BY_FILE_NAME) {
|
|
166867
|
+
const initializerBfN = new INITIALIZERS_BY_FILE_NAME[name](initializerData);
|
|
166868
|
+
if (!(await initializerBfN.validate(SCHEMAS_BY_INITIALIZER_NAME[name] || {}))) {
|
|
166869
|
+
throw new Error(`Invalid ${name} initializer file`);
|
|
166870
|
+
}
|
|
166871
|
+
if (initializerData.kind === claim.kind) {
|
|
166872
|
+
result.push(initializerBfN);
|
|
166873
|
+
}
|
|
166874
|
+
else {
|
|
166875
|
+
logger.debug(`Skipping initializer ${name} because it is not applicable to ${claim.kind}`);
|
|
166876
|
+
}
|
|
166877
|
+
}
|
|
166878
|
+
});
|
|
166879
|
+
for (const initializer of INITIALIZERS) {
|
|
166880
|
+
if (initializer.applicableKinds.includes(claim.kind)) {
|
|
166881
|
+
result.push(new initializer({ path: claimPath }));
|
|
166882
|
+
}
|
|
166883
|
+
}
|
|
166884
|
+
logger.info(`Loaded initializers ${JSON.stringify(result)}`);
|
|
166885
|
+
loadedInitializers = result;
|
|
166886
|
+
return loadedInitializers;
|
|
166887
|
+
}
|
|
166888
|
+
function loadClaimDefaults() {
|
|
166889
|
+
try {
|
|
166890
|
+
return catalog_common/* default.io.fromYaml */.Z.io.fromYaml(external_fs_.readFileSync(`${getPath('claimsDefaults')}/claims_defaults.yaml`, 'utf-8'));
|
|
166891
|
+
}
|
|
166892
|
+
catch (error) {
|
|
166893
|
+
const errMsg = `Could not read claims defaults file in path ${getPath('claimsDefaults')}/claims_defaults.yaml: ${error}`;
|
|
166894
|
+
logger.error(errMsg);
|
|
166895
|
+
throw new Error(errMsg);
|
|
166896
|
+
}
|
|
166897
|
+
}
|
|
166898
|
+
/*
|
|
166899
|
+
* Using fast-json-patch, compares a claim to its kind's defaults, then patches it.
|
|
166900
|
+
*
|
|
166901
|
+
* Input:
|
|
166902
|
+
* - claim: our custom claim object, which we want to patch
|
|
166903
|
+
* - defaultsClaims: an object, containing the defaults for each claim kind,
|
|
166904
|
+
* with the same structure that we use for the actual claims
|
|
166905
|
+
*
|
|
166906
|
+
* Returns:
|
|
166907
|
+
* - The patched claim
|
|
166908
|
+
*
|
|
166909
|
+
*/
|
|
166910
|
+
function loader_patchClaim(claim, defaultsClaims) {
|
|
166911
|
+
if (defaultsClaims[claim.kind]) {
|
|
166912
|
+
claim = applyBlockAwareDefaults(claim, defaultsClaims[claim.kind]);
|
|
166913
|
+
}
|
|
166914
|
+
return claim;
|
|
166915
|
+
}
|
|
166916
|
+
async function loadCRsWithFullSet(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
|
|
166917
|
+
const result = {};
|
|
166918
|
+
const fullResult = {};
|
|
166919
|
+
await crawlWithExclusions(crsPath, (entry) => {
|
|
166920
|
+
return isYamlFile.test(entry);
|
|
166921
|
+
}, async (entry, data) => {
|
|
166922
|
+
const yamlData = stripKnownRelations(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data));
|
|
166923
|
+
const metadata = yamlData?.metadata;
|
|
166924
|
+
if (!(yamlData &&
|
|
166925
|
+
typeof yamlData === 'object' &&
|
|
166926
|
+
'kind' in yamlData &&
|
|
166927
|
+
metadata &&
|
|
166928
|
+
typeof metadata === 'object' &&
|
|
166929
|
+
'name' in metadata)) {
|
|
166930
|
+
logger.warn(`Invalid CR file ${entry}`);
|
|
166931
|
+
}
|
|
166932
|
+
else {
|
|
166933
|
+
const crKey = `${yamlData.kind}-${metadata.name}`;
|
|
166934
|
+
if (fullResult[crKey]) {
|
|
166935
|
+
logger.error(`Duplicate CR ${crKey}`);
|
|
166936
|
+
}
|
|
166937
|
+
// Keep the complete CR set for validations that need repository-wide context.
|
|
166938
|
+
fullResult[crKey] = yamlData;
|
|
166939
|
+
// Keep the filtered CR set for previous-CR lookup during claim rendering.
|
|
166940
|
+
if (allowedClaimReferences.length === 0 ||
|
|
166941
|
+
allowedClaimReferences.includes(yamlData.metadata?.annotations?.[catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('claim-ref')])) {
|
|
166942
|
+
result[crKey] = yamlData;
|
|
166943
|
+
}
|
|
166944
|
+
}
|
|
166945
|
+
}, excludedPaths.concat(getAdditionalPaths()));
|
|
166946
|
+
return { crs: result, fullCrs: fullResult };
|
|
166947
|
+
}
|
|
166948
|
+
async function loadCRs(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
|
|
166949
|
+
const { crs } = await loadCRsWithFullSet(crsPath, excludedPaths, allowedClaimReferences);
|
|
166950
|
+
return crs;
|
|
166951
|
+
}
|
|
166952
|
+
/*
|
|
166953
|
+
* Description: Get the renamed using claimRef annotation
|
|
166954
|
+
* Input: claims: any, crs: any
|
|
166955
|
+
* Output: renames: IRenameResult[]
|
|
166956
|
+
*/
|
|
166957
|
+
async function loadRenames(claims, crs) {
|
|
166958
|
+
/*
|
|
166959
|
+
* If checkRenames is false, we don't need to check for renames
|
|
166960
|
+
*/
|
|
166961
|
+
const renamesEnabled = getRenamesEnabled();
|
|
166962
|
+
if (!renamesEnabled)
|
|
166963
|
+
return [];
|
|
166964
|
+
const result = [];
|
|
166965
|
+
/**
|
|
166966
|
+
* For each CR, look for a claim that does not match the name with CR's firestartr.dev/claim-ref annotation
|
|
166967
|
+
*/
|
|
166968
|
+
for (const cr of Object.values(crs)) {
|
|
166969
|
+
const anyCr = cr;
|
|
166970
|
+
if (!anyCr?.metadata?.annotations)
|
|
166971
|
+
continue;
|
|
166972
|
+
// if the annotation is a claimRef
|
|
166973
|
+
const annotationName = common.generic.getFirestartrAnnotation('claim-ref');
|
|
166974
|
+
const annotations = anyCr?.metadata?.annotations || {};
|
|
166975
|
+
if (annotationName in annotations) {
|
|
166976
|
+
const claimRef = anyCr.metadata.annotations[annotationName];
|
|
166977
|
+
// split the annotation into kind and name
|
|
166978
|
+
const [kind, name] = claimRef.split('/');
|
|
166979
|
+
// if the claim exists, check if the name is different for the given provider
|
|
166980
|
+
const referencedClaim = claims[`${kind}-${name}`].claim;
|
|
166981
|
+
const oldName = anyCr.metadata.name;
|
|
166982
|
+
const newName = referencedClaim.providers[getConfiguredProvider()].name;
|
|
166983
|
+
if (oldName !== newName) {
|
|
166984
|
+
result.push({
|
|
166985
|
+
kind: referencedClaim.kind,
|
|
166986
|
+
claimPath: claims[`${kind}-${name}`].claimPath,
|
|
166987
|
+
claimName: referencedClaim.name,
|
|
166988
|
+
oldName,
|
|
166989
|
+
newName,
|
|
166990
|
+
});
|
|
166991
|
+
}
|
|
166992
|
+
}
|
|
166993
|
+
}
|
|
166994
|
+
return result;
|
|
166995
|
+
}
|
|
166996
|
+
async function loadClaimsList(claimRefList, claimsPath = getPath('claims')) {
|
|
166997
|
+
const data = {
|
|
166998
|
+
renderClaims: {},
|
|
166999
|
+
crs: {},
|
|
167000
|
+
fullCrs: {},
|
|
167001
|
+
};
|
|
167002
|
+
const defaults = loadClaimDefaults();
|
|
167003
|
+
for await (const claimRef of claimRefList) {
|
|
167004
|
+
const [renderedClaimData] = await loadClaim(claimRef, getOrg(), defaults, loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, claimsPath);
|
|
167005
|
+
data.renderClaims = lodash_default().merge(data.renderClaims, renderedClaimData);
|
|
167006
|
+
}
|
|
167007
|
+
const crClaimReferences = [];
|
|
167008
|
+
for (const ref of Object.keys(data.renderClaims)) {
|
|
167009
|
+
// Replaces only the first instance of '-'
|
|
167010
|
+
crClaimReferences.push(ref.replace('-', '/'));
|
|
167011
|
+
}
|
|
167012
|
+
const loadedCrs = await loadCRsWithFullSet(getPath('crs'), [getPath('globals'), getPath('initializers')], crClaimReferences);
|
|
167013
|
+
data['crs'] = loadedCrs.crs;
|
|
167014
|
+
data['fullCrs'] = loadedCrs.fullCrs;
|
|
167015
|
+
return data;
|
|
167016
|
+
}
|
|
167017
|
+
function getOrg() {
|
|
167018
|
+
const groupOrg = catalog_common/* default.environment.getFromEnvironmentWithDefault */.Z.environment.getFromEnvironmentWithDefault(catalog_common/* default.types.envVars.org */.Z.types.envVars.org, '');
|
|
167019
|
+
return groupOrg;
|
|
167020
|
+
}
|
|
167021
|
+
|
|
167022
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/references.ts
|
|
167023
|
+
function validateTfStateKeyUniqueness(crs) {
|
|
167024
|
+
const tfStateKeys = {};
|
|
167025
|
+
for (const crKey of Object.keys(crs)) {
|
|
167026
|
+
const cr = crs[crKey];
|
|
167027
|
+
if (!isTerraformWorkspace(cr))
|
|
167028
|
+
continue;
|
|
167029
|
+
const tfKey = cr.spec.firestartr.tfStateKey;
|
|
167030
|
+
if (tfStateKeys[tfKey]) {
|
|
167031
|
+
throw new Error(`❗❗ ❌ RENDER ERROR ❌ ❗❗
|
|
167032
|
+
|
|
167033
|
+
The tfStateKey ${tfKey} is not unique,
|
|
167034
|
+
|
|
167035
|
+
It is being used by the following CRs:
|
|
167036
|
+
|
|
167037
|
+
- ${tfStateKeys[tfKey].kind} ${tfStateKeys[tfKey].metadata.name}
|
|
167038
|
+
|
|
167039
|
+
- ${cr.kind} ${cr.metadata.name}
|
|
167040
|
+
|
|
167041
|
+
Check the following Claims to ensure that the tfStateKey is unique:
|
|
167042
|
+
|
|
167043
|
+
- ${tfStateKeys[tfKey].metadata.annotations['firestartr.dev/claim-ref']}
|
|
167044
|
+
|
|
167045
|
+
- ${cr.metadata.annotations['firestartr.dev/claim-ref']}
|
|
167046
|
+
`);
|
|
167047
|
+
}
|
|
167048
|
+
tfStateKeys[cr.spec.firestartr.tfStateKey] = cr;
|
|
167049
|
+
}
|
|
167050
|
+
}
|
|
167051
|
+
function references_isCatalogEntity(cr) {
|
|
167052
|
+
return [
|
|
167053
|
+
'Component',
|
|
167054
|
+
'Domain',
|
|
167055
|
+
'System',
|
|
167056
|
+
'User',
|
|
167057
|
+
'Group',
|
|
167058
|
+
'Resource',
|
|
167059
|
+
].includes(cr.kind);
|
|
167060
|
+
}
|
|
167061
|
+
function isTerraformWorkspace(cr) {
|
|
167062
|
+
return cr.kind === 'FirestartrTerraformWorkspace';
|
|
167063
|
+
}
|
|
167064
|
+
|
|
167065
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/crSize.ts
|
|
167066
|
+
|
|
167067
|
+
const K8S_OBJECT_SIZE_LIMIT = 1572864; // 1.5 MiB in bytes, etcd recommended limit: https://etcd.io/docs/latest/dev-guide/limit/
|
|
167068
|
+
function validateCrSizes(crs) {
|
|
167069
|
+
for (const key of Object.keys(crs)) {
|
|
167070
|
+
const cr = crs[key];
|
|
167071
|
+
const serialized = catalog_common/* default.io.toYaml */.Z.io.toYaml(cr);
|
|
167072
|
+
const size = Buffer.byteLength(serialized, 'utf8');
|
|
167073
|
+
if (size > K8S_OBJECT_SIZE_LIMIT) {
|
|
167074
|
+
throw new Error(`CR "${cr.kind}-${cr.metadata.name}" exceeds the Kubernetes object size limit by ${size - K8S_OBJECT_SIZE_LIMIT} bytes. Maximum allowed is ${K8S_OBJECT_SIZE_LIMIT} bytes (1.5MiB).`);
|
|
167075
|
+
}
|
|
167076
|
+
}
|
|
167077
|
+
}
|
|
167078
|
+
|
|
167079
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/permissions.ts
|
|
167080
|
+
|
|
167081
|
+
function validatePermissionsUniqueness(crs) {
|
|
167082
|
+
for (const crkey in crs) {
|
|
167083
|
+
const cr = crs[crkey];
|
|
167084
|
+
if (cr.kind === 'FirestartrGithubRepository') {
|
|
167085
|
+
const permissions = cr.spec.permissions;
|
|
167086
|
+
logger.debug(`Validating Permissions Uniqueness of ${crkey}`);
|
|
167087
|
+
if (permissions) {
|
|
167088
|
+
const rolesByIdentifier = new Map();
|
|
167089
|
+
for (const perm of permissions) {
|
|
167090
|
+
const identifier = perm.collaborator
|
|
167091
|
+
? perm.collaborator
|
|
167092
|
+
: `ref:${perm.ref.kind}:${perm.ref.name}`;
|
|
167093
|
+
const role = perm.role;
|
|
167094
|
+
const prevRole = rolesByIdentifier.get(identifier);
|
|
167095
|
+
if (prevRole === undefined) {
|
|
167096
|
+
rolesByIdentifier.set(identifier, role);
|
|
167097
|
+
}
|
|
167098
|
+
else if (prevRole !== role) {
|
|
167099
|
+
throw new Error(`Conflicting permission role in FirestartrGithubRepository ${crkey}: ${identifier} has roles "${prevRole}" and "${role}".\nFull CR: ${JSON.stringify(cr, null, 2)}`);
|
|
167100
|
+
}
|
|
167101
|
+
}
|
|
167102
|
+
}
|
|
167103
|
+
}
|
|
167104
|
+
}
|
|
167105
|
+
}
|
|
167106
|
+
|
|
167107
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/backstageAnnotations.ts
|
|
167108
|
+
const backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX = 'firestartr.backstage.dev/';
|
|
167109
|
+
const CATALOG_KINDS = new Set([
|
|
167110
|
+
'User',
|
|
167111
|
+
'Group',
|
|
167112
|
+
'Component',
|
|
167113
|
+
'System',
|
|
167114
|
+
'Domain',
|
|
167115
|
+
'API',
|
|
167116
|
+
'Resource',
|
|
167117
|
+
'CatalogKubernetesResource',
|
|
167118
|
+
'CatalogTerraformWorkspace',
|
|
167119
|
+
'CatalogArgoDeploy',
|
|
167120
|
+
'CatalogOrgWebhook',
|
|
167121
|
+
'CatalogSecrets',
|
|
167122
|
+
]);
|
|
167123
|
+
function validateNoBackstageAnnotationsInK8sCrs(crs) {
|
|
167124
|
+
for (const crKey in crs) {
|
|
167125
|
+
const cr = crs[crKey];
|
|
167126
|
+
if (CATALOG_KINDS.has(cr.kind))
|
|
167127
|
+
continue;
|
|
167128
|
+
if (cr.metadata?.annotations) {
|
|
167129
|
+
const backstageKeys = Object.keys(cr.metadata.annotations).filter((k) => k.startsWith(backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX));
|
|
167130
|
+
if (backstageKeys.length > 0) {
|
|
167131
|
+
throw new Error(`K8s CR ${crKey} contains Backstage-only annotations (${backstageKeys.join(', ')}). ` +
|
|
167132
|
+
`Annotations with prefix ${backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX} must only appear on Backstage catalog entities, not on Kubernetes CRs.`);
|
|
167133
|
+
}
|
|
167134
|
+
}
|
|
167135
|
+
}
|
|
167136
|
+
}
|
|
167137
|
+
|
|
167138
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/refsSorter/refsSorter.ts
|
|
167139
|
+
|
|
167140
|
+
/**
|
|
167141
|
+
* @param renderClaims renderClaims to sort
|
|
167142
|
+
* @param kinds kinds to get from renderClaims
|
|
167143
|
+
* @returns renderClaims with only the kinds specified
|
|
167144
|
+
*/
|
|
167145
|
+
function sortRenderClaimsByKind(renderClaims, kinds) {
|
|
167146
|
+
let result = {};
|
|
167147
|
+
for (const kind of kinds) {
|
|
167148
|
+
for (const key in renderClaims) {
|
|
167149
|
+
if (renderClaims[key].claim.kind === kind) {
|
|
167150
|
+
result[key] = renderClaims[key];
|
|
167151
|
+
}
|
|
167152
|
+
}
|
|
167153
|
+
result = sortSelfKindRefs(result, kind);
|
|
167154
|
+
}
|
|
167155
|
+
return result;
|
|
167156
|
+
}
|
|
167157
|
+
function sortSelfKindRefs(renderClaims, kind) {
|
|
167158
|
+
if (!hasSelfRefs(kind)) {
|
|
167159
|
+
return renderClaims;
|
|
167160
|
+
}
|
|
167161
|
+
const newRenderClaims = {};
|
|
167162
|
+
const data = extractRefs(renderClaims, kind);
|
|
167163
|
+
const ordered = [];
|
|
167164
|
+
const visiting = [];
|
|
167165
|
+
const visited = [];
|
|
167166
|
+
for (const key of Object.keys(data)) {
|
|
167167
|
+
if (!visited.find((obj) => obj.name === key)) {
|
|
167168
|
+
sortRefs(data, data[key], ordered, visiting, visited);
|
|
167169
|
+
}
|
|
167170
|
+
}
|
|
167171
|
+
for (const cr of ordered) {
|
|
167172
|
+
newRenderClaims[cr.name] = renderClaims[cr.name];
|
|
167173
|
+
}
|
|
167174
|
+
return newRenderClaims;
|
|
167175
|
+
}
|
|
167176
|
+
function sortRefs(data, claim, ordered = [], visiting = [], visited = []) {
|
|
167177
|
+
if (visiting.find((obj) => obj.name === claim.name)) {
|
|
167178
|
+
throw new Error(`Circular dependency detected for '${claim.name}'`);
|
|
167179
|
+
}
|
|
167180
|
+
if (!visited.find((obj) => obj.name === claim.name)) {
|
|
167181
|
+
visiting.push(claim);
|
|
167182
|
+
if (claim.refs) {
|
|
167183
|
+
for (const ref of claim.refs) {
|
|
167184
|
+
const referencedObject = data[ref];
|
|
167185
|
+
if (!referencedObject) {
|
|
167186
|
+
throw new Error(`Reference '${ref}' does not exist for '${claim.name}'`);
|
|
167187
|
+
}
|
|
167188
|
+
sortRefs(data, referencedObject, ordered, visiting, visited);
|
|
167189
|
+
}
|
|
167190
|
+
}
|
|
167191
|
+
visited.push(visiting.pop());
|
|
167192
|
+
ordered.push(claim);
|
|
167193
|
+
}
|
|
167194
|
+
}
|
|
167195
|
+
function hasSelfRefs(kind) {
|
|
167196
|
+
return ['TFWorkspaceClaim', 'GroupClaim'].includes(kind);
|
|
167197
|
+
}
|
|
167198
|
+
|
|
167199
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/renderer/claims-sorter.ts
|
|
167200
|
+
|
|
167201
|
+
function sortKinds(orderedKinds, claims) {
|
|
167202
|
+
const result = [];
|
|
167203
|
+
for (const kind of orderedKinds) {
|
|
167204
|
+
const kindRenderClaims = sortRenderClaimsByKind(claims, [kind]);
|
|
167205
|
+
result.push(kindRenderClaims);
|
|
167206
|
+
}
|
|
167207
|
+
return result;
|
|
167208
|
+
}
|
|
167209
|
+
|
|
166744
167210
|
;// CONCATENATED MODULE: ../cdk8s_renderer/src/overriders/utils.ts
|
|
166745
167211
|
|
|
166746
167212
|
|
|
@@ -166782,14 +167248,12 @@ async function utils_renderFeature(featureName, featureVersion, featureOutputObj
|
|
|
166782
167248
|
|
|
166783
167249
|
|
|
166784
167250
|
|
|
166785
|
-
|
|
166786
|
-
|
|
166787
167251
|
// this is the only way currently to make
|
|
166788
167252
|
// work the system and inject our code
|
|
166789
167253
|
// without having to download a feature
|
|
166790
|
-
let
|
|
167254
|
+
let featureOverride_MOCK_FEATURES_FN;
|
|
166791
167255
|
function MOCK_FEATURES(mock) {
|
|
166792
|
-
|
|
167256
|
+
featureOverride_MOCK_FEATURES_FN = mock;
|
|
166793
167257
|
if (mock) {
|
|
166794
167258
|
log.warn('⚠️ Warning features system downloader has been mocked, it should only happen in unit testing');
|
|
166795
167259
|
}
|
|
@@ -166820,8 +167284,8 @@ class FeaturesOverrider extends OverriderPatches {
|
|
|
166820
167284
|
let owner = 'prefapp';
|
|
166821
167285
|
let versionOrRef = this.featureVersion;
|
|
166822
167286
|
let renderer = 'getFeatureConfig';
|
|
166823
|
-
if (
|
|
166824
|
-
return
|
|
167287
|
+
if (featureOverride_MOCK_FEATURES_FN) {
|
|
167288
|
+
return featureOverride_MOCK_FEATURES_FN();
|
|
166825
167289
|
}
|
|
166826
167290
|
if (this.featureRepo) {
|
|
166827
167291
|
[owner, repo] = this.featureRepo.split(/\//);
|
|
@@ -166839,8 +167303,8 @@ class FeaturesOverrider extends OverriderPatches {
|
|
|
166839
167303
|
const featureName = this.featureName;
|
|
166840
167304
|
const featureVersion = this.featureVersion || this.featureRef;
|
|
166841
167305
|
const featureArgs = this.featureArgs;
|
|
166842
|
-
const fSetUpAndRunRenderer = function (
|
|
166843
|
-
return this.setUpAndRunRenderer(
|
|
167306
|
+
const fSetUpAndRunRenderer = function (target) {
|
|
167307
|
+
return this.setUpAndRunRenderer(target);
|
|
166844
167308
|
}.bind(this);
|
|
166845
167309
|
let renderedFeatureConfig = null;
|
|
166846
167310
|
return [
|
|
@@ -166849,7 +167313,7 @@ class FeaturesOverrider extends OverriderPatches {
|
|
|
166849
167313
|
return true;
|
|
166850
167314
|
},
|
|
166851
167315
|
async apply(cr) {
|
|
166852
|
-
renderedFeatureConfig = await fSetUpAndRunRenderer(
|
|
167316
|
+
renderedFeatureConfig = await fSetUpAndRunRenderer(claim);
|
|
166853
167317
|
return cr;
|
|
166854
167318
|
},
|
|
166855
167319
|
identify() {
|
|
@@ -166862,28 +167326,6 @@ class FeaturesOverrider extends OverriderPatches {
|
|
|
166862
167326
|
return utils_renderFeature(featureName, featureVersion, renderedFeatureConfig, cr, claim.name);
|
|
166863
167327
|
},
|
|
166864
167328
|
},
|
|
166865
|
-
{
|
|
166866
|
-
isPostPatch: true,
|
|
166867
|
-
validate() {
|
|
166868
|
-
return true;
|
|
166869
|
-
},
|
|
166870
|
-
async apply(cr) {
|
|
166871
|
-
if (!renderedFeatureConfig) {
|
|
166872
|
-
logger.warn(`Feature ${featureName}: renderedFeatureConfig is null, skipping post-patch`);
|
|
166873
|
-
return cr;
|
|
166874
|
-
}
|
|
166875
|
-
const provider = helperCTX(this).provider;
|
|
166876
|
-
const jsonPatches = renderedFeatureConfig.patches?.[provider] || [];
|
|
166877
|
-
fast_json_patch_default().applyPatch(cr, jsonPatches);
|
|
166878
|
-
return cr;
|
|
166879
|
-
},
|
|
166880
|
-
identify() {
|
|
166881
|
-
return `feature-json-patch/${featureName}`;
|
|
166882
|
-
},
|
|
166883
|
-
applicable() {
|
|
166884
|
-
return { applicableProviders: ['catalog', 'github'] };
|
|
166885
|
-
},
|
|
166886
|
-
},
|
|
166887
167329
|
];
|
|
166888
167330
|
}
|
|
166889
167331
|
}
|
|
@@ -166949,7 +167391,7 @@ function getPreviousCRfromClaim(claim, previousCRs, expectedKind) {
|
|
|
166949
167391
|
const isVariantClaim = !!claim._parentClaimName;
|
|
166950
167392
|
for (const previousCRKey of previousCRsKeys) {
|
|
166951
167393
|
const previousCR = previousCRs[previousCRKey];
|
|
166952
|
-
if (
|
|
167394
|
+
if (references_isCatalogEntity(previousCR))
|
|
166953
167395
|
continue;
|
|
166954
167396
|
if (isExcludedFromPreviousCR(previousCR.kind))
|
|
166955
167397
|
continue;
|
|
@@ -171264,15 +171706,30 @@ class CatalogSystemChart extends BaseCatalogChart {
|
|
|
171264
171706
|
;// CONCATENATED MODULE: ../cdk8s_renderer/src/charts/catalog/userChart.ts
|
|
171265
171707
|
|
|
171266
171708
|
|
|
171709
|
+
const ORG_ROLE_ANNOTATION = 'firestartr.backstage.dev/org-role';
|
|
171267
171710
|
class CatalogUserChart extends BaseCatalogChart {
|
|
171268
171711
|
template() {
|
|
171269
171712
|
const claim = this.get('claim');
|
|
171713
|
+
const explicitOrgRole = claim.annotations?.[ORG_ROLE_ANNOTATION];
|
|
171714
|
+
const inferredOrgRole = claim.providers &&
|
|
171715
|
+
typeof claim.providers === 'object' &&
|
|
171716
|
+
'github' in claim.providers &&
|
|
171717
|
+
claim.providers.github?.role === 'admin'
|
|
171718
|
+
? 'owner'
|
|
171719
|
+
: undefined;
|
|
171720
|
+
const orgRole = explicitOrgRole ?? inferredOrgRole;
|
|
171721
|
+
const annotations = {
|
|
171722
|
+
...(claim.annotations || {}),
|
|
171723
|
+
};
|
|
171724
|
+
if (orgRole) {
|
|
171725
|
+
annotations[ORG_ROLE_ANNOTATION] = orgRole;
|
|
171726
|
+
}
|
|
171270
171727
|
return {
|
|
171271
171728
|
apiVersion: 'backstage.io/v1alpha1',
|
|
171272
171729
|
kind: 'User',
|
|
171273
171730
|
metadata: {
|
|
171274
171731
|
name: claim.name,
|
|
171275
|
-
annotations
|
|
171732
|
+
annotations,
|
|
171276
171733
|
},
|
|
171277
171734
|
spec: {
|
|
171278
171735
|
profile: claim.profile,
|
|
@@ -172428,6 +172885,7 @@ function validateActionsVariablesUniqueness(crs) {
|
|
|
172428
172885
|
|
|
172429
172886
|
|
|
172430
172887
|
|
|
172888
|
+
|
|
172431
172889
|
/*
|
|
172432
172890
|
* Function called when rendering but not importing
|
|
172433
172891
|
*
|
|
@@ -172455,6 +172913,7 @@ async function renderer_render(catalogScope, firestartrScope, claimList) {
|
|
|
172455
172913
|
validateActionsVariablesUniqueness(result);
|
|
172456
172914
|
validateCrSizes(result);
|
|
172457
172915
|
validatePermissionsUniqueness(result);
|
|
172916
|
+
validateNoBackstageAnnotationsInK8sCrs(result);
|
|
172458
172917
|
}
|
|
172459
172918
|
catch (e) {
|
|
172460
172919
|
logger.error(e.message);
|
|
@@ -172893,7 +173352,7 @@ async function addLastStateAndLastClaimAnnotations(filePath, lastStatePRLink, la
|
|
|
172893
173352
|
setRepositoryUrl: setRepositoryUrl,
|
|
172894
173353
|
setDefaultBranch: setDefaultBranch,
|
|
172895
173354
|
runComparer: runComparer,
|
|
172896
|
-
isCatalogEntity:
|
|
173355
|
+
isCatalogEntity: references_isCatalogEntity,
|
|
172897
173356
|
loadCRs: loadCRs,
|
|
172898
173357
|
renderTfWorkspace: renderTfWorkspace,
|
|
172899
173358
|
normalizeModuleContent: normalizeModuleContent,
|
|
@@ -173685,6 +174144,10 @@ class RepoGithubDecanter extends GithubDecanter {
|
|
|
173685
174144
|
__decantPages() {
|
|
173686
174145
|
if (this.data.pages) {
|
|
173687
174146
|
const pagesData = this.data.pages;
|
|
174147
|
+
const supportedBuildTypes = ['workflow', 'legacy'];
|
|
174148
|
+
if (!supportedBuildTypes.includes(pagesData.build_type)) {
|
|
174149
|
+
return;
|
|
174150
|
+
}
|
|
173688
174151
|
const pagesConfig = {
|
|
173689
174152
|
buildType: pagesData.build_type,
|
|
173690
174153
|
...(typeof pagesData.cname === 'string' && pagesData.cname.length > 0
|
|
@@ -363190,7 +363653,7 @@ function helperCreateCheckRunName(cmd, item) {
|
|
|
363190
363653
|
|
|
363191
363654
|
;// CONCATENATED MODULE: ../operator/src/utils/index.ts
|
|
363192
363655
|
const secretRegex = /\$\{\{ secrets\.(.*?) \}\}/g;
|
|
363193
|
-
function
|
|
363656
|
+
function utils_isRecord(value) {
|
|
363194
363657
|
return typeof value === 'object' && value !== null;
|
|
363195
363658
|
}
|
|
363196
363659
|
function getFirstNonEmptyString(...values) {
|
|
@@ -363228,7 +363691,7 @@ function replaceInlineSecrets(inline, secrets) {
|
|
|
363228
363691
|
return result;
|
|
363229
363692
|
}
|
|
363230
363693
|
function extractErrorDetails(error) {
|
|
363231
|
-
const exitCode =
|
|
363694
|
+
const exitCode = utils_isRecord(error) && typeof error.exitCode === 'number'
|
|
363232
363695
|
? error.exitCode
|
|
363233
363696
|
: undefined;
|
|
363234
363697
|
if (typeof error === 'string') {
|
|
@@ -363239,7 +363702,7 @@ function extractErrorDetails(error) {
|
|
|
363239
363702
|
const output = getFirstNonEmptyString(errorWithOutput.output, error.message);
|
|
363240
363703
|
return { output: output ?? String(error), exitCode };
|
|
363241
363704
|
}
|
|
363242
|
-
if (
|
|
363705
|
+
if (utils_isRecord(error)) {
|
|
363243
363706
|
const output = getFirstNonEmptyString(error.output, error.message, error.error);
|
|
363244
363707
|
if (output !== undefined) {
|
|
363245
363708
|
return { output, exitCode };
|
|
@@ -713352,7 +713815,7 @@ const crsStatusSubcommand = {
|
|
|
713352
713815
|
};
|
|
713353
713816
|
|
|
713354
713817
|
;// CONCATENATED MODULE: ./package.json
|
|
713355
|
-
const package_namespaceObject = JSON.parse('{"i8":"2.11.0-snapshot-
|
|
713818
|
+
const package_namespaceObject = JSON.parse('{"i8":"2.11.0-snapshot-patch-claims"}');
|
|
713356
713819
|
;// CONCATENATED MODULE: ../../package.json
|
|
713357
713820
|
const package_namespaceObject_1 = {"i8":"2.10.0"};
|
|
713358
713821
|
// EXTERNAL MODULE: ../../node_modules/semver/index.js
|