@firestartr/cli 2.11.0-snapshot-main-1 → 2.11.0-snapshot-patches-patch-claims-3

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 CHANGED
@@ -128395,7 +128395,7 @@ function trasformLeg(leg) {
128395
128395
 
128396
128396
 
128397
128397
  function getFeatureRenderedPathForEntity(entity, featureName, basePath = '/tmp') {
128398
- const entityFolderName = `${entity.metadata.name}`.toLowerCase();
128398
+ const entityFolderName = `${entity.metadata?.name ?? entity.name}`.toLowerCase();
128399
128399
  return external_path_default().join(basePath, entityFolderName, featureName);
128400
128400
  }
128401
128401
  function getFeatureRenderedConfigForComponent(entity, featureName, basePath = '/tmp/features') {
@@ -164488,771 +164488,6 @@ const base_secrets_schema = 'firestartr.dev://common/SecretsClaim';
164488
164488
  SecretsClaimSchema: base_secrets_schema,
164489
164489
  });
164490
164490
 
164491
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/lazy_loader.ts
164492
-
164493
-
164494
-
164495
-
164496
-
164497
-
164498
-
164499
-
164500
-
164501
-
164502
-
164503
-
164504
-
164505
-
164506
-
164507
-
164508
- // We need to ensure the grep command is a gnu version
164509
- let IS_GNU_GREP = false;
164510
- let GREP_ON_CHECK = false;
164511
- // this loop is for avoid race conditions
164512
- // once a check is running no more checks
164513
- async function waitForCheck() {
164514
- const f_wait = () => new Promise((timeOut) => setTimeout(timeOut, 10));
164515
- do {
164516
- await f_wait();
164517
- } while (GREP_ON_CHECK);
164518
- }
164519
- function checkGrep() {
164520
- return new Promise((ok, ko) => {
164521
- // idempotency: already checked
164522
- if (IS_GNU_GREP)
164523
- return ok();
164524
- // a check is already running no new checks
164525
- if (GREP_ON_CHECK)
164526
- return waitForCheck();
164527
- logger.info('Checking the grep command');
164528
- GREP_ON_CHECK = true;
164529
- const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['--version']);
164530
- handler.on('close', (code) => {
164531
- GREP_ON_CHECK = false;
164532
- if (code === 0) {
164533
- logger.debug('Grep is a gnu grep');
164534
- IS_GNU_GREP = true;
164535
- ok();
164536
- }
164537
- else {
164538
- ko('Lazy evaluation needs a gnu-grep command');
164539
- }
164540
- });
164541
- });
164542
- }
164543
- async function loadClaim(claimRef, org, defaults = loadClaimDefaults(), patchClaim = loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, existingRefs = {}, postValidations = new Map()) {
164544
- await checkGrep();
164545
- let result = existingRefs;
164546
- logger.info(`Load reference ${claimRef}`);
164547
- initVirtualClaims(org);
164548
- logger.info(`Load reference (parts) ${claimRef.split(/-/)[0]} ${claimRef.replace(/^[^-]+-/, '')}`);
164549
- // cargas datos con grep
164550
- try {
164551
- const claimData = await lazyGetClaim(claimRef.split(/-/)[0], claimRef.replace(/^[^-]+-/, ''), org, cwd);
164552
- const claim = patchClaim(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(claimData), defaults);
164553
- let variants = [];
164554
- if (claim.kind === 'TFWorkspaceClaim' &&
164555
- claim.providers?.terraform?.variants) {
164556
- variants = claim.providers.terraform.variants;
164557
- delete claim.providers.terraform.variants;
164558
- }
164559
- logger.silly(`Patched claim is:
164560
- ---
164561
- ${catalog_common/* default.io.toYaml */.Z.io.toYaml(claim)}`);
164562
- try {
164563
- validateClaim(claim, base[`${claim.kind}Schema`]);
164564
- await optionalValidation(claim);
164565
- }
164566
- catch (error) {
164567
- let errorMsg = '';
164568
- if (Array.isArray(error)) {
164569
- for (const data of error) {
164570
- errorMsg = `${errorMsg}
164571
- - ${data.instancePath}: ${data.message}`;
164572
- }
164573
- }
164574
- else {
164575
- errorMsg = error instanceof Error ? error.message : String(error);
164576
- }
164577
- throw new Error(`Error when validating claim ${claimRef}: ${errorMsg}`);
164578
- }
164579
- result[claimRef] = {};
164580
- result[claimRef]['claim'] = claim;
164581
- result[claimRef]['claimPath'] = VisitedClaims[claimRef];
164582
- if (VisitedClaims[claimRef] === 'virtual') {
164583
- result = await setVirtualClaimAdditionalData(result, claim, claimRef);
164584
- }
164585
- else {
164586
- result = await setNonVirtualClaimAdditionalData(result, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
164587
- }
164588
- const claimKind = claim.kind;
164589
- const references = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(claim));
164590
- for (const ref of references) {
164591
- if (!result[ref]) {
164592
- const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
164593
- result = lodash_default().merge(result, resolvedReferences);
164594
- }
164595
- }
164596
- if (variants.length > 0) {
164597
- const parentClaimPath = VisitedClaims[claimRef];
164598
- for (const variant of variants) {
164599
- if (!variant.name || !variant.overrides) {
164600
- throw new Error(`Variant in claim ${claimRef} is missing required field 'name' or 'overrides'`);
164601
- }
164602
- const prohibitedOverrideFields = ['source', 'module', 'name'];
164603
- for (const field of prohibitedOverrideFields) {
164604
- if (field in variant.overrides) {
164605
- throw new Error(`Variant '${variant.name}' in claim ${claimRef} cannot override '${field}'`);
164606
- }
164607
- }
164608
- const composedName = claim.providers.terraform.name + '-' + variant.name;
164609
- const variantClaim = lodash_default().cloneDeep(claim);
164610
- variantClaim._parentClaimName = claim.name;
164611
- variantClaim.name = composedName;
164612
- variantClaim.providers.terraform = lodash_default().merge({}, claim.providers.terraform, variant.overrides);
164613
- variantClaim.providers.terraform.name = composedName;
164614
- if (!variantClaim.annotations) {
164615
- variantClaim.annotations = {};
164616
- }
164617
- variantClaim.annotations['firestartr.dev/variant-of'] =
164618
- claim.providers.terraform.name;
164619
- const variantRef = `TFWorkspaceClaim-${composedName}`;
164620
- if (result[variantRef]) {
164621
- throw new Error(`Variant name '${variant.name}' (composed: '${composedName}') from claim '${claimRef}' conflicts with existing claim '${variantRef}'`);
164622
- }
164623
- logger.info(`Creating synthetic variant claim ${variantRef}`);
164624
- result[variantRef] = {};
164625
- result[variantRef]['claim'] = variantClaim;
164626
- result[variantRef]['claimPath'] = parentClaimPath;
164627
- result = await setNonVirtualClaimAdditionalData(result, variantClaim, variantRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
164628
- const variantReferences = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(variantClaim));
164629
- for (const ref of variantReferences) {
164630
- if (!result[ref]) {
164631
- const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
164632
- result = lodash_default().merge(result, resolvedReferences);
164633
- }
164634
- }
164635
- }
164636
- }
164637
- }
164638
- catch (err) {
164639
- throw `Lazy Loading: ${err}`;
164640
- }
164641
- return [result, postValidations];
164642
- }
164643
- let LoadedClaims = {};
164644
- let VisitedClaims = {};
164645
- let DuplicatedClaims = {};
164646
- function resetLazyLoader() {
164647
- LoadedClaims = {};
164648
- VisitedClaims = {};
164649
- DuplicatedClaims = {};
164650
- }
164651
- async function lazyGetClaim(kind, name, org, cwd) {
164652
- const indice = `${kind}-${name}`;
164653
- logger.info(`Lazy loading ${kind}-${name} with index ${indice}`);
164654
- if (indice in LoadedClaims)
164655
- return LoadedClaims[indice];
164656
- if (isVirtualClaim(kind, name)) {
164657
- await loadVirtualClaim(kind, name, org);
164658
- }
164659
- else {
164660
- await getClaimsByName(name, cwd);
164661
- }
164662
- if (indice in LoadedClaims) {
164663
- return LoadedClaims[indice];
164664
- }
164665
- else {
164666
- throw new Error(`Error: ${kind}-${name} not found`);
164667
- }
164668
- }
164669
- async function getClaimsByName(name, cwd = '.') {
164670
- return new Promise((ok, ko) => {
164671
- const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['-r', '-l', '--include=*', '-E', `name: "?${name}"?`, '.'], {
164672
- cwd: cwd,
164673
- });
164674
- logger.info(`Running ${['grep', '-r', '-l', '--include', '-E', 'name: "' + name + '"?', '.'].join(' ')}`);
164675
- const entradas = [];
164676
- const chunks = [];
164677
- handler.stdout.on('data', (data) => {
164678
- chunks.push(data.toString('utf-8'));
164679
- });
164680
- handler.on('close', () => {
164681
- const dataFinal = chunks.join('');
164682
- const fileNameList = dataFinal.split(/\n/).filter((line) => line !== '');
164683
- for (const fileName of fileNameList) {
164684
- // only yaml files
164685
- if (!fileName.match(/\.yml$|\.yaml$/)) {
164686
- continue;
164687
- }
164688
- // only entries not already visited
164689
- if (Object.values(VisitedClaims).includes(fileName)) {
164690
- continue;
164691
- }
164692
- entradas.push(external_path_.join(cwd, fileName));
164693
- }
164694
- return Promise.all(entradas.map((entrada) => {
164695
- return loadRawClaim(entrada);
164696
- }))
164697
- .then(() => {
164698
- ok();
164699
- })
164700
- .catch((err) => {
164701
- ko(err);
164702
- });
164703
- });
164704
- });
164705
- }
164706
- async function loadRawClaim(entry) {
164707
- return new Promise((ok, ko) => {
164708
- external_fs_.readFile(entry, 'utf-8', (error, data) => {
164709
- if (error)
164710
- return ko(`Reading ${entry}: ${error}`);
164711
- const claim = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
164712
- if (!('kind' in claim && 'name' in claim)) {
164713
- logger.warn(`Invalid claim file ${entry}`);
164714
- }
164715
- else {
164716
- const claimKey = `${claim.kind}-${claim.name}`;
164717
- if (Object.keys(DuplicatedClaims).includes(claimKey) &&
164718
- DuplicatedClaims[claimKey] !== entry) {
164719
- return ko(`Duplicated claim ${claimKey} found files: ${DuplicatedClaims[claimKey]} and ${entry}`);
164720
- }
164721
- LoadedClaims[claimKey] = data;
164722
- VisitedClaims[claimKey] = entry;
164723
- DuplicatedClaims[claimKey] = entry;
164724
- ok();
164725
- }
164726
- });
164727
- });
164728
- }
164729
- async function setVirtualClaimAdditionalData(renderedData, claim, claimRef) {
164730
- const virtualClaim = getVirtualClaim(claim.kind, claim.name);
164731
- renderedData[claimRef]['initializers'] = [
164732
- new UUIDInitializer(claim),
164733
- new InitializerClaimRef(),
164734
- new InitializerDefault(virtualClaim.getDefaultConfig()),
164735
- ];
164736
- renderedData[claimRef]['globals'] = [];
164737
- renderedData[claimRef]['overrides'] = [];
164738
- renderedData[claimRef]['normalizers'] = [new NameNormalizer()];
164739
- return renderedData;
164740
- }
164741
- async function setNonVirtualClaimAdditionalData(renderedData, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers) {
164742
- renderedData[claimRef]['initializers'] = await loadInitializers(claim, renderedData[claimRef]['claimPath']);
164743
- renderedData[claimRef]['globals'] = await loadGlobals(claim);
164744
- renderedData[claimRef]['overrides'] = loadOverrides(claim);
164745
- renderedData[claimRef]['normalizers'] = await loadNormalizers(claim, renderedData[claimRef]['claimPath']);
164746
- return renderedData;
164747
- }
164748
- async function loadVirtualClaim(kind, name, org) {
164749
- const virtualClaim = getVirtualClaim(kind, name);
164750
- const expandedClaim = await virtualClaim.expand({ org });
164751
- logger.info(`Loading virtual claim ${kind} ${name} ${org}`);
164752
- LoadedClaims[`${kind}-${name}`] = catalog_common/* default.io.toYaml */.Z.io.toYaml(expandedClaim);
164753
- VisitedClaims[`${kind}-${name}`] = 'virtual';
164754
- }
164755
-
164756
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/claimsDefaulter.ts
164757
-
164758
-
164759
-
164760
- /*
164761
- * Default blocks are objects that cannot be merged but applied as a whole. Meaning:
164762
- * - If the object is defined at the claim-level it is maintained *AS IT IS* (no merge)
164763
- * - If the block is missing at the claim-level, the default block is applied
164764
- */
164765
- const defaultBlocksPaths = ['/providers/terraform/sync'];
164766
- function applyBlockAwareDefaults(claim, defaultClaim) {
164767
- // we always work with a clone of the original
164768
- const claimClone = JSON.parse(JSON.stringify(claim));
164769
- // if the block is claim-level defined we store it here
164770
- const defaultBlocks = new Map();
164771
- // we remove the blocks entirely of the claim
164772
- // to achieve an add copy
164773
- for (const defaultBlockPath of defaultBlocksPaths) {
164774
- if (claimsDefaulter_hasDeepPath(claimClone, defaultBlockPath) !== true)
164775
- continue;
164776
- const originalValue = fast_json_patch_default().getValueByPointer(claimClone, defaultBlockPath);
164777
- if (originalValue) {
164778
- logger.silly(`${claim.kind}/${claim.name}: has an original ${defaultBlockPath}: preserving`);
164779
- defaultBlocks.set(defaultBlockPath, originalValue);
164780
- fast_json_patch_default().applyPatch(claimClone, [{ op: 'remove', path: defaultBlockPath }]);
164781
- }
164782
- }
164783
- // if the patch has the same path of a block
164784
- // and the block was defined at claim-level
164785
- // we interchange the value with the original value
164786
- // otherwise we use the default
164787
- const jsonPatchOps = fast_json_patch_default().compare(claimClone, defaultClaim)
164788
- .filter((jp) => jp.op === 'add')
164789
- .map((jp) => {
164790
- if (defaultBlocks.has(jp.path)) {
164791
- return {
164792
- ...jp,
164793
- value: defaultBlocks.get(jp.path),
164794
- };
164795
- }
164796
- else {
164797
- return jp;
164798
- }
164799
- });
164800
- return fast_json_patch_default().applyPatch(claimClone, jsonPatchOps).newDocument;
164801
- }
164802
- function claimsDefaulter_hasDeepPath(data, deepPath) {
164803
- return lodash_default().has(data, deepPath.replace(/\//g, '.').replace(/^\./, ''));
164804
- }
164805
-
164806
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/loader.ts
164807
-
164808
-
164809
-
164810
-
164811
-
164812
-
164813
-
164814
-
164815
-
164816
-
164817
-
164818
-
164819
-
164820
-
164821
-
164822
- const isYamlFile = new RegExp(/\.(yaml|yml)$/);
164823
- /**
164824
- *
164825
- * @returns Virtual Claims
164826
- */
164827
- const virtualClaims = [new FirestartrAllClaim()];
164828
- /*
164829
- * Loads all applicable globals for a given claim and stores them into a list.
164830
- *
164831
- * Input:
164832
- * - claim: our custom claim object, with which we check if the global is applicable
164833
- *
164834
- * Returns:
164835
- * - A GlobalSection array promise, containing all the globals loaded for this claim
164836
- *
164837
- */
164838
- async function loadGlobals(claim) {
164839
- const result = [];
164840
- await crawl(getPath('globals'), (entry) => {
164841
- return isYamlFile.test(entry);
164842
- }, async (entry, data) => {
164843
- const globalData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
164844
- const ext = external_path_.extname(entry);
164845
- const name = external_path_.basename(entry, ext);
164846
- if (name in SECTIONS_BY_FILE_NAME) {
164847
- const section = new SECTIONS_BY_FILE_NAME[name](globalData);
164848
- if (!(await section.validate(SCHEMAS_BY_SECTION_NAME[name] || {}))) {
164849
- throw new Error(`Invalid ${name} global file`);
164850
- }
164851
- if (globalData.kind === claim.kind) {
164852
- result.push(section);
164853
- }
164854
- else {
164855
- logger.debug(`Skipping global ${name} because it is not applicable to ${claim.kind}`);
164856
- }
164857
- }
164858
- });
164859
- logger.info(`Loaded globals ${result}`);
164860
- return result;
164861
- }
164862
- /*
164863
- * If the input claim is a GithubRepositoryClaim, it loads all it's applicable
164864
- * overrides and stores them into a list. Otherwise, it returns an empty list.
164865
- *
164866
- * Input:
164867
- * - claim: our custom claim object, which should be a GithubRepositoryClaim
164868
- *
164869
- * Returns:
164870
- * - An Overrider array, with a GithubRepositoryOverrider if the claim
164871
- * was a GithubRepositoryClaim, or empty if it was not.
164872
- *
164873
- */
164874
- function loadOverrides(claim) {
164875
- const overrides = [];
164876
- if (claim.kind === 'ComponentClaim' && claim.providers.github.overrides) {
164877
- overrides.push(new GithubRepositoryOverrider());
164878
- }
164879
- return overrides;
164880
- }
164881
- /**
164882
- * Load all normalizers and stores them into a list.
164883
- * @param claim
164884
- * @returns
164885
- */
164886
- async function loadNormalizers(_claim, path) {
164887
- const result = [];
164888
- for (const normalizer of NORMALIZERS) {
164889
- result.push(new normalizer({ path: path }));
164890
- }
164891
- return result;
164892
- }
164893
- /*
164894
- * Loads all applicable initializers for a given claim and stores them into a list.
164895
- *
164896
- * Input:
164897
- * - claim: our custom claim object, with which we check if the initializer is applicable
164898
- *
164899
- * Returns:
164900
- * - An Initializer array promise, containing all the initializers loaded for this claim
164901
- *
164902
- */
164903
- let loadedInitializers = false;
164904
- async function loadInitializers(claim, claimPath, initializersPath = getPath('initializers')) {
164905
- const result = [];
164906
- await crawl(initializersPath, (entry) => {
164907
- return isYamlFile.test(entry);
164908
- }, async (entry, data) => {
164909
- const initializerData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
164910
- const ext = external_path_.extname(entry);
164911
- const name = external_path_.basename(entry, ext);
164912
- if (name in INITIALIZERS_BY_FILE_NAME) {
164913
- const initializerBfN = new INITIALIZERS_BY_FILE_NAME[name](initializerData);
164914
- if (!(await initializerBfN.validate(SCHEMAS_BY_INITIALIZER_NAME[name] || {}))) {
164915
- throw new Error(`Invalid ${name} initializer file`);
164916
- }
164917
- if (initializerData.kind === claim.kind) {
164918
- result.push(initializerBfN);
164919
- }
164920
- else {
164921
- logger.debug(`Skipping initializer ${name} because it is not applicable to ${claim.kind}`);
164922
- }
164923
- }
164924
- });
164925
- for (const initializer of INITIALIZERS) {
164926
- if (initializer.applicableKinds.includes(claim.kind)) {
164927
- result.push(new initializer({ path: claimPath }));
164928
- }
164929
- }
164930
- logger.info(`Loaded initializers ${JSON.stringify(result)}`);
164931
- loadedInitializers = result;
164932
- return loadedInitializers;
164933
- }
164934
- function loadClaimDefaults() {
164935
- try {
164936
- return catalog_common/* default.io.fromYaml */.Z.io.fromYaml(external_fs_.readFileSync(`${getPath('claimsDefaults')}/claims_defaults.yaml`, 'utf-8'));
164937
- }
164938
- catch (error) {
164939
- const errMsg = `Could not read claims defaults file in path ${getPath('claimsDefaults')}/claims_defaults.yaml: ${error}`;
164940
- logger.error(errMsg);
164941
- throw new Error(errMsg);
164942
- }
164943
- }
164944
- /*
164945
- * Using fast-json-patch, compares a claim to its kind's defaults, then patches it.
164946
- *
164947
- * Input:
164948
- * - claim: our custom claim object, which we want to patch
164949
- * - defaultsClaims: an object, containing the defaults for each claim kind,
164950
- * with the same structure that we use for the actual claims
164951
- *
164952
- * Returns:
164953
- * - The patched claim
164954
- *
164955
- */
164956
- function loader_patchClaim(claim, defaultsClaims) {
164957
- if (defaultsClaims[claim.kind]) {
164958
- claim = applyBlockAwareDefaults(claim, defaultsClaims[claim.kind]);
164959
- }
164960
- return claim;
164961
- }
164962
- async function loadCRsWithFullSet(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
164963
- const result = {};
164964
- const fullResult = {};
164965
- await crawlWithExclusions(crsPath, (entry) => {
164966
- return isYamlFile.test(entry);
164967
- }, async (entry, data) => {
164968
- const yamlData = stripKnownRelations(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data));
164969
- const metadata = yamlData?.metadata;
164970
- if (!(yamlData &&
164971
- typeof yamlData === 'object' &&
164972
- 'kind' in yamlData &&
164973
- metadata &&
164974
- typeof metadata === 'object' &&
164975
- 'name' in metadata)) {
164976
- logger.warn(`Invalid CR file ${entry}`);
164977
- }
164978
- else {
164979
- const crKey = `${yamlData.kind}-${metadata.name}`;
164980
- if (fullResult[crKey]) {
164981
- logger.error(`Duplicate CR ${crKey}`);
164982
- }
164983
- // Keep the complete CR set for validations that need repository-wide context.
164984
- fullResult[crKey] = yamlData;
164985
- // Keep the filtered CR set for previous-CR lookup during claim rendering.
164986
- if (allowedClaimReferences.length === 0 ||
164987
- allowedClaimReferences.includes(yamlData.metadata?.annotations?.[catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('claim-ref')])) {
164988
- result[crKey] = yamlData;
164989
- }
164990
- }
164991
- }, excludedPaths.concat(getAdditionalPaths()));
164992
- return { crs: result, fullCrs: fullResult };
164993
- }
164994
- async function loadCRs(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
164995
- const { crs } = await loadCRsWithFullSet(crsPath, excludedPaths, allowedClaimReferences);
164996
- return crs;
164997
- }
164998
- /*
164999
- * Description: Get the renamed using claimRef annotation
165000
- * Input: claims: any, crs: any
165001
- * Output: renames: IRenameResult[]
165002
- */
165003
- async function loadRenames(claims, crs) {
165004
- /*
165005
- * If checkRenames is false, we don't need to check for renames
165006
- */
165007
- const renamesEnabled = getRenamesEnabled();
165008
- if (!renamesEnabled)
165009
- return [];
165010
- const result = [];
165011
- /**
165012
- * For each CR, look for a claim that does not match the name with CR's firestartr.dev/claim-ref annotation
165013
- */
165014
- for (const cr of Object.values(crs)) {
165015
- const anyCr = cr;
165016
- if (!anyCr?.metadata?.annotations)
165017
- continue;
165018
- // if the annotation is a claimRef
165019
- const annotationName = common.generic.getFirestartrAnnotation('claim-ref');
165020
- const annotations = anyCr?.metadata?.annotations || {};
165021
- if (annotationName in annotations) {
165022
- const claimRef = anyCr.metadata.annotations[annotationName];
165023
- // split the annotation into kind and name
165024
- const [kind, name] = claimRef.split('/');
165025
- // if the claim exists, check if the name is different for the given provider
165026
- const referencedClaim = claims[`${kind}-${name}`].claim;
165027
- const oldName = anyCr.metadata.name;
165028
- const newName = referencedClaim.providers[getConfiguredProvider()].name;
165029
- if (oldName !== newName) {
165030
- result.push({
165031
- kind: referencedClaim.kind,
165032
- claimPath: claims[`${kind}-${name}`].claimPath,
165033
- claimName: referencedClaim.name,
165034
- oldName,
165035
- newName,
165036
- });
165037
- }
165038
- }
165039
- }
165040
- return result;
165041
- }
165042
- async function loadClaimsList(claimRefList, claimsPath = getPath('claims')) {
165043
- const data = {
165044
- renderClaims: {},
165045
- crs: {},
165046
- fullCrs: {},
165047
- };
165048
- const defaults = loadClaimDefaults();
165049
- for await (const claimRef of claimRefList) {
165050
- const [renderedClaimData] = await loadClaim(claimRef, getOrg(), defaults, loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, claimsPath);
165051
- data.renderClaims = lodash_default().merge(data.renderClaims, renderedClaimData);
165052
- }
165053
- const crClaimReferences = [];
165054
- for (const ref of Object.keys(data.renderClaims)) {
165055
- // Replaces only the first instance of '-'
165056
- crClaimReferences.push(ref.replace('-', '/'));
165057
- }
165058
- const loadedCrs = await loadCRsWithFullSet(getPath('crs'), [getPath('globals'), getPath('initializers')], crClaimReferences);
165059
- data['crs'] = loadedCrs.crs;
165060
- data['fullCrs'] = loadedCrs.fullCrs;
165061
- return data;
165062
- }
165063
- function getOrg() {
165064
- const groupOrg = catalog_common/* default.environment.getFromEnvironmentWithDefault */.Z.environment.getFromEnvironmentWithDefault(catalog_common/* default.types.envVars.org */.Z.types.envVars.org, '');
165065
- return groupOrg;
165066
- }
165067
-
165068
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/references.ts
165069
- function validateTfStateKeyUniqueness(crs) {
165070
- const tfStateKeys = {};
165071
- for (const crKey of Object.keys(crs)) {
165072
- const cr = crs[crKey];
165073
- if (!isTerraformWorkspace(cr))
165074
- continue;
165075
- const tfKey = cr.spec.firestartr.tfStateKey;
165076
- if (tfStateKeys[tfKey]) {
165077
- throw new Error(`❗❗ ❌ RENDER ERROR ❌ ❗❗
165078
-
165079
- The tfStateKey ${tfKey} is not unique,
165080
-
165081
- It is being used by the following CRs:
165082
-
165083
- - ${tfStateKeys[tfKey].kind} ${tfStateKeys[tfKey].metadata.name}
165084
-
165085
- - ${cr.kind} ${cr.metadata.name}
165086
-
165087
- Check the following Claims to ensure that the tfStateKey is unique:
165088
-
165089
- - ${tfStateKeys[tfKey].metadata.annotations['firestartr.dev/claim-ref']}
165090
-
165091
- - ${cr.metadata.annotations['firestartr.dev/claim-ref']}
165092
- `);
165093
- }
165094
- tfStateKeys[cr.spec.firestartr.tfStateKey] = cr;
165095
- }
165096
- }
165097
- function references_isCatalogEntity(cr) {
165098
- return [
165099
- 'Component',
165100
- 'Domain',
165101
- 'System',
165102
- 'User',
165103
- 'Group',
165104
- 'Resource',
165105
- ].includes(cr.kind);
165106
- }
165107
- function isTerraformWorkspace(cr) {
165108
- return cr.kind === 'FirestartrTerraformWorkspace';
165109
- }
165110
-
165111
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/crSize.ts
165112
-
165113
- const K8S_OBJECT_SIZE_LIMIT = 1572864; // 1.5 MiB in bytes, etcd recommended limit: https://etcd.io/docs/latest/dev-guide/limit/
165114
- function validateCrSizes(crs) {
165115
- for (const key of Object.keys(crs)) {
165116
- const cr = crs[key];
165117
- const serialized = catalog_common/* default.io.toYaml */.Z.io.toYaml(cr);
165118
- const size = Buffer.byteLength(serialized, 'utf8');
165119
- if (size > K8S_OBJECT_SIZE_LIMIT) {
165120
- 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).`);
165121
- }
165122
- }
165123
- }
165124
-
165125
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/permissions.ts
165126
-
165127
- function validatePermissionsUniqueness(crs) {
165128
- for (const crkey in crs) {
165129
- const cr = crs[crkey];
165130
- if (cr.kind === 'FirestartrGithubRepository') {
165131
- const permissions = cr.spec.permissions;
165132
- logger.debug(`Validating Permissions Uniqueness of ${crkey}`);
165133
- if (permissions) {
165134
- const rolesByIdentifier = new Map();
165135
- for (const perm of permissions) {
165136
- const identifier = perm.collaborator
165137
- ? perm.collaborator
165138
- : `ref:${perm.ref.kind}:${perm.ref.name}`;
165139
- const role = perm.role;
165140
- const prevRole = rolesByIdentifier.get(identifier);
165141
- if (prevRole === undefined) {
165142
- rolesByIdentifier.set(identifier, role);
165143
- }
165144
- else if (prevRole !== role) {
165145
- throw new Error(`Conflicting permission role in FirestartrGithubRepository ${crkey}: ${identifier} has roles "${prevRole}" and "${role}".\nFull CR: ${JSON.stringify(cr, null, 2)}`);
165146
- }
165147
- }
165148
- }
165149
- }
165150
- }
165151
- }
165152
-
165153
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/backstageAnnotations.ts
165154
- const backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX = 'firestartr.backstage.dev/';
165155
- const CATALOG_KINDS = new Set([
165156
- 'User',
165157
- 'Group',
165158
- 'Component',
165159
- 'System',
165160
- 'Domain',
165161
- 'API',
165162
- 'Resource',
165163
- 'CatalogKubernetesResource',
165164
- 'CatalogTerraformWorkspace',
165165
- 'CatalogArgoDeploy',
165166
- 'CatalogOrgWebhook',
165167
- 'CatalogSecrets',
165168
- ]);
165169
- function validateNoBackstageAnnotationsInK8sCrs(crs) {
165170
- for (const crKey in crs) {
165171
- const cr = crs[crKey];
165172
- if (CATALOG_KINDS.has(cr.kind))
165173
- continue;
165174
- if (cr.metadata?.annotations) {
165175
- const backstageKeys = Object.keys(cr.metadata.annotations).filter((k) => k.startsWith(backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX));
165176
- if (backstageKeys.length > 0) {
165177
- throw new Error(`K8s CR ${crKey} contains Backstage-only annotations (${backstageKeys.join(', ')}). ` +
165178
- `Annotations with prefix ${backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX} must only appear on Backstage catalog entities, not on Kubernetes CRs.`);
165179
- }
165180
- }
165181
- }
165182
- }
165183
-
165184
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/refsSorter/refsSorter.ts
165185
-
165186
- /**
165187
- * @param renderClaims renderClaims to sort
165188
- * @param kinds kinds to get from renderClaims
165189
- * @returns renderClaims with only the kinds specified
165190
- */
165191
- function sortRenderClaimsByKind(renderClaims, kinds) {
165192
- let result = {};
165193
- for (const kind of kinds) {
165194
- for (const key in renderClaims) {
165195
- if (renderClaims[key].claim.kind === kind) {
165196
- result[key] = renderClaims[key];
165197
- }
165198
- }
165199
- result = sortSelfKindRefs(result, kind);
165200
- }
165201
- return result;
165202
- }
165203
- function sortSelfKindRefs(renderClaims, kind) {
165204
- if (!hasSelfRefs(kind)) {
165205
- return renderClaims;
165206
- }
165207
- const newRenderClaims = {};
165208
- const data = extractRefs(renderClaims, kind);
165209
- const ordered = [];
165210
- const visiting = [];
165211
- const visited = [];
165212
- for (const key of Object.keys(data)) {
165213
- if (!visited.find((obj) => obj.name === key)) {
165214
- sortRefs(data, data[key], ordered, visiting, visited);
165215
- }
165216
- }
165217
- for (const cr of ordered) {
165218
- newRenderClaims[cr.name] = renderClaims[cr.name];
165219
- }
165220
- return newRenderClaims;
165221
- }
165222
- function sortRefs(data, claim, ordered = [], visiting = [], visited = []) {
165223
- if (visiting.find((obj) => obj.name === claim.name)) {
165224
- throw new Error(`Circular dependency detected for '${claim.name}'`);
165225
- }
165226
- if (!visited.find((obj) => obj.name === claim.name)) {
165227
- visiting.push(claim);
165228
- if (claim.refs) {
165229
- for (const ref of claim.refs) {
165230
- const referencedObject = data[ref];
165231
- if (!referencedObject) {
165232
- throw new Error(`Reference '${ref}' does not exist for '${claim.name}'`);
165233
- }
165234
- sortRefs(data, referencedObject, ordered, visiting, visited);
165235
- }
165236
- }
165237
- visited.push(visiting.pop());
165238
- ordered.push(claim);
165239
- }
165240
- }
165241
- function hasSelfRefs(kind) {
165242
- return ['TFWorkspaceClaim', 'GroupClaim'].includes(kind);
165243
- }
165244
-
165245
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/renderer/claims-sorter.ts
165246
-
165247
- function sortKinds(orderedKinds, claims) {
165248
- const result = [];
165249
- for (const kind of orderedKinds) {
165250
- const kindRenderClaims = sortRenderClaimsByKind(claims, [kind]);
165251
- result.push(kindRenderClaims);
165252
- }
165253
- return result;
165254
- }
165255
-
165256
164491
  ;// CONCATENATED MODULE: ../features_renderer/src/common.ts
165257
164492
 
165258
164493
  function isDirectory(path) {
@@ -165292,15 +164527,19 @@ var ajv_default = /*#__PURE__*/__nccwpck_require__.n(dist_ajv);
165292
164527
  $ref: '#/definitions/File',
165293
164528
  },
165294
164529
  },
164530
+ claimPatches: {
164531
+ type: 'array',
164532
+ items: {
164533
+ $ref: '#/definitions/Patch',
164534
+ },
164535
+ },
164536
+ // Legacy field kept for backward compatibility. Feature authors may
164537
+ // still ship `patches`, but the renderer ignores it for claim-level
164538
+ // behaviour. Claim-level patches must come from `claimPatches`.
165295
164539
  patches: {
165296
- type: 'object',
165297
- patternProperties: {
165298
- '^.+$': {
165299
- type: 'array',
165300
- items: {
165301
- $ref: '#/definitions/Patch',
165302
- },
165303
- },
164540
+ type: 'array',
164541
+ items: {
164542
+ $ref: '#/definitions/Patch',
165304
164543
  },
165305
164544
  },
165306
164545
  filesTemplates: {
@@ -165323,7 +164562,7 @@ var ajv_default = /*#__PURE__*/__nccwpck_require__.n(dist_ajv);
165323
164562
  },
165324
164563
  },
165325
164564
  },
165326
- required: ['args', 'feature_name', 'files', 'patches'],
164565
+ required: ['args', 'feature_name', 'files'],
165327
164566
  title: 'root',
165328
164567
  },
165329
164568
  Args: {
@@ -165403,7 +164642,7 @@ var ajv_default = /*#__PURE__*/__nccwpck_require__.n(dist_ajv);
165403
164642
  type: 'string',
165404
164643
  },
165405
164644
  value: {
165406
- type: 'string',
164645
+ type: ['string', 'object', 'array', 'number', 'boolean', 'null'],
165407
164646
  },
165408
164647
  },
165409
164648
  required: ['name', 'op', 'path'],
@@ -165445,6 +164684,12 @@ function __validateFeatureConfig(featurePath) {
165445
164684
  }
165446
164685
  }
165447
164686
  function __validateFeatureConfigData(configData) {
164687
+ // Detect old provider-keyed claimPatches shape for migration hint.
164688
+ if (configData.claimPatches &&
164689
+ !Array.isArray(configData.claimPatches) &&
164690
+ typeof configData.claimPatches === 'object') {
164691
+ throw `Feature: config.yaml invalid claimPatches: expected flat array of claimPatches (claim-relative pointers like /annotations/backstage.io~1techdocs-ref), but got provider-keyed object ${JSON.stringify(Object.keys(configData.claimPatches))}. Migrate: claimPatches: { catalog: [...] } → claimPatches: [{ op, path: /annotations/backstage.io~1techdocs-ref, value }]. $ref paths also migrate: [spec, org] → [providers, github, org], [metadata, annotations, firestartr.dev/external-name] → [providers, github, name]`;
164692
+ }
165448
164693
  const ajv = new (ajv_default())({
165449
164694
  allowUnionTypes: true,
165450
164695
  });
@@ -165466,14 +164711,12 @@ function stripAnchoringConstraints(schemaDef) {
165466
164711
  return clone;
165467
164712
  }
165468
164713
  function __validateJsonPatches(configData) {
165469
- const keys = Object.keys(configData.patches);
165470
- for (const key of keys) {
165471
- if (configData.patches[key]) {
165472
- if (fast_json_patch_default().validate(configData.patches[key])) {
165473
- const errors = JSON.stringify(fast_json_patch_default().validate(configData.patches[key]).message);
165474
- throw `Feature: config.yaml -> patches: invalid patches ${errors}`;
165475
- }
165476
- }
164714
+ const patches = configData.claimPatches;
164715
+ if (!Array.isArray(patches))
164716
+ return;
164717
+ const err = fast_json_patch_default().validate(patches);
164718
+ if (err) {
164719
+ throw `Feature: config.yaml -> claimPatches: invalid claimPatches ${JSON.stringify(err.message ?? err)}`;
165477
164720
  }
165478
164721
  }
165479
164722
 
@@ -166311,10 +165554,12 @@ const renderTestsSchema = {
166311
165554
  items: {
166312
165555
  type: 'object',
166313
165556
  additionalProperties: false,
166314
- required: ['name', 'cr'],
165557
+ required: ['name'],
165558
+ anyOf: [{ required: ['cr'] }, { required: ['claim'] }],
166315
165559
  properties: {
166316
165560
  name: { type: 'string', minLength: 1 },
166317
165561
  cr: { type: 'string', minLength: 1 },
165562
+ claim: { type: 'string', minLength: 1 },
166318
165563
  args: { type: 'object' },
166319
165564
  },
166320
165565
  },
@@ -166369,6 +165614,9 @@ function resolveCrPath(featurePath, crRelPath) {
166369
165614
  }
166370
165615
  return resolved;
166371
165616
  }
165617
+ function resolveClaimPath(featurePath, claimRelPath) {
165618
+ return resolveCrPath(featurePath, claimRelPath);
165619
+ }
166372
165620
  function listYamlFiles(dir) {
166373
165621
  if (!fs.existsSync(dir))
166374
165622
  return [];
@@ -166432,7 +165680,7 @@ function buildExpectedOutput(config, renderDir) {
166432
165680
  }));
166433
165681
  return {
166434
165682
  files,
166435
- patches: config.patches || [],
165683
+ claimPatches: config.claimPatches || [],
166436
165684
  };
166437
165685
  }
166438
165686
  /* ---------- Context-style API for a render temp dir ---------- */
@@ -166486,6 +165734,7 @@ async function createRenderContext(prefix = 'feature-render-') {
166486
165734
  buildExpectedOutput,
166487
165735
  loadAndValidateRenderTests,
166488
165736
  resolveCrPath,
165737
+ resolveClaimPath,
166489
165738
  });
166490
165739
 
166491
165740
  ;// CONCATENATED MODULE: ../features_renderer/src/featureArgsValidation.ts
@@ -166578,7 +165827,7 @@ function render(featurePath, featureRenderPath, entity, firestartrConfig = {}, f
166578
165827
  resolveInside(featureRenderPath, dest, 'file dest', 'render target directory');
166579
165828
  }
166580
165829
  }
166581
- const output = { files: [] };
165830
+ const output = { files: [], claimPatches: [] };
166582
165831
  context.config.files.forEach((file) => {
166583
165832
  const { src, dest } = file;
166584
165833
  // For now let's keep upgradable flag for backward compatibility
@@ -166599,7 +165848,11 @@ function render(featurePath, featureRenderPath, entity, firestartrConfig = {}, f
166599
165848
  userManaged: userManaged,
166600
165849
  targetBranch,
166601
165850
  });
166602
- output.patches = context.config.patches;
165851
+ // claimPatches are applied to the claim during claim stitching. Present
165852
+ // in the output even when empty. The legacy `patches` field is deliberately
165853
+ // not copied: it is accepted in config.yaml for backward compatibility but
165854
+ // ignored for claim-level behaviour.
165855
+ output.claimPatches = context.config.claimPatches || [];
166603
165856
  // Not used anymore
166604
165857
  // output.unpatches = context.config.unpatches
166605
165858
  });
@@ -166609,19 +165862,97 @@ function render(featurePath, featureRenderPath, entity, firestartrConfig = {}, f
166609
165862
  external_fs_default().writeFileSync(configFile, JSON.stringify(output));
166610
165863
  return output;
166611
165864
  }
166612
- function buildContext(entity, args, firestartrConfig, featureArgs) {
165865
+ function getClaimPatches(featurePath, entity, firestartrConfig = {}, featureArgs = {}) {
165866
+ const configData = validate(featurePath);
165867
+ validateFeatureArgs(featurePath, featureArgs);
165868
+ const context = buildContext(entity, configData.args, firestartrConfig, featureArgs);
165869
+ const rendered = JSON.parse(renderContent(JSON.stringify(configData), context));
165870
+ return rendered.claimPatches ?? [];
165871
+ }
165872
+ function buildContext(stitchedClaim, args, firestartrConfig, featureArgs) {
166613
165873
  const context = {};
165874
+ const resolveRef = (doc, ref) => {
165875
+ const v = lodash_default().get(doc, ref);
165876
+ if (v !== undefined)
165877
+ return v;
165878
+ // Fallback for transition: try CR-shaped alternatives when stitchedClaim is CR-shaped
165879
+ // and vice versa. Covers the ADR 0006 table plus legacy feature_a provisioner paths.
165880
+ const altTable = {
165881
+ 'providers,github,org': [
165882
+ ['spec', 'org'],
165883
+ ['spec', 'provisioner', 'org'],
165884
+ ['spec', 'firestartr', 'technology', 'stack'],
165885
+ ],
165886
+ 'providers,github,branchStrategy,defaultBranch': [
165887
+ ['spec', 'repo', 'defaultBranch'],
165888
+ ['spec', 'provisioner', 'repo', 'defaultBranch'],
165889
+ ],
165890
+ 'providers,github,name': [
165891
+ ['metadata', 'annotations', 'firestartr.dev/external-name'],
165892
+ ['metadata', 'name'],
165893
+ ],
165894
+ name: [['metadata', 'name']],
165895
+ 'annotations,firestartr.dev/dest-annotation': [
165896
+ ['metadata', 'annotations', 'firestartr.dev/dest-annotation'],
165897
+ ],
165898
+ };
165899
+ const key = ref.join(',');
165900
+ const alts = altTable[key];
165901
+ if (alts) {
165902
+ for (const alt of alts) {
165903
+ const av = lodash_default().get(doc, alt);
165904
+ if (av !== undefined)
165905
+ return av;
165906
+ }
165907
+ }
165908
+ // Reverse fallback: if ref is CR-shaped, try claim-shaped
165909
+ const reverseTable = {
165910
+ 'spec,org': ['providers', 'github', 'org'],
165911
+ 'spec,provisioner,technology,stack': ['providers', 'github', 'org'],
165912
+ 'spec,firestartr,technology,stack': ['providers', 'github', 'org'],
165913
+ 'metadata,name': ['name'],
165914
+ 'metadata,annotations,firestartr.dev/dest-annotation': [
165915
+ 'annotations',
165916
+ 'firestartr.dev/dest-annotation',
165917
+ ],
165918
+ 'spec,provisioner,org': ['providers', 'github', 'org'],
165919
+ 'spec,provisioner,repo,defaultBranch': [
165920
+ 'providers',
165921
+ 'github',
165922
+ 'branchStrategy',
165923
+ 'defaultBranch',
165924
+ ],
165925
+ 'spec,repo,defaultBranch': [
165926
+ 'providers',
165927
+ 'github',
165928
+ 'branchStrategy',
165929
+ 'defaultBranch',
165930
+ ],
165931
+ 'metadata,annotations,firestartr.dev/external-name': [
165932
+ 'providers',
165933
+ 'github',
165934
+ 'name',
165935
+ ],
165936
+ };
165937
+ const rev = reverseTable[ref.join(',')];
165938
+ if (rev) {
165939
+ const rv = lodash_default().get(doc, rev);
165940
+ if (rv !== undefined)
165941
+ return rv;
165942
+ }
165943
+ return v;
165944
+ };
166614
165945
  Object.entries(args).forEach(([key, arg]) => {
166615
165946
  if ('$default' in arg) {
166616
165947
  if (Array.isArray(arg['$default'])) {
166617
- context[key] = lodash_default().get(entity, arg['$default']);
165948
+ context[key] = resolveRef(stitchedClaim, arg['$default']);
166618
165949
  }
166619
165950
  else {
166620
165951
  context[key] = arg['$default'];
166621
165952
  }
166622
165953
  }
166623
165954
  if ('$ref' in arg) {
166624
- const refValue = lodash_default().get(entity, arg['$ref']);
165955
+ const refValue = resolveRef(stitchedClaim, arg['$ref']);
166625
165956
  context[key] = refValue;
166626
165957
  }
166627
165958
  else if ('$lit' in arg) {
@@ -166751,6 +166082,7 @@ function updateFileContent(featureRenderPath, filePath, content) {
166751
166082
 
166752
166083
 
166753
166084
 
166085
+
166754
166086
  /* harmony default export */ const features_renderer = ({
166755
166087
  validate: validate,
166756
166088
  render: render,
@@ -166760,6 +166092,7 @@ function updateFileContent(featureRenderPath, filePath, content) {
166760
166092
  renderContent: renderContent,
166761
166093
  expandFiles: expandFiles,
166762
166094
  validateFeatureArgs: validateFeatureArgs,
166095
+ getClaimPatches: getClaimPatches,
166763
166096
  });
166764
166097
 
166765
166098
  ;// CONCATENATED MODULE: ../features_preparer/src/logger.ts
@@ -166784,6 +166117,13 @@ function renderFeature(featureName, version, owner, repo, featureOwner, renderPa
166784
166117
  function renderFeatureFromPath(extractPath, renderedPath, featureOwner, featureArgs = {}) {
166785
166118
  return features_renderer.render(extractPath, renderedPath, featureOwner, {}, featureArgs);
166786
166119
  }
166120
+ function getFeatureClaimPatches(featureName, version, owner, repo, featureOwner, featureArgs = {}) {
166121
+ const extractPath = external_path_default().join(catalog_common/* default.features.tarballs.getFeaturesExtractPath */.Z.features.tarballs.getFeaturesExtractPath(featureName, version, owner, repo), 'packages', featureName);
166122
+ return getClaimPatches(extractPath, featureOwner, {}, featureArgs);
166123
+ }
166124
+ function getFeatureClaimPatchesFromPath(extractPath, featureOwner, featureArgs = {}) {
166125
+ return getClaimPatches(extractPath, featureOwner, {}, featureArgs);
166126
+ }
166787
166127
 
166788
166128
  // EXTERNAL MODULE: ../../node_modules/adm-zip/adm-zip.js
166789
166129
  var adm_zip = __nccwpck_require__(7993);
@@ -166844,6 +166184,26 @@ featureArgs = {}, repo = 'features', owner = 'prefapp') {
166844
166184
  };
166845
166185
  return renderFeature(featureName, reference, owner, repo, featureOwner, '/tmp', featureArgs);
166846
166186
  }
166187
+ async function installer_getFeatureClaimPatches(featureName, version, featureOwner, featureArgs = {}, repo = 'features', owner = 'prefapp') {
166188
+ const reference = `${featureName}-v${version}`;
166189
+ return processFeatureClaimPatches(featureName, reference, featureOwner, featureArgs, repo, owner);
166190
+ }
166191
+ async function getFeatureClaimPatchesFromRef(featureName, featureRef, featureOwner, featureArgs = {}, repo = 'features', owner = 'prefapp') {
166192
+ const reference = `${featureRef}`;
166193
+ return processFeatureClaimPatches(featureName, reference, featureOwner, featureArgs, repo, owner);
166194
+ }
166195
+ async function processFeatureClaimPatches(featureName, reference, featureOwner, featureArgs = {}, repo = 'features', owner = 'prefapp') {
166196
+ await downloadFeatureZip(repo, featureName, reference, owner);
166197
+ featureArgs['traceability'] = {
166198
+ version: reference,
166199
+ owner,
166200
+ repo,
166201
+ name: featureName,
166202
+ ref: reference,
166203
+ url: `https://github.com/${owner}/${repo}/tree/${reference}/packages/${featureName}`,
166204
+ };
166205
+ return getFeatureClaimPatches(featureName, reference, owner, repo, featureOwner, featureArgs);
166206
+ }
166847
166207
  async function prepareFeature(featureName, version, repo = 'features', owner = 'prefapp') {
166848
166208
  await downloadFeatureZip(repo, featureName, version, owner);
166849
166209
  }
@@ -166898,6 +166258,9 @@ async function downloadFeatureZip(repo, featureName, reference, owner = 'prefapp
166898
166258
  /* harmony default export */ const src = ({
166899
166259
  renderFeature: renderFeature,
166900
166260
  renderFeatureFromPath: renderFeatureFromPath,
166261
+ getFeatureClaimPatches: installer_getFeatureClaimPatches,
166262
+ getFeatureClaimPatchesFromRef: getFeatureClaimPatchesFromRef,
166263
+ getFeatureClaimPatchesFromPath: getFeatureClaimPatchesFromPath,
166901
166264
  getFeatureConfigFromRef: getFeatureConfigFromRef,
166902
166265
  getFeatureConfig: getFeatureConfig,
166903
166266
  prepareFeature: prepareFeature,
@@ -166914,6 +166277,1118 @@ async function downloadFeatureZip(repo, featureName, reference, owner = 'prefapp
166914
166277
  getFeatureConfigFromRef: src.getFeatureConfigFromRef,
166915
166278
  });
166916
166279
 
166280
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/claims/stitching/protectedPaths.ts
166281
+ // Platform-curated protected claim paths — features may not write to these.
166282
+ // Stored as JSON Pointers (RFC 6901). Supports wildcard `*` for a single segment.
166283
+ // Example: /providers/STAR/org matches /providers/github/org where STAR is *.
166284
+ const PROTECTED_CLAIM_PATHS = [
166285
+ '/kind',
166286
+ '/name',
166287
+ '/providers/*/org',
166288
+ '/providers/github/org',
166289
+ '/providers/github/name',
166290
+ '/metadata/name',
166291
+ '/metadata/namespace',
166292
+ ];
166293
+ function isProtectedPath(patchPath) {
166294
+ const normalizedPatch = normalizePointer(patchPath);
166295
+ for (const protectedPath of PROTECTED_CLAIM_PATHS) {
166296
+ if (matchesProtected(protectedPath, normalizedPatch)) {
166297
+ return true;
166298
+ }
166299
+ }
166300
+ return false;
166301
+ }
166302
+ function normalizePointer(pointer) {
166303
+ if (!pointer.startsWith('/')) {
166304
+ return '/' + pointer;
166305
+ }
166306
+ return pointer;
166307
+ }
166308
+ function matchesProtected(protectedPointer, patchPointer) {
166309
+ const protectedSegments = protectedPointer
166310
+ .split('/')
166311
+ .slice(1)
166312
+ .map(unescapePointer);
166313
+ const patchSegments = patchPointer.split('/').slice(1).map(unescapePointer);
166314
+ // Treat ancestor/descendant as protected: a patch to a parent (e.g. /metadata)
166315
+ // would replace the protected child (/metadata/name), and a patch to a child
166316
+ // (e.g. /metadata/name/extra) is also under the protected tree. Match when
166317
+ // the shorter prefix equals the longer prefix (with wildcard support).
166318
+ const minLen = Math.min(protectedSegments.length, patchSegments.length);
166319
+ for (let i = 0; i < minLen; i++) {
166320
+ if (protectedSegments[i] === '*')
166321
+ continue;
166322
+ if (protectedSegments[i] !== patchSegments[i])
166323
+ return false;
166324
+ }
166325
+ return true;
166326
+ }
166327
+ function unescapePointer(segment) {
166328
+ return segment.replace(/~1/g, '/').replace(/~0/g, '~');
166329
+ }
166330
+
166331
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/claims/stitching/errors.ts
166332
+ class StitchingError extends Error {
166333
+ constructor(violations) {
166334
+ const lines = violations.map((v) => ` - ${v.message}`).join('\n');
166335
+ super(`Claim stitching failed with ${violations.length} violation(s):\n${lines}`);
166336
+ this.name = 'StitchingError';
166337
+ this.violations = violations;
166338
+ }
166339
+ }
166340
+ function formatStitchingError(error) {
166341
+ return error.message;
166342
+ }
166343
+
166344
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/claims/stitching/stitching.ts
166345
+
166346
+
166347
+
166348
+
166349
+ let MOCK_FEATURES_FN;
166350
+ function MOCK_STITCHING_FEATURES(mock) {
166351
+ MOCK_FEATURES_FN = mock;
166352
+ }
166353
+ function pointerExists(doc, pointer) {
166354
+ const segments = pointer
166355
+ .split('/')
166356
+ .slice(1)
166357
+ .map((s) => s.replace(/~1/g, '/').replace(/~0/g, '~'));
166358
+ let cur = doc;
166359
+ for (const seg of segments) {
166360
+ if (cur === null || cur === undefined || typeof cur !== 'object')
166361
+ return false;
166362
+ if (!Object.prototype.hasOwnProperty.call(cur, seg))
166363
+ return false;
166364
+ cur = cur[seg];
166365
+ }
166366
+ return true;
166367
+ }
166368
+ function isAppendPointer(pointer) {
166369
+ return pointer.endsWith('/-');
166370
+ }
166371
+ function isRecord(value) {
166372
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
166373
+ }
166374
+ // Deduplication identity for a feature patch. Ordinary writes collide on the
166375
+ // normalized pointer. Array appends (`add ... /-`) collide on the pointer plus
166376
+ // the appended element's `name` when present, for example so several features can each add
166377
+ // a distinct label to /providers/github/labels/- while the same label name from
166378
+ // two features is silently deduplicated (or errors if values differ).
166379
+ function writeIdentity(patch) {
166380
+ const path = normalizePointer(patch.path);
166381
+ if (patch.op === 'add' &&
166382
+ isAppendPointer(path) &&
166383
+ isRecord(patch.value) &&
166384
+ typeof patch.value.name === 'string') {
166385
+ return `${path}#${patch.value.name}`;
166386
+ }
166387
+ return path;
166388
+ }
166389
+ // Check whether an array at `appendPath`'s parent already contains an element
166390
+ // whose `name` matches `value.name`. Used for the "claim wins" gate: when a
166391
+ // feature tries to append an array element that already exists in the claim,
166392
+ // the patch is silently dropped.
166393
+ function arrayElementExists(doc, appendPath, value) {
166394
+ if (!isRecord(value) || typeof value.name !== 'string')
166395
+ return false;
166396
+ const parentPath = appendPath.slice(0, -2); // strip trailing /-
166397
+ const segments = parentPath
166398
+ .split('/')
166399
+ .slice(1)
166400
+ .map((s) => s.replace(/~1/g, '/').replace(/~0/g, '~'));
166401
+ let cur = doc;
166402
+ for (const seg of segments) {
166403
+ if (cur === null || cur === undefined || typeof cur !== 'object')
166404
+ return false;
166405
+ if (!Object.prototype.hasOwnProperty.call(cur, seg))
166406
+ return false;
166407
+ cur = cur[seg];
166408
+ }
166409
+ if (!Array.isArray(cur))
166410
+ return false;
166411
+ return cur.some((el) => isRecord(el) && el.name === value.name);
166412
+ }
166413
+ // fast-json-patch does not create intermediate containers for `add`, and
166414
+ // appending to an array requires the array to already exist. Ensure every
166415
+ // ancestor segment exists before applying an `add`: missing containers are
166416
+ // created as objects, except the immediate parent of a `/-` append, which is
166417
+ // created as an array. Existing (user/default-declared) values are never
166418
+ // overwritten.
166419
+ function ensureAddParents(doc, patch) {
166420
+ const segments = patch.path.split('/').slice(1);
166421
+ let prefix = '';
166422
+ for (let i = 0; i < segments.length - 1; i++) {
166423
+ prefix += '/' + segments[i];
166424
+ if (pointerExists(doc, prefix))
166425
+ continue;
166426
+ const isArrayParent = isAppendPointer(patch.path) && i === segments.length - 2;
166427
+ const value = isArrayParent ? [] : {};
166428
+ try {
166429
+ doc = fast_json_patch.applyPatch(doc, [{ op: 'add', path: prefix, value }], false, false).newDocument;
166430
+ }
166431
+ catch {
166432
+ // Concurrent structural conflict — let the actual patch surface the error.
166433
+ }
166434
+ }
166435
+ return doc;
166436
+ }
166437
+ async function stitchClaim(claimAfterDefaults, preCollectedEnvelopes) {
166438
+ const envelopes = preCollectedEnvelopes ?? (await collectFeaturePatches(claimAfterDefaults));
166439
+ if (envelopes.length === 0) {
166440
+ return claimAfterDefaults;
166441
+ }
166442
+ // Normalize all patches once so every gate and the apply phase use the same pointers.
166443
+ const normalizedEnvelopes = envelopes.map((env) => ({
166444
+ feature: env.feature,
166445
+ patches: env.patches.map((p) => ({
166446
+ ...p,
166447
+ path: normalizePointer(p.path),
166448
+ _raw: p.path,
166449
+ })),
166450
+ }));
166451
+ // ── Phase 1: silently drop patches that should not be applied ──────────
166452
+ // • Array append whose element already exists in the claim → claim wins
166453
+ // • Duplicate identity with identical value across features → silent dedup
166454
+ const dropped = new Set(); // "envelopeIdx:patchIdx"
166455
+ const seenIdentities = new Map();
166456
+ for (let ei = 0; ei < normalizedEnvelopes.length; ei++) {
166457
+ const envelope = normalizedEnvelopes[ei];
166458
+ for (let pi = 0; pi < envelope.patches.length; pi++) {
166459
+ const patch = envelope.patches[pi];
166460
+ const key = `${ei}:${pi}`;
166461
+ // Array claim-wins: element already in claim → drop
166462
+ if (patch.op === 'add' && isAppendPointer(patch.path)) {
166463
+ if (arrayElementExists(claimAfterDefaults, patch.path, patch.value)) {
166464
+ dropped.add(key);
166465
+ continue;
166466
+ }
166467
+ }
166468
+ // Silent dedup: same identity + same value → drop
166469
+ const identity = writeIdentity(patch);
166470
+ const existing = seenIdentities.get(identity);
166471
+ if (existing) {
166472
+ if (JSON.stringify(existing.value) === JSON.stringify(patch.value)) {
166473
+ dropped.add(key);
166474
+ continue;
166475
+ }
166476
+ // Different value — kept here, caught as a violation in Phase 2.
166477
+ }
166478
+ else {
166479
+ seenIdentities.set(identity, {
166480
+ feature: envelope.feature,
166481
+ value: patch.value,
166482
+ });
166483
+ }
166484
+ }
166485
+ }
166486
+ // ── Phase 2: collect violations on non-dropped patches ─────────────────
166487
+ const violations = [];
166488
+ const seenForViolations = new Map(); // identity → feature
166489
+ for (let ei = 0; ei < normalizedEnvelopes.length; ei++) {
166490
+ const envelope = normalizedEnvelopes[ei];
166491
+ for (let pi = 0; pi < envelope.patches.length; pi++) {
166492
+ if (dropped.has(`${ei}:${pi}`))
166493
+ continue;
166494
+ const patch = envelope.patches[pi];
166495
+ const path = patch.path;
166496
+ const raw = patch._raw ?? path;
166497
+ // Gate 1: protected path
166498
+ if (isProtectedPath(path)) {
166499
+ violations.push({
166500
+ feature: envelope.feature,
166501
+ op: patch.op,
166502
+ path,
166503
+ reason: 'protected-path',
166504
+ message: `Feature '${envelope.feature}' patch ${patch.op} ${raw} (normalized ${path}) targets protected claim path`,
166505
+ });
166506
+ }
166507
+ // Gate 2: conflicting value from another feature
166508
+ const identity = writeIdentity(patch);
166509
+ if (seenForViolations.has(identity)) {
166510
+ violations.push({
166511
+ feature: envelope.feature,
166512
+ op: patch.op,
166513
+ path,
166514
+ reason: 'duplicate-path',
166515
+ conflictingFeature: seenForViolations.get(identity),
166516
+ message: `Feature '${envelope.feature}' and '${seenForViolations.get(identity)}' both write to ${path} (deduplication)`,
166517
+ });
166518
+ }
166519
+ else {
166520
+ seenForViolations.set(identity, envelope.feature);
166521
+ }
166522
+ // Gate 3: replace / remove to an absent path
166523
+ if (['replace', 'remove'].includes(patch.op)) {
166524
+ if (!pointerExists(claimAfterDefaults, path)) {
166525
+ violations.push({
166526
+ feature: envelope.feature,
166527
+ op: patch.op,
166528
+ path,
166529
+ reason: 'overwrite-protected',
166530
+ message: `Feature '${envelope.feature}' patch ${patch.op} ${raw} (normalized ${path}) targets absent path (replace/remove requires existing value)`,
166531
+ });
166532
+ }
166533
+ }
166534
+ }
166535
+ }
166536
+ if (violations.length > 0) {
166537
+ throw new StitchingError(violations);
166538
+ }
166539
+ // ── Phase 3: apply remaining patches ───────────────────────────────────
166540
+ let stitched = JSON.parse(JSON.stringify(claimAfterDefaults));
166541
+ for (let ei = 0; ei < normalizedEnvelopes.length; ei++) {
166542
+ const envelope = normalizedEnvelopes[ei];
166543
+ const patchesToApply = envelope.patches.filter((_, pi) => !dropped.has(`${ei}:${pi}`));
166544
+ if (patchesToApply.length === 0)
166545
+ continue;
166546
+ for (const patch of patchesToApply) {
166547
+ if (patch.op === 'add') {
166548
+ stitched = ensureAddParents(stitched, patch);
166549
+ }
166550
+ }
166551
+ const result = fast_json_patch.applyPatch(stitched, patchesToApply, false, false);
166552
+ stitched = result.newDocument;
166553
+ }
166554
+ return stitched;
166555
+ }
166556
+ async function collectFeaturePatches(claim) {
166557
+ if (MOCK_FEATURES_FN) {
166558
+ return MOCK_FEATURES_FN(claim);
166559
+ }
166560
+ const typedClaim = claim;
166561
+ const features = typedClaim.providers?.github?.features ?? [];
166562
+ if (features.length === 0)
166563
+ return [];
166564
+ // In unit tests without GitHub credentials, avoid real download — tests that care
166565
+ // about stitching should set MOCK_STITCHING_FEATURES explicitly.
166566
+ if (process.env.JEST_WORKER_ID && !process.env.GITHUB_TOKEN) {
166567
+ return [];
166568
+ }
166569
+ const envelopes = [];
166570
+ for (const feature of features) {
166571
+ const featureName = feature.name;
166572
+ const versionOrRef = feature.ref ?? feature.version ?? '';
166573
+ const repo = feature.repo
166574
+ ? (feature.repo.split('/')[1] ?? 'features')
166575
+ : 'features';
166576
+ const owner = feature.repo
166577
+ ? (feature.repo.split('/')[0] ?? 'prefapp')
166578
+ : 'prefapp';
166579
+ const args = feature.args ?? {};
166580
+ try {
166581
+ let patchesOrRendered;
166582
+ const preparerAny = features_preparer;
166583
+ if (feature.ref) {
166584
+ if (typeof preparerAny.getFeatureClaimPatchesFromRef === 'function') {
166585
+ patchesOrRendered = await preparerAny.getFeatureClaimPatchesFromRef(featureName, versionOrRef, claim, args, repo, owner);
166586
+ }
166587
+ else {
166588
+ patchesOrRendered = await preparerAny.getFeatureConfigFromRef(featureName, versionOrRef, claim, args, repo, owner);
166589
+ }
166590
+ }
166591
+ else {
166592
+ if (typeof preparerAny.getFeatureClaimPatches === 'function') {
166593
+ patchesOrRendered = await preparerAny.getFeatureClaimPatches(featureName, versionOrRef, claim, args, repo, owner);
166594
+ }
166595
+ else {
166596
+ patchesOrRendered = await preparerAny.getFeatureConfig(featureName, versionOrRef, claim, args, repo, owner);
166597
+ }
166598
+ }
166599
+ const patches = Array.isArray(patchesOrRendered)
166600
+ ? patchesOrRendered
166601
+ : extractClaimPatches(patchesOrRendered);
166602
+ envelopes.push({ feature: featureName, patches });
166603
+ }
166604
+ catch (err) {
166605
+ throw new Error(`Failed to collect claimPatches for feature '${featureName}': ${err instanceof Error ? err.message : String(err)}`);
166606
+ }
166607
+ }
166608
+ return envelopes;
166609
+ }
166610
+ function extractClaimPatches(rendered) {
166611
+ const patches = rendered.claimPatches;
166612
+ if (!patches)
166613
+ return [];
166614
+ if (Array.isArray(patches))
166615
+ return patches;
166616
+ throw new Error(`Feature claimPatches must be a flat array (claim-relative pointers like /annotations/...), got ${typeof patches}: ${JSON.stringify(patches).slice(0, 200)}`);
166617
+ }
166618
+
166619
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/lazy_loader.ts
166620
+
166621
+
166622
+
166623
+
166624
+
166625
+
166626
+
166627
+
166628
+
166629
+
166630
+
166631
+
166632
+
166633
+
166634
+
166635
+
166636
+
166637
+ // We need to ensure the grep command is a gnu version
166638
+ let IS_GNU_GREP = false;
166639
+ let GREP_ON_CHECK = false;
166640
+ // this loop is for avoid race conditions
166641
+ // once a check is running no more checks
166642
+ async function waitForCheck() {
166643
+ const f_wait = () => new Promise((timeOut) => setTimeout(timeOut, 10));
166644
+ do {
166645
+ await f_wait();
166646
+ } while (GREP_ON_CHECK);
166647
+ }
166648
+ function checkGrep() {
166649
+ return new Promise((ok, ko) => {
166650
+ // idempotency: already checked
166651
+ if (IS_GNU_GREP)
166652
+ return ok();
166653
+ // a check is already running no new checks
166654
+ if (GREP_ON_CHECK)
166655
+ return waitForCheck();
166656
+ logger.info('Checking the grep command');
166657
+ GREP_ON_CHECK = true;
166658
+ const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['--version']);
166659
+ handler.on('close', (code) => {
166660
+ GREP_ON_CHECK = false;
166661
+ if (code === 0) {
166662
+ logger.debug('Grep is a gnu grep');
166663
+ IS_GNU_GREP = true;
166664
+ ok();
166665
+ }
166666
+ else {
166667
+ ko('Lazy evaluation needs a gnu-grep command');
166668
+ }
166669
+ });
166670
+ });
166671
+ }
166672
+ async function loadClaim(claimRef, org, defaults = loadClaimDefaults(), patchClaim = loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, existingRefs = {}, postValidations = new Map()) {
166673
+ await checkGrep();
166674
+ let result = existingRefs;
166675
+ logger.info(`Load reference ${claimRef}`);
166676
+ initVirtualClaims(org);
166677
+ logger.info(`Load reference (parts) ${claimRef.split(/-/)[0]} ${claimRef.replace(/^[^-]+-/, '')}`);
166678
+ // cargas datos con grep
166679
+ try {
166680
+ const claimData = await lazyGetClaim(claimRef.split(/-/)[0], claimRef.replace(/^[^-]+-/, ''), org, cwd);
166681
+ let claim = patchClaim(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(claimData), defaults);
166682
+ // Claim stitching: feature claim-patches with three gates before AJV
166683
+ try {
166684
+ claim = await stitchClaim(claim);
166685
+ }
166686
+ catch (e) {
166687
+ throw new Error(`Error when stitching claim ${claimRef}: ${e instanceof Error ? e.message : String(e)}`);
166688
+ }
166689
+ let variants = [];
166690
+ if (claim.kind === 'TFWorkspaceClaim' &&
166691
+ claim.providers?.terraform?.variants) {
166692
+ variants = claim.providers.terraform.variants;
166693
+ delete claim.providers.terraform.variants;
166694
+ }
166695
+ logger.silly(`Patched claim is:
166696
+ ---
166697
+ ${catalog_common/* default.io.toYaml */.Z.io.toYaml(claim)}`);
166698
+ try {
166699
+ validateClaim(claim, base[`${claim.kind}Schema`]);
166700
+ await optionalValidation(claim);
166701
+ }
166702
+ catch (error) {
166703
+ let errorMsg = '';
166704
+ if (Array.isArray(error)) {
166705
+ for (const data of error) {
166706
+ errorMsg = `${errorMsg}
166707
+ - ${data.instancePath}: ${data.message}`;
166708
+ }
166709
+ }
166710
+ else {
166711
+ errorMsg = error instanceof Error ? error.message : String(error);
166712
+ }
166713
+ throw new Error(`Error when validating claim ${claimRef}: ${errorMsg}`);
166714
+ }
166715
+ result[claimRef] = {};
166716
+ result[claimRef]['claim'] = claim;
166717
+ result[claimRef]['claimPath'] = VisitedClaims[claimRef];
166718
+ if (VisitedClaims[claimRef] === 'virtual') {
166719
+ result = await setVirtualClaimAdditionalData(result, claim, claimRef);
166720
+ }
166721
+ else {
166722
+ result = await setNonVirtualClaimAdditionalData(result, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
166723
+ }
166724
+ const claimKind = claim.kind;
166725
+ const references = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(claim));
166726
+ for (const ref of references) {
166727
+ if (!result[ref]) {
166728
+ const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
166729
+ result = lodash_default().merge(result, resolvedReferences);
166730
+ }
166731
+ }
166732
+ if (variants.length > 0) {
166733
+ const parentClaimPath = VisitedClaims[claimRef];
166734
+ for (const variant of variants) {
166735
+ if (!variant.name || !variant.overrides) {
166736
+ throw new Error(`Variant in claim ${claimRef} is missing required field 'name' or 'overrides'`);
166737
+ }
166738
+ const prohibitedOverrideFields = ['source', 'module', 'name'];
166739
+ for (const field of prohibitedOverrideFields) {
166740
+ if (field in variant.overrides) {
166741
+ throw new Error(`Variant '${variant.name}' in claim ${claimRef} cannot override '${field}'`);
166742
+ }
166743
+ }
166744
+ const composedName = claim.providers.terraform.name + '-' + variant.name;
166745
+ const variantClaim = lodash_default().cloneDeep(claim);
166746
+ variantClaim._parentClaimName = claim.name;
166747
+ variantClaim.name = composedName;
166748
+ variantClaim.providers.terraform = lodash_default().merge({}, claim.providers.terraform, variant.overrides);
166749
+ variantClaim.providers.terraform.name = composedName;
166750
+ if (!variantClaim.annotations) {
166751
+ variantClaim.annotations = {};
166752
+ }
166753
+ variantClaim.annotations['firestartr.dev/variant-of'] =
166754
+ claim.providers.terraform.name;
166755
+ const variantRef = `TFWorkspaceClaim-${composedName}`;
166756
+ if (result[variantRef]) {
166757
+ throw new Error(`Variant name '${variant.name}' (composed: '${composedName}') from claim '${claimRef}' conflicts with existing claim '${variantRef}'`);
166758
+ }
166759
+ logger.info(`Creating synthetic variant claim ${variantRef}`);
166760
+ result[variantRef] = {};
166761
+ result[variantRef]['claim'] = variantClaim;
166762
+ result[variantRef]['claimPath'] = parentClaimPath;
166763
+ result = await setNonVirtualClaimAdditionalData(result, variantClaim, variantRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
166764
+ const variantReferences = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(variantClaim));
166765
+ for (const ref of variantReferences) {
166766
+ if (!result[ref]) {
166767
+ const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
166768
+ result = lodash_default().merge(result, resolvedReferences);
166769
+ }
166770
+ }
166771
+ }
166772
+ }
166773
+ }
166774
+ catch (err) {
166775
+ throw `Lazy Loading: ${err}`;
166776
+ }
166777
+ return [result, postValidations];
166778
+ }
166779
+ let LoadedClaims = {};
166780
+ let VisitedClaims = {};
166781
+ let DuplicatedClaims = {};
166782
+ function resetLazyLoader() {
166783
+ LoadedClaims = {};
166784
+ VisitedClaims = {};
166785
+ DuplicatedClaims = {};
166786
+ }
166787
+ async function lazyGetClaim(kind, name, org, cwd) {
166788
+ const indice = `${kind}-${name}`;
166789
+ logger.info(`Lazy loading ${kind}-${name} with index ${indice}`);
166790
+ if (indice in LoadedClaims)
166791
+ return LoadedClaims[indice];
166792
+ if (isVirtualClaim(kind, name)) {
166793
+ await loadVirtualClaim(kind, name, org);
166794
+ }
166795
+ else {
166796
+ await getClaimsByName(name, cwd);
166797
+ }
166798
+ if (indice in LoadedClaims) {
166799
+ return LoadedClaims[indice];
166800
+ }
166801
+ else {
166802
+ throw new Error(`Error: ${kind}-${name} not found`);
166803
+ }
166804
+ }
166805
+ async function getClaimsByName(name, cwd = '.') {
166806
+ return new Promise((ok, ko) => {
166807
+ const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['-r', '-l', '--include=*', '-E', `name: "?${name}"?`, '.'], {
166808
+ cwd: cwd,
166809
+ });
166810
+ logger.info(`Running ${['grep', '-r', '-l', '--include', '-E', 'name: "' + name + '"?', '.'].join(' ')}`);
166811
+ const entradas = [];
166812
+ const chunks = [];
166813
+ handler.stdout.on('data', (data) => {
166814
+ chunks.push(data.toString('utf-8'));
166815
+ });
166816
+ handler.on('close', () => {
166817
+ const dataFinal = chunks.join('');
166818
+ const fileNameList = dataFinal.split(/\n/).filter((line) => line !== '');
166819
+ for (const fileName of fileNameList) {
166820
+ // only yaml files
166821
+ if (!fileName.match(/\.yml$|\.yaml$/)) {
166822
+ continue;
166823
+ }
166824
+ // only entries not already visited
166825
+ if (Object.values(VisitedClaims).includes(fileName)) {
166826
+ continue;
166827
+ }
166828
+ entradas.push(external_path_.join(cwd, fileName));
166829
+ }
166830
+ return Promise.all(entradas.map((entrada) => {
166831
+ return loadRawClaim(entrada);
166832
+ }))
166833
+ .then(() => {
166834
+ ok();
166835
+ })
166836
+ .catch((err) => {
166837
+ ko(err);
166838
+ });
166839
+ });
166840
+ });
166841
+ }
166842
+ async function loadRawClaim(entry) {
166843
+ return new Promise((ok, ko) => {
166844
+ external_fs_.readFile(entry, 'utf-8', (error, data) => {
166845
+ if (error)
166846
+ return ko(`Reading ${entry}: ${error}`);
166847
+ const claim = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
166848
+ if (!('kind' in claim && 'name' in claim)) {
166849
+ logger.warn(`Invalid claim file ${entry}`);
166850
+ }
166851
+ else {
166852
+ const claimKey = `${claim.kind}-${claim.name}`;
166853
+ if (Object.keys(DuplicatedClaims).includes(claimKey) &&
166854
+ DuplicatedClaims[claimKey] !== entry) {
166855
+ return ko(`Duplicated claim ${claimKey} found files: ${DuplicatedClaims[claimKey]} and ${entry}`);
166856
+ }
166857
+ LoadedClaims[claimKey] = data;
166858
+ VisitedClaims[claimKey] = entry;
166859
+ DuplicatedClaims[claimKey] = entry;
166860
+ ok();
166861
+ }
166862
+ });
166863
+ });
166864
+ }
166865
+ async function setVirtualClaimAdditionalData(renderedData, claim, claimRef) {
166866
+ const virtualClaim = getVirtualClaim(claim.kind, claim.name);
166867
+ renderedData[claimRef]['initializers'] = [
166868
+ new UUIDInitializer(claim),
166869
+ new InitializerClaimRef(),
166870
+ new InitializerDefault(virtualClaim.getDefaultConfig()),
166871
+ ];
166872
+ renderedData[claimRef]['globals'] = [];
166873
+ renderedData[claimRef]['overrides'] = [];
166874
+ renderedData[claimRef]['normalizers'] = [new NameNormalizer()];
166875
+ return renderedData;
166876
+ }
166877
+ async function setNonVirtualClaimAdditionalData(renderedData, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers) {
166878
+ renderedData[claimRef]['initializers'] = await loadInitializers(claim, renderedData[claimRef]['claimPath']);
166879
+ renderedData[claimRef]['globals'] = await loadGlobals(claim);
166880
+ renderedData[claimRef]['overrides'] = loadOverrides(claim);
166881
+ renderedData[claimRef]['normalizers'] = await loadNormalizers(claim, renderedData[claimRef]['claimPath']);
166882
+ return renderedData;
166883
+ }
166884
+ async function loadVirtualClaim(kind, name, org) {
166885
+ const virtualClaim = getVirtualClaim(kind, name);
166886
+ const expandedClaim = await virtualClaim.expand({ org });
166887
+ logger.info(`Loading virtual claim ${kind} ${name} ${org}`);
166888
+ LoadedClaims[`${kind}-${name}`] = catalog_common/* default.io.toYaml */.Z.io.toYaml(expandedClaim);
166889
+ VisitedClaims[`${kind}-${name}`] = 'virtual';
166890
+ }
166891
+
166892
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/claimsDefaulter.ts
166893
+
166894
+
166895
+
166896
+ /*
166897
+ * Default blocks are objects that cannot be merged but applied as a whole. Meaning:
166898
+ * - If the object is defined at the claim-level it is maintained *AS IT IS* (no merge)
166899
+ * - If the block is missing at the claim-level, the default block is applied
166900
+ */
166901
+ const defaultBlocksPaths = ['/providers/terraform/sync'];
166902
+ function applyBlockAwareDefaults(claim, defaultClaim) {
166903
+ // we always work with a clone of the original
166904
+ const claimClone = JSON.parse(JSON.stringify(claim));
166905
+ // if the block is claim-level defined we store it here
166906
+ const defaultBlocks = new Map();
166907
+ // we remove the blocks entirely of the claim
166908
+ // to achieve an add copy
166909
+ for (const defaultBlockPath of defaultBlocksPaths) {
166910
+ if (claimsDefaulter_hasDeepPath(claimClone, defaultBlockPath) !== true)
166911
+ continue;
166912
+ const originalValue = fast_json_patch_default().getValueByPointer(claimClone, defaultBlockPath);
166913
+ if (originalValue) {
166914
+ logger.silly(`${claim.kind}/${claim.name}: has an original ${defaultBlockPath}: preserving`);
166915
+ defaultBlocks.set(defaultBlockPath, originalValue);
166916
+ fast_json_patch_default().applyPatch(claimClone, [{ op: 'remove', path: defaultBlockPath }]);
166917
+ }
166918
+ }
166919
+ // if the patch has the same path of a block
166920
+ // and the block was defined at claim-level
166921
+ // we interchange the value with the original value
166922
+ // otherwise we use the default
166923
+ const jsonPatchOps = fast_json_patch_default().compare(claimClone, defaultClaim)
166924
+ .filter((jp) => jp.op === 'add')
166925
+ .map((jp) => {
166926
+ if (defaultBlocks.has(jp.path)) {
166927
+ return {
166928
+ ...jp,
166929
+ value: defaultBlocks.get(jp.path),
166930
+ };
166931
+ }
166932
+ else {
166933
+ return jp;
166934
+ }
166935
+ });
166936
+ return fast_json_patch_default().applyPatch(claimClone, jsonPatchOps).newDocument;
166937
+ }
166938
+ function claimsDefaulter_hasDeepPath(data, deepPath) {
166939
+ return lodash_default().has(data, deepPath.replace(/\//g, '.').replace(/^\./, ''));
166940
+ }
166941
+
166942
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/loader.ts
166943
+
166944
+
166945
+
166946
+
166947
+
166948
+
166949
+
166950
+
166951
+
166952
+
166953
+
166954
+
166955
+
166956
+
166957
+
166958
+ const isYamlFile = new RegExp(/\.(yaml|yml)$/);
166959
+ /**
166960
+ *
166961
+ * @returns Virtual Claims
166962
+ */
166963
+ const virtualClaims = [new FirestartrAllClaim()];
166964
+ /*
166965
+ * Loads all applicable globals for a given claim and stores them into a list.
166966
+ *
166967
+ * Input:
166968
+ * - claim: our custom claim object, with which we check if the global is applicable
166969
+ *
166970
+ * Returns:
166971
+ * - A GlobalSection array promise, containing all the globals loaded for this claim
166972
+ *
166973
+ */
166974
+ async function loadGlobals(claim) {
166975
+ const result = [];
166976
+ await crawl(getPath('globals'), (entry) => {
166977
+ return isYamlFile.test(entry);
166978
+ }, async (entry, data) => {
166979
+ const globalData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
166980
+ const ext = external_path_.extname(entry);
166981
+ const name = external_path_.basename(entry, ext);
166982
+ if (name in SECTIONS_BY_FILE_NAME) {
166983
+ const section = new SECTIONS_BY_FILE_NAME[name](globalData);
166984
+ if (!(await section.validate(SCHEMAS_BY_SECTION_NAME[name] || {}))) {
166985
+ throw new Error(`Invalid ${name} global file`);
166986
+ }
166987
+ if (globalData.kind === claim.kind) {
166988
+ result.push(section);
166989
+ }
166990
+ else {
166991
+ logger.debug(`Skipping global ${name} because it is not applicable to ${claim.kind}`);
166992
+ }
166993
+ }
166994
+ });
166995
+ logger.info(`Loaded globals ${result}`);
166996
+ return result;
166997
+ }
166998
+ /*
166999
+ * If the input claim is a GithubRepositoryClaim, it loads all it's applicable
167000
+ * overrides and stores them into a list. Otherwise, it returns an empty list.
167001
+ *
167002
+ * Input:
167003
+ * - claim: our custom claim object, which should be a GithubRepositoryClaim
167004
+ *
167005
+ * Returns:
167006
+ * - An Overrider array, with a GithubRepositoryOverrider if the claim
167007
+ * was a GithubRepositoryClaim, or empty if it was not.
167008
+ *
167009
+ */
167010
+ function loadOverrides(claim) {
167011
+ const overrides = [];
167012
+ if (claim.kind === 'ComponentClaim' && claim.providers.github.overrides) {
167013
+ overrides.push(new GithubRepositoryOverrider());
167014
+ }
167015
+ return overrides;
167016
+ }
167017
+ /**
167018
+ * Load all normalizers and stores them into a list.
167019
+ * @param claim
167020
+ * @returns
167021
+ */
167022
+ async function loadNormalizers(_claim, path) {
167023
+ const result = [];
167024
+ for (const normalizer of NORMALIZERS) {
167025
+ result.push(new normalizer({ path: path }));
167026
+ }
167027
+ return result;
167028
+ }
167029
+ /*
167030
+ * Loads all applicable initializers for a given claim and stores them into a list.
167031
+ *
167032
+ * Input:
167033
+ * - claim: our custom claim object, with which we check if the initializer is applicable
167034
+ *
167035
+ * Returns:
167036
+ * - An Initializer array promise, containing all the initializers loaded for this claim
167037
+ *
167038
+ */
167039
+ let loadedInitializers = false;
167040
+ async function loadInitializers(claim, claimPath, initializersPath = getPath('initializers')) {
167041
+ const result = [];
167042
+ await crawl(initializersPath, (entry) => {
167043
+ return isYamlFile.test(entry);
167044
+ }, async (entry, data) => {
167045
+ const initializerData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
167046
+ const ext = external_path_.extname(entry);
167047
+ const name = external_path_.basename(entry, ext);
167048
+ if (name in INITIALIZERS_BY_FILE_NAME) {
167049
+ const initializerBfN = new INITIALIZERS_BY_FILE_NAME[name](initializerData);
167050
+ if (!(await initializerBfN.validate(SCHEMAS_BY_INITIALIZER_NAME[name] || {}))) {
167051
+ throw new Error(`Invalid ${name} initializer file`);
167052
+ }
167053
+ if (initializerData.kind === claim.kind) {
167054
+ result.push(initializerBfN);
167055
+ }
167056
+ else {
167057
+ logger.debug(`Skipping initializer ${name} because it is not applicable to ${claim.kind}`);
167058
+ }
167059
+ }
167060
+ });
167061
+ for (const initializer of INITIALIZERS) {
167062
+ if (initializer.applicableKinds.includes(claim.kind)) {
167063
+ result.push(new initializer({ path: claimPath }));
167064
+ }
167065
+ }
167066
+ logger.info(`Loaded initializers ${JSON.stringify(result)}`);
167067
+ loadedInitializers = result;
167068
+ return loadedInitializers;
167069
+ }
167070
+ function loadClaimDefaults() {
167071
+ try {
167072
+ return catalog_common/* default.io.fromYaml */.Z.io.fromYaml(external_fs_.readFileSync(`${getPath('claimsDefaults')}/claims_defaults.yaml`, 'utf-8'));
167073
+ }
167074
+ catch (error) {
167075
+ const errMsg = `Could not read claims defaults file in path ${getPath('claimsDefaults')}/claims_defaults.yaml: ${error}`;
167076
+ logger.error(errMsg);
167077
+ throw new Error(errMsg);
167078
+ }
167079
+ }
167080
+ /*
167081
+ * Using fast-json-patch, compares a claim to its kind's defaults, then patches it.
167082
+ *
167083
+ * Input:
167084
+ * - claim: our custom claim object, which we want to patch
167085
+ * - defaultsClaims: an object, containing the defaults for each claim kind,
167086
+ * with the same structure that we use for the actual claims
167087
+ *
167088
+ * Returns:
167089
+ * - The patched claim
167090
+ *
167091
+ */
167092
+ function loader_patchClaim(claim, defaultsClaims) {
167093
+ if (defaultsClaims[claim.kind]) {
167094
+ claim = applyBlockAwareDefaults(claim, defaultsClaims[claim.kind]);
167095
+ }
167096
+ return claim;
167097
+ }
167098
+ async function loadCRsWithFullSet(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
167099
+ const result = {};
167100
+ const fullResult = {};
167101
+ await crawlWithExclusions(crsPath, (entry) => {
167102
+ return isYamlFile.test(entry);
167103
+ }, async (entry, data) => {
167104
+ const yamlData = stripKnownRelations(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data));
167105
+ const metadata = yamlData?.metadata;
167106
+ if (!(yamlData &&
167107
+ typeof yamlData === 'object' &&
167108
+ 'kind' in yamlData &&
167109
+ metadata &&
167110
+ typeof metadata === 'object' &&
167111
+ 'name' in metadata)) {
167112
+ logger.warn(`Invalid CR file ${entry}`);
167113
+ }
167114
+ else {
167115
+ const crKey = `${yamlData.kind}-${metadata.name}`;
167116
+ if (fullResult[crKey]) {
167117
+ logger.error(`Duplicate CR ${crKey}`);
167118
+ }
167119
+ // Keep the complete CR set for validations that need repository-wide context.
167120
+ fullResult[crKey] = yamlData;
167121
+ // Keep the filtered CR set for previous-CR lookup during claim rendering.
167122
+ if (allowedClaimReferences.length === 0 ||
167123
+ allowedClaimReferences.includes(yamlData.metadata?.annotations?.[catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('claim-ref')])) {
167124
+ result[crKey] = yamlData;
167125
+ }
167126
+ }
167127
+ }, excludedPaths.concat(getAdditionalPaths()));
167128
+ return { crs: result, fullCrs: fullResult };
167129
+ }
167130
+ async function loadCRs(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
167131
+ const { crs } = await loadCRsWithFullSet(crsPath, excludedPaths, allowedClaimReferences);
167132
+ return crs;
167133
+ }
167134
+ /*
167135
+ * Description: Get the renamed using claimRef annotation
167136
+ * Input: claims: any, crs: any
167137
+ * Output: renames: IRenameResult[]
167138
+ */
167139
+ async function loadRenames(claims, crs) {
167140
+ /*
167141
+ * If checkRenames is false, we don't need to check for renames
167142
+ */
167143
+ const renamesEnabled = getRenamesEnabled();
167144
+ if (!renamesEnabled)
167145
+ return [];
167146
+ const result = [];
167147
+ /**
167148
+ * For each CR, look for a claim that does not match the name with CR's firestartr.dev/claim-ref annotation
167149
+ */
167150
+ for (const cr of Object.values(crs)) {
167151
+ const anyCr = cr;
167152
+ if (!anyCr?.metadata?.annotations)
167153
+ continue;
167154
+ // if the annotation is a claimRef
167155
+ const annotationName = common.generic.getFirestartrAnnotation('claim-ref');
167156
+ const annotations = anyCr?.metadata?.annotations || {};
167157
+ if (annotationName in annotations) {
167158
+ const claimRef = anyCr.metadata.annotations[annotationName];
167159
+ // split the annotation into kind and name
167160
+ const [kind, name] = claimRef.split('/');
167161
+ // if the claim exists, check if the name is different for the given provider
167162
+ const referencedClaim = claims[`${kind}-${name}`].claim;
167163
+ const oldName = anyCr.metadata.name;
167164
+ const newName = referencedClaim.providers[getConfiguredProvider()].name;
167165
+ if (oldName !== newName) {
167166
+ result.push({
167167
+ kind: referencedClaim.kind,
167168
+ claimPath: claims[`${kind}-${name}`].claimPath,
167169
+ claimName: referencedClaim.name,
167170
+ oldName,
167171
+ newName,
167172
+ });
167173
+ }
167174
+ }
167175
+ }
167176
+ return result;
167177
+ }
167178
+ async function loadClaimsList(claimRefList, claimsPath = getPath('claims')) {
167179
+ const data = {
167180
+ renderClaims: {},
167181
+ crs: {},
167182
+ fullCrs: {},
167183
+ };
167184
+ const defaults = loadClaimDefaults();
167185
+ for await (const claimRef of claimRefList) {
167186
+ const [renderedClaimData] = await loadClaim(claimRef, getOrg(), defaults, loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, claimsPath);
167187
+ data.renderClaims = lodash_default().merge(data.renderClaims, renderedClaimData);
167188
+ }
167189
+ const crClaimReferences = [];
167190
+ for (const ref of Object.keys(data.renderClaims)) {
167191
+ // Replaces only the first instance of '-'
167192
+ crClaimReferences.push(ref.replace('-', '/'));
167193
+ }
167194
+ const loadedCrs = await loadCRsWithFullSet(getPath('crs'), [getPath('globals'), getPath('initializers')], crClaimReferences);
167195
+ data['crs'] = loadedCrs.crs;
167196
+ data['fullCrs'] = loadedCrs.fullCrs;
167197
+ return data;
167198
+ }
167199
+ function getOrg() {
167200
+ const groupOrg = catalog_common/* default.environment.getFromEnvironmentWithDefault */.Z.environment.getFromEnvironmentWithDefault(catalog_common/* default.types.envVars.org */.Z.types.envVars.org, '');
167201
+ return groupOrg;
167202
+ }
167203
+
167204
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/references.ts
167205
+ function validateTfStateKeyUniqueness(crs) {
167206
+ const tfStateKeys = {};
167207
+ for (const crKey of Object.keys(crs)) {
167208
+ const cr = crs[crKey];
167209
+ if (!isTerraformWorkspace(cr))
167210
+ continue;
167211
+ const tfKey = cr.spec.firestartr.tfStateKey;
167212
+ if (tfStateKeys[tfKey]) {
167213
+ throw new Error(`❗❗ ❌ RENDER ERROR ❌ ❗❗
167214
+
167215
+ The tfStateKey ${tfKey} is not unique,
167216
+
167217
+ It is being used by the following CRs:
167218
+
167219
+ - ${tfStateKeys[tfKey].kind} ${tfStateKeys[tfKey].metadata.name}
167220
+
167221
+ - ${cr.kind} ${cr.metadata.name}
167222
+
167223
+ Check the following Claims to ensure that the tfStateKey is unique:
167224
+
167225
+ - ${tfStateKeys[tfKey].metadata.annotations['firestartr.dev/claim-ref']}
167226
+
167227
+ - ${cr.metadata.annotations['firestartr.dev/claim-ref']}
167228
+ `);
167229
+ }
167230
+ tfStateKeys[cr.spec.firestartr.tfStateKey] = cr;
167231
+ }
167232
+ }
167233
+ function references_isCatalogEntity(cr) {
167234
+ return [
167235
+ 'Component',
167236
+ 'Domain',
167237
+ 'System',
167238
+ 'User',
167239
+ 'Group',
167240
+ 'Resource',
167241
+ ].includes(cr.kind);
167242
+ }
167243
+ function isTerraformWorkspace(cr) {
167244
+ return cr.kind === 'FirestartrTerraformWorkspace';
167245
+ }
167246
+
167247
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/crSize.ts
167248
+
167249
+ const K8S_OBJECT_SIZE_LIMIT = 1572864; // 1.5 MiB in bytes, etcd recommended limit: https://etcd.io/docs/latest/dev-guide/limit/
167250
+ function validateCrSizes(crs) {
167251
+ for (const key of Object.keys(crs)) {
167252
+ const cr = crs[key];
167253
+ const serialized = catalog_common/* default.io.toYaml */.Z.io.toYaml(cr);
167254
+ const size = Buffer.byteLength(serialized, 'utf8');
167255
+ if (size > K8S_OBJECT_SIZE_LIMIT) {
167256
+ 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).`);
167257
+ }
167258
+ }
167259
+ }
167260
+
167261
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/permissions.ts
167262
+
167263
+ function validatePermissionsUniqueness(crs) {
167264
+ for (const crkey in crs) {
167265
+ const cr = crs[crkey];
167266
+ if (cr.kind === 'FirestartrGithubRepository') {
167267
+ const permissions = cr.spec.permissions;
167268
+ logger.debug(`Validating Permissions Uniqueness of ${crkey}`);
167269
+ if (permissions) {
167270
+ const rolesByIdentifier = new Map();
167271
+ for (const perm of permissions) {
167272
+ const identifier = perm.collaborator
167273
+ ? perm.collaborator
167274
+ : `ref:${perm.ref.kind}:${perm.ref.name}`;
167275
+ const role = perm.role;
167276
+ const prevRole = rolesByIdentifier.get(identifier);
167277
+ if (prevRole === undefined) {
167278
+ rolesByIdentifier.set(identifier, role);
167279
+ }
167280
+ else if (prevRole !== role) {
167281
+ throw new Error(`Conflicting permission role in FirestartrGithubRepository ${crkey}: ${identifier} has roles "${prevRole}" and "${role}".\nFull CR: ${JSON.stringify(cr, null, 2)}`);
167282
+ }
167283
+ }
167284
+ }
167285
+ }
167286
+ }
167287
+ }
167288
+
167289
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/backstageAnnotations.ts
167290
+ const backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX = 'firestartr.backstage.dev/';
167291
+ const CATALOG_KINDS = new Set([
167292
+ 'User',
167293
+ 'Group',
167294
+ 'Component',
167295
+ 'System',
167296
+ 'Domain',
167297
+ 'API',
167298
+ 'Resource',
167299
+ 'CatalogKubernetesResource',
167300
+ 'CatalogTerraformWorkspace',
167301
+ 'CatalogArgoDeploy',
167302
+ 'CatalogOrgWebhook',
167303
+ 'CatalogSecrets',
167304
+ ]);
167305
+ function validateNoBackstageAnnotationsInK8sCrs(crs) {
167306
+ for (const crKey in crs) {
167307
+ const cr = crs[crKey];
167308
+ if (CATALOG_KINDS.has(cr.kind))
167309
+ continue;
167310
+ if (cr.metadata?.annotations) {
167311
+ const backstageKeys = Object.keys(cr.metadata.annotations).filter((k) => k.startsWith(backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX));
167312
+ if (backstageKeys.length > 0) {
167313
+ throw new Error(`K8s CR ${crKey} contains Backstage-only annotations (${backstageKeys.join(', ')}). ` +
167314
+ `Annotations with prefix ${backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX} must only appear on Backstage catalog entities, not on Kubernetes CRs.`);
167315
+ }
167316
+ }
167317
+ }
167318
+ }
167319
+
167320
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/refsSorter/refsSorter.ts
167321
+
167322
+ /**
167323
+ * @param renderClaims renderClaims to sort
167324
+ * @param kinds kinds to get from renderClaims
167325
+ * @returns renderClaims with only the kinds specified
167326
+ */
167327
+ function sortRenderClaimsByKind(renderClaims, kinds) {
167328
+ let result = {};
167329
+ for (const kind of kinds) {
167330
+ for (const key in renderClaims) {
167331
+ if (renderClaims[key].claim.kind === kind) {
167332
+ result[key] = renderClaims[key];
167333
+ }
167334
+ }
167335
+ result = sortSelfKindRefs(result, kind);
167336
+ }
167337
+ return result;
167338
+ }
167339
+ function sortSelfKindRefs(renderClaims, kind) {
167340
+ if (!hasSelfRefs(kind)) {
167341
+ return renderClaims;
167342
+ }
167343
+ const newRenderClaims = {};
167344
+ const data = extractRefs(renderClaims, kind);
167345
+ const ordered = [];
167346
+ const visiting = [];
167347
+ const visited = [];
167348
+ for (const key of Object.keys(data)) {
167349
+ if (!visited.find((obj) => obj.name === key)) {
167350
+ sortRefs(data, data[key], ordered, visiting, visited);
167351
+ }
167352
+ }
167353
+ for (const cr of ordered) {
167354
+ newRenderClaims[cr.name] = renderClaims[cr.name];
167355
+ }
167356
+ return newRenderClaims;
167357
+ }
167358
+ function sortRefs(data, claim, ordered = [], visiting = [], visited = []) {
167359
+ if (visiting.find((obj) => obj.name === claim.name)) {
167360
+ throw new Error(`Circular dependency detected for '${claim.name}'`);
167361
+ }
167362
+ if (!visited.find((obj) => obj.name === claim.name)) {
167363
+ visiting.push(claim);
167364
+ if (claim.refs) {
167365
+ for (const ref of claim.refs) {
167366
+ const referencedObject = data[ref];
167367
+ if (!referencedObject) {
167368
+ throw new Error(`Reference '${ref}' does not exist for '${claim.name}'`);
167369
+ }
167370
+ sortRefs(data, referencedObject, ordered, visiting, visited);
167371
+ }
167372
+ }
167373
+ visited.push(visiting.pop());
167374
+ ordered.push(claim);
167375
+ }
167376
+ }
167377
+ function hasSelfRefs(kind) {
167378
+ return ['TFWorkspaceClaim', 'GroupClaim'].includes(kind);
167379
+ }
167380
+
167381
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/renderer/claims-sorter.ts
167382
+
167383
+ function sortKinds(orderedKinds, claims) {
167384
+ const result = [];
167385
+ for (const kind of orderedKinds) {
167386
+ const kindRenderClaims = sortRenderClaimsByKind(claims, [kind]);
167387
+ result.push(kindRenderClaims);
167388
+ }
167389
+ return result;
167390
+ }
167391
+
166917
167392
  ;// CONCATENATED MODULE: ../cdk8s_renderer/src/overriders/utils.ts
166918
167393
 
166919
167394
 
@@ -166955,14 +167430,12 @@ async function utils_renderFeature(featureName, featureVersion, featureOutputObj
166955
167430
 
166956
167431
 
166957
167432
 
166958
-
166959
-
166960
167433
  // this is the only way currently to make
166961
167434
  // work the system and inject our code
166962
167435
  // without having to download a feature
166963
- let MOCK_FEATURES_FN;
167436
+ let featureOverride_MOCK_FEATURES_FN;
166964
167437
  function MOCK_FEATURES(mock) {
166965
- MOCK_FEATURES_FN = mock;
167438
+ featureOverride_MOCK_FEATURES_FN = mock;
166966
167439
  if (mock) {
166967
167440
  log.warn('⚠️ Warning features system downloader has been mocked, it should only happen in unit testing');
166968
167441
  }
@@ -166993,8 +167466,8 @@ class FeaturesOverrider extends OverriderPatches {
166993
167466
  let owner = 'prefapp';
166994
167467
  let versionOrRef = this.featureVersion;
166995
167468
  let renderer = 'getFeatureConfig';
166996
- if (MOCK_FEATURES_FN) {
166997
- return MOCK_FEATURES_FN();
167469
+ if (featureOverride_MOCK_FEATURES_FN) {
167470
+ return featureOverride_MOCK_FEATURES_FN();
166998
167471
  }
166999
167472
  if (this.featureRepo) {
167000
167473
  [owner, repo] = this.featureRepo.split(/\//);
@@ -167012,8 +167485,8 @@ class FeaturesOverrider extends OverriderPatches {
167012
167485
  const featureName = this.featureName;
167013
167486
  const featureVersion = this.featureVersion || this.featureRef;
167014
167487
  const featureArgs = this.featureArgs;
167015
- const fSetUpAndRunRenderer = function (cr) {
167016
- return this.setUpAndRunRenderer(cr);
167488
+ const fSetUpAndRunRenderer = function (target) {
167489
+ return this.setUpAndRunRenderer(target);
167017
167490
  }.bind(this);
167018
167491
  let renderedFeatureConfig = null;
167019
167492
  return [
@@ -167022,7 +167495,7 @@ class FeaturesOverrider extends OverriderPatches {
167022
167495
  return true;
167023
167496
  },
167024
167497
  async apply(cr) {
167025
- renderedFeatureConfig = await fSetUpAndRunRenderer(cr);
167498
+ renderedFeatureConfig = await fSetUpAndRunRenderer(claim);
167026
167499
  return cr;
167027
167500
  },
167028
167501
  identify() {
@@ -167035,28 +167508,6 @@ class FeaturesOverrider extends OverriderPatches {
167035
167508
  return utils_renderFeature(featureName, featureVersion, renderedFeatureConfig, cr, claim.name);
167036
167509
  },
167037
167510
  },
167038
- {
167039
- isPostPatch: true,
167040
- validate() {
167041
- return true;
167042
- },
167043
- async apply(cr) {
167044
- if (!renderedFeatureConfig) {
167045
- logger.warn(`Feature ${featureName}: renderedFeatureConfig is null, skipping post-patch`);
167046
- return cr;
167047
- }
167048
- const provider = helperCTX(this).provider;
167049
- const jsonPatches = renderedFeatureConfig.patches?.[provider] || [];
167050
- fast_json_patch_default().applyPatch(cr, jsonPatches);
167051
- return cr;
167052
- },
167053
- identify() {
167054
- return `feature-json-patch/${featureName}`;
167055
- },
167056
- applicable() {
167057
- return { applicableProviders: ['catalog', 'github'] };
167058
- },
167059
- },
167060
167511
  ];
167061
167512
  }
167062
167513
  }
@@ -363508,7 +363959,7 @@ function helperCreateCheckRunName(cmd, item) {
363508
363959
 
363509
363960
  ;// CONCATENATED MODULE: ../operator/src/utils/index.ts
363510
363961
  const secretRegex = /\$\{\{ secrets\.(.*?) \}\}/g;
363511
- function isRecord(value) {
363962
+ function utils_isRecord(value) {
363512
363963
  return typeof value === 'object' && value !== null;
363513
363964
  }
363514
363965
  function getFirstNonEmptyString(...values) {
@@ -363546,7 +363997,7 @@ function replaceInlineSecrets(inline, secrets) {
363546
363997
  return result;
363547
363998
  }
363548
363999
  function extractErrorDetails(error) {
363549
- const exitCode = isRecord(error) && typeof error.exitCode === 'number'
364000
+ const exitCode = utils_isRecord(error) && typeof error.exitCode === 'number'
363550
364001
  ? error.exitCode
363551
364002
  : undefined;
363552
364003
  if (typeof error === 'string') {
@@ -363557,7 +364008,7 @@ function extractErrorDetails(error) {
363557
364008
  const output = getFirstNonEmptyString(errorWithOutput.output, error.message);
363558
364009
  return { output: output ?? String(error), exitCode };
363559
364010
  }
363560
- if (isRecord(error)) {
364011
+ if (utils_isRecord(error)) {
363561
364012
  const output = getFirstNonEmptyString(error.output, error.message, error.error);
363562
364013
  if (output !== undefined) {
363563
364014
  return { output, exitCode };
@@ -713893,7 +714344,7 @@ const crsStatusSubcommand = {
713893
714344
  };
713894
714345
 
713895
714346
  ;// CONCATENATED MODULE: ./package.json
713896
- const package_namespaceObject = JSON.parse('{"i8":"2.11.0-snapshot-main-1"}');
714347
+ const package_namespaceObject = JSON.parse('{"i8":"2.11.0-snapshot-patches-patch-claims-3"}');
713897
714348
  ;// CONCATENATED MODULE: ../../package.json
713898
714349
  const package_namespaceObject_1 = {"i8":"2.10.0"};
713899
714350
  // EXTERNAL MODULE: ../../node_modules/semver/index.js