@firestartr/cli 2.11.0-snapshot-mco-3 → 2.11.0-snapshot-patch-claims-4

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') {
@@ -164550,771 +164550,6 @@ const base_secrets_schema = 'firestartr.dev://common/SecretsClaim';
164550
164550
  SecretsClaimSchema: base_secrets_schema,
164551
164551
  });
164552
164552
 
164553
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/lazy_loader.ts
164554
-
164555
-
164556
-
164557
-
164558
-
164559
-
164560
-
164561
-
164562
-
164563
-
164564
-
164565
-
164566
-
164567
-
164568
-
164569
-
164570
- // We need to ensure the grep command is a gnu version
164571
- let IS_GNU_GREP = false;
164572
- let GREP_ON_CHECK = false;
164573
- // this loop is for avoid race conditions
164574
- // once a check is running no more checks
164575
- async function waitForCheck() {
164576
- const f_wait = () => new Promise((timeOut) => setTimeout(timeOut, 10));
164577
- do {
164578
- await f_wait();
164579
- } while (GREP_ON_CHECK);
164580
- }
164581
- function checkGrep() {
164582
- return new Promise((ok, ko) => {
164583
- // idempotency: already checked
164584
- if (IS_GNU_GREP)
164585
- return ok();
164586
- // a check is already running no new checks
164587
- if (GREP_ON_CHECK)
164588
- return waitForCheck();
164589
- logger.info('Checking the grep command');
164590
- GREP_ON_CHECK = true;
164591
- const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['--version']);
164592
- handler.on('close', (code) => {
164593
- GREP_ON_CHECK = false;
164594
- if (code === 0) {
164595
- logger.debug('Grep is a gnu grep');
164596
- IS_GNU_GREP = true;
164597
- ok();
164598
- }
164599
- else {
164600
- ko('Lazy evaluation needs a gnu-grep command');
164601
- }
164602
- });
164603
- });
164604
- }
164605
- async function loadClaim(claimRef, org, defaults = loadClaimDefaults(), patchClaim = loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, existingRefs = {}, postValidations = new Map()) {
164606
- await checkGrep();
164607
- let result = existingRefs;
164608
- logger.info(`Load reference ${claimRef}`);
164609
- initVirtualClaims(org);
164610
- logger.info(`Load reference (parts) ${claimRef.split(/-/)[0]} ${claimRef.replace(/^[^-]+-/, '')}`);
164611
- // cargas datos con grep
164612
- try {
164613
- const claimData = await lazyGetClaim(claimRef.split(/-/)[0], claimRef.replace(/^[^-]+-/, ''), org, cwd);
164614
- const claim = patchClaim(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(claimData), defaults);
164615
- let variants = [];
164616
- if (claim.kind === 'TFWorkspaceClaim' &&
164617
- claim.providers?.terraform?.variants) {
164618
- variants = claim.providers.terraform.variants;
164619
- delete claim.providers.terraform.variants;
164620
- }
164621
- logger.silly(`Patched claim is:
164622
- ---
164623
- ${catalog_common/* default.io.toYaml */.Z.io.toYaml(claim)}`);
164624
- try {
164625
- validateClaim(claim, base[`${claim.kind}Schema`]);
164626
- await optionalValidation(claim);
164627
- }
164628
- catch (error) {
164629
- let errorMsg = '';
164630
- if (Array.isArray(error)) {
164631
- for (const data of error) {
164632
- errorMsg = `${errorMsg}
164633
- - ${data.instancePath}: ${data.message}`;
164634
- }
164635
- }
164636
- else {
164637
- errorMsg = error instanceof Error ? error.message : String(error);
164638
- }
164639
- throw new Error(`Error when validating claim ${claimRef}: ${errorMsg}`);
164640
- }
164641
- result[claimRef] = {};
164642
- result[claimRef]['claim'] = claim;
164643
- result[claimRef]['claimPath'] = VisitedClaims[claimRef];
164644
- if (VisitedClaims[claimRef] === 'virtual') {
164645
- result = await setVirtualClaimAdditionalData(result, claim, claimRef);
164646
- }
164647
- else {
164648
- result = await setNonVirtualClaimAdditionalData(result, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
164649
- }
164650
- const claimKind = claim.kind;
164651
- const references = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(claim));
164652
- for (const ref of references) {
164653
- if (!result[ref]) {
164654
- const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
164655
- result = lodash_default().merge(result, resolvedReferences);
164656
- }
164657
- }
164658
- if (variants.length > 0) {
164659
- const parentClaimPath = VisitedClaims[claimRef];
164660
- for (const variant of variants) {
164661
- if (!variant.name || !variant.overrides) {
164662
- throw new Error(`Variant in claim ${claimRef} is missing required field 'name' or 'overrides'`);
164663
- }
164664
- const prohibitedOverrideFields = ['source', 'module', 'name'];
164665
- for (const field of prohibitedOverrideFields) {
164666
- if (field in variant.overrides) {
164667
- throw new Error(`Variant '${variant.name}' in claim ${claimRef} cannot override '${field}'`);
164668
- }
164669
- }
164670
- const composedName = claim.providers.terraform.name + '-' + variant.name;
164671
- const variantClaim = lodash_default().cloneDeep(claim);
164672
- variantClaim._parentClaimName = claim.name;
164673
- variantClaim.name = composedName;
164674
- variantClaim.providers.terraform = lodash_default().merge({}, claim.providers.terraform, variant.overrides);
164675
- variantClaim.providers.terraform.name = composedName;
164676
- if (!variantClaim.annotations) {
164677
- variantClaim.annotations = {};
164678
- }
164679
- variantClaim.annotations['firestartr.dev/variant-of'] =
164680
- claim.providers.terraform.name;
164681
- const variantRef = `TFWorkspaceClaim-${composedName}`;
164682
- if (result[variantRef]) {
164683
- throw new Error(`Variant name '${variant.name}' (composed: '${composedName}') from claim '${claimRef}' conflicts with existing claim '${variantRef}'`);
164684
- }
164685
- logger.info(`Creating synthetic variant claim ${variantRef}`);
164686
- result[variantRef] = {};
164687
- result[variantRef]['claim'] = variantClaim;
164688
- result[variantRef]['claimPath'] = parentClaimPath;
164689
- result = await setNonVirtualClaimAdditionalData(result, variantClaim, variantRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
164690
- const variantReferences = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(variantClaim));
164691
- for (const ref of variantReferences) {
164692
- if (!result[ref]) {
164693
- const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
164694
- result = lodash_default().merge(result, resolvedReferences);
164695
- }
164696
- }
164697
- }
164698
- }
164699
- }
164700
- catch (err) {
164701
- throw `Lazy Loading: ${err}`;
164702
- }
164703
- return [result, postValidations];
164704
- }
164705
- let LoadedClaims = {};
164706
- let VisitedClaims = {};
164707
- let DuplicatedClaims = {};
164708
- function resetLazyLoader() {
164709
- LoadedClaims = {};
164710
- VisitedClaims = {};
164711
- DuplicatedClaims = {};
164712
- }
164713
- async function lazyGetClaim(kind, name, org, cwd) {
164714
- const indice = `${kind}-${name}`;
164715
- logger.info(`Lazy loading ${kind}-${name} with index ${indice}`);
164716
- if (indice in LoadedClaims)
164717
- return LoadedClaims[indice];
164718
- if (isVirtualClaim(kind, name)) {
164719
- await loadVirtualClaim(kind, name, org);
164720
- }
164721
- else {
164722
- await getClaimsByName(name, cwd);
164723
- }
164724
- if (indice in LoadedClaims) {
164725
- return LoadedClaims[indice];
164726
- }
164727
- else {
164728
- throw new Error(`Error: ${kind}-${name} not found`);
164729
- }
164730
- }
164731
- async function getClaimsByName(name, cwd = '.') {
164732
- return new Promise((ok, ko) => {
164733
- const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['-r', '-l', '--include=*', '-E', `name: "?${name}"?`, '.'], {
164734
- cwd: cwd,
164735
- });
164736
- logger.info(`Running ${['grep', '-r', '-l', '--include', '-E', 'name: "' + name + '"?', '.'].join(' ')}`);
164737
- const entradas = [];
164738
- const chunks = [];
164739
- handler.stdout.on('data', (data) => {
164740
- chunks.push(data.toString('utf-8'));
164741
- });
164742
- handler.on('close', () => {
164743
- const dataFinal = chunks.join('');
164744
- const fileNameList = dataFinal.split(/\n/).filter((line) => line !== '');
164745
- for (const fileName of fileNameList) {
164746
- // only yaml files
164747
- if (!fileName.match(/\.yml$|\.yaml$/)) {
164748
- continue;
164749
- }
164750
- // only entries not already visited
164751
- if (Object.values(VisitedClaims).includes(fileName)) {
164752
- continue;
164753
- }
164754
- entradas.push(external_path_.join(cwd, fileName));
164755
- }
164756
- return Promise.all(entradas.map((entrada) => {
164757
- return loadRawClaim(entrada);
164758
- }))
164759
- .then(() => {
164760
- ok();
164761
- })
164762
- .catch((err) => {
164763
- ko(err);
164764
- });
164765
- });
164766
- });
164767
- }
164768
- async function loadRawClaim(entry) {
164769
- return new Promise((ok, ko) => {
164770
- external_fs_.readFile(entry, 'utf-8', (error, data) => {
164771
- if (error)
164772
- return ko(`Reading ${entry}: ${error}`);
164773
- const claim = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
164774
- if (!('kind' in claim && 'name' in claim)) {
164775
- logger.warn(`Invalid claim file ${entry}`);
164776
- }
164777
- else {
164778
- const claimKey = `${claim.kind}-${claim.name}`;
164779
- if (Object.keys(DuplicatedClaims).includes(claimKey) &&
164780
- DuplicatedClaims[claimKey] !== entry) {
164781
- return ko(`Duplicated claim ${claimKey} found files: ${DuplicatedClaims[claimKey]} and ${entry}`);
164782
- }
164783
- LoadedClaims[claimKey] = data;
164784
- VisitedClaims[claimKey] = entry;
164785
- DuplicatedClaims[claimKey] = entry;
164786
- ok();
164787
- }
164788
- });
164789
- });
164790
- }
164791
- async function setVirtualClaimAdditionalData(renderedData, claim, claimRef) {
164792
- const virtualClaim = getVirtualClaim(claim.kind, claim.name);
164793
- renderedData[claimRef]['initializers'] = [
164794
- new UUIDInitializer(claim),
164795
- new InitializerClaimRef(),
164796
- new InitializerDefault(virtualClaim.getDefaultConfig()),
164797
- ];
164798
- renderedData[claimRef]['globals'] = [];
164799
- renderedData[claimRef]['overrides'] = [];
164800
- renderedData[claimRef]['normalizers'] = [new NameNormalizer()];
164801
- return renderedData;
164802
- }
164803
- async function setNonVirtualClaimAdditionalData(renderedData, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers) {
164804
- renderedData[claimRef]['initializers'] = await loadInitializers(claim, renderedData[claimRef]['claimPath']);
164805
- renderedData[claimRef]['globals'] = await loadGlobals(claim);
164806
- renderedData[claimRef]['overrides'] = loadOverrides(claim);
164807
- renderedData[claimRef]['normalizers'] = await loadNormalizers(claim, renderedData[claimRef]['claimPath']);
164808
- return renderedData;
164809
- }
164810
- async function loadVirtualClaim(kind, name, org) {
164811
- const virtualClaim = getVirtualClaim(kind, name);
164812
- const expandedClaim = await virtualClaim.expand({ org });
164813
- logger.info(`Loading virtual claim ${kind} ${name} ${org}`);
164814
- LoadedClaims[`${kind}-${name}`] = catalog_common/* default.io.toYaml */.Z.io.toYaml(expandedClaim);
164815
- VisitedClaims[`${kind}-${name}`] = 'virtual';
164816
- }
164817
-
164818
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/claimsDefaulter.ts
164819
-
164820
-
164821
-
164822
- /*
164823
- * Default blocks are objects that cannot be merged but applied as a whole. Meaning:
164824
- * - If the object is defined at the claim-level it is maintained *AS IT IS* (no merge)
164825
- * - If the block is missing at the claim-level, the default block is applied
164826
- */
164827
- const defaultBlocksPaths = ['/providers/terraform/sync'];
164828
- function applyBlockAwareDefaults(claim, defaultClaim) {
164829
- // we always work with a clone of the original
164830
- const claimClone = JSON.parse(JSON.stringify(claim));
164831
- // if the block is claim-level defined we store it here
164832
- const defaultBlocks = new Map();
164833
- // we remove the blocks entirely of the claim
164834
- // to achieve an add copy
164835
- for (const defaultBlockPath of defaultBlocksPaths) {
164836
- if (claimsDefaulter_hasDeepPath(claimClone, defaultBlockPath) !== true)
164837
- continue;
164838
- const originalValue = fast_json_patch_default().getValueByPointer(claimClone, defaultBlockPath);
164839
- if (originalValue) {
164840
- logger.silly(`${claim.kind}/${claim.name}: has an original ${defaultBlockPath}: preserving`);
164841
- defaultBlocks.set(defaultBlockPath, originalValue);
164842
- fast_json_patch_default().applyPatch(claimClone, [{ op: 'remove', path: defaultBlockPath }]);
164843
- }
164844
- }
164845
- // if the patch has the same path of a block
164846
- // and the block was defined at claim-level
164847
- // we interchange the value with the original value
164848
- // otherwise we use the default
164849
- const jsonPatchOps = fast_json_patch_default().compare(claimClone, defaultClaim)
164850
- .filter((jp) => jp.op === 'add')
164851
- .map((jp) => {
164852
- if (defaultBlocks.has(jp.path)) {
164853
- return {
164854
- ...jp,
164855
- value: defaultBlocks.get(jp.path),
164856
- };
164857
- }
164858
- else {
164859
- return jp;
164860
- }
164861
- });
164862
- return fast_json_patch_default().applyPatch(claimClone, jsonPatchOps).newDocument;
164863
- }
164864
- function claimsDefaulter_hasDeepPath(data, deepPath) {
164865
- return lodash_default().has(data, deepPath.replace(/\//g, '.').replace(/^\./, ''));
164866
- }
164867
-
164868
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/loader.ts
164869
-
164870
-
164871
-
164872
-
164873
-
164874
-
164875
-
164876
-
164877
-
164878
-
164879
-
164880
-
164881
-
164882
-
164883
-
164884
- const isYamlFile = new RegExp(/\.(yaml|yml)$/);
164885
- /**
164886
- *
164887
- * @returns Virtual Claims
164888
- */
164889
- const virtualClaims = [new FirestartrAllClaim()];
164890
- /*
164891
- * Loads all applicable globals for a given claim and stores them into a list.
164892
- *
164893
- * Input:
164894
- * - claim: our custom claim object, with which we check if the global is applicable
164895
- *
164896
- * Returns:
164897
- * - A GlobalSection array promise, containing all the globals loaded for this claim
164898
- *
164899
- */
164900
- async function loadGlobals(claim) {
164901
- const result = [];
164902
- await crawl(getPath('globals'), (entry) => {
164903
- return isYamlFile.test(entry);
164904
- }, async (entry, data) => {
164905
- const globalData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
164906
- const ext = external_path_.extname(entry);
164907
- const name = external_path_.basename(entry, ext);
164908
- if (name in SECTIONS_BY_FILE_NAME) {
164909
- const section = new SECTIONS_BY_FILE_NAME[name](globalData);
164910
- if (!(await section.validate(SCHEMAS_BY_SECTION_NAME[name] || {}))) {
164911
- throw new Error(`Invalid ${name} global file`);
164912
- }
164913
- if (globalData.kind === claim.kind) {
164914
- result.push(section);
164915
- }
164916
- else {
164917
- logger.debug(`Skipping global ${name} because it is not applicable to ${claim.kind}`);
164918
- }
164919
- }
164920
- });
164921
- logger.info(`Loaded globals ${result}`);
164922
- return result;
164923
- }
164924
- /*
164925
- * If the input claim is a GithubRepositoryClaim, it loads all it's applicable
164926
- * overrides and stores them into a list. Otherwise, it returns an empty list.
164927
- *
164928
- * Input:
164929
- * - claim: our custom claim object, which should be a GithubRepositoryClaim
164930
- *
164931
- * Returns:
164932
- * - An Overrider array, with a GithubRepositoryOverrider if the claim
164933
- * was a GithubRepositoryClaim, or empty if it was not.
164934
- *
164935
- */
164936
- function loadOverrides(claim) {
164937
- const overrides = [];
164938
- if (claim.kind === 'ComponentClaim' && claim.providers.github.overrides) {
164939
- overrides.push(new GithubRepositoryOverrider());
164940
- }
164941
- return overrides;
164942
- }
164943
- /**
164944
- * Load all normalizers and stores them into a list.
164945
- * @param claim
164946
- * @returns
164947
- */
164948
- async function loadNormalizers(_claim, path) {
164949
- const result = [];
164950
- for (const normalizer of NORMALIZERS) {
164951
- result.push(new normalizer({ path: path }));
164952
- }
164953
- return result;
164954
- }
164955
- /*
164956
- * Loads all applicable initializers for a given claim and stores them into a list.
164957
- *
164958
- * Input:
164959
- * - claim: our custom claim object, with which we check if the initializer is applicable
164960
- *
164961
- * Returns:
164962
- * - An Initializer array promise, containing all the initializers loaded for this claim
164963
- *
164964
- */
164965
- let loadedInitializers = false;
164966
- async function loadInitializers(claim, claimPath, initializersPath = getPath('initializers')) {
164967
- const result = [];
164968
- await crawl(initializersPath, (entry) => {
164969
- return isYamlFile.test(entry);
164970
- }, async (entry, data) => {
164971
- const initializerData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
164972
- const ext = external_path_.extname(entry);
164973
- const name = external_path_.basename(entry, ext);
164974
- if (name in INITIALIZERS_BY_FILE_NAME) {
164975
- const initializerBfN = new INITIALIZERS_BY_FILE_NAME[name](initializerData);
164976
- if (!(await initializerBfN.validate(SCHEMAS_BY_INITIALIZER_NAME[name] || {}))) {
164977
- throw new Error(`Invalid ${name} initializer file`);
164978
- }
164979
- if (initializerData.kind === claim.kind) {
164980
- result.push(initializerBfN);
164981
- }
164982
- else {
164983
- logger.debug(`Skipping initializer ${name} because it is not applicable to ${claim.kind}`);
164984
- }
164985
- }
164986
- });
164987
- for (const initializer of INITIALIZERS) {
164988
- if (initializer.applicableKinds.includes(claim.kind)) {
164989
- result.push(new initializer({ path: claimPath }));
164990
- }
164991
- }
164992
- logger.info(`Loaded initializers ${JSON.stringify(result)}`);
164993
- loadedInitializers = result;
164994
- return loadedInitializers;
164995
- }
164996
- function loadClaimDefaults() {
164997
- try {
164998
- return catalog_common/* default.io.fromYaml */.Z.io.fromYaml(external_fs_.readFileSync(`${getPath('claimsDefaults')}/claims_defaults.yaml`, 'utf-8'));
164999
- }
165000
- catch (error) {
165001
- const errMsg = `Could not read claims defaults file in path ${getPath('claimsDefaults')}/claims_defaults.yaml: ${error}`;
165002
- logger.error(errMsg);
165003
- throw new Error(errMsg);
165004
- }
165005
- }
165006
- /*
165007
- * Using fast-json-patch, compares a claim to its kind's defaults, then patches it.
165008
- *
165009
- * Input:
165010
- * - claim: our custom claim object, which we want to patch
165011
- * - defaultsClaims: an object, containing the defaults for each claim kind,
165012
- * with the same structure that we use for the actual claims
165013
- *
165014
- * Returns:
165015
- * - The patched claim
165016
- *
165017
- */
165018
- function loader_patchClaim(claim, defaultsClaims) {
165019
- if (defaultsClaims[claim.kind]) {
165020
- claim = applyBlockAwareDefaults(claim, defaultsClaims[claim.kind]);
165021
- }
165022
- return claim;
165023
- }
165024
- async function loadCRsWithFullSet(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
165025
- const result = {};
165026
- const fullResult = {};
165027
- await crawlWithExclusions(crsPath, (entry) => {
165028
- return isYamlFile.test(entry);
165029
- }, async (entry, data) => {
165030
- const yamlData = stripKnownRelations(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data));
165031
- const metadata = yamlData?.metadata;
165032
- if (!(yamlData &&
165033
- typeof yamlData === 'object' &&
165034
- 'kind' in yamlData &&
165035
- metadata &&
165036
- typeof metadata === 'object' &&
165037
- 'name' in metadata)) {
165038
- logger.warn(`Invalid CR file ${entry}`);
165039
- }
165040
- else {
165041
- const crKey = `${yamlData.kind}-${metadata.name}`;
165042
- if (fullResult[crKey]) {
165043
- logger.error(`Duplicate CR ${crKey}`);
165044
- }
165045
- // Keep the complete CR set for validations that need repository-wide context.
165046
- fullResult[crKey] = yamlData;
165047
- // Keep the filtered CR set for previous-CR lookup during claim rendering.
165048
- if (allowedClaimReferences.length === 0 ||
165049
- allowedClaimReferences.includes(yamlData.metadata?.annotations?.[catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('claim-ref')])) {
165050
- result[crKey] = yamlData;
165051
- }
165052
- }
165053
- }, excludedPaths.concat(getAdditionalPaths()));
165054
- return { crs: result, fullCrs: fullResult };
165055
- }
165056
- async function loadCRs(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
165057
- const { crs } = await loadCRsWithFullSet(crsPath, excludedPaths, allowedClaimReferences);
165058
- return crs;
165059
- }
165060
- /*
165061
- * Description: Get the renamed using claimRef annotation
165062
- * Input: claims: any, crs: any
165063
- * Output: renames: IRenameResult[]
165064
- */
165065
- async function loadRenames(claims, crs) {
165066
- /*
165067
- * If checkRenames is false, we don't need to check for renames
165068
- */
165069
- const renamesEnabled = getRenamesEnabled();
165070
- if (!renamesEnabled)
165071
- return [];
165072
- const result = [];
165073
- /**
165074
- * For each CR, look for a claim that does not match the name with CR's firestartr.dev/claim-ref annotation
165075
- */
165076
- for (const cr of Object.values(crs)) {
165077
- const anyCr = cr;
165078
- if (!anyCr?.metadata?.annotations)
165079
- continue;
165080
- // if the annotation is a claimRef
165081
- const annotationName = common.generic.getFirestartrAnnotation('claim-ref');
165082
- const annotations = anyCr?.metadata?.annotations || {};
165083
- if (annotationName in annotations) {
165084
- const claimRef = anyCr.metadata.annotations[annotationName];
165085
- // split the annotation into kind and name
165086
- const [kind, name] = claimRef.split('/');
165087
- // if the claim exists, check if the name is different for the given provider
165088
- const referencedClaim = claims[`${kind}-${name}`].claim;
165089
- const oldName = anyCr.metadata.name;
165090
- const newName = referencedClaim.providers[getConfiguredProvider()].name;
165091
- if (oldName !== newName) {
165092
- result.push({
165093
- kind: referencedClaim.kind,
165094
- claimPath: claims[`${kind}-${name}`].claimPath,
165095
- claimName: referencedClaim.name,
165096
- oldName,
165097
- newName,
165098
- });
165099
- }
165100
- }
165101
- }
165102
- return result;
165103
- }
165104
- async function loadClaimsList(claimRefList, claimsPath = getPath('claims')) {
165105
- const data = {
165106
- renderClaims: {},
165107
- crs: {},
165108
- fullCrs: {},
165109
- };
165110
- const defaults = loadClaimDefaults();
165111
- for await (const claimRef of claimRefList) {
165112
- const [renderedClaimData] = await loadClaim(claimRef, getOrg(), defaults, loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, claimsPath);
165113
- data.renderClaims = lodash_default().merge(data.renderClaims, renderedClaimData);
165114
- }
165115
- const crClaimReferences = [];
165116
- for (const ref of Object.keys(data.renderClaims)) {
165117
- // Replaces only the first instance of '-'
165118
- crClaimReferences.push(ref.replace('-', '/'));
165119
- }
165120
- const loadedCrs = await loadCRsWithFullSet(getPath('crs'), [getPath('globals'), getPath('initializers')], crClaimReferences);
165121
- data['crs'] = loadedCrs.crs;
165122
- data['fullCrs'] = loadedCrs.fullCrs;
165123
- return data;
165124
- }
165125
- function getOrg() {
165126
- const groupOrg = catalog_common/* default.environment.getFromEnvironmentWithDefault */.Z.environment.getFromEnvironmentWithDefault(catalog_common/* default.types.envVars.org */.Z.types.envVars.org, '');
165127
- return groupOrg;
165128
- }
165129
-
165130
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/references.ts
165131
- function validateTfStateKeyUniqueness(crs) {
165132
- const tfStateKeys = {};
165133
- for (const crKey of Object.keys(crs)) {
165134
- const cr = crs[crKey];
165135
- if (!isTerraformWorkspace(cr))
165136
- continue;
165137
- const tfKey = cr.spec.firestartr.tfStateKey;
165138
- if (tfStateKeys[tfKey]) {
165139
- throw new Error(`❗❗ ❌ RENDER ERROR ❌ ❗❗
165140
-
165141
- The tfStateKey ${tfKey} is not unique,
165142
-
165143
- It is being used by the following CRs:
165144
-
165145
- - ${tfStateKeys[tfKey].kind} ${tfStateKeys[tfKey].metadata.name}
165146
-
165147
- - ${cr.kind} ${cr.metadata.name}
165148
-
165149
- Check the following Claims to ensure that the tfStateKey is unique:
165150
-
165151
- - ${tfStateKeys[tfKey].metadata.annotations['firestartr.dev/claim-ref']}
165152
-
165153
- - ${cr.metadata.annotations['firestartr.dev/claim-ref']}
165154
- `);
165155
- }
165156
- tfStateKeys[cr.spec.firestartr.tfStateKey] = cr;
165157
- }
165158
- }
165159
- function references_isCatalogEntity(cr) {
165160
- return [
165161
- 'Component',
165162
- 'Domain',
165163
- 'System',
165164
- 'User',
165165
- 'Group',
165166
- 'Resource',
165167
- ].includes(cr.kind);
165168
- }
165169
- function isTerraformWorkspace(cr) {
165170
- return cr.kind === 'FirestartrTerraformWorkspace';
165171
- }
165172
-
165173
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/crSize.ts
165174
-
165175
- const K8S_OBJECT_SIZE_LIMIT = 1572864; // 1.5 MiB in bytes, etcd recommended limit: https://etcd.io/docs/latest/dev-guide/limit/
165176
- function validateCrSizes(crs) {
165177
- for (const key of Object.keys(crs)) {
165178
- const cr = crs[key];
165179
- const serialized = catalog_common/* default.io.toYaml */.Z.io.toYaml(cr);
165180
- const size = Buffer.byteLength(serialized, 'utf8');
165181
- if (size > K8S_OBJECT_SIZE_LIMIT) {
165182
- 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).`);
165183
- }
165184
- }
165185
- }
165186
-
165187
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/permissions.ts
165188
-
165189
- function validatePermissionsUniqueness(crs) {
165190
- for (const crkey in crs) {
165191
- const cr = crs[crkey];
165192
- if (cr.kind === 'FirestartrGithubRepository') {
165193
- const permissions = cr.spec.permissions;
165194
- logger.debug(`Validating Permissions Uniqueness of ${crkey}`);
165195
- if (permissions) {
165196
- const rolesByIdentifier = new Map();
165197
- for (const perm of permissions) {
165198
- const identifier = perm.collaborator
165199
- ? perm.collaborator
165200
- : `ref:${perm.ref.kind}:${perm.ref.name}`;
165201
- const role = perm.role;
165202
- const prevRole = rolesByIdentifier.get(identifier);
165203
- if (prevRole === undefined) {
165204
- rolesByIdentifier.set(identifier, role);
165205
- }
165206
- else if (prevRole !== role) {
165207
- throw new Error(`Conflicting permission role in FirestartrGithubRepository ${crkey}: ${identifier} has roles "${prevRole}" and "${role}".\nFull CR: ${JSON.stringify(cr, null, 2)}`);
165208
- }
165209
- }
165210
- }
165211
- }
165212
- }
165213
- }
165214
-
165215
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/backstageAnnotations.ts
165216
- const backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX = 'firestartr.backstage.dev/';
165217
- const CATALOG_KINDS = new Set([
165218
- 'User',
165219
- 'Group',
165220
- 'Component',
165221
- 'System',
165222
- 'Domain',
165223
- 'API',
165224
- 'Resource',
165225
- 'CatalogKubernetesResource',
165226
- 'CatalogTerraformWorkspace',
165227
- 'CatalogArgoDeploy',
165228
- 'CatalogOrgWebhook',
165229
- 'CatalogSecrets',
165230
- ]);
165231
- function validateNoBackstageAnnotationsInK8sCrs(crs) {
165232
- for (const crKey in crs) {
165233
- const cr = crs[crKey];
165234
- if (CATALOG_KINDS.has(cr.kind))
165235
- continue;
165236
- if (cr.metadata?.annotations) {
165237
- const backstageKeys = Object.keys(cr.metadata.annotations).filter((k) => k.startsWith(backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX));
165238
- if (backstageKeys.length > 0) {
165239
- throw new Error(`K8s CR ${crKey} contains Backstage-only annotations (${backstageKeys.join(', ')}). ` +
165240
- `Annotations with prefix ${backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX} must only appear on Backstage catalog entities, not on Kubernetes CRs.`);
165241
- }
165242
- }
165243
- }
165244
- }
165245
-
165246
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/refsSorter/refsSorter.ts
165247
-
165248
- /**
165249
- * @param renderClaims renderClaims to sort
165250
- * @param kinds kinds to get from renderClaims
165251
- * @returns renderClaims with only the kinds specified
165252
- */
165253
- function sortRenderClaimsByKind(renderClaims, kinds) {
165254
- let result = {};
165255
- for (const kind of kinds) {
165256
- for (const key in renderClaims) {
165257
- if (renderClaims[key].claim.kind === kind) {
165258
- result[key] = renderClaims[key];
165259
- }
165260
- }
165261
- result = sortSelfKindRefs(result, kind);
165262
- }
165263
- return result;
165264
- }
165265
- function sortSelfKindRefs(renderClaims, kind) {
165266
- if (!hasSelfRefs(kind)) {
165267
- return renderClaims;
165268
- }
165269
- const newRenderClaims = {};
165270
- const data = extractRefs(renderClaims, kind);
165271
- const ordered = [];
165272
- const visiting = [];
165273
- const visited = [];
165274
- for (const key of Object.keys(data)) {
165275
- if (!visited.find((obj) => obj.name === key)) {
165276
- sortRefs(data, data[key], ordered, visiting, visited);
165277
- }
165278
- }
165279
- for (const cr of ordered) {
165280
- newRenderClaims[cr.name] = renderClaims[cr.name];
165281
- }
165282
- return newRenderClaims;
165283
- }
165284
- function sortRefs(data, claim, ordered = [], visiting = [], visited = []) {
165285
- if (visiting.find((obj) => obj.name === claim.name)) {
165286
- throw new Error(`Circular dependency detected for '${claim.name}'`);
165287
- }
165288
- if (!visited.find((obj) => obj.name === claim.name)) {
165289
- visiting.push(claim);
165290
- if (claim.refs) {
165291
- for (const ref of claim.refs) {
165292
- const referencedObject = data[ref];
165293
- if (!referencedObject) {
165294
- throw new Error(`Reference '${ref}' does not exist for '${claim.name}'`);
165295
- }
165296
- sortRefs(data, referencedObject, ordered, visiting, visited);
165297
- }
165298
- }
165299
- visited.push(visiting.pop());
165300
- ordered.push(claim);
165301
- }
165302
- }
165303
- function hasSelfRefs(kind) {
165304
- return ['TFWorkspaceClaim', 'GroupClaim'].includes(kind);
165305
- }
165306
-
165307
- ;// CONCATENATED MODULE: ../cdk8s_renderer/src/renderer/claims-sorter.ts
165308
-
165309
- function sortKinds(orderedKinds, claims) {
165310
- const result = [];
165311
- for (const kind of orderedKinds) {
165312
- const kindRenderClaims = sortRenderClaimsByKind(claims, [kind]);
165313
- result.push(kindRenderClaims);
165314
- }
165315
- return result;
165316
- }
165317
-
165318
164553
  ;// CONCATENATED MODULE: ../features_renderer/src/common.ts
165319
164554
 
165320
164555
  function isDirectory(path) {
@@ -165354,6 +164589,16 @@ var ajv_default = /*#__PURE__*/__nccwpck_require__.n(dist_ajv);
165354
164589
  $ref: '#/definitions/File',
165355
164590
  },
165356
164591
  },
164592
+ claimPatches: {
164593
+ type: 'array',
164594
+ items: {
164595
+ $ref: '#/definitions/Patch',
164596
+ },
164597
+ },
164598
+ // Legacy field kept for backward compatibility. Real feature packages
164599
+ // (prefapp/features) ship `patches` in the provider-keyed object
164600
+ // shape. The renderer ignores it for claim-level behaviour; claim-level
164601
+ // patches must come from `claimPatches`.
165357
164602
  patches: {
165358
164603
  type: 'object',
165359
164604
  patternProperties: {
@@ -165385,7 +164630,7 @@ var ajv_default = /*#__PURE__*/__nccwpck_require__.n(dist_ajv);
165385
164630
  },
165386
164631
  },
165387
164632
  },
165388
- required: ['args', 'feature_name', 'files', 'patches'],
164633
+ required: ['args', 'feature_name', 'files'],
165389
164634
  title: 'root',
165390
164635
  },
165391
164636
  Args: {
@@ -165465,10 +164710,10 @@ var ajv_default = /*#__PURE__*/__nccwpck_require__.n(dist_ajv);
165465
164710
  type: 'string',
165466
164711
  },
165467
164712
  value: {
165468
- type: 'string',
164713
+ type: ['string', 'object', 'array', 'number', 'boolean', 'null'],
165469
164714
  },
165470
164715
  },
165471
- required: ['name', 'op', 'path'],
164716
+ required: ['op', 'path'],
165472
164717
  title: 'Patch',
165473
164718
  },
165474
164719
  },
@@ -165490,10 +164735,10 @@ function validate(featurePath) {
165490
164735
  }
165491
164736
  function __validateDirStructure(featurePath) {
165492
164737
  if (!isDirectory(featurePath)) {
165493
- throw `Feature: ${featurePath} not a directory`;
164738
+ throw new Error(`Feature: ${featurePath} not a directory`);
165494
164739
  }
165495
164740
  if (!isFile(external_path_.join(featurePath, 'config.yaml'))) {
165496
- throw `Feature: ${featurePath}/config.yaml not found or not a file`;
164741
+ throw new Error(`Feature: ${featurePath}/config.yaml not found or not a file`);
165497
164742
  }
165498
164743
  }
165499
164744
  function __validateFeatureConfig(featurePath) {
@@ -165503,10 +164748,16 @@ function __validateFeatureConfig(featurePath) {
165503
164748
  return configData;
165504
164749
  }
165505
164750
  catch (error) {
165506
- throw `Feature: loading config.yaml: ${error}`;
164751
+ throw new Error(`Feature: loading config.yaml: ${error}`);
165507
164752
  }
165508
164753
  }
165509
164754
  function __validateFeatureConfigData(configData) {
164755
+ // Detect old provider-keyed claimPatches shape for migration hint.
164756
+ if (configData.claimPatches &&
164757
+ !Array.isArray(configData.claimPatches) &&
164758
+ typeof configData.claimPatches === 'object') {
164759
+ throw new Error(`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]`);
164760
+ }
165510
164761
  const ajv = new (ajv_default())({
165511
164762
  allowUnionTypes: true,
165512
164763
  });
@@ -165517,7 +164768,7 @@ function __validateFeatureConfigData(configData) {
165517
164768
  const validate = ajv.compile(activeSchema);
165518
164769
  const valid = validate(configData);
165519
164770
  if (!valid) {
165520
- throw `Feature: config.yaml invalid ${JSON.stringify(validate.errors)}`;
164771
+ throw new Error(`Feature: config.yaml invalid ${JSON.stringify(validate.errors)}`);
165521
164772
  }
165522
164773
  }
165523
164774
  function stripAnchoringConstraints(schemaDef) {
@@ -165528,12 +164779,26 @@ function stripAnchoringConstraints(schemaDef) {
165528
164779
  return clone;
165529
164780
  }
165530
164781
  function __validateJsonPatches(configData) {
165531
- const keys = Object.keys(configData.patches);
165532
- for (const key of keys) {
165533
- if (configData.patches[key]) {
165534
- if (fast_json_patch_default().validate(configData.patches[key])) {
165535
- const errors = JSON.stringify(fast_json_patch_default().validate(configData.patches[key]).message);
165536
- throw `Feature: config.yaml -> patches: invalid patches ${errors}`;
164782
+ const patches = configData.claimPatches;
164783
+ if (!Array.isArray(patches))
164784
+ return;
164785
+ const err = fast_json_patch_default().validate(patches);
164786
+ if (err) {
164787
+ throw new Error(`Feature: config.yaml -> claimPatches: invalid claimPatches ${JSON.stringify(err.message ?? err)}`);
164788
+ }
164789
+ // Legacy provider-keyed `patches` field is accepted for backward
164790
+ // compatibility. Its values are per-provider arrays of the same Patch
164791
+ // shape, so validate each of them too.
164792
+ const legacyPatches = configData.patches;
164793
+ if (legacyPatches && typeof legacyPatches === 'object') {
164794
+ for (const key of Object.keys(legacyPatches)) {
164795
+ const arr = legacyPatches[key];
164796
+ if (!Array.isArray(arr)) {
164797
+ throw new Error(`Feature: config.yaml -> patches.${key}: expected an array of patches, got ${typeof arr}`);
164798
+ }
164799
+ const legacyErr = fast_json_patch_default().validate(arr);
164800
+ if (legacyErr) {
164801
+ throw new Error(`Feature: config.yaml -> patches.${key}: invalid patch ${JSON.stringify(legacyErr.message ?? legacyErr)}`);
165537
164802
  }
165538
164803
  }
165539
164804
  }
@@ -166380,10 +165645,12 @@ const renderTestsSchema = {
166380
165645
  items: {
166381
165646
  type: 'object',
166382
165647
  additionalProperties: false,
166383
- required: ['name', 'cr'],
165648
+ required: ['name'],
165649
+ anyOf: [{ required: ['cr'] }, { required: ['claim'] }],
166384
165650
  properties: {
166385
165651
  name: { type: 'string', minLength: 1 },
166386
165652
  cr: { type: 'string', minLength: 1 },
165653
+ claim: { type: 'string', minLength: 1 },
166387
165654
  args: { type: 'object' },
166388
165655
  },
166389
165656
  },
@@ -166438,6 +165705,9 @@ function resolveCrPath(featurePath, crRelPath) {
166438
165705
  }
166439
165706
  return resolved;
166440
165707
  }
165708
+ function resolveClaimPath(featurePath, claimRelPath) {
165709
+ return resolveCrPath(featurePath, claimRelPath);
165710
+ }
166441
165711
  function listYamlFiles(dir) {
166442
165712
  if (!fs.existsSync(dir))
166443
165713
  return [];
@@ -166501,7 +165771,7 @@ function buildExpectedOutput(config, renderDir) {
166501
165771
  }));
166502
165772
  return {
166503
165773
  files,
166504
- patches: config.patches || [],
165774
+ claimPatches: config.claimPatches || [],
166505
165775
  traceability: {},
166506
165776
  };
166507
165777
  }
@@ -166556,6 +165826,7 @@ async function createRenderContext(prefix = 'feature-render-') {
166556
165826
  buildExpectedOutput,
166557
165827
  loadAndValidateRenderTests,
166558
165828
  resolveCrPath,
165829
+ resolveClaimPath,
166559
165830
  });
166560
165831
 
166561
165832
  ;// CONCATENATED MODULE: ../features_renderer/src/featureArgsValidation.ts
@@ -166648,7 +165919,7 @@ function render(featurePath, featureRenderPath, entity, firestartrConfig = {}, f
166648
165919
  resolveInside(featureRenderPath, dest, 'file dest', 'render target directory');
166649
165920
  }
166650
165921
  }
166651
- const output = { files: [] };
165922
+ const output = { files: [], claimPatches: [] };
166652
165923
  context.config.files.forEach((file) => {
166653
165924
  const { src, dest } = file;
166654
165925
  // For now let's keep upgradable flag for backward compatibility
@@ -166669,30 +165940,125 @@ function render(featurePath, featureRenderPath, entity, firestartrConfig = {}, f
166669
165940
  userManaged: userManaged,
166670
165941
  targetBranch,
166671
165942
  });
166672
- output.patches = context.config.patches;
166673
- // Not used anymore
166674
- // output.unpatches = context.config.unpatches
166675
165943
  });
165944
+ // claimPatches are applied to the claim during claim stitching. Present in
165945
+ // the output even when empty or when the feature renders no files. The
165946
+ // legacy `patches` field is deliberately not copied: it is accepted in
165947
+ // config.yaml for backward compatibility but ignored for claim-level
165948
+ // behaviour.
165949
+ output.claimPatches = context.config.claimPatches || [];
166676
165950
  output.traceability = context.traceability;
165951
+ external_fs_default().mkdirSync(featureRenderPath, { recursive: true });
166677
165952
  external_fs_default().writeFileSync(external_path_default().join(featureRenderPath, 'config.json'), JSON.stringify(context.config));
166678
165953
  // write the output file
166679
165954
  const configFile = external_path_default().join(featureRenderPath, 'output.json');
166680
165955
  external_fs_default().writeFileSync(configFile, JSON.stringify(output));
166681
165956
  return output;
166682
165957
  }
166683
- function buildContext(entity, args, firestartrConfig, featureArgs) {
165958
+ function getClaimPatches(featurePath, entity, firestartrConfig = {}, featureArgs = {}) {
165959
+ const configData = validate(featurePath);
165960
+ validateFeatureArgs(featurePath, featureArgs);
165961
+ const context = buildContext(entity, configData.args, firestartrConfig, featureArgs);
165962
+ const rendered = JSON.parse(renderContent(JSON.stringify(configData), context));
165963
+ return rendered.claimPatches ?? [];
165964
+ }
165965
+ function buildContext(stitchedClaim, args, firestartrConfig, featureArgs) {
166684
165966
  const context = {};
165967
+ const resolveRef = (doc, ref) => {
165968
+ const v = lodash_default().get(doc, ref);
165969
+ if (v !== undefined)
165970
+ return v;
165971
+ // Fallback for transition: try CR-shaped alternatives when stitchedClaim is CR-shaped
165972
+ // and vice versa. Covers the ADR 0006 table plus legacy feature_a provisioner paths.
165973
+ const altTable = {
165974
+ 'providers,github,org': [
165975
+ ['spec', 'org'],
165976
+ ['spec', 'provisioner', 'org'],
165977
+ ],
165978
+ 'providers,github,branchStrategy,defaultBranch': [
165979
+ ['spec', 'repo', 'defaultBranch'],
165980
+ ['spec', 'provisioner', 'repo', 'defaultBranch'],
165981
+ ],
165982
+ 'providers,github,name': [
165983
+ ['metadata', 'annotations', 'firestartr.dev/external-name'],
165984
+ ['metadata', 'name'],
165985
+ ],
165986
+ 'providers,github,technology,stack': [
165987
+ ['spec', 'firestartr', 'technology', 'stack'],
165988
+ ['spec', 'provisioner', 'technology', 'stack'],
165989
+ ],
165990
+ name: [['metadata', 'name']],
165991
+ 'annotations,firestartr.dev/dest-annotation': [
165992
+ ['metadata', 'annotations', 'firestartr.dev/dest-annotation'],
165993
+ ],
165994
+ };
165995
+ const key = ref.join(',');
165996
+ const alts = altTable[key];
165997
+ if (alts) {
165998
+ for (const alt of alts) {
165999
+ const av = lodash_default().get(doc, alt);
166000
+ if (av !== undefined)
166001
+ return av;
166002
+ }
166003
+ }
166004
+ // Reverse fallback: if ref is CR-shaped, try claim-shaped
166005
+ const reverseTable = {
166006
+ 'spec,org': ['providers', 'github', 'org'],
166007
+ 'spec,provisioner,technology,stack': [
166008
+ 'providers',
166009
+ 'github',
166010
+ 'technology',
166011
+ 'stack',
166012
+ ],
166013
+ 'spec,firestartr,technology,stack': [
166014
+ 'providers',
166015
+ 'github',
166016
+ 'technology',
166017
+ 'stack',
166018
+ ],
166019
+ 'metadata,name': ['name'],
166020
+ 'metadata,annotations,firestartr.dev/dest-annotation': [
166021
+ 'annotations',
166022
+ 'firestartr.dev/dest-annotation',
166023
+ ],
166024
+ 'spec,provisioner,org': ['providers', 'github', 'org'],
166025
+ 'spec,provisioner,repo,defaultBranch': [
166026
+ 'providers',
166027
+ 'github',
166028
+ 'branchStrategy',
166029
+ 'defaultBranch',
166030
+ ],
166031
+ 'spec,repo,defaultBranch': [
166032
+ 'providers',
166033
+ 'github',
166034
+ 'branchStrategy',
166035
+ 'defaultBranch',
166036
+ ],
166037
+ 'metadata,annotations,firestartr.dev/external-name': [
166038
+ 'providers',
166039
+ 'github',
166040
+ 'name',
166041
+ ],
166042
+ };
166043
+ const rev = reverseTable[ref.join(',')];
166044
+ if (rev) {
166045
+ const rv = lodash_default().get(doc, rev);
166046
+ if (rv !== undefined)
166047
+ return rv;
166048
+ }
166049
+ return v;
166050
+ };
166685
166051
  Object.entries(args).forEach(([key, arg]) => {
166686
166052
  if ('$default' in arg) {
166687
166053
  if (Array.isArray(arg['$default'])) {
166688
- context[key] = lodash_default().get(entity, arg['$default']);
166054
+ context[key] = resolveRef(stitchedClaim, arg['$default']);
166689
166055
  }
166690
166056
  else {
166691
166057
  context[key] = arg['$default'];
166692
166058
  }
166693
166059
  }
166694
166060
  if ('$ref' in arg) {
166695
- const refValue = lodash_default().get(entity, arg['$ref']);
166061
+ const refValue = resolveRef(stitchedClaim, arg['$ref']);
166696
166062
  context[key] = refValue;
166697
166063
  }
166698
166064
  else if ('$lit' in arg) {
@@ -166822,6 +166188,7 @@ function updateFileContent(featureRenderPath, filePath, content) {
166822
166188
 
166823
166189
 
166824
166190
 
166191
+
166825
166192
  /* harmony default export */ const features_renderer = ({
166826
166193
  validate: validate,
166827
166194
  render: render,
@@ -166831,6 +166198,7 @@ function updateFileContent(featureRenderPath, filePath, content) {
166831
166198
  renderContent: renderContent,
166832
166199
  expandFiles: expandFiles,
166833
166200
  validateFeatureArgs: validateFeatureArgs,
166201
+ getClaimPatches: getClaimPatches,
166834
166202
  });
166835
166203
 
166836
166204
  ;// CONCATENATED MODULE: ../features_preparer/src/logger.ts
@@ -166855,6 +166223,13 @@ function renderFeature(featureName, version, owner, repo, featureOwner, renderPa
166855
166223
  function renderFeatureFromPath(extractPath, renderedPath, featureOwner, featureArgs = {}) {
166856
166224
  return features_renderer.render(extractPath, renderedPath, featureOwner, {}, featureArgs);
166857
166225
  }
166226
+ function getFeatureClaimPatches(featureName, version, owner, repo, featureOwner, featureArgs = {}) {
166227
+ const extractPath = external_path_default().join(catalog_common/* default.features.tarballs.getFeaturesExtractPath */.Z.features.tarballs.getFeaturesExtractPath(featureName, version, owner, repo), 'packages', featureName);
166228
+ return getClaimPatches(extractPath, featureOwner, {}, featureArgs);
166229
+ }
166230
+ function getFeatureClaimPatchesFromPath(extractPath, featureOwner, featureArgs = {}) {
166231
+ return getClaimPatches(extractPath, featureOwner, {}, featureArgs);
166232
+ }
166858
166233
 
166859
166234
  // EXTERNAL MODULE: ../../node_modules/adm-zip/adm-zip.js
166860
166235
  var adm_zip = __nccwpck_require__(7993);
@@ -166905,6 +166280,7 @@ featureArgs = {}, repo = 'features', owner = 'prefapp') {
166905
166280
  async function processFeature(featureName, reference, featureOwner, // -> cr
166906
166281
  featureArgs = {}, repo = 'features', owner = 'prefapp') {
166907
166282
  await downloadFeatureZip(repo, featureName, reference, owner);
166283
+ featureArgs = { ...(featureArgs ?? {}) };
166908
166284
  const commitInfo = await resolveFeatureCommit(owner, repo, reference);
166909
166285
  featureArgs['traceability'] = {
166910
166286
  version: reference,
@@ -166918,6 +166294,27 @@ featureArgs = {}, repo = 'features', owner = 'prefapp') {
166918
166294
  };
166919
166295
  return renderFeature(featureName, reference, owner, repo, featureOwner, '/tmp', featureArgs);
166920
166296
  }
166297
+ async function installer_getFeatureClaimPatches(featureName, version, featureOwner, featureArgs = {}, repo = 'features', owner = 'prefapp') {
166298
+ const reference = `${featureName}-v${version}`;
166299
+ return processFeatureClaimPatches(featureName, reference, featureOwner, featureArgs, repo, owner);
166300
+ }
166301
+ async function getFeatureClaimPatchesFromRef(featureName, featureRef, featureOwner, featureArgs = {}, repo = 'features', owner = 'prefapp') {
166302
+ const reference = `${featureRef}`;
166303
+ return processFeatureClaimPatches(featureName, reference, featureOwner, featureArgs, repo, owner);
166304
+ }
166305
+ async function processFeatureClaimPatches(featureName, reference, featureOwner, featureArgs = {}, repo = 'features', owner = 'prefapp') {
166306
+ await downloadFeatureZip(repo, featureName, reference, owner);
166307
+ featureArgs = { ...(featureArgs ?? {}) };
166308
+ featureArgs['traceability'] = {
166309
+ version: reference,
166310
+ owner,
166311
+ repo,
166312
+ name: featureName,
166313
+ ref: reference,
166314
+ url: `https://github.com/${owner}/${repo}/tree/${reference}/packages/${featureName}`,
166315
+ };
166316
+ return getFeatureClaimPatches(featureName, reference, owner, repo, featureOwner, featureArgs);
166317
+ }
166921
166318
  async function resolveFeatureCommit(owner, repo, reference) {
166922
166319
  try {
166923
166320
  const octokit = await github["default"].getOctokitForOrg(owner, true);
@@ -167005,6 +166402,9 @@ async function downloadFeatureZip(repo, featureName, reference, owner = 'prefapp
167005
166402
  /* harmony default export */ const src = ({
167006
166403
  renderFeature: renderFeature,
167007
166404
  renderFeatureFromPath: renderFeatureFromPath,
166405
+ getFeatureClaimPatches: installer_getFeatureClaimPatches,
166406
+ getFeatureClaimPatchesFromRef: getFeatureClaimPatchesFromRef,
166407
+ getFeatureClaimPatchesFromPath: getFeatureClaimPatchesFromPath,
167008
166408
  getFeatureConfigFromRef: getFeatureConfigFromRef,
167009
166409
  getFeatureConfig: getFeatureConfig,
167010
166410
  prepareFeature: prepareFeature,
@@ -167019,8 +166419,1266 @@ async function downloadFeatureZip(repo, featureName, reference, owner = 'prefapp
167019
166419
  renderFeatureFromPath: src.renderFeatureFromPath,
167020
166420
  getFeatureConfig: src.getFeatureConfig,
167021
166421
  getFeatureConfigFromRef: src.getFeatureConfigFromRef,
166422
+ getFeatureClaimPatches: src.getFeatureClaimPatches,
166423
+ getFeatureClaimPatchesFromRef: src.getFeatureClaimPatchesFromRef,
166424
+ getFeatureClaimPatchesFromPath: src.getFeatureClaimPatchesFromPath,
167022
166425
  });
167023
166426
 
166427
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/claims/stitching/protectedPaths.ts
166428
+ // Platform-curated protected claim paths — features may not write to these.
166429
+ // Stored as JSON Pointers (RFC 6901). Supports wildcard `*` for a single segment.
166430
+ // Example: /providers/STAR/org matches /providers/github/org where STAR is *.
166431
+ const PROTECTED_CLAIM_PATHS = [
166432
+ '/kind',
166433
+ '/name',
166434
+ '/providers/*/org',
166435
+ '/providers/github/org',
166436
+ '/providers/github/name',
166437
+ '/providers/*/features',
166438
+ '/metadata/name',
166439
+ '/metadata/namespace',
166440
+ ];
166441
+ function isProtectedPath(patchPath) {
166442
+ const normalizedPatch = normalizePointer(patchPath);
166443
+ for (const protectedPath of PROTECTED_CLAIM_PATHS) {
166444
+ if (matchesProtected(protectedPath, normalizedPatch)) {
166445
+ return true;
166446
+ }
166447
+ }
166448
+ return false;
166449
+ }
166450
+ function normalizePointer(pointer) {
166451
+ // '' is RFC 6901's whole-document (root) pointer. Replacing the root touches
166452
+ // every protected field, so it must keep its identity for classification
166453
+ // instead of being rewritten to '/' (the "" empty-string member).
166454
+ if (pointer === '')
166455
+ return pointer;
166456
+ if (!pointer.startsWith('/')) {
166457
+ return '/' + pointer;
166458
+ }
166459
+ return pointer;
166460
+ }
166461
+ function matchesProtected(protectedPointer, patchPointer) {
166462
+ const protectedSegments = protectedPointer
166463
+ .split('/')
166464
+ .slice(1)
166465
+ .map(unescapePointer);
166466
+ const patchSegments = patchPointer.split('/').slice(1).map(unescapePointer);
166467
+ // Treat ancestor/descendant as protected: a patch to a parent (e.g. /metadata)
166468
+ // would replace the protected child (/metadata/name), and a patch to a child
166469
+ // (e.g. /metadata/name/extra) is also under the protected tree. Match when
166470
+ // the shorter prefix equals the longer prefix (with wildcard support).
166471
+ const minLen = Math.min(protectedSegments.length, patchSegments.length);
166472
+ for (let i = 0; i < minLen; i++) {
166473
+ if (protectedSegments[i] === '*')
166474
+ continue;
166475
+ if (protectedSegments[i] !== patchSegments[i])
166476
+ return false;
166477
+ }
166478
+ return true;
166479
+ }
166480
+ function unescapePointer(segment) {
166481
+ return segment.replace(/~1/g, '/').replace(/~0/g, '~');
166482
+ }
166483
+
166484
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/claims/stitching/errors.ts
166485
+ class StitchingError extends Error {
166486
+ constructor(violations) {
166487
+ const lines = violations.map((v) => ` - ${v.message}`).join('\n');
166488
+ super(`Claim stitching failed with ${violations.length} violation(s):\n${lines}`);
166489
+ this.name = 'StitchingError';
166490
+ this.violations = violations;
166491
+ }
166492
+ }
166493
+ function formatStitchingError(error) {
166494
+ return error.message;
166495
+ }
166496
+
166497
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/claims/stitching/validateFeatureDescriptors.ts
166498
+
166499
+
166500
+ let validateFeatureDescriptors_validate;
166501
+ let validateFeatureDescriptors_ajv;
166502
+ function getValidate() {
166503
+ if (!validateFeatureDescriptors_validate) {
166504
+ validateFeatureDescriptors_ajv = new (_2020_default())();
166505
+ validateFeatureDescriptors_ajv.addSchema(feature_schema.definitions.GithubComponentFeatureClaim);
166506
+ validateFeatureDescriptors_validate = validateFeatureDescriptors_ajv.compile({
166507
+ type: 'array',
166508
+ items: { $ref: 'firestartr.dev://github/GithubComponentFeatureClaim' },
166509
+ });
166510
+ }
166511
+ return validateFeatureDescriptors_validate;
166512
+ }
166513
+ // Validates the `providers.github.features` descriptor array against the same
166514
+ // GithubComponentFeatureClaim schema used by claim-kind AJV validation. This
166515
+ // runs BEFORE any feature preparer (auth/network) is invoked, so malformed or
166516
+ // unauthorized `repo`/`ref`/`version` values are rejected without triggering
166517
+ // GitHub downloads. Full AJV validation of the stitched claim is still applied
166518
+ // after stitching.
166519
+ function validateFeatureDescriptors(claim) {
166520
+ const typedClaim = claim;
166521
+ const features = typedClaim.providers?.github?.features;
166522
+ if (!Array.isArray(features))
166523
+ return;
166524
+ const v = getValidate();
166525
+ if (v(features))
166526
+ return;
166527
+ const details = (v.errors ?? [])
166528
+ .map((e) => {
166529
+ const formatted = `${e.instancePath || '/'} ${e.message}`;
166530
+ return ` - ${formatted}`;
166531
+ })
166532
+ .join('\n');
166533
+ throw new Error(`Invalid feature descriptor(s):\n${details}\nFix the claim before stitching or rendering.`);
166534
+ }
166535
+
166536
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/claims/stitching/stitching.ts
166537
+
166538
+
166539
+
166540
+
166541
+
166542
+ let MOCK_FEATURES_FN;
166543
+ function MOCK_STITCHING_FEATURES(mock) {
166544
+ MOCK_FEATURES_FN = mock;
166545
+ }
166546
+ // Non-enumerable stamp marking a claim as already stitched. Lets stitching be
166547
+ // once-only at each entry point (e.g. renderFromImports) without re-running
166548
+ // feature downloads or re-applying gates on the same claim object.
166549
+ const STITCHED_CLAIM = Symbol('firestartr.stitchedClaim');
166550
+ function stitching_unescapePointer(segment) {
166551
+ return segment.replace(/~1/g, '/').replace(/~0/g, '~');
166552
+ }
166553
+ function pointerExists(doc, pointer) {
166554
+ const segments = pointer.split('/').slice(1).map(stitching_unescapePointer);
166555
+ let cur = doc;
166556
+ for (const seg of segments) {
166557
+ if (cur === null || cur === undefined || typeof cur !== 'object')
166558
+ return false;
166559
+ if (!Object.prototype.hasOwnProperty.call(cur, seg))
166560
+ return false;
166561
+ cur = cur[seg];
166562
+ }
166563
+ return true;
166564
+ }
166565
+ function isAppendPointer(pointer) {
166566
+ return pointer.endsWith('/-');
166567
+ }
166568
+ function isRecord(value) {
166569
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
166570
+ }
166571
+ // Deduplication identity for a feature patch (Phase 1 silent dedup). Two
166572
+ // patches are only considered identical intent when the operation, the
166573
+ // normalized pointer, and — for array appends (`add ... /-`) — the appended
166574
+ // element's `name` all match, e.g. two features adding the same label. The
166575
+ // operation is part of the identity so an `add` and a `replace` on the same
166576
+ // pointer are never deduplicated against each other.
166577
+ function dedupIdentity(patch) {
166578
+ const path = normalizePointer(patch.path);
166579
+ if (patch.op === 'add' &&
166580
+ isAppendPointer(path) &&
166581
+ isRecord(patch.value) &&
166582
+ typeof patch.value.name === 'string') {
166583
+ return `${patch.op} ${path}#${patch.value.name}`;
166584
+ }
166585
+ return `${patch.op} ${path}`;
166586
+ }
166587
+ // Write region for a feature patch — the claim locations the patch occupies.
166588
+ // For a regular op it is the unescaped pointer segments; for an array append
166589
+ // (`add ... /-`) carrying a `name` it is the array parent plus the element
166590
+ // `name`, so two appends of distinct names stay sibling writes while an append
166591
+ // and a whole-array write overlap.
166592
+ function writeRegion(patch) {
166593
+ const path = normalizePointer(patch.path);
166594
+ const segments = path.split('/').slice(1).map(stitching_unescapePointer);
166595
+ if (patch.op === 'add' &&
166596
+ isAppendPointer(path) &&
166597
+ isRecord(patch.value) &&
166598
+ typeof patch.value.name === 'string') {
166599
+ return [...segments.slice(0, -1), patch.value.name];
166600
+ }
166601
+ return segments;
166602
+ }
166603
+ // Ancestor/descendant (or identical) regions conflict: under JSON Patch
166604
+ // semantics a parent write replaces its whole subtree, so the composed result
166605
+ // would depend on feature order. Distinct-name appends yield sibling regions
166606
+ // and stay composable.
166607
+ function regionsOverlap(a, b) {
166608
+ const minLen = Math.min(a.length, b.length);
166609
+ for (let i = 0; i < minLen; i++) {
166610
+ if (a[i] !== b[i])
166611
+ return false;
166612
+ }
166613
+ return true;
166614
+ }
166615
+ function isStitchedClaim(claim) {
166616
+ return (isRecord(claim) &&
166617
+ claim[STITCHED_CLAIM] === true);
166618
+ }
166619
+ function markStitched(claim) {
166620
+ if (isRecord(claim)) {
166621
+ Object.defineProperty(claim, STITCHED_CLAIM, {
166622
+ value: true,
166623
+ enumerable: false,
166624
+ writable: false,
166625
+ configurable: true,
166626
+ });
166627
+ }
166628
+ return claim;
166629
+ }
166630
+ // Check whether an array at `appendPath`'s parent already contains an element
166631
+ // whose `name` matches `value.name`. Used for the "claim wins" gate: when a
166632
+ // feature tries to append an array element that already exists in the claim,
166633
+ // the patch is silently dropped.
166634
+ function arrayElementExists(doc, appendPath, value) {
166635
+ if (!isRecord(value) || typeof value.name !== 'string')
166636
+ return false;
166637
+ const parentPath = appendPath.slice(0, -2); // strip trailing /-
166638
+ const segments = parentPath.split('/').slice(1).map(stitching_unescapePointer);
166639
+ let cur = doc;
166640
+ for (const seg of segments) {
166641
+ if (cur === null || cur === undefined || typeof cur !== 'object')
166642
+ return false;
166643
+ if (!Object.prototype.hasOwnProperty.call(cur, seg))
166644
+ return false;
166645
+ cur = cur[seg];
166646
+ }
166647
+ if (!Array.isArray(cur))
166648
+ return false;
166649
+ return cur.some((el) => isRecord(el) && el.name === value.name);
166650
+ }
166651
+ // fast-json-patch does not create intermediate containers for `add`, and
166652
+ // appending to an array requires the array to already exist. Ensure every
166653
+ // ancestor segment exists before applying an `add`: missing containers are
166654
+ // created as objects, except the immediate parent of a `/-` append, which is
166655
+ // created as an array. Existing (user/default-declared) values are never
166656
+ // overwritten.
166657
+ function ensureAddParents(doc, patch) {
166658
+ const segments = patch.path.split('/').slice(1);
166659
+ let prefix = '';
166660
+ for (let i = 0; i < segments.length - 1; i++) {
166661
+ prefix += '/' + segments[i];
166662
+ if (pointerExists(doc, prefix))
166663
+ continue;
166664
+ const isArrayParent = isAppendPointer(patch.path) && i === segments.length - 2;
166665
+ const value = isArrayParent ? [] : {};
166666
+ try {
166667
+ doc = fast_json_patch.applyPatch(doc, [{ op: 'add', path: prefix, value }], false, false).newDocument;
166668
+ }
166669
+ catch {
166670
+ // Concurrent structural conflict — let the actual patch surface the error.
166671
+ }
166672
+ }
166673
+ return doc;
166674
+ }
166675
+ async function stitchClaim(claimAfterDefaults, preCollectedEnvelopes, originalClaim) {
166676
+ if (isStitchedClaim(claimAfterDefaults)) {
166677
+ return claimAfterDefaults;
166678
+ }
166679
+ const envelopes = preCollectedEnvelopes ?? (await collectFeaturePatches(claimAfterDefaults));
166680
+ if (envelopes.length === 0) {
166681
+ return markStitched(claimAfterDefaults);
166682
+ }
166683
+ // Normalize all patches once so every gate and the apply phase use the same pointers.
166684
+ const normalizedEnvelopes = envelopes.map((env) => ({
166685
+ feature: env.feature,
166686
+ patches: env.patches.map((p) => ({
166687
+ ...p,
166688
+ path: normalizePointer(p.path),
166689
+ _raw: p.path,
166690
+ })),
166691
+ }));
166692
+ // ── Phase 1: silently drop patches that should not be applied ──────────
166693
+ // • Array append whose element already exists in the claim → claim wins
166694
+ // (never for protected claim paths, which are rejected in Phase 2)
166695
+ // • Duplicate identity with identical value across features → silent dedup
166696
+ // (a feature's own ordered patches are always retained verbatim)
166697
+ const dropped = new Set(); // "envelopeIdx:patchIdx"
166698
+ const seenIdentities = new Map();
166699
+ for (let ei = 0; ei < normalizedEnvelopes.length; ei++) {
166700
+ const envelope = normalizedEnvelopes[ei];
166701
+ for (let pi = 0; pi < envelope.patches.length; pi++) {
166702
+ const patch = envelope.patches[pi];
166703
+ const key = `${ei}:${pi}`;
166704
+ // Array claim-wins: element already in claim → drop (protected paths
166705
+ // are exempt so every attempt on them is rejected in Phase 2)
166706
+ if (patch.op === 'add' &&
166707
+ isAppendPointer(patch.path) &&
166708
+ !isProtectedPath(patch.path)) {
166709
+ if (arrayElementExists(claimAfterDefaults, patch.path, patch.value)) {
166710
+ dropped.add(key);
166711
+ continue;
166712
+ }
166713
+ }
166714
+ // Silent dedup across features only: same op + destination + value from
166715
+ // a DIFFERENT feature → drop. A feature's own ordered patches (e.g. a
166716
+ // repeated append, or a scalar written twice) are always retained.
166717
+ const identity = dedupIdentity(patch);
166718
+ const existing = seenIdentities.get(identity);
166719
+ if (existing && existing.feature !== envelope.feature) {
166720
+ if (JSON.stringify(existing.value) === JSON.stringify(patch.value)) {
166721
+ dropped.add(key);
166722
+ continue;
166723
+ }
166724
+ // Different value — kept here, caught as a violation in Phase 2.
166725
+ }
166726
+ // Refresh the recorded writer/value so later features compare against
166727
+ // the latest write by this feature.
166728
+ seenIdentities.set(identity, {
166729
+ feature: envelope.feature,
166730
+ value: patch.value,
166731
+ });
166732
+ }
166733
+ }
166734
+ // ── Phase 2: collect violations on non-dropped patches ─────────────────
166735
+ const violations = [];
166736
+ // Writers observed so far (write region + feature). Gate 2 compares every new
166737
+ // patch's region against prior writers from OTHER features, covering both
166738
+ // identical destinations and ancestor/descendant destinations.
166739
+ const priorWrites = [];
166740
+ for (let ei = 0; ei < normalizedEnvelopes.length; ei++) {
166741
+ const envelope = normalizedEnvelopes[ei];
166742
+ // Per-feature shadow document: tracks mutations within this envelope so that
166743
+ // ordered sequences like add → replace within one feature resolve correctly.
166744
+ let shadow = JSON.parse(JSON.stringify(claimAfterDefaults));
166745
+ for (let pi = 0; pi < envelope.patches.length; pi++) {
166746
+ if (dropped.has(`${ei}:${pi}`))
166747
+ continue;
166748
+ const patch = envelope.patches[pi];
166749
+ const path = patch.path;
166750
+ const raw = patch._raw ?? path;
166751
+ // Gate 1: protected path
166752
+ if (isProtectedPath(path)) {
166753
+ violations.push({
166754
+ feature: envelope.feature,
166755
+ op: patch.op,
166756
+ path,
166757
+ reason: 'protected-path',
166758
+ message: `Feature '${envelope.feature}' patch ${patch.op} ${raw} (normalized ${path}) targets protected claim path`,
166759
+ });
166760
+ }
166761
+ // Gate 2: conflicting write from a DIFFERENT feature to the same
166762
+ // destination or an ancestor/descendant of it (region-based, op-agnostic
166763
+ // — see writeRegion). A feature's own ordered patches never self-conflict.
166764
+ const region = writeRegion(patch);
166765
+ const overlapping = priorWrites.find((w) => w.feature !== envelope.feature && regionsOverlap(w.region, region));
166766
+ if (overlapping) {
166767
+ violations.push({
166768
+ feature: envelope.feature,
166769
+ op: patch.op,
166770
+ path,
166771
+ reason: 'duplicate-path',
166772
+ conflictingFeature: overlapping.feature,
166773
+ message: `Feature '${envelope.feature}' and '${overlapping.feature}' both write overlapping paths (${raw} overlaps ${overlapping.path}); compose them in one feature instead`,
166774
+ });
166775
+ }
166776
+ priorWrites.push({ region, feature: envelope.feature, path });
166777
+ // Gate 3: replace / remove to a path absent from this feature's mutation
166778
+ // sequence (tracked via shadow), not the static claimAfterDefaults.
166779
+ if (['replace', 'remove'].includes(patch.op)) {
166780
+ if (!pointerExists(shadow, path)) {
166781
+ violations.push({
166782
+ feature: envelope.feature,
166783
+ op: patch.op,
166784
+ path,
166785
+ reason: 'overwrite-protected',
166786
+ message: `Feature '${envelope.feature}' patch ${patch.op} ${raw} (normalized ${path}) targets absent path (replace/remove requires existing value)`,
166787
+ });
166788
+ }
166789
+ }
166790
+ // Gate 4: non-append ops must not overwrite a user-declared field
166791
+ // (overwrite protection). The user's own claim wins over any feature.
166792
+ // Only the patch's target field itself is protected: adding a sibling
166793
+ // field under a user-declared parent (e.g. a new field in
166794
+ // /providers/github) is allowed. Array appends (`add ... /-`) are
166795
+ // exempt: the appended element is deduplicated against the claim in
166796
+ // Phase 1, preserving original values, while distinct elements from
166797
+ // multiple features may be added.
166798
+ if (originalClaim && !isAppendPointer(path)) {
166799
+ if (pointerExists(originalClaim, path)) {
166800
+ violations.push({
166801
+ feature: envelope.feature,
166802
+ op: patch.op,
166803
+ path,
166804
+ reason: 'user-declared-path',
166805
+ message: `Feature '${envelope.feature}' patch ${patch.op} ${raw} (normalized ${path}) targets a field declared by the user (overwrite protection)`,
166806
+ });
166807
+ }
166808
+ }
166809
+ // Update shadow for subsequent patches within this feature
166810
+ try {
166811
+ if (patch.op === 'add')
166812
+ shadow = ensureAddParents(shadow, patch);
166813
+ shadow = fast_json_patch.applyPatch(shadow, [patch], false, false).newDocument;
166814
+ }
166815
+ catch {
166816
+ /* leave shadow unchanged — Gate 3 stays conservative */
166817
+ }
166818
+ }
166819
+ }
166820
+ if (violations.length > 0) {
166821
+ throw new StitchingError(violations);
166822
+ }
166823
+ // ── Phase 3: apply remaining patches ───────────────────────────────────
166824
+ let stitched = JSON.parse(JSON.stringify(claimAfterDefaults));
166825
+ for (let ei = 0; ei < normalizedEnvelopes.length; ei++) {
166826
+ const envelope = normalizedEnvelopes[ei];
166827
+ const patchesToApply = envelope.patches.filter((_, pi) => !dropped.has(`${ei}:${pi}`));
166828
+ if (patchesToApply.length === 0)
166829
+ continue;
166830
+ // ── Apply each patch in order, creating parents for adds as needed ───
166831
+ for (const patch of patchesToApply) {
166832
+ if (patch.op === 'add') {
166833
+ stitched = ensureAddParents(stitched, patch);
166834
+ }
166835
+ const result = fast_json_patch.applyPatch(stitched, [patch], false, false);
166836
+ stitched = result.newDocument;
166837
+ }
166838
+ }
166839
+ return markStitched(stitched);
166840
+ }
166841
+ async function collectFeaturePatches(claim) {
166842
+ if (MOCK_FEATURES_FN) {
166843
+ return MOCK_FEATURES_FN(claim);
166844
+ }
166845
+ const typedClaim = claim;
166846
+ const features = typedClaim.providers?.github?.features;
166847
+ if (features === undefined)
166848
+ return [];
166849
+ if (!Array.isArray(features)) {
166850
+ throw new Error('Invalid feature descriptor(s): /providers/github/features must be an array');
166851
+ }
166852
+ if (features.length === 0)
166853
+ return [];
166854
+ // Gate 0: reject malformed feature descriptors (repo/ref/version shape)
166855
+ // BEFORE any preparer call, so no auth/network work is triggered by data
166856
+ // that claim-kind AJV validation would reject.
166857
+ validateFeatureDescriptors(claim);
166858
+ const envelopes = [];
166859
+ for (const feature of features) {
166860
+ const featureName = feature.name;
166861
+ const versionOrRef = feature.ref ?? feature.version ?? '';
166862
+ const repo = feature.repo
166863
+ ? (feature.repo.split('/')[1] ?? 'features')
166864
+ : 'features';
166865
+ const owner = feature.repo
166866
+ ? (feature.repo.split('/')[0] ?? 'prefapp')
166867
+ : 'prefapp';
166868
+ const args = feature.args ?? {};
166869
+ try {
166870
+ let patchesOrRendered;
166871
+ const preparerAny = features_preparer;
166872
+ if (feature.ref) {
166873
+ if (typeof preparerAny.getFeatureClaimPatchesFromRef === 'function') {
166874
+ patchesOrRendered = await preparerAny.getFeatureClaimPatchesFromRef(featureName, versionOrRef, claim, args, repo, owner);
166875
+ }
166876
+ else {
166877
+ patchesOrRendered = await preparerAny.getFeatureConfigFromRef(featureName, versionOrRef, claim, args, repo, owner);
166878
+ }
166879
+ }
166880
+ else {
166881
+ if (typeof preparerAny.getFeatureClaimPatches === 'function') {
166882
+ patchesOrRendered = await preparerAny.getFeatureClaimPatches(featureName, versionOrRef, claim, args, repo, owner);
166883
+ }
166884
+ else {
166885
+ patchesOrRendered = await preparerAny.getFeatureConfig(featureName, versionOrRef, claim, args, repo, owner);
166886
+ }
166887
+ }
166888
+ const patches = Array.isArray(patchesOrRendered)
166889
+ ? patchesOrRendered
166890
+ : extractClaimPatches(patchesOrRendered);
166891
+ envelopes.push({ feature: featureName, patches });
166892
+ }
166893
+ catch (err) {
166894
+ throw new Error(`Failed to collect claimPatches for feature '${featureName}': ${err instanceof Error ? err.message : String(err)}`);
166895
+ }
166896
+ }
166897
+ return envelopes;
166898
+ }
166899
+ function extractClaimPatches(rendered) {
166900
+ const patches = rendered.claimPatches;
166901
+ if (!patches)
166902
+ return [];
166903
+ if (Array.isArray(patches))
166904
+ return patches;
166905
+ throw new Error(`Feature claimPatches must be a flat array (claim-relative pointers like /annotations/...), got ${typeof patches}: ${JSON.stringify(patches).slice(0, 200)}`);
166906
+ }
166907
+
166908
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/lazy_loader.ts
166909
+
166910
+
166911
+
166912
+
166913
+
166914
+
166915
+
166916
+
166917
+
166918
+
166919
+
166920
+
166921
+
166922
+
166923
+
166924
+
166925
+
166926
+ // We need to ensure the grep command is a gnu version
166927
+ let IS_GNU_GREP = false;
166928
+ let GREP_ON_CHECK = false;
166929
+ // this loop is for avoid race conditions
166930
+ // once a check is running no more checks
166931
+ async function waitForCheck() {
166932
+ const f_wait = () => new Promise((timeOut) => setTimeout(timeOut, 10));
166933
+ do {
166934
+ await f_wait();
166935
+ } while (GREP_ON_CHECK);
166936
+ }
166937
+ function checkGrep() {
166938
+ return new Promise((ok, ko) => {
166939
+ // idempotency: already checked
166940
+ if (IS_GNU_GREP)
166941
+ return ok();
166942
+ // a check is already running no new checks
166943
+ if (GREP_ON_CHECK)
166944
+ return waitForCheck();
166945
+ logger.info('Checking the grep command');
166946
+ GREP_ON_CHECK = true;
166947
+ const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['--version']);
166948
+ handler.on('close', (code) => {
166949
+ GREP_ON_CHECK = false;
166950
+ if (code === 0) {
166951
+ logger.debug('Grep is a gnu grep');
166952
+ IS_GNU_GREP = true;
166953
+ ok();
166954
+ }
166955
+ else {
166956
+ ko('Lazy evaluation needs a gnu-grep command');
166957
+ }
166958
+ });
166959
+ });
166960
+ }
166961
+ async function loadClaim(claimRef, org, defaults = loadClaimDefaults(), patchClaim = loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, existingRefs = {}, postValidations = new Map()) {
166962
+ await checkGrep();
166963
+ let result = existingRefs;
166964
+ logger.info(`Load reference ${claimRef}`);
166965
+ initVirtualClaims(org);
166966
+ logger.info(`Load reference (parts) ${claimRef.split(/-/)[0]} ${claimRef.replace(/^[^-]+-/, '')}`);
166967
+ // cargas datos con grep
166968
+ try {
166969
+ const claimData = await lazyGetClaim(claimRef.split(/-/)[0], claimRef.replace(/^[^-]+-/, ''), org, cwd);
166970
+ const rawClaim = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(claimData);
166971
+ let claim = patchClaim(rawClaim, defaults);
166972
+ // Claim stitching: feature claim-patches with gates before AJV
166973
+ try {
166974
+ claim = await stitchClaim(claim, undefined, rawClaim);
166975
+ }
166976
+ catch (e) {
166977
+ throw new Error(`Error when stitching claim ${claimRef}: ${e instanceof Error ? e.message : String(e)}`);
166978
+ }
166979
+ let variants = [];
166980
+ if (claim.kind === 'TFWorkspaceClaim' &&
166981
+ claim.providers?.terraform?.variants) {
166982
+ variants = claim.providers.terraform.variants;
166983
+ delete claim.providers.terraform.variants;
166984
+ }
166985
+ logger.silly(`Patched claim is:
166986
+ ---
166987
+ ${catalog_common/* default.io.toYaml */.Z.io.toYaml(claim)}`);
166988
+ try {
166989
+ validateClaim(claim, base[`${claim.kind}Schema`]);
166990
+ await optionalValidation(claim);
166991
+ }
166992
+ catch (error) {
166993
+ let errorMsg = '';
166994
+ if (Array.isArray(error)) {
166995
+ for (const data of error) {
166996
+ errorMsg = `${errorMsg}
166997
+ - ${data.instancePath}: ${data.message}`;
166998
+ }
166999
+ }
167000
+ else {
167001
+ errorMsg = error instanceof Error ? error.message : String(error);
167002
+ }
167003
+ throw new Error(`Error when validating claim ${claimRef}: ${errorMsg}`);
167004
+ }
167005
+ result[claimRef] = {};
167006
+ result[claimRef]['claim'] = claim;
167007
+ result[claimRef]['claimPath'] = VisitedClaims[claimRef];
167008
+ if (VisitedClaims[claimRef] === 'virtual') {
167009
+ result = await setVirtualClaimAdditionalData(result, claim, claimRef);
167010
+ }
167011
+ else {
167012
+ result = await setNonVirtualClaimAdditionalData(result, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
167013
+ }
167014
+ const claimKind = claim.kind;
167015
+ const references = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(claim));
167016
+ for (const ref of references) {
167017
+ if (!result[ref]) {
167018
+ const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
167019
+ result = lodash_default().merge(result, resolvedReferences);
167020
+ }
167021
+ }
167022
+ if (variants.length > 0) {
167023
+ const parentClaimPath = VisitedClaims[claimRef];
167024
+ for (const variant of variants) {
167025
+ if (!variant.name || !variant.overrides) {
167026
+ throw new Error(`Variant in claim ${claimRef} is missing required field 'name' or 'overrides'`);
167027
+ }
167028
+ const prohibitedOverrideFields = ['source', 'module', 'name'];
167029
+ for (const field of prohibitedOverrideFields) {
167030
+ if (field in variant.overrides) {
167031
+ throw new Error(`Variant '${variant.name}' in claim ${claimRef} cannot override '${field}'`);
167032
+ }
167033
+ }
167034
+ const composedName = claim.providers.terraform.name + '-' + variant.name;
167035
+ const variantClaim = lodash_default().cloneDeep(claim);
167036
+ variantClaim._parentClaimName = claim.name;
167037
+ variantClaim.name = composedName;
167038
+ variantClaim.providers.terraform = lodash_default().merge({}, claim.providers.terraform, variant.overrides);
167039
+ variantClaim.providers.terraform.name = composedName;
167040
+ if (!variantClaim.annotations) {
167041
+ variantClaim.annotations = {};
167042
+ }
167043
+ variantClaim.annotations['firestartr.dev/variant-of'] =
167044
+ claim.providers.terraform.name;
167045
+ const variantRef = `TFWorkspaceClaim-${composedName}`;
167046
+ if (result[variantRef]) {
167047
+ throw new Error(`Variant name '${variant.name}' (composed: '${composedName}') from claim '${claimRef}' conflicts with existing claim '${variantRef}'`);
167048
+ }
167049
+ logger.info(`Creating synthetic variant claim ${variantRef}`);
167050
+ result[variantRef] = {};
167051
+ result[variantRef]['claim'] = variantClaim;
167052
+ result[variantRef]['claimPath'] = parentClaimPath;
167053
+ result = await setNonVirtualClaimAdditionalData(result, variantClaim, variantRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers);
167054
+ const variantReferences = extractAllRefs(catalog_common/* default.io.toYaml */.Z.io.toYaml(variantClaim));
167055
+ for (const ref of variantReferences) {
167056
+ if (!result[ref]) {
167057
+ const [resolvedReferences] = await loadClaim(ref, org, defaults, patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, cwd, result, postValidations);
167058
+ result = lodash_default().merge(result, resolvedReferences);
167059
+ }
167060
+ }
167061
+ }
167062
+ }
167063
+ }
167064
+ catch (err) {
167065
+ throw `Lazy Loading: ${err}`;
167066
+ }
167067
+ return [result, postValidations];
167068
+ }
167069
+ let LoadedClaims = {};
167070
+ let VisitedClaims = {};
167071
+ let DuplicatedClaims = {};
167072
+ function resetLazyLoader() {
167073
+ LoadedClaims = {};
167074
+ VisitedClaims = {};
167075
+ DuplicatedClaims = {};
167076
+ }
167077
+ async function lazyGetClaim(kind, name, org, cwd) {
167078
+ const indice = `${kind}-${name}`;
167079
+ logger.info(`Lazy loading ${kind}-${name} with index ${indice}`);
167080
+ if (indice in LoadedClaims)
167081
+ return LoadedClaims[indice];
167082
+ if (isVirtualClaim(kind, name)) {
167083
+ await loadVirtualClaim(kind, name, org);
167084
+ }
167085
+ else {
167086
+ await getClaimsByName(name, cwd);
167087
+ }
167088
+ if (indice in LoadedClaims) {
167089
+ return LoadedClaims[indice];
167090
+ }
167091
+ else {
167092
+ throw new Error(`Error: ${kind}-${name} not found`);
167093
+ }
167094
+ }
167095
+ async function getClaimsByName(name, cwd = '.') {
167096
+ return new Promise((ok, ko) => {
167097
+ const handler = (0,external_node_child_process_namespaceObject.spawn)('grep', ['-r', '-l', '--include=*', '-E', `name: "?${name}"?`, '.'], {
167098
+ cwd: cwd,
167099
+ });
167100
+ logger.info(`Running ${['grep', '-r', '-l', '--include', '-E', 'name: "' + name + '"?', '.'].join(' ')}`);
167101
+ const entradas = [];
167102
+ const chunks = [];
167103
+ handler.stdout.on('data', (data) => {
167104
+ chunks.push(data.toString('utf-8'));
167105
+ });
167106
+ handler.on('close', () => {
167107
+ const dataFinal = chunks.join('');
167108
+ const fileNameList = dataFinal.split(/\n/).filter((line) => line !== '');
167109
+ for (const fileName of fileNameList) {
167110
+ // only yaml files
167111
+ if (!fileName.match(/\.yml$|\.yaml$/)) {
167112
+ continue;
167113
+ }
167114
+ // only entries not already visited
167115
+ if (Object.values(VisitedClaims).includes(fileName)) {
167116
+ continue;
167117
+ }
167118
+ entradas.push(external_path_.join(cwd, fileName));
167119
+ }
167120
+ return Promise.all(entradas.map((entrada) => {
167121
+ return loadRawClaim(entrada);
167122
+ }))
167123
+ .then(() => {
167124
+ ok();
167125
+ })
167126
+ .catch((err) => {
167127
+ ko(err);
167128
+ });
167129
+ });
167130
+ });
167131
+ }
167132
+ async function loadRawClaim(entry) {
167133
+ return new Promise((ok, ko) => {
167134
+ external_fs_.readFile(entry, 'utf-8', (error, data) => {
167135
+ if (error)
167136
+ return ko(`Reading ${entry}: ${error}`);
167137
+ const claim = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
167138
+ if (!('kind' in claim && 'name' in claim)) {
167139
+ logger.warn(`Invalid claim file ${entry}`);
167140
+ }
167141
+ else {
167142
+ const claimKey = `${claim.kind}-${claim.name}`;
167143
+ if (Object.keys(DuplicatedClaims).includes(claimKey) &&
167144
+ DuplicatedClaims[claimKey] !== entry) {
167145
+ return ko(`Duplicated claim ${claimKey} found files: ${DuplicatedClaims[claimKey]} and ${entry}`);
167146
+ }
167147
+ LoadedClaims[claimKey] = data;
167148
+ VisitedClaims[claimKey] = entry;
167149
+ DuplicatedClaims[claimKey] = entry;
167150
+ ok();
167151
+ }
167152
+ });
167153
+ });
167154
+ }
167155
+ async function setVirtualClaimAdditionalData(renderedData, claim, claimRef) {
167156
+ const virtualClaim = getVirtualClaim(claim.kind, claim.name);
167157
+ renderedData[claimRef]['initializers'] = [
167158
+ new UUIDInitializer(claim),
167159
+ new InitializerClaimRef(),
167160
+ new InitializerDefault(virtualClaim.getDefaultConfig()),
167161
+ ];
167162
+ renderedData[claimRef]['globals'] = [];
167163
+ renderedData[claimRef]['overrides'] = [];
167164
+ renderedData[claimRef]['normalizers'] = [new NameNormalizer()];
167165
+ return renderedData;
167166
+ }
167167
+ async function setNonVirtualClaimAdditionalData(renderedData, claim, claimRef, loadInitializers, loadGlobals, loadOverrides, loadNormalizers) {
167168
+ renderedData[claimRef]['initializers'] = await loadInitializers(claim, renderedData[claimRef]['claimPath']);
167169
+ renderedData[claimRef]['globals'] = await loadGlobals(claim);
167170
+ renderedData[claimRef]['overrides'] = loadOverrides(claim);
167171
+ renderedData[claimRef]['normalizers'] = await loadNormalizers(claim, renderedData[claimRef]['claimPath']);
167172
+ return renderedData;
167173
+ }
167174
+ async function loadVirtualClaim(kind, name, org) {
167175
+ const virtualClaim = getVirtualClaim(kind, name);
167176
+ const expandedClaim = await virtualClaim.expand({ org });
167177
+ logger.info(`Loading virtual claim ${kind} ${name} ${org}`);
167178
+ LoadedClaims[`${kind}-${name}`] = catalog_common/* default.io.toYaml */.Z.io.toYaml(expandedClaim);
167179
+ VisitedClaims[`${kind}-${name}`] = 'virtual';
167180
+ }
167181
+
167182
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/claimsDefaulter.ts
167183
+
167184
+
167185
+
167186
+ /*
167187
+ * Default blocks are objects that cannot be merged but applied as a whole. Meaning:
167188
+ * - If the object is defined at the claim-level it is maintained *AS IT IS* (no merge)
167189
+ * - If the block is missing at the claim-level, the default block is applied
167190
+ */
167191
+ const defaultBlocksPaths = ['/providers/terraform/sync'];
167192
+ function applyBlockAwareDefaults(claim, defaultClaim) {
167193
+ // we always work with a clone of the original
167194
+ const claimClone = JSON.parse(JSON.stringify(claim));
167195
+ // if the block is claim-level defined we store it here
167196
+ const defaultBlocks = new Map();
167197
+ // we remove the blocks entirely of the claim
167198
+ // to achieve an add copy
167199
+ for (const defaultBlockPath of defaultBlocksPaths) {
167200
+ if (claimsDefaulter_hasDeepPath(claimClone, defaultBlockPath) !== true)
167201
+ continue;
167202
+ const originalValue = fast_json_patch_default().getValueByPointer(claimClone, defaultBlockPath);
167203
+ if (originalValue) {
167204
+ logger.silly(`${claim.kind}/${claim.name}: has an original ${defaultBlockPath}: preserving`);
167205
+ defaultBlocks.set(defaultBlockPath, originalValue);
167206
+ fast_json_patch_default().applyPatch(claimClone, [{ op: 'remove', path: defaultBlockPath }]);
167207
+ }
167208
+ }
167209
+ // if the patch has the same path of a block
167210
+ // and the block was defined at claim-level
167211
+ // we interchange the value with the original value
167212
+ // otherwise we use the default
167213
+ const jsonPatchOps = fast_json_patch_default().compare(claimClone, defaultClaim)
167214
+ .filter((jp) => jp.op === 'add')
167215
+ .map((jp) => {
167216
+ if (defaultBlocks.has(jp.path)) {
167217
+ return {
167218
+ ...jp,
167219
+ value: defaultBlocks.get(jp.path),
167220
+ };
167221
+ }
167222
+ else {
167223
+ return jp;
167224
+ }
167225
+ });
167226
+ return fast_json_patch_default().applyPatch(claimClone, jsonPatchOps).newDocument;
167227
+ }
167228
+ function claimsDefaulter_hasDeepPath(data, deepPath) {
167229
+ return lodash_default().has(data, deepPath.replace(/\//g, '.').replace(/^\./, ''));
167230
+ }
167231
+
167232
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/loader/loader.ts
167233
+
167234
+
167235
+
167236
+
167237
+
167238
+
167239
+
167240
+
167241
+
167242
+
167243
+
167244
+
167245
+
167246
+
167247
+
167248
+ const isYamlFile = new RegExp(/\.(yaml|yml)$/);
167249
+ /**
167250
+ *
167251
+ * @returns Virtual Claims
167252
+ */
167253
+ const virtualClaims = [new FirestartrAllClaim()];
167254
+ /*
167255
+ * Loads all applicable globals for a given claim and stores them into a list.
167256
+ *
167257
+ * Input:
167258
+ * - claim: our custom claim object, with which we check if the global is applicable
167259
+ *
167260
+ * Returns:
167261
+ * - A GlobalSection array promise, containing all the globals loaded for this claim
167262
+ *
167263
+ */
167264
+ async function loadGlobals(claim) {
167265
+ const result = [];
167266
+ await crawl(getPath('globals'), (entry) => {
167267
+ return isYamlFile.test(entry);
167268
+ }, async (entry, data) => {
167269
+ const globalData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
167270
+ const ext = external_path_.extname(entry);
167271
+ const name = external_path_.basename(entry, ext);
167272
+ if (name in SECTIONS_BY_FILE_NAME) {
167273
+ const section = new SECTIONS_BY_FILE_NAME[name](globalData);
167274
+ if (!(await section.validate(SCHEMAS_BY_SECTION_NAME[name] || {}))) {
167275
+ throw new Error(`Invalid ${name} global file`);
167276
+ }
167277
+ if (globalData.kind === claim.kind) {
167278
+ result.push(section);
167279
+ }
167280
+ else {
167281
+ logger.debug(`Skipping global ${name} because it is not applicable to ${claim.kind}`);
167282
+ }
167283
+ }
167284
+ });
167285
+ logger.info(`Loaded globals ${result}`);
167286
+ return result;
167287
+ }
167288
+ /*
167289
+ * If the input claim is a GithubRepositoryClaim, it loads all it's applicable
167290
+ * overrides and stores them into a list. Otherwise, it returns an empty list.
167291
+ *
167292
+ * Input:
167293
+ * - claim: our custom claim object, which should be a GithubRepositoryClaim
167294
+ *
167295
+ * Returns:
167296
+ * - An Overrider array, with a GithubRepositoryOverrider if the claim
167297
+ * was a GithubRepositoryClaim, or empty if it was not.
167298
+ *
167299
+ */
167300
+ function loadOverrides(claim) {
167301
+ const overrides = [];
167302
+ if (claim.kind === 'ComponentClaim' && claim.providers.github.overrides) {
167303
+ overrides.push(new GithubRepositoryOverrider());
167304
+ }
167305
+ return overrides;
167306
+ }
167307
+ /**
167308
+ * Load all normalizers and stores them into a list.
167309
+ * @param claim
167310
+ * @returns
167311
+ */
167312
+ async function loadNormalizers(_claim, path) {
167313
+ const result = [];
167314
+ for (const normalizer of NORMALIZERS) {
167315
+ result.push(new normalizer({ path: path }));
167316
+ }
167317
+ return result;
167318
+ }
167319
+ /*
167320
+ * Loads all applicable initializers for a given claim and stores them into a list.
167321
+ *
167322
+ * Input:
167323
+ * - claim: our custom claim object, with which we check if the initializer is applicable
167324
+ *
167325
+ * Returns:
167326
+ * - An Initializer array promise, containing all the initializers loaded for this claim
167327
+ *
167328
+ */
167329
+ let loadedInitializers = false;
167330
+ async function loadInitializers(claim, claimPath, initializersPath = getPath('initializers')) {
167331
+ const result = [];
167332
+ await crawl(initializersPath, (entry) => {
167333
+ return isYamlFile.test(entry);
167334
+ }, async (entry, data) => {
167335
+ const initializerData = catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data);
167336
+ const ext = external_path_.extname(entry);
167337
+ const name = external_path_.basename(entry, ext);
167338
+ if (name in INITIALIZERS_BY_FILE_NAME) {
167339
+ const initializerBfN = new INITIALIZERS_BY_FILE_NAME[name](initializerData);
167340
+ if (!(await initializerBfN.validate(SCHEMAS_BY_INITIALIZER_NAME[name] || {}))) {
167341
+ throw new Error(`Invalid ${name} initializer file`);
167342
+ }
167343
+ if (initializerData.kind === claim.kind) {
167344
+ result.push(initializerBfN);
167345
+ }
167346
+ else {
167347
+ logger.debug(`Skipping initializer ${name} because it is not applicable to ${claim.kind}`);
167348
+ }
167349
+ }
167350
+ });
167351
+ for (const initializer of INITIALIZERS) {
167352
+ if (initializer.applicableKinds.includes(claim.kind)) {
167353
+ result.push(new initializer({ path: claimPath }));
167354
+ }
167355
+ }
167356
+ logger.info(`Loaded initializers ${JSON.stringify(result)}`);
167357
+ loadedInitializers = result;
167358
+ return loadedInitializers;
167359
+ }
167360
+ function loadClaimDefaults() {
167361
+ try {
167362
+ return catalog_common/* default.io.fromYaml */.Z.io.fromYaml(external_fs_.readFileSync(`${getPath('claimsDefaults')}/claims_defaults.yaml`, 'utf-8'));
167363
+ }
167364
+ catch (error) {
167365
+ const errMsg = `Could not read claims defaults file in path ${getPath('claimsDefaults')}/claims_defaults.yaml: ${error}`;
167366
+ logger.error(errMsg);
167367
+ throw new Error(errMsg);
167368
+ }
167369
+ }
167370
+ /*
167371
+ * Using fast-json-patch, compares a claim to its kind's defaults, then patches it.
167372
+ *
167373
+ * Input:
167374
+ * - claim: our custom claim object, which we want to patch
167375
+ * - defaultsClaims: an object, containing the defaults for each claim kind,
167376
+ * with the same structure that we use for the actual claims
167377
+ *
167378
+ * Returns:
167379
+ * - The patched claim
167380
+ *
167381
+ */
167382
+ function loader_patchClaim(claim, defaultsClaims) {
167383
+ if (defaultsClaims[claim.kind]) {
167384
+ claim = applyBlockAwareDefaults(claim, defaultsClaims[claim.kind]);
167385
+ }
167386
+ return claim;
167387
+ }
167388
+ async function loadCRsWithFullSet(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
167389
+ const result = {};
167390
+ const fullResult = {};
167391
+ await crawlWithExclusions(crsPath, (entry) => {
167392
+ return isYamlFile.test(entry);
167393
+ }, async (entry, data) => {
167394
+ const yamlData = stripKnownRelations(catalog_common/* default.io.fromYaml */.Z.io.fromYaml(data));
167395
+ const metadata = yamlData?.metadata;
167396
+ if (!(yamlData &&
167397
+ typeof yamlData === 'object' &&
167398
+ 'kind' in yamlData &&
167399
+ metadata &&
167400
+ typeof metadata === 'object' &&
167401
+ 'name' in metadata)) {
167402
+ logger.warn(`Invalid CR file ${entry}`);
167403
+ }
167404
+ else {
167405
+ const crKey = `${yamlData.kind}-${metadata.name}`;
167406
+ if (fullResult[crKey]) {
167407
+ logger.error(`Duplicate CR ${crKey}`);
167408
+ }
167409
+ // Keep the complete CR set for validations that need repository-wide context.
167410
+ fullResult[crKey] = yamlData;
167411
+ // Keep the filtered CR set for previous-CR lookup during claim rendering.
167412
+ if (allowedClaimReferences.length === 0 ||
167413
+ allowedClaimReferences.includes(yamlData.metadata?.annotations?.[catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('claim-ref')])) {
167414
+ result[crKey] = yamlData;
167415
+ }
167416
+ }
167417
+ }, excludedPaths.concat(getAdditionalPaths()));
167418
+ return { crs: result, fullCrs: fullResult };
167419
+ }
167420
+ async function loadCRs(crsPath = getPath('crs'), excludedPaths = [getPath('globals'), getPath('initializers')], allowedClaimReferences = []) {
167421
+ const { crs } = await loadCRsWithFullSet(crsPath, excludedPaths, allowedClaimReferences);
167422
+ return crs;
167423
+ }
167424
+ /*
167425
+ * Description: Get the renamed using claimRef annotation
167426
+ * Input: claims: any, crs: any
167427
+ * Output: renames: IRenameResult[]
167428
+ */
167429
+ async function loadRenames(claims, crs) {
167430
+ /*
167431
+ * If checkRenames is false, we don't need to check for renames
167432
+ */
167433
+ const renamesEnabled = getRenamesEnabled();
167434
+ if (!renamesEnabled)
167435
+ return [];
167436
+ const result = [];
167437
+ /**
167438
+ * For each CR, look for a claim that does not match the name with CR's firestartr.dev/claim-ref annotation
167439
+ */
167440
+ for (const cr of Object.values(crs)) {
167441
+ const anyCr = cr;
167442
+ if (!anyCr?.metadata?.annotations)
167443
+ continue;
167444
+ // if the annotation is a claimRef
167445
+ const annotationName = common.generic.getFirestartrAnnotation('claim-ref');
167446
+ const annotations = anyCr?.metadata?.annotations || {};
167447
+ if (annotationName in annotations) {
167448
+ const claimRef = anyCr.metadata.annotations[annotationName];
167449
+ // split the annotation into kind and name
167450
+ const [kind, name] = claimRef.split('/');
167451
+ // if the claim exists, check if the name is different for the given provider
167452
+ const referencedClaim = claims[`${kind}-${name}`].claim;
167453
+ const oldName = anyCr.metadata.name;
167454
+ const newName = referencedClaim.providers[getConfiguredProvider()].name;
167455
+ if (oldName !== newName) {
167456
+ result.push({
167457
+ kind: referencedClaim.kind,
167458
+ claimPath: claims[`${kind}-${name}`].claimPath,
167459
+ claimName: referencedClaim.name,
167460
+ oldName,
167461
+ newName,
167462
+ });
167463
+ }
167464
+ }
167465
+ }
167466
+ return result;
167467
+ }
167468
+ async function loadClaimsList(claimRefList, claimsPath = getPath('claims')) {
167469
+ const data = {
167470
+ renderClaims: {},
167471
+ crs: {},
167472
+ fullCrs: {},
167473
+ };
167474
+ const defaults = loadClaimDefaults();
167475
+ for await (const claimRef of claimRefList) {
167476
+ const [renderedClaimData] = await loadClaim(claimRef, getOrg(), defaults, loader_patchClaim, loadInitializers, loadGlobals, loadOverrides, loadNormalizers, claimsPath);
167477
+ data.renderClaims = lodash_default().merge(data.renderClaims, renderedClaimData);
167478
+ }
167479
+ const crClaimReferences = [];
167480
+ for (const ref of Object.keys(data.renderClaims)) {
167481
+ // Replaces only the first instance of '-'
167482
+ crClaimReferences.push(ref.replace('-', '/'));
167483
+ }
167484
+ const loadedCrs = await loadCRsWithFullSet(getPath('crs'), [getPath('globals'), getPath('initializers')], crClaimReferences);
167485
+ data['crs'] = loadedCrs.crs;
167486
+ data['fullCrs'] = loadedCrs.fullCrs;
167487
+ return data;
167488
+ }
167489
+ function getOrg() {
167490
+ const groupOrg = catalog_common/* default.environment.getFromEnvironmentWithDefault */.Z.environment.getFromEnvironmentWithDefault(catalog_common/* default.types.envVars.org */.Z.types.envVars.org, '');
167491
+ return groupOrg;
167492
+ }
167493
+
167494
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/references.ts
167495
+ function validateTfStateKeyUniqueness(crs) {
167496
+ const tfStateKeys = {};
167497
+ for (const crKey of Object.keys(crs)) {
167498
+ const cr = crs[crKey];
167499
+ if (!isTerraformWorkspace(cr))
167500
+ continue;
167501
+ const tfKey = cr.spec.firestartr.tfStateKey;
167502
+ if (tfStateKeys[tfKey]) {
167503
+ throw new Error(`❗❗ ❌ RENDER ERROR ❌ ❗❗
167504
+
167505
+ The tfStateKey ${tfKey} is not unique,
167506
+
167507
+ It is being used by the following CRs:
167508
+
167509
+ - ${tfStateKeys[tfKey].kind} ${tfStateKeys[tfKey].metadata.name}
167510
+
167511
+ - ${cr.kind} ${cr.metadata.name}
167512
+
167513
+ Check the following Claims to ensure that the tfStateKey is unique:
167514
+
167515
+ - ${tfStateKeys[tfKey].metadata.annotations['firestartr.dev/claim-ref']}
167516
+
167517
+ - ${cr.metadata.annotations['firestartr.dev/claim-ref']}
167518
+ `);
167519
+ }
167520
+ tfStateKeys[cr.spec.firestartr.tfStateKey] = cr;
167521
+ }
167522
+ }
167523
+ function references_isCatalogEntity(cr) {
167524
+ return [
167525
+ 'Component',
167526
+ 'Domain',
167527
+ 'System',
167528
+ 'User',
167529
+ 'Group',
167530
+ 'Resource',
167531
+ ].includes(cr.kind);
167532
+ }
167533
+ function isTerraformWorkspace(cr) {
167534
+ return cr.kind === 'FirestartrTerraformWorkspace';
167535
+ }
167536
+
167537
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/crSize.ts
167538
+
167539
+ const K8S_OBJECT_SIZE_LIMIT = 1572864; // 1.5 MiB in bytes, etcd recommended limit: https://etcd.io/docs/latest/dev-guide/limit/
167540
+ function validateCrSizes(crs) {
167541
+ for (const key of Object.keys(crs)) {
167542
+ const cr = crs[key];
167543
+ const serialized = catalog_common/* default.io.toYaml */.Z.io.toYaml(cr);
167544
+ const size = Buffer.byteLength(serialized, 'utf8');
167545
+ if (size > K8S_OBJECT_SIZE_LIMIT) {
167546
+ 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).`);
167547
+ }
167548
+ }
167549
+ }
167550
+
167551
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/permissions.ts
167552
+
167553
+ function validatePermissionsUniqueness(crs) {
167554
+ for (const crkey in crs) {
167555
+ const cr = crs[crkey];
167556
+ if (cr.kind === 'FirestartrGithubRepository') {
167557
+ const permissions = cr.spec.permissions;
167558
+ logger.debug(`Validating Permissions Uniqueness of ${crkey}`);
167559
+ if (permissions) {
167560
+ const rolesByIdentifier = new Map();
167561
+ for (const perm of permissions) {
167562
+ const identifier = perm.collaborator
167563
+ ? perm.collaborator
167564
+ : `ref:${perm.ref.kind}:${perm.ref.name}`;
167565
+ const role = perm.role;
167566
+ const prevRole = rolesByIdentifier.get(identifier);
167567
+ if (prevRole === undefined) {
167568
+ rolesByIdentifier.set(identifier, role);
167569
+ }
167570
+ else if (prevRole !== role) {
167571
+ throw new Error(`Conflicting permission role in FirestartrGithubRepository ${crkey}: ${identifier} has roles "${prevRole}" and "${role}".\nFull CR: ${JSON.stringify(cr, null, 2)}`);
167572
+ }
167573
+ }
167574
+ }
167575
+ }
167576
+ }
167577
+ }
167578
+
167579
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/validations/backstageAnnotations.ts
167580
+ const backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX = 'firestartr.backstage.dev/';
167581
+ const CATALOG_KINDS = new Set([
167582
+ 'User',
167583
+ 'Group',
167584
+ 'Component',
167585
+ 'System',
167586
+ 'Domain',
167587
+ 'API',
167588
+ 'Resource',
167589
+ 'CatalogKubernetesResource',
167590
+ 'CatalogTerraformWorkspace',
167591
+ 'CatalogArgoDeploy',
167592
+ 'CatalogOrgWebhook',
167593
+ 'CatalogSecrets',
167594
+ ]);
167595
+ function validateNoBackstageAnnotationsInK8sCrs(crs) {
167596
+ for (const crKey in crs) {
167597
+ const cr = crs[crKey];
167598
+ if (CATALOG_KINDS.has(cr.kind))
167599
+ continue;
167600
+ if (cr.metadata?.annotations) {
167601
+ const backstageKeys = Object.keys(cr.metadata.annotations).filter((k) => k.startsWith(backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX));
167602
+ if (backstageKeys.length > 0) {
167603
+ throw new Error(`K8s CR ${crKey} contains Backstage-only annotations (${backstageKeys.join(', ')}). ` +
167604
+ `Annotations with prefix ${backstageAnnotations_BACKSTAGE_ANNOTATION_PREFIX} must only appear on Backstage catalog entities, not on Kubernetes CRs.`);
167605
+ }
167606
+ }
167607
+ }
167608
+ }
167609
+
167610
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/refsSorter/refsSorter.ts
167611
+
167612
+ /**
167613
+ * @param renderClaims renderClaims to sort
167614
+ * @param kinds kinds to get from renderClaims
167615
+ * @returns renderClaims with only the kinds specified
167616
+ */
167617
+ function sortRenderClaimsByKind(renderClaims, kinds) {
167618
+ let result = {};
167619
+ for (const kind of kinds) {
167620
+ for (const key in renderClaims) {
167621
+ if (renderClaims[key].claim.kind === kind) {
167622
+ result[key] = renderClaims[key];
167623
+ }
167624
+ }
167625
+ result = sortSelfKindRefs(result, kind);
167626
+ }
167627
+ return result;
167628
+ }
167629
+ function sortSelfKindRefs(renderClaims, kind) {
167630
+ if (!hasSelfRefs(kind)) {
167631
+ return renderClaims;
167632
+ }
167633
+ const newRenderClaims = {};
167634
+ const data = extractRefs(renderClaims, kind);
167635
+ const ordered = [];
167636
+ const visiting = [];
167637
+ const visited = [];
167638
+ for (const key of Object.keys(data)) {
167639
+ if (!visited.find((obj) => obj.name === key)) {
167640
+ sortRefs(data, data[key], ordered, visiting, visited);
167641
+ }
167642
+ }
167643
+ for (const cr of ordered) {
167644
+ newRenderClaims[cr.name] = renderClaims[cr.name];
167645
+ }
167646
+ return newRenderClaims;
167647
+ }
167648
+ function sortRefs(data, claim, ordered = [], visiting = [], visited = []) {
167649
+ if (visiting.find((obj) => obj.name === claim.name)) {
167650
+ throw new Error(`Circular dependency detected for '${claim.name}'`);
167651
+ }
167652
+ if (!visited.find((obj) => obj.name === claim.name)) {
167653
+ visiting.push(claim);
167654
+ if (claim.refs) {
167655
+ for (const ref of claim.refs) {
167656
+ const referencedObject = data[ref];
167657
+ if (!referencedObject) {
167658
+ throw new Error(`Reference '${ref}' does not exist for '${claim.name}'`);
167659
+ }
167660
+ sortRefs(data, referencedObject, ordered, visiting, visited);
167661
+ }
167662
+ }
167663
+ visited.push(visiting.pop());
167664
+ ordered.push(claim);
167665
+ }
167666
+ }
167667
+ function hasSelfRefs(kind) {
167668
+ return ['TFWorkspaceClaim', 'GroupClaim'].includes(kind);
167669
+ }
167670
+
167671
+ ;// CONCATENATED MODULE: ../cdk8s_renderer/src/renderer/claims-sorter.ts
167672
+
167673
+ function sortKinds(orderedKinds, claims) {
167674
+ const result = [];
167675
+ for (const kind of orderedKinds) {
167676
+ const kindRenderClaims = sortRenderClaimsByKind(claims, [kind]);
167677
+ result.push(kindRenderClaims);
167678
+ }
167679
+ return result;
167680
+ }
167681
+
167024
167682
  ;// CONCATENATED MODULE: ../cdk8s_renderer/src/overriders/utils.ts
167025
167683
 
167026
167684
 
@@ -167071,14 +167729,12 @@ async function utils_renderFeature(featureName, featureVersion, featureOutputObj
167071
167729
 
167072
167730
 
167073
167731
 
167074
-
167075
-
167076
167732
  // this is the only way currently to make
167077
167733
  // work the system and inject our code
167078
167734
  // without having to download a feature
167079
- let MOCK_FEATURES_FN;
167735
+ let featureOverride_MOCK_FEATURES_FN;
167080
167736
  function MOCK_FEATURES(mock) {
167081
- MOCK_FEATURES_FN = mock;
167737
+ featureOverride_MOCK_FEATURES_FN = mock;
167082
167738
  if (mock) {
167083
167739
  log.warn('⚠️ Warning features system downloader has been mocked, it should only happen in unit testing');
167084
167740
  }
@@ -167109,8 +167765,8 @@ class FeaturesOverrider extends OverriderPatches {
167109
167765
  let owner = 'prefapp';
167110
167766
  let versionOrRef = this.featureVersion;
167111
167767
  let renderer = 'getFeatureConfig';
167112
- if (MOCK_FEATURES_FN) {
167113
- return MOCK_FEATURES_FN();
167768
+ if (featureOverride_MOCK_FEATURES_FN) {
167769
+ return featureOverride_MOCK_FEATURES_FN();
167114
167770
  }
167115
167771
  if (this.featureRepo) {
167116
167772
  [owner, repo] = this.featureRepo.split(/\//);
@@ -167128,8 +167784,8 @@ class FeaturesOverrider extends OverriderPatches {
167128
167784
  const featureName = this.featureName;
167129
167785
  const featureVersion = this.featureVersion || this.featureRef;
167130
167786
  const featureArgs = this.featureArgs;
167131
- const fSetUpAndRunRenderer = function (cr) {
167132
- return this.setUpAndRunRenderer(cr);
167787
+ const fSetUpAndRunRenderer = function (target) {
167788
+ return this.setUpAndRunRenderer(target);
167133
167789
  }.bind(this);
167134
167790
  let renderedFeatureConfig = null;
167135
167791
  return [
@@ -167138,7 +167794,7 @@ class FeaturesOverrider extends OverriderPatches {
167138
167794
  return true;
167139
167795
  },
167140
167796
  async apply(cr) {
167141
- renderedFeatureConfig = await fSetUpAndRunRenderer(cr);
167797
+ renderedFeatureConfig = await fSetUpAndRunRenderer(claim);
167142
167798
  return cr;
167143
167799
  },
167144
167800
  identify() {
@@ -167151,28 +167807,6 @@ class FeaturesOverrider extends OverriderPatches {
167151
167807
  return utils_renderFeature(featureName, featureVersion, renderedFeatureConfig, cr, claim.name);
167152
167808
  },
167153
167809
  },
167154
- {
167155
- isPostPatch: true,
167156
- validate() {
167157
- return true;
167158
- },
167159
- async apply(cr) {
167160
- if (!renderedFeatureConfig) {
167161
- logger.warn(`Feature ${featureName}: renderedFeatureConfig is null, skipping post-patch`);
167162
- return cr;
167163
- }
167164
- const provider = helperCTX(this).provider;
167165
- const jsonPatches = renderedFeatureConfig.patches?.[provider] || [];
167166
- fast_json_patch_default().applyPatch(cr, jsonPatches);
167167
- return cr;
167168
- },
167169
- identify() {
167170
- return `feature-json-patch/${featureName}`;
167171
- },
167172
- applicable() {
167173
- return { applicableProviders: ['catalog', 'github'] };
167174
- },
167175
- },
167176
167810
  ];
167177
167811
  }
167178
167812
  }
@@ -173087,6 +173721,7 @@ function walkArray(arr, symbolsToResolve, renderClaim) {
173087
173721
 
173088
173722
 
173089
173723
 
173724
+
173090
173725
  /*
173091
173726
  * Function called when rendering from the importer class.
173092
173727
  *
@@ -173129,11 +173764,19 @@ async function renderFromImports(rClaims, crs = {}, catalogOutputDir = '/tmp/.ca
173129
173764
  // after resolving imported refs, preventing setRenderedClaim() from throwing
173130
173765
  // 'already rendered' for claims that were previously seeded
173131
173766
  emptyRenderedClaims();
173132
- // after resolving the imported-refs, we need to validate the claims again, and apply the defaults if needed
173767
+ // After resolving the imported-refs, each claim goes through the same
173768
+ // defaults → stitching → AJV pipeline as loadClaim so feature claim-patches
173769
+ // are applied and validated at the import boundary too. Stitching is
173770
+ // once-only: already stitched claims are left untouched (no feature
173771
+ // re-download, no gates re-applied).
173133
173772
  for (const renderClaim of Object.values(rClaims)) {
173134
- if (defaults) {
173135
- renderClaim.claim = loader_patchClaim(renderClaim.claim, defaults);
173773
+ if (renderClaim.claim && renderClaim.claim[STITCHED_CLAIM]) {
173774
+ validateClaim(renderClaim.claim, `firestartr.dev://common/${renderClaim.claim.kind}`);
173775
+ continue;
173136
173776
  }
173777
+ const rawClaim = renderClaim.claim;
173778
+ const claim = defaults ? loader_patchClaim(rawClaim, defaults) : rawClaim;
173779
+ renderClaim.claim = await stitchClaim(claim, undefined, rawClaim);
173137
173780
  validateClaim(renderClaim.claim, `firestartr.dev://common/${renderClaim.claim.kind}`);
173138
173781
  }
173139
173782
  const catalogScope = new lib.App({
@@ -364197,7 +364840,7 @@ function helperCreateCheckRunName(cmd, item) {
364197
364840
 
364198
364841
  ;// CONCATENATED MODULE: ../operator/src/utils/index.ts
364199
364842
  const secretRegex = /\$\{\{ secrets\.(.*?) \}\}/g;
364200
- function isRecord(value) {
364843
+ function utils_isRecord(value) {
364201
364844
  return typeof value === 'object' && value !== null;
364202
364845
  }
364203
364846
  function getFirstNonEmptyString(...values) {
@@ -364235,7 +364878,7 @@ function replaceInlineSecrets(inline, secrets) {
364235
364878
  return result;
364236
364879
  }
364237
364880
  function extractErrorDetails(error) {
364238
- const exitCode = isRecord(error) && typeof error.exitCode === 'number'
364881
+ const exitCode = utils_isRecord(error) && typeof error.exitCode === 'number'
364239
364882
  ? error.exitCode
364240
364883
  : undefined;
364241
364884
  if (typeof error === 'string') {
@@ -364246,7 +364889,7 @@ function extractErrorDetails(error) {
364246
364889
  const output = getFirstNonEmptyString(errorWithOutput.output, error.message);
364247
364890
  return { output: output ?? String(error), exitCode };
364248
364891
  }
364249
- if (isRecord(error)) {
364892
+ if (utils_isRecord(error)) {
364250
364893
  const output = getFirstNonEmptyString(error.output, error.message, error.error);
364251
364894
  if (output !== undefined) {
364252
364895
  return { output, exitCode };
@@ -714628,7 +715271,7 @@ const crsStatusSubcommand = {
714628
715271
  };
714629
715272
 
714630
715273
  ;// CONCATENATED MODULE: ./package.json
714631
- const package_namespaceObject = JSON.parse('{"i8":"2.11.0-snapshot-mco-3"}');
715274
+ const package_namespaceObject = JSON.parse('{"i8":"2.11.0-snapshot-patch-claims-4"}');
714632
715275
  ;// CONCATENATED MODULE: ../../package.json
714633
715276
  const package_namespaceObject_1 = {"i8":"2.10.0"};
714634
715277
  // EXTERNAL MODULE: ../../node_modules/semver/index.js