@firestartr/cli 2.11.0-snapshot-patch-claims-2 → 2.11.0-snapshot-mco-03
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 +976 -1262
- package/build/packages/cdk8s_renderer/index.d.ts +2 -0
- package/build/packages/cdk8s_renderer/src/overriders/featureOverride.d.ts +11 -2
- package/build/packages/cdk8s_renderer/src/utils/repositoryClaimUtils.d.ts +1 -0
- package/build/packages/features_preparer/src/index.d.ts +2 -5
- package/build/packages/features_preparer/src/installer.d.ts +0 -2
- package/build/packages/features_preparer/src/renderer.d.ts +0 -2
- package/build/packages/features_renderer/index.d.ts +1 -4
- package/build/packages/features_renderer/src/auxiliar.d.ts +1 -4
- package/build/packages/features_renderer/src/render.d.ts +1 -2
- package/build/packages/features_renderer/src/schema.d.ts +8 -3
- package/build/packages/importer/src/decanter/config.d.ts +37 -0
- package/build/packages/importer/src/decanter/index.d.ts +1 -1
- package/package.json +1 -1
- package/build/packages/cdk8s_renderer/src/claims/stitching/errors.d.ts +0 -14
- package/build/packages/cdk8s_renderer/src/claims/stitching/protectedPaths.d.ts +0 -3
- package/build/packages/cdk8s_renderer/src/claims/stitching/stitching.d.ts +0 -19
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
|
|
128398
|
+
const entityFolderName = `${entity.metadata.name}`.toLowerCase();
|
|
128399
128399
|
return external_path_default().join(basePath, entityFolderName, featureName);
|
|
128400
128400
|
}
|
|
128401
128401
|
function getFeatureRenderedConfigForComponent(entity, featureName, basePath = '/tmp/features') {
|
|
@@ -164363,6 +164363,771 @@ const base_secrets_schema = 'firestartr.dev://common/SecretsClaim';
|
|
|
164363
164363
|
SecretsClaimSchema: base_secrets_schema,
|
|
164364
164364
|
});
|
|
164365
164365
|
|
|
164366
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/lazy_loader.ts
|
|
164367
|
+
|
|
164368
|
+
|
|
164369
|
+
|
|
164370
|
+
|
|
164371
|
+
|
|
164372
|
+
|
|
164373
|
+
|
|
164374
|
+
|
|
164375
|
+
|
|
164376
|
+
|
|
164377
|
+
|
|
164378
|
+
|
|
164379
|
+
|
|
164380
|
+
|
|
164381
|
+
|
|
164382
|
+
|
|
164383
|
+
// We need to ensure the grep command is a gnu version
|
|
164384
|
+
let IS_GNU_GREP = false;
|
|
164385
|
+
let GREP_ON_CHECK = false;
|
|
164386
|
+
// this loop is for avoid race conditions
|
|
164387
|
+
// once a check is running no more checks
|
|
164388
|
+
async function waitForCheck() {
|
|
164389
|
+
const f_wait = () => new Promise((timeOut) => setTimeout(timeOut, 10));
|
|
164390
|
+
do {
|
|
164391
|
+
await f_wait();
|
|
164392
|
+
} while (GREP_ON_CHECK);
|
|
164393
|
+
}
|
|
164394
|
+
function checkGrep() {
|
|
164395
|
+
return new Promise((ok, ko) => {
|
|
164396
|
+
// idempotency: already checked
|
|
164397
|
+
if (IS_GNU_GREP)
|
|
164398
|
+
return ok();
|
|
164399
|
+
// a check is already running no new checks
|
|
164400
|
+
if (GREP_ON_CHECK)
|
|
164401
|
+
return waitForCheck();
|
|
164402
|
+
logger.info('Checking the grep command');
|
|
164403
|
+
GREP_ON_CHECK = true;
|
|
164404
|
+
const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['--version']);
|
|
164405
|
+
handler.on('close', (code) => {
|
|
164406
|
+
GREP_ON_CHECK = false;
|
|
164407
|
+
if (code === 0) {
|
|
164408
|
+
logger.debug('Grep is a gnu grep');
|
|
164409
|
+
IS_GNU_GREP = true;
|
|
164410
|
+
ok();
|
|
164411
|
+
}
|
|
164412
|
+
else {
|
|
164413
|
+
ko('Lazy evaluation needs a gnu-grep command');
|
|
164414
|
+
}
|
|
164415
|
+
});
|
|
164416
|
+
});
|
|
164417
|
+
}
|
|
164418
|
+
async function loadClaim(claimRef, org, defaults = loadClaimDefaults(), patchClaim = loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, existingRefs = {}, postValidations = new Map()) {
|
|
164419
|
+
await checkGrep();
|
|
164420
|
+
let result = existingRefs;
|
|
164421
|
+
logger.info(`Load reference ${claimRef}`);
|
|
164422
|
+
initVirtualClaims(org);
|
|
164423
|
+
logger.info(`Load reference (parts) ${claimRef.split(/-/)[0]} ${claimRef.replace(/^[^-]+-/, '')}`);
|
|
164424
|
+
// cargas datos con grep
|
|
164425
|
+
try {
|
|
164426
|
+
const claimData = await lazyGetClaim(claimRef.split(/-/)[0], claimRef.replace(/^[^-]+-/, ''), org, cwd);
|
|
164427
|
+
const claim = patchClaim(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(claimData), defaults);
|
|
164428
|
+
let variants = [];
|
|
164429
|
+
if (claim.kind === 'TFWorkspaceClaim' &&
|
|
164430
|
+
claim.providers?.terraform?.variants) {
|
|
164431
|
+
variants = claim.providers.terraform.variants;
|
|
164432
|
+
delete claim.providers.terraform.variants;
|
|
164433
|
+
}
|
|
164434
|
+
logger.silly(`Patched claim is:
|
|
164435
|
+
---
|
|
164436
|
+
${catalog_common/* default.io.toYaml */.Z.io.toYaml(claim)}`);
|
|
164437
|
+
try {
|
|
164438
|
+
validateClaim(claim, base[`${claim.kind}Schema`]);
|
|
164439
|
+
await optionalValidation(claim);
|
|
164440
|
+
}
|
|
164441
|
+
catch (error) {
|
|
164442
|
+
let errorMsg = '';
|
|
164443
|
+
if (Array.isArray(error)) {
|
|
164444
|
+
for (const data of error) {
|
|
164445
|
+
errorMsg = `${errorMsg}
|
|
164446
|
+
- ${data.instancePath}: ${data.message}`;
|
|
164447
|
+
}
|
|
164448
|
+
}
|
|
164449
|
+
else {
|
|
164450
|
+
errorMsg = error instanceof Error ? error.message : String(error);
|
|
164451
|
+
}
|
|
164452
|
+
throw new Error(`Error when validating claim ${claimRef}: ${errorMsg}`);
|
|
164453
|
+
}
|
|
164454
|
+
result[claimRef] = {};
|
|
164455
|
+
result[claimRef]['claim'] = claim;
|
|
164456
|
+
result[claimRef]['claimPath'] = VisitedClaims[claimRef];
|
|
164457
|
+
if (VisitedClaims[claimRef] === 'virtual') {
|
|
164458
|
+
result = await setVirtualClaimAdditionalData(result, claim, claimRef);
|
|
164459
|
+
}
|
|
164460
|
+
else {
|
|
164461
|
+
result = await setNonVirtualClaimAdditionalData(result, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
|
|
164462
|
+
}
|
|
164463
|
+
const claimKind = claim.kind;
|
|
164464
|
+
const references = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(claim));
|
|
164465
|
+
for (const ref of references) {
|
|
164466
|
+
if (!result[ref]) {
|
|
164467
|
+
const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
|
|
164468
|
+
result = lodash_default().merge(result, resolvedReferences);
|
|
164469
|
+
}
|
|
164470
|
+
}
|
|
164471
|
+
if (variants.length > 0) {
|
|
164472
|
+
const parentClaimPath = VisitedClaims[claimRef];
|
|
164473
|
+
for (const variant of variants) {
|
|
164474
|
+
if (!variant.name || !variant.overrides) {
|
|
164475
|
+
throw new Error(`Variant in claim ${claimRef} is missing required field 'name' or 'overrides'`);
|
|
164476
|
+
}
|
|
164477
|
+
const prohibitedOverrideFields = ['source', 'module', 'name'];
|
|
164478
|
+
for (const field of prohibitedOverrideFields) {
|
|
164479
|
+
if (field in variant.overrides) {
|
|
164480
|
+
throw new Error(`Variant '${variant.name}' in claim ${claimRef} cannot override '${field}'`);
|
|
164481
|
+
}
|
|
164482
|
+
}
|
|
164483
|
+
const composedName = claim.providers.terraform.name + '-' + variant.name;
|
|
164484
|
+
const variantClaim = lodash_default().cloneDeep(claim);
|
|
164485
|
+
variantClaim._parentClaimName = claim.name;
|
|
164486
|
+
variantClaim.name = composedName;
|
|
164487
|
+
variantClaim.providers.terraform = lodash_default().merge({}, claim.providers.terraform, variant.overrides);
|
|
164488
|
+
variantClaim.providers.terraform.name = composedName;
|
|
164489
|
+
if (!variantClaim.annotations) {
|
|
164490
|
+
variantClaim.annotations = {};
|
|
164491
|
+
}
|
|
164492
|
+
variantClaim.annotations['firestartr.dev/variant-of'] =
|
|
164493
|
+
claim.providers.terraform.name;
|
|
164494
|
+
const variantRef = `TFWorkspaceClaim-${composedName}`;
|
|
164495
|
+
if (result[variantRef]) {
|
|
164496
|
+
throw new Error(`Variant name '${variant.name}' (composed: '${composedName}') from claim '${claimRef}' conflicts with existing claim '${variantRef}'`);
|
|
164497
|
+
}
|
|
164498
|
+
logger.info(`Creating synthetic variant claim ${variantRef}`);
|
|
164499
|
+
result[variantRef] = {};
|
|
164500
|
+
result[variantRef]['claim'] = variantClaim;
|
|
164501
|
+
result[variantRef]['claimPath'] = parentClaimPath;
|
|
164502
|
+
result = await setNonVirtualClaimAdditionalData(result, variantClaim, variantRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
|
|
164503
|
+
const variantReferences = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(variantClaim));
|
|
164504
|
+
for (const ref of variantReferences) {
|
|
164505
|
+
if (!result[ref]) {
|
|
164506
|
+
const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
|
|
164507
|
+
result = lodash_default().merge(result, resolvedReferences);
|
|
164508
|
+
}
|
|
164509
|
+
}
|
|
164510
|
+
}
|
|
164511
|
+
}
|
|
164512
|
+
}
|
|
164513
|
+
catch (err) {
|
|
164514
|
+
throw `Lazy Loading: ${err}`;
|
|
164515
|
+
}
|
|
164516
|
+
return [result, postValidations];
|
|
164517
|
+
}
|
|
164518
|
+
let LoadedClaims = {};
|
|
164519
|
+
let VisitedClaims = {};
|
|
164520
|
+
let DuplicatedClaims = {};
|
|
164521
|
+
function resetLazyLoader() {
|
|
164522
|
+
LoadedClaims = {};
|
|
164523
|
+
VisitedClaims = {};
|
|
164524
|
+
DuplicatedClaims = {};
|
|
164525
|
+
}
|
|
164526
|
+
async function lazyGetClaim(kind, name, org, cwd) {
|
|
164527
|
+
const indice = `${kind}-${name}`;
|
|
164528
|
+
logger.info(`Lazy loading ${kind}-${name} with index ${indice}`);
|
|
164529
|
+
if (indice in LoadedClaims)
|
|
164530
|
+
return LoadedClaims[indice];
|
|
164531
|
+
if (isVirtualClaim(kind, name)) {
|
|
164532
|
+
await loadVirtualClaim(kind, name, org);
|
|
164533
|
+
}
|
|
164534
|
+
else {
|
|
164535
|
+
await getClaimsByName(name, cwd);
|
|
164536
|
+
}
|
|
164537
|
+
if (indice in LoadedClaims) {
|
|
164538
|
+
return LoadedClaims[indice];
|
|
164539
|
+
}
|
|
164540
|
+
else {
|
|
164541
|
+
throw new Error(`Error: ${kind}-${name} not found`);
|
|
164542
|
+
}
|
|
164543
|
+
}
|
|
164544
|
+
async function getClaimsByName(name, cwd = '.') {
|
|
164545
|
+
return new Promise((ok, ko) => {
|
|
164546
|
+
const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['-r', '-l', '--include=*', '-E', `name: "?${name}"?`, '.'], {
|
|
164547
|
+
cwd: cwd,
|
|
164548
|
+
});
|
|
164549
|
+
logger.info(`Running ${['grep', '-r', '-l', '--include', '-E', 'name: "' + name + '"?', '.'].join(' ')}`);
|
|
164550
|
+
const entradas = [];
|
|
164551
|
+
const chunks = [];
|
|
164552
|
+
handler.stdout.on('data', (data) => {
|
|
164553
|
+
chunks.push(data.toString('utf-8'));
|
|
164554
|
+
});
|
|
164555
|
+
handler.on('close', () => {
|
|
164556
|
+
const dataFinal = chunks.join('');
|
|
164557
|
+
const fileNameList = dataFinal.split(/\n/).filter((line) => line !== '');
|
|
164558
|
+
for (const fileName of fileNameList) {
|
|
164559
|
+
// only yaml files
|
|
164560
|
+
if (!fileName.match(/\.yml$|\.yaml$/)) {
|
|
164561
|
+
continue;
|
|
164562
|
+
}
|
|
164563
|
+
// only entries not already visited
|
|
164564
|
+
if (Object.values(VisitedClaims).includes(fileName)) {
|
|
164565
|
+
continue;
|
|
164566
|
+
}
|
|
164567
|
+
entradas.push(external_path_.join(cwd, fileName));
|
|
164568
|
+
}
|
|
164569
|
+
return Promise.all(entradas.map((entrada) => {
|
|
164570
|
+
return loadRawClaim(entrada);
|
|
164571
|
+
}))
|
|
164572
|
+
.then(() => {
|
|
164573
|
+
ok();
|
|
164574
|
+
})
|
|
164575
|
+
.catch((err) => {
|
|
164576
|
+
ko(err);
|
|
164577
|
+
});
|
|
164578
|
+
});
|
|
164579
|
+
});
|
|
164580
|
+
}
|
|
164581
|
+
async function loadRawClaim(entry) {
|
|
164582
|
+
return new Promise((ok, ko) => {
|
|
164583
|
+
external_fs_.readFile(entry, 'utf-8', (error, data) => {
|
|
164584
|
+
if (error)
|
|
164585
|
+
return ko(`Reading ${entry}: ${error}`);
|
|
164586
|
+
const claim = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
|
|
164587
|
+
if (!('kind' in claim && 'name' in claim)) {
|
|
164588
|
+
logger.warn(`Invalid claim file ${entry}`);
|
|
164589
|
+
}
|
|
164590
|
+
else {
|
|
164591
|
+
const claimKey = `${claim.kind}-${claim.name}`;
|
|
164592
|
+
if (Object.keys(DuplicatedClaims).includes(claimKey) &&
|
|
164593
|
+
DuplicatedClaims[claimKey] !== entry) {
|
|
164594
|
+
return ko(`Duplicated claim ${claimKey} found files: ${DuplicatedClaims[claimKey]} and ${entry}`);
|
|
164595
|
+
}
|
|
164596
|
+
LoadedClaims[claimKey] = data;
|
|
164597
|
+
VisitedClaims[claimKey] = entry;
|
|
164598
|
+
DuplicatedClaims[claimKey] = entry;
|
|
164599
|
+
ok();
|
|
164600
|
+
}
|
|
164601
|
+
});
|
|
164602
|
+
});
|
|
164603
|
+
}
|
|
164604
|
+
async function setVirtualClaimAdditionalData(renderedData, claim, claimRef) {
|
|
164605
|
+
const virtualClaim = getVirtualClaim(claim.kind, claim.name);
|
|
164606
|
+
renderedData[claimRef]['initializers'] = [
|
|
164607
|
+
new UUIDInitializer(claim),
|
|
164608
|
+
new InitializerClaimRef(),
|
|
164609
|
+
new InitializerDefault(virtualClaim.getDefaultConfig()),
|
|
164610
|
+
];
|
|
164611
|
+
renderedData[claimRef]['globals'] = [];
|
|
164612
|
+
renderedData[claimRef]['overrides'] = [];
|
|
164613
|
+
renderedData[claimRef]['normalizers'] = [new NameNormalizer()];
|
|
164614
|
+
return renderedData;
|
|
164615
|
+
}
|
|
164616
|
+
async function setNonVirtualClaimAdditionalData(renderedData, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers) {
|
|
164617
|
+
renderedData[claimRef]['initializers'] = await loadInitializers(claim, renderedData[claimRef]['claimPath']);
|
|
164618
|
+
renderedData[claimRef]['globals'] = await loadGlobals(claim);
|
|
164619
|
+
renderedData[claimRef]['overrides'] = loadOverrides(claim);
|
|
164620
|
+
renderedData[claimRef]['normalizers'] = await loadNormalizers(claim, renderedData[claimRef]['claimPath']);
|
|
164621
|
+
return renderedData;
|
|
164622
|
+
}
|
|
164623
|
+
async function loadVirtualClaim(kind, name, org) {
|
|
164624
|
+
const virtualClaim = getVirtualClaim(kind, name);
|
|
164625
|
+
const expandedClaim = await virtualClaim.expand({ org });
|
|
164626
|
+
logger.info(`Loading virtual claim ${kind} ${name} ${org}`);
|
|
164627
|
+
LoadedClaims[`${kind}-${name}`] = catalog_common/* default.io.toYaml */.Z.io.toYaml(expandedClaim);
|
|
164628
|
+
VisitedClaims[`${kind}-${name}`] = 'virtual';
|
|
164629
|
+
}
|
|
164630
|
+
|
|
164631
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/claimsDefaulter.ts
|
|
164632
|
+
|
|
164633
|
+
|
|
164634
|
+
|
|
164635
|
+
/*
|
|
164636
|
+
* Default blocks are objects that cannot be merged but applied as a whole. Meaning:
|
|
164637
|
+
* - If the object is defined at the claim-level it is maintained *AS IT IS* (no merge)
|
|
164638
|
+
* - If the block is missing at the claim-level, the default block is applied
|
|
164639
|
+
*/
|
|
164640
|
+
const defaultBlocksPaths = ['/providers/terraform/sync'];
|
|
164641
|
+
function applyBlockAwareDefaults(claim, defaultClaim) {
|
|
164642
|
+
// we always work with a clone of the original
|
|
164643
|
+
const claimClone = JSON.parse(JSON.stringify(claim));
|
|
164644
|
+
// if the block is claim-level defined we store it here
|
|
164645
|
+
const defaultBlocks = new Map();
|
|
164646
|
+
// we remove the blocks entirely of the claim
|
|
164647
|
+
// to achieve an add copy
|
|
164648
|
+
for (const defaultBlockPath of defaultBlocksPaths) {
|
|
164649
|
+
if (claimsDefaulter_hasDeepPath(claimClone, defaultBlockPath) !== true)
|
|
164650
|
+
continue;
|
|
164651
|
+
const originalValue = fast_json_patch_default().getValueByPointer(claimClone, defaultBlockPath);
|
|
164652
|
+
if (originalValue) {
|
|
164653
|
+
logger.silly(`${claim.kind}/${claim.name}: has an original ${defaultBlockPath}: preserving`);
|
|
164654
|
+
defaultBlocks.set(defaultBlockPath, originalValue);
|
|
164655
|
+
fast_json_patch_default().applyPatch(claimClone, [{ op: 'remove', path: defaultBlockPath }]);
|
|
164656
|
+
}
|
|
164657
|
+
}
|
|
164658
|
+
// if the patch has the same path of a block
|
|
164659
|
+
// and the block was defined at claim-level
|
|
164660
|
+
// we interchange the value with the original value
|
|
164661
|
+
// otherwise we use the default
|
|
164662
|
+
const jsonPatchOps = fast_json_patch_default().compare(claimClone, defaultClaim)
|
|
164663
|
+
.filter((jp) => jp.op === 'add')
|
|
164664
|
+
.map((jp) => {
|
|
164665
|
+
if (defaultBlocks.has(jp.path)) {
|
|
164666
|
+
return {
|
|
164667
|
+
...jp,
|
|
164668
|
+
value: defaultBlocks.get(jp.path),
|
|
164669
|
+
};
|
|
164670
|
+
}
|
|
164671
|
+
else {
|
|
164672
|
+
return jp;
|
|
164673
|
+
}
|
|
164674
|
+
});
|
|
164675
|
+
return fast_json_patch_default().applyPatch(claimClone, jsonPatchOps).newDocument;
|
|
164676
|
+
}
|
|
164677
|
+
function claimsDefaulter_hasDeepPath(data, deepPath) {
|
|
164678
|
+
return lodash_default().has(data, deepPath.replace(/\//g, '.').replace(/^\./, ''));
|
|
164679
|
+
}
|
|
164680
|
+
|
|
164681
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/loader.ts
|
|
164682
|
+
|
|
164683
|
+
|
|
164684
|
+
|
|
164685
|
+
|
|
164686
|
+
|
|
164687
|
+
|
|
164688
|
+
|
|
164689
|
+
|
|
164690
|
+
|
|
164691
|
+
|
|
164692
|
+
|
|
164693
|
+
|
|
164694
|
+
|
|
164695
|
+
|
|
164696
|
+
|
|
164697
|
+
const isYamlFile = new RegExp(/\.(yaml|yml)$/);
|
|
164698
|
+
/**
|
|
164699
|
+
*
|
|
164700
|
+
* @returns Virtual Claims
|
|
164701
|
+
*/
|
|
164702
|
+
const virtualClaims = [new FirestartrAllClaim()];
|
|
164703
|
+
/*
|
|
164704
|
+
* Loads all applicable globals for a given claim and stores them into a list.
|
|
164705
|
+
*
|
|
164706
|
+
* Input:
|
|
164707
|
+
* - claim: our custom claim object, with which we check if the global is applicable
|
|
164708
|
+
*
|
|
164709
|
+
* Returns:
|
|
164710
|
+
* - A GlobalSection array promise, containing all the globals loaded for this claim
|
|
164711
|
+
*
|
|
164712
|
+
*/
|
|
164713
|
+
async function loadGlobals(claim) {
|
|
164714
|
+
const result = [];
|
|
164715
|
+
await crawl(getPath('globals'), (entry) => {
|
|
164716
|
+
return isYamlFile.test(entry);
|
|
164717
|
+
}, async (entry, data) => {
|
|
164718
|
+
const globalData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
|
|
164719
|
+
const ext = external_path_.extname(entry);
|
|
164720
|
+
const name = external_path_.basename(entry, ext);
|
|
164721
|
+
if (name in SECTIONS_BY_FILE_NAME) {
|
|
164722
|
+
const section = new SECTIONS_BY_FILE_NAME[name](globalData);
|
|
164723
|
+
if (!(await section.validate(SCHEMAS_BY_SECTION_NAME[name] || {}))) {
|
|
164724
|
+
throw new Error(`Invalid ${name} global file`);
|
|
164725
|
+
}
|
|
164726
|
+
if (globalData.kind === claim.kind) {
|
|
164727
|
+
result.push(section);
|
|
164728
|
+
}
|
|
164729
|
+
else {
|
|
164730
|
+
logger.debug(`Skipping global ${name} because it is not applicable to ${claim.kind}`);
|
|
164731
|
+
}
|
|
164732
|
+
}
|
|
164733
|
+
});
|
|
164734
|
+
logger.info(`Loaded globals ${result}`);
|
|
164735
|
+
return result;
|
|
164736
|
+
}
|
|
164737
|
+
/*
|
|
164738
|
+
* If the input claim is a GithubRepositoryClaim, it loads all it's applicable
|
|
164739
|
+
* overrides and stores them into a list. Otherwise, it returns an empty list.
|
|
164740
|
+
*
|
|
164741
|
+
* Input:
|
|
164742
|
+
* - claim: our custom claim object, which should be a GithubRepositoryClaim
|
|
164743
|
+
*
|
|
164744
|
+
* Returns:
|
|
164745
|
+
* - An Overrider array, with a GithubRepositoryOverrider if the claim
|
|
164746
|
+
* was a GithubRepositoryClaim, or empty if it was not.
|
|
164747
|
+
*
|
|
164748
|
+
*/
|
|
164749
|
+
function loadOverrides(claim) {
|
|
164750
|
+
const overrides = [];
|
|
164751
|
+
if (claim.kind === 'ComponentClaim' && claim.providers.github.overrides) {
|
|
164752
|
+
overrides.push(new GithubRepositoryOverrider());
|
|
164753
|
+
}
|
|
164754
|
+
return overrides;
|
|
164755
|
+
}
|
|
164756
|
+
/**
|
|
164757
|
+
* Load all normalizers and stores them into a list.
|
|
164758
|
+
* @param claim
|
|
164759
|
+
* @returns
|
|
164760
|
+
*/
|
|
164761
|
+
async function loadNormalizers(_claim, path) {
|
|
164762
|
+
const result = [];
|
|
164763
|
+
for (const normalizer of NORMALIZERS) {
|
|
164764
|
+
result.push(new normalizer({ path: path }));
|
|
164765
|
+
}
|
|
164766
|
+
return result;
|
|
164767
|
+
}
|
|
164768
|
+
/*
|
|
164769
|
+
* Loads all applicable initializers for a given claim and stores them into a list.
|
|
164770
|
+
*
|
|
164771
|
+
* Input:
|
|
164772
|
+
* - claim: our custom claim object, with which we check if the initializer is applicable
|
|
164773
|
+
*
|
|
164774
|
+
* Returns:
|
|
164775
|
+
* - An Initializer array promise, containing all the initializers loaded for this claim
|
|
164776
|
+
*
|
|
164777
|
+
*/
|
|
164778
|
+
let loadedInitializers = false;
|
|
164779
|
+
async function loadInitializers(claim, claimPath, initializersPath = getPath('initializers')) {
|
|
164780
|
+
const result = [];
|
|
164781
|
+
await crawl(initializersPath, (entry) => {
|
|
164782
|
+
return isYamlFile.test(entry);
|
|
164783
|
+
}, async (entry, data) => {
|
|
164784
|
+
const initializerData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
|
|
164785
|
+
const ext = external_path_.extname(entry);
|
|
164786
|
+
const name = external_path_.basename(entry, ext);
|
|
164787
|
+
if (name in INITIALIZERS_BY_FILE_NAME) {
|
|
164788
|
+
const initializerBfN = new INITIALIZERS_BY_FILE_NAME[name](initializerData);
|
|
164789
|
+
if (!(await initializerBfN.validate(SCHEMAS_BY_INITIALIZER_NAME[name] || {}))) {
|
|
164790
|
+
throw new Error(`Invalid ${name} initializer file`);
|
|
164791
|
+
}
|
|
164792
|
+
if (initializerData.kind === claim.kind) {
|
|
164793
|
+
result.push(initializerBfN);
|
|
164794
|
+
}
|
|
164795
|
+
else {
|
|
164796
|
+
logger.debug(`Skipping initializer ${name} because it is not applicable to ${claim.kind}`);
|
|
164797
|
+
}
|
|
164798
|
+
}
|
|
164799
|
+
});
|
|
164800
|
+
for (const initializer of INITIALIZERS) {
|
|
164801
|
+
if (initializer.applicableKinds.includes(claim.kind)) {
|
|
164802
|
+
result.push(new initializer({ path: claimPath }));
|
|
164803
|
+
}
|
|
164804
|
+
}
|
|
164805
|
+
logger.info(`Loaded initializers ${JSON.stringify(result)}`);
|
|
164806
|
+
loadedInitializers = result;
|
|
164807
|
+
return loadedInitializers;
|
|
164808
|
+
}
|
|
164809
|
+
function loadClaimDefaults() {
|
|
164810
|
+
try {
|
|
164811
|
+
return catalog_common/* default.io.fromYaml */.Z.io.fromYaml(external_fs_.readFileSync(`${getPath('claimsDefaults')}/claims_defaults.yaml`, 'utf-8'));
|
|
164812
|
+
}
|
|
164813
|
+
catch (error) {
|
|
164814
|
+
const errMsg = `Could not read claims defaults file in path ${getPath('claimsDefaults')}/claims_defaults.yaml: ${error}`;
|
|
164815
|
+
logger.error(errMsg);
|
|
164816
|
+
throw new Error(errMsg);
|
|
164817
|
+
}
|
|
164818
|
+
}
|
|
164819
|
+
/*
|
|
164820
|
+
* Using fast-json-patch, compares a claim to its kind's defaults, then patches it.
|
|
164821
|
+
*
|
|
164822
|
+
* Input:
|
|
164823
|
+
* - claim: our custom claim object, which we want to patch
|
|
164824
|
+
* - defaultsClaims: an object, containing the defaults for each claim kind,
|
|
164825
|
+
* with the same structure that we use for the actual claims
|
|
164826
|
+
*
|
|
164827
|
+
* Returns:
|
|
164828
|
+
* - The patched claim
|
|
164829
|
+
*
|
|
164830
|
+
*/
|
|
164831
|
+
function loader_patchClaim(claim, defaultsClaims) {
|
|
164832
|
+
if (defaultsClaims[claim.kind]) {
|
|
164833
|
+
claim = applyBlockAwareDefaults(claim, defaultsClaims[claim.kind]);
|
|
164834
|
+
}
|
|
164835
|
+
return claim;
|
|
164836
|
+
}
|
|
164837
|
+
async function loadCRsWithFullSet(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
|
|
164838
|
+
const result = {};
|
|
164839
|
+
const fullResult = {};
|
|
164840
|
+
await crawlWithExclusions(crsPath, (entry) => {
|
|
164841
|
+
return isYamlFile.test(entry);
|
|
164842
|
+
}, async (entry, data) => {
|
|
164843
|
+
const yamlData = stripKnownRelations(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data));
|
|
164844
|
+
const metadata = yamlData?.metadata;
|
|
164845
|
+
if (!(yamlData &&
|
|
164846
|
+
typeof yamlData === 'object' &&
|
|
164847
|
+
'kind' in yamlData &&
|
|
164848
|
+
metadata &&
|
|
164849
|
+
typeof metadata === 'object' &&
|
|
164850
|
+
'name' in metadata)) {
|
|
164851
|
+
logger.warn(`Invalid CR file ${entry}`);
|
|
164852
|
+
}
|
|
164853
|
+
else {
|
|
164854
|
+
const crKey = `${yamlData.kind}-${metadata.name}`;
|
|
164855
|
+
if (fullResult[crKey]) {
|
|
164856
|
+
logger.error(`Duplicate CR ${crKey}`);
|
|
164857
|
+
}
|
|
164858
|
+
// Keep the complete CR set for validations that need repository-wide context.
|
|
164859
|
+
fullResult[crKey] = yamlData;
|
|
164860
|
+
// Keep the filtered CR set for previous-CR lookup during claim rendering.
|
|
164861
|
+
if (allowedClaimReferences.length === 0 ||
|
|
164862
|
+
allowedClaimReferences.includes(yamlData.metadata?.annotations?.[catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('claim-ref')])) {
|
|
164863
|
+
result[crKey] = yamlData;
|
|
164864
|
+
}
|
|
164865
|
+
}
|
|
164866
|
+
}, excludedPaths.concat(getAdditionalPaths()));
|
|
164867
|
+
return { crs: result, fullCrs: fullResult };
|
|
164868
|
+
}
|
|
164869
|
+
async function loadCRs(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
|
|
164870
|
+
const { crs } = await loadCRsWithFullSet(crsPath, excludedPaths, allowedClaimReferences);
|
|
164871
|
+
return crs;
|
|
164872
|
+
}
|
|
164873
|
+
/*
|
|
164874
|
+
* Description: Get the renamed using claimRef annotation
|
|
164875
|
+
* Input: claims: any, crs: any
|
|
164876
|
+
* Output: renames: IRenameResult[]
|
|
164877
|
+
*/
|
|
164878
|
+
async function loadRenames(claims, crs) {
|
|
164879
|
+
/*
|
|
164880
|
+
* If checkRenames is false, we don't need to check for renames
|
|
164881
|
+
*/
|
|
164882
|
+
const renamesEnabled = getRenamesEnabled();
|
|
164883
|
+
if (!renamesEnabled)
|
|
164884
|
+
return [];
|
|
164885
|
+
const result = [];
|
|
164886
|
+
/**
|
|
164887
|
+
* For each CR, look for a claim that does not match the name with CR's firestartr.dev/claim-ref annotation
|
|
164888
|
+
*/
|
|
164889
|
+
for (const cr of Object.values(crs)) {
|
|
164890
|
+
const anyCr = cr;
|
|
164891
|
+
if (!anyCr?.metadata?.annotations)
|
|
164892
|
+
continue;
|
|
164893
|
+
// if the annotation is a claimRef
|
|
164894
|
+
const annotationName = common.generic.getFirestartrAnnotation('claim-ref');
|
|
164895
|
+
const annotations = anyCr?.metadata?.annotations || {};
|
|
164896
|
+
if (annotationName in annotations) {
|
|
164897
|
+
const claimRef = anyCr.metadata.annotations[annotationName];
|
|
164898
|
+
// split the annotation into kind and name
|
|
164899
|
+
const [kind, name] = claimRef.split('/');
|
|
164900
|
+
// if the claim exists, check if the name is different for the given provider
|
|
164901
|
+
const referencedClaim = claims[`${kind}-${name}`].claim;
|
|
164902
|
+
const oldName = anyCr.metadata.name;
|
|
164903
|
+
const newName = referencedClaim.providers[getConfiguredProvider()].name;
|
|
164904
|
+
if (oldName !== newName) {
|
|
164905
|
+
result.push({
|
|
164906
|
+
kind: referencedClaim.kind,
|
|
164907
|
+
claimPath: claims[`${kind}-${name}`].claimPath,
|
|
164908
|
+
claimName: referencedClaim.name,
|
|
164909
|
+
oldName,
|
|
164910
|
+
newName,
|
|
164911
|
+
});
|
|
164912
|
+
}
|
|
164913
|
+
}
|
|
164914
|
+
}
|
|
164915
|
+
return result;
|
|
164916
|
+
}
|
|
164917
|
+
async function loadClaimsList(claimRefList, claimsPath = getPath('claims')) {
|
|
164918
|
+
const data = {
|
|
164919
|
+
renderClaims: {},
|
|
164920
|
+
crs: {},
|
|
164921
|
+
fullCrs: {},
|
|
164922
|
+
};
|
|
164923
|
+
const defaults = loadClaimDefaults();
|
|
164924
|
+
for await (const claimRef of claimRefList) {
|
|
164925
|
+
const [renderedClaimData] = await loadClaim(claimRef, getOrg(), defaults, loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, claimsPath);
|
|
164926
|
+
data.renderClaims = lodash_default().merge(data.renderClaims, renderedClaimData);
|
|
164927
|
+
}
|
|
164928
|
+
const crClaimReferences = [];
|
|
164929
|
+
for (const ref of Object.keys(data.renderClaims)) {
|
|
164930
|
+
// Replaces only the first instance of '-'
|
|
164931
|
+
crClaimReferences.push(ref.replace('-', '/'));
|
|
164932
|
+
}
|
|
164933
|
+
const loadedCrs = await loadCRsWithFullSet(getPath('crs'), [getPath('globals'), getPath('initializers')], crClaimReferences);
|
|
164934
|
+
data['crs'] = loadedCrs.crs;
|
|
164935
|
+
data['fullCrs'] = loadedCrs.fullCrs;
|
|
164936
|
+
return data;
|
|
164937
|
+
}
|
|
164938
|
+
function getOrg() {
|
|
164939
|
+
const groupOrg = catalog_common/* default.environment.getFromEnvironmentWithDefault */.Z.environment.getFromEnvironmentWithDefault(catalog_common/* default.types.envVars.org */.Z.types.envVars.org, '');
|
|
164940
|
+
return groupOrg;
|
|
164941
|
+
}
|
|
164942
|
+
|
|
164943
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/references.ts
|
|
164944
|
+
function validateTfStateKeyUniqueness(crs) {
|
|
164945
|
+
const tfStateKeys = {};
|
|
164946
|
+
for (const crKey of Object.keys(crs)) {
|
|
164947
|
+
const cr = crs[crKey];
|
|
164948
|
+
if (!isTerraformWorkspace(cr))
|
|
164949
|
+
continue;
|
|
164950
|
+
const tfKey = cr.spec.firestartr.tfStateKey;
|
|
164951
|
+
if (tfStateKeys[tfKey]) {
|
|
164952
|
+
throw new Error(`❗❗ ❌ RENDER ERROR ❌ ❗❗
|
|
164953
|
+
|
|
164954
|
+
The tfStateKey ${tfKey} is not unique,
|
|
164955
|
+
|
|
164956
|
+
It is being used by the following CRs:
|
|
164957
|
+
|
|
164958
|
+
- ${tfStateKeys[tfKey].kind} ${tfStateKeys[tfKey].metadata.name}
|
|
164959
|
+
|
|
164960
|
+
- ${cr.kind} ${cr.metadata.name}
|
|
164961
|
+
|
|
164962
|
+
Check the following Claims to ensure that the tfStateKey is unique:
|
|
164963
|
+
|
|
164964
|
+
- ${tfStateKeys[tfKey].metadata.annotations['firestartr.dev/claim-ref']}
|
|
164965
|
+
|
|
164966
|
+
- ${cr.metadata.annotations['firestartr.dev/claim-ref']}
|
|
164967
|
+
`);
|
|
164968
|
+
}
|
|
164969
|
+
tfStateKeys[cr.spec.firestartr.tfStateKey] = cr;
|
|
164970
|
+
}
|
|
164971
|
+
}
|
|
164972
|
+
function references_isCatalogEntity(cr) {
|
|
164973
|
+
return [
|
|
164974
|
+
'Component',
|
|
164975
|
+
'Domain',
|
|
164976
|
+
'System',
|
|
164977
|
+
'User',
|
|
164978
|
+
'Group',
|
|
164979
|
+
'Resource',
|
|
164980
|
+
].includes(cr.kind);
|
|
164981
|
+
}
|
|
164982
|
+
function isTerraformWorkspace(cr) {
|
|
164983
|
+
return cr.kind === 'FirestartrTerraformWorkspace';
|
|
164984
|
+
}
|
|
164985
|
+
|
|
164986
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/crSize.ts
|
|
164987
|
+
|
|
164988
|
+
const K8S_OBJECT_SIZE_LIMIT = 1572864; // 1.5 MiB in bytes, etcd recommended limit: https://etcd.io/docs/latest/dev-guide/limit/
|
|
164989
|
+
function validateCrSizes(crs) {
|
|
164990
|
+
for (const key of Object.keys(crs)) {
|
|
164991
|
+
const cr = crs[key];
|
|
164992
|
+
const serialized = catalog_common/* default.io.toYaml */.Z.io.toYaml(cr);
|
|
164993
|
+
const size = Buffer.byteLength(serialized, 'utf8');
|
|
164994
|
+
if (size > K8S_OBJECT_SIZE_LIMIT) {
|
|
164995
|
+
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).`);
|
|
164996
|
+
}
|
|
164997
|
+
}
|
|
164998
|
+
}
|
|
164999
|
+
|
|
165000
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/permissions.ts
|
|
165001
|
+
|
|
165002
|
+
function validatePermissionsUniqueness(crs) {
|
|
165003
|
+
for (const crkey in crs) {
|
|
165004
|
+
const cr = crs[crkey];
|
|
165005
|
+
if (cr.kind === 'FirestartrGithubRepository') {
|
|
165006
|
+
const permissions = cr.spec.permissions;
|
|
165007
|
+
logger.debug(`Validating Permissions Uniqueness of ${crkey}`);
|
|
165008
|
+
if (permissions) {
|
|
165009
|
+
const rolesByIdentifier = new Map();
|
|
165010
|
+
for (const perm of permissions) {
|
|
165011
|
+
const identifier = perm.collaborator
|
|
165012
|
+
? perm.collaborator
|
|
165013
|
+
: `ref:${perm.ref.kind}:${perm.ref.name}`;
|
|
165014
|
+
const role = perm.role;
|
|
165015
|
+
const prevRole = rolesByIdentifier.get(identifier);
|
|
165016
|
+
if (prevRole === undefined) {
|
|
165017
|
+
rolesByIdentifier.set(identifier, role);
|
|
165018
|
+
}
|
|
165019
|
+
else if (prevRole !== role) {
|
|
165020
|
+
throw new Error(`Conflicting permission role in FirestartrGithubRepository ${crkey}: ${identifier} has roles "${prevRole}" and "${role}".\nFull CR: ${JSON.stringify(cr, null, 2)}`);
|
|
165021
|
+
}
|
|
165022
|
+
}
|
|
165023
|
+
}
|
|
165024
|
+
}
|
|
165025
|
+
}
|
|
165026
|
+
}
|
|
165027
|
+
|
|
165028
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/backstageAnnotations.ts
|
|
165029
|
+
const backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX = 'firestartr.backstage.dev/';
|
|
165030
|
+
const CATALOG_KINDS = new Set([
|
|
165031
|
+
'User',
|
|
165032
|
+
'Group',
|
|
165033
|
+
'Component',
|
|
165034
|
+
'System',
|
|
165035
|
+
'Domain',
|
|
165036
|
+
'API',
|
|
165037
|
+
'Resource',
|
|
165038
|
+
'CatalogKubernetesResource',
|
|
165039
|
+
'CatalogTerraformWorkspace',
|
|
165040
|
+
'CatalogArgoDeploy',
|
|
165041
|
+
'CatalogOrgWebhook',
|
|
165042
|
+
'CatalogSecrets',
|
|
165043
|
+
]);
|
|
165044
|
+
function validateNoBackstageAnnotationsInK8sCrs(crs) {
|
|
165045
|
+
for (const crKey in crs) {
|
|
165046
|
+
const cr = crs[crKey];
|
|
165047
|
+
if (CATALOG_KINDS.has(cr.kind))
|
|
165048
|
+
continue;
|
|
165049
|
+
if (cr.metadata?.annotations) {
|
|
165050
|
+
const backstageKeys = Object.keys(cr.metadata.annotations).filter((k) => k.startsWith(backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX));
|
|
165051
|
+
if (backstageKeys.length > 0) {
|
|
165052
|
+
throw new Error(`K8s CR ${crKey} contains Backstage-only annotations (${backstageKeys.join(', ')}). ` +
|
|
165053
|
+
`Annotations with prefix ${backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX} must only appear on Backstage catalog entities, not on Kubernetes CRs.`);
|
|
165054
|
+
}
|
|
165055
|
+
}
|
|
165056
|
+
}
|
|
165057
|
+
}
|
|
165058
|
+
|
|
165059
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/refsSorter/refsSorter.ts
|
|
165060
|
+
|
|
165061
|
+
/**
|
|
165062
|
+
* @param renderClaims renderClaims to sort
|
|
165063
|
+
* @param kinds kinds to get from renderClaims
|
|
165064
|
+
* @returns renderClaims with only the kinds specified
|
|
165065
|
+
*/
|
|
165066
|
+
function sortRenderClaimsByKind(renderClaims, kinds) {
|
|
165067
|
+
let result = {};
|
|
165068
|
+
for (const kind of kinds) {
|
|
165069
|
+
for (const key in renderClaims) {
|
|
165070
|
+
if (renderClaims[key].claim.kind === kind) {
|
|
165071
|
+
result[key] = renderClaims[key];
|
|
165072
|
+
}
|
|
165073
|
+
}
|
|
165074
|
+
result = sortSelfKindRefs(result, kind);
|
|
165075
|
+
}
|
|
165076
|
+
return result;
|
|
165077
|
+
}
|
|
165078
|
+
function sortSelfKindRefs(renderClaims, kind) {
|
|
165079
|
+
if (!hasSelfRefs(kind)) {
|
|
165080
|
+
return renderClaims;
|
|
165081
|
+
}
|
|
165082
|
+
const newRenderClaims = {};
|
|
165083
|
+
const data = extractRefs(renderClaims, kind);
|
|
165084
|
+
const ordered = [];
|
|
165085
|
+
const visiting = [];
|
|
165086
|
+
const visited = [];
|
|
165087
|
+
for (const key of Object.keys(data)) {
|
|
165088
|
+
if (!visited.find((obj) => obj.name === key)) {
|
|
165089
|
+
sortRefs(data, data[key], ordered, visiting, visited);
|
|
165090
|
+
}
|
|
165091
|
+
}
|
|
165092
|
+
for (const cr of ordered) {
|
|
165093
|
+
newRenderClaims[cr.name] = renderClaims[cr.name];
|
|
165094
|
+
}
|
|
165095
|
+
return newRenderClaims;
|
|
165096
|
+
}
|
|
165097
|
+
function sortRefs(data, claim, ordered = [], visiting = [], visited = []) {
|
|
165098
|
+
if (visiting.find((obj) => obj.name === claim.name)) {
|
|
165099
|
+
throw new Error(`Circular dependency detected for '${claim.name}'`);
|
|
165100
|
+
}
|
|
165101
|
+
if (!visited.find((obj) => obj.name === claim.name)) {
|
|
165102
|
+
visiting.push(claim);
|
|
165103
|
+
if (claim.refs) {
|
|
165104
|
+
for (const ref of claim.refs) {
|
|
165105
|
+
const referencedObject = data[ref];
|
|
165106
|
+
if (!referencedObject) {
|
|
165107
|
+
throw new Error(`Reference '${ref}' does not exist for '${claim.name}'`);
|
|
165108
|
+
}
|
|
165109
|
+
sortRefs(data, referencedObject, ordered, visiting, visited);
|
|
165110
|
+
}
|
|
165111
|
+
}
|
|
165112
|
+
visited.push(visiting.pop());
|
|
165113
|
+
ordered.push(claim);
|
|
165114
|
+
}
|
|
165115
|
+
}
|
|
165116
|
+
function hasSelfRefs(kind) {
|
|
165117
|
+
return ['TFWorkspaceClaim', 'GroupClaim'].includes(kind);
|
|
165118
|
+
}
|
|
165119
|
+
|
|
165120
|
+
;// CONCATENATED MODULE: ../cdk8s_renderer/src/renderer/claims-sorter.ts
|
|
165121
|
+
|
|
165122
|
+
function sortKinds(orderedKinds, claims) {
|
|
165123
|
+
const result = [];
|
|
165124
|
+
for (const kind of orderedKinds) {
|
|
165125
|
+
const kindRenderClaims = sortRenderClaimsByKind(claims, [kind]);
|
|
165126
|
+
result.push(kindRenderClaims);
|
|
165127
|
+
}
|
|
165128
|
+
return result;
|
|
165129
|
+
}
|
|
165130
|
+
|
|
164366
165131
|
;// CONCATENATED MODULE: ../features_renderer/src/common.ts
|
|
164367
165132
|
|
|
164368
165133
|
function isDirectory(path) {
|
|
@@ -164403,9 +165168,14 @@ var ajv_default = /*#__PURE__*/__nccwpck_require__.n(dist_ajv);
|
|
|
164403
165168
|
},
|
|
164404
165169
|
},
|
|
164405
165170
|
patches: {
|
|
164406
|
-
type: '
|
|
164407
|
-
|
|
164408
|
-
|
|
165171
|
+
type: 'object',
|
|
165172
|
+
patternProperties: {
|
|
165173
|
+
'^.+$': {
|
|
165174
|
+
type: 'array',
|
|
165175
|
+
items: {
|
|
165176
|
+
$ref: '#/definitions/Patch',
|
|
165177
|
+
},
|
|
165178
|
+
},
|
|
164409
165179
|
},
|
|
164410
165180
|
},
|
|
164411
165181
|
filesTemplates: {
|
|
@@ -164508,7 +165278,7 @@ var ajv_default = /*#__PURE__*/__nccwpck_require__.n(dist_ajv);
|
|
|
164508
165278
|
type: 'string',
|
|
164509
165279
|
},
|
|
164510
165280
|
value: {
|
|
164511
|
-
type:
|
|
165281
|
+
type: 'string',
|
|
164512
165282
|
},
|
|
164513
165283
|
},
|
|
164514
165284
|
required: ['name', 'op', 'path'],
|
|
@@ -164550,12 +165320,6 @@ function __validateFeatureConfig(featurePath) {
|
|
|
164550
165320
|
}
|
|
164551
165321
|
}
|
|
164552
165322
|
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
|
-
}
|
|
164559
165323
|
const ajv = new (ajv_default())({
|
|
164560
165324
|
allowUnionTypes: true,
|
|
164561
165325
|
});
|
|
@@ -164577,12 +165341,14 @@ function stripAnchoringConstraints(schemaDef) {
|
|
|
164577
165341
|
return clone;
|
|
164578
165342
|
}
|
|
164579
165343
|
function __validateJsonPatches(configData) {
|
|
164580
|
-
const
|
|
164581
|
-
|
|
164582
|
-
|
|
164583
|
-
|
|
164584
|
-
|
|
164585
|
-
|
|
165344
|
+
const keys = Object.keys(configData.patches);
|
|
165345
|
+
for (const key of keys) {
|
|
165346
|
+
if (configData.patches[key]) {
|
|
165347
|
+
if (fast_json_patch_default().validate(configData.patches[key])) {
|
|
165348
|
+
const errors = JSON.stringify(fast_json_patch_default().validate(configData.patches[key]).message);
|
|
165349
|
+
throw `Feature: config.yaml -> patches: invalid patches ${errors}`;
|
|
165350
|
+
}
|
|
165351
|
+
}
|
|
164586
165352
|
}
|
|
164587
165353
|
}
|
|
164588
165354
|
|
|
@@ -165420,12 +166186,10 @@ const renderTestsSchema = {
|
|
|
165420
166186
|
items: {
|
|
165421
166187
|
type: 'object',
|
|
165422
166188
|
additionalProperties: false,
|
|
165423
|
-
required: ['name'],
|
|
165424
|
-
anyOf: [{ required: ['cr'] }, { required: ['claim'] }],
|
|
166189
|
+
required: ['name', 'cr'],
|
|
165425
166190
|
properties: {
|
|
165426
166191
|
name: { type: 'string', minLength: 1 },
|
|
165427
166192
|
cr: { type: 'string', minLength: 1 },
|
|
165428
|
-
claim: { type: 'string', minLength: 1 },
|
|
165429
166193
|
args: { type: 'object' },
|
|
165430
166194
|
},
|
|
165431
166195
|
},
|
|
@@ -165480,9 +166244,6 @@ function resolveCrPath(featurePath, crRelPath) {
|
|
|
165480
166244
|
}
|
|
165481
166245
|
return resolved;
|
|
165482
166246
|
}
|
|
165483
|
-
function resolveClaimPath(featurePath, claimRelPath) {
|
|
165484
|
-
return resolveCrPath(featurePath, claimRelPath);
|
|
165485
|
-
}
|
|
165486
166247
|
function listYamlFiles(dir) {
|
|
165487
166248
|
if (!fs.existsSync(dir))
|
|
165488
166249
|
return [];
|
|
@@ -165600,7 +166361,6 @@ async function createRenderContext(prefix = 'feature-render-') {
|
|
|
165600
166361
|
buildExpectedOutput,
|
|
165601
166362
|
loadAndValidateRenderTests,
|
|
165602
166363
|
resolveCrPath,
|
|
165603
|
-
resolveClaimPath,
|
|
165604
166364
|
});
|
|
165605
166365
|
|
|
165606
166366
|
;// CONCATENATED MODULE: ../features_renderer/src/featureArgsValidation.ts
|
|
@@ -165724,97 +166484,19 @@ function render(featurePath, featureRenderPath, entity, firestartrConfig = {}, f
|
|
|
165724
166484
|
external_fs_default().writeFileSync(configFile, JSON.stringify(output));
|
|
165725
166485
|
return output;
|
|
165726
166486
|
}
|
|
165727
|
-
function
|
|
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) {
|
|
166487
|
+
function buildContext(entity, args, firestartrConfig, featureArgs) {
|
|
165735
166488
|
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
|
-
};
|
|
165807
166489
|
Object.entries(args).forEach(([key, arg]) => {
|
|
165808
166490
|
if ('$default' in arg) {
|
|
165809
166491
|
if (Array.isArray(arg['$default'])) {
|
|
165810
|
-
context[key] =
|
|
166492
|
+
context[key] = lodash_default().get(entity, arg['$default']);
|
|
165811
166493
|
}
|
|
165812
166494
|
else {
|
|
165813
166495
|
context[key] = arg['$default'];
|
|
165814
166496
|
}
|
|
165815
166497
|
}
|
|
165816
166498
|
if ('$ref' in arg) {
|
|
165817
|
-
const refValue =
|
|
166499
|
+
const refValue = lodash_default().get(entity, arg['$ref']);
|
|
165818
166500
|
context[key] = refValue;
|
|
165819
166501
|
}
|
|
165820
166502
|
else if ('$lit' in arg) {
|
|
@@ -165944,7 +166626,6 @@ function updateFileContent(featureRenderPath, filePath, content) {
|
|
|
165944
166626
|
|
|
165945
166627
|
|
|
165946
166628
|
|
|
165947
|
-
|
|
165948
166629
|
/* harmony default export */ const features_renderer = ({
|
|
165949
166630
|
validate: validate,
|
|
165950
166631
|
render: render,
|
|
@@ -165954,7 +166635,6 @@ function updateFileContent(featureRenderPath, filePath, content) {
|
|
|
165954
166635
|
renderContent: renderContent,
|
|
165955
166636
|
expandFiles: expandFiles,
|
|
165956
166637
|
validateFeatureArgs: validateFeatureArgs,
|
|
165957
|
-
getPatches: getPatches,
|
|
165958
166638
|
});
|
|
165959
166639
|
|
|
165960
166640
|
;// CONCATENATED MODULE: ../features_preparer/src/logger.ts
|
|
@@ -165979,13 +166659,6 @@ function renderFeature(featureName, version, owner, repo, featureOwner, renderPa
|
|
|
165979
166659
|
function renderFeatureFromPath(extractPath, renderedPath, featureOwner, featureArgs = {}) {
|
|
165980
166660
|
return features_renderer.render(extractPath, renderedPath, featureOwner, {}, featureArgs);
|
|
165981
166661
|
}
|
|
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
|
-
}
|
|
165989
166662
|
|
|
165990
166663
|
// EXTERNAL MODULE: ../../node_modules/adm-zip/adm-zip.js
|
|
165991
166664
|
var adm_zip = __nccwpck_require__(7993);
|
|
@@ -166046,26 +166719,6 @@ featureArgs = {}, repo = 'features', owner = 'prefapp') {
|
|
|
166046
166719
|
};
|
|
166047
166720
|
return renderFeature(featureName, reference, owner, repo, featureOwner, '/tmp', featureArgs);
|
|
166048
166721
|
}
|
|
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
|
-
}
|
|
166069
166722
|
async function prepareFeature(featureName, version, repo = 'features', owner = 'prefapp') {
|
|
166070
166723
|
await downloadFeatureZip(repo, featureName, version, owner);
|
|
166071
166724
|
}
|
|
@@ -166120,9 +166773,6 @@ async function downloadFeatureZip(repo, featureName, reference, owner = 'prefapp
|
|
|
166120
166773
|
/* harmony default export */ const src = ({
|
|
166121
166774
|
renderFeature: renderFeature,
|
|
166122
166775
|
renderFeatureFromPath: renderFeatureFromPath,
|
|
166123
|
-
getFeaturePatches: installer_getFeaturePatches,
|
|
166124
|
-
getFeaturePatchesFromRef: getFeaturePatchesFromRef,
|
|
166125
|
-
getFeaturePatchesFromPath: getFeaturePatchesFromPath,
|
|
166126
166776
|
getFeatureConfigFromRef: getFeatureConfigFromRef,
|
|
166127
166777
|
getFeatureConfig: getFeatureConfig,
|
|
166128
166778
|
prepareFeature: prepareFeature,
|
|
@@ -166139,1118 +166789,6 @@ async function downloadFeatureZip(repo, featureName, reference, owner = 'prefapp
|
|
|
166139
166789
|
getFeatureConfigFromRef: src.getFeatureConfigFromRef,
|
|
166140
166790
|
});
|
|
166141
166791
|
|
|
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 is silently deduplicated (or errors if values differ).
|
|
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
|
-
// Check whether an array at `appendPath`'s parent already contains an element
|
|
166252
|
-
// whose `name` matches `value.name`. Used for the "claim wins" gate: when a
|
|
166253
|
-
// feature tries to append an array element that already exists in the claim,
|
|
166254
|
-
// the patch is silently dropped.
|
|
166255
|
-
function arrayElementExists(doc, appendPath, value) {
|
|
166256
|
-
if (!isRecord(value) || typeof value.name !== 'string')
|
|
166257
|
-
return false;
|
|
166258
|
-
const parentPath = appendPath.slice(0, -2); // strip trailing /-
|
|
166259
|
-
const segments = parentPath
|
|
166260
|
-
.split('/')
|
|
166261
|
-
.slice(1)
|
|
166262
|
-
.map((s) => s.replace(/~1/g, '/').replace(/~0/g, '~'));
|
|
166263
|
-
let cur = doc;
|
|
166264
|
-
for (const seg of segments) {
|
|
166265
|
-
if (cur === null || cur === undefined || typeof cur !== 'object')
|
|
166266
|
-
return false;
|
|
166267
|
-
if (!Object.prototype.hasOwnProperty.call(cur, seg))
|
|
166268
|
-
return false;
|
|
166269
|
-
cur = cur[seg];
|
|
166270
|
-
}
|
|
166271
|
-
if (!Array.isArray(cur))
|
|
166272
|
-
return false;
|
|
166273
|
-
return cur.some((el) => isRecord(el) && el.name === value.name);
|
|
166274
|
-
}
|
|
166275
|
-
// fast-json-patch does not create intermediate containers for `add`, and
|
|
166276
|
-
// appending to an array requires the array to already exist. Ensure every
|
|
166277
|
-
// ancestor segment exists before applying an `add`: missing containers are
|
|
166278
|
-
// created as objects, except the immediate parent of a `/-` append, which is
|
|
166279
|
-
// created as an array. Existing (user/default-declared) values are never
|
|
166280
|
-
// overwritten.
|
|
166281
|
-
function ensureAddParents(doc, patch) {
|
|
166282
|
-
const segments = patch.path.split('/').slice(1);
|
|
166283
|
-
let prefix = '';
|
|
166284
|
-
for (let i = 0; i < segments.length - 1; i++) {
|
|
166285
|
-
prefix += '/' + segments[i];
|
|
166286
|
-
if (pointerExists(doc, prefix))
|
|
166287
|
-
continue;
|
|
166288
|
-
const isArrayParent = isAppendPointer(patch.path) && i === segments.length - 2;
|
|
166289
|
-
const value = isArrayParent ? [] : {};
|
|
166290
|
-
try {
|
|
166291
|
-
doc = fast_json_patch.applyPatch(doc, [{ op: 'add', path: prefix, value }], false, false).newDocument;
|
|
166292
|
-
}
|
|
166293
|
-
catch {
|
|
166294
|
-
// Concurrent structural conflict — let the actual patch surface the error.
|
|
166295
|
-
}
|
|
166296
|
-
}
|
|
166297
|
-
return doc;
|
|
166298
|
-
}
|
|
166299
|
-
async function stitchClaim(claimAfterDefaults, preCollectedEnvelopes) {
|
|
166300
|
-
const envelopes = preCollectedEnvelopes ?? (await collectFeaturePatches(claimAfterDefaults));
|
|
166301
|
-
if (envelopes.length === 0) {
|
|
166302
|
-
return claimAfterDefaults;
|
|
166303
|
-
}
|
|
166304
|
-
// Normalize all patches once so every gate and the apply phase use the same pointers.
|
|
166305
|
-
const normalizedEnvelopes = envelopes.map((env) => ({
|
|
166306
|
-
feature: env.feature,
|
|
166307
|
-
patches: env.patches.map((p) => ({
|
|
166308
|
-
...p,
|
|
166309
|
-
path: normalizePointer(p.path),
|
|
166310
|
-
_raw: p.path,
|
|
166311
|
-
})),
|
|
166312
|
-
}));
|
|
166313
|
-
// ── Phase 1: silently drop patches that should not be applied ──────────
|
|
166314
|
-
// • Array append whose element already exists in the claim → claim wins
|
|
166315
|
-
// • Duplicate identity with identical value across features → silent dedup
|
|
166316
|
-
const dropped = new Set(); // "envelopeIdx:patchIdx"
|
|
166317
|
-
const seenIdentities = new Map();
|
|
166318
|
-
for (let ei = 0; ei < normalizedEnvelopes.length; ei++) {
|
|
166319
|
-
const envelope = normalizedEnvelopes[ei];
|
|
166320
|
-
for (let pi = 0; pi < envelope.patches.length; pi++) {
|
|
166321
|
-
const patch = envelope.patches[pi];
|
|
166322
|
-
const key = `${ei}:${pi}`;
|
|
166323
|
-
// Array claim-wins: element already in claim → drop
|
|
166324
|
-
if (patch.op === 'add' && isAppendPointer(patch.path)) {
|
|
166325
|
-
if (arrayElementExists(claimAfterDefaults, patch.path, patch.value)) {
|
|
166326
|
-
dropped.add(key);
|
|
166327
|
-
continue;
|
|
166328
|
-
}
|
|
166329
|
-
}
|
|
166330
|
-
// Silent dedup: same identity + same value → drop
|
|
166331
|
-
const identity = writeIdentity(patch);
|
|
166332
|
-
const existing = seenIdentities.get(identity);
|
|
166333
|
-
if (existing) {
|
|
166334
|
-
if (JSON.stringify(existing.value) === JSON.stringify(patch.value)) {
|
|
166335
|
-
dropped.add(key);
|
|
166336
|
-
continue;
|
|
166337
|
-
}
|
|
166338
|
-
// Different value — kept here, caught as a violation in Phase 2.
|
|
166339
|
-
}
|
|
166340
|
-
else {
|
|
166341
|
-
seenIdentities.set(identity, {
|
|
166342
|
-
feature: envelope.feature,
|
|
166343
|
-
value: patch.value,
|
|
166344
|
-
});
|
|
166345
|
-
}
|
|
166346
|
-
}
|
|
166347
|
-
}
|
|
166348
|
-
// ── Phase 2: collect violations on non-dropped patches ─────────────────
|
|
166349
|
-
const violations = [];
|
|
166350
|
-
const seenForViolations = new Map(); // identity → feature
|
|
166351
|
-
for (let ei = 0; ei < normalizedEnvelopes.length; ei++) {
|
|
166352
|
-
const envelope = normalizedEnvelopes[ei];
|
|
166353
|
-
for (let pi = 0; pi < envelope.patches.length; pi++) {
|
|
166354
|
-
if (dropped.has(`${ei}:${pi}`))
|
|
166355
|
-
continue;
|
|
166356
|
-
const patch = envelope.patches[pi];
|
|
166357
|
-
const path = patch.path;
|
|
166358
|
-
const raw = patch._raw ?? path;
|
|
166359
|
-
// Gate 1: protected path
|
|
166360
|
-
if (isProtectedPath(path)) {
|
|
166361
|
-
violations.push({
|
|
166362
|
-
feature: envelope.feature,
|
|
166363
|
-
op: patch.op,
|
|
166364
|
-
path,
|
|
166365
|
-
reason: 'protected-path',
|
|
166366
|
-
message: `Feature '${envelope.feature}' patch ${patch.op} ${raw} (normalized ${path}) targets protected claim path`,
|
|
166367
|
-
});
|
|
166368
|
-
}
|
|
166369
|
-
// Gate 2: conflicting value from another feature
|
|
166370
|
-
const identity = writeIdentity(patch);
|
|
166371
|
-
if (seenForViolations.has(identity)) {
|
|
166372
|
-
violations.push({
|
|
166373
|
-
feature: envelope.feature,
|
|
166374
|
-
op: patch.op,
|
|
166375
|
-
path,
|
|
166376
|
-
reason: 'duplicate-path',
|
|
166377
|
-
conflictingFeature: seenForViolations.get(identity),
|
|
166378
|
-
message: `Feature '${envelope.feature}' and '${seenForViolations.get(identity)}' both write to ${path} (deduplication)`,
|
|
166379
|
-
});
|
|
166380
|
-
}
|
|
166381
|
-
else {
|
|
166382
|
-
seenForViolations.set(identity, envelope.feature);
|
|
166383
|
-
}
|
|
166384
|
-
// Gate 3: replace / remove to an absent path
|
|
166385
|
-
if (['replace', 'remove'].includes(patch.op)) {
|
|
166386
|
-
if (!pointerExists(claimAfterDefaults, path)) {
|
|
166387
|
-
violations.push({
|
|
166388
|
-
feature: envelope.feature,
|
|
166389
|
-
op: patch.op,
|
|
166390
|
-
path,
|
|
166391
|
-
reason: 'overwrite-protected',
|
|
166392
|
-
message: `Feature '${envelope.feature}' patch ${patch.op} ${raw} (normalized ${path}) targets absent path (replace/remove requires existing value)`,
|
|
166393
|
-
});
|
|
166394
|
-
}
|
|
166395
|
-
}
|
|
166396
|
-
}
|
|
166397
|
-
}
|
|
166398
|
-
if (violations.length > 0) {
|
|
166399
|
-
throw new StitchingError(violations);
|
|
166400
|
-
}
|
|
166401
|
-
// ── Phase 3: apply remaining patches ───────────────────────────────────
|
|
166402
|
-
let stitched = JSON.parse(JSON.stringify(claimAfterDefaults));
|
|
166403
|
-
for (let ei = 0; ei < normalizedEnvelopes.length; ei++) {
|
|
166404
|
-
const envelope = normalizedEnvelopes[ei];
|
|
166405
|
-
const patchesToApply = envelope.patches.filter((_, pi) => !dropped.has(`${ei}:${pi}`));
|
|
166406
|
-
if (patchesToApply.length === 0)
|
|
166407
|
-
continue;
|
|
166408
|
-
for (const patch of patchesToApply) {
|
|
166409
|
-
if (patch.op === 'add') {
|
|
166410
|
-
stitched = ensureAddParents(stitched, patch);
|
|
166411
|
-
}
|
|
166412
|
-
}
|
|
166413
|
-
const result = fast_json_patch.applyPatch(stitched, patchesToApply, false, false);
|
|
166414
|
-
stitched = result.newDocument;
|
|
166415
|
-
}
|
|
166416
|
-
return stitched;
|
|
166417
|
-
}
|
|
166418
|
-
async function collectFeaturePatches(claim) {
|
|
166419
|
-
if (MOCK_FEATURES_FN) {
|
|
166420
|
-
return MOCK_FEATURES_FN(claim);
|
|
166421
|
-
}
|
|
166422
|
-
const typedClaim = claim;
|
|
166423
|
-
const features = typedClaim.providers?.github?.features ?? [];
|
|
166424
|
-
if (features.length === 0)
|
|
166425
|
-
return [];
|
|
166426
|
-
// In unit tests without GitHub credentials, avoid real download — tests that care
|
|
166427
|
-
// about stitching should set MOCK_STITCHING_FEATURES explicitly.
|
|
166428
|
-
if (process.env.JEST_WORKER_ID && !process.env.GITHUB_TOKEN) {
|
|
166429
|
-
return [];
|
|
166430
|
-
}
|
|
166431
|
-
const envelopes = [];
|
|
166432
|
-
for (const feature of features) {
|
|
166433
|
-
const featureName = feature.name;
|
|
166434
|
-
const versionOrRef = feature.ref ?? feature.version ?? '';
|
|
166435
|
-
const repo = feature.repo
|
|
166436
|
-
? (feature.repo.split('/')[1] ?? 'features')
|
|
166437
|
-
: 'features';
|
|
166438
|
-
const owner = feature.repo
|
|
166439
|
-
? (feature.repo.split('/')[0] ?? 'prefapp')
|
|
166440
|
-
: 'prefapp';
|
|
166441
|
-
const args = feature.args ?? {};
|
|
166442
|
-
try {
|
|
166443
|
-
let patchesOrRendered;
|
|
166444
|
-
const preparerAny = features_preparer;
|
|
166445
|
-
if (feature.ref) {
|
|
166446
|
-
if (typeof preparerAny.getFeaturePatchesFromRef === 'function') {
|
|
166447
|
-
patchesOrRendered = await preparerAny.getFeaturePatchesFromRef(featureName, versionOrRef, claim, args, repo, owner);
|
|
166448
|
-
}
|
|
166449
|
-
else {
|
|
166450
|
-
patchesOrRendered = await preparerAny.getFeatureConfigFromRef(featureName, versionOrRef, claim, args, repo, owner);
|
|
166451
|
-
}
|
|
166452
|
-
}
|
|
166453
|
-
else {
|
|
166454
|
-
if (typeof preparerAny.getFeaturePatches === 'function') {
|
|
166455
|
-
patchesOrRendered = await preparerAny.getFeaturePatches(featureName, versionOrRef, claim, args, repo, owner);
|
|
166456
|
-
}
|
|
166457
|
-
else {
|
|
166458
|
-
patchesOrRendered = await preparerAny.getFeatureConfig(featureName, versionOrRef, claim, args, repo, owner);
|
|
166459
|
-
}
|
|
166460
|
-
}
|
|
166461
|
-
const patches = Array.isArray(patchesOrRendered)
|
|
166462
|
-
? patchesOrRendered
|
|
166463
|
-
: extractClaimPatches(patchesOrRendered);
|
|
166464
|
-
envelopes.push({ feature: featureName, patches });
|
|
166465
|
-
}
|
|
166466
|
-
catch (err) {
|
|
166467
|
-
throw new Error(`Failed to collect patches for feature '${featureName}': ${err instanceof Error ? err.message : String(err)}`);
|
|
166468
|
-
}
|
|
166469
|
-
}
|
|
166470
|
-
return envelopes;
|
|
166471
|
-
}
|
|
166472
|
-
function extractClaimPatches(rendered) {
|
|
166473
|
-
const patches = rendered.patches;
|
|
166474
|
-
if (!patches)
|
|
166475
|
-
return [];
|
|
166476
|
-
if (Array.isArray(patches))
|
|
166477
|
-
return patches;
|
|
166478
|
-
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`);
|
|
166479
|
-
}
|
|
166480
|
-
|
|
166481
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/lazy_loader.ts
|
|
166482
|
-
|
|
166483
|
-
|
|
166484
|
-
|
|
166485
|
-
|
|
166486
|
-
|
|
166487
|
-
|
|
166488
|
-
|
|
166489
|
-
|
|
166490
|
-
|
|
166491
|
-
|
|
166492
|
-
|
|
166493
|
-
|
|
166494
|
-
|
|
166495
|
-
|
|
166496
|
-
|
|
166497
|
-
|
|
166498
|
-
|
|
166499
|
-
// We need to ensure the grep command is a gnu version
|
|
166500
|
-
let IS_GNU_GREP = false;
|
|
166501
|
-
let GREP_ON_CHECK = false;
|
|
166502
|
-
// this loop is for avoid race conditions
|
|
166503
|
-
// once a check is running no more checks
|
|
166504
|
-
async function waitForCheck() {
|
|
166505
|
-
const f_wait = () => new Promise((timeOut) => setTimeout(timeOut, 10));
|
|
166506
|
-
do {
|
|
166507
|
-
await f_wait();
|
|
166508
|
-
} while (GREP_ON_CHECK);
|
|
166509
|
-
}
|
|
166510
|
-
function checkGrep() {
|
|
166511
|
-
return new Promise((ok, ko) => {
|
|
166512
|
-
// idempotency: already checked
|
|
166513
|
-
if (IS_GNU_GREP)
|
|
166514
|
-
return ok();
|
|
166515
|
-
// a check is already running no new checks
|
|
166516
|
-
if (GREP_ON_CHECK)
|
|
166517
|
-
return waitForCheck();
|
|
166518
|
-
logger.info('Checking the grep command');
|
|
166519
|
-
GREP_ON_CHECK = true;
|
|
166520
|
-
const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['--version']);
|
|
166521
|
-
handler.on('close', (code) => {
|
|
166522
|
-
GREP_ON_CHECK = false;
|
|
166523
|
-
if (code === 0) {
|
|
166524
|
-
logger.debug('Grep is a gnu grep');
|
|
166525
|
-
IS_GNU_GREP = true;
|
|
166526
|
-
ok();
|
|
166527
|
-
}
|
|
166528
|
-
else {
|
|
166529
|
-
ko('Lazy evaluation needs a gnu-grep command');
|
|
166530
|
-
}
|
|
166531
|
-
});
|
|
166532
|
-
});
|
|
166533
|
-
}
|
|
166534
|
-
async function loadClaim(claimRef, org, defaults = loadClaimDefaults(), patchClaim = loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, existingRefs = {}, postValidations = new Map()) {
|
|
166535
|
-
await checkGrep();
|
|
166536
|
-
let result = existingRefs;
|
|
166537
|
-
logger.info(`Load reference ${claimRef}`);
|
|
166538
|
-
initVirtualClaims(org);
|
|
166539
|
-
logger.info(`Load reference (parts) ${claimRef.split(/-/)[0]} ${claimRef.replace(/^[^-]+-/, '')}`);
|
|
166540
|
-
// cargas datos con grep
|
|
166541
|
-
try {
|
|
166542
|
-
const claimData = await lazyGetClaim(claimRef.split(/-/)[0], claimRef.replace(/^[^-]+-/, ''), org, cwd);
|
|
166543
|
-
let claim = patchClaim(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(claimData), defaults);
|
|
166544
|
-
// Claim stitching: feature claim-patches with three gates before AJV
|
|
166545
|
-
try {
|
|
166546
|
-
claim = await stitchClaim(claim);
|
|
166547
|
-
}
|
|
166548
|
-
catch (e) {
|
|
166549
|
-
throw new Error(`Error when stitching claim ${claimRef}: ${e instanceof Error ? e.message : String(e)}`);
|
|
166550
|
-
}
|
|
166551
|
-
let variants = [];
|
|
166552
|
-
if (claim.kind === 'TFWorkspaceClaim' &&
|
|
166553
|
-
claim.providers?.terraform?.variants) {
|
|
166554
|
-
variants = claim.providers.terraform.variants;
|
|
166555
|
-
delete claim.providers.terraform.variants;
|
|
166556
|
-
}
|
|
166557
|
-
logger.silly(`Patched claim is:
|
|
166558
|
-
---
|
|
166559
|
-
${catalog_common/* default.io.toYaml */.Z.io.toYaml(claim)}`);
|
|
166560
|
-
try {
|
|
166561
|
-
validateClaim(claim, base[`${claim.kind}Schema`]);
|
|
166562
|
-
await optionalValidation(claim);
|
|
166563
|
-
}
|
|
166564
|
-
catch (error) {
|
|
166565
|
-
let errorMsg = '';
|
|
166566
|
-
if (Array.isArray(error)) {
|
|
166567
|
-
for (const data of error) {
|
|
166568
|
-
errorMsg = `${errorMsg}
|
|
166569
|
-
- ${data.instancePath}: ${data.message}`;
|
|
166570
|
-
}
|
|
166571
|
-
}
|
|
166572
|
-
else {
|
|
166573
|
-
errorMsg = error instanceof Error ? error.message : String(error);
|
|
166574
|
-
}
|
|
166575
|
-
throw new Error(`Error when validating claim ${claimRef}: ${errorMsg}`);
|
|
166576
|
-
}
|
|
166577
|
-
result[claimRef] = {};
|
|
166578
|
-
result[claimRef]['claim'] = claim;
|
|
166579
|
-
result[claimRef]['claimPath'] = VisitedClaims[claimRef];
|
|
166580
|
-
if (VisitedClaims[claimRef] === 'virtual') {
|
|
166581
|
-
result = await setVirtualClaimAdditionalData(result, claim, claimRef);
|
|
166582
|
-
}
|
|
166583
|
-
else {
|
|
166584
|
-
result = await setNonVirtualClaimAdditionalData(result, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
|
|
166585
|
-
}
|
|
166586
|
-
const claimKind = claim.kind;
|
|
166587
|
-
const references = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(claim));
|
|
166588
|
-
for (const ref of references) {
|
|
166589
|
-
if (!result[ref]) {
|
|
166590
|
-
const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
|
|
166591
|
-
result = lodash_default().merge(result, resolvedReferences);
|
|
166592
|
-
}
|
|
166593
|
-
}
|
|
166594
|
-
if (variants.length > 0) {
|
|
166595
|
-
const parentClaimPath = VisitedClaims[claimRef];
|
|
166596
|
-
for (const variant of variants) {
|
|
166597
|
-
if (!variant.name || !variant.overrides) {
|
|
166598
|
-
throw new Error(`Variant in claim ${claimRef} is missing required field 'name' or 'overrides'`);
|
|
166599
|
-
}
|
|
166600
|
-
const prohibitedOverrideFields = ['source', 'module', 'name'];
|
|
166601
|
-
for (const field of prohibitedOverrideFields) {
|
|
166602
|
-
if (field in variant.overrides) {
|
|
166603
|
-
throw new Error(`Variant '${variant.name}' in claim ${claimRef} cannot override '${field}'`);
|
|
166604
|
-
}
|
|
166605
|
-
}
|
|
166606
|
-
const composedName = claim.providers.terraform.name + '-' + variant.name;
|
|
166607
|
-
const variantClaim = lodash_default().cloneDeep(claim);
|
|
166608
|
-
variantClaim._parentClaimName = claim.name;
|
|
166609
|
-
variantClaim.name = composedName;
|
|
166610
|
-
variantClaim.providers.terraform = lodash_default().merge({}, claim.providers.terraform, variant.overrides);
|
|
166611
|
-
variantClaim.providers.terraform.name = composedName;
|
|
166612
|
-
if (!variantClaim.annotations) {
|
|
166613
|
-
variantClaim.annotations = {};
|
|
166614
|
-
}
|
|
166615
|
-
variantClaim.annotations['firestartr.dev/variant-of'] =
|
|
166616
|
-
claim.providers.terraform.name;
|
|
166617
|
-
const variantRef = `TFWorkspaceClaim-${composedName}`;
|
|
166618
|
-
if (result[variantRef]) {
|
|
166619
|
-
throw new Error(`Variant name '${variant.name}' (composed: '${composedName}') from claim '${claimRef}' conflicts with existing claim '${variantRef}'`);
|
|
166620
|
-
}
|
|
166621
|
-
logger.info(`Creating synthetic variant claim ${variantRef}`);
|
|
166622
|
-
result[variantRef] = {};
|
|
166623
|
-
result[variantRef]['claim'] = variantClaim;
|
|
166624
|
-
result[variantRef]['claimPath'] = parentClaimPath;
|
|
166625
|
-
result = await setNonVirtualClaimAdditionalData(result, variantClaim, variantRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
|
|
166626
|
-
const variantReferences = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(variantClaim));
|
|
166627
|
-
for (const ref of variantReferences) {
|
|
166628
|
-
if (!result[ref]) {
|
|
166629
|
-
const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
|
|
166630
|
-
result = lodash_default().merge(result, resolvedReferences);
|
|
166631
|
-
}
|
|
166632
|
-
}
|
|
166633
|
-
}
|
|
166634
|
-
}
|
|
166635
|
-
}
|
|
166636
|
-
catch (err) {
|
|
166637
|
-
throw `Lazy Loading: ${err}`;
|
|
166638
|
-
}
|
|
166639
|
-
return [result, postValidations];
|
|
166640
|
-
}
|
|
166641
|
-
let LoadedClaims = {};
|
|
166642
|
-
let VisitedClaims = {};
|
|
166643
|
-
let DuplicatedClaims = {};
|
|
166644
|
-
function resetLazyLoader() {
|
|
166645
|
-
LoadedClaims = {};
|
|
166646
|
-
VisitedClaims = {};
|
|
166647
|
-
DuplicatedClaims = {};
|
|
166648
|
-
}
|
|
166649
|
-
async function lazyGetClaim(kind, name, org, cwd) {
|
|
166650
|
-
const indice = `${kind}-${name}`;
|
|
166651
|
-
logger.info(`Lazy loading ${kind}-${name} with index ${indice}`);
|
|
166652
|
-
if (indice in LoadedClaims)
|
|
166653
|
-
return LoadedClaims[indice];
|
|
166654
|
-
if (isVirtualClaim(kind, name)) {
|
|
166655
|
-
await loadVirtualClaim(kind, name, org);
|
|
166656
|
-
}
|
|
166657
|
-
else {
|
|
166658
|
-
await getClaimsByName(name, cwd);
|
|
166659
|
-
}
|
|
166660
|
-
if (indice in LoadedClaims) {
|
|
166661
|
-
return LoadedClaims[indice];
|
|
166662
|
-
}
|
|
166663
|
-
else {
|
|
166664
|
-
throw new Error(`Error: ${kind}-${name} not found`);
|
|
166665
|
-
}
|
|
166666
|
-
}
|
|
166667
|
-
async function getClaimsByName(name, cwd = '.') {
|
|
166668
|
-
return new Promise((ok, ko) => {
|
|
166669
|
-
const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['-r', '-l', '--include=*', '-E', `name: "?${name}"?`, '.'], {
|
|
166670
|
-
cwd: cwd,
|
|
166671
|
-
});
|
|
166672
|
-
logger.info(`Running ${['grep', '-r', '-l', '--include', '-E', 'name: "' + name + '"?', '.'].join(' ')}`);
|
|
166673
|
-
const entradas = [];
|
|
166674
|
-
const chunks = [];
|
|
166675
|
-
handler.stdout.on('data', (data) => {
|
|
166676
|
-
chunks.push(data.toString('utf-8'));
|
|
166677
|
-
});
|
|
166678
|
-
handler.on('close', () => {
|
|
166679
|
-
const dataFinal = chunks.join('');
|
|
166680
|
-
const fileNameList = dataFinal.split(/\n/).filter((line) => line !== '');
|
|
166681
|
-
for (const fileName of fileNameList) {
|
|
166682
|
-
// only yaml files
|
|
166683
|
-
if (!fileName.match(/\.yml$|\.yaml$/)) {
|
|
166684
|
-
continue;
|
|
166685
|
-
}
|
|
166686
|
-
// only entries not already visited
|
|
166687
|
-
if (Object.values(VisitedClaims).includes(fileName)) {
|
|
166688
|
-
continue;
|
|
166689
|
-
}
|
|
166690
|
-
entradas.push(external_path_.join(cwd, fileName));
|
|
166691
|
-
}
|
|
166692
|
-
return Promise.all(entradas.map((entrada) => {
|
|
166693
|
-
return loadRawClaim(entrada);
|
|
166694
|
-
}))
|
|
166695
|
-
.then(() => {
|
|
166696
|
-
ok();
|
|
166697
|
-
})
|
|
166698
|
-
.catch((err) => {
|
|
166699
|
-
ko(err);
|
|
166700
|
-
});
|
|
166701
|
-
});
|
|
166702
|
-
});
|
|
166703
|
-
}
|
|
166704
|
-
async function loadRawClaim(entry) {
|
|
166705
|
-
return new Promise((ok, ko) => {
|
|
166706
|
-
external_fs_.readFile(entry, 'utf-8', (error, data) => {
|
|
166707
|
-
if (error)
|
|
166708
|
-
return ko(`Reading ${entry}: ${error}`);
|
|
166709
|
-
const claim = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
|
|
166710
|
-
if (!('kind' in claim && 'name' in claim)) {
|
|
166711
|
-
logger.warn(`Invalid claim file ${entry}`);
|
|
166712
|
-
}
|
|
166713
|
-
else {
|
|
166714
|
-
const claimKey = `${claim.kind}-${claim.name}`;
|
|
166715
|
-
if (Object.keys(DuplicatedClaims).includes(claimKey) &&
|
|
166716
|
-
DuplicatedClaims[claimKey] !== entry) {
|
|
166717
|
-
return ko(`Duplicated claim ${claimKey} found files: ${DuplicatedClaims[claimKey]} and ${entry}`);
|
|
166718
|
-
}
|
|
166719
|
-
LoadedClaims[claimKey] = data;
|
|
166720
|
-
VisitedClaims[claimKey] = entry;
|
|
166721
|
-
DuplicatedClaims[claimKey] = entry;
|
|
166722
|
-
ok();
|
|
166723
|
-
}
|
|
166724
|
-
});
|
|
166725
|
-
});
|
|
166726
|
-
}
|
|
166727
|
-
async function setVirtualClaimAdditionalData(renderedData, claim, claimRef) {
|
|
166728
|
-
const virtualClaim = getVirtualClaim(claim.kind, claim.name);
|
|
166729
|
-
renderedData[claimRef]['initializers'] = [
|
|
166730
|
-
new UUIDInitializer(claim),
|
|
166731
|
-
new InitializerClaimRef(),
|
|
166732
|
-
new InitializerDefault(virtualClaim.getDefaultConfig()),
|
|
166733
|
-
];
|
|
166734
|
-
renderedData[claimRef]['globals'] = [];
|
|
166735
|
-
renderedData[claimRef]['overrides'] = [];
|
|
166736
|
-
renderedData[claimRef]['normalizers'] = [new NameNormalizer()];
|
|
166737
|
-
return renderedData;
|
|
166738
|
-
}
|
|
166739
|
-
async function setNonVirtualClaimAdditionalData(renderedData, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers) {
|
|
166740
|
-
renderedData[claimRef]['initializers'] = await loadInitializers(claim, renderedData[claimRef]['claimPath']);
|
|
166741
|
-
renderedData[claimRef]['globals'] = await loadGlobals(claim);
|
|
166742
|
-
renderedData[claimRef]['overrides'] = loadOverrides(claim);
|
|
166743
|
-
renderedData[claimRef]['normalizers'] = await loadNormalizers(claim, renderedData[claimRef]['claimPath']);
|
|
166744
|
-
return renderedData;
|
|
166745
|
-
}
|
|
166746
|
-
async function loadVirtualClaim(kind, name, org) {
|
|
166747
|
-
const virtualClaim = getVirtualClaim(kind, name);
|
|
166748
|
-
const expandedClaim = await virtualClaim.expand({ org });
|
|
166749
|
-
logger.info(`Loading virtual claim ${kind} ${name} ${org}`);
|
|
166750
|
-
LoadedClaims[`${kind}-${name}`] = catalog_common/* default.io.toYaml */.Z.io.toYaml(expandedClaim);
|
|
166751
|
-
VisitedClaims[`${kind}-${name}`] = 'virtual';
|
|
166752
|
-
}
|
|
166753
|
-
|
|
166754
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/claimsDefaulter.ts
|
|
166755
|
-
|
|
166756
|
-
|
|
166757
|
-
|
|
166758
|
-
/*
|
|
166759
|
-
* Default blocks are objects that cannot be merged but applied as a whole. Meaning:
|
|
166760
|
-
* - If the object is defined at the claim-level it is maintained *AS IT IS* (no merge)
|
|
166761
|
-
* - If the block is missing at the claim-level, the default block is applied
|
|
166762
|
-
*/
|
|
166763
|
-
const defaultBlocksPaths = ['/providers/terraform/sync'];
|
|
166764
|
-
function applyBlockAwareDefaults(claim, defaultClaim) {
|
|
166765
|
-
// we always work with a clone of the original
|
|
166766
|
-
const claimClone = JSON.parse(JSON.stringify(claim));
|
|
166767
|
-
// if the block is claim-level defined we store it here
|
|
166768
|
-
const defaultBlocks = new Map();
|
|
166769
|
-
// we remove the blocks entirely of the claim
|
|
166770
|
-
// to achieve an add copy
|
|
166771
|
-
for (const defaultBlockPath of defaultBlocksPaths) {
|
|
166772
|
-
if (claimsDefaulter_hasDeepPath(claimClone, defaultBlockPath) !== true)
|
|
166773
|
-
continue;
|
|
166774
|
-
const originalValue = fast_json_patch_default().getValueByPointer(claimClone, defaultBlockPath);
|
|
166775
|
-
if (originalValue) {
|
|
166776
|
-
logger.silly(`${claim.kind}/${claim.name}: has an original ${defaultBlockPath}: preserving`);
|
|
166777
|
-
defaultBlocks.set(defaultBlockPath, originalValue);
|
|
166778
|
-
fast_json_patch_default().applyPatch(claimClone, [{ op: 'remove', path: defaultBlockPath }]);
|
|
166779
|
-
}
|
|
166780
|
-
}
|
|
166781
|
-
// if the patch has the same path of a block
|
|
166782
|
-
// and the block was defined at claim-level
|
|
166783
|
-
// we interchange the value with the original value
|
|
166784
|
-
// otherwise we use the default
|
|
166785
|
-
const jsonPatchOps = fast_json_patch_default().compare(claimClone, defaultClaim)
|
|
166786
|
-
.filter((jp) => jp.op === 'add')
|
|
166787
|
-
.map((jp) => {
|
|
166788
|
-
if (defaultBlocks.has(jp.path)) {
|
|
166789
|
-
return {
|
|
166790
|
-
...jp,
|
|
166791
|
-
value: defaultBlocks.get(jp.path),
|
|
166792
|
-
};
|
|
166793
|
-
}
|
|
166794
|
-
else {
|
|
166795
|
-
return jp;
|
|
166796
|
-
}
|
|
166797
|
-
});
|
|
166798
|
-
return fast_json_patch_default().applyPatch(claimClone, jsonPatchOps).newDocument;
|
|
166799
|
-
}
|
|
166800
|
-
function claimsDefaulter_hasDeepPath(data, deepPath) {
|
|
166801
|
-
return lodash_default().has(data, deepPath.replace(/\//g, '.').replace(/^\./, ''));
|
|
166802
|
-
}
|
|
166803
|
-
|
|
166804
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/loader.ts
|
|
166805
|
-
|
|
166806
|
-
|
|
166807
|
-
|
|
166808
|
-
|
|
166809
|
-
|
|
166810
|
-
|
|
166811
|
-
|
|
166812
|
-
|
|
166813
|
-
|
|
166814
|
-
|
|
166815
|
-
|
|
166816
|
-
|
|
166817
|
-
|
|
166818
|
-
|
|
166819
|
-
|
|
166820
|
-
const isYamlFile = new RegExp(/\.(yaml|yml)$/);
|
|
166821
|
-
/**
|
|
166822
|
-
*
|
|
166823
|
-
* @returns Virtual Claims
|
|
166824
|
-
*/
|
|
166825
|
-
const virtualClaims = [new FirestartrAllClaim()];
|
|
166826
|
-
/*
|
|
166827
|
-
* Loads all applicable globals for a given claim and stores them into a list.
|
|
166828
|
-
*
|
|
166829
|
-
* Input:
|
|
166830
|
-
* - claim: our custom claim object, with which we check if the global is applicable
|
|
166831
|
-
*
|
|
166832
|
-
* Returns:
|
|
166833
|
-
* - A GlobalSection array promise, containing all the globals loaded for this claim
|
|
166834
|
-
*
|
|
166835
|
-
*/
|
|
166836
|
-
async function loadGlobals(claim) {
|
|
166837
|
-
const result = [];
|
|
166838
|
-
await crawl(getPath('globals'), (entry) => {
|
|
166839
|
-
return isYamlFile.test(entry);
|
|
166840
|
-
}, async (entry, data) => {
|
|
166841
|
-
const globalData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
|
|
166842
|
-
const ext = external_path_.extname(entry);
|
|
166843
|
-
const name = external_path_.basename(entry, ext);
|
|
166844
|
-
if (name in SECTIONS_BY_FILE_NAME) {
|
|
166845
|
-
const section = new SECTIONS_BY_FILE_NAME[name](globalData);
|
|
166846
|
-
if (!(await section.validate(SCHEMAS_BY_SECTION_NAME[name] || {}))) {
|
|
166847
|
-
throw new Error(`Invalid ${name} global file`);
|
|
166848
|
-
}
|
|
166849
|
-
if (globalData.kind === claim.kind) {
|
|
166850
|
-
result.push(section);
|
|
166851
|
-
}
|
|
166852
|
-
else {
|
|
166853
|
-
logger.debug(`Skipping global ${name} because it is not applicable to ${claim.kind}`);
|
|
166854
|
-
}
|
|
166855
|
-
}
|
|
166856
|
-
});
|
|
166857
|
-
logger.info(`Loaded globals ${result}`);
|
|
166858
|
-
return result;
|
|
166859
|
-
}
|
|
166860
|
-
/*
|
|
166861
|
-
* If the input claim is a GithubRepositoryClaim, it loads all it's applicable
|
|
166862
|
-
* overrides and stores them into a list. Otherwise, it returns an empty list.
|
|
166863
|
-
*
|
|
166864
|
-
* Input:
|
|
166865
|
-
* - claim: our custom claim object, which should be a GithubRepositoryClaim
|
|
166866
|
-
*
|
|
166867
|
-
* Returns:
|
|
166868
|
-
* - An Overrider array, with a GithubRepositoryOverrider if the claim
|
|
166869
|
-
* was a GithubRepositoryClaim, or empty if it was not.
|
|
166870
|
-
*
|
|
166871
|
-
*/
|
|
166872
|
-
function loadOverrides(claim) {
|
|
166873
|
-
const overrides = [];
|
|
166874
|
-
if (claim.kind === 'ComponentClaim' && claim.providers.github.overrides) {
|
|
166875
|
-
overrides.push(new GithubRepositoryOverrider());
|
|
166876
|
-
}
|
|
166877
|
-
return overrides;
|
|
166878
|
-
}
|
|
166879
|
-
/**
|
|
166880
|
-
* Load all normalizers and stores them into a list.
|
|
166881
|
-
* @param claim
|
|
166882
|
-
* @returns
|
|
166883
|
-
*/
|
|
166884
|
-
async function loadNormalizers(_claim, path) {
|
|
166885
|
-
const result = [];
|
|
166886
|
-
for (const normalizer of NORMALIZERS) {
|
|
166887
|
-
result.push(new normalizer({ path: path }));
|
|
166888
|
-
}
|
|
166889
|
-
return result;
|
|
166890
|
-
}
|
|
166891
|
-
/*
|
|
166892
|
-
* Loads all applicable initializers for a given claim and stores them into a list.
|
|
166893
|
-
*
|
|
166894
|
-
* Input:
|
|
166895
|
-
* - claim: our custom claim object, with which we check if the initializer is applicable
|
|
166896
|
-
*
|
|
166897
|
-
* Returns:
|
|
166898
|
-
* - An Initializer array promise, containing all the initializers loaded for this claim
|
|
166899
|
-
*
|
|
166900
|
-
*/
|
|
166901
|
-
let loadedInitializers = false;
|
|
166902
|
-
async function loadInitializers(claim, claimPath, initializersPath = getPath('initializers')) {
|
|
166903
|
-
const result = [];
|
|
166904
|
-
await crawl(initializersPath, (entry) => {
|
|
166905
|
-
return isYamlFile.test(entry);
|
|
166906
|
-
}, async (entry, data) => {
|
|
166907
|
-
const initializerData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
|
|
166908
|
-
const ext = external_path_.extname(entry);
|
|
166909
|
-
const name = external_path_.basename(entry, ext);
|
|
166910
|
-
if (name in INITIALIZERS_BY_FILE_NAME) {
|
|
166911
|
-
const initializerBfN = new INITIALIZERS_BY_FILE_NAME[name](initializerData);
|
|
166912
|
-
if (!(await initializerBfN.validate(SCHEMAS_BY_INITIALIZER_NAME[name] || {}))) {
|
|
166913
|
-
throw new Error(`Invalid ${name} initializer file`);
|
|
166914
|
-
}
|
|
166915
|
-
if (initializerData.kind === claim.kind) {
|
|
166916
|
-
result.push(initializerBfN);
|
|
166917
|
-
}
|
|
166918
|
-
else {
|
|
166919
|
-
logger.debug(`Skipping initializer ${name} because it is not applicable to ${claim.kind}`);
|
|
166920
|
-
}
|
|
166921
|
-
}
|
|
166922
|
-
});
|
|
166923
|
-
for (const initializer of INITIALIZERS) {
|
|
166924
|
-
if (initializer.applicableKinds.includes(claim.kind)) {
|
|
166925
|
-
result.push(new initializer({ path: claimPath }));
|
|
166926
|
-
}
|
|
166927
|
-
}
|
|
166928
|
-
logger.info(`Loaded initializers ${JSON.stringify(result)}`);
|
|
166929
|
-
loadedInitializers = result;
|
|
166930
|
-
return loadedInitializers;
|
|
166931
|
-
}
|
|
166932
|
-
function loadClaimDefaults() {
|
|
166933
|
-
try {
|
|
166934
|
-
return catalog_common/* default.io.fromYaml */.Z.io.fromYaml(external_fs_.readFileSync(`${getPath('claimsDefaults')}/claims_defaults.yaml`, 'utf-8'));
|
|
166935
|
-
}
|
|
166936
|
-
catch (error) {
|
|
166937
|
-
const errMsg = `Could not read claims defaults file in path ${getPath('claimsDefaults')}/claims_defaults.yaml: ${error}`;
|
|
166938
|
-
logger.error(errMsg);
|
|
166939
|
-
throw new Error(errMsg);
|
|
166940
|
-
}
|
|
166941
|
-
}
|
|
166942
|
-
/*
|
|
166943
|
-
* Using fast-json-patch, compares a claim to its kind's defaults, then patches it.
|
|
166944
|
-
*
|
|
166945
|
-
* Input:
|
|
166946
|
-
* - claim: our custom claim object, which we want to patch
|
|
166947
|
-
* - defaultsClaims: an object, containing the defaults for each claim kind,
|
|
166948
|
-
* with the same structure that we use for the actual claims
|
|
166949
|
-
*
|
|
166950
|
-
* Returns:
|
|
166951
|
-
* - The patched claim
|
|
166952
|
-
*
|
|
166953
|
-
*/
|
|
166954
|
-
function loader_patchClaim(claim, defaultsClaims) {
|
|
166955
|
-
if (defaultsClaims[claim.kind]) {
|
|
166956
|
-
claim = applyBlockAwareDefaults(claim, defaultsClaims[claim.kind]);
|
|
166957
|
-
}
|
|
166958
|
-
return claim;
|
|
166959
|
-
}
|
|
166960
|
-
async function loadCRsWithFullSet(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
|
|
166961
|
-
const result = {};
|
|
166962
|
-
const fullResult = {};
|
|
166963
|
-
await crawlWithExclusions(crsPath, (entry) => {
|
|
166964
|
-
return isYamlFile.test(entry);
|
|
166965
|
-
}, async (entry, data) => {
|
|
166966
|
-
const yamlData = stripKnownRelations(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data));
|
|
166967
|
-
const metadata = yamlData?.metadata;
|
|
166968
|
-
if (!(yamlData &&
|
|
166969
|
-
typeof yamlData === 'object' &&
|
|
166970
|
-
'kind' in yamlData &&
|
|
166971
|
-
metadata &&
|
|
166972
|
-
typeof metadata === 'object' &&
|
|
166973
|
-
'name' in metadata)) {
|
|
166974
|
-
logger.warn(`Invalid CR file ${entry}`);
|
|
166975
|
-
}
|
|
166976
|
-
else {
|
|
166977
|
-
const crKey = `${yamlData.kind}-${metadata.name}`;
|
|
166978
|
-
if (fullResult[crKey]) {
|
|
166979
|
-
logger.error(`Duplicate CR ${crKey}`);
|
|
166980
|
-
}
|
|
166981
|
-
// Keep the complete CR set for validations that need repository-wide context.
|
|
166982
|
-
fullResult[crKey] = yamlData;
|
|
166983
|
-
// Keep the filtered CR set for previous-CR lookup during claim rendering.
|
|
166984
|
-
if (allowedClaimReferences.length === 0 ||
|
|
166985
|
-
allowedClaimReferences.includes(yamlData.metadata?.annotations?.[catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('claim-ref')])) {
|
|
166986
|
-
result[crKey] = yamlData;
|
|
166987
|
-
}
|
|
166988
|
-
}
|
|
166989
|
-
}, excludedPaths.concat(getAdditionalPaths()));
|
|
166990
|
-
return { crs: result, fullCrs: fullResult };
|
|
166991
|
-
}
|
|
166992
|
-
async function loadCRs(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
|
|
166993
|
-
const { crs } = await loadCRsWithFullSet(crsPath, excludedPaths, allowedClaimReferences);
|
|
166994
|
-
return crs;
|
|
166995
|
-
}
|
|
166996
|
-
/*
|
|
166997
|
-
* Description: Get the renamed using claimRef annotation
|
|
166998
|
-
* Input: claims: any, crs: any
|
|
166999
|
-
* Output: renames: IRenameResult[]
|
|
167000
|
-
*/
|
|
167001
|
-
async function loadRenames(claims, crs) {
|
|
167002
|
-
/*
|
|
167003
|
-
* If checkRenames is false, we don't need to check for renames
|
|
167004
|
-
*/
|
|
167005
|
-
const renamesEnabled = getRenamesEnabled();
|
|
167006
|
-
if (!renamesEnabled)
|
|
167007
|
-
return [];
|
|
167008
|
-
const result = [];
|
|
167009
|
-
/**
|
|
167010
|
-
* For each CR, look for a claim that does not match the name with CR's firestartr.dev/claim-ref annotation
|
|
167011
|
-
*/
|
|
167012
|
-
for (const cr of Object.values(crs)) {
|
|
167013
|
-
const anyCr = cr;
|
|
167014
|
-
if (!anyCr?.metadata?.annotations)
|
|
167015
|
-
continue;
|
|
167016
|
-
// if the annotation is a claimRef
|
|
167017
|
-
const annotationName = common.generic.getFirestartrAnnotation('claim-ref');
|
|
167018
|
-
const annotations = anyCr?.metadata?.annotations || {};
|
|
167019
|
-
if (annotationName in annotations) {
|
|
167020
|
-
const claimRef = anyCr.metadata.annotations[annotationName];
|
|
167021
|
-
// split the annotation into kind and name
|
|
167022
|
-
const [kind, name] = claimRef.split('/');
|
|
167023
|
-
// if the claim exists, check if the name is different for the given provider
|
|
167024
|
-
const referencedClaim = claims[`${kind}-${name}`].claim;
|
|
167025
|
-
const oldName = anyCr.metadata.name;
|
|
167026
|
-
const newName = referencedClaim.providers[getConfiguredProvider()].name;
|
|
167027
|
-
if (oldName !== newName) {
|
|
167028
|
-
result.push({
|
|
167029
|
-
kind: referencedClaim.kind,
|
|
167030
|
-
claimPath: claims[`${kind}-${name}`].claimPath,
|
|
167031
|
-
claimName: referencedClaim.name,
|
|
167032
|
-
oldName,
|
|
167033
|
-
newName,
|
|
167034
|
-
});
|
|
167035
|
-
}
|
|
167036
|
-
}
|
|
167037
|
-
}
|
|
167038
|
-
return result;
|
|
167039
|
-
}
|
|
167040
|
-
async function loadClaimsList(claimRefList, claimsPath = getPath('claims')) {
|
|
167041
|
-
const data = {
|
|
167042
|
-
renderClaims: {},
|
|
167043
|
-
crs: {},
|
|
167044
|
-
fullCrs: {},
|
|
167045
|
-
};
|
|
167046
|
-
const defaults = loadClaimDefaults();
|
|
167047
|
-
for await (const claimRef of claimRefList) {
|
|
167048
|
-
const [renderedClaimData] = await loadClaim(claimRef, getOrg(), defaults, loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, claimsPath);
|
|
167049
|
-
data.renderClaims = lodash_default().merge(data.renderClaims, renderedClaimData);
|
|
167050
|
-
}
|
|
167051
|
-
const crClaimReferences = [];
|
|
167052
|
-
for (const ref of Object.keys(data.renderClaims)) {
|
|
167053
|
-
// Replaces only the first instance of '-'
|
|
167054
|
-
crClaimReferences.push(ref.replace('-', '/'));
|
|
167055
|
-
}
|
|
167056
|
-
const loadedCrs = await loadCRsWithFullSet(getPath('crs'), [getPath('globals'), getPath('initializers')], crClaimReferences);
|
|
167057
|
-
data['crs'] = loadedCrs.crs;
|
|
167058
|
-
data['fullCrs'] = loadedCrs.fullCrs;
|
|
167059
|
-
return data;
|
|
167060
|
-
}
|
|
167061
|
-
function getOrg() {
|
|
167062
|
-
const groupOrg = catalog_common/* default.environment.getFromEnvironmentWithDefault */.Z.environment.getFromEnvironmentWithDefault(catalog_common/* default.types.envVars.org */.Z.types.envVars.org, '');
|
|
167063
|
-
return groupOrg;
|
|
167064
|
-
}
|
|
167065
|
-
|
|
167066
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/references.ts
|
|
167067
|
-
function validateTfStateKeyUniqueness(crs) {
|
|
167068
|
-
const tfStateKeys = {};
|
|
167069
|
-
for (const crKey of Object.keys(crs)) {
|
|
167070
|
-
const cr = crs[crKey];
|
|
167071
|
-
if (!isTerraformWorkspace(cr))
|
|
167072
|
-
continue;
|
|
167073
|
-
const tfKey = cr.spec.firestartr.tfStateKey;
|
|
167074
|
-
if (tfStateKeys[tfKey]) {
|
|
167075
|
-
throw new Error(`❗❗ ❌ RENDER ERROR ❌ ❗❗
|
|
167076
|
-
|
|
167077
|
-
The tfStateKey ${tfKey} is not unique,
|
|
167078
|
-
|
|
167079
|
-
It is being used by the following CRs:
|
|
167080
|
-
|
|
167081
|
-
- ${tfStateKeys[tfKey].kind} ${tfStateKeys[tfKey].metadata.name}
|
|
167082
|
-
|
|
167083
|
-
- ${cr.kind} ${cr.metadata.name}
|
|
167084
|
-
|
|
167085
|
-
Check the following Claims to ensure that the tfStateKey is unique:
|
|
167086
|
-
|
|
167087
|
-
- ${tfStateKeys[tfKey].metadata.annotations['firestartr.dev/claim-ref']}
|
|
167088
|
-
|
|
167089
|
-
- ${cr.metadata.annotations['firestartr.dev/claim-ref']}
|
|
167090
|
-
`);
|
|
167091
|
-
}
|
|
167092
|
-
tfStateKeys[cr.spec.firestartr.tfStateKey] = cr;
|
|
167093
|
-
}
|
|
167094
|
-
}
|
|
167095
|
-
function references_isCatalogEntity(cr) {
|
|
167096
|
-
return [
|
|
167097
|
-
'Component',
|
|
167098
|
-
'Domain',
|
|
167099
|
-
'System',
|
|
167100
|
-
'User',
|
|
167101
|
-
'Group',
|
|
167102
|
-
'Resource',
|
|
167103
|
-
].includes(cr.kind);
|
|
167104
|
-
}
|
|
167105
|
-
function isTerraformWorkspace(cr) {
|
|
167106
|
-
return cr.kind === 'FirestartrTerraformWorkspace';
|
|
167107
|
-
}
|
|
167108
|
-
|
|
167109
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/crSize.ts
|
|
167110
|
-
|
|
167111
|
-
const K8S_OBJECT_SIZE_LIMIT = 1572864; // 1.5 MiB in bytes, etcd recommended limit: https://etcd.io/docs/latest/dev-guide/limit/
|
|
167112
|
-
function validateCrSizes(crs) {
|
|
167113
|
-
for (const key of Object.keys(crs)) {
|
|
167114
|
-
const cr = crs[key];
|
|
167115
|
-
const serialized = catalog_common/* default.io.toYaml */.Z.io.toYaml(cr);
|
|
167116
|
-
const size = Buffer.byteLength(serialized, 'utf8');
|
|
167117
|
-
if (size > K8S_OBJECT_SIZE_LIMIT) {
|
|
167118
|
-
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).`);
|
|
167119
|
-
}
|
|
167120
|
-
}
|
|
167121
|
-
}
|
|
167122
|
-
|
|
167123
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/permissions.ts
|
|
167124
|
-
|
|
167125
|
-
function validatePermissionsUniqueness(crs) {
|
|
167126
|
-
for (const crkey in crs) {
|
|
167127
|
-
const cr = crs[crkey];
|
|
167128
|
-
if (cr.kind === 'FirestartrGithubRepository') {
|
|
167129
|
-
const permissions = cr.spec.permissions;
|
|
167130
|
-
logger.debug(`Validating Permissions Uniqueness of ${crkey}`);
|
|
167131
|
-
if (permissions) {
|
|
167132
|
-
const rolesByIdentifier = new Map();
|
|
167133
|
-
for (const perm of permissions) {
|
|
167134
|
-
const identifier = perm.collaborator
|
|
167135
|
-
? perm.collaborator
|
|
167136
|
-
: `ref:${perm.ref.kind}:${perm.ref.name}`;
|
|
167137
|
-
const role = perm.role;
|
|
167138
|
-
const prevRole = rolesByIdentifier.get(identifier);
|
|
167139
|
-
if (prevRole === undefined) {
|
|
167140
|
-
rolesByIdentifier.set(identifier, role);
|
|
167141
|
-
}
|
|
167142
|
-
else if (prevRole !== role) {
|
|
167143
|
-
throw new Error(`Conflicting permission role in FirestartrGithubRepository ${crkey}: ${identifier} has roles "${prevRole}" and "${role}".\nFull CR: ${JSON.stringify(cr, null, 2)}`);
|
|
167144
|
-
}
|
|
167145
|
-
}
|
|
167146
|
-
}
|
|
167147
|
-
}
|
|
167148
|
-
}
|
|
167149
|
-
}
|
|
167150
|
-
|
|
167151
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/backstageAnnotations.ts
|
|
167152
|
-
const backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX = 'firestartr.backstage.dev/';
|
|
167153
|
-
const CATALOG_KINDS = new Set([
|
|
167154
|
-
'User',
|
|
167155
|
-
'Group',
|
|
167156
|
-
'Component',
|
|
167157
|
-
'System',
|
|
167158
|
-
'Domain',
|
|
167159
|
-
'API',
|
|
167160
|
-
'Resource',
|
|
167161
|
-
'CatalogKubernetesResource',
|
|
167162
|
-
'CatalogTerraformWorkspace',
|
|
167163
|
-
'CatalogArgoDeploy',
|
|
167164
|
-
'CatalogOrgWebhook',
|
|
167165
|
-
'CatalogSecrets',
|
|
167166
|
-
]);
|
|
167167
|
-
function validateNoBackstageAnnotationsInK8sCrs(crs) {
|
|
167168
|
-
for (const crKey in crs) {
|
|
167169
|
-
const cr = crs[crKey];
|
|
167170
|
-
if (CATALOG_KINDS.has(cr.kind))
|
|
167171
|
-
continue;
|
|
167172
|
-
if (cr.metadata?.annotations) {
|
|
167173
|
-
const backstageKeys = Object.keys(cr.metadata.annotations).filter((k) => k.startsWith(backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX));
|
|
167174
|
-
if (backstageKeys.length > 0) {
|
|
167175
|
-
throw new Error(`K8s CR ${crKey} contains Backstage-only annotations (${backstageKeys.join(', ')}). ` +
|
|
167176
|
-
`Annotations with prefix ${backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX} must only appear on Backstage catalog entities, not on Kubernetes CRs.`);
|
|
167177
|
-
}
|
|
167178
|
-
}
|
|
167179
|
-
}
|
|
167180
|
-
}
|
|
167181
|
-
|
|
167182
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/refsSorter/refsSorter.ts
|
|
167183
|
-
|
|
167184
|
-
/**
|
|
167185
|
-
* @param renderClaims renderClaims to sort
|
|
167186
|
-
* @param kinds kinds to get from renderClaims
|
|
167187
|
-
* @returns renderClaims with only the kinds specified
|
|
167188
|
-
*/
|
|
167189
|
-
function sortRenderClaimsByKind(renderClaims, kinds) {
|
|
167190
|
-
let result = {};
|
|
167191
|
-
for (const kind of kinds) {
|
|
167192
|
-
for (const key in renderClaims) {
|
|
167193
|
-
if (renderClaims[key].claim.kind === kind) {
|
|
167194
|
-
result[key] = renderClaims[key];
|
|
167195
|
-
}
|
|
167196
|
-
}
|
|
167197
|
-
result = sortSelfKindRefs(result, kind);
|
|
167198
|
-
}
|
|
167199
|
-
return result;
|
|
167200
|
-
}
|
|
167201
|
-
function sortSelfKindRefs(renderClaims, kind) {
|
|
167202
|
-
if (!hasSelfRefs(kind)) {
|
|
167203
|
-
return renderClaims;
|
|
167204
|
-
}
|
|
167205
|
-
const newRenderClaims = {};
|
|
167206
|
-
const data = extractRefs(renderClaims, kind);
|
|
167207
|
-
const ordered = [];
|
|
167208
|
-
const visiting = [];
|
|
167209
|
-
const visited = [];
|
|
167210
|
-
for (const key of Object.keys(data)) {
|
|
167211
|
-
if (!visited.find((obj) => obj.name === key)) {
|
|
167212
|
-
sortRefs(data, data[key], ordered, visiting, visited);
|
|
167213
|
-
}
|
|
167214
|
-
}
|
|
167215
|
-
for (const cr of ordered) {
|
|
167216
|
-
newRenderClaims[cr.name] = renderClaims[cr.name];
|
|
167217
|
-
}
|
|
167218
|
-
return newRenderClaims;
|
|
167219
|
-
}
|
|
167220
|
-
function sortRefs(data, claim, ordered = [], visiting = [], visited = []) {
|
|
167221
|
-
if (visiting.find((obj) => obj.name === claim.name)) {
|
|
167222
|
-
throw new Error(`Circular dependency detected for '${claim.name}'`);
|
|
167223
|
-
}
|
|
167224
|
-
if (!visited.find((obj) => obj.name === claim.name)) {
|
|
167225
|
-
visiting.push(claim);
|
|
167226
|
-
if (claim.refs) {
|
|
167227
|
-
for (const ref of claim.refs) {
|
|
167228
|
-
const referencedObject = data[ref];
|
|
167229
|
-
if (!referencedObject) {
|
|
167230
|
-
throw new Error(`Reference '${ref}' does not exist for '${claim.name}'`);
|
|
167231
|
-
}
|
|
167232
|
-
sortRefs(data, referencedObject, ordered, visiting, visited);
|
|
167233
|
-
}
|
|
167234
|
-
}
|
|
167235
|
-
visited.push(visiting.pop());
|
|
167236
|
-
ordered.push(claim);
|
|
167237
|
-
}
|
|
167238
|
-
}
|
|
167239
|
-
function hasSelfRefs(kind) {
|
|
167240
|
-
return ['TFWorkspaceClaim', 'GroupClaim'].includes(kind);
|
|
167241
|
-
}
|
|
167242
|
-
|
|
167243
|
-
;// CONCATENATED MODULE: ../cdk8s_renderer/src/renderer/claims-sorter.ts
|
|
167244
|
-
|
|
167245
|
-
function sortKinds(orderedKinds, claims) {
|
|
167246
|
-
const result = [];
|
|
167247
|
-
for (const kind of orderedKinds) {
|
|
167248
|
-
const kindRenderClaims = sortRenderClaimsByKind(claims, [kind]);
|
|
167249
|
-
result.push(kindRenderClaims);
|
|
167250
|
-
}
|
|
167251
|
-
return result;
|
|
167252
|
-
}
|
|
167253
|
-
|
|
167254
166792
|
;// CONCATENATED MODULE: ../cdk8s_renderer/src/overriders/utils.ts
|
|
167255
166793
|
|
|
167256
166794
|
|
|
@@ -167292,12 +166830,14 @@ async function utils_renderFeature(featureName, featureVersion, featureOutputObj
|
|
|
167292
166830
|
|
|
167293
166831
|
|
|
167294
166832
|
|
|
166833
|
+
|
|
166834
|
+
|
|
167295
166835
|
// this is the only way currently to make
|
|
167296
166836
|
// work the system and inject our code
|
|
167297
166837
|
// without having to download a feature
|
|
167298
|
-
let
|
|
166838
|
+
let MOCK_FEATURES_FN;
|
|
167299
166839
|
function MOCK_FEATURES(mock) {
|
|
167300
|
-
|
|
166840
|
+
MOCK_FEATURES_FN = mock;
|
|
167301
166841
|
if (mock) {
|
|
167302
166842
|
log.warn('⚠️ Warning features system downloader has been mocked, it should only happen in unit testing');
|
|
167303
166843
|
}
|
|
@@ -167328,8 +166868,8 @@ class FeaturesOverrider extends OverriderPatches {
|
|
|
167328
166868
|
let owner = 'prefapp';
|
|
167329
166869
|
let versionOrRef = this.featureVersion;
|
|
167330
166870
|
let renderer = 'getFeatureConfig';
|
|
167331
|
-
if (
|
|
167332
|
-
return
|
|
166871
|
+
if (MOCK_FEATURES_FN) {
|
|
166872
|
+
return MOCK_FEATURES_FN();
|
|
167333
166873
|
}
|
|
167334
166874
|
if (this.featureRepo) {
|
|
167335
166875
|
[owner, repo] = this.featureRepo.split(/\//);
|
|
@@ -167347,8 +166887,8 @@ class FeaturesOverrider extends OverriderPatches {
|
|
|
167347
166887
|
const featureName = this.featureName;
|
|
167348
166888
|
const featureVersion = this.featureVersion || this.featureRef;
|
|
167349
166889
|
const featureArgs = this.featureArgs;
|
|
167350
|
-
const fSetUpAndRunRenderer = function (
|
|
167351
|
-
return this.setUpAndRunRenderer(
|
|
166890
|
+
const fSetUpAndRunRenderer = function (cr) {
|
|
166891
|
+
return this.setUpAndRunRenderer(cr);
|
|
167352
166892
|
}.bind(this);
|
|
167353
166893
|
let renderedFeatureConfig = null;
|
|
167354
166894
|
return [
|
|
@@ -167357,7 +166897,7 @@ class FeaturesOverrider extends OverriderPatches {
|
|
|
167357
166897
|
return true;
|
|
167358
166898
|
},
|
|
167359
166899
|
async apply(cr) {
|
|
167360
|
-
renderedFeatureConfig = await fSetUpAndRunRenderer(
|
|
166900
|
+
renderedFeatureConfig = await fSetUpAndRunRenderer(cr);
|
|
167361
166901
|
return cr;
|
|
167362
166902
|
},
|
|
167363
166903
|
identify() {
|
|
@@ -167370,6 +166910,28 @@ class FeaturesOverrider extends OverriderPatches {
|
|
|
167370
166910
|
return utils_renderFeature(featureName, featureVersion, renderedFeatureConfig, cr, claim.name);
|
|
167371
166911
|
},
|
|
167372
166912
|
},
|
|
166913
|
+
{
|
|
166914
|
+
isPostPatch: true,
|
|
166915
|
+
validate() {
|
|
166916
|
+
return true;
|
|
166917
|
+
},
|
|
166918
|
+
async apply(cr) {
|
|
166919
|
+
if (!renderedFeatureConfig) {
|
|
166920
|
+
logger.warn(`Feature ${featureName}: renderedFeatureConfig is null, skipping post-patch`);
|
|
166921
|
+
return cr;
|
|
166922
|
+
}
|
|
166923
|
+
const provider = helperCTX(this).provider;
|
|
166924
|
+
const jsonPatches = renderedFeatureConfig.patches?.[provider] || [];
|
|
166925
|
+
fast_json_patch_default().applyPatch(cr, jsonPatches);
|
|
166926
|
+
return cr;
|
|
166927
|
+
},
|
|
166928
|
+
identify() {
|
|
166929
|
+
return `feature-json-patch/${featureName}`;
|
|
166930
|
+
},
|
|
166931
|
+
applicable() {
|
|
166932
|
+
return { applicableProviders: ['catalog', 'github'] };
|
|
166933
|
+
},
|
|
166934
|
+
},
|
|
167373
166935
|
];
|
|
167374
166936
|
}
|
|
167375
166937
|
}
|
|
@@ -173264,6 +172826,7 @@ function walkArray(arr, symbolsToResolve, renderClaim) {
|
|
|
173264
172826
|
|
|
173265
172827
|
|
|
173266
172828
|
|
|
172829
|
+
|
|
173267
172830
|
/*
|
|
173268
172831
|
* Function called when rendering from the importer class.
|
|
173269
172832
|
*
|
|
@@ -173301,6 +172864,10 @@ async function renderFromImports(rClaims, crs = {}, catalogOutputDir = '/tmp/.ca
|
|
|
173301
172864
|
logger.error(`Error while resolving imported-refs: ${e.message}`);
|
|
173302
172865
|
throw new Error(`Error while resolving imported-refs: ${e.message}`);
|
|
173303
172866
|
}
|
|
172867
|
+
// Clear the rendered claims symbol table to ensure a clean state
|
|
172868
|
+
// after resolving imported refs, preventing setRenderedClaim() from throwing
|
|
172869
|
+
// 'already rendered' for claims that were previously seeded
|
|
172870
|
+
emptyRenderedClaims();
|
|
173304
172871
|
// after resolving the imported-refs, we need to validate the claims again, and apply the defaults if needed
|
|
173305
172872
|
for (const renderClaim of Object.values(rClaims)) {
|
|
173306
172873
|
if (defaults) {
|
|
@@ -173382,6 +172949,8 @@ async function addLastStateAndLastClaimAnnotations(filePath, lastStatePRLink, la
|
|
|
173382
172949
|
|
|
173383
172950
|
|
|
173384
172951
|
|
|
172952
|
+
|
|
172953
|
+
|
|
173385
172954
|
|
|
173386
172955
|
|
|
173387
172956
|
|
|
@@ -173475,6 +173044,9 @@ async function runRenderer(globalsPath, initializersPath, claimsPath, crsPath, c
|
|
|
173475
173044
|
}
|
|
173476
173045
|
|
|
173477
173046
|
;// CONCATENATED MODULE: ../importer/src/decanter/config.ts
|
|
173047
|
+
|
|
173048
|
+
|
|
173049
|
+
|
|
173478
173050
|
let claimsPath = '';
|
|
173479
173051
|
function setClaimsPath(path) {
|
|
173480
173052
|
claimsPath = path;
|
|
@@ -173511,6 +173083,92 @@ function getConfigPath() {
|
|
|
173511
173083
|
}
|
|
173512
173084
|
return configPath;
|
|
173513
173085
|
}
|
|
173086
|
+
/**
|
|
173087
|
+
* claimsDefaults path
|
|
173088
|
+
*/
|
|
173089
|
+
let claimsDefaultsPath = '';
|
|
173090
|
+
function setClaimsDefaultsPath(path) {
|
|
173091
|
+
claimsDefaultsPath = path;
|
|
173092
|
+
}
|
|
173093
|
+
function getClaimsDefaultsPath() {
|
|
173094
|
+
if (!claimsDefaultsPath) {
|
|
173095
|
+
throw new Error('Claims defaults path not set');
|
|
173096
|
+
}
|
|
173097
|
+
return claimsDefaultsPath;
|
|
173098
|
+
}
|
|
173099
|
+
/**
|
|
173100
|
+
* Cached default owner claim reference from claims_defaults.yaml.
|
|
173101
|
+
* Loaded once via loadClaimsDefaultsOnce() to avoid repeated file reads.
|
|
173102
|
+
*/
|
|
173103
|
+
let defaultOwnerClaimRef = null;
|
|
173104
|
+
/**
|
|
173105
|
+
* Resolved default owner CODEOWNERS handles, derived from defaultOwnerClaimRef
|
|
173106
|
+
* through the same claim-to-external-name mapping used by CODEOWNERS generation.
|
|
173107
|
+
*/
|
|
173108
|
+
let defaultOwnerHandles = {
|
|
173109
|
+
team: null,
|
|
173110
|
+
user: null,
|
|
173111
|
+
};
|
|
173112
|
+
/**
|
|
173113
|
+
* Loads claims_defaults.yaml once and caches the default owner claim reference.
|
|
173114
|
+
* Must be called after setClaimsDefaultsPath() and before any decanter runs.
|
|
173115
|
+
*/
|
|
173116
|
+
function loadClaimsDefaultsOnce() {
|
|
173117
|
+
try {
|
|
173118
|
+
const raw = external_fs_.readFileSync(`${getClaimsDefaultsPath()}/claims_defaults.yaml`, 'utf-8');
|
|
173119
|
+
const defaults = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(raw);
|
|
173120
|
+
defaultOwnerClaimRef = defaults?.ComponentClaim?.owner ?? null;
|
|
173121
|
+
}
|
|
173122
|
+
catch {
|
|
173123
|
+
defaultOwnerClaimRef = null;
|
|
173124
|
+
}
|
|
173125
|
+
}
|
|
173126
|
+
/**
|
|
173127
|
+
* Returns the cached default owner claim reference (e.g., "group:group_a" or "user:user_a").
|
|
173128
|
+
* Returns null if not loaded or not set in claims_defaults.yaml.
|
|
173129
|
+
*/
|
|
173130
|
+
function getDefaultOwnerClaimRef() {
|
|
173131
|
+
return defaultOwnerClaimRef;
|
|
173132
|
+
}
|
|
173133
|
+
/**
|
|
173134
|
+
* Resolves the default owner claim reference to CODEOWNERS handle(s) using the
|
|
173135
|
+
* same claim-to-external-name mapping used by CODEOWNERS generation.
|
|
173136
|
+
* Must be called after the referenced claims have been seeded into the renderer
|
|
173137
|
+
* (i.e., after setPreviousCRs) so resolveCodeownersRef can resolve them.
|
|
173138
|
+
*/
|
|
173139
|
+
function resolveDefaultOwnerHandles(org) {
|
|
173140
|
+
defaultOwnerHandles = { team: null, user: null };
|
|
173141
|
+
const claimRef = defaultOwnerClaimRef;
|
|
173142
|
+
if (!org || !claimRef || !claimRef.includes(':')) {
|
|
173143
|
+
return;
|
|
173144
|
+
}
|
|
173145
|
+
try {
|
|
173146
|
+
const [kind] = claimRef.split(':');
|
|
173147
|
+
const handle = resolveCodeownersRef(claimRef, org).toLowerCase();
|
|
173148
|
+
if (kind === 'group') {
|
|
173149
|
+
defaultOwnerHandles.team = handle;
|
|
173150
|
+
}
|
|
173151
|
+
else if (kind === 'user') {
|
|
173152
|
+
defaultOwnerHandles.user = handle;
|
|
173153
|
+
}
|
|
173154
|
+
}
|
|
173155
|
+
catch {
|
|
173156
|
+
// referenced claim not resolvable → no default owner escape hatch
|
|
173157
|
+
}
|
|
173158
|
+
}
|
|
173159
|
+
/**
|
|
173160
|
+
* Returns the resolved default owner CODEOWNERS handles, if any.
|
|
173161
|
+
*/
|
|
173162
|
+
function getDefaultOwnerHandles() {
|
|
173163
|
+
return defaultOwnerHandles;
|
|
173164
|
+
}
|
|
173165
|
+
/**
|
|
173166
|
+
* Resets the cached default owner claim ref and handles (useful for testing).
|
|
173167
|
+
*/
|
|
173168
|
+
function resetClaimsDefaultsCache() {
|
|
173169
|
+
defaultOwnerClaimRef = null;
|
|
173170
|
+
defaultOwnerHandles = { team: null, user: null };
|
|
173171
|
+
}
|
|
173514
173172
|
/* harmony default export */ const config = ({
|
|
173515
173173
|
setClaimsPath,
|
|
173516
173174
|
getClaimsPath,
|
|
@@ -173518,6 +173176,13 @@ function getConfigPath() {
|
|
|
173518
173176
|
getResourcesPath,
|
|
173519
173177
|
setConfigPath,
|
|
173520
173178
|
getConfigPath,
|
|
173179
|
+
setClaimsDefaultsPath,
|
|
173180
|
+
getClaimsDefaultsPath,
|
|
173181
|
+
loadClaimsDefaultsOnce,
|
|
173182
|
+
getDefaultOwnerClaimRef,
|
|
173183
|
+
resolveDefaultOwnerHandles,
|
|
173184
|
+
getDefaultOwnerHandles,
|
|
173185
|
+
resetClaimsDefaultsCache,
|
|
173521
173186
|
});
|
|
173522
173187
|
|
|
173523
173188
|
;// CONCATENATED MODULE: ../importer/src/logger.ts
|
|
@@ -174119,6 +173784,7 @@ function transformRepoName(repoName) {
|
|
|
174119
173784
|
|
|
174120
173785
|
|
|
174121
173786
|
|
|
173787
|
+
|
|
174122
173788
|
const TYPE_MAP = {
|
|
174123
173789
|
User: 'user',
|
|
174124
173790
|
Team: 'group',
|
|
@@ -174264,15 +173930,43 @@ class RepoGithubDecanter extends GithubDecanter {
|
|
|
174264
173930
|
return (this.data.teamsAndMembers.directMembers.some((member) => member.name?.toLowerCase() === normalizedUserName) ||
|
|
174265
173931
|
this.data.teamsAndMembers.outsideMembers.some((member) => member.name?.toLowerCase() === normalizedUserName));
|
|
174266
173932
|
};
|
|
173933
|
+
// The default owner is resolved once in the importer/configuration layer
|
|
173934
|
+
// from claims_defaults.yaml, through the same claim-to-external-name
|
|
173935
|
+
// mapping used by CODEOWNERS generation. ComponentClaim.owner is a claim
|
|
173936
|
+
// reference (e.g. "group:group_a" or "user:user_a"), not a GitHub handle,
|
|
173937
|
+
// so we must compare against the resolved external name.
|
|
173938
|
+
let defaultOwnerTeamHandle = null;
|
|
173939
|
+
let defaultOwnerUserHandle = null;
|
|
173940
|
+
const defaultOwnerHandles = getDefaultOwnerHandles();
|
|
173941
|
+
if (defaultOwnerHandles.team) {
|
|
173942
|
+
defaultOwnerTeamHandle = defaultOwnerHandles.team;
|
|
173943
|
+
}
|
|
173944
|
+
if (defaultOwnerHandles.user) {
|
|
173945
|
+
defaultOwnerUserHandle = defaultOwnerHandles.user;
|
|
173946
|
+
}
|
|
173947
|
+
const isDefaultOwner = (owner) => {
|
|
173948
|
+
const normalized = owner.name.toLowerCase();
|
|
173949
|
+
if (owner.isTeam)
|
|
173950
|
+
return normalized === defaultOwnerTeamHandle;
|
|
173951
|
+
return normalized === defaultOwnerUserHandle;
|
|
173952
|
+
};
|
|
174267
173953
|
// let's validate that every element in the
|
|
174268
173954
|
// CODEOWNERS file is either a team or a user in the repository,
|
|
174269
173955
|
// otherwise we will have dangling references in the claim which will cause issues down the line
|
|
174270
173956
|
for (const owner of owners) {
|
|
174271
173957
|
if (owner.isTeam && !isInTeams(owner.name)) {
|
|
173958
|
+
if (isDefaultOwner(owner)) {
|
|
173959
|
+
importer_src_logger.warn(`[${this.org}/${this.data.repoDetails.name}] CODEOWNERS file references default owner team ${owner.name} which is not yet in the repository's teams — will be granted on provisioning; continuing.`);
|
|
173960
|
+
continue;
|
|
173961
|
+
}
|
|
174272
173962
|
importer_src_logger.error(`[${this.org}/${this.data.repoDetails.name}] CODEOWNERS file references team ${owner.name} which is not present in the repository's teams.`);
|
|
174273
173963
|
throw new Error(`[${this.org}/${this.data.repoDetails.name}] CODEOWNERS file references team ${owner.name} which is not present in the repository's teams.`);
|
|
174274
173964
|
}
|
|
174275
173965
|
else if (!owner.isTeam && !isInUsers(owner.name)) {
|
|
173966
|
+
if (isDefaultOwner(owner)) {
|
|
173967
|
+
importer_src_logger.warn(`[${this.org}/${this.data.repoDetails.name}] CODEOWNERS file references default owner user ${owner.name} not yet collaborator — will be granted on provisioning; continuing.`);
|
|
173968
|
+
continue;
|
|
173969
|
+
}
|
|
174276
173970
|
importer_src_logger.error(`[${this.org}/${this.data.repoDetails.name}] CODEOWNERS file references user ${owner.name} which is not present in the repository's collaborators.`);
|
|
174277
173971
|
throw new Error(`[${this.org}/${this.data.repoDetails.name}] CODEOWNERS file references user ${owner.name} which is not present in the repository's collaborators.`);
|
|
174278
173972
|
}
|
|
@@ -174577,22 +174271,39 @@ function isInPreviousCRs(kind, name) {
|
|
|
174577
174271
|
}
|
|
174578
174272
|
const randomFolder = external_path_.join('/tmp', `claims_${catalog_common/* default.generic.randomString */.Z.generic.randomString(10)}`);
|
|
174579
174273
|
const tmpRenderedCrsPath = external_path_.join('/tmp', '.resources');
|
|
174580
|
-
async function setPreviousCRs(resourcesPath) {
|
|
174274
|
+
async function setPreviousCRs(resourcesPath, org) {
|
|
174581
174275
|
const crs = await cdk8s_renderer.loadCRs(resourcesPath, [
|
|
174582
174276
|
external_path_.join(resourcesPath, '.github'),
|
|
174583
174277
|
external_path_.join(resourcesPath, '.config'),
|
|
174584
174278
|
external_path_.join(resourcesPath, '.import'),
|
|
174585
174279
|
]);
|
|
174586
174280
|
const alreadyImportedCrs = {};
|
|
174281
|
+
emptyRenderedClaims();
|
|
174282
|
+
const claimRefAnnotation = catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('claim-ref');
|
|
174587
174283
|
for (const value of Object.values(crs)) {
|
|
174588
174284
|
const resourceName = value.metadata.annotations[catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('external-name')];
|
|
174589
174285
|
const resourceKind = value.kind;
|
|
174590
174286
|
alreadyImportedCrs[`${resourceKind}-${resourceName}`] = value;
|
|
174287
|
+
// Seed the renderer's claim symbol table from already-imported CRs so that
|
|
174288
|
+
// claim references (e.g. the default owner "group:group_a") can be resolved
|
|
174289
|
+
// to their external names through the same mapping used by CODEOWNERS.
|
|
174290
|
+
const claimRef = value.metadata?.annotations?.[claimRefAnnotation];
|
|
174291
|
+
if (claimRef && typeof claimRef === 'string' && claimRef.includes('/')) {
|
|
174292
|
+
const [claimKind, claimName] = claimRef.split('/');
|
|
174293
|
+
if ((claimKind === 'GroupClaim' || claimKind === 'UserClaim') &&
|
|
174294
|
+
claimName) {
|
|
174295
|
+
setRenderedClaim({ kind: claimKind, name: claimName }, value);
|
|
174296
|
+
}
|
|
174297
|
+
}
|
|
174591
174298
|
}
|
|
174592
174299
|
previousCRs = alreadyImportedCrs;
|
|
174300
|
+
if (org) {
|
|
174301
|
+
resolveDefaultOwnerHandles(org);
|
|
174302
|
+
}
|
|
174303
|
+
emptyRenderedClaims();
|
|
174593
174304
|
}
|
|
174594
174305
|
async function importGithubGitopsRepository(org, skipPlan, claimsPath, resourcesPath, configPath, filters = [], needsReImport, force) {
|
|
174595
|
-
await setPreviousCRs(resourcesPath);
|
|
174306
|
+
await setPreviousCRs(resourcesPath, org);
|
|
174596
174307
|
configurePaths(randomFolder, '/tmp/tmp-resources', // Not used, but required by renderer
|
|
174597
174308
|
configPath);
|
|
174598
174309
|
importer_src_logger.info(`Importing gitops repository for organization: ${org}`);
|
|
@@ -174959,6 +174670,7 @@ async function reimporter_isDirectory(path) {
|
|
|
174959
174670
|
|
|
174960
174671
|
|
|
174961
174672
|
|
|
174673
|
+
|
|
174962
174674
|
// const MAP_COLLECTION_KIND_CR_KIND: any = {
|
|
174963
174675
|
// gh-members: 'FirestartrGithubMembership',
|
|
174964
174676
|
// gh-group: 'FirestartrGithubGroup',
|
|
@@ -174969,6 +174681,8 @@ async function runImporter(force, skipPlan, claimsPath, crsPath, configPath, cla
|
|
|
174969
174681
|
let generatedFilters = [];
|
|
174970
174682
|
//gh-repo,REGEXP=.*vite.*
|
|
174971
174683
|
cdk8s_renderer.setPath('claimsDefaults', claimsDefaultsPath);
|
|
174684
|
+
setClaimsDefaultsPath(claimsDefaultsPath);
|
|
174685
|
+
loadClaimsDefaultsOnce();
|
|
174972
174686
|
generatedFilters = buildFilters(filters, force, crsPath, generatedFilters);
|
|
174973
174687
|
if (needsReimport) {
|
|
174974
174688
|
await reimportGithubGitopsRepository(org, crsPath, configPath, generatedFilters);
|
|
@@ -363697,7 +363411,7 @@ function helperCreateCheckRunName(cmd, item) {
|
|
|
363697
363411
|
|
|
363698
363412
|
;// CONCATENATED MODULE: ../operator/src/utils/index.ts
|
|
363699
363413
|
const secretRegex = /\$\{\{ secrets\.(.*?) \}\}/g;
|
|
363700
|
-
function
|
|
363414
|
+
function isRecord(value) {
|
|
363701
363415
|
return typeof value === 'object' && value !== null;
|
|
363702
363416
|
}
|
|
363703
363417
|
function getFirstNonEmptyString(...values) {
|
|
@@ -363735,7 +363449,7 @@ function replaceInlineSecrets(inline, secrets) {
|
|
|
363735
363449
|
return result;
|
|
363736
363450
|
}
|
|
363737
363451
|
function extractErrorDetails(error) {
|
|
363738
|
-
const exitCode =
|
|
363452
|
+
const exitCode = isRecord(error) && typeof error.exitCode === 'number'
|
|
363739
363453
|
? error.exitCode
|
|
363740
363454
|
: undefined;
|
|
363741
363455
|
if (typeof error === 'string') {
|
|
@@ -363746,7 +363460,7 @@ function extractErrorDetails(error) {
|
|
|
363746
363460
|
const output = getFirstNonEmptyString(errorWithOutput.output, error.message);
|
|
363747
363461
|
return { output: output ?? String(error), exitCode };
|
|
363748
363462
|
}
|
|
363749
|
-
if (
|
|
363463
|
+
if (isRecord(error)) {
|
|
363750
363464
|
const output = getFirstNonEmptyString(error.output, error.message, error.error);
|
|
363751
363465
|
if (output !== undefined) {
|
|
363752
363466
|
return { output, exitCode };
|
|
@@ -713859,7 +713573,7 @@ const crsStatusSubcommand = {
|
|
|
713859
713573
|
};
|
|
713860
713574
|
|
|
713861
713575
|
;// CONCATENATED MODULE: ./package.json
|
|
713862
|
-
const package_namespaceObject = JSON.parse('{"i8":"2.11.0-snapshot-
|
|
713576
|
+
const package_namespaceObject = JSON.parse('{"i8":"2.11.0-snapshot-mco-03"}');
|
|
713863
713577
|
;// CONCATENATED MODULE: ../../package.json
|
|
713864
713578
|
const package_namespaceObject_1 = {"i8":"2.10.0"};
|
|
713865
713579
|
// EXTERNAL MODULE: ../../node_modules/semver/index.js
|