@firestartr/cli 2.11.0-snapshot-import-filter-fix-2 → 2.11.0-snapshot-importer-filter-fix-3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -134117,6 +134117,7 @@ class GithubCheckRun {
134117
134117
  this.pullNumber = params.pullNumber;
134118
134118
  this.includeCheckRunComment = Boolean(params.includeCheckRunComment);
134119
134119
  this.checkRunComment = params.checkRunComment;
134120
+ this.stickyCommentBaseKind = params.stickyCommentBaseKind;
134120
134121
  this.buffer = new CheckRunBuffer('', (data) => this.__updateCheckRun(data).catch(() => { }), { intervalSec: FLUSH_TIMEOUT });
134121
134122
  }
134122
134123
  /**
@@ -134188,7 +134189,13 @@ class GithubCheckRun {
134188
134189
  text,
134189
134190
  },
134190
134191
  });
134191
- if (this.includeCheckRunComment && this.pullNumber !== undefined) {
134192
+ // With a shared sticky base kind, the result publisher targeting the
134193
+ // same base kind is always the last word: close() performs no sticky
134194
+ // rewrite (it could otherwise land after the result publish on error
134195
+ // paths and clobber it with a stale progress comment).
134196
+ if (this.includeCheckRunComment &&
134197
+ this.pullNumber !== undefined &&
134198
+ !this.stickyCommentBaseKind) {
134192
134199
  try {
134193
134200
  await this.__ensureAndUpdateStickyComment(this.__buildCheckRunUrl());
134194
134201
  this.hasCommented = true;
@@ -134253,7 +134260,14 @@ class GithubCheckRun {
134253
134260
  text,
134254
134261
  },
134255
134262
  });
134256
- if (this.includeCheckRunComment && this.pullNumber !== undefined) {
134263
+ // After the awaits above, close() may have begun. With a shared sticky
134264
+ // base kind the result publisher must be the last word, so an in-flight
134265
+ // progress upsert must not land after it. Legacy flows (no shared base
134266
+ // kind) keep their current behavior.
134267
+ const closedMidFlight = this.stickyCommentBaseKind && (this.closed || this.closing);
134268
+ if (this.includeCheckRunComment &&
134269
+ this.pullNumber !== undefined &&
134270
+ !closedMidFlight) {
134257
134271
  try {
134258
134272
  await this.__ensureAndUpdateStickyComment(this.__buildCheckRunUrl());
134259
134273
  }
@@ -134300,7 +134314,7 @@ class GithubCheckRun {
134300
134314
  owner: this.owner,
134301
134315
  repo: this.repo,
134302
134316
  pullNumber: this.pullNumber,
134303
- baseKind: `check-run:${this.name}`,
134317
+ baseKind: this.stickyCommentBaseKind ?? `check-run:${this.name}`,
134304
134318
  bodies: [linkLine],
134305
134319
  });
134306
134320
  }
@@ -134338,6 +134352,7 @@ async function createCheckRunForOrg(org, owner, repo, name, opts) {
134338
134352
  pullNumber: opts?.pullNumber,
134339
134353
  includeCheckRunComment: Boolean(opts?.includeCheckRunComment),
134340
134354
  checkRunComment: opts?.checkRunComment,
134355
+ stickyCommentBaseKind: opts?.stickyCommentBaseKind,
134341
134356
  });
134342
134357
  }
134343
134358
  async function createCheckRun(owner, repo, name, opts) {
@@ -134790,6 +134805,7 @@ function createFacade(profileName) {
134790
134805
  pullNumber: opts?.pullNumber,
134791
134806
  includeCheckRunComment: Boolean(opts?.includeCheckRunComment),
134792
134807
  checkRunComment: opts?.checkRunComment,
134808
+ stickyCommentBaseKind: opts?.stickyCommentBaseKind,
134793
134809
  });
134794
134810
  },
134795
134811
  CheckRun: CheckRun,
@@ -134943,6 +134959,100 @@ async function checkIfInstalledForOrg(org = 'default') {
134943
134959
  }
134944
134960
 
134945
134961
 
134962
+ /***/ }),
134963
+
134964
+ /***/ 16907:
134965
+ /***/ ((__unused_webpack_module, __webpack_exports__, __nccwpck_require__) => {
134966
+
134967
+ __nccwpck_require__.r(__webpack_exports__);
134968
+ /* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
134969
+ /* harmony export */ "initTfDebug": () => (/* binding */ initTfDebug),
134970
+ /* harmony export */ "writeConfig": () => (/* binding */ writeConfig),
134971
+ /* harmony export */ "writeTfOutput": () => (/* binding */ writeTfOutput)
134972
+ /* harmony export */ });
134973
+ /* harmony import */ var catalog_common__WEBPACK_IMPORTED_MODULE_0__ = __nccwpck_require__(78542);
134974
+ /* harmony import */ var fs_promises__WEBPACK_IMPORTED_MODULE_1__ = __nccwpck_require__(73292);
134975
+ /* harmony import */ var fs_promises__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__nccwpck_require__.n(fs_promises__WEBPACK_IMPORTED_MODULE_1__);
134976
+ /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __nccwpck_require__(71017);
134977
+ /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__nccwpck_require__.n(path__WEBPACK_IMPORTED_MODULE_2__);
134978
+ /* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_3__ = __nccwpck_require__(31986);
134979
+
134980
+
134981
+
134982
+
134983
+ const DEBUG_PREFIX = '/tmp/tf-debug/';
134984
+ async function initTfDebug(ctx) {
134985
+ try {
134986
+ const projectPath = ctx?.projectPath;
134987
+ if (!projectPath || !projectPath.startsWith(DEBUG_PREFIX))
134988
+ return;
134989
+ // Normalize projectPath by stripping a trailing UUID-like suffix from the
134990
+ // final path segment. This makes the debug folder deterministic even if
134991
+ // callers still supply a name with an embedded tfStateKey or uuid suffix.
134992
+ const dir = path__WEBPACK_IMPORTED_MODULE_2__.dirname(projectPath);
134993
+ const name = path__WEBPACK_IMPORTED_MODULE_2__.basename(projectPath);
134994
+ const baseName = name.replace(/-[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/, '');
134995
+ const normalizedProjectPath = path__WEBPACK_IMPORTED_MODULE_2__.join(dir, baseName);
134996
+ // Ensure the session project dir and a dedicated subdir for
134997
+ // terraform_provisioner exist. Do NOT remove an existing deterministic
134998
+ // debug folder here — removing it during build() breaks the reuse
134999
+ // validation when build() is invoked a second time for output().
135000
+ await fs_promises__WEBPACK_IMPORTED_MODULE_1__.mkdir(normalizedProjectPath, { recursive: true });
135001
+ const debugArtifactsDir = path__WEBPACK_IMPORTED_MODULE_2__.join(normalizedProjectPath, 'tf_provisioner_debug');
135002
+ await fs_promises__WEBPACK_IMPORTED_MODULE_1__.mkdir(debugArtifactsDir, { recursive: true });
135003
+ // Write cr.yaml and deps.yaml if provided on context
135004
+ if (ctx.rawCr) {
135005
+ await fs_promises__WEBPACK_IMPORTED_MODULE_1__.writeFile(path__WEBPACK_IMPORTED_MODULE_2__.join(debugArtifactsDir, 'cr.yaml'), catalog_common__WEBPACK_IMPORTED_MODULE_0__/* ["default"].io.toYaml */ .Z.io.toYaml(ctx.rawCr));
135006
+ }
135007
+ if (ctx.deps) {
135008
+ await fs_promises__WEBPACK_IMPORTED_MODULE_1__.writeFile(path__WEBPACK_IMPORTED_MODULE_2__.join(debugArtifactsDir, 'deps.yaml'), catalog_common__WEBPACK_IMPORTED_MODULE_0__/* ["default"].io.toYaml */ .Z.io.toYaml(ctx.deps));
135009
+ }
135010
+ // Enable file logging for debug runs
135011
+ _logger__WEBPACK_IMPORTED_MODULE_3__/* ["default"].enableFileLogging */ .Z.enableFileLogging(path__WEBPACK_IMPORTED_MODULE_2__.join(debugArtifactsDir, 'debug.log'));
135012
+ }
135013
+ catch (e) {
135014
+ _logger__WEBPACK_IMPORTED_MODULE_3__/* ["default"].warn */ .Z.warn(`[terraform-provisioner]: failed to init tf debug artifacts: ${e}`);
135015
+ }
135016
+ }
135017
+ async function writeTfOutput(projectPath, output) {
135018
+ try {
135019
+ if (!projectPath || !projectPath.startsWith(DEBUG_PREFIX))
135020
+ return;
135021
+ const debugArtifactsDir = path__WEBPACK_IMPORTED_MODULE_2__.join(projectPath, 'tf_provisioner_debug');
135022
+ await fs_promises__WEBPACK_IMPORTED_MODULE_1__.mkdir(debugArtifactsDir, { recursive: true });
135023
+ await fs_promises__WEBPACK_IMPORTED_MODULE_1__.writeFile(path__WEBPACK_IMPORTED_MODULE_2__.join(debugArtifactsDir, 'terraform-output.txt'), output);
135024
+ }
135025
+ catch (e) {
135026
+ _logger__WEBPACK_IMPORTED_MODULE_3__/* ["default"].warn */ .Z.warn(`[terraform-provisioner]: failed to write terraform output: ${e}`);
135027
+ }
135028
+ }
135029
+ async function writeConfig(projectPath, config) {
135030
+ try {
135031
+ if (!projectPath || !projectPath.startsWith(DEBUG_PREFIX))
135032
+ return;
135033
+ const debugArtifactsDir = path__WEBPACK_IMPORTED_MODULE_2__.join(projectPath, 'tf_provisioner_debug');
135034
+ await fs_promises__WEBPACK_IMPORTED_MODULE_1__.mkdir(debugArtifactsDir, { recursive: true });
135035
+ await fs_promises__WEBPACK_IMPORTED_MODULE_1__.writeFile(path__WEBPACK_IMPORTED_MODULE_2__.join(debugArtifactsDir, 'config.json'), JSON.stringify(config, null, 2));
135036
+ }
135037
+ catch (e) {
135038
+ _logger__WEBPACK_IMPORTED_MODULE_3__/* ["default"].warn */ .Z.warn(`[terraform-provisioner]: failed to write config.json: ${e}`);
135039
+ }
135040
+ }
135041
+
135042
+
135043
+ /***/ }),
135044
+
135045
+ /***/ 31986:
135046
+ /***/ ((__unused_webpack_module, __webpack_exports__, __nccwpck_require__) => {
135047
+
135048
+ /* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
135049
+ /* harmony export */ "Z": () => (__WEBPACK_DEFAULT_EXPORT__)
135050
+ /* harmony export */ });
135051
+ /* harmony import */ var catalog_common__WEBPACK_IMPORTED_MODULE_0__ = __nccwpck_require__(78542);
135052
+
135053
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (catalog_common__WEBPACK_IMPORTED_MODULE_0__/* ["default"].logger */ .Z.logger);
135054
+
135055
+
134946
135056
  /***/ }),
134947
135057
 
134948
135058
  /***/ 71421:
@@ -160443,6 +160553,13 @@ InitializerClaimRef.applicableKinds = [
160443
160553
  * and the value is the rendered CR
160444
160554
  */
160445
160555
  let renderedClaims = {};
160556
+ /**
160557
+ * previousClaimsSymbols holds previously rendered claims (from prior import
160558
+ * runs, e.g. the CRs already present on disk) keyed by claim kind and name.
160559
+ * It is only consulted as a fallback when a claim reference is not part of the
160560
+ * current render run but still exists as a previous CR.
160561
+ */
160562
+ let previousClaimsSymbols = {};
160446
160563
 
160447
160564
  function setRenderedClaim(claim, cr) {
160448
160565
  const claimKey = `${claim.kind}-${claim.name}`;
@@ -160452,8 +160569,12 @@ function setRenderedClaim(claim, cr) {
160452
160569
  }
160453
160570
  renderedClaims[claimKey] = cr;
160454
160571
  }
160572
+ function setPreviousClaimsSymbols(symbols) {
160573
+ previousClaimsSymbols = symbols ?? {};
160574
+ }
160455
160575
  function emptyRenderedClaims() {
160456
160576
  renderedClaims = {};
160577
+ previousClaimsSymbols = {};
160457
160578
  }
160458
160579
  /**
160459
160580
  * Resolves a claim reference
@@ -160466,9 +160587,13 @@ function resolveClaimRef(kind, name, symbolsTable = renderedClaims) {
160466
160587
  if (symbolsTable[`${kind}-${name}`]) {
160467
160588
  return symbolsTable[`${kind}-${name}`];
160468
160589
  }
160469
- else {
160470
- throw new Error(`Claim ${kind}-${name} not found`);
160590
+ if (symbolsTable === renderedClaims) {
160591
+ const previousCr = previousClaimsSymbols[`${kind}-${name}`];
160592
+ if (previousCr) {
160593
+ return previousCr;
160594
+ }
160471
160595
  }
160596
+ throw new Error(`Claim ${kind}-${name} not found`);
160472
160597
  }
160473
160598
 
160474
160599
  ;// CONCATENATED MODULE: ../cdk8s_renderer/src/utils/repositoryClaimUtils.ts
@@ -171316,19 +171441,18 @@ const ORG_ROLE_ANNOTATION = 'firestartr.backstage.dev/org-role';
171316
171441
  class CatalogUserChart extends BaseCatalogChart {
171317
171442
  template() {
171318
171443
  const claim = this.get('claim');
171319
- const explicitOrgRole = claim.annotations?.[ORG_ROLE_ANNOTATION];
171320
171444
  const inferredOrgRole = claim.providers &&
171321
171445
  typeof claim.providers === 'object' &&
171322
171446
  'github' in claim.providers &&
171323
171447
  claim.providers.github?.role === 'admin'
171324
171448
  ? 'owner'
171325
171449
  : undefined;
171326
- const orgRole = explicitOrgRole ?? inferredOrgRole;
171450
+ const { [ORG_ROLE_ANNOTATION]: _, ...claimAnnotations } = claim.annotations || {};
171327
171451
  const annotations = {
171328
- ...(claim.annotations || {}),
171452
+ ...claimAnnotations,
171329
171453
  };
171330
- if (orgRole) {
171331
- annotations[ORG_ROLE_ANNOTATION] = orgRole;
171454
+ if (inferredOrgRole) {
171455
+ annotations[ORG_ROLE_ANNOTATION] = inferredOrgRole;
171332
171456
  }
171333
171457
  return {
171334
171458
  apiVersion: 'backstage.io/v1alpha1',
@@ -172826,6 +172950,8 @@ function walkArray(arr, symbolsToResolve, renderClaim) {
172826
172950
 
172827
172951
 
172828
172952
 
172953
+
172954
+
172829
172955
  /*
172830
172956
  * Function called when rendering from the importer class.
172831
172957
  *
@@ -172849,8 +172975,9 @@ async function renderFromImports(rClaims, crs = {}, catalogOutputDir = '/tmp/.ca
172849
172975
  }
172850
172976
  // type: is the kind of the claim
172851
172977
  // value: is the imported-ref (the name in Github, can be with special characters, spaces, etc)
172978
+ const previousClaimsIndex = buildPreviousClaimsIndex(crs);
172852
172979
  const fSolver = (type, value) => {
172853
- return solver(type, value, rClaims);
172980
+ return solver(type, value, rClaims, previousClaimsIndex);
172854
172981
  };
172855
172982
  try {
172856
172983
  // we need to expand the imported-refs
@@ -172880,6 +173007,9 @@ async function renderFromImports(rClaims, crs = {}, catalogOutputDir = '/tmp/.ca
172880
173007
  outputFileExtension: '.yaml',
172881
173008
  yamlOutputType: lib.YamlOutputType.FILE_PER_RESOURCE,
172882
173009
  });
173010
+ // Claims skipped from this run (e.g. by fCheckCRExistsOnDisk) but still
173011
+ // present as previous CRs must be resolvable by charts that reference them.
173012
+ setPreviousClaimsSymbols(buildPreviousClaimsSymbols(crs));
172883
173013
  const result = await renderClaims(catalogScope, firestartrScope, { renderClaims: rClaims, crs, renames: [] });
172884
173014
  firestartrScope.synth();
172885
173015
  if (crOutputDir) {
@@ -172887,8 +173017,58 @@ async function renderFromImports(rClaims, crs = {}, catalogOutputDir = '/tmp/.ca
172887
173017
  }
172888
173018
  return result;
172889
173019
  }
172890
- async function solver(type, value, rClaims) {
172891
- // TODO: we need to receive the claims directory as a parameter, and read all the claims to find the one that matches the imported-ref
173020
+ function buildPreviousClaimsIndex(crs) {
173021
+ const index = {
173022
+ user: new Map(),
173023
+ group: new Map(),
173024
+ };
173025
+ for (const cr of Object.values(crs ?? {})) {
173026
+ const anyCr = cr;
173027
+ const kind = anyCr?.kind;
173028
+ const externalName = anyCr?.metadata?.annotations?.[catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('external-name')];
173029
+ const claimRef = anyCr?.metadata?.annotations?.[catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('claim-ref')];
173030
+ if (!kind || !externalName || !claimRef) {
173031
+ continue;
173032
+ }
173033
+ const claimName = claimRef.split('/')[1];
173034
+ if (!claimName) {
173035
+ continue;
173036
+ }
173037
+ if (kind === 'FirestartrGithubMembership') {
173038
+ index.user.set(externalName, claimName);
173039
+ }
173040
+ else if (kind === 'FirestartrGithubGroup') {
173041
+ index.group.set(externalName, claimName);
173042
+ }
173043
+ }
173044
+ return index;
173045
+ }
173046
+ function buildPreviousClaimsSymbols(crs) {
173047
+ const symbols = {};
173048
+ for (const cr of Object.values(crs ?? {})) {
173049
+ const anyCr = cr;
173050
+ const kind = anyCr?.kind;
173051
+ const claimRef = anyCr?.metadata?.annotations?.[catalog_common/* default.generic.getFirestartrAnnotation */.Z.generic.getFirestartrAnnotation('claim-ref')];
173052
+ if (!kind || !claimRef) {
173053
+ continue;
173054
+ }
173055
+ const claimName = claimRef.split('/')[1];
173056
+ if (!claimName) {
173057
+ continue;
173058
+ }
173059
+ const claimKind = kind === 'FirestartrGithubMembership'
173060
+ ? 'UserClaim'
173061
+ : kind === 'FirestartrGithubGroup'
173062
+ ? 'GroupClaim'
173063
+ : undefined;
173064
+ if (!claimKind) {
173065
+ continue;
173066
+ }
173067
+ symbols[`${claimKind}-${claimName}`] = anyCr;
173068
+ }
173069
+ return symbols;
173070
+ }
173071
+ async function solver(type, value, rClaims, previousClaimsIndex) {
172892
173072
  const claimKind = type === 'user' ? 'UserClaim' : 'GroupClaim';
172893
173073
  for (const key in rClaims) {
172894
173074
  if (key.startsWith(claimKind)) {
@@ -172898,6 +173078,12 @@ async function solver(type, value, rClaims) {
172898
173078
  }
172899
173079
  }
172900
173080
  }
173081
+ const previousClaimName = type === 'user'
173082
+ ? previousClaimsIndex.user.get(value)
173083
+ : previousClaimsIndex.group.get(value);
173084
+ if (previousClaimName) {
173085
+ return `${type}:${previousClaimName}`;
173086
+ }
172901
173087
  throw new Error(`Could not resolve imported-ref of type ${type} with value ${value}`);
172902
173088
  }
172903
173089
 
@@ -173409,23 +173595,25 @@ class CollectionMixins {
173409
173595
  async filter(kind, filters, elementList) {
173410
173596
  if (filters.length === 0)
173411
173597
  return elementList;
173412
- let filteredList = elementList;
173413
173598
  if (this.IS_FILTER_BY_NAME_SET(filters, kind)) {
173414
- filteredList = this.FILTER_BY_NAME_APPLY(filters, kind, (names) => filteredList.filter((el) => names.indexOf(el) !== -1));
173599
+ return this.FILTER_BY_NAME_APPLY(filters, kind, (names) => {
173600
+ const result = elementList.filter((el) => names.indexOf(el) !== -1);
173601
+ return result;
173602
+ });
173415
173603
  }
173416
- else if (this.IS_FILTER_BY_REGEXP_SET(filters, kind)) {
173417
- filteredList = this.FILTER_BY_REGEXP_APPLY(filters, kind, (nameRegExp) => {
173418
- return filteredList.filter((el) => nameRegExp.test(el));
173604
+ if (this.IS_FILTER_BY_REGEXP_SET(filters, kind)) {
173605
+ return this.FILTER_BY_REGEXP_APPLY(filters, kind, (nameRegExp) => {
173606
+ return elementList.filter((el) => nameRegExp.test(el));
173419
173607
  });
173420
173608
  }
173421
173609
  if (this.IS_FILTER_BY_FUNCTION_SET(filters, kind)) {
173422
- filteredList = await this.FILTER_BY_FUNCTION_APPLY(filters, kind, async (fn) => {
173423
- return (await Promise.all(filteredList.map(async (el) => {
173610
+ await this.FILTER_BY_FUNCTION_APPLY(filters, kind, async (fn) => {
173611
+ elementList = (await Promise.all(elementList.map(async (el) => {
173424
173612
  return (await fn(kind, el)) ? el : undefined;
173425
173613
  }))).filter((el) => el !== undefined);
173426
173614
  });
173427
173615
  }
173428
- return filteredList;
173616
+ return elementList;
173429
173617
  }
173430
173618
  }
173431
173619
 
@@ -360975,10 +361163,8 @@ class TFPlanItemVersion extends TFPlanItem {
360975
361163
  }
360976
361164
  }
360977
361165
 
360978
- ;// CONCATENATED MODULE: ../terraform_provisioner/src/logger.ts
360979
-
360980
- /* harmony default export */ const terraform_provisioner_src_logger = (catalog_common/* default.logger */.Z.logger);
360981
-
361166
+ // EXTERNAL MODULE: ../terraform_provisioner/src/logger.ts
361167
+ var terraform_provisioner_src_logger = __nccwpck_require__(31986);
360982
361168
  ;// CONCATENATED MODULE: ../terraform_provisioner/src/process_handler.ts
360983
361169
 
360984
361170
  const GRACE_PERIOD = 60 * 2; // 2 min
@@ -360996,7 +361182,7 @@ function processHandler(processToHandle, ctl, onTimedOut) {
360996
361182
  }
360997
361183
  }
360998
361184
  catch (error) {
360999
- terraform_provisioner_src_logger.error(`FATAL: timeout signal ${signal} could not be delivered to the process: ${error}`);
361185
+ terraform_provisioner_src_logger/* default.error */.Z.error(`FATAL: timeout signal ${signal} could not be delivered to the process: ${error}`);
361000
361186
  if (!callerNotified) {
361001
361187
  ctl.processKilled(false);
361002
361188
  callerNotified = true;
@@ -361008,15 +361194,15 @@ function processHandler(processToHandle, ctl, onTimedOut) {
361008
361194
  onTimedOut();
361009
361195
  timedOut = true;
361010
361196
  // send sigInt
361011
- terraform_provisioner_src_logger.error(`Terraform process has not exited after initial timeout of ${ctl.hardTimeout} seconds, sending SIGINT...`);
361197
+ terraform_provisioner_src_logger/* default.error */.Z.error(`Terraform process has not exited after initial timeout of ${ctl.hardTimeout} seconds, sending SIGINT...`);
361012
361198
  safeKill('SIGINT');
361013
361199
  // grace period
361014
361200
  gracefulResetId = setTimeout(() => {
361015
- terraform_provisioner_src_logger.error(`Terraform process has not exited after SIGINT grace period of ${GRACE_PERIOD} seconds (total elapsed ~${ctl.hardTimeout + GRACE_PERIOD} seconds), sending SIGTERM...`);
361201
+ terraform_provisioner_src_logger/* default.error */.Z.error(`Terraform process has not exited after SIGINT grace period of ${GRACE_PERIOD} seconds (total elapsed ~${ctl.hardTimeout + GRACE_PERIOD} seconds), sending SIGTERM...`);
361016
361202
  safeKill('SIGTERM');
361017
361203
  // hard reset period
361018
361204
  hardResetId = setTimeout(() => {
361019
- terraform_provisioner_src_logger.error(`Terraform process has not exited after SIGTERM hard reset period of ${HARD_RESET_PERIOD} seconds (total elapsed ~${ctl.hardTimeout + GRACE_PERIOD + HARD_RESET_PERIOD} seconds), sending SIGKILL...`);
361205
+ terraform_provisioner_src_logger/* default.error */.Z.error(`Terraform process has not exited after SIGTERM hard reset period of ${HARD_RESET_PERIOD} seconds (total elapsed ~${ctl.hardTimeout + GRACE_PERIOD + HARD_RESET_PERIOD} seconds), sending SIGKILL...`);
361020
361206
  safeKill('SIGKILL');
361021
361207
  setTimeout(() => {
361022
361208
  // we send if the process was killed or not to the caller
@@ -361379,7 +361565,7 @@ async function initFromModule(path, source, secrets, stream, ctl) {
361379
361565
  return tfExec(path, ['init', `-from-module=${source}`], secrets, [], stream, ctl);
361380
361566
  }
361381
361567
  async function plan(path, secrets, format, args = ['plan'], stream, ctl) {
361382
- terraform_provisioner_src_logger.info(`Running terraform plan with ${format} in path ${path}`);
361568
+ terraform_provisioner_src_logger/* default.info */.Z.info(`Running terraform plan with ${format} in path ${path}`);
361383
361569
  const plan = await tfExec(path, args.concat(format === 'json' ? ['-json'] : []), secrets, ['-input=false'], stream, ctl);
361384
361570
  if (format === 'json') {
361385
361571
  const tfPlan = planGet(plan);
@@ -361388,7 +361574,7 @@ async function plan(path, secrets, format, args = ['plan'], stream, ctl) {
361388
361574
  return plan;
361389
361575
  }
361390
361576
  async function apply(path, secrets, stream, ctl) {
361391
- terraform_provisioner_src_logger.debug(`Running terraform apply in path ${path}`);
361577
+ terraform_provisioner_src_logger/* default.debug */.Z.debug(`Running terraform apply in path ${path}`);
361392
361578
  let lastError;
361393
361579
  for (let attempt = 1; attempt <= MAX_APPLY_ATTEMPTS; attempt++) {
361394
361580
  try {
@@ -361398,11 +361584,11 @@ async function apply(path, secrets, stream, ctl) {
361398
361584
  lastError = error;
361399
361585
  if (isGitHubInconsistentApplyError(lastError)) {
361400
361586
  if (attempt < MAX_APPLY_ATTEMPTS) {
361401
- terraform_provisioner_src_logger.warn(`Transient GitHub provider apply error detected (attempt ${attempt} of ${MAX_APPLY_ATTEMPTS}); retrying after ${TRANSIENT_APPLY_RETRY_DELAY_MS}ms: ${GITHUB_INCONSISTENT_APPLY_SIGNATURE.join(', ')}`);
361587
+ terraform_provisioner_src_logger/* default.warn */.Z.warn(`Transient GitHub provider apply error detected (attempt ${attempt} of ${MAX_APPLY_ATTEMPTS}); retrying after ${TRANSIENT_APPLY_RETRY_DELAY_MS}ms: ${GITHUB_INCONSISTENT_APPLY_SIGNATURE.join(', ')}`);
361402
361588
  await catalog_common/* default.generic.sleep */.Z.generic.sleep(TRANSIENT_APPLY_RETRY_DELAY_MS);
361403
361589
  continue;
361404
361590
  }
361405
- terraform_provisioner_src_logger.warn(`Transient GitHub provider apply error persisted after ${MAX_APPLY_ATTEMPTS} attempts; giving up.`);
361591
+ terraform_provisioner_src_logger/* default.warn */.Z.warn(`Transient GitHub provider apply error persisted after ${MAX_APPLY_ATTEMPTS} attempts; giving up.`);
361406
361592
  }
361407
361593
  throw lastError;
361408
361594
  }
@@ -361410,15 +361596,15 @@ async function apply(path, secrets, stream, ctl) {
361410
361596
  throw lastError;
361411
361597
  }
361412
361598
  async function customCommand(path, secrets, args, stream) {
361413
- terraform_provisioner_src_logger.debug(`Running terraform customCommand in path ${path} ${args.join(',')}`);
361599
+ terraform_provisioner_src_logger/* default.debug */.Z.debug(`Running terraform customCommand in path ${path} ${args.join(',')}`);
361414
361600
  return await tfExec(path, args, secrets, [], stream);
361415
361601
  }
361416
361602
  async function destroy(path, secrets, stream, ctl) {
361417
- terraform_provisioner_src_logger.debug(`Running terraform destroy in path ${path}`);
361603
+ terraform_provisioner_src_logger/* default.debug */.Z.debug(`Running terraform destroy in path ${path}`);
361418
361604
  return await tfExec(path, ['destroy', '-auto-approve', TOFU_LOCK_TIMEOUT], secrets, ['-input=false'], stream, ctl);
361419
361605
  }
361420
361606
  async function output(path, secrets) {
361421
- terraform_provisioner_src_logger.debug(`Running terraform output in path ${path}`);
361607
+ terraform_provisioner_src_logger/* default.debug */.Z.debug(`Running terraform output in path ${path}`);
361422
361608
  return await tfExec(path, ['output', '-json'], secrets, []);
361423
361609
  }
361424
361610
  async function tfExec(path, args, secrets, extraArgs = ['-input=false'], stream, ctl) {
@@ -361476,7 +361662,7 @@ async function tfExec(path, args, secrets, extraArgs = ['-input=false'], stream,
361476
361662
  // this process has been killed/terminated
361477
361663
  // by timeout (not in our control)
361478
361664
  if (processTimeout) {
361479
- terraform_provisioner_src_logger.error(`Terraform output ${path}: ${[output, outputErrors].join('')}`);
361665
+ terraform_provisioner_src_logger/* default.error */.Z.error(`Terraform output ${path}: ${[output, outputErrors].join('')}`);
361480
361666
  ko(catalog_common/* default.generic.buildCommandExecutionError */.Z.generic.buildCommandExecutionError([output, outputErrors, '\n<PROCESS TIMEOUT>'].join(''), catalog_common/* default.generic.normalizeExitCode */.Z.generic.normalizeExitCode(code), args.concat(extraArgs), {
361481
361667
  errorName: 'TerraformCommandError',
361482
361668
  label: 'Terraform command',
@@ -361484,14 +361670,14 @@ async function tfExec(path, args, secrets, extraArgs = ['-input=false'], stream,
361484
361670
  return;
361485
361671
  }
361486
361672
  if (code !== 0) {
361487
- terraform_provisioner_src_logger.error(`Terraform output ${path}: ${[output, outputErrors].join('')}`);
361673
+ terraform_provisioner_src_logger/* default.error */.Z.error(`Terraform output ${path}: ${[output, outputErrors].join('')}`);
361488
361674
  ko(catalog_common/* default.generic.buildCommandExecutionError */.Z.generic.buildCommandExecutionError([output, outputErrors].join(''), catalog_common/* default.generic.normalizeExitCode */.Z.generic.normalizeExitCode(code), args.concat(extraArgs), {
361489
361675
  errorName: 'TerraformCommandError',
361490
361676
  label: 'Terraform command',
361491
361677
  }));
361492
361678
  }
361493
361679
  else {
361494
- terraform_provisioner_src_logger.info(`Terraform output ${path}: ${output}`);
361680
+ terraform_provisioner_src_logger/* default.info */.Z.info(`Terraform output ${path}: ${output}`);
361495
361681
  ok(output);
361496
361682
  }
361497
361683
  });
@@ -361629,6 +361815,62 @@ async function configGit() {
361629
361815
  external_fs_.writeFileSync(gitconfigPath, `[url "https://firestartr:${ghToken}@github.com"]\ninsteadOf = https://github.com\n`);
361630
361816
  }
361631
361817
 
361818
+ ;// CONCATENATED MODULE: ../terraform_provisioner/src/writer_additional_files.ts
361819
+
361820
+
361821
+
361822
+ class WriterAdditionalFiles extends writer {
361823
+ constructor(files) {
361824
+ super();
361825
+ this.files = files;
361826
+ }
361827
+ // This writer complies with the abstract Writer class but does not render content in the traditional sense.
361828
+ async _render() {
361829
+ return '';
361830
+ }
361831
+ async writeToTerraformProject(projectPath) {
361832
+ for (const file of this.files) {
361833
+ try {
361834
+ const targetPath = external_path_.resolve(projectPath, file.path);
361835
+ const absProjectPath = external_path_.resolve(projectPath);
361836
+ if (!targetPath.startsWith(absProjectPath + external_path_.sep)) {
361837
+ throw new Error(`Path traversal detected: ${file.path}`);
361838
+ }
361839
+ await promises_.mkdir(external_path_.dirname(targetPath), { recursive: true });
361840
+ await promises_.writeFile(targetPath, Buffer.from(file.content, 'base64').toString('utf8'));
361841
+ }
361842
+ catch (err) {
361843
+ throw new Error(`Error writing additional file: ${file.path}: ${err}`);
361844
+ }
361845
+ }
361846
+ }
361847
+ }
361848
+
361849
+ ;// CONCATENATED MODULE: ../terraform_provisioner/src/writer_imports.ts
361850
+
361851
+ class WriterImports extends writer {
361852
+ constructor(config) {
361853
+ super();
361854
+ this.config = config;
361855
+ }
361856
+ async _render() {
361857
+ let importBlocks = '';
361858
+ for (const importBlock of this.config.imports) {
361859
+ importBlocks += `
361860
+
361861
+ import {
361862
+
361863
+ to = ${importBlock.to}
361864
+
361865
+ id = "${importBlock.id}"
361866
+ }
361867
+
361868
+ `;
361869
+ }
361870
+ this.output = importBlocks;
361871
+ }
361872
+ }
361873
+
361632
361874
  ;// CONCATENATED MODULE: ../terraform_provisioner/src/writer_main_tf.ts
361633
361875
 
361634
361876
 
@@ -361651,6 +361893,31 @@ ${this.mainBlock}
361651
361893
  }
361652
361894
  }
361653
361895
 
361896
+ ;// CONCATENATED MODULE: ../terraform_provisioner/src/writer_provider_tf_json.ts
361897
+
361898
+
361899
+
361900
+ class WriterProviderJson extends writer {
361901
+ constructor(mainBlock, providers, backend, tfStateKey) {
361902
+ super();
361903
+ this.mainBlock = mainBlock;
361904
+ this.providers = providers;
361905
+ this.backend = backend;
361906
+ this.tfStateKey = tfStateKey;
361907
+ }
361908
+ async _render() {
361909
+ this.output = await new WriterTerraform(this.providers, this.backend, this.tfStateKey, false).render('json');
361910
+ }
361911
+ writeToTerraformProject(mainTfPath) {
361912
+ if (this.output.trim() === '') {
361913
+ terraform_provisioner_src_logger/* default.info */.Z.info(`Skipping writing ${mainTfPath} as there is no provider to write.`);
361914
+ }
361915
+ else {
361916
+ super.writeToTerraformProject(mainTfPath);
361917
+ }
361918
+ }
361919
+ }
361920
+
361654
361921
  ;// CONCATENATED MODULE: ../terraform_provisioner/src/resolutor/resolver.ts
361655
361922
 
361656
361923
  const REG_IS_CLAIM_SECRET_REF = new RegExp(/^secret-ref-\d+$/);
@@ -361710,7 +361977,7 @@ function getRefNameFromKey(key) {
361710
361977
  function resolveClaimSecret(value, refs) {
361711
361978
  if (typeof value === 'string' && REG_IS_CLAIM_SECRET_REF.test(value)) {
361712
361979
  if (!Object.prototype.hasOwnProperty.call(refs, value)) {
361713
- terraform_provisioner_src_logger.error(`SecretsClaim ref ${value} is not present on references`);
361980
+ terraform_provisioner_src_logger/* default.error */.Z.error(`SecretsClaim ref ${value} is not present on references`);
361714
361981
  throw new Error(`SecretsClaim ref ${value} is not present on references`);
361715
361982
  }
361716
361983
  return refs[value];
@@ -361806,87 +362073,6 @@ function fCheckString(keys, refs) {
361806
362073
  return true;
361807
362074
  }
361808
362075
 
361809
- ;// CONCATENATED MODULE: ../terraform_provisioner/src/writer_provider_tf_json.ts
361810
-
361811
-
361812
-
361813
- class WriterProviderJson extends writer {
361814
- constructor(mainBlock, providers, backend, tfStateKey) {
361815
- super();
361816
- this.mainBlock = mainBlock;
361817
- this.providers = providers;
361818
- this.backend = backend;
361819
- this.tfStateKey = tfStateKey;
361820
- }
361821
- async _render() {
361822
- this.output = await new WriterTerraform(this.providers, this.backend, this.tfStateKey, false).render('json');
361823
- }
361824
- writeToTerraformProject(mainTfPath) {
361825
- if (this.output.trim() === '') {
361826
- terraform_provisioner_src_logger.info(`Skipping writing ${mainTfPath} as there is no provider to write.`);
361827
- }
361828
- else {
361829
- super.writeToTerraformProject(mainTfPath);
361830
- }
361831
- }
361832
- }
361833
-
361834
- ;// CONCATENATED MODULE: ../terraform_provisioner/src/writer_additional_files.ts
361835
-
361836
-
361837
-
361838
- class WriterAdditionalFiles extends writer {
361839
- constructor(files) {
361840
- super();
361841
- this.files = files;
361842
- }
361843
- // This writer complies with the abstract Writer class but does not render content in the traditional sense.
361844
- async _render() {
361845
- return '';
361846
- }
361847
- async writeToTerraformProject(projectPath) {
361848
- for (const file of this.files) {
361849
- try {
361850
- const targetPath = external_path_.resolve(projectPath, file.path);
361851
- const absProjectPath = external_path_.resolve(projectPath);
361852
- if (!targetPath.startsWith(absProjectPath + external_path_.sep)) {
361853
- throw new Error(`Path traversal detected: ${file.path}`);
361854
- }
361855
- await promises_.mkdir(external_path_.dirname(targetPath), { recursive: true });
361856
- await promises_.writeFile(targetPath, Buffer.from(file.content, 'base64').toString('utf8'));
361857
- }
361858
- catch (err) {
361859
- throw new Error(`Error writing additional file: ${file.path}: ${err}`);
361860
- }
361861
- }
361862
- }
361863
- }
361864
-
361865
- ;// CONCATENATED MODULE: ../terraform_provisioner/src/writer_imports.ts
361866
-
361867
- class WriterImports extends writer {
361868
- constructor(config) {
361869
- super();
361870
- this.config = config;
361871
- }
361872
- async _render() {
361873
- let importBlocks = '';
361874
- for (const importBlock of this.config.imports) {
361875
- importBlocks += `
361876
-
361877
- import {
361878
-
361879
- to = ${importBlock.to}
361880
-
361881
- id = "${importBlock.id}"
361882
- }
361883
-
361884
- `;
361885
- }
361886
- this.output = importBlocks;
361887
- }
361888
- }
361889
-
361890
362076
  // EXTERNAL MODULE: external "stream"
361891
362077
  var external_stream_ = __nccwpck_require__(12781);
361892
362078
  ;// CONCATENATED MODULE: ../terraform_provisioner/src/project_tf.ts
@@ -361907,10 +362093,14 @@ class project_tf_TFProjectManager {
361907
362093
  ? external_path_.resolve(this.projectPath)
361908
362094
  : '';
361909
362095
  // Remove the entire workspace directory
362096
+ // Never delete debug workspaces. Support both gh-debug (existing) and
362097
+ // the new tf-debug workspace prefix.
361910
362098
  if (resolvedProjectPath &&
361911
- resolvedProjectPath.startsWith('/tmp/gh-debug/')) {
362099
+ (resolvedProjectPath.startsWith('/tmp/gh-debug/') ||
362100
+ resolvedProjectPath.startsWith('/tmp/tf-debug/') ||
362101
+ process.env.FIRESTARTR_DEBUG === 'true')) {
361912
362102
  // Never delete debug workspaces, per spec.
361913
- terraform_provisioner_src_logger.info(`[terraform-provisioner]: SKIP teardown for debug workspace at ${this.projectPath}`);
362103
+ terraform_provisioner_src_logger/* default.info */.Z.info(`[terraform-provisioner]: SKIP teardown for debug workspace at ${this.projectPath}`);
361914
362104
  return;
361915
362105
  }
361916
362106
  if (resolvedProjectPath &&
@@ -361921,7 +362111,7 @@ class project_tf_TFProjectManager {
361921
362111
  recursive: true,
361922
362112
  force: true,
361923
362113
  });
361924
- terraform_provisioner_src_logger.info(`[terraform-provisioner]: Workspace at ${resolvedProjectPath} torn up successfully`);
362114
+ terraform_provisioner_src_logger/* default.info */.Z.info(`[terraform-provisioner]: Workspace at ${resolvedProjectPath} torn up successfully`);
361925
362115
  }
361926
362116
  catch (e) {
361927
362117
  throw new Error(`[terraform-provisioner]: Failed to tear up local project at ${this.projectPath}: ${e}`);
@@ -361937,7 +362127,81 @@ class project_tf_TFProjectManager {
361937
362127
  this.onImport = false;
361938
362128
  this.onImport = !!ctx.importMode;
361939
362129
  this.ctx = ctx;
361940
- this.projectPath = ctx.projectPath;
362130
+ // Normalize incoming debug project paths so the provisioner tolerates both
362131
+ // old (suffixed) and new (stripped) naming. If ctx.projectPath points to a
362132
+ // /tmp/tf-debug path, strip a trailing UUID-like suffix from the final
362133
+ // segment so reuse checks look at the deterministic folder.
362134
+ const incomingPath = ctx.projectPath;
362135
+ if (typeof incomingPath === 'string' &&
362136
+ incomingPath.startsWith('/tmp/tf-debug/')) {
362137
+ const dir = external_path_.dirname(incomingPath);
362138
+ const name = external_path_.basename(incomingPath);
362139
+ // If the incoming debug folder includes a tfStateKey suffix, preserve
362140
+ // it when normalizing. We expect the operator to set projectPath to
362141
+ // `/tmp/tf-debug/<kind>-<baseName>-<tfStateKey>` when tfStateKey is
362142
+ // available. Strip only a trailing UUID-like suffix if present.
362143
+ const baseName = name.replace(/-[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/, '');
362144
+ const normalized = external_path_.join(dir, baseName);
362145
+ // If the deterministic folder exists, use it. If not, but there is an
362146
+ // existing legacy suffixed folder, fall back to that so we remain
362147
+ // tolerant of older operators that still write suffixed debug folders.
362148
+ if (external_fs_.existsSync(normalized)) {
362149
+ this.projectPath = normalized;
362150
+ }
362151
+ else {
362152
+ try {
362153
+ const entries = external_fs_.readdirSync(dir, { withFileTypes: true });
362154
+ const escapedBaseName = baseName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
362155
+ const legacyDirRegex = new RegExp(`^${escapedBaseName}-[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$`);
362156
+ const candidate = entries
362157
+ .filter((e) => e.isDirectory())
362158
+ .map((e) => e.name)
362159
+ .find((n) => legacyDirRegex.test(n));
362160
+ if (candidate) {
362161
+ // Prefer using the deterministic normalized path even if a
362162
+ // legacy suffixed candidate exists. Try to atomically rename the
362163
+ // legacy folder to the normalized name so subsequent runs use
362164
+ // a single, stable location. If rename fails, fall back to the
362165
+ // legacy candidate to avoid breaking execution.
362166
+ const candidatePath = external_path_.join(dir, candidate);
362167
+ try {
362168
+ external_fs_.renameSync(candidatePath, normalized);
362169
+ this.projectPath = normalized;
362170
+ }
362171
+ catch (renameErr) {
362172
+ // Renaming may fail (permissions, cross-fs). Fall back to
362173
+ // legacy candidate to preserve behavior.
362174
+ terraform_provisioner_src_logger/* default.warn */.Z.warn(`[terraform-provisioner]: failed to rename legacy debug folder ${candidatePath} -> ${normalized}: ${renameErr}`);
362175
+ this.projectPath = candidatePath;
362176
+ }
362177
+ }
362178
+ else {
362179
+ this.projectPath = normalized;
362180
+ }
362181
+ }
362182
+ catch (e) {
362183
+ // If reading the directory fails for any reason, fall back to the
362184
+ // normalized path — this keeps behavior deterministic and avoids
362185
+ // throwing from the constructor.
362186
+ this.projectPath = normalized;
362187
+ }
362188
+ }
362189
+ }
362190
+ else {
362191
+ this.projectPath = ctx.projectPath;
362192
+ }
362193
+ // Ensure ctx.projectPath matches the resolved projectPath so subsequent
362194
+ // debug initialization (which reads ctx.projectPath) operates on the
362195
+ // same directory the project managers will write to. This prevents a
362196
+ // timing mismatch where debug.init creates the deterministic folder but
362197
+ // the project manager writes into a different (suffixed) folder.
362198
+ try {
362199
+ if (this.ctx && typeof this.ctx === 'object')
362200
+ this.ctx.projectPath = this.projectPath;
362201
+ }
362202
+ catch (e) {
362203
+ // Non-fatal: keep behavior deterministic even if we cannot mutate ctx
362204
+ }
361941
362205
  this.mainTfWriter = new WriterMainTf(ctx.inline, ctx.requiredProviders, ctx.backend, ctx.tfStateKey);
361942
362206
  this.providerJsonWriter = new WriterProviderJson(ctx.inline, ctx.requiredProviders, ctx.backend, ctx.tfStateKey);
361943
362207
  this.tfVarsJsonWriter = new WriterTfVarsJson(ctx.values, ctx.references);
@@ -361965,14 +362229,41 @@ class project_tf_TFProjectManager {
361965
362229
  this.stream.on('end', fnEnd);
361966
362230
  }
361967
362231
  async build() {
362232
+ // If this context indicates a debug workspace, initialize debug artifacts
362233
+ // early so files like cr.yaml/deps.yaml are present before build steps.
362234
+ try {
362235
+ terraform_provisioner_src_logger/* default.debug */.Z.debug(`[terraform-provisioner]: build() start - ctx.projectPath=${this.ctx?.projectPath} projectPath=${this.projectPath}`);
362236
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
362237
+ const debug = __nccwpck_require__(16907);
362238
+ await debug.initTfDebug(this.ctx);
362239
+ terraform_provisioner_src_logger/* default.debug */.Z.debug(`[terraform-provisioner]: build() after initTfDebug - ctx.projectPath=${this.ctx?.projectPath} projectPath=${this.projectPath}`);
362240
+ }
362241
+ catch (e) {
362242
+ // Best-effort; failures here should not block normal execution but
362243
+ // emit a warning so operators know why debug artifacts may be absent.
362244
+ terraform_provisioner_src_logger/* default.warn */.Z.warn(`[terraform-provisioner]: failed to init tf debug artifacts: ${e?.message ?? e}`);
362245
+ }
361968
362246
  if (this.ctx?.reuseExistingProject) {
361969
362247
  if (!external_fs_.existsSync(this.projectPath)) {
361970
362248
  throw new Error(`[terraform-provisioner]: Workspace reuse requested but projectPath does not exist: ${this.projectPath}. Cannot continue.`);
361971
362249
  }
362250
+ try {
362251
+ const entries = external_fs_.readdirSync(this.projectPath);
362252
+ // Directory listing may contain user-supplied filenames; keep at debug level
362253
+ // to avoid leaking sensitive names in normal info logs.
362254
+ terraform_provisioner_src_logger/* default.debug */.Z.debug(`[terraform-provisioner]: reuse check - projectPath contents: ${JSON.stringify(entries)}`);
362255
+ }
362256
+ catch (e) {
362257
+ terraform_provisioner_src_logger/* default.warn */.Z.warn(`[terraform-provisioner]: failed to read projectPath ${this.projectPath}: ${e}`);
362258
+ }
361972
362259
  const expectedFiles = await computeInlineWorkspaceFiles(this.ctx);
362260
+ // expectedFiles may include user-supplied paths; log at debug level only.
362261
+ terraform_provisioner_src_logger/* default.debug */.Z.debug(`[terraform-provisioner]: reuse check - expected files: ${JSON.stringify(expectedFiles)}`);
361973
362262
  const missing = validateWorkspaceStructure(this.projectPath, expectedFiles);
362263
+ // Missing files may reveal internal filenames; keep at debug level.
362264
+ terraform_provisioner_src_logger/* default.debug */.Z.debug(`[terraform-provisioner]: reuse check - missing files: ${JSON.stringify(missing)}`);
361974
362265
  if (missing.length === 0) {
361975
- terraform_provisioner_src_logger.info(`[terraform-provisioner]: Reusing existing Inline workspace at ${this.projectPath}`);
362266
+ terraform_provisioner_src_logger/* default.info */.Z.info(`[terraform-provisioner]: Reusing existing Inline workspace at ${this.projectPath}`);
361976
362267
  // imports.tf is command-scoped: always (re)generate it for import commands after reuse validation.
361977
362268
  if (this.onImport) {
361978
362269
  const writerImports = new WriterImports(this.customArgs);
@@ -361985,7 +362276,7 @@ class project_tf_TFProjectManager {
361985
362276
  }
361986
362277
  throw new Error(`[terraform-provisioner]: Workspace reuse requested but missing required files: ${missing.join(', ')}. Cannot continue.`);
361987
362278
  }
361988
- terraform_provisioner_src_logger.info(`[terraform-provisioner]: Creating new Inline workspace at ${this.projectPath}`);
362279
+ terraform_provisioner_src_logger/* default.info */.Z.info(`[terraform-provisioner]: Creating new Inline workspace at ${this.projectPath}`);
361989
362280
  await this.mainTfWriter.render();
361990
362281
  this.mainTfWriter.writeToTerraformProject(external_path_.join(this.projectPath, 'firestartr-main.tf'));
361991
362282
  await this.providerJsonWriter.render();
@@ -362056,13 +362347,13 @@ class project_tf_TFProjectManager {
362056
362347
  const addressesList = (await customCommand(this.projectPath, this.secrets, ['state', 'list'], this.stream))
362057
362348
  .split(/\n/)
362058
362349
  .filter((line) => line.replace(/\n|\s/g, ''));
362059
- terraform_provisioner_src_logger.info(`[terraform-provisioner]: destroyStateOnly: Obtained the addresses of the resources ${addressesList.join(',')}`);
362350
+ terraform_provisioner_src_logger/* default.info */.Z.info(`[terraform-provisioner]: destroyStateOnly: Obtained the addresses of the resources ${addressesList.join(',')}`);
362060
362351
  if (addressesList.length > 0) {
362061
362352
  await customCommand(this.projectPath, this.secrets, ['state', 'rm'].concat(addressesList), this.stream);
362062
- terraform_provisioner_src_logger.info(`[terraform-provisioner]: destroyStateOnly: deleted from the state the following addresses ${addressesList.join(',')}`);
362353
+ terraform_provisioner_src_logger/* default.info */.Z.info(`[terraform-provisioner]: destroyStateOnly: deleted from the state the following addresses ${addressesList.join(',')}`);
362063
362354
  }
362064
362355
  else {
362065
- terraform_provisioner_src_logger.info('[terraform-provisioner]: destroyStateOnly: warning the state is already empty, no destroy has taken place');
362356
+ terraform_provisioner_src_logger/* default.info */.Z.info('[terraform-provisioner]: destroyStateOnly: warning the state is already empty, no destroy has taken place');
362066
362357
  }
362067
362358
  if (this.stream)
362068
362359
  this.stream.end();
@@ -362112,7 +362403,7 @@ async function initializeMirrors(repos = [...DEFAULT_MIRROR_WARMUP_LIST]) {
362112
362403
  await onError(err);
362113
362404
  }
362114
362405
  else {
362115
- terraform_provisioner_src_logger.error('[mirror] Refresher beforeRefresh error:', err);
362406
+ terraform_provisioner_src_logger/* default.error */.Z.error('[mirror] Refresher beforeRefresh error:', err);
362116
362407
  }
362117
362408
  return; // skip this tick if beforeRefresh fails
362118
362409
  }
@@ -362131,7 +362422,7 @@ async function initializeMirrors(repos = [...DEFAULT_MIRROR_WARMUP_LIST]) {
362131
362422
  await onError(err);
362132
362423
  }
362133
362424
  else {
362134
- terraform_provisioner_src_logger.error('[mirror] Refresher error:', err);
362425
+ terraform_provisioner_src_logger/* default.error */.Z.error('[mirror] Refresher error:', err);
362135
362426
  }
362136
362427
  }
362137
362428
  }
@@ -362335,7 +362626,7 @@ async function installMirrorForRepo(remoteUrl) {
362335
362626
  const headPath = external_path_default().join(mirrorPath, 'HEAD');
362336
362627
  await external_fs_promises_default().access(configPath);
362337
362628
  await external_fs_promises_default().access(headPath);
362338
- terraform_provisioner_src_logger.info(`[mirror] Mirror exists at ${mirrorPath}, refreshing...`);
362629
+ terraform_provisioner_src_logger/* default.info */.Z.info(`[mirror] Mirror exists at ${mirrorPath}, refreshing...`);
362339
362630
  await refreshMirror(mirrorPath);
362340
362631
  }
362341
362632
  catch (e) {
@@ -362345,7 +362636,7 @@ async function installMirrorForRepo(remoteUrl) {
362345
362636
  else if (stat === null) {
362346
362637
  try {
362347
362638
  await external_fs_promises_default().mkdir(external_path_default().posix.dirname(mirrorPath), { recursive: true });
362348
- terraform_provisioner_src_logger.info(`[mirror] Cloning bare mirror from ${repoUrl} to ${mirrorPath}`);
362639
+ terraform_provisioner_src_logger/* default.info */.Z.info(`[mirror] Cloning bare mirror from ${repoUrl} to ${mirrorPath}`);
362349
362640
  await gitCloneMirror(repoUrl, mirrorPath);
362350
362641
  }
362351
362642
  catch (e) {
@@ -362431,7 +362722,7 @@ async function refreshMirror(mirrorPath) {
362431
362722
  }
362432
362723
  // Run the actual refresher, which throws on failure
362433
362724
  await gitFetchPrune(mirrorPath);
362434
- terraform_provisioner_src_logger.debug(`[mirror] Mirror at ${mirrorPath} was successfully refreshed`);
362725
+ terraform_provisioner_src_logger/* default.debug */.Z.debug(`[mirror] Mirror at ${mirrorPath} was successfully refreshed`);
362435
362726
  }
362436
362727
  // --- Spec 002-mirror-tfm-usage: Warmup support ---
362437
362728
 
@@ -362486,7 +362777,7 @@ async function resolveMirroredModuleSource(source) {
362486
362777
  return translateModuleSource(source);
362487
362778
  }
362488
362779
  catch (e) {
362489
- terraform_provisioner_src_logger.warn(`[mirror] Could not mirror ${repoUrl}; failing provisioning. Reason: ${e.message}`);
362780
+ terraform_provisioner_src_logger/* default.warn */.Z.warn(`[mirror] Could not mirror ${repoUrl}; failing provisioning. Reason: ${e.message}`);
362490
362781
  throw e;
362491
362782
  }
362492
362783
  }
@@ -362602,10 +362893,14 @@ class TFProjectManagerRemote {
362602
362893
  ? external_path_.resolve(this.projectPath)
362603
362894
  : '';
362604
362895
  // Remove the entire workspace directory
362896
+ // Never delete debug workspaces. Support both gh-debug (existing) and
362897
+ // the new tf-debug workspace prefix.
362605
362898
  if (resolvedProjectPath &&
362606
- resolvedProjectPath.startsWith('/tmp/gh-debug/')) {
362899
+ (resolvedProjectPath.startsWith('/tmp/gh-debug/') ||
362900
+ resolvedProjectPath.startsWith('/tmp/tf-debug/') ||
362901
+ process.env.FIRESTARTR_DEBUG === 'true')) {
362607
362902
  // Never delete debug workspaces, per spec.
362608
- terraform_provisioner_src_logger.info(`[terraform-provisioner]: SKIP teardown for debug workspace at ${this.projectPath}`);
362903
+ terraform_provisioner_src_logger/* default.info */.Z.info(`[terraform-provisioner]: SKIP teardown for debug workspace at ${this.projectPath}`);
362609
362904
  return;
362610
362905
  }
362611
362906
  if (resolvedProjectPath &&
@@ -362616,7 +362911,7 @@ class TFProjectManagerRemote {
362616
362911
  recursive: true,
362617
362912
  force: true,
362618
362913
  });
362619
- terraform_provisioner_src_logger.info(`[terraform-provisioner]: Workspace at ${resolvedProjectPath} torn up successfully`);
362914
+ terraform_provisioner_src_logger/* default.info */.Z.info(`[terraform-provisioner]: Workspace at ${resolvedProjectPath} torn up successfully`);
362620
362915
  }
362621
362916
  catch (e) {
362622
362917
  throw new Error(`[terraform-provisioner]: Failed to tear up local project at ${this.projectPath}: ${e}`);
@@ -362663,6 +362958,18 @@ class TFProjectManagerRemote {
362663
362958
  this.stream.on('end', fnEnd);
362664
362959
  }
362665
362960
  async build() {
362961
+ // If this context indicates a debug workspace, initialize debug artifacts
362962
+ // early so files like cr.yaml/deps.yaml are present before build steps.
362963
+ try {
362964
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
362965
+ const debug = __nccwpck_require__(16907);
362966
+ await debug.initTfDebug(this.ctx);
362967
+ }
362968
+ catch (e) {
362969
+ // Best-effort; failures here should not block normal execution but
362970
+ // emit a warning so operators know why debug artifacts may be absent.
362971
+ terraform_provisioner_src_logger/* default.warn */.Z.warn(`[terraform-provisioner]: failed to init tf debug artifacts: ${e?.message ?? e}`);
362972
+ }
362666
362973
  // Workspace reuse block for remote
362667
362974
  if (this.ctx?.reuseExistingProject) {
362668
362975
  if (!external_fs_.existsSync(this.projectPath)) {
@@ -362671,7 +362978,7 @@ class TFProjectManagerRemote {
362671
362978
  const expectedFiles = await computeRemoteWorkspaceFiles(this.ctx);
362672
362979
  const missing = validateWorkspaceStructure(this.projectPath, expectedFiles);
362673
362980
  if (missing.length === 0) {
362674
- terraform_provisioner_src_logger.info(`[terraform-provisioner]: Reusing existing Remote workspace at ${this.projectPath}`);
362981
+ terraform_provisioner_src_logger/* default.info */.Z.info(`[terraform-provisioner]: Reusing existing Remote workspace at ${this.projectPath}`);
362675
362982
  // imports.tf is command-scoped: always (re)generate it for import commands after reuse validation.
362676
362983
  if (this.onImport) {
362677
362984
  const writerImports = new WriterImports(this.customArgs);
@@ -362684,7 +362991,7 @@ class TFProjectManagerRemote {
362684
362991
  }
362685
362992
  throw new Error(`[terraform-provisioner]: Workspace reuse requested but missing required files: ${missing.join(', ')}. Cannot continue.`);
362686
362993
  }
362687
- terraform_provisioner_src_logger.info(`[terraform-provisioner]: Creating new Remote workspace at ${this.projectPath}`);
362994
+ terraform_provisioner_src_logger/* default.info */.Z.info(`[terraform-provisioner]: Creating new Remote workspace at ${this.projectPath}`);
362688
362995
  external_fs_.rmSync(this.projectPath, { recursive: true, force: true });
362689
362996
  await configGit();
362690
362997
  await this.__initFromModule();
@@ -362761,13 +363068,13 @@ class TFProjectManagerRemote {
362761
363068
  const addressesList = (await customCommand(this.projectPath, this.secrets, ['state', 'list'], this.stream))
362762
363069
  .split(/\n/)
362763
363070
  .filter((line) => line.replace(/\n|\s/g, ''));
362764
- terraform_provisioner_src_logger.info(`[terraform-provisioner]: destroyStateOnly: Obtained the addresses of the resources ${addressesList.join(',')}`);
363071
+ terraform_provisioner_src_logger/* default.info */.Z.info(`[terraform-provisioner]: destroyStateOnly: Obtained the addresses of the resources ${addressesList.join(',')}`);
362765
363072
  if (addressesList.length > 0) {
362766
363073
  await customCommand(this.projectPath, this.secrets, ['state', 'rm'].concat(addressesList), this.stream);
362767
- terraform_provisioner_src_logger.info(`[terraform-provisioner]: destroyStateOnly: deleted from the state the following addresses ${addressesList.join(',')}`);
363074
+ terraform_provisioner_src_logger/* default.info */.Z.info(`[terraform-provisioner]: destroyStateOnly: deleted from the state the following addresses ${addressesList.join(',')}`);
362768
363075
  }
362769
363076
  else {
362770
- terraform_provisioner_src_logger.info('[terraform-provisioner]: destroyStateOnly: warning the state is already empty, no destroy has taken place');
363077
+ terraform_provisioner_src_logger/* default.info */.Z.info('[terraform-provisioner]: destroyStateOnly: warning the state is already empty, no destroy has taken place');
362771
363078
  }
362772
363079
  if (this.stream)
362773
363080
  this.stream.end();
@@ -362840,7 +363147,7 @@ async function run() {
362840
363147
  }
362841
363148
  // Programatic API
362842
363149
  async function runTerraformProvisioner(context, command = 'init', streaming, customArgs, ctl) {
362843
- terraform_provisioner_src_logger.info(`Running command ${command} on a ${context.type} project`);
363150
+ terraform_provisioner_src_logger/* default.info */.Z.info(`Running command ${command} on a ${context.type} project`);
362844
363151
  validateContext(context);
362845
363152
  let tfProject = {};
362846
363153
  if (context.type === 'Inline') {
@@ -362866,7 +363173,7 @@ async function runTerraformProvisioner(context, command = 'init', streaming, cus
362866
363173
  tfProject.context.importMode = true;
362867
363174
  }
362868
363175
  if (command === 'destroy-state-only') {
362869
- terraform_provisioner_src_logger.info('[gh-provisioner] WARNING! is a destroy-state-only');
363176
+ terraform_provisioner_src_logger/* default.info */.Z.info('[gh-provisioner] WARNING! is a destroy-state-only');
362870
363177
  }
362871
363178
  if (ctl) {
362872
363179
  tfProject.ctl = ctl;
@@ -362875,7 +363182,7 @@ async function runTerraformProvisioner(context, command = 'init', streaming, cus
362875
363182
  return output;
362876
363183
  }
362877
363184
  async function execCommand(command, tfProject) {
362878
- terraform_provisioner_src_logger.info(`Executing command ${command} on ${tfProject.projectPath}`);
363185
+ terraform_provisioner_src_logger/* default.info */.Z.info(`Executing command ${command} on ${tfProject.projectPath}`);
362879
363186
  // Handle no-build commands FIRST
362880
363187
  if (command === 'tear-up-project') {
362881
363188
  if (tfProject.tearUpProject) {
@@ -362937,6 +363244,28 @@ function operatorProfile() {
362937
363244
  return github["default"].withProfile('operator');
362938
363245
  }
362939
363246
 
363247
+ function resolveProgressCommentResource(item) {
363248
+ return { kind: item.kind, name: item.metadata?.name ?? 'unknown' };
363249
+ }
363250
+ /**
363251
+ * Single builder of the sticky base kind shared by the apply progress
363252
+ * comment (upserted by the check run while the operation runs) and the
363253
+ * final result publisher (which updates that same comment in place).
363254
+ * Keyed per resource so claims of the same kind never overwrite each
363255
+ * other's feedback.
363256
+ */
363257
+ function progressCommentBaseKind(cmd, item) {
363258
+ const { kind, name } = resolveProgressCommentResource(item);
363259
+ return `${cmd}:${kind}:${name}`;
363260
+ }
363261
+ /**
363262
+ * Body of the apply progress comment. The check-run module appends the
363263
+ * `[here](<check-run-url>)` link to it.
363264
+ */
363265
+ function progressCommentText(cmd, item) {
363266
+ const { kind, name } = resolveProgressCommentResource(item);
363267
+ return `The ${kind} '${name}' is being processed (cmd=${cmd}). Details: `;
363268
+ }
362940
363269
  async function tryPublishApply(item, planOutput, isSuccess = true, exitCode) {
362941
363270
  const kind = item.kind;
362942
363271
  const metadataName = item.metadata?.name ?? 'unknown';
@@ -362990,7 +363319,7 @@ ${commentContent}
362990
363319
  owner: org,
362991
363320
  repo,
362992
363321
  pullNumber: prNumber,
362993
- baseKind: `${kind.toLowerCase()}:destroy`,
363322
+ baseKind: progressCommentBaseKind('destroy', item),
362994
363323
  bodies: commentBodies,
362995
363324
  });
362996
363325
  operator_src_logger.debug(`The user feedback for the '${item.kind}/${item.metadata.name}' destroy operation has been published as a comment on pull request '${prNumber}'.`);
@@ -363027,7 +363356,7 @@ ${commentContent}
363027
363356
  owner: org,
363028
363357
  repo,
363029
363358
  pullNumber: prNumber,
363030
- baseKind: `apply:${kind}`,
363359
+ baseKind: progressCommentBaseKind('apply', item),
363031
363360
  bodies: commentBodies,
363032
363361
  });
363033
363362
  }
@@ -363128,93 +363457,6 @@ ${commentContent}
363128
363457
  }
363129
363458
  }
363130
363459
 
363131
- ;// CONCATENATED MODULE: ../operator/src/tfworkspaces/policies.ts
363132
-
363133
-
363134
-
363135
- function policyAllowsOp(policy, op, item) {
363136
- let msg = '';
363137
- const foundPolicy = catalog_common/* default.policies.getPolicyByName */.Z.policies.getPolicyByName(policy);
363138
- if (op === OperationType.RETRY.toString() &&
363139
- foundPolicy?.allowedOps.includes(op)) {
363140
- if ('deletionTimestamp' in item.metadata && 'full-control' !== policy) {
363141
- msg = `A RETRY operation is not allowed on a resource with a deletionTimestamp. It means
363142
- that the resource is being deleted and it is not possible to retry the operation with policy: ${policy}.
363143
-
363144
- To fix this issue, you must first delete the "firestartr.dev/finalizer" from finalizers array in the resource manifest,
363145
- it will be automatically deleted by Kubernetes. Terraform will not execute any operation on the resource.
363146
- `;
363147
- return { allowed: false, msg };
363148
- }
363149
- else {
363150
- return { allowed: true, msg };
363151
- }
363152
- }
363153
- if (op === OperationType.RETRY_SYNC.toString() &&
363154
- foundPolicy?.allowedOps.includes(OperationType.SYNC.toString())) {
363155
- if ('deletionTimestamp' in item.metadata && 'full-control' !== policy) {
363156
- msg = `A RETRY_SYNC operation is not allowed on a resource with a deletionTimestamp. It means
363157
- that the resource is being deleted and it is not possible to retry the operation with policy: ${policy}.
363158
-
363159
- To fix this issue, you must first delete the "firestartr.dev/finalizer" from finalizers array in the resource manifest,
363160
- it will be automatically deleted by Kubernetes. Terraform will not execute any operation on the resource.
363161
- `;
363162
- return { allowed: false, msg };
363163
- }
363164
- return { allowed: true, msg };
363165
- }
363166
- if (!foundPolicy) {
363167
- msg = `Policy ${policy} not found`;
363168
- return { allowed: false, msg };
363169
- }
363170
- const allowed = foundPolicy.allowedOps.includes(op);
363171
- if (!allowed) {
363172
- msg = searchAllowedPolicies(op, policy);
363173
- }
363174
- return { allowed, msg };
363175
- }
363176
- function searchAllowedPolicies(op, policy) {
363177
- const allowedPolicies = [];
363178
- for (const policy of catalog_common/* default.policies.FIRESTARTR_POLICIES */.Z.policies.FIRESTARTR_POLICIES) {
363179
- if (policy.allowedOps.includes(op)) {
363180
- allowedPolicies.push(policy.name);
363181
- }
363182
- }
363183
- let policies = '';
363184
- if (allowedPolicies.length > 0) {
363185
- policies = allowedPolicies.join(', ');
363186
- }
363187
- return `
363188
-
363189
- Operation ${op} not allowed by policy \`${policy}\`, to allow this operation,
363190
-
363191
- switch to one of the following policies: \`${policies}\`
363192
-
363193
- `;
363194
- }
363195
- async function* errorPolicyCompatibility(syncPolicy, generalPolicy, item, op) {
363196
- const message = `Conflict: 'sync-policy': ${syncPolicy} and 'policy': ${generalPolicy} are not compatible`;
363197
- for (const typeStatus of [
363198
- ['ERROR', 'True'],
363199
- ['PROVISIONED', 'False'],
363200
- ['PROVISIONING', 'False'],
363201
- ['OUT_OF_SYNC', 'False'],
363202
- ['DELETED', 'False'],
363203
- ['PLANNING', 'False'],
363204
- ['DELETING', 'False'],
363205
- ]) {
363206
- const [type, status] = typeStatus;
363207
- yield {
363208
- item,
363209
- reason: op,
363210
- type,
363211
- status,
363212
- message,
363213
- };
363214
- }
363215
- await tryPublishError(item, op, message);
363216
- }
363217
-
363218
363460
  ;// CONCATENATED MODULE: ../operator/src/user-feedback-ops/tf-checkrun.ts
363219
363461
 
363220
363462
 
@@ -363227,7 +363469,12 @@ async function TFCheckRun(cmd, item) {
363227
363469
  const prInfo = extractPrInfo(item);
363228
363470
  const checkRun = await tf_checkrun_operatorProfile().feedback.createCheckRun(prInfo.org, prInfo.repo, helperCreateCheckRunName(cmd, item), {
363229
363471
  pullNumber: Number(prInfo.prNumber),
363230
- // check-run comments removed: redundant with native checks widget (#1985)
363472
+ // Apply progress comment: the result publisher updates this same
363473
+ // comment in place when the operation ends (shared sticky base
363474
+ // kind keyed per resource).
363475
+ includeCheckRunComment: true,
363476
+ checkRunComment: progressCommentText(cmd, item),
363477
+ stickyCommentBaseKind: progressCommentBaseKind(cmd, item),
363231
363478
  });
363232
363479
  checkRun.mdOptionsDetails({
363233
363480
  quotes: 'terraform',
@@ -363325,6 +363572,93 @@ function extractErrorDetails(error) {
363325
363572
  return { output: String(error), exitCode };
363326
363573
  }
363327
363574
 
363575
+ ;// CONCATENATED MODULE: ../operator/src/tfworkspaces/policies.ts
363576
+
363577
+
363578
+
363579
+ function policyAllowsOp(policy, op, item) {
363580
+ let msg = '';
363581
+ const foundPolicy = catalog_common/* default.policies.getPolicyByName */.Z.policies.getPolicyByName(policy);
363582
+ if (op === OperationType.RETRY.toString() &&
363583
+ foundPolicy?.allowedOps.includes(op)) {
363584
+ if ('deletionTimestamp' in item.metadata && 'full-control' !== policy) {
363585
+ msg = `A RETRY operation is not allowed on a resource with a deletionTimestamp. It means
363586
+ that the resource is being deleted and it is not possible to retry the operation with policy: ${policy}.
363587
+
363588
+ To fix this issue, you must first delete the "firestartr.dev/finalizer" from finalizers array in the resource manifest,
363589
+ it will be automatically deleted by Kubernetes. Terraform will not execute any operation on the resource.
363590
+ `;
363591
+ return { allowed: false, msg };
363592
+ }
363593
+ else {
363594
+ return { allowed: true, msg };
363595
+ }
363596
+ }
363597
+ if (op === OperationType.RETRY_SYNC.toString() &&
363598
+ foundPolicy?.allowedOps.includes(OperationType.SYNC.toString())) {
363599
+ if ('deletionTimestamp' in item.metadata && 'full-control' !== policy) {
363600
+ msg = `A RETRY_SYNC operation is not allowed on a resource with a deletionTimestamp. It means
363601
+ that the resource is being deleted and it is not possible to retry the operation with policy: ${policy}.
363602
+
363603
+ To fix this issue, you must first delete the "firestartr.dev/finalizer" from finalizers array in the resource manifest,
363604
+ it will be automatically deleted by Kubernetes. Terraform will not execute any operation on the resource.
363605
+ `;
363606
+ return { allowed: false, msg };
363607
+ }
363608
+ return { allowed: true, msg };
363609
+ }
363610
+ if (!foundPolicy) {
363611
+ msg = `Policy ${policy} not found`;
363612
+ return { allowed: false, msg };
363613
+ }
363614
+ const allowed = foundPolicy.allowedOps.includes(op);
363615
+ if (!allowed) {
363616
+ msg = searchAllowedPolicies(op, policy);
363617
+ }
363618
+ return { allowed, msg };
363619
+ }
363620
+ function searchAllowedPolicies(op, policy) {
363621
+ const allowedPolicies = [];
363622
+ for (const policy of catalog_common/* default.policies.FIRESTARTR_POLICIES */.Z.policies.FIRESTARTR_POLICIES) {
363623
+ if (policy.allowedOps.includes(op)) {
363624
+ allowedPolicies.push(policy.name);
363625
+ }
363626
+ }
363627
+ let policies = '';
363628
+ if (allowedPolicies.length > 0) {
363629
+ policies = allowedPolicies.join(', ');
363630
+ }
363631
+ return `
363632
+
363633
+ Operation ${op} not allowed by policy \`${policy}\`, to allow this operation,
363634
+
363635
+ switch to one of the following policies: \`${policies}\`
363636
+
363637
+ `;
363638
+ }
363639
+ async function* errorPolicyCompatibility(syncPolicy, generalPolicy, item, op) {
363640
+ const message = `Conflict: 'sync-policy': ${syncPolicy} and 'policy': ${generalPolicy} are not compatible`;
363641
+ for (const typeStatus of [
363642
+ ['ERROR', 'True'],
363643
+ ['PROVISIONED', 'False'],
363644
+ ['PROVISIONING', 'False'],
363645
+ ['OUT_OF_SYNC', 'False'],
363646
+ ['DELETED', 'False'],
363647
+ ['PLANNING', 'False'],
363648
+ ['DELETING', 'False'],
363649
+ ]) {
363650
+ const [type, status] = typeStatus;
363651
+ yield {
363652
+ item,
363653
+ reason: op,
363654
+ type,
363655
+ status,
363656
+ message,
363657
+ };
363658
+ }
363659
+ await tryPublishError(item, op, message);
363660
+ }
363661
+
363328
363662
  ;// CONCATENATED MODULE: ../operator/src/tfworkspaces/process-operation.ts
363329
363663
 
363330
363664
 
@@ -363337,11 +363671,36 @@ function extractErrorDetails(error) {
363337
363671
 
363338
363672
 
363339
363673
 
363674
+
363340
363675
  const TF_PROJECTS_PATH = '/tmp/tfworkspaces';
363341
363676
  const TF_CACHES_PATH = '/tmp/tfcaches';
363342
363677
  function generateSessionId() {
363343
363678
  return Math.random().toString(36).substring(2, 6).padEnd(4, '0');
363344
363679
  }
363680
+ // Recursively copy session workspace to debugPath (best-effort)
363681
+ async function copyDir(src, dest) {
363682
+ await promises_.mkdir(dest, { recursive: true });
363683
+ const entries = await promises_.readdir(src, { withFileTypes: true });
363684
+ for (const e of entries) {
363685
+ const s = external_path_.join(src, e.name);
363686
+ const d = external_path_.join(dest, e.name);
363687
+ if (e.isDirectory()) {
363688
+ await copyDir(s, d);
363689
+ }
363690
+ else if (e.isSymbolicLink()) {
363691
+ try {
363692
+ const link = await promises_.readlink(s);
363693
+ await promises_.symlink(link, d);
363694
+ }
363695
+ catch (err) {
363696
+ // ignore symlink copy failures
363697
+ }
363698
+ }
363699
+ else {
363700
+ await promises_.copyFile(s, d);
363701
+ }
363702
+ }
363703
+ }
363345
363704
  async function tearUpSessionWorkspace(item, deps, sessionId, failureContext) {
363346
363705
  try {
363347
363706
  const context = buildProvisionerContext(item, deps, sessionId);
@@ -363733,6 +364092,9 @@ async function* process_operation_sync(item, op, handler, syncPolicy, generalPol
363733
364092
  }
363734
364093
  }
363735
364094
  async function* process_operation_markedToDeletion(item, op, handler) {
364095
+ // Apply progress comment: announces the destroy on the wet-repo PR and
364096
+ // streams its output; the result publisher updates it in place at the end.
364097
+ const checkRunCtl = await TFCheckRun('destroy', item);
363736
364098
  let error = false;
363737
364099
  let deps;
363738
364100
  let terraformExecutionStarted = false;
@@ -363797,7 +364159,7 @@ async function* process_operation_markedToDeletion(item, op, handler) {
363797
364159
  deps = await handler.resolveReferences();
363798
364160
  const context = buildProvisionerContext(item, deps, sessionId);
363799
364161
  terraformExecutionStarted = true;
363800
- const destroyOutput = await runTerraformProvisioner(context, 'destroy', null, undefined, {
364162
+ const destroyOutput = await runTerraformProvisioner(context, 'destroy', checkRunCtl, undefined, {
363801
364163
  tfCacheDir: external_path_.join(TF_CACHES_PATH, `slot_${handler.getSlotInfo().slotId}`),
363802
364164
  hardTimeout: handler.recommendedTimeout(),
363803
364165
  processKilled: (killed) => {
@@ -363834,6 +364196,7 @@ async function* process_operation_markedToDeletion(item, op, handler) {
363834
364196
  catch (e) {
363835
364197
  error = true;
363836
364198
  const { output: errorMsg } = extractErrorDetails(e);
364199
+ checkRunCtl.fnOnError(errorMsg);
363837
364200
  await tryPublishDestroy(item, errorMsg, false);
363838
364201
  await handler.writeTerraformOutputInTfResult(item, errorMsg, 1);
363839
364202
  if (item.metadata.annotations['firestartr.dev/last-state-pr'] || false) {
@@ -363943,6 +364306,7 @@ async function* doApply(item, op, handler) {
363943
364306
  operator_src_logger.info(`The Terraform processor is applying and assessing dependencies for item '${item.kind}/${item.metadata.name}' with dependencies: '${deps}'.`);
363944
364307
  const context = buildProvisionerContext(item, deps, sessionId);
363945
364308
  terraformExecutionStarted = true;
364309
+ operator_src_logger.info(`[operator]: runTerraformProvisioner apply - projectPath=${context.projectPath} reuseExistingProject=${context.reuseExistingProject}`);
363946
364310
  const applyOutput = await runTerraformProvisioner(context, 'apply', checkRunCtl, undefined, {
363947
364311
  tfCacheDir: external_path_.join(TF_CACHES_PATH, `slot_${handler.getSlotInfo().slotId}`),
363948
364312
  hardTimeout: handler.recommendedTimeout(),
@@ -363955,7 +364319,70 @@ async function* doApply(item, op, handler) {
363955
364319
  }
363956
364320
  },
363957
364321
  });
364322
+ // If tf-debug annotation is present, create a snapshot copy of the
364323
+ // session-scoped workspace into the deterministic debug folder. We do
364324
+ // this as a best-effort, non-fatal operation so debug artifacts are
364325
+ // available for inspection without interfering with the reuse flow.
364326
+ try {
364327
+ const tfDebug = item && item.metadata && item.metadata.annotations
364328
+ ? item.metadata.annotations['firestartr.dev/tf-debug']
364329
+ : undefined;
364330
+ if (sessionId && tfDebug === '1' && context.projectPath) {
364331
+ const rawName = item.metadata.name;
364332
+ const baseName = rawName.replace(/-[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/, // strip uuid
364333
+ '');
364334
+ const tfStateKey = context.tfStateKey ||
364335
+ item?.spec?.firestartr?.tfStateKey;
364336
+ const safeKey = tfStateKey
364337
+ ? String(tfStateKey).replace(/\//g, '-')
364338
+ : '';
364339
+ const debugPath = external_path_.join('/tmp/tf-debug', `${item.kind.toLowerCase()}-${baseName}${safeKey ? `-${safeKey}` : ''}`);
364340
+ // If the session workspace is already the deterministic debugPath,
364341
+ // do not remove or copy it (that would delete the freshly-created
364342
+ // workspace). Instead, just ensure the debug artifacts folder exists
364343
+ // and write the metadata files there. When the source and target are
364344
+ // different, perform a best-effort copy as before.
364345
+ const srcPath = context.projectPath;
364346
+ try {
364347
+ if (srcPath && external_path_.resolve(srcPath) === external_path_.resolve(debugPath)) {
364348
+ const debugArtifactsDir = external_path_.join(debugPath, 'tf_provisioner_debug');
364349
+ await promises_.mkdir(debugArtifactsDir, { recursive: true });
364350
+ await promises_.writeFile(external_path_.join(debugArtifactsDir, 'cr.yaml'), catalog_common/* default.io.toYaml */.Z.io.toYaml(item));
364351
+ await promises_.writeFile(external_path_.join(debugArtifactsDir, 'deps.yaml'), catalog_common/* default.io.toYaml */.Z.io.toYaml(deps));
364352
+ operator_src_logger.info(`[operator]: debug snapshot preserved at ${debugPath}`);
364353
+ }
364354
+ else {
364355
+ // Remove any previous debug snapshot; ignore failures
364356
+ try {
364357
+ await promises_.rm(debugPath, { recursive: true, force: true });
364358
+ }
364359
+ catch (e) {
364360
+ operator_src_logger.warn(`Failed to remove existing debug path ${debugPath}: ${e}`);
364361
+ }
364362
+ try {
364363
+ if (srcPath)
364364
+ await copyDir(srcPath, debugPath);
364365
+ const debugArtifactsDir = external_path_.join(debugPath, 'tf_provisioner_debug');
364366
+ await promises_.mkdir(debugArtifactsDir, { recursive: true });
364367
+ await promises_.writeFile(external_path_.join(debugArtifactsDir, 'cr.yaml'), catalog_common/* default.io.toYaml */.Z.io.toYaml(item));
364368
+ await promises_.writeFile(external_path_.join(debugArtifactsDir, 'deps.yaml'), catalog_common/* default.io.toYaml */.Z.io.toYaml(deps));
364369
+ operator_src_logger.info(`[operator]: debug snapshot created at ${debugPath}`);
364370
+ }
364371
+ catch (e) {
364372
+ operator_src_logger.warn(`[operator]: failed to snapshot debug workspace: ${e}`);
364373
+ }
364374
+ }
364375
+ }
364376
+ catch (e) {
364377
+ operator_src_logger.warn(`[operator]: debug snapshot flow failed: ${e}`);
364378
+ }
364379
+ }
364380
+ }
364381
+ catch (e) {
364382
+ operator_src_logger.warn(`[operator]: debug snapshot flow failed: ${e}`);
364383
+ }
363958
364384
  context.reuseExistingProject = true;
364385
+ operator_src_logger.info(`[operator]: runTerraformProvisioner output - projectPath=${context.projectPath} reuseExistingProject=${context.reuseExistingProject}`);
363959
364386
  const terraformOutputJson = await runTerraformProvisioner(context, 'output');
363960
364387
  if (!terraformOutputJson) {
363961
364388
  throw new Error(`Terraform output is empty for ${item.kind}/${item.metadata.name}`);
@@ -364111,6 +364538,16 @@ function buildProvisionerContext(item, deps, sessionId) {
364111
364538
  if (typeof tfStateKey !== 'string' || tfStateKey.trim() === '') {
364112
364539
  throw new Error(`Invalid terraform state key: ${tfStateKey}`);
364113
364540
  }
364541
+ // Preserve the raw CR and resolved dependencies on the context so provisioners
364542
+ // can emit debug artifacts when requested. This is intentionally additive
364543
+ // and does not change the public runTerraformProvisioner API shape.
364544
+ context['rawCr'] = item;
364545
+ context['deps'] = deps;
364546
+ // Always use a session-scoped projectPath for apply/plan/etc when a
364547
+ // sessionId is provided. Do not hand the deterministic debug path to the
364548
+ // provisioner; instead, the operator will perform a copy to /tmp/tf-debug
364549
+ // after apply if the tf-debug annotation is present. This avoids races and
364550
+ // accidental deletion of debug folders during the provisioner lifecycle.
364114
364551
  if (sessionId) {
364115
364552
  context['projectPath'] = external_path_.join(TF_PROJECTS_PATH, `${item.kind.toLowerCase()}-${item.metadata.name}-${sessionId}`);
364116
364553
  }
@@ -366511,13 +366948,17 @@ function providers_replaceInlineSecrets(inline, secrets) {
366511
366948
  const DEBUG_DIR = external_path_default().join(external_os_default().tmpdir(), 'gh-debug');
366512
366949
  // Returns the project path to use for debug artifacts (always SessionProjectPath for consistency)
366513
366950
  function getDebugProjectPath(entity) {
366514
- // Use the sessionProjectPath, which now always includes the 4-character sessionId
366951
+ // Use the sessionProjectPath if present. sessionProjectPath will include
366952
+ // the tfStateKey suffix when in debug mode, as set by runGhProvisioner.
366515
366953
  return (entity.sessionProjectPath ||
366516
366954
  external_path_default().join(DEBUG_DIR, entity.k8sId.replace(/\//, '-') + '-id_missing'));
366517
366955
  }
366518
366956
  async function initDebug(entity, deps) {
366519
- // Clean only this session's project debug directory, NOT all debug workspaces
366520
- // Only create the specific debug project path for this session; never remove in debug mode
366957
+ // If a previous deterministic debug folder exists for this resource, wipe it
366958
+ // We intentionally remove only the per-claim debug folder (the whole folder)
366959
+ // to ensure a fresh debug run and avoid accumulating files between runs.
366960
+ await (0,promises_namespaceObject.rm)(getDebugProjectPath(entity), { recursive: true, force: true });
366961
+ // Create the (fresh) project path and debug artifacts dir
366521
366962
  await (0,promises_namespaceObject.mkdir)(getDebugProjectPath(entity), { recursive: true });
366522
366963
  const debugArtifactsDir = external_path_default().join(getDebugProjectPath(entity), 'gh_provisioner_debug');
366523
366964
  await (0,promises_namespaceObject.mkdir)(debugArtifactsDir, { recursive: true });
@@ -367440,9 +367881,21 @@ async function runGhProvisioner(data, opts) {
367440
367881
  try {
367441
367882
  entity = await initSystem(data.mainCr, data.deps);
367442
367883
  // Generate per-execution sessionId and session projectPath
367884
+ // For debug mode we want a deterministic per-resource folder (no random suffix)
367885
+ // Use the resource's tfStateKey when present for stability, otherwise fall
367886
+ // back to metadata UID-like deterministic id stored on the CR name/fields.
367443
367887
  sessionId = generateSessionId();
367444
367888
  if (entity.inDebugMode) {
367445
- sessionProjectPath = `/tmp/gh-debug/${entity.cr.kind.toLowerCase()}-${entity.cr.name}-${sessionId}`;
367889
+ // Use deterministic per-resource folder under /tmp/gh-debug. Include
367890
+ // the tfStateKey as a suffix when available to avoid collisions for
367891
+ // resources (like features) that share a human-friendly name.
367892
+ const rawName = entity.cr.name;
367893
+ const baseName = rawName.replace(/-[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/, '');
367894
+ const tfStateKey = entity.cr?.spec?.firestartr?.tfStateKey;
367895
+ const safeKey = typeof tfStateKey === 'string' && tfStateKey.trim() !== ''
367896
+ ? tfStateKey
367897
+ : null;
367898
+ sessionProjectPath = `/tmp/gh-debug/${entity.cr.kind.toLowerCase()}-${baseName}${safeKey ? `-${safeKey}` : ''}`;
367446
367899
  }
367447
367900
  else {
367448
367901
  sessionProjectPath = `/tmp/gh-workspaces/${entity.cr.kind.toLowerCase()}-${entity.cr.name}-${sessionId}`;
@@ -368440,6 +368893,11 @@ async function* gh_process_operation_markedToDeletion(item, op, handler) {
368440
368893
  // we close it with an error
368441
368894
  if (checkRunCtl)
368442
368895
  checkRunCtl.fnOnError(errorMsg);
368896
+ // also close the Terraform check run: its periodic flush would
368897
+ // otherwise keep rewriting the apply progress comment after the
368898
+ // final destroy result is published
368899
+ if (checkRunTFCtl)
368900
+ checkRunTFCtl.fnOnError(errorMsg);
368443
368901
  await tryPublishDestroy(item, errorMsg, false);
368444
368902
  await handler.writeTerraformOutputInTfResult(item, errorMsg, errCode ?? 1);
368445
368903
  void handler.error();
@@ -368694,10 +369152,18 @@ async function tfPlanner(claimFilePath, claim, namespace, debug, jobTtl = 300, c
368694
369152
  job.spec.ttlSecondsAfterFinished = jobTtl;
368695
369153
  job.spec.template = controllerDeploy.spec.template;
368696
369154
  job.spec.template.spec.containers[0].image = withToolImageTag(job.spec.template.spec.containers[0].image, toolImageTag);
368697
- // set activeDeadlineSeconds to force terminate jobs that exceed this time
368698
- // see https://kubernetes.io/docs/concepts/workloads/controllers/job/#job-termination-and-cleanup
368699
- job.spec.activeDeadlineSeconds = 3600;
369155
+ if (!debug) {
369156
+ // set activeDeadlineSeconds to force terminate jobs that exceed this time
369157
+ // see https://kubernetes.io/docs/concepts/workloads/controllers/job/#job-termination-and-cleanup
369158
+ job.spec.activeDeadlineSeconds = 3600;
369159
+ }
368700
369160
  job.spec.template.spec.containers[0].env = [{ name: 'CI', value: 'True' }];
369161
+ if (debug) {
369162
+ job.spec.template.spec.containers[0].env.push({
369163
+ name: 'FIRESTARTR_DEBUG',
369164
+ value: 'true',
369165
+ });
369166
+ }
368701
369167
  job.spec.template.spec.containers[0].command = [
368702
369168
  'sh',
368703
369169
  '-c',
@@ -368705,7 +369171,7 @@ async function tfPlanner(claimFilePath, claim, namespace, debug, jobTtl = 300, c
368705
369171
  ];
368706
369172
  if (debug) {
368707
369173
  job.spec.template.spec.containers[0].command[2] =
368708
- job.spec.template.spec.containers[0].command[2].concat(' || tail -f /dev/null');
369174
+ job.spec.template.spec.containers[0].command[2].concat(' ; tail -f /dev/null');
368709
369175
  }
368710
369176
  job.spec.template.spec.restartPolicy = 'Never';
368711
369177
  job.metadata = metadata;
@@ -368720,7 +369186,7 @@ async function tfPlanner(claimFilePath, claim, namespace, debug, jobTtl = 300, c
368720
369186
  ctlCleanUp: () => cleanUp(namespace, metadata.name),
368721
369187
  });
368722
369188
  await batchV1Api.createNamespacedJob({ namespace, body: job });
368723
- await copyClaimAndGetLogs(namespace, job.metadata.name, claimFilePath);
369189
+ await copyClaimAndGetLogs(namespace, job.metadata.name, claimFilePath, debug);
368724
369190
  }
368725
369191
  async function cleanUp(namespace, jobName) {
368726
369192
  try {
@@ -368731,7 +369197,7 @@ async function cleanUp(namespace, jobName) {
368731
369197
  await batchV1Api.deleteNamespacedJob({
368732
369198
  name: jobName,
368733
369199
  namespace,
368734
- gracePeriodSeconds: 1 * 60,
369200
+ gracePeriodSeconds: 0,
368735
369201
  propagationPolicy: 'Foreground',
368736
369202
  });
368737
369203
  }
@@ -368744,7 +369210,7 @@ async function cleanUp(namespace, jobName) {
368744
369210
  console.error(cleanError);
368745
369211
  }
368746
369212
  }
368747
- async function copyClaimAndGetLogs(namespace, jobName, sourcePath) {
369213
+ async function copyClaimAndGetLogs(namespace, jobName, sourcePath, skipLogs = false) {
368748
369214
  const { kc } = await getConnection();
368749
369215
  const k8sApi = kc.makeApiClient(client.CoreV1Api);
368750
369216
  const logStream = new stream.PassThrough();
@@ -368786,6 +369252,10 @@ async function copyClaimAndGetLogs(namespace, jobName, sourcePath) {
368786
369252
  console.log('Copying claim to pod');
368787
369253
  await kubectlCp(sourcePath, namespace, pod.metadata.name);
368788
369254
  console.log('Claim copied to pod');
369255
+ if (skipLogs) {
369256
+ console.log('Debug mode: skipping log streaming');
369257
+ return;
369258
+ }
368789
369259
  try {
368790
369260
  const logClient = new client.Log(kc);
368791
369261
  await new Promise((resolve, reject) => {
@@ -713423,7 +713893,7 @@ const crsStatusSubcommand = {
713423
713893
  };
713424
713894
 
713425
713895
  ;// CONCATENATED MODULE: ./package.json
713426
- const package_namespaceObject = JSON.parse('{"i8":"2.11.0-snapshot-import-filter-fix-2"}');
713896
+ const package_namespaceObject = JSON.parse('{"i8":"2.11.0-snapshot-importer-filter-fix-3"}');
713427
713897
  ;// CONCATENATED MODULE: ../../package.json
713428
713898
  const package_namespaceObject_1 = {"i8":"2.10.0"};
713429
713899
  // EXTERNAL MODULE: ../../node_modules/semver/index.js