@firestartr/cli 1.53.0-snapshot-7 → 1.53.0-snapshot-9

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
@@ -356807,6 +356807,10 @@ class SyncerInitializer extends InitializerPatches {
356807
356807
  const provider = helperCTX(ctx).provider;
356808
356808
  return claim.providers[provider].sync || {};
356809
356809
  }
356810
+ function policyInfo(ctx) {
356811
+ const provider = helperCTX(ctx).provider;
356812
+ return claim.providers[provider].policy;
356813
+ }
356810
356814
  return [
356811
356815
  {
356812
356816
  validate(cr) {
@@ -356837,21 +356841,22 @@ class SyncerInitializer extends InitializerPatches {
356837
356841
  }
356838
356842
  },
356839
356843
  apply(cr) {
356844
+ cr.metadata.annotations = cr.metadata.annotations || {};
356845
+ // Apply general policy annotation
356846
+ if (policyInfo(this)) {
356847
+ cr.metadata.annotations['firestartr.dev/policy'] = policyInfo(this);
356848
+ }
356840
356849
  if (syncInfo(this).enabled) {
356841
- cr.metadata.annotations = cr.metadata.annotations || {};
356842
356850
  cr.metadata.annotations['firestartr.dev/sync-enabled'] = 'true';
356843
356851
  if (syncInfo(this).period) {
356844
- cr.metadata.annotations = cr.metadata.annotations || {};
356845
356852
  cr.metadata.annotations['firestartr.dev/sync-period'] =
356846
356853
  syncInfo(this).period;
356847
356854
  }
356848
356855
  if (syncInfo(this).policy) {
356849
- cr.metadata.annotations = cr.metadata.annotations || {};
356850
356856
  cr.metadata.annotations['firestartr.dev/sync-policy'] =
356851
356857
  syncInfo(this).policy;
356852
356858
  }
356853
356859
  if (syncInfo(this).schedule) {
356854
- cr.metadata.annotations = cr.metadata.annotations || {};
356855
356860
  cr.metadata.annotations[SYNC_SCHED_ANNOTATION] =
356856
356861
  syncInfo(this).schedule;
356857
356862
  cr.metadata.annotations[SYNC_SCHED_TIMEZONE_ANNOTATION] =
@@ -357572,6 +357577,69 @@ const external_node_child_process_namespaceObject = __WEBPACK_EXTERNAL_createReq
357572
357577
  },
357573
357578
  additionalProperties: false,
357574
357579
  },
357580
+ PolicyType: {
357581
+ $id: 'firestartr.dev://common/PolicyType',
357582
+ type: 'string',
357583
+ description: 'Policy for resource management',
357584
+ enum: [
357585
+ 'apply',
357586
+ 'create-only',
357587
+ 'create-update-only',
357588
+ 'full-control',
357589
+ 'observe',
357590
+ 'observe-only',
357591
+ ],
357592
+ },
357593
+ SyncConfig: {
357594
+ $id: 'firestartr.dev://common/SyncConfig',
357595
+ type: 'object',
357596
+ description: 'Sync configuration for resources',
357597
+ properties: {
357598
+ enabled: {
357599
+ type: 'boolean',
357600
+ description: 'Enable periodic sync operations',
357601
+ },
357602
+ period: {
357603
+ type: 'string',
357604
+ pattern: '^[0-9]+[smhd]$',
357605
+ description: 'Sync period (e.g., 1h, 30m, 5s). Must be enabled without schedule.',
357606
+ },
357607
+ schedule: {
357608
+ type: 'string',
357609
+ description: 'Cron schedule for sync operations. Must be enabled without period.',
357610
+ },
357611
+ schedule_timezone: {
357612
+ type: 'string',
357613
+ description: 'Timezone for cron schedule (e.g., UTC, America/New_York)',
357614
+ },
357615
+ policy: {
357616
+ type: 'string',
357617
+ description: 'Policy for sync operations (apply or observe)',
357618
+ },
357619
+ },
357620
+ additionalProperties: false,
357621
+ required: ['enabled'],
357622
+ oneOf: [
357623
+ {
357624
+ required: ['period'],
357625
+ },
357626
+ {
357627
+ required: ['schedule'],
357628
+ },
357629
+ {
357630
+ not: {
357631
+ anyOf: [
357632
+ {
357633
+ required: ['period'],
357634
+ },
357635
+ {
357636
+ required: ['schedule'],
357637
+ },
357638
+ ],
357639
+ },
357640
+ },
357641
+ ],
357642
+ },
357575
357643
  },
357576
357644
  });
357577
357645
 
@@ -357932,6 +358000,9 @@ const external_node_child_process_namespaceObject = __WEBPACK_EXTERNAL_createReq
357932
358000
  {
357933
358001
  type: 'object',
357934
358002
  properties: {
358003
+ policy: {
358004
+ $ref: 'firestartr.dev://common/PolicyType',
358005
+ },
357935
358006
  privacy: {
357936
358007
  type: 'string',
357937
358008
  enum: ['closed', 'secret'],
@@ -357942,6 +358013,9 @@ const external_node_child_process_namespaceObject = __WEBPACK_EXTERNAL_createReq
357942
358013
  org: {
357943
358014
  type: 'string',
357944
358015
  },
358016
+ sync: {
358017
+ $ref: 'firestartr.dev://common/SyncConfig',
358018
+ },
357945
358019
  },
357946
358020
  required: ['org', 'privacy'],
357947
358021
  },
@@ -357967,6 +358041,9 @@ const external_node_child_process_namespaceObject = __WEBPACK_EXTERNAL_createReq
357967
358041
  {
357968
358042
  type: 'object',
357969
358043
  properties: {
358044
+ policy: {
358045
+ $ref: 'firestartr.dev://common/PolicyType',
358046
+ },
357970
358047
  role: {
357971
358048
  type: 'string',
357972
358049
  enum: ['admin', 'member'],
@@ -357974,6 +358051,9 @@ const external_node_child_process_namespaceObject = __WEBPACK_EXTERNAL_createReq
357974
358051
  org: {
357975
358052
  type: 'string',
357976
358053
  },
358054
+ sync: {
358055
+ $ref: 'firestartr.dev://common/SyncConfig',
358056
+ },
357977
358057
  },
357978
358058
  required: ['org', 'role'],
357979
358059
  },
@@ -357998,6 +358078,9 @@ const external_node_child_process_namespaceObject = __WEBPACK_EXTERNAL_createReq
357998
358078
  {
357999
358079
  type: 'object',
358000
358080
  properties: {
358081
+ policy: {
358082
+ $ref: 'firestartr.dev://common/PolicyType',
358083
+ },
358001
358084
  org: {
358002
358085
  type: 'string',
358003
358086
  description: 'The github organization name',
@@ -358006,6 +358089,9 @@ const external_node_child_process_namespaceObject = __WEBPACK_EXTERNAL_createReq
358006
358089
  type: 'string',
358007
358090
  enum: ['private', 'public', 'internal'],
358008
358091
  },
358092
+ sync: {
358093
+ $ref: 'firestartr.dev://common/SyncConfig',
358094
+ },
358009
358095
  features: {
358010
358096
  type: 'array',
358011
358097
  items: {
@@ -358041,6 +358127,9 @@ const external_node_child_process_namespaceObject = __WEBPACK_EXTERNAL_createReq
358041
358127
  {
358042
358128
  type: 'object',
358043
358129
  properties: {
358130
+ policy: {
358131
+ $ref: 'firestartr.dev://common/PolicyType',
358132
+ },
358044
358133
  orgName: {
358045
358134
  type: 'string',
358046
358135
  description: 'Organization name on GitHub',
@@ -358074,6 +358163,9 @@ const external_node_child_process_namespaceObject = __WEBPACK_EXTERNAL_createReq
358074
358163
  },
358075
358164
  required: ['url', 'contentType', 'events', 'secretRef'],
358076
358165
  },
358166
+ sync: {
358167
+ $ref: 'firestartr.dev://common/SyncConfig',
358168
+ },
358077
358169
  },
358078
358170
  required: ['orgName', 'webhook'],
358079
358171
  },
@@ -358245,15 +358337,7 @@ const GithubSchemas = [
358245
358337
  type: 'object',
358246
358338
  properties: {
358247
358339
  policy: {
358248
- type: 'string',
358249
- enum: [
358250
- 'apply',
358251
- 'create-only',
358252
- 'create-update-only',
358253
- 'full-control',
358254
- 'observe',
358255
- 'observe-only',
358256
- ],
358340
+ $ref: 'firestartr.dev://common/PolicyType',
358257
358341
  },
358258
358342
  name: {
358259
358343
  type: 'string',
@@ -358263,47 +358347,7 @@ const GithubSchemas = [
358263
358347
  enum: ['remote', 'inline', 'Remote', 'Inline'],
358264
358348
  },
358265
358349
  sync: {
358266
- type: 'object',
358267
- properties: {
358268
- enabled: {
358269
- type: 'boolean',
358270
- },
358271
- period: {
358272
- type: 'string',
358273
- pattern: '^[0-9]+[smhd]$',
358274
- },
358275
- schedule: {
358276
- type: 'string',
358277
- },
358278
- schedule_timezone: {
358279
- type: 'string',
358280
- },
358281
- policy: {
358282
- type: 'string',
358283
- },
358284
- },
358285
- additionalProperties: false,
358286
- required: ['enabled'],
358287
- oneOf: [
358288
- {
358289
- required: ['period'],
358290
- },
358291
- {
358292
- required: ['schedule'],
358293
- },
358294
- {
358295
- not: {
358296
- anyOf: [
358297
- {
358298
- required: ['period'],
358299
- },
358300
- {
358301
- required: ['schedule'],
358302
- },
358303
- ],
358304
- },
358305
- },
358306
- ],
358350
+ $ref: 'firestartr.dev://common/SyncConfig',
358307
358351
  },
358308
358352
  valuesSchema: {
358309
358353
  type: 'string',
@@ -364067,8 +364111,13 @@ class FeatureRepoChart extends BaseGithubChart {
364067
364111
  const annotations = this.getAnnotationsFromRepo(this.get('repoCr'), [
364068
364112
  'claim-ref',
364069
364113
  'revision',
364114
+ 'policy',
364115
+ 'sync-policy',
364070
364116
  'sync-enabled',
364071
364117
  'sync-period',
364118
+ 'sync-schedule',
364119
+ 'sync-schedule-timezone',
364120
+ 'last-state-pr',
364072
364121
  ]);
364073
364122
  cr.metadata.annotations = {
364074
364123
  ...cr.metadata.annotations,
@@ -364141,8 +364190,13 @@ class RepoSecretsSectionChart extends BaseGithubChart {
364141
364190
  const annotations = this.getAnnotationsFromRepo(this.get('repoCr'), [
364142
364191
  'claim-ref',
364143
364192
  'revision',
364193
+ 'policy',
364194
+ 'sync-policy',
364144
364195
  'sync-enabled',
364145
364196
  'sync-period',
364197
+ 'sync-schedule',
364198
+ 'sync-schedule-timezone',
364199
+ 'last-state-pr',
364146
364200
  ]);
364147
364201
  cr.metadata.annotations = {
364148
364202
  ...cr.metadata.annotations,
@@ -370410,10 +370464,15 @@ class Resource {
370410
370464
  this.set('operation', operation);
370411
370465
  this.set('deps', deps);
370412
370466
  }
370413
- async run() {
370467
+ async run(options) {
370414
370468
  await this.preprocess();
370415
370469
  await this.synth();
370416
- await this.runTerraform();
370470
+ if (options?.planOnly) {
370471
+ await this.runTerraformPlanOnly();
370472
+ }
370473
+ else {
370474
+ await this.runTerraform();
370475
+ }
370417
370476
  await this.postprocess();
370418
370477
  if (this.logStream) {
370419
370478
  this.logStream.end();
@@ -370438,6 +370497,13 @@ class Resource {
370438
370497
  log(msg) {
370439
370498
  this.logFn(msg);
370440
370499
  }
370500
+ async runTerraformPlanOnly() {
370501
+ await this.onTFStreaming();
370502
+ let output = '';
370503
+ output += await terraformInit(this.get('main_artifact'), this.logStream);
370504
+ output += await terraformPlan(this.get('main_artifact'), this.logStream);
370505
+ this.set('output', output);
370506
+ }
370441
370507
  async runTerraform() {
370442
370508
  await this.onTFStreaming();
370443
370509
  let output = '';
@@ -370825,7 +370891,7 @@ async function runProvisioner(data, opts) {
370825
370891
  if ('logStreamCallbacksTF' in opts) {
370826
370892
  resource.setTFStreamLogs(opts['logStreamCallbacksTF']);
370827
370893
  }
370828
- await resource.run();
370894
+ await resource.run({ planOnly: opts.planOnly });
370829
370895
  return resource;
370830
370896
  }
370831
370897
  function createInstanceOf(entity, op, deps) {
@@ -371107,6 +371173,56 @@ function helperCreateCheckRunName(cmd, item) {
371107
371173
  return `${item.kind} - ${cmd}`;
371108
371174
  }
371109
371175
 
371176
+ ;// CONCATENATED MODULE: ../operator/src/utils/index.ts
371177
+ const secretRegex = /\$\{\{ secrets\.(.*?) \}\}/g;
371178
+ function replaceConfigSecrets(config, secrets) {
371179
+ for (const key in config) {
371180
+ if (typeof config[key] === 'object' && config[key] !== null) {
371181
+ // If the property is an object, call this function recursively
371182
+ replaceConfigSecrets(config[key], secrets);
371183
+ }
371184
+ else if (typeof config[key] === 'string') {
371185
+ // If the property is a string and its value is equal to secrets.something,
371186
+ // replace the value with the value of the 'something' key in the secrets object
371187
+ config[key] = config[key].replace(secretRegex, (_, group1) => {
371188
+ if (!secrets[group1]) {
371189
+ throw new Error(`Secret ${group1} not found in secrets`);
371190
+ }
371191
+ return secrets[group1];
371192
+ });
371193
+ }
371194
+ }
371195
+ return config;
371196
+ }
371197
+ function replaceInlineSecrets(inline, secrets) {
371198
+ if (typeof inline !== 'string' || !inline)
371199
+ return inline;
371200
+ let result = inline;
371201
+ result = result.replace(secretRegex, (_, group1) => {
371202
+ if (!secrets[group1]) {
371203
+ throw new Error(`Secret ${group1} not found in secrets`);
371204
+ }
371205
+ return secrets[group1];
371206
+ });
371207
+ return result;
371208
+ }
371209
+ /**
371210
+ * Retrieves a policy annotation value from a custom resource
371211
+ * @param item - The CR to get the policy from
371212
+ * @param annotation - The annotation key to retrieve
371213
+ * @returns The policy value, or undefined if not set
371214
+ */
371215
+ function getPolicy(item, annotation) {
371216
+ const policy = item.metadata.annotations && item.metadata.annotations[annotation];
371217
+ if (policy)
371218
+ return policy;
371219
+ }
371220
+
371221
+ ;// CONCATENATED MODULE: ../operator/src/utils/operationErrorMessages.ts
371222
+ const APPLY_DEFAULT_ERROR_MESSAGE = 'An error occurred while executing the Terraform apply operation.';
371223
+ const DESTROY_DEFAULT_ERROR_MESSAGE = 'An error occurred while executing the Terraform destroy operation.';
371224
+ const PLAN_DEFAULT_ERROR_MESSAGE = 'An error occurred while executing the Terraform plan operation.';
371225
+
371110
371226
  ;// CONCATENATED MODULE: ../operator/cdktf.ts
371111
371227
 
371112
371228
 
@@ -371116,9 +371232,18 @@ function helperCreateCheckRunName(cmd, item) {
371116
371232
 
371117
371233
 
371118
371234
 
371235
+
371236
+ const cdktf_LAST_STATE_PR_ANNOTATION = 'firestartr.dev/last-state-pr';
371237
+
371119
371238
  function processOperation(item, op, handler) {
371120
371239
  operator_src_logger.info(`Processing operation ${op} on ${item.kind}/${item.metadata?.name}`);
371121
371240
  try {
371241
+ const policy = getPolicy(item, 'firestartr.dev/policy');
371242
+ // If general policy is observe/observe-only, route to observe mode instead of apply
371243
+ if (!policy || policy === 'observe' || policy === 'observe-only') {
371244
+ operator_src_logger.info(`Policy is '${policy || 'not set (default)'}', routing to observe mode`);
371245
+ return cdktf_observe(item, op, handler);
371246
+ }
371122
371247
  switch (op) {
371123
371248
  case OperationType.UPDATED:
371124
371249
  return updated(item, op, handler);
@@ -371143,6 +371268,11 @@ function processOperation(item, op, handler) {
371143
371268
  throw e;
371144
371269
  }
371145
371270
  }
371271
+ async function* cdktf_observe(item, op, handler) {
371272
+ for await (const transition of doPlan(item, op, handler)) {
371273
+ yield transition;
371274
+ }
371275
+ }
371146
371276
  async function* created(item, op, handler) {
371147
371277
  for await (const transition of doApply(item, op, handler)) {
371148
371278
  yield transition;
@@ -371178,8 +371308,18 @@ async function* sync(item, op, handler) {
371178
371308
  status: 'False',
371179
371309
  message: 'Synth CDKTF',
371180
371310
  };
371181
- for await (const transition of doApply(item, op, handler)) {
371182
- yield transition;
371311
+ const syncPolicy = getPolicy(item, 'firestartr.dev/sync-policy');
371312
+ if (syncPolicy === 'apply') {
371313
+ operator_src_logger.info(`SYNC OPERATION: applying item ${item.metadata.name} with sync-policy=${syncPolicy}`);
371314
+ for await (const transition of doApply(item, op, handler)) {
371315
+ yield transition;
371316
+ }
371317
+ }
371318
+ else {
371319
+ operator_src_logger.info(`SYNC OPERATION: planning item ${item.metadata.name} with sync-policy=${syncPolicy || 'default (observe)'}`);
371320
+ for await (const transition of doPlan(item, op, handler)) {
371321
+ yield transition;
371322
+ }
371183
371323
  }
371184
371324
  yield {
371185
371325
  item,
@@ -371218,15 +371358,14 @@ async function* markedToDeletion(item, op, handler) {
371218
371358
  message: 'Destroying process started',
371219
371359
  };
371220
371360
  const deps = await handler.resolveReferences();
371221
- const annotation = 'firestartr.dev/last-state-pr';
371222
- const statePr = item?.metadata?.annotations?.[annotation];
371361
+ const statePr = item?.metadata?.annotations?.[cdktf_LAST_STATE_PR_ANNOTATION];
371223
371362
  const hasStatePr = typeof statePr === 'string' && statePr.trim().length > 0;
371224
371363
  if (!hasStatePr) {
371225
371364
  operator_src_logger.warn(`CR ${item?.kind ?? 'UnknownKind'}/${item?.metadata?.name ?? 'unknown'} ` +
371226
- `has no "${annotation}" annotation; skipping GitHub Check Runs (synth, terraform apply).`);
371365
+ `has no "${cdktf_LAST_STATE_PR_ANNOTATION}" annotation; skipping GitHub Check Runs (synth, terraform apply).`);
371227
371366
  }
371228
371367
  else {
371229
- operator_src_logger.debug(`CR ${item.kind}/${item.metadata.name} uses "${annotation}" = ${statePr}`);
371368
+ operator_src_logger.debug(`CR ${item.kind}/${item.metadata.name} uses "${cdktf_LAST_STATE_PR_ANNOTATION}" = ${statePr}`);
371230
371369
  }
371231
371370
  const destroyOutput = await provisioner.runProvisioner({
371232
371371
  mainCr: item,
@@ -371261,7 +371400,7 @@ async function* markedToDeletion(item, op, handler) {
371261
371400
  };
371262
371401
  await handler.finalize(handler.pluralKind, item.metadata.namespace, item, 'firestartr.dev/finalizer');
371263
371402
  await handler.writeTerraformOutputInTfResult(item, output);
371264
- if (item.metadata.annotations['firestartr.dev/last-state-pr'] || false) {
371403
+ if (item.metadata.annotations[cdktf_LAST_STATE_PR_ANNOTATION] || false) {
371265
371404
  await addDestroyCommitStatus(item, 'success', 'Destroy operation completed', `Terraform Destroy ${item.metadata.name}`);
371266
371405
  }
371267
371406
  void handler.success();
@@ -371272,7 +371411,7 @@ async function* markedToDeletion(item, op, handler) {
371272
371411
  reason: op,
371273
371412
  type: 'ERROR',
371274
371413
  status: 'True',
371275
- message: e.toString(),
371414
+ message: DESTROY_DEFAULT_ERROR_MESSAGE,
371276
371415
  };
371277
371416
  // if there is a current checkRun working
371278
371417
  // we close it with an error
@@ -371342,15 +371481,14 @@ async function* doApply(item, op, handler) {
371342
371481
  }
371343
371482
  const deps = await handler.resolveReferences();
371344
371483
  operator_src_logger.info(`Item ${item.metadata.name} has the following dependencies: ${deps}`);
371345
- const annotation = 'firestartr.dev/last-state-pr';
371346
- const statePr = item?.metadata?.annotations?.[annotation];
371484
+ const statePr = item?.metadata?.annotations?.[cdktf_LAST_STATE_PR_ANNOTATION];
371347
371485
  const hasStatePr = typeof statePr === 'string' && statePr.trim().length > 0;
371348
371486
  if (!hasStatePr) {
371349
371487
  operator_src_logger.warn(`CR ${item?.kind ?? 'UnknownKind'}/${item?.metadata?.name ?? 'unknown'} ` +
371350
- `has no "${annotation}" annotation; skipping GitHub Check Runs (synth, terraform apply).`);
371488
+ `has no "${cdktf_LAST_STATE_PR_ANNOTATION}" annotation; skipping GitHub Check Runs (synth, terraform apply).`);
371351
371489
  }
371352
371490
  else {
371353
- operator_src_logger.debug(`CR ${item.kind}/${item.metadata.name} uses "${annotation}" = ${statePr}`);
371491
+ operator_src_logger.debug(`CR ${item.kind}/${item.metadata.name} uses "${cdktf_LAST_STATE_PR_ANNOTATION}" = ${statePr}`);
371354
371492
  }
371355
371493
  const applyOutput = await provisioner.runProvisioner({
371356
371494
  mainCr: item,
@@ -371424,21 +371562,21 @@ async function* doApply(item, op, handler) {
371424
371562
  reason: op,
371425
371563
  type: 'ERROR',
371426
371564
  status: 'True',
371427
- message: error.toString(),
371565
+ message: APPLY_DEFAULT_ERROR_MESSAGE,
371428
371566
  };
371429
371567
  yield {
371430
371568
  item,
371431
371569
  reason: op,
371432
371570
  type: 'PROVISIONED',
371433
371571
  status: 'False',
371434
- message: error.toString(),
371572
+ message: APPLY_DEFAULT_ERROR_MESSAGE,
371435
371573
  };
371436
371574
  yield {
371437
371575
  item,
371438
371576
  reason: op,
371439
371577
  type: 'PROVISIONING',
371440
371578
  status: 'False',
371441
- message: error.toString(),
371579
+ message: APPLY_DEFAULT_ERROR_MESSAGE,
371442
371580
  };
371443
371581
  handler.error();
371444
371582
  if (error) {
@@ -371446,6 +371584,219 @@ async function* doApply(item, op, handler) {
371446
371584
  }
371447
371585
  }
371448
371586
  }
371587
+ async function* doPlan(item, op, handler) {
371588
+ let checkRunCtl;
371589
+ try {
371590
+ cleanTerraformState();
371591
+ yield {
371592
+ item,
371593
+ reason: op,
371594
+ type: 'PLANNING',
371595
+ status: 'True',
371596
+ message: 'Planning process started',
371597
+ };
371598
+ const deps = await handler.resolveReferences();
371599
+ const statePr = item?.metadata?.annotations?.[cdktf_LAST_STATE_PR_ANNOTATION];
371600
+ const hasStatePr = typeof statePr === 'string' && statePr.trim().length > 0;
371601
+ if (!hasStatePr) {
371602
+ operator_src_logger.warn(`CR ${item?.kind ?? 'UnknownKind'}/${item?.metadata?.name ?? 'unknown'} ` +
371603
+ `has no "${cdktf_LAST_STATE_PR_ANNOTATION}" annotation; skipping GitHub Check Runs for plan.`);
371604
+ }
371605
+ else {
371606
+ operator_src_logger.debug(`CR ${item.kind}/${item.metadata.name} uses "${cdktf_LAST_STATE_PR_ANNOTATION}" = ${statePr}`);
371607
+ await addPlanStatusCheck(statePr, 'CDKTF plan in progress...');
371608
+ }
371609
+ // Run provisioner in plan-only mode
371610
+ const planResult = await provisioner.runProvisioner({ mainCr: item, deps }, {
371611
+ planOnly: true,
371612
+ delete: 'deletionTimestamp' in item.metadata,
371613
+ ...(hasStatePr
371614
+ ? {
371615
+ logStreamCallbacksCDKTF: {
371616
+ prepare: async () => {
371617
+ checkRunCtl = await GHCheckRun('synth', item);
371618
+ return checkRunCtl;
371619
+ },
371620
+ },
371621
+ logStreamCallbacksTF: {
371622
+ prepare: async () => {
371623
+ checkRunCtl = await GHCheckRun('plan', item);
371624
+ return checkRunCtl;
371625
+ },
371626
+ },
371627
+ }
371628
+ : {}),
371629
+ });
371630
+ const planOutput = planResult?.output || '';
371631
+ // Parse terraform plan output to detect changes
371632
+ // Handles multiple Terraform output formats and versions
371633
+ const hasChanges = detectPlanChanges(planOutput);
371634
+ if (hasChanges) {
371635
+ yield {
371636
+ item,
371637
+ reason: op,
371638
+ type: 'OUT_OF_SYNC',
371639
+ status: 'True',
371640
+ message: 'Plan has changes',
371641
+ };
371642
+ yield {
371643
+ item,
371644
+ reason: op,
371645
+ type: 'PROVISIONED',
371646
+ status: 'False',
371647
+ message: 'Plan has changes',
371648
+ };
371649
+ }
371650
+ else {
371651
+ yield {
371652
+ item,
371653
+ reason: op,
371654
+ type: 'OUT_OF_SYNC',
371655
+ status: 'False',
371656
+ message: 'Plan has no changes',
371657
+ };
371658
+ yield {
371659
+ item,
371660
+ reason: op,
371661
+ type: 'PROVISIONED',
371662
+ status: 'True',
371663
+ message: 'Plan has no changes',
371664
+ };
371665
+ }
371666
+ // Store plan details for later reference
371667
+ yield {
371668
+ item,
371669
+ reason: op,
371670
+ type: 'LAST_PLAN_DETAILS',
371671
+ status: 'Unknown',
371672
+ message: planOutput,
371673
+ };
371674
+ yield {
371675
+ item,
371676
+ reason: op,
371677
+ type: 'PLANNING',
371678
+ status: 'False',
371679
+ message: 'Planning process finished',
371680
+ };
371681
+ if (hasStatePr) {
371682
+ await addPlanStatusCheck(statePr, hasChanges ? 'Plan has changes' : 'Plan has no changes', 'completed');
371683
+ }
371684
+ }
371685
+ catch (e) {
371686
+ operator_src_logger.error(`CDKTF plan failed: ${e}`);
371687
+ if (checkRunCtl) {
371688
+ checkRunCtl.fnOnError(e);
371689
+ }
371690
+ yield {
371691
+ item,
371692
+ reason: op,
371693
+ type: 'ERROR',
371694
+ status: 'True',
371695
+ message: e.toString(),
371696
+ };
371697
+ yield {
371698
+ item,
371699
+ reason: op,
371700
+ type: 'PLANNING',
371701
+ status: 'False',
371702
+ message: e.toString(),
371703
+ };
371704
+ yield {
371705
+ item,
371706
+ reason: op,
371707
+ type: 'PROVISIONED',
371708
+ status: 'False',
371709
+ message: e.toString(),
371710
+ };
371711
+ const statePr = item?.metadata?.annotations?.[cdktf_LAST_STATE_PR_ANNOTATION];
371712
+ if (statePr) {
371713
+ const summaryText = tryCreateErrorSummary('CDKTF Plan failed', e);
371714
+ await addPlanStatusCheck(statePr, summaryText, 'completed', true);
371715
+ }
371716
+ await handler.writeTerraformOutputInTfResult(item, e);
371717
+ void handler.error();
371718
+ }
371719
+ }
371720
+ /**
371721
+ * Detects if a Terraform plan output contains changes
371722
+ * Handles multiple Terraform versions and output formats
371723
+ * @param planOutput - The text output from terraform plan
371724
+ * @returns true if changes are detected, false otherwise
371725
+ */
371726
+ function detectPlanChanges(planOutput) {
371727
+ if (!planOutput || planOutput.trim().length === 0) {
371728
+ return false;
371729
+ }
371730
+ // Normalize the output for consistent matching
371731
+ const normalized = planOutput.toLowerCase();
371732
+ // Pattern 1: "Plan: X to add, Y to change, Z to destroy"
371733
+ // Matches: "Plan: 1 to add, 0 to change, 0 to destroy"
371734
+ const planPattern = /plan:\s*(\d+)\s+to\s+add,\s*(\d+)\s+to\s+change,\s*(\d+)\s+to\s+destroy/i;
371735
+ const planMatch = planOutput.match(planPattern);
371736
+ if (planMatch) {
371737
+ const add = Number(planMatch[1]);
371738
+ const change = Number(planMatch[2]);
371739
+ const destroy = Number(planMatch[3]);
371740
+ if (add > 0 || change > 0 || destroy > 0) {
371741
+ return true;
371742
+ }
371743
+ // Explicitly found "Plan:" with 0/0/0 - no changes
371744
+ return false;
371745
+ }
371746
+ // Pattern 2: Individual change indicators
371747
+ // Handles variations like "1 to add", "2 to change", "3 to destroy"
371748
+ const hasAdditions = /\d+\s+to\s+add/i.test(planOutput);
371749
+ const hasChanges = /\d+\s+to\s+change/i.test(planOutput);
371750
+ const hasDestructions = /\d+\s+to\s+destroy/i.test(planOutput);
371751
+ const hasImports = /\d+\s+to\s+import/i.test(planOutput);
371752
+ if (hasAdditions || hasChanges || hasDestructions || hasImports) {
371753
+ return true;
371754
+ }
371755
+ // Pattern 3: Resource-level change indicators
371756
+ // Matches: "# resource will be created", "# resource will be updated", etc.
371757
+ const resourceChangePatterns = [
371758
+ /will\s+be\s+(created|destroyed|updated|replaced)/i,
371759
+ /must\s+be\s+(created|destroyed|updated|replaced)/i,
371760
+ /#.*\s+(create|destroy|update|replace)/i,
371761
+ ];
371762
+ for (const pattern of resourceChangePatterns) {
371763
+ if (pattern.test(planOutput)) {
371764
+ return true;
371765
+ }
371766
+ }
371767
+ // Pattern 4: Action symbols in plan output
371768
+ // Terraform uses symbols like +, -, ~, -/+ to indicate changes
371769
+ const actionSymbols = [
371770
+ /^\s*[+]\s+/m,
371771
+ /^\s*[-]\s+/m,
371772
+ /^\s*[~]\s+/m,
371773
+ /^\s*[-][/][+]\s+/m, // Replace
371774
+ ];
371775
+ for (const pattern of actionSymbols) {
371776
+ if (pattern.test(planOutput)) {
371777
+ return true;
371778
+ }
371779
+ }
371780
+ // Pattern 5: No changes messages (inverse check)
371781
+ const noChangesPatterns = [
371782
+ /no\s+changes/i,
371783
+ /infrastructure\s+is\s+up[-\s]to[-\s]date/i,
371784
+ /your\s+infrastructure\s+matches\s+the\s+configuration/i,
371785
+ /0\s+to\s+add,\s*0\s+to\s+change,\s*0\s+to\s+destroy/i,
371786
+ ];
371787
+ for (const pattern of noChangesPatterns) {
371788
+ if (pattern.test(planOutput)) {
371789
+ return false;
371790
+ }
371791
+ }
371792
+ // If we find "Plan:" keyword but couldn't parse it, log a warning and assume no changes
371793
+ if (normalized.includes('plan:')) {
371794
+ operator_src_logger.warn('Found "Plan:" in output but could not parse change counts. Assuming no changes.');
371795
+ return false;
371796
+ }
371797
+ // Default: assume no changes if we can't detect any
371798
+ return false;
371799
+ }
371449
371800
  function cleanTerraformState() {
371450
371801
  external_fs_.rmSync('/library/packages/provisioner/cdktf.out', {
371451
371802
  recursive: true,
@@ -372445,40 +372796,6 @@ function tf_checkrun_helperCreateCheckRunName(cmd) {
372445
372796
  return `TFWorkspace - ${cmd}`;
372446
372797
  }
372447
372798
 
372448
- ;// CONCATENATED MODULE: ../operator/src/utils/index.ts
372449
- const secretRegex = /\$\{\{ secrets\.(.*?) \}\}/g;
372450
- function replaceConfigSecrets(config, secrets) {
372451
- for (const key in config) {
372452
- if (typeof config[key] === 'object' && config[key] !== null) {
372453
- // If the property is an object, call this function recursively
372454
- replaceConfigSecrets(config[key], secrets);
372455
- }
372456
- else if (typeof config[key] === 'string') {
372457
- // If the property is a string and its value is equal to secrets.something,
372458
- // replace the value with the value of the 'something' key in the secrets object
372459
- config[key] = config[key].replace(secretRegex, (_, group1) => {
372460
- if (!secrets[group1]) {
372461
- throw new Error(`Secret ${group1} not found in secrets`);
372462
- }
372463
- return secrets[group1];
372464
- });
372465
- }
372466
- }
372467
- return config;
372468
- }
372469
- function replaceInlineSecrets(inline, secrets) {
372470
- if (typeof inline !== 'string' || !inline)
372471
- return inline;
372472
- let result = inline;
372473
- result = result.replace(secretRegex, (_, group1) => {
372474
- if (!secrets[group1]) {
372475
- throw new Error(`Secret ${group1} not found in secrets`);
372476
- }
372477
- return secrets[group1];
372478
- });
372479
- return result;
372480
- }
372481
-
372482
372799
  ;// CONCATENATED MODULE: ../operator/src/tfworkspaces/process-operation.ts
372483
372800
 
372484
372801
 
@@ -372491,6 +372808,7 @@ function replaceInlineSecrets(inline, secrets) {
372491
372808
 
372492
372809
 
372493
372810
 
372811
+
372494
372812
  const TF_PROJECTS_PATH = '/tmp/tfworkspaces';
372495
372813
  function process_operation_processOperation(item, op, handler) {
372496
372814
  try {
@@ -372626,28 +372944,28 @@ async function* doPlanJSONFormat(item, op, handler) {
372626
372944
  reason: op,
372627
372945
  type: 'PROVISIONED',
372628
372946
  status: 'False',
372629
- message: JSON.stringify(e),
372947
+ message: PLAN_DEFAULT_ERROR_MESSAGE,
372630
372948
  };
372631
372949
  yield {
372632
372950
  item,
372633
372951
  reason: op,
372634
372952
  type: 'PLANNING',
372635
372953
  status: 'False',
372636
- message: JSON.stringify(e),
372954
+ message: PLAN_DEFAULT_ERROR_MESSAGE,
372637
372955
  };
372638
372956
  yield {
372639
372957
  item,
372640
372958
  reason: op,
372641
372959
  type: 'OUT_OF_SYNC',
372642
372960
  status: 'False',
372643
- message: 'Error observing item',
372961
+ message: PLAN_DEFAULT_ERROR_MESSAGE,
372644
372962
  };
372645
372963
  yield {
372646
372964
  item,
372647
372965
  reason: op,
372648
372966
  type: 'ERROR',
372649
372967
  status: 'True',
372650
- message: JSON.stringify(e),
372968
+ message: PLAN_DEFAULT_ERROR_MESSAGE,
372651
372969
  };
372652
372970
  const summaryText = tryCreateErrorSummary('Terraform Plan failed', e);
372653
372971
  if (item.metadata.annotations['firestartr.dev/last-state-pr'] || false) {
@@ -372669,11 +372987,6 @@ async function* process_operation_renamed(item, op, handler) {
372669
372987
  yield transition;
372670
372988
  }
372671
372989
  }
372672
- function getPolicy(item, annotation) {
372673
- const policy = item.metadata.annotations && item.metadata.annotations[annotation];
372674
- if (policy)
372675
- return policy;
372676
- }
372677
372990
  async function* process_operation_updated(item, op, handler) {
372678
372991
  for await (const transition of process_operation_doApply(item, op, handler)) {
372679
372992
  yield transition;
@@ -372818,7 +373131,7 @@ async function* process_operation_markedToDeletion(item, op, handler) {
372818
373131
  reason: op,
372819
373132
  type: 'ERROR',
372820
373133
  status: 'True',
372821
- message: e.toString(),
373134
+ message: DESTROY_DEFAULT_ERROR_MESSAGE,
372822
373135
  };
372823
373136
  await handler.writeTerraformOutputInTfResult(item, e);
372824
373137
  if (item.metadata.annotations['firestartr.dev/last-state-pr'] || false) {
@@ -372936,21 +373249,21 @@ async function* process_operation_doApply(item, op, handler) {
372936
373249
  reason: op,
372937
373250
  type: 'ERROR',
372938
373251
  status: 'True',
372939
- message: JSON.stringify(e),
373252
+ message: APPLY_DEFAULT_ERROR_MESSAGE,
372940
373253
  };
372941
373254
  yield {
372942
373255
  item,
372943
373256
  reason: op,
372944
373257
  type: 'PROVISIONED',
372945
373258
  status: 'False',
372946
- message: JSON.stringify(e),
373259
+ message: APPLY_DEFAULT_ERROR_MESSAGE,
372947
373260
  };
372948
373261
  yield {
372949
373262
  item,
372950
373263
  reason: op,
372951
373264
  type: 'PROVISIONING',
372952
373265
  status: 'False',
372953
- message: JSON.stringify(e),
373266
+ message: APPLY_DEFAULT_ERROR_MESSAGE,
372954
373267
  };
372955
373268
  handler.error();
372956
373269
  if (e) {
@@ -373313,11 +373626,12 @@ async function acquireLease(namespace, cb, interval = 10000) {
373313
373626
 
373314
373627
 
373315
373628
 
373629
+
373316
373630
  const processOperationPlan_TF_PROJECTS_PATH = '/tmp/tfworkspaces';
373317
373631
  function processOperationPlan(item, op, handler) {
373318
373632
  try {
373319
373633
  processOperationPlan_clearLocalTfProjects();
373320
- const policy = processOperationPlan_getPolicy(item);
373634
+ const policy = getPolicy(item, 'firestartr.dev/policy');
373321
373635
  if (policy === 'observe' || policy === 'apply') {
373322
373636
  return processOperationPlan_plan(item, op, handler);
373323
373637
  }
@@ -373426,21 +373740,21 @@ async function* doPlanPlainTextFormat(item, op, handler, action) {
373426
373740
  reason: op,
373427
373741
  type: 'PROVISIONED',
373428
373742
  status: 'False',
373429
- message: JSON.stringify(e),
373743
+ message: PLAN_DEFAULT_ERROR_MESSAGE,
373430
373744
  };
373431
373745
  yield {
373432
373746
  item,
373433
373747
  reason: op,
373434
373748
  type: 'PLANNING',
373435
373749
  status: 'False',
373436
- message: JSON.stringify(e),
373750
+ message: PLAN_DEFAULT_ERROR_MESSAGE,
373437
373751
  };
373438
373752
  yield {
373439
373753
  item,
373440
373754
  reason: op,
373441
373755
  type: 'ERROR',
373442
373756
  status: 'True',
373443
- message: JSON.stringify(e),
373757
+ message: PLAN_DEFAULT_ERROR_MESSAGE,
373444
373758
  };
373445
373759
  const summaryText = tryCreateErrorSummary('Terraform Plan failed', e);
373446
373760
  if (item.metadata.annotations['firestartr.dev/last-state-pr'] || false) {
@@ -373544,28 +373858,28 @@ async function* processOperationPlan_doPlanJSONFormat(item, op, handler, action)
373544
373858
  reason: op,
373545
373859
  type: 'PROVISIONED',
373546
373860
  status: 'False',
373547
- message: JSON.stringify(e),
373861
+ message: PLAN_DEFAULT_ERROR_MESSAGE,
373548
373862
  };
373549
373863
  yield {
373550
373864
  item,
373551
373865
  reason: op,
373552
373866
  type: 'PLANNING',
373553
373867
  status: 'False',
373554
- message: JSON.stringify(e),
373868
+ message: PLAN_DEFAULT_ERROR_MESSAGE,
373555
373869
  };
373556
373870
  yield {
373557
373871
  item,
373558
373872
  reason: op,
373559
373873
  type: 'OUT_OF_SYNC',
373560
373874
  status: 'False',
373561
- message: 'Error observing item',
373875
+ message: PLAN_DEFAULT_ERROR_MESSAGE,
373562
373876
  };
373563
373877
  yield {
373564
373878
  item,
373565
373879
  reason: op,
373566
373880
  type: 'ERROR',
373567
373881
  status: 'True',
373568
- message: JSON.stringify(e),
373882
+ message: PLAN_DEFAULT_ERROR_MESSAGE,
373569
373883
  };
373570
373884
  void handler.error();
373571
373885
  if (e) {
@@ -373764,12 +374078,6 @@ function processOperationPlan_getErrorOutputMessage(cr, key, ref) {
373764
374078
  throw new Error(`❌ Source ${cr.spec.source} not supported`);
373765
374079
  }
373766
374080
  }
373767
- function processOperationPlan_getPolicy(item) {
373768
- const policy = item.metadata.annotations &&
373769
- item.metadata.annotations['firestartr.dev/policy'];
373770
- if (policy)
373771
- return policy;
373772
- }
373773
374081
 
373774
374082
  ;// CONCATENATED MODULE: ../operator/src/ctx.ts
373775
374083
  class Ctx {