@intentius/terragucci 0.4.23 → 0.4.25

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire as __terragucciRequire } from 'node:module';
3
3
  const require = __terragucciRequire(import.meta.url);
4
- var cY=Object.defineProperty;var WI=(e,t)=>{for(var n in t)cY(e,n,{get:t[n],enumerable:!0})};import{spawnSync as MOe}from"node:child_process";import{existsSync as J9,readFileSync as X_,realpathSync as K9,unlinkSync as LOe,writeFileSync as V9}from"node:fs";import{dirname as Q_,join as Z9,relative as eS,resolve as Oe}from"node:path";import{fileURLToPath as GOe}from"node:url";import{execFileSync as sD}from"node:child_process";import{existsSync as Jr,readFileSync as Mn,readdirSync as Ew,statSync as JR}from"node:fs";import{dirname as _w,isAbsolute as Z7,join as Pt,relative as xw,resolve as Sw}from"node:path";import{createHash as uY}from"node:crypto";function mf(e){return`sha256:${uY("sha256").update(e,"utf8").digest("hex")}`}var gu=Symbol.for("chant.declarable");function Xe(e){return"props"in e}var lY=".declarable";function HI(e){return typeof e!="object"||e===null?!1:e[gu]===!0?!0:dY(e)}function dY(e){for(let t of Object.getOwnPropertySymbols(e)){let n=Object.getOwnPropertyDescriptor(e,t);if(!(n===void 0||n.enumerable||n.value!==!0)&&t.description?.endsWith(lY)===!0)return!0}return!1}function Wl(e){return e.kind==="property"}var Fs=Symbol.for("chant.intrinsic");function Ey(e){let t=tS(e,"$",new Set);if(t===void 0)throw new Error("canonicalJson: value at $ is not representable in JSON");return t}function tS(e,t,n){if(e!==null&&(typeof e=="object"||typeof e=="function")){let o=e.toJSON;typeof o=="function"&&(e=o.call(e))}if(e===void 0)return;if(e===null)return"null";switch(typeof e){case"boolean":return e?"true":"false";case"number":if(!Number.isFinite(e))throw new Error(`canonicalJson: non-finite number at ${t}`);return String(e);case"string":return JSON.stringify(e);case"bigint":throw new Error(`canonicalJson: bigint at ${t} is not representable in JSON`);case"function":case"symbol":throw new Error(`canonicalJson: ${typeof e} at ${t} is not representable in JSON`)}let r=e;if(n.has(r))throw new Error(`canonicalJson: circular structure at ${t}`);n.add(r);try{if(Array.isArray(r))return`[${r.map((a,c)=>tS(a,`${t}[${c}]`,n)??"null").join(",")}]`;let o=Object.keys(r).sort(),s=[];for(let i of o){let a=tS(r[i],`${t}.${i}`,n);a!==void 0&&s.push(`${JSON.stringify(i)}:${a}`)}return`{${s.join(",")}}`}finally{n.delete(r)}}var Ty="jcs1-sha256:",pY="sha256:",qI=/^(?:jcs1-)?sha256:([0-9a-f]{64})$/;function Rn(e,t){return Ty+mf(Ey({kind:e,subject:t})).slice(pY.length)}function Ie(e,t){if(e===t)return!0;if(e===void 0||t===void 0)return!1;let n=qI.exec(e),r=qI.exec(t);return n!==null&&r!==null&&n[1]===r[1]}var fY="https://intentius.io/chant/schemas/workspace/change-set/v1/change-set.schema.json",gY=1,mY=["create","update","replace","delete","read","no-op","forget"];var Pi=(e,t)=>e<t?-1:e>t?1:0;function Ay(e){return`${e.member}\0${e.address}\0${e.deposed??""}\0${e.action}`}var KI=(e,t)=>Pi(e.member,t.member)||Pi(e.address,t.address)||Pi(e.trigger??"",t.trigger??"");function Wa(e){let t=e.filter(n=>n.provisional!==!0).map(n=>({member:n.member,planDigest:n.planDigest})).sort((n,r)=>Pi(n.member,r.member));for(let n=1;n<t.length;n++)if(t[n-1].member===t[n].member)throw new Error(`the change set names member ${t[n].member} twice`);return Rn("change-set",t)}function hY(e){let t=new Set(e.members.filter(s=>s.provisional===!0).map(s=>s.member)),n=e.members.filter(s=>!t.has(s.member)).map(s=>({member:s.member,status:s.status,holes:s.holes})).sort((s,i)=>Pi(s.member,i.member)),r=e.entries.filter(s=>!t.has(s.member)).sort((s,i)=>Pi(Ay(s),Ay(i))),o=(e.sideEffects??[]).filter(s=>!t.has(s.member)).sort(KI);return Rn("change-set-document",{set:Wa(e.members),members:n,entries:r,sideEffects:o})}function yY(e,t){let n=Object.fromEntries(mY.map(c=>[c,0])),r={},o={},s=[],i=[],a=(c,u,l)=>{let d=c[u]??={};d[l]=(d[l]??0)+1};for(let c of t){n[c.action]++,a(r,c.type,c.action),a(o,c.member,c.action);let u={member:c.member,address:c.address,type:c.type,...c.deposed!==void 0?{deposed:c.deposed}:{},...c.disruption!==void 0?{disruption:c.disruption}:{}};c.action==="delete"&&s.push(u),c.action==="replace"&&i.push(u)}return{members:e.length,entries:t.length,actions:n,types:JI(r),byMember:JI(o),deletes:s,replacements:i,failed:e.filter(c=>c.status==="failed").map(c=>c.member),holes:e.reduce((c,u)=>c+u.holes.length,0)}}function JI(e){return Object.fromEntries(Object.entries(e).sort(([t],[n])=>Pi(t,n)))}function nS(e,t={}){let n=e.map(i=>i.member).sort((i,a)=>Pi(i.member,a.member)),r=[];for(let i of e)for(let a of i.entries){if(a.member!==i.member.member)throw new Error(`an entry at ${a.address} names member ${a.member}, inside member ${i.member.member}`);r.push(a)}r.sort((i,a)=>Pi(Ay(i),Ay(a)));let o=e.flatMap(i=>(i.sideEffects??[]).map(a=>({member:i.member.member,...a}))).sort(KI),s=hY({members:n,entries:r,sideEffects:o});return{$schema:fY,contract:gY,...t.chant!==void 0?{chant:t.chant}:{},digest:s,members:n,entries:r,...o.length>0?{sideEffects:o}:{},summary:yY(n,r)}}var rS=class extends Error{constructor(n,r){super(`canary names "${n}", which is not in this set (known: ${r.join(", ")||"none"})`);this.canary=n;this.name="UnknownCanaryError"}canary},oS=class extends Error{constructor(n){super(`dependency cycle among: ${n.join(", ")}`);this.members=n;this.name="WaveCycleError"}members};function VI(e,t={}){let n=new Set(e.map(c=>c.name)),r=new Set([...n,...t.known??[]]);for(let c of t.canary??[])if(!r.has(c))throw new rS(c,[...r].sort());let o=[...new Set((t.canary??[]).filter(c=>n.has(c)))].sort(),s=o.length>0?[o]:[],i=new Set([...n].filter(c=>!o.includes(c))),a=new Map(e.map(c=>[c.name,(c.dependsOn??[]).filter(u=>i.has(u))]));for(;i.size>0;){let c=[...i].filter(u=>a.get(u).every(l=>!i.has(l))).sort();if(c.length===0)throw new oS([...i].sort());for(let u of c)i.delete(u);s.push(c)}return s}var sS=class extends Error{constructor(n){super(`a wave cannot be gated on a provisional plan: ${n.join(", ")} planned before what it reads applied. Plan it again in its own wave, after its upstream applied`);this.members=n;this.name="ProvisionalWaveMemberError"}members};function mu(e){let t=e.filter(n=>n.provisional===!0).map(n=>n.member);if(t.length>0)throw new sS([...new Set(t)].sort());return Wa(e)}var ZI="1.1.0",hu=["catalog/**","**/.terragrunt-cache/**"];function wY(e){let t=/v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/.exec(e);if(t)return{major:Number(t[1]),minor:Number(t[2]),patch:Number(t[3]),...t[4]?{pre:t[4]}:{},raw:t[0]}}function QI(e){let t=wY(e);if(!t)return`could not read a version from \`terragrunt --version\` (got ${JSON.stringify(e.trim().slice(0,80))})`;let[n,r]=ZI.split(".").map(Number);if(!(t.major>n||t.major===n&&t.minor>=r))return`Terragrunt ${t.raw} is older than ${ZI}, the oldest release chant runs units with (run --all, find --dag and --filter as 1.1 ships them)`}function eC(e){return`{./${e}}`}function hf(e){return`!./${e.replace(/^\.\//,"")}`}function tC(e={}){return["find","--json","--dag","--dependencies","--include","--reading","--no-color",...[...hu,...e.exclude??[]].flatMap(n=>["--filter",hf(n)])]}var YI=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),XI=e=>Array.isArray(e)?e.filter(t=>typeof t=="string"):[],Hl=e=>e.replace(/\\/g,"/").replace(/^\.\//,"").replace(/\/+$/,"");function Py(e){let t=typeof e=="string"?JSON.parse(e.trim()===""?"[]":e):e;if(!Array.isArray(t))throw new Error("terragrunt find --json did not print an array");let n=[];for(let r of t){if(!YI(r)||r.type!=="unit"||typeof r.path!="string")continue;let o=YI(r.include)?Object.fromEntries(Object.entries(r.include).filter(i=>typeof i[1]=="string").map(([i,a])=>[i,Hl(a)])):void 0,s=Array.isArray(r.reading)?XI(r.reading).map(Hl):void 0;n.push({path:Hl(r.path),dependencies:[...new Set(XI(r.dependencies).map(Hl))].sort(),...o&&Object.keys(o).length>0?{include:o}:{},...s?{reading:s}:{}})}return n}function jy(e){let t=e.lastIndexOf("/");return t<=0?".":e.slice(0,t)}function ql(e,t){let n=Hl(t),r="";for(let o=0;o<n.length;o++){let s=n[o];s==="*"&&n[o+1]==="*"?n[o+2]==="/"?(r+="(?:.*/)?",o+=2):(r+=".*",o+=1):s==="*"?r+="[^/]*":s==="?"?r+="[^/]":r+=s.replace(/[.+^${}()|[\]\\]/g,"\\$&")}return new RegExp(`^${r}$`).test(e)}function bY(e){return e.map(t=>({name:t.path,dependsOn:t.dependencies}))}var Oy=class extends Error{constructor(t){super(t),this.name="TerragruntWaveError"}};function iS(e,t={}){let n=new Set((t.canary??[]).flatMap(i=>e.filter(a=>ql(a.path,i)).map(a=>a.path))),r=new Set(e.map(i=>i.path));for(let i of e){if(!n.has(i.path))continue;let a=i.dependencies.filter(c=>r.has(c)&&!n.has(c));if(a.length>0)throw new Oy(`canary ${i.path} depends on ${a.join(", ")}, which is not a canary, so the canary wave would apply it first`)}let o=bY(e),s=i=>{try{return VI(i)}catch(a){throw new Oy(a instanceof Error?a.message:String(a))}};return[...s(o.filter(i=>n.has(i.name))),...s(o.filter(i=>!n.has(i.name)))]}function aS(e,t,n=r=>r.dependencies){let r=new Set(t.map(Hl)),o=new Set(r),s=!0;for(;s;){s=!1;for(let i of e)o.has(i.path)||n(i).some(a=>o.has(a))&&(o.add(i.path),s=!0)}return[...o].filter(i=>!r.has(i)).sort()}var Vl=class extends Error{reason;mark;constructor(t,n){super(t),this.name="YAMLException",this.reason=t,this.mark=n}},yu={isObject:e=>typeof e=="object"&&e!==null,repeat:(e,t)=>e.repeat(Math.max(0,t))};var lS={tag:"tag:yaml.org,2002:null",kind:"scalar",resolve:e=>e===null||e==="~"||e==="null"||e==="Null"||e==="NULL",construct:()=>null},vY=e=>e>=48&&e<=57||e>=65&&e<=70||e>=97&&e<=102,$Y=e=>e>=48&&e<=55,kY=e=>e>=48&&e<=57;function _Y(e){if(e===null)return!1;let t=e.length,n=0,r=!1;if(!t)return!1;let o=e[n];if((o==="-"||o==="+")&&(o=e[++n]),o==="0"){if(n+1===t)return!0;o=e[++n];let s={b:i=>i===48||i===49,x:vY,o:$Y}[o];if(s){for(n++;n<t;n++){if(!s(e.charCodeAt(n)))return!1;r=!0}return r&&isFinite(uS(e))}}for(;n<t;n++){if(!kY(e.charCodeAt(n)))return!1;r=!0}return r?isFinite(uS(e)):!1}function uS(e){let t=e,n=1,r=t[0];if((r==="-"||r==="+")&&(r==="-"&&(n=-1),t=t.slice(1),r=t[0]),t==="0")return 0;if(r==="0"){if(t[1]==="b")return n*parseInt(t.slice(2),2);if(t[1]==="x")return n*parseInt(t.slice(2),16);if(t[1]==="o")return n*parseInt(t.slice(2),8)}return n*parseInt(t,10)}var dS={tag:"tag:yaml.org,2002:int",kind:"scalar",resolve:_Y,construct:uS},SY=new RegExp("^(?:[-+]?(?:[0-9]+)(?:\\.[0-9]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$"),RY=new RegExp("^(?:[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");function xY(e){return e===null||!SY.test(e)?!1:isFinite(parseFloat(e,10))?!0:RY.test(e)}var pS={tag:"tag:yaml.org,2002:float",kind:"scalar",resolve:xY,construct:e=>{let t=e.toLowerCase(),n=t[0]==="-"?-1:1;return"+-".indexOf(t[0])>=0&&(t=t.slice(1)),t===".inf"?n===1?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:t===".nan"?NaN:n*parseFloat(t,10)}},fS={tag:"tag:yaml.org,2002:str",kind:"scalar",construct:e=>e!==null?e:""},gS={tag:"tag:yaml.org,2002:seq",kind:"sequence",construct:e=>e!==null?e:[]},mS={tag:"tag:yaml.org,2002:map",kind:"mapping",construct:e=>e!==null?e:{}};for(let e of[lS,dS,pS,fS,gS,mS])e.resolve??=()=>!0;function EY(e,t){let n={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}};for(let r of[...e,...t])r.resolve??=()=>!0,r.construct??=o=>o,r.multi?(n.multi[r.kind].push(r),n.multi.fallback.push(r)):n[r.kind][r.tag]=n.fallback[r.tag]=r;return n}var Ii=Object.prototype.hasOwnProperty,Iy=1,lC=2,dC=3,Cy=4,cS=1,TY=2,nC=3,AY=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,OY=/[,\[\]{}]/,pC=/^(?:!|!!|![0-9A-Za-z-]+!)$/,fC=/^(?:!|[^,\[\]{}])(?:%[0-9a-f]{2}|[0-9a-z\-#;/?:@&=+$,_.!~*'()\[\]])*$/i;function rC(e){return Object.prototype.toString.call(e)}function zs(e){return e===10||e===13}function ji(e){return e===9||e===32}function Br(e){return e===9||e===32||e===10||e===13}function Jl(e){return e===44||e===91||e===93||e===123||e===125}function PY(e){if(e>=48&&e<=57)return e-48;let t=e|32;return t>=97&&t<=102?t-97+10:-1}function jY(e){return e===120?2:e===117?4:e===85?8:0}function IY(e){return e>=48&&e<=57?e-48:-1}function oC(e){switch(e){case 48:return"\0";case 97:return"\x07";case 98:return"\b";case 116:return" ";case 9:return" ";case 110:return`
4
+ var cY=Object.defineProperty;var WI=(e,t)=>{for(var n in t)cY(e,n,{get:t[n],enumerable:!0})};import{spawnSync as MOe}from"node:child_process";import{existsSync as J9,readFileSync as X_,realpathSync as K9,unlinkSync as LOe,writeFileSync as V9}from"node:fs";import{dirname as Q_,join as Z9,relative as eS,resolve as Oe}from"node:path";import{fileURLToPath as GOe}from"node:url";import{execFileSync as sD}from"node:child_process";import{existsSync as Jr,readFileSync as Mn,readdirSync as Ew,statSync as JR}from"node:fs";import{dirname as _w,isAbsolute as ZX,join as Pt,relative as xw,resolve as Sw}from"node:path";import{createHash as uY}from"node:crypto";function mf(e){return`sha256:${uY("sha256").update(e,"utf8").digest("hex")}`}var gu=Symbol.for("chant.declarable");function Xe(e){return"props"in e}var lY=".declarable";function HI(e){return typeof e!="object"||e===null?!1:e[gu]===!0?!0:dY(e)}function dY(e){for(let t of Object.getOwnPropertySymbols(e)){let n=Object.getOwnPropertyDescriptor(e,t);if(!(n===void 0||n.enumerable||n.value!==!0)&&t.description?.endsWith(lY)===!0)return!0}return!1}function Wl(e){return e.kind==="property"}var Fs=Symbol.for("chant.intrinsic");function Ey(e){let t=tS(e,"$",new Set);if(t===void 0)throw new Error("canonicalJson: value at $ is not representable in JSON");return t}function tS(e,t,n){if(e!==null&&(typeof e=="object"||typeof e=="function")){let o=e.toJSON;typeof o=="function"&&(e=o.call(e))}if(e===void 0)return;if(e===null)return"null";switch(typeof e){case"boolean":return e?"true":"false";case"number":if(!Number.isFinite(e))throw new Error(`canonicalJson: non-finite number at ${t}`);return String(e);case"string":return JSON.stringify(e);case"bigint":throw new Error(`canonicalJson: bigint at ${t} is not representable in JSON`);case"function":case"symbol":throw new Error(`canonicalJson: ${typeof e} at ${t} is not representable in JSON`)}let r=e;if(n.has(r))throw new Error(`canonicalJson: circular structure at ${t}`);n.add(r);try{if(Array.isArray(r))return`[${r.map((a,c)=>tS(a,`${t}[${c}]`,n)??"null").join(",")}]`;let o=Object.keys(r).sort(),s=[];for(let i of o){let a=tS(r[i],`${t}.${i}`,n);a!==void 0&&s.push(`${JSON.stringify(i)}:${a}`)}return`{${s.join(",")}}`}finally{n.delete(r)}}var Ty="jcs1-sha256:",pY="sha256:",qI=/^(?:jcs1-)?sha256:([0-9a-f]{64})$/;function Rn(e,t){return Ty+mf(Ey({kind:e,subject:t})).slice(pY.length)}function Ie(e,t){if(e===t)return!0;if(e===void 0||t===void 0)return!1;let n=qI.exec(e),r=qI.exec(t);return n!==null&&r!==null&&n[1]===r[1]}var fY="https://intentius.io/chant/schemas/workspace/change-set/v1/change-set.schema.json",gY=1,mY=["create","update","replace","delete","read","no-op","forget"];var Pi=(e,t)=>e<t?-1:e>t?1:0;function Ay(e){return`${e.member}\0${e.address}\0${e.deposed??""}\0${e.action}`}var KI=(e,t)=>Pi(e.member,t.member)||Pi(e.address,t.address)||Pi(e.trigger??"",t.trigger??"");function Wa(e){let t=e.filter(n=>n.provisional!==!0).map(n=>({member:n.member,planDigest:n.planDigest})).sort((n,r)=>Pi(n.member,r.member));for(let n=1;n<t.length;n++)if(t[n-1].member===t[n].member)throw new Error(`the change set names member ${t[n].member} twice`);return Rn("change-set",t)}function hY(e){let t=new Set(e.members.filter(s=>s.provisional===!0).map(s=>s.member)),n=e.members.filter(s=>!t.has(s.member)).map(s=>({member:s.member,status:s.status,holes:s.holes})).sort((s,i)=>Pi(s.member,i.member)),r=e.entries.filter(s=>!t.has(s.member)).sort((s,i)=>Pi(Ay(s),Ay(i))),o=(e.sideEffects??[]).filter(s=>!t.has(s.member)).sort(KI);return Rn("change-set-document",{set:Wa(e.members),members:n,entries:r,sideEffects:o})}function yY(e,t){let n=Object.fromEntries(mY.map(c=>[c,0])),r={},o={},s=[],i=[],a=(c,u,l)=>{let d=c[u]??={};d[l]=(d[l]??0)+1};for(let c of t){n[c.action]++,a(r,c.type,c.action),a(o,c.member,c.action);let u={member:c.member,address:c.address,type:c.type,...c.deposed!==void 0?{deposed:c.deposed}:{},...c.disruption!==void 0?{disruption:c.disruption}:{}};c.action==="delete"&&s.push(u),c.action==="replace"&&i.push(u)}return{members:e.length,entries:t.length,actions:n,types:JI(r),byMember:JI(o),deletes:s,replacements:i,failed:e.filter(c=>c.status==="failed").map(c=>c.member),holes:e.reduce((c,u)=>c+u.holes.length,0)}}function JI(e){return Object.fromEntries(Object.entries(e).sort(([t],[n])=>Pi(t,n)))}function nS(e,t={}){let n=e.map(i=>i.member).sort((i,a)=>Pi(i.member,a.member)),r=[];for(let i of e)for(let a of i.entries){if(a.member!==i.member.member)throw new Error(`an entry at ${a.address} names member ${a.member}, inside member ${i.member.member}`);r.push(a)}r.sort((i,a)=>Pi(Ay(i),Ay(a)));let o=e.flatMap(i=>(i.sideEffects??[]).map(a=>({member:i.member.member,...a}))).sort(KI),s=hY({members:n,entries:r,sideEffects:o});return{$schema:fY,contract:gY,...t.chant!==void 0?{chant:t.chant}:{},digest:s,members:n,entries:r,...o.length>0?{sideEffects:o}:{},summary:yY(n,r)}}var rS=class extends Error{constructor(n,r){super(`canary names "${n}", which is not in this set (known: ${r.join(", ")||"none"})`);this.canary=n;this.name="UnknownCanaryError"}canary},oS=class extends Error{constructor(n){super(`dependency cycle among: ${n.join(", ")}`);this.members=n;this.name="WaveCycleError"}members};function VI(e,t={}){let n=new Set(e.map(c=>c.name)),r=new Set([...n,...t.known??[]]);for(let c of t.canary??[])if(!r.has(c))throw new rS(c,[...r].sort());let o=[...new Set((t.canary??[]).filter(c=>n.has(c)))].sort(),s=o.length>0?[o]:[],i=new Set([...n].filter(c=>!o.includes(c))),a=new Map(e.map(c=>[c.name,(c.dependsOn??[]).filter(u=>i.has(u))]));for(;i.size>0;){let c=[...i].filter(u=>a.get(u).every(l=>!i.has(l))).sort();if(c.length===0)throw new oS([...i].sort());for(let u of c)i.delete(u);s.push(c)}return s}var sS=class extends Error{constructor(n){super(`a wave cannot be gated on a provisional plan: ${n.join(", ")} planned before what it reads applied. Plan it again in its own wave, after its upstream applied`);this.members=n;this.name="ProvisionalWaveMemberError"}members};function mu(e){let t=e.filter(n=>n.provisional===!0).map(n=>n.member);if(t.length>0)throw new sS([...new Set(t)].sort());return Wa(e)}var ZI="1.1.0",hu=["catalog/**","**/.terragrunt-cache/**"];function wY(e){let t=/v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/.exec(e);if(t)return{major:Number(t[1]),minor:Number(t[2]),patch:Number(t[3]),...t[4]?{pre:t[4]}:{},raw:t[0]}}function QI(e){let t=wY(e);if(!t)return`could not read a version from \`terragrunt --version\` (got ${JSON.stringify(e.trim().slice(0,80))})`;let[n,r]=ZI.split(".").map(Number);if(!(t.major>n||t.major===n&&t.minor>=r))return`Terragrunt ${t.raw} is older than ${ZI}, the oldest release chant runs units with (run --all, find --dag and --filter as 1.1 ships them)`}function eC(e){return`{./${e}}`}function hf(e){return`!./${e.replace(/^\.\//,"")}`}function tC(e={}){return["find","--json","--dag","--dependencies","--include","--reading","--no-color",...[...hu,...e.exclude??[]].flatMap(n=>["--filter",hf(n)])]}var YI=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),XI=e=>Array.isArray(e)?e.filter(t=>typeof t=="string"):[],Hl=e=>e.replace(/\\/g,"/").replace(/^\.\//,"").replace(/\/+$/,"");function Py(e){let t=typeof e=="string"?JSON.parse(e.trim()===""?"[]":e):e;if(!Array.isArray(t))throw new Error("terragrunt find --json did not print an array");let n=[];for(let r of t){if(!YI(r)||r.type!=="unit"||typeof r.path!="string")continue;let o=YI(r.include)?Object.fromEntries(Object.entries(r.include).filter(i=>typeof i[1]=="string").map(([i,a])=>[i,Hl(a)])):void 0,s=Array.isArray(r.reading)?XI(r.reading).map(Hl):void 0;n.push({path:Hl(r.path),dependencies:[...new Set(XI(r.dependencies).map(Hl))].sort(),...o&&Object.keys(o).length>0?{include:o}:{},...s?{reading:s}:{}})}return n}function jy(e){let t=e.lastIndexOf("/");return t<=0?".":e.slice(0,t)}function ql(e,t){let n=Hl(t),r="";for(let o=0;o<n.length;o++){let s=n[o];s==="*"&&n[o+1]==="*"?n[o+2]==="/"?(r+="(?:.*/)?",o+=2):(r+=".*",o+=1):s==="*"?r+="[^/]*":s==="?"?r+="[^/]":r+=s.replace(/[.+^${}()|[\]\\]/g,"\\$&")}return new RegExp(`^${r}$`).test(e)}function bY(e){return e.map(t=>({name:t.path,dependsOn:t.dependencies}))}var Oy=class extends Error{constructor(t){super(t),this.name="TerragruntWaveError"}};function iS(e,t={}){let n=new Set((t.canary??[]).flatMap(i=>e.filter(a=>ql(a.path,i)).map(a=>a.path))),r=new Set(e.map(i=>i.path));for(let i of e){if(!n.has(i.path))continue;let a=i.dependencies.filter(c=>r.has(c)&&!n.has(c));if(a.length>0)throw new Oy(`canary ${i.path} depends on ${a.join(", ")}, which is not a canary, so the canary wave would apply it first`)}let o=bY(e),s=i=>{try{return VI(i)}catch(a){throw new Oy(a instanceof Error?a.message:String(a))}};return[...s(o.filter(i=>n.has(i.name))),...s(o.filter(i=>!n.has(i.name)))]}function aS(e,t,n=r=>r.dependencies){let r=new Set(t.map(Hl)),o=new Set(r),s=!0;for(;s;){s=!1;for(let i of e)o.has(i.path)||n(i).some(a=>o.has(a))&&(o.add(i.path),s=!0)}return[...o].filter(i=>!r.has(i)).sort()}var Vl=class extends Error{reason;mark;constructor(t,n){super(t),this.name="YAMLException",this.reason=t,this.mark=n}},yu={isObject:e=>typeof e=="object"&&e!==null,repeat:(e,t)=>e.repeat(Math.max(0,t))};var lS={tag:"tag:yaml.org,2002:null",kind:"scalar",resolve:e=>e===null||e==="~"||e==="null"||e==="Null"||e==="NULL",construct:()=>null},vY=e=>e>=48&&e<=57||e>=65&&e<=70||e>=97&&e<=102,$Y=e=>e>=48&&e<=55,kY=e=>e>=48&&e<=57;function _Y(e){if(e===null)return!1;let t=e.length,n=0,r=!1;if(!t)return!1;let o=e[n];if((o==="-"||o==="+")&&(o=e[++n]),o==="0"){if(n+1===t)return!0;o=e[++n];let s={b:i=>i===48||i===49,x:vY,o:$Y}[o];if(s){for(n++;n<t;n++){if(!s(e.charCodeAt(n)))return!1;r=!0}return r&&isFinite(uS(e))}}for(;n<t;n++){if(!kY(e.charCodeAt(n)))return!1;r=!0}return r?isFinite(uS(e)):!1}function uS(e){let t=e,n=1,r=t[0];if((r==="-"||r==="+")&&(r==="-"&&(n=-1),t=t.slice(1),r=t[0]),t==="0")return 0;if(r==="0"){if(t[1]==="b")return n*parseInt(t.slice(2),2);if(t[1]==="x")return n*parseInt(t.slice(2),16);if(t[1]==="o")return n*parseInt(t.slice(2),8)}return n*parseInt(t,10)}var dS={tag:"tag:yaml.org,2002:int",kind:"scalar",resolve:_Y,construct:uS},SY=new RegExp("^(?:[-+]?(?:[0-9]+)(?:\\.[0-9]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$"),RY=new RegExp("^(?:[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");function xY(e){return e===null||!SY.test(e)?!1:isFinite(parseFloat(e,10))?!0:RY.test(e)}var pS={tag:"tag:yaml.org,2002:float",kind:"scalar",resolve:xY,construct:e=>{let t=e.toLowerCase(),n=t[0]==="-"?-1:1;return"+-".indexOf(t[0])>=0&&(t=t.slice(1)),t===".inf"?n===1?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:t===".nan"?NaN:n*parseFloat(t,10)}},fS={tag:"tag:yaml.org,2002:str",kind:"scalar",construct:e=>e!==null?e:""},gS={tag:"tag:yaml.org,2002:seq",kind:"sequence",construct:e=>e!==null?e:[]},mS={tag:"tag:yaml.org,2002:map",kind:"mapping",construct:e=>e!==null?e:{}};for(let e of[lS,dS,pS,fS,gS,mS])e.resolve??=()=>!0;function EY(e,t){let n={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}};for(let r of[...e,...t])r.resolve??=()=>!0,r.construct??=o=>o,r.multi?(n.multi[r.kind].push(r),n.multi.fallback.push(r)):n[r.kind][r.tag]=n.fallback[r.tag]=r;return n}var Ii=Object.prototype.hasOwnProperty,Iy=1,lC=2,dC=3,Cy=4,cS=1,TY=2,nC=3,AY=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,OY=/[,\[\]{}]/,pC=/^(?:!|!!|![0-9A-Za-z-]+!)$/,fC=/^(?:!|[^,\[\]{}])(?:%[0-9a-f]{2}|[0-9a-z\-#;/?:@&=+$,_.!~*'()\[\]])*$/i;function rC(e){return Object.prototype.toString.call(e)}function zs(e){return e===10||e===13}function ji(e){return e===9||e===32}function Br(e){return e===9||e===32||e===10||e===13}function Jl(e){return e===44||e===91||e===93||e===123||e===125}function PY(e){if(e>=48&&e<=57)return e-48;let t=e|32;return t>=97&&t<=102?t-97+10:-1}function jY(e){return e===120?2:e===117?4:e===85?8:0}function IY(e){return e>=48&&e<=57?e-48:-1}function oC(e){switch(e){case 48:return"\0";case 97:return"\x07";case 98:return"\b";case 116:return" ";case 9:return" ";case 110:return`
5
5
  `;case 118:return"\v";case 102:return"\f";case 114:return"\r";case 101:return"\x1B";case 32:return" ";case 34:return'"';case 47:return"/";case 92:return"\\";case 78:return"\x85";case 95:return"\xA0";case 76:return"\u2028";case 80:return"\u2029";default:return""}}function CY(e){return e<=65535?String.fromCharCode(e):String.fromCharCode((e-65536>>10)+55296,(e-65536&1023)+56320)}function gC(e,t,n){t==="__proto__"?Object.defineProperty(e,t,{configurable:!0,enumerable:!0,writable:!0,value:n}):e[t]=n}var mC=new Array(256),hC=new Array(256);for(let e=0;e<256;e++)mC[e]=oC(e)?1:0,hC[e]=oC(e);function NY(e,t){this.input=e,this.implicitTypes=t.implicit,this.typeMap=EY(t.implicit,t.explicit),this.maxDepth=100,this.maxTotalMergeKeys=1e4,this.length=e.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.depth=0,this.totalMergeKeys=0,this.firstTabInLine=-1,this.documents=[],this.anchorMapTransactions=[]}function DY(e,t){let n={name:null,buffer:e.input.slice(0,-1),position:e.position,line:e.line,column:e.position-e.lineStart};return new Vl(t,n)}function we(e,t){throw DY(e,t)}function wu(e,t,n){let r=e.anchorMapTransactions;if(r.length!==0){let o=r[r.length-1];Ii.call(o,t)||(o[t]={existed:Ii.call(e.anchorMap,t),value:e.anchorMap[t]})}e.anchorMap[t]=n}function MY(e){e.anchorMapTransactions.push(Object.create(null))}function LY(e){let t=e.anchorMapTransactions.pop(),n=e.anchorMapTransactions;if(n.length===0)return;let r=n[n.length-1],o=Object.keys(t);for(let s=0,i=o.length;s<i;s+=1){let a=o[s];Ii.call(r,a)||(r[a]=t[a])}}function GY(e){let t=e.anchorMapTransactions.pop(),n=Object.keys(t);for(let r=n.length-1;r>=0;r-=1){let o=t[n[r]];o.existed?e.anchorMap[n[r]]=o.value:delete e.anchorMap[n[r]]}}function yC(e){return{position:e.position,line:e.line,lineStart:e.lineStart,lineIndent:e.lineIndent,firstTabInLine:e.firstTabInLine,tag:e.tag,anchor:e.anchor,kind:e.kind,result:e.result}}function sC(e,t){e.position=t.position,e.line=t.line,e.lineStart=t.lineStart,e.lineIndent=t.lineIndent,e.firstTabInLine=t.firstTabInLine,e.tag=t.tag,e.anchor=t.anchor,e.kind=t.kind,e.result=t.result}var iC={YAML:function(t,n,r){t.version!==null&&we(t,"duplication of %YAML directive"),r.length!==1&&we(t,"YAML directive accepts exactly one argument");let o=/^([0-9]+)\.([0-9]+)$/.exec(r[0]);o===null&&we(t,"ill-formed argument of the YAML directive"),parseInt(o[1],10)!==1&&we(t,"unacceptable YAML version of the document"),t.version=r[0]},TAG:function(t,n,r){let o;r.length!==2&&we(t,"TAG directive accepts exactly two arguments");let s=r[0];o=r[1],pC.test(s)||we(t,"ill-formed tag handle (first argument) of the TAG directive"),Ii.call(t.tagMap,s)&&we(t,'there is a previously declared suffix for "'+s+'" tag handle'),fC.test(o)||we(t,"ill-formed tag prefix (second argument) of the TAG directive");try{o=decodeURIComponent(o)}catch{we(t,"tag prefix is malformed: "+o)}t.tagMap[s]=o}};function Ha(e,t,n,r){if(t<n){let o=e.input.slice(t,n);if(r)for(let s=0,i=o.length;s<i;s+=1){let a=o.charCodeAt(s);a===9||a>=32&&a<=1114111||we(e,"expected valid JSON character")}else AY.test(o)&&we(e,"the stream contains non-printable characters");e.result+=o}}function aC(e){e.totalMergeKeys++,e.maxTotalMergeKeys!==-1&&e.totalMergeKeys>e.maxTotalMergeKeys&&we(e,"merge keys exceeded maxTotalMergeKeys ("+e.maxTotalMergeKeys+")")}function cC(e,t,n,r){yu.isObject(n)||we(e,"cannot merge mappings; the provided source object is unacceptable"),aC(e);let o=Object.keys(n);for(let s=0,i=o.length;s<i;s+=1){let a=o[s];aC(e),Ii.call(t,a)||(gC(t,a,n[a]),r[a]=!0)}}function Kl(e,t,n,r,o,s){if(Array.isArray(o)){o=Array.prototype.slice.call(o);for(let i=0,a=o.length;i<a;i+=1)Array.isArray(o[i])&&we(e,"nested arrays are not supported inside keys"),typeof o=="object"&&rC(o[i])==="[object Object]"&&(o[i]="[object Object]")}if(typeof o=="object"&&rC(o)==="[object Object]"&&(o="[object Object]"),o=String(o),t===null&&(t={}),r==="tag:yaml.org,2002:merge")if(Array.isArray(s)){s.length>100&&we(e,"abnormal merge sequence size");for(let i=0,a=s.length;i<a;i+=1)cC(e,t,s[i],n)}else cC(e,t,s,n);else gC(t,o,s),delete n[o];return t}function hS(e){let t=e.input.charCodeAt(e.position);t===10?e.position++:t===13?(e.position++,e.input.charCodeAt(e.position)===10&&e.position++):we(e,"a line break is expected"),e.line+=1,e.lineStart=e.position,e.firstTabInLine=-1}function mn(e,t,n){let r=0,o=e.input.charCodeAt(e.position);for(;o!==0;){for(;ji(o);)o===9&&e.firstTabInLine===-1&&(e.firstTabInLine=e.position),o=e.input.charCodeAt(++e.position);if(t&&o===35)do o=e.input.charCodeAt(++e.position);while(o!==10&&o!==13&&o!==0);if(zs(o))for(hS(e),o=e.input.charCodeAt(e.position),r++,e.lineIndent=0;o===32;)e.lineIndent++,o=e.input.charCodeAt(++e.position);else break}return r}function Ny(e){let t=e.position,n=e.input.charCodeAt(t);return!!((n===45||n===46)&&n===e.input.charCodeAt(t+1)&&n===e.input.charCodeAt(t+2)&&(t+=3,n=e.input.charCodeAt(t),n===0||Br(n)))}function yS(e,t){t===1?e.result+=" ":t>1&&(e.result+=yu.repeat(`
6
6
  `,t-1))}function FY(e,t,n){let r,o,s,i,a,c,u=e.kind,l=e.result,d=e.input.charCodeAt(e.position);if(Br(d)||Jl(d)||d===35||d===38||d===42||d===33||d===124||d===62||d===39||d===34||d===37||d===64||d===96)return!1;if(d===63||d===45){let p=e.input.charCodeAt(e.position+1);if(Br(p)||n&&Jl(p))return!1}for(e.kind="scalar",e.result="",r=o=e.position,s=!1;d!==0;){if(d===58){let p=e.input.charCodeAt(e.position+1);if(Br(p)||n&&Jl(p))break}else if(d===35){let p=e.input.charCodeAt(e.position-1);if(Br(p))break}else{if(e.position===e.lineStart&&Ny(e)||n&&Jl(d))break;if(zs(d))if(i=e.line,a=e.lineStart,c=e.lineIndent,mn(e,!1,-1),e.lineIndent>=t){s=!0,d=e.input.charCodeAt(e.position);continue}else{e.position=o,e.line=i,e.lineStart=a,e.lineIndent=c;break}}s&&(Ha(e,r,o,!1),yS(e,e.line-i),r=o=e.position,s=!1),ji(d)||(o=e.position+1),d=e.input.charCodeAt(++e.position)}return Ha(e,r,o,!1),e.result?!0:(e.kind=u,e.result=l,!1)}function zY(e,t){let n,r,o=e.input.charCodeAt(e.position);if(o!==39)return!1;for(e.kind="scalar",e.result="",e.position++,n=r=e.position;(o=e.input.charCodeAt(e.position))!==0;)if(o===39)if(Ha(e,n,e.position,!0),o=e.input.charCodeAt(++e.position),o===39)n=e.position,e.position++,r=e.position;else return!0;else zs(o)?(Ha(e,n,r,!0),yS(e,mn(e,!1,t)),n=r=e.position):e.position===e.lineStart&&Ny(e)?we(e,"unexpected end of the document within a single quoted scalar"):(e.position++,ji(o)||(r=e.position));we(e,"unexpected end of the stream within a single quoted scalar")}function UY(e,t){let n,r,o,s=e.input.charCodeAt(e.position);if(s!==34)return!1;for(e.kind="scalar",e.result="",e.position++,n=r=e.position;(s=e.input.charCodeAt(e.position))!==0;){if(s===34)return Ha(e,n,e.position,!0),e.position++,!0;if(s===92){if(Ha(e,n,e.position,!0),s=e.input.charCodeAt(++e.position),zs(s))mn(e,!1,t);else if(s<256&&mC[s])e.result+=hC[s],e.position++;else if((o=jY(s))>0){let i=o,a=0;for(;i>0;i--)s=e.input.charCodeAt(++e.position),(o=PY(s))>=0?a=(a<<4)+o:we(e,"expected hexadecimal character");e.result+=CY(a),e.position++}else we(e,"unknown escape sequence");n=r=e.position}else zs(s)?(Ha(e,n,r,!0),yS(e,mn(e,!1,t)),n=r=e.position):e.position===e.lineStart&&Ny(e)?we(e,"unexpected end of the document within a double quoted scalar"):(e.position++,ji(s)||(r=e.position))}we(e,"unexpected end of the stream within a double quoted scalar")}function BY(e,t){let n=!0,r,o=e.tag,s,i=e.anchor,a,c,u,l,d=Object.create(null),p,f,g,m=e.input.charCodeAt(e.position);if(m===91)a=93,l=!1,s=[];else if(m===123)a=125,l=!0,s={};else return!1;for(e.anchor!==null&&wu(e,e.anchor,s),m=e.input.charCodeAt(++e.position);m!==0;){if(mn(e,!0,t),m=e.input.charCodeAt(e.position),m===a)return e.position++,e.tag=o,e.anchor=i,e.kind=l?"mapping":"sequence",e.result=s,!0;if(n?m===44&&we(e,"expected the node content, but found ','"):we(e,"missed comma between flow collection entries"),f=p=g=null,c=u=!1,m===63){let h=e.input.charCodeAt(e.position+1);Br(h)&&(c=u=!0,e.position++,mn(e,!0,t))}r=e.line,Zl(e,t,Iy,!1,!0),f=e.tag,p=e.result,mn(e,!0,t),m=e.input.charCodeAt(e.position),(u||e.line===r)&&m===58&&(c=!0,m=e.input.charCodeAt(++e.position),mn(e,!0,t),Zl(e,t,Iy,!1,!0),g=e.result),l?Kl(e,s,d,f,p,g):c?s.push(Kl(e,null,d,f,p,g)):s.push(p),mn(e,!0,t),m=e.input.charCodeAt(e.position),m===44?(n=!0,m=e.input.charCodeAt(++e.position)):n=!1}we(e,"unexpected end of the stream within a flow collection")}function WY(e,t){let n,r=cS,o=!1,s=!1,i=t,a=0,c=!1,u,l=e.input.charCodeAt(e.position);if(l===124)n=!1;else if(l===62)n=!0;else return!1;for(e.kind="scalar",e.result="";l!==0;)if(l=e.input.charCodeAt(++e.position),l===43||l===45)cS===r?r=l===43?nC:TY:we(e,"repeat of a chomping mode identifier");else if((u=IY(l))>=0)u===0?we(e,"bad explicit indentation width of a block scalar; it cannot be less than one"):s?we(e,"repeat of an indentation width identifier"):(i=t+u-1,s=!0);else break;if(ji(l)){do l=e.input.charCodeAt(++e.position);while(ji(l));if(l===35)do l=e.input.charCodeAt(++e.position);while(!zs(l)&&l!==0)}for(;l!==0;){for(hS(e),e.lineIndent=0,l=e.input.charCodeAt(e.position);(!s||e.lineIndent<i)&&l===32;)e.lineIndent++,l=e.input.charCodeAt(++e.position);if(!s&&e.lineIndent>i&&(i=e.lineIndent),zs(l)){a++;continue}if(!s&&i===0&&we(e,"missing indentation for block scalar"),e.lineIndent<i){r===nC?e.result+=yu.repeat(`
7
7
  `,o?1+a:a):r===cS&&o&&(e.result+=`
@@ -31,43 +31,43 @@ var cY=Object.defineProperty;var WI=(e,t)=>{for(var n in t)cY(e,n,{get:t[n],enum
31
31
  ${n.join(`
32
32
  `)}`,n);let i=JSON.parse(JSON.stringify(e)),a=[i,i.defaults,...oe(i.projects)?Object.values(i.projects):[]];for(let c of a)if(oe(c)&&c.gate!==void 0&&(c.gate=lo(c.gate)),oe(c)&&oe(c.environments))for(let u of Object.values(c.environments))oe(u)&&u.gate!==void 0&&(u.gate=lo(u.gate));return i}function V5(e){let t=new Map;return(r=>{for(let o of $5(r)){if(o==="node_modules"||o.startsWith("."))continue;let s=TS(r,o);k5(s).isDirectory()||o.endsWith(".ts")&&!o.endsWith(".d.ts")&&!o.endsWith(".test.ts")&&t.set(HC(e,s).split("\\").join("/"),WC(s,"utf-8"))}})(e),t}var Z5="npm i -D @intentius/tsad-reference";async function Y5(e){let t;try{t=await import("@intentius/tsad-reference")}catch{throw new S(`${e} is TypeScript, which needs the TypeScript folder: ${Z5}`)}let{foldProject:n,EMPTY_HOST:r}=t,o=_5(AS(e)),s=HC(o,AS(e)).split("\\").join("/"),i=n(V5(o),{...r,profile:"data-host"}).verdicts.get(s);if(!i)throw new S(`${e}: not found`);if(i.kind==="run")throw new S(`${e} is not data (${i.rule}): ${i.reason}`);let a=Object.fromEntries(i.exports);if(!("default"in a))throw new S(`${e} must export the config as \`export default\``);return a.default}async function zC(e){let t=await import(S5(AS(e)).href);if(!("default"in t))throw new S(`${e} must export the config as \`export default\``);return t.default}var UC=e=>{let t=n=>n===null||typeof n!="object"?n:Array.isArray(n)?n.map(t):Object.fromEntries(Object.keys(n).sort().map(r=>[r,t(n[r])]));return JSON.stringify(t(JSON.parse(JSON.stringify(e??{}))))};async function Re(e,t="fold"){if(!BC(e))throw new S(`${e} does not exist`);if(e.endsWith(".ts")){if(t==="run")return Ni(await zC(e),e);let o=await Y5(e);if(t==="check"){let s=await zC(e);if(UC(o)!==UC(s))throw new S(`${e}: folding and running the config disagree, so it is not data`)}return Ni(o,e)}let n=WC(e,"utf-8"),r;try{r=e.endsWith(".json")?JSON.parse(n):n.trim()===""?{}:Yl(n)}catch(o){throw new S(`${e}: ${o.message}`)}return Ni(r,e)}function po(e){let n=e.replace(/^https?:\/\//,"").replace(/\.git$/,"").replace(/\/+$/,"").split("/");if(n.length<3||n.some(s=>s===""))throw new S(`project key "${e}" must be <host>/<owner>/<name>, such as github.com/acme/infra`);let[r,...o]=n;return{key:e,host:r,path:o.join("/"),owner:o.slice(0,-1).join("/"),name:o[o.length-1]}}function ir(e){let t=e.toLowerCase().replace(/:\d+$/,"");if(t==="github.com"||t.startsWith("github."))return"github";if(t==="gitlab.com"||t.startsWith("gitlab.")||t.includes(".gitlab."))return"gitlab";if(t==="codeberg.org"||t.startsWith("forgejo.")||t.startsWith("gitea.")||t.includes("forgejo"))return"forgejo"}function ue(e){if(e.projects)throw new S("this config lists projects, so it belongs to a control repo; run terragucci reconcile instead");return PS(Ky,e)}function ot(e,t){let n=e.projects?.[t];if(n===void 0)throw new S(`no project "${t}" in the config`);let r=PS(PS(Ky,e.defaults??{}),n??{}),o=[];if(r.environments&&(VC(r.environments,`projects["${t}"].environments`,o,r),o.push(...ZC(r,`projects["${t}"]`))),o.length)throw new S(`projects["${t}"] has ${o.length} problem(s) once the defaults are merged in:
33
33
  ${o.join(`
34
- `)}`,o);return r}function X5(e,t){if(!e||!t)return t??e;let n={...e};for(let[r,o]of Object.entries(t))n[r]={...e[r],...o};return n}function PS(e,t){let{defaults:n,projects:r,...o}=t,s={...e,...o,gate:lo(o.gate)??e.gate,env:{...e.env,...o.env??{}}};return o.oidc&&(s.oidc={...e.oidc,...o.oidc}),(e.terragrunt||o.terragrunt)&&(s.terragrunt={...e.terragrunt,...o.terragrunt}),(e.respond||o.respond)&&(s.respond={...e.respond,...o.respond}),(e.policy||o.policy)&&(s.policy={...e.policy,...o.policy}),(e.waves||o.waves)&&(s.waves={...e.waves,...o.waves}),(e.apply||o.apply)&&(s.apply={...e.apply,...o.apply}),(e.generate||o.generate)&&(s.generate=_S(e.generate,o.generate)),(e.environments||o.environments)&&(s.environments=X5(e.environments,o.environments)),s}import{spawn as C7}from"node:child_process";import{cpSync as N7,existsSync as tg,mkdirSync as D7,readdirSync as BR,readFileSync as KN,rmSync as M7,statSync as VN,writeFileSync as WR}from"node:fs";import{join as qr,relative as qN,resolve as ZN,sep as L7}from"node:path";import{existsSync as xR,readFileSync as ER}from"node:fs";import{isAbsolute as bX,join as md}from"node:path";import{createHash as vX}from"node:crypto";import{randomUUID as Q5}from"node:crypto";var XC=/\/api\/v4\/projects\/[^/]+\/terraform\/state\/([^/]+)\/?$/,YC=e=>typeof e=="string"&&e!==""?e:void 0;function Mf(e){if(!e)return!1;try{return XC.test(new URL(e).pathname)}catch{return!1}}function xn(e){try{let t=new URL(e);return`${t.protocol}//${t.host}${t.pathname}`}catch{return e}}var Su=(e,t,n)=>YC(e[n])??YC(t[`TF_HTTP_${n.toUpperCase()}`]);function QC(e,t=process.env){let n=Su(e,t,"address");if(!n||!Mf(n))return;let r=decodeURIComponent(new URL(n).pathname.match(XC)[1]),o=Su(e,t,"username"),s=Su(e,t,"password"),i=Su(e,t,"lock_address"),a=Su(e,t,"unlock_address");return{address:n,name:r,...i?{lockAddress:i}:{},...a?{unlockAddress:a}:{},lockMethod:Su(e,t,"lock_method")??"LOCK",unlockMethod:Su(e,t,"unlock_method")??"UNLOCK",...o||s?{auth:`Basic ${Buffer.from(`${o??""}:${s??""}`).toString("base64")}`}:{}}}var Lf=(e,t=!1)=>({...e.auth?{authorization:e.auth}:{},...t?{"content-type":"application/json"}:{}}),eX=e=>e.replace(/\/+$/,"");function Gf(e,t,n,r){let o=n===401?": the backend's username and password (TF_HTTP_USERNAME, TF_HTTP_PASSWORD) are not a token GitLab accepts":n===403?": the token may not read this project's state (reads need Developer)":"";return new Error(`GitLab answered ${n} to ${e} ${xn(t)}${o}${r&&!o?`: ${r.trim().slice(0,200)}`:""}`)}async function Yy(e,t){let n=await t(e.address,{method:"GET",headers:Lf(e)});if(n.status===404||n.status===204)return;let r=await n.text();if(!n.ok)throw Gf("a read of",e.address,n.status,r);let o;try{o=JSON.parse(r)}catch{throw new Error(`GitLab answered ${xn(e.address)} with no state`)}if(typeof o.serial!="number")throw new Error(`the state at ${xn(e.address)} has no serial`);return{serial:o.serial,...typeof o.lineage=="string"?{lineage:o.lineage}:{}}}var Zy=(e,t)=>`${eX(e.address)}/versions/${encodeURIComponent(t)}`;async function eN(e,t,n){let r=await n(Zy(e,t),{method:"HEAD",headers:Lf(e)});if(r.status===404)return!1;if(!r.ok)throw Gf("a check of",Zy(e,t),r.status,"");return!0}async function tN(e,t,n){let r=await n(Zy(e,t),{method:"GET",headers:Lf(e)});if(r.status===404)return;let o=await r.text();if(!r.ok)throw Gf("a read of",Zy(e,t),r.status,o);return o}async function $R(e,t){if(!e.lockAddress||!e.unlockAddress)throw new Error(`the http backend of ${xn(e.address)} names no ${e.lockAddress?"unlock_address":"lock_address"}`);let n=`terragucci-probe-${Q5()}`,r=JSON.stringify({ID:n,Operation:"OperationTypeInvalid",Info:"terragucci reads who holds the lock",Who:"terragucci",Version:"",Created:new Date().toISOString(),Path:""}),o=await t(e.lockAddress,{method:e.lockMethod,headers:Lf(e,!0),body:r}),s=await o.text();if(o.status===409||o.status===423)return tX(s);if(!o.ok)throw Gf("a lock of",e.lockAddress,o.status,s);await kR(e,n,t)}function tX(e){try{let t=JSON.parse(e);return JSON.stringify(Object.fromEntries(["ID","Who","Created"].filter(n=>typeof t[n]=="string").map(n=>[n,t[n]])))}catch{return e}}async function kR(e,t,n){if(!e.unlockAddress)throw new Error(`the http backend of ${xn(e.address)} names no unlock_address`);let r=await n(e.unlockAddress,{method:e.unlockMethod,headers:Lf(e,!0),body:JSON.stringify({ID:t})}),o=await r.text();if(r.status===409||r.status===423)throw new Error(`GitLab did not release lock ${t} on ${xn(e.unlockAddress)}: another lock holds the state now`);if(!r.ok)throw Gf("a release of",e.unlockAddress,r.status,o)}function Xy(e,t){let n;try{n=new URL(e)}catch{return}let r=n.pathname.match(/^(.*\/api\/v4\/projects\/[^/]+\/terraform\/state\/)([^/]+?)(\/lock)?\/?$/);if(r)return n.pathname=`${r[1]}${r[2]}-${t}${r[3]??""}`,n.toString()}import{createHmac as nX}from"node:crypto";import{readFileSync as rX}from"node:fs";var _R="2021-08-06",Qy="https://login.microsoftonline.com",oX="https://storage.azure.com/.default";function nN(e,t=process.env){let n={account:e.account,container:e.container,endpoint:(e.endpoint??`https://${e.account}.blob.core.windows.net`).replace(/\/+$/,"")};if(t.AZURE_STORAGE_KEY)return{...n,accountKey:t.AZURE_STORAGE_KEY};let r=t.ARM_TENANT_ID,o=t.ARM_CLIENT_ID,s=t.ARM_OIDC_TOKEN_FILE_PATH;if(r&&o&&s)return{...n,oidc:{tenantId:r,clientId:o,tokenFile:s,authority:(t.AZURE_AUTHORITY_HOST||Qy).replace(/\/+$/,"")}};throw new Y(`reports.bucket is az://${e.account}/${e.container}, but the job has no credentials for it: give the job oidc.azure (it sets ARM_TENANT_ID, ARM_CLIENT_ID and ARM_OIDC_TOKEN_FILE_PATH), or set AZURE_STORAGE_KEY`)}var rN=(e,t)=>nX("sha256",Buffer.from(e,"base64")).update(t,"utf8").digest("base64"),sX=["content-encoding","content-language","content-length","content-md5","content-type","date","if-modified-since","if-match","if-none-match","if-unmodified-since","range"];function iX(e,t,n,r,o){let s=new URL(r),i=Object.fromEntries(Object.entries(o).map(([p,f])=>[p.toLowerCase(),f])),a=sX.map(p=>p==="content-length"&&i[p]==="0"?"":i[p]??""),c=Object.keys(i).filter(p=>p.startsWith("x-ms-")).sort().map(p=>`${p}:${i[p].trim()}
34
+ `)}`,o);return r}function X5(e,t){if(!e||!t)return t??e;let n={...e};for(let[r,o]of Object.entries(t))n[r]={...e[r],...o};return n}function PS(e,t){let{defaults:n,projects:r,...o}=t,s={...e,...o,gate:lo(o.gate)??e.gate,env:{...e.env,...o.env??{}}};return o.oidc&&(s.oidc={...e.oidc,...o.oidc}),(e.terragrunt||o.terragrunt)&&(s.terragrunt={...e.terragrunt,...o.terragrunt}),(e.respond||o.respond)&&(s.respond={...e.respond,...o.respond}),(e.policy||o.policy)&&(s.policy={...e.policy,...o.policy}),(e.waves||o.waves)&&(s.waves={...e.waves,...o.waves}),(e.apply||o.apply)&&(s.apply={...e.apply,...o.apply}),(e.generate||o.generate)&&(s.generate=_S(e.generate,o.generate)),(e.environments||o.environments)&&(s.environments=X5(e.environments,o.environments)),s}import{spawn as CX}from"node:child_process";import{cpSync as NX,existsSync as tg,mkdirSync as DX,readdirSync as BR,readFileSync as KN,rmSync as MX,statSync as VN,writeFileSync as WR}from"node:fs";import{join as qr,relative as qN,resolve as ZN,sep as LX}from"node:path";import{existsSync as xR,readFileSync as ER}from"node:fs";import{isAbsolute as b7,join as md}from"node:path";import{createHash as v7}from"node:crypto";import{randomUUID as Q5}from"node:crypto";var XC=/\/api\/v4\/projects\/[^/]+\/terraform\/state\/([^/]+)\/?$/,YC=e=>typeof e=="string"&&e!==""?e:void 0;function Mf(e){if(!e)return!1;try{return XC.test(new URL(e).pathname)}catch{return!1}}function xn(e){try{let t=new URL(e);return`${t.protocol}//${t.host}${t.pathname}`}catch{return e}}var Su=(e,t,n)=>YC(e[n])??YC(t[`TF_HTTP_${n.toUpperCase()}`]);function QC(e,t=process.env){let n=Su(e,t,"address");if(!n||!Mf(n))return;let r=decodeURIComponent(new URL(n).pathname.match(XC)[1]),o=Su(e,t,"username"),s=Su(e,t,"password"),i=Su(e,t,"lock_address"),a=Su(e,t,"unlock_address");return{address:n,name:r,...i?{lockAddress:i}:{},...a?{unlockAddress:a}:{},lockMethod:Su(e,t,"lock_method")??"LOCK",unlockMethod:Su(e,t,"unlock_method")??"UNLOCK",...o||s?{auth:`Basic ${Buffer.from(`${o??""}:${s??""}`).toString("base64")}`}:{}}}var Lf=(e,t=!1)=>({...e.auth?{authorization:e.auth}:{},...t?{"content-type":"application/json"}:{}}),e7=e=>e.replace(/\/+$/,"");function Gf(e,t,n,r){let o=n===401?": the backend's username and password (TF_HTTP_USERNAME, TF_HTTP_PASSWORD) are not a token GitLab accepts":n===403?": the token may not read this project's state (reads need Developer)":"";return new Error(`GitLab answered ${n} to ${e} ${xn(t)}${o}${r&&!o?`: ${r.trim().slice(0,200)}`:""}`)}async function Yy(e,t){let n=await t(e.address,{method:"GET",headers:Lf(e)});if(n.status===404||n.status===204)return;let r=await n.text();if(!n.ok)throw Gf("a read of",e.address,n.status,r);let o;try{o=JSON.parse(r)}catch{throw new Error(`GitLab answered ${xn(e.address)} with no state`)}if(typeof o.serial!="number")throw new Error(`the state at ${xn(e.address)} has no serial`);return{serial:o.serial,...typeof o.lineage=="string"?{lineage:o.lineage}:{}}}var Zy=(e,t)=>`${e7(e.address)}/versions/${encodeURIComponent(t)}`;async function eN(e,t,n){let r=await n(Zy(e,t),{method:"HEAD",headers:Lf(e)});if(r.status===404)return!1;if(!r.ok)throw Gf("a check of",Zy(e,t),r.status,"");return!0}async function tN(e,t,n){let r=await n(Zy(e,t),{method:"GET",headers:Lf(e)});if(r.status===404)return;let o=await r.text();if(!r.ok)throw Gf("a read of",Zy(e,t),r.status,o);return o}async function $R(e,t){if(!e.lockAddress||!e.unlockAddress)throw new Error(`the http backend of ${xn(e.address)} names no ${e.lockAddress?"unlock_address":"lock_address"}`);let n=`terragucci-probe-${Q5()}`,r=JSON.stringify({ID:n,Operation:"OperationTypeInvalid",Info:"terragucci reads who holds the lock",Who:"terragucci",Version:"",Created:new Date().toISOString(),Path:""}),o=await t(e.lockAddress,{method:e.lockMethod,headers:Lf(e,!0),body:r}),s=await o.text();if(o.status===409||o.status===423)return t7(s);if(!o.ok)throw Gf("a lock of",e.lockAddress,o.status,s);await kR(e,n,t)}function t7(e){try{let t=JSON.parse(e);return JSON.stringify(Object.fromEntries(["ID","Who","Created"].filter(n=>typeof t[n]=="string").map(n=>[n,t[n]])))}catch{return e}}async function kR(e,t,n){if(!e.unlockAddress)throw new Error(`the http backend of ${xn(e.address)} names no unlock_address`);let r=await n(e.unlockAddress,{method:e.unlockMethod,headers:Lf(e,!0),body:JSON.stringify({ID:t})}),o=await r.text();if(r.status===409||r.status===423)throw new Error(`GitLab did not release lock ${t} on ${xn(e.unlockAddress)}: another lock holds the state now`);if(!r.ok)throw Gf("a release of",e.unlockAddress,r.status,o)}function Xy(e,t){let n;try{n=new URL(e)}catch{return}let r=n.pathname.match(/^(.*\/api\/v4\/projects\/[^/]+\/terraform\/state\/)([^/]+?)(\/lock)?\/?$/);if(r)return n.pathname=`${r[1]}${r[2]}-${t}${r[3]??""}`,n.toString()}import{createHmac as n7}from"node:crypto";import{readFileSync as r7}from"node:fs";var _R="2021-08-06",Qy="https://login.microsoftonline.com",o7="https://storage.azure.com/.default";function nN(e,t=process.env){let n={account:e.account,container:e.container,endpoint:(e.endpoint??`https://${e.account}.blob.core.windows.net`).replace(/\/+$/,"")};if(t.AZURE_STORAGE_KEY)return{...n,accountKey:t.AZURE_STORAGE_KEY};let r=t.ARM_TENANT_ID,o=t.ARM_CLIENT_ID,s=t.ARM_OIDC_TOKEN_FILE_PATH;if(r&&o&&s)return{...n,oidc:{tenantId:r,clientId:o,tokenFile:s,authority:(t.AZURE_AUTHORITY_HOST||Qy).replace(/\/+$/,"")}};throw new Y(`reports.bucket is az://${e.account}/${e.container}, but the job has no credentials for it: give the job oidc.azure (it sets ARM_TENANT_ID, ARM_CLIENT_ID and ARM_OIDC_TOKEN_FILE_PATH), or set AZURE_STORAGE_KEY`)}var rN=(e,t)=>n7("sha256",Buffer.from(e,"base64")).update(t,"utf8").digest("base64"),s7=["content-encoding","content-language","content-length","content-md5","content-type","date","if-modified-since","if-match","if-none-match","if-unmodified-since","range"];function i7(e,t,n,r,o){let s=new URL(r),i=Object.fromEntries(Object.entries(o).map(([p,f])=>[p.toLowerCase(),f])),a=s7.map(p=>p==="content-length"&&i[p]==="0"?"":i[p]??""),c=Object.keys(i).filter(p=>p.startsWith("x-ms-")).sort().map(p=>`${p}:${i[p].trim()}
35
35
  `).join(""),u=new Map;for(let[p,f]of s.searchParams)u.set(p.toLowerCase(),[...u.get(p.toLowerCase())??[],f]);let l=[...u.keys()].sort().map(p=>`
36
36
  ${p}:${u.get(p).sort().join(",")}`).join(""),d=[n,...a].join(`
37
37
  `)+`
38
- `+c+`/${e}${s.pathname}`+l;return`SharedKey ${e}:${rN(t,d)}`}function aX(e,t,n,r){let o=Gy(n),s=e.endpoint.startsWith("https:")?"https":"",i=`/blob/${e.account}/${e.container}/${t}`,a=[s,_R,"b","","","","","","",""],c,u;if("key"in r){let p=r.key;c=["r","",o,i,p.oid,p.tid,p.start,p.expiry,p.service,p.version,"","","","",...a].join(`
38
+ `+c+`/${e}${s.pathname}`+l;return`SharedKey ${e}:${rN(t,d)}`}function a7(e,t,n,r){let o=Gy(n),s=e.endpoint.startsWith("https:")?"https":"",i=`/blob/${e.account}/${e.container}/${t}`,a=[s,_R,"b","","","","","","",""],c,u;if("key"in r){let p=r.key;c=["r","",o,i,p.oid,p.tid,p.start,p.expiry,p.service,p.version,"","","","",...a].join(`
39
39
  `),u=[["skoid",p.oid],["sktid",p.tid],["skt",p.start],["ske",p.expiry],["sks",p.service],["skv",p.version]]}else c=["r","",o,i,"","",...a].join(`
40
40
  `),u=[];let l=rN("key"in r?r.key.value:r.accountKey,c);return new URLSearchParams([["sv",_R],["sr","b"],["sp","r"],["se",o],...s?[["spr",s]]:[],...u,["sig",l]]).toString()}var Mi=e=>{try{let t=JSON.parse(e);if(t.error)return[t.error,t.error_description?.split(`\r
41
41
  `)[0]].filter(Boolean).join(": ")}catch{}return[hn(e,"Code"),hn(e,"Message")?.split(`
42
- `)[0]].filter(Boolean).join(": ")||e.slice(0,300)},ud=class{constructor(t,n=fetch,r=o=>rX(o,"utf-8")){this.target=t;this.fetchFn=n;this.readToken=r}target;fetchFn;readToken;token;keys=new Map;get location(){return`az://${this.target.account}/${this.target.container}`}blobUrl(t,n=""){let r=this.target,o=[n,"sas"in r?r.sas.replace(/^\?/,""):""].filter(Boolean).join("&");return`${r.endpoint}/${r.container}/${Xl(t)}${o?`?${o}`:""}`}async bearer(t){let n=async()=>{let s;try{s=this.readToken(t.tokenFile).trim()}catch(l){throw new Y(`cannot read the OIDC token in ${t.tokenFile}: ${l.message}`)}if(!s)throw new Y(`the OIDC token file ${t.tokenFile} is empty`);let i=new URLSearchParams({client_id:t.clientId,scope:oX,grant_type:"client_credentials",client_assertion_type:"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",client_assertion:s}).toString(),a=await this.fetchFn(`${t.authority}/${t.tenantId}/oauth2/v2.0/token`,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:i}),c=await a.text();if(!a.ok)throw new Y(`Entra ID refused the OIDC token for client ${t.clientId}: ${a.status} ${Mi(c)}`);let u={};try{u=JSON.parse(c)}catch{}if(!u.access_token)throw new Y(`Entra ID answered client ${t.clientId} without a token`);return{token:u.access_token,expires:Date.now()+Number(u.expires_in??3600)*1e3}},r=()=>this.token=n().catch(s=>{throw this.token=void 0,s}),o=await(this.token??r());return o.expires-Date.now()<6e4&&(o=await r()),o.token}async headers(t,n,r){let o={"x-ms-date":new Date().toUTCString(),"x-ms-version":_R,...r},s=this.target;return"accountKey"in s?{...o,authorization:iX(s.account,s.accountKey,t,n,o)}:"sas"in s?o:{...o,authorization:`Bearer ${await this.bearer(s.oidc)}`}}async put(t,n,r,o){let s=this.blobUrl(t),i=o?"ifMatch"in o?{"if-match":o.ifMatch}:{"if-none-match":"*"}:{},a=typeof n=="string"?Buffer.byteLength(n):n.byteLength,c=await this.headers("PUT",s,{"x-ms-blob-type":"BlockBlob","content-type":r,"content-length":String(a),...i}),u=await this.fetchFn(s,{method:"PUT",headers:c,body:n});if(u.status===412||u.status===409&&o)throw new Er(`PUT ${this.location}/${t}: ${u.status}, it changed since it was read`);if(!u.ok)throw new Y(`PUT ${this.location}/${t}: ${u.status} ${Mi(await u.text())}`);let l=u.headers?.get("etag")??void 0;return l?{etag:l}:{}}async read(t){let n=this.blobUrl(t),r=await this.fetchFn(n,{method:"GET",headers:await this.headers("GET",n,{})});if(r.status===404)return{};if(!r.ok)throw new Y(`GET ${this.location}/${t}: ${r.status} ${Mi(await r.text())}`);let o=r.headers?.get("etag")??void 0;return{body:await r.text(),...o?{etag:o}:{}}}async get(t){return(await this.read(t)).body}async head(t,n){let r=this.blobUrl(t,n?new URLSearchParams(n).toString():""),o=await this.fetchFn(r,{method:"HEAD",headers:await this.headers("HEAD",r,{})});if(o.status===404||n&&o.status===400)return{exists:!1,metadata:{}};if(!o.ok)throw new Y(`HEAD ${this.location}/${t}: ${o.status}`);let s=d=>o.headers?.get(d)??void 0,i={};o.headers?.forEach?.((d,p)=>{p.toLowerCase().startsWith("x-ms-meta-")&&(i[p.toLowerCase().slice(10)]=d)});let c=s("etag"),u=s("x-ms-version-id"),l=s("x-ms-lease-state");return{exists:!0,...c?{etag:c}:{},...u?{versionId:u}:{},...l?{leaseState:l}:{},metadata:i}}async readAt(t,n){let r=this.blobUrl(t,new URLSearchParams(n).toString()),o=await this.fetchFn(r,{method:"GET",headers:await this.headers("GET",r,{})});if(!(o.status===404||o.status===400)){if(!o.ok)throw new Y(`GET ${this.location}/${t} ${JSON.stringify(n)}: ${o.status} ${Mi(await o.text())}`);return o.text()}}async snapshot(t){let n=this.blobUrl(t,"comp=snapshot"),r=await this.fetchFn(n,{method:"PUT",headers:await this.headers("PUT",n,{"content-length":"0"})});if(!r.ok)throw new Y(`snapshot of ${this.location}/${t}: ${r.status} ${Mi(await r.text())}`);let o=r.headers?.get("x-ms-snapshot");if(!o)throw new Y(`snapshot of ${this.location}/${t}: Azure answered without x-ms-snapshot`);return o}async putBlob(t,n,r,o={}){let s=this.blobUrl(t),i=Object.fromEntries(Object.entries(o.metadata??{}).map(([u,l])=>[`x-ms-meta-${u}`,l])),a={"x-ms-blob-type":"BlockBlob","content-type":r,"content-length":String(Buffer.byteLength(n)),...i,...o.leaseId?{"x-ms-lease-id":o.leaseId}:{},...o.ifNoneMatch?{"if-none-match":"*"}:{}},c=await this.fetchFn(s,{method:"PUT",headers:await this.headers("PUT",s,a),body:n});if(o.ifNoneMatch&&(c.status===409||c.status===412))return!1;if(!c.ok)throw new Y(`PUT ${this.location}/${t}: ${c.status} ${Mi(await c.text())}`);return!0}async lease(t,n,r){let o=this.blobUrl(t,"comp=lease"),s={"x-ms-lease-action":n,"content-length":"0",...n==="acquire"?{"x-ms-lease-duration":"-1","x-ms-proposed-lease-id":r}:{"x-ms-lease-id":r}},i=await this.fetchFn(o,{method:"PUT",headers:await this.headers("PUT",o,s)});if(n==="acquire"&&i.status===409)return!1;if(!i.ok)throw new Y(`${n} the lease of ${this.location}/${t}: ${i.status} ${Mi(await i.text())}`);return!0}async setMetadata(t,n,r){let o=this.blobUrl(t,"comp=metadata"),s={"content-length":"0",...Object.fromEntries(Object.entries(n).map(([a,c])=>[`x-ms-meta-${a}`,c])),...r?{"x-ms-lease-id":r}:{}},i=await this.fetchFn(o,{method:"PUT",headers:await this.headers("PUT",o,s)});if(!i.ok)throw new Y(`set the metadata of ${this.location}/${t}: ${i.status} ${Mi(await i.text())}`)}delegationKey(t,n){let r=Gy(n),o=this.keys.get(r);return o||(o=(async()=>{let s=`${this.target.endpoint}/?restype=service&comp=userdelegationkey`,i=`<?xml version="1.0" encoding="utf-8"?><KeyInfo><Start>${Gy(t)}</Start><Expiry>${r}</Expiry></KeyInfo>`,a=await this.fetchFn(s,{method:"POST",headers:await this.headers("POST",s,{"content-type":"application/xml"}),body:i}),c=await a.text();if(!a.ok)throw new Y(`Get User Delegation Key on ${this.target.account}: ${a.status} ${Mi(c)}`);let u=l=>{let d=hn(c,l);if(!d)throw new Y(`Get User Delegation Key on ${this.target.account} answered without ${l}`);return d};return{oid:u("SignedOid"),tid:u("SignedTid"),start:u("SignedStart"),expiry:u("SignedExpiry"),service:u("SignedService"),version:u("SignedVersion"),value:u("Value")}})(),o.catch(()=>this.keys.delete(r)),this.keys.set(r,o)),o}async presign(t,n,r=new Date){if(!Number.isInteger(n)||n<1||n>Jn)throw new Y(`a SAS link lives 1 to ${Jn} seconds, not ${n}`);let o=new Date(Math.floor(r.getTime()/1e3)*1e3+n*1e3),s=this.target,i=aX(s,t,o,"accountKey"in s?{accountKey:s.accountKey}:{key:await this.delegationKey(r,o)});return{url:`${this.blobUrl(t)}?${i}`,expires:o}}};import{createHash as uX,createSign as aN}from"node:crypto";import{readFileSync as lX}from"node:fs";import{readFileSync as cX}from"node:fs";var Ff="TERRAGUCCI_TRADED";function Li(e){let t=e[Ff];if(t)try{let n=JSON.parse(cX(t,"utf-8"));return{aws:n.aws??{},gcp:n.gcp??{}}}catch(n){throw new Y(`${Ff} names ${t}, which cannot be read: ${n.message}`)}}function Ru(e,t){let n=e.aws[t];if(!n)throw new Y(`the re-plan traded no credentials for ${t}`);return n}var ew="https://storage.googleapis.com",oN="https://iamcredentials.googleapis.com",SR="https://www.googleapis.com/auth/cloud-platform",dX="https://www.googleapis.com/auth/devstorage.read_write";function cN(e,t=process.env){let n=t.GOOGLE_APPLICATION_CREDENTIALS,r=!n&&t.GOOGLE_OAUTH_ACCESS_TOKEN?Li(t):void 0;if(r&&t.GOOGLE_OAUTH_ACCESS_TOKEN){let o=Object.entries(r.gcp).find(([,s])=>s.token===t.GOOGLE_OAUTH_ACCESS_TOKEN)?.[0];return{bucket:e.bucket,endpoint:(e.endpoint??ew).replace(/\/+$/,""),accessToken:t.GOOGLE_OAUTH_ACCESS_TOKEN,...o?{signAs:o}:{}}}if(!n)throw new Y(`reports.bucket is gs://${e.bucket}, but the job has no credentials for it: give the job oidc.gcp (it sets GOOGLE_APPLICATION_CREDENTIALS), or set GOOGLE_APPLICATION_CREDENTIALS to a credentials file`);return{bucket:e.bucket,endpoint:(e.endpoint??ew).replace(/\/+$/,""),credentialsFile:n}}var sN=e=>Buffer.from(e).toString("base64url");function pX(e,t){let n=Math.floor(t.getTime()/1e3),r=sN(JSON.stringify({alg:"RS256",typ:"JWT",...e.private_key_id?{kid:e.private_key_id}:{}})),o=sN(JSON.stringify({iss:e.client_email,sub:e.client_email,scope:dX,iat:n,exp:n+3600}));return`${r}.${o}.${aN("RSA-SHA256").update(`${r}.${o}`).sign(e.private_key).toString("base64url")}`}var iN=e=>{let t=/\/serviceAccounts\/([^/:]+):generateAccessToken$/.exec(e);return t?decodeURIComponent(t[1]):void 0};async function fX(e,t,n,r,o,s,i){let a=new URL(`${e}/${t}/${Xl(n)}`),c=s.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}/,""),u=`${c.slice(0,8)}/auto/storage/goog4_request`,l={"X-Goog-Algorithm":"GOOG4-RSA-SHA256","X-Goog-Credential":`${r}/${u}`,"X-Goog-Date":c,"X-Goog-Expires":String(o),"X-Goog-SignedHeaders":"host"},d=Object.keys(l).sort().map(g=>`${Zt(g)}=${Zt(l[g])}`).join("&"),p=["GET",a.pathname,d,`host:${a.host}`,"","host","UNSIGNED-PAYLOAD"].join(`
43
- `),f=["GOOG4-RSA-SHA256",c,u,uX("sha256").update(p).digest("hex")].join(`
44
- `);return`${a.origin}${a.pathname}?${d}&X-Goog-Signature=${(await i(f)).toString("hex")}`}var Va=e=>{try{let t=JSON.parse(e);if(typeof t.error=="object"&&t.error?.message)return t.error.message;if(typeof t.error=="string")return[t.error,t.error_description].filter(Boolean).join(": ")}catch{}return e.slice(0,300)},Za=class{constructor(t,n=fetch,r=o=>lX(o,"utf-8")){this.target=t;this.fetchFn=n;this.readFile=r}target;fetchFn;readFile;creds;token;get location(){return`gs://${this.target.bucket}`}get source(){return this.target.credentialsFile??"the backend's credentials"}credentials(){if(this.creds)return this.creds;let t=this.source,n;try{n=JSON.parse(this.target.credentialsJson??this.readFile(this.target.credentialsFile??""))}catch(r){throw new Y(`cannot read the credentials in ${t}: ${r.message}`)}if(n.type==="external_account"&&n.token_url&&n.audience&&n.credential_source&&(n.credential_source.file||n.credential_source.url))return this.creds=n;if(n.type==="service_account"&&n.client_email&&n.private_key)return this.creds=n;throw new Y(`${t} is not an external_account file with a credential_source file or url, nor a service_account key`)}async post(t,n,r,o){let s=await this.fetchFn(t,{method:"POST",headers:n,body:r}),i=await s.text();if(!s.ok)throw new Y(`${o}: ${s.status} ${Va(i)}`);try{return JSON.parse(i)}catch{throw new Y(`${o}: the answer is not JSON`)}}async subjectToken(t){let n=t.credential_source,r;if(n.file)try{r=this.readFile(n.file)}catch(i){throw new Y(`cannot read the OIDC token in ${n.file}: ${i.message}`)}else{let i=await this.fetchFn(n.url,{method:"GET",headers:n.headers??{}});if(r=await i.text(),!i.ok)throw new Y(`the OIDC token at ${n.url.split("?")[0]}: ${i.status} ${Va(r)}`)}let o=n.format?.type==="json"?n.format.subject_token_field_name:void 0,s=r.trim();if(o)try{s=String(JSON.parse(r)[o]??"")}catch{throw new Y(`the job's OIDC token is not JSON with ${o}`)}if(!s)throw new Y("the job's OIDC token is empty");return s}async exchange(t){let n=await this.post(t.token_url,{"content-type":"application/x-www-form-urlencoded"},new URLSearchParams({grant_type:"urn:ietf:params:oauth:grant-type:token-exchange",audience:t.audience,scope:SR,requested_token_type:"urn:ietf:params:oauth:token-type:access_token",subject_token:await this.subjectToken(t),subject_token_type:t.subject_token_type}).toString(),`Google STS refused the OIDC token for ${t.audience}`);if(typeof n.access_token!="string")throw new Y("Google STS answered without a token");let r={token:n.access_token,expires:Date.now()+Number(n.expires_in??3600)*1e3};if(!t.service_account_impersonation_url)return r;let o=await this.post(t.service_account_impersonation_url,{"content-type":"application/json",authorization:`Bearer ${r.token}`},JSON.stringify({scope:[SR],lifetime:"3600s"}),`impersonating ${iN(t.service_account_impersonation_url)??"the service account"}`);if(typeof o.accessToken!="string")throw new Y("IAM answered the impersonation without a token");let s=typeof o.expireTime=="string"?Date.parse(o.expireTime):NaN;return{token:o.accessToken,expires:Number.isNaN(s)?Date.now()+36e5:s}}async own(){if(this.target.accessToken)return{token:this.target.accessToken,expires:Date.now()+36e5};let t=this.credentials();return t.type==="service_account"?{token:pX(t,new Date),expires:Date.now()+36e5}:this.exchange(t)}async impersonating(t){let n=await this.own(),r=await this.post(`${(this.target.iamEndpoint??oN).replace(/\/+$/,"")}/v1/projects/-/serviceAccounts/${encodeURIComponent(t)}:generateAccessToken`,{"content-type":"application/json",authorization:`Bearer ${n.token}`},JSON.stringify({scope:[SR],lifetime:"3600s"}),`impersonating ${t}, which needs Service Account Token Creator for the identity`);if(typeof r.accessToken!="string")throw new Y(`IAM answered the impersonation of ${t} without a token`);let o=typeof r.expireTime=="string"?Date.parse(r.expireTime):NaN;return{token:r.accessToken,expires:Number.isNaN(o)?Date.now()+36e5:o}}async bearer(){let t=this.target.impersonate,n=()=>t?this.impersonating(t):this.own(),r=()=>this.token=n().catch(s=>{throw this.token=void 0,s}),o=await(this.token??r());return o.expires-Date.now()<6e4&&(o=await r()),o.token}async identityToken(){return this.target.impersonate?this.impersonating(this.target.impersonate):this.own()}async put(t,n,r,o){let s=this.target,i=o?"ifMatch"in o?o.ifMatch:"0":"",a=`${s.endpoint}/upload/storage/v1/b/${encodeURIComponent(s.bucket)}/o?uploadType=media&name=${Zt(t)}${i?`&ifGenerationMatch=${Zt(i)}`:""}`,c=await this.fetchFn(a,{method:"POST",headers:{"content-type":r,authorization:`Bearer ${await this.bearer()}`},body:n});if(c.status===412)throw new Er(`PUT ${this.location}/${t}: 412, it changed since it was read`);let u=await c.text();if(!c.ok)throw new Y(`PUT ${this.location}/${t}: ${c.status} ${Va(u)}`);let l;try{l=JSON.parse(u).generation}catch{}return l!==void 0?{etag:String(l)}:{}}async read(t){let n=this.target,r=`${n.endpoint}/storage/v1/b/${encodeURIComponent(n.bucket)}/o/${Zt(t)}?alt=media`,o=await this.fetchFn(r,{method:"GET",headers:{authorization:`Bearer ${await this.bearer()}`}});if(o.status===404)return{};if(!o.ok)throw new Y(`GET ${this.location}/${t}: ${o.status} ${Va(await o.text())}`);let s=o.headers?.get("x-goog-generation")??void 0;return{body:await o.text(),...s?{etag:s}:{}}}async get(t){return(await this.read(t)).body}objectUrl(t){return`${this.target.endpoint}/storage/v1/b/${encodeURIComponent(this.target.bucket)}/o/${Zt(t)}`}async head(t,n){let r=`${this.objectUrl(t)}${n?`?generation=${Zt(n)}`:""}`,o=await this.fetchFn(r,{method:"GET",headers:{authorization:`Bearer ${await this.bearer()}`}}),s=await o.text();if(o.status===404||n&&o.status===400)return{exists:!1};if(!o.ok)throw new Y(`GET ${this.location}/${t} metadata: ${o.status} ${Va(s)}`);let i;try{i=JSON.parse(s).generation}catch{}return{exists:!0,...i!=null&&i!==""?{generation:String(i)}:{}}}async readGeneration(t,n){let r=`${this.objectUrl(t)}?alt=media&generation=${Zt(n)}`,o=await this.fetchFn(r,{method:"GET",headers:{authorization:`Bearer ${await this.bearer()}`}});if(!(o.status===404||o.status===400)){if(!o.ok)throw new Y(`GET ${this.location}/${t}#${n}: ${o.status} ${Va(await o.text())}`);return o.text()}}async versioning(){let t=`${this.target.endpoint}/storage/v1/b/${encodeURIComponent(this.target.bucket)}?fields=versioning`,n=await this.fetchFn(t,{method:"GET",headers:{authorization:`Bearer ${await this.bearer()}`}}),r=await n.text();if(!(n.status===403||n.status===401)){if(!n.ok)throw new Y(`GET ${this.location} settings: ${n.status} ${Va(r)}`);try{return JSON.parse(r).versioning?.enabled===!0}catch{return}}}async putIfAbsent(t,n,r){try{return await this.put(t,n,r,{ifNoneMatch:"*"}),!0}catch(o){if(o instanceof Er)return!1;throw o}}async remove(t){let n=await this.fetchFn(this.objectUrl(t),{method:"DELETE",headers:{authorization:`Bearer ${await this.bearer()}`}});if(!n.ok&&n.status!==404)throw new Y(`DELETE ${this.location}/${t}: ${n.status} ${Va(await n.text())}`)}async presign(t,n,r=new Date){if(!Number.isInteger(n)||n<1||n>Jn)throw new Y(`a signed URL lives 1 to ${Jn} seconds, not ${n}`);let o,s,i=this.target.accessToken&&this.target.signAs?void 0:this.credentials();if(i)if(i.type==="service_account")o=i.client_email,s=async c=>aN("RSA-SHA256").update(c).sign(i.private_key);else{let c=i.service_account_impersonation_url?iN(i.service_account_impersonation_url):void 0;if(!c)throw new Y(`a signed URL needs a service account to sign it, and ${this.source} impersonates none: set oidc.gcp's service accounts`);o=c;let u=new URL(i.service_account_impersonation_url).origin;s=async l=>{let d=await this.post(`${u}/v1/projects/-/serviceAccounts/${encodeURIComponent(c)}:signBlob`,{"content-type":"application/json",authorization:`Bearer ${await this.bearer()}`},JSON.stringify({payload:Buffer.from(l).toString("base64")}),`signBlob as ${c}, which needs Service Account Token Creator on itself`);if(typeof d.signedBlob!="string")throw new Y(`signBlob as ${c} answered without a signature`);return Buffer.from(d.signedBlob,"base64")}}else{let c=this.target.signAs;o=c,s=async u=>{let l=await this.post(`${(this.target.iamEndpoint??oN).replace(/\/+$/,"")}/v1/projects/-/serviceAccounts/${encodeURIComponent(c)}:signBlob`,{"content-type":"application/json",authorization:`Bearer ${await this.bearer()}`},JSON.stringify({payload:Buffer.from(u).toString("base64")}),`signBlob as ${c}, which needs Service Account Token Creator on itself`);if(typeof l.signedBlob!="string")throw new Y(`signBlob as ${c} answered without a signature`);return Buffer.from(l.signedBlob,"base64")}}return{url:await fX(this.target.endpoint,this.target.bucket,t,o,n,r,s),expires:new Date(r.getTime()+n*1e3)}}};import{createHash as gX,createHmac as RR}from"node:crypto";import{readFileSync as mX}from"node:fs";function hX(e){let t=/^(?:s3:\/\/)?([^/]+)\/?$/.exec(e.trim());if(!t)throw new Y(`reports.bucket must be s3://<bucket>, not ${e}`);return t[1]}function dd(e,t=process.env){let n=e.endpoint??t.AWS_ENDPOINT_URL_S3??t.AWS_ENDPOINT_URL,r=t.AWS_REGION||t.AWS_DEFAULT_REGION||"us-east-1",o={bucket:hX(e.bucket),...n?{endpoint:n.replace(/\/+$/,"")}:{},region:r},s=t.AWS_WEB_IDENTITY_TOKEN_FILE,i=l=>({...o,webIdentity:{roleArn:l,tokenFile:s,sessionName:t.AWS_ROLE_SESSION_NAME||"terragucci-report",endpoint:(t.AWS_ENDPOINT_URL_STS||t.AWS_ENDPOINT_URL||`https://sts.${r}.amazonaws.com`).replace(/\/+$/,"")}}),a=Li(t);if(e.role&&a&&!s){let l=Ru(a,e.role);return{...o,accessKeyId:l.accessKeyId,secretAccessKey:l.secretAccessKey,...l.sessionToken?{sessionToken:l.sessionToken}:{}}}if(e.role){if(!s)throw new Y(`reports.role is set, but AWS_WEB_IDENTITY_TOKEN_FILE is not: the job needs an OIDC token to assume ${e.role}, which a job with oidc gets`);return i(e.role)}let c=t.AWS_ACCESS_KEY_ID,u=t.AWS_SECRET_ACCESS_KEY;if(c&&u)return{...o,accessKeyId:c,secretAccessKey:u,...t.AWS_SESSION_TOKEN?{sessionToken:t.AWS_SESSION_TOKEN}:{}};if(t.AWS_ROLE_ARN&&s)return i(t.AWS_ROLE_ARN);throw new Y("reports.bucket is set, but the job has no credentials for it: set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE (a job with oidc sets both), or reports.role")}async function Bf(e,t,n=r=>mX(r,"utf-8")){let r;try{r=n(e.tokenFile).trim()}catch(d){throw new Y(`cannot read the OIDC token in ${e.tokenFile}: ${d.message}`)}if(!r)throw new Y(`the OIDC token file ${e.tokenFile} is empty`);let o=new URLSearchParams({Action:"AssumeRoleWithWebIdentity",Version:"2011-06-15",RoleArn:e.roleArn,RoleSessionName:e.sessionName,WebIdentityToken:r}).toString(),s=await t(`${e.endpoint}/`,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded; charset=utf-8",accept:"application/xml"},body:o}),i=await s.text();if(!s.ok){let d=[hn(i,"Code"),hn(i,"Message")].filter(Boolean).join(": ")||i.slice(0,300);throw new Y(`AssumeRoleWithWebIdentity for ${e.roleArn}: ${s.status} ${d}`)}let a=hn(i,"AccessKeyId"),c=hn(i,"SecretAccessKey"),u=hn(i,"SessionToken");if(!a||!c||!u)throw new Y(`AssumeRoleWithWebIdentity for ${e.roleArn} answered without credentials`);let l=hn(i,"Expiration");return{accessKeyId:a,secretAccessKey:c,sessionToken:u,...l&&!Number.isNaN(Date.parse(l))?{expiration:new Date(l)}:{}}}var Uf=e=>gX("sha256").update(e).digest("hex"),Ya=(e,t)=>RR("sha256",e).update(t).digest();function zf(e,t,n,r,o=new Date,s,i={}){let a=tw(e,n);return{url:a,headers:xu(e,t,a,{...s?{"content-type":s}:{},...i},Uf(r),o)}}function xu(e,t,n,r,o,s,i="s3"){let a=new URL(n),c=s.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}/,""),u=c.slice(0,8),l={host:a.host,"x-amz-content-sha256":o,"x-amz-date":c,...Object.fromEntries(Object.entries(r).map(([k,v])=>[k.toLowerCase(),v])),...e.sessionToken?{"x-amz-security-token":e.sessionToken}:{}},d=Object.keys(l).sort(),p=[...a.searchParams].map(([k,v])=>`${Zt(k)}=${Zt(v)}`).sort().join("&"),f=[t,a.pathname,p,...d.map(k=>`${k}:${l[k].trim()}`),"",d.join(";"),o].join(`
42
+ `)[0]].filter(Boolean).join(": ")||e.slice(0,300)},ud=class{constructor(t,n=fetch,r=o=>r7(o,"utf-8")){this.target=t;this.fetchFn=n;this.readToken=r}target;fetchFn;readToken;token;keys=new Map;get location(){return`az://${this.target.account}/${this.target.container}`}blobUrl(t,n=""){let r=this.target,o=[n,"sas"in r?r.sas.replace(/^\?/,""):""].filter(Boolean).join("&");return`${r.endpoint}/${r.container}/${Xl(t)}${o?`?${o}`:""}`}async bearer(t){let n=async()=>{let s;try{s=this.readToken(t.tokenFile).trim()}catch(l){throw new Y(`cannot read the OIDC token in ${t.tokenFile}: ${l.message}`)}if(!s)throw new Y(`the OIDC token file ${t.tokenFile} is empty`);let i=new URLSearchParams({client_id:t.clientId,scope:o7,grant_type:"client_credentials",client_assertion_type:"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",client_assertion:s}).toString(),a=await this.fetchFn(`${t.authority}/${t.tenantId}/oauth2/v2.0/token`,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:i}),c=await a.text();if(!a.ok)throw new Y(`Entra ID refused the OIDC token for client ${t.clientId}: ${a.status} ${Mi(c)}`);let u={};try{u=JSON.parse(c)}catch{}if(!u.access_token)throw new Y(`Entra ID answered client ${t.clientId} without a token`);return{token:u.access_token,expires:Date.now()+Number(u.expires_in??3600)*1e3}},r=()=>this.token=n().catch(s=>{throw this.token=void 0,s}),o=await(this.token??r());return o.expires-Date.now()<6e4&&(o=await r()),o.token}async headers(t,n,r){let o={"x-ms-date":new Date().toUTCString(),"x-ms-version":_R,...r},s=this.target;return"accountKey"in s?{...o,authorization:i7(s.account,s.accountKey,t,n,o)}:"sas"in s?o:{...o,authorization:`Bearer ${await this.bearer(s.oidc)}`}}async put(t,n,r,o){let s=this.blobUrl(t),i=o?"ifMatch"in o?{"if-match":o.ifMatch}:{"if-none-match":"*"}:{},a=typeof n=="string"?Buffer.byteLength(n):n.byteLength,c=await this.headers("PUT",s,{"x-ms-blob-type":"BlockBlob","content-type":r,"content-length":String(a),...i}),u=await this.fetchFn(s,{method:"PUT",headers:c,body:n});if(u.status===412||u.status===409&&o)throw new Er(`PUT ${this.location}/${t}: ${u.status}, it changed since it was read`);if(!u.ok)throw new Y(`PUT ${this.location}/${t}: ${u.status} ${Mi(await u.text())}`);let l=u.headers?.get("etag")??void 0;return l?{etag:l}:{}}async read(t){let n=this.blobUrl(t),r=await this.fetchFn(n,{method:"GET",headers:await this.headers("GET",n,{})});if(r.status===404)return{};if(!r.ok)throw new Y(`GET ${this.location}/${t}: ${r.status} ${Mi(await r.text())}`);let o=r.headers?.get("etag")??void 0;return{body:await r.text(),...o?{etag:o}:{}}}async get(t){return(await this.read(t)).body}async head(t,n){let r=this.blobUrl(t,n?new URLSearchParams(n).toString():""),o=await this.fetchFn(r,{method:"HEAD",headers:await this.headers("HEAD",r,{})});if(o.status===404||n&&o.status===400)return{exists:!1,metadata:{}};if(!o.ok)throw new Y(`HEAD ${this.location}/${t}: ${o.status}`);let s=d=>o.headers?.get(d)??void 0,i={};o.headers?.forEach?.((d,p)=>{p.toLowerCase().startsWith("x-ms-meta-")&&(i[p.toLowerCase().slice(10)]=d)});let c=s("etag"),u=s("x-ms-version-id"),l=s("x-ms-lease-state");return{exists:!0,...c?{etag:c}:{},...u?{versionId:u}:{},...l?{leaseState:l}:{},metadata:i}}async readAt(t,n){let r=this.blobUrl(t,new URLSearchParams(n).toString()),o=await this.fetchFn(r,{method:"GET",headers:await this.headers("GET",r,{})});if(!(o.status===404||o.status===400)){if(!o.ok)throw new Y(`GET ${this.location}/${t} ${JSON.stringify(n)}: ${o.status} ${Mi(await o.text())}`);return o.text()}}async snapshot(t){let n=this.blobUrl(t,"comp=snapshot"),r=await this.fetchFn(n,{method:"PUT",headers:await this.headers("PUT",n,{"content-length":"0"})});if(!r.ok)throw new Y(`snapshot of ${this.location}/${t}: ${r.status} ${Mi(await r.text())}`);let o=r.headers?.get("x-ms-snapshot");if(!o)throw new Y(`snapshot of ${this.location}/${t}: Azure answered without x-ms-snapshot`);return o}async putBlob(t,n,r,o={}){let s=this.blobUrl(t),i=Object.fromEntries(Object.entries(o.metadata??{}).map(([u,l])=>[`x-ms-meta-${u}`,l])),a={"x-ms-blob-type":"BlockBlob","content-type":r,"content-length":String(Buffer.byteLength(n)),...i,...o.leaseId?{"x-ms-lease-id":o.leaseId}:{},...o.ifNoneMatch?{"if-none-match":"*"}:{}},c=await this.fetchFn(s,{method:"PUT",headers:await this.headers("PUT",s,a),body:n});if(o.ifNoneMatch&&(c.status===409||c.status===412))return!1;if(!c.ok)throw new Y(`PUT ${this.location}/${t}: ${c.status} ${Mi(await c.text())}`);return!0}async lease(t,n,r){let o=this.blobUrl(t,"comp=lease"),s={"x-ms-lease-action":n,"content-length":"0",...n==="acquire"?{"x-ms-lease-duration":"-1","x-ms-proposed-lease-id":r}:{"x-ms-lease-id":r}},i=await this.fetchFn(o,{method:"PUT",headers:await this.headers("PUT",o,s)});if(n==="acquire"&&i.status===409)return!1;if(!i.ok)throw new Y(`${n} the lease of ${this.location}/${t}: ${i.status} ${Mi(await i.text())}`);return!0}async setMetadata(t,n,r){let o=this.blobUrl(t,"comp=metadata"),s={"content-length":"0",...Object.fromEntries(Object.entries(n).map(([a,c])=>[`x-ms-meta-${a}`,c])),...r?{"x-ms-lease-id":r}:{}},i=await this.fetchFn(o,{method:"PUT",headers:await this.headers("PUT",o,s)});if(!i.ok)throw new Y(`set the metadata of ${this.location}/${t}: ${i.status} ${Mi(await i.text())}`)}delegationKey(t,n){let r=Gy(n),o=this.keys.get(r);return o||(o=(async()=>{let s=`${this.target.endpoint}/?restype=service&comp=userdelegationkey`,i=`<?xml version="1.0" encoding="utf-8"?><KeyInfo><Start>${Gy(t)}</Start><Expiry>${r}</Expiry></KeyInfo>`,a=await this.fetchFn(s,{method:"POST",headers:await this.headers("POST",s,{"content-type":"application/xml"}),body:i}),c=await a.text();if(!a.ok)throw new Y(`Get User Delegation Key on ${this.target.account}: ${a.status} ${Mi(c)}`);let u=l=>{let d=hn(c,l);if(!d)throw new Y(`Get User Delegation Key on ${this.target.account} answered without ${l}`);return d};return{oid:u("SignedOid"),tid:u("SignedTid"),start:u("SignedStart"),expiry:u("SignedExpiry"),service:u("SignedService"),version:u("SignedVersion"),value:u("Value")}})(),o.catch(()=>this.keys.delete(r)),this.keys.set(r,o)),o}async presign(t,n,r=new Date){if(!Number.isInteger(n)||n<1||n>Jn)throw new Y(`a SAS link lives 1 to ${Jn} seconds, not ${n}`);let o=new Date(Math.floor(r.getTime()/1e3)*1e3+n*1e3),s=this.target,i=a7(s,t,o,"accountKey"in s?{accountKey:s.accountKey}:{key:await this.delegationKey(r,o)});return{url:`${this.blobUrl(t)}?${i}`,expires:o}}};import{createHash as u7,createSign as aN}from"node:crypto";import{readFileSync as l7}from"node:fs";import{readFileSync as c7}from"node:fs";var Ff="TERRAGUCCI_TRADED";function Li(e){let t=e[Ff];if(t)try{let n=JSON.parse(c7(t,"utf-8"));return{aws:n.aws??{},gcp:n.gcp??{}}}catch(n){throw new Y(`${Ff} names ${t}, which cannot be read: ${n.message}`)}}function Ru(e,t){let n=e.aws[t];if(!n)throw new Y(`the re-plan traded no credentials for ${t}`);return n}var ew="https://storage.googleapis.com",oN="https://iamcredentials.googleapis.com",SR="https://www.googleapis.com/auth/cloud-platform",d7="https://www.googleapis.com/auth/devstorage.read_write";function cN(e,t=process.env){let n=t.GOOGLE_APPLICATION_CREDENTIALS,r=!n&&t.GOOGLE_OAUTH_ACCESS_TOKEN?Li(t):void 0;if(r&&t.GOOGLE_OAUTH_ACCESS_TOKEN){let o=Object.entries(r.gcp).find(([,s])=>s.token===t.GOOGLE_OAUTH_ACCESS_TOKEN)?.[0];return{bucket:e.bucket,endpoint:(e.endpoint??ew).replace(/\/+$/,""),accessToken:t.GOOGLE_OAUTH_ACCESS_TOKEN,...o?{signAs:o}:{}}}if(!n)throw new Y(`reports.bucket is gs://${e.bucket}, but the job has no credentials for it: give the job oidc.gcp (it sets GOOGLE_APPLICATION_CREDENTIALS), or set GOOGLE_APPLICATION_CREDENTIALS to a credentials file`);return{bucket:e.bucket,endpoint:(e.endpoint??ew).replace(/\/+$/,""),credentialsFile:n}}var sN=e=>Buffer.from(e).toString("base64url");function p7(e,t){let n=Math.floor(t.getTime()/1e3),r=sN(JSON.stringify({alg:"RS256",typ:"JWT",...e.private_key_id?{kid:e.private_key_id}:{}})),o=sN(JSON.stringify({iss:e.client_email,sub:e.client_email,scope:d7,iat:n,exp:n+3600}));return`${r}.${o}.${aN("RSA-SHA256").update(`${r}.${o}`).sign(e.private_key).toString("base64url")}`}var iN=e=>{let t=/\/serviceAccounts\/([^/:]+):generateAccessToken$/.exec(e);return t?decodeURIComponent(t[1]):void 0};async function f7(e,t,n,r,o,s,i){let a=new URL(`${e}/${t}/${Xl(n)}`),c=s.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}/,""),u=`${c.slice(0,8)}/auto/storage/goog4_request`,l={"X-Goog-Algorithm":"GOOG4-RSA-SHA256","X-Goog-Credential":`${r}/${u}`,"X-Goog-Date":c,"X-Goog-Expires":String(o),"X-Goog-SignedHeaders":"host"},d=Object.keys(l).sort().map(g=>`${Zt(g)}=${Zt(l[g])}`).join("&"),p=["GET",a.pathname,d,`host:${a.host}`,"","host","UNSIGNED-PAYLOAD"].join(`
43
+ `),f=["GOOG4-RSA-SHA256",c,u,u7("sha256").update(p).digest("hex")].join(`
44
+ `);return`${a.origin}${a.pathname}?${d}&X-Goog-Signature=${(await i(f)).toString("hex")}`}var Va=e=>{try{let t=JSON.parse(e);if(typeof t.error=="object"&&t.error?.message)return t.error.message;if(typeof t.error=="string")return[t.error,t.error_description].filter(Boolean).join(": ")}catch{}return e.slice(0,300)},Za=class{constructor(t,n=fetch,r=o=>l7(o,"utf-8")){this.target=t;this.fetchFn=n;this.readFile=r}target;fetchFn;readFile;creds;token;get location(){return`gs://${this.target.bucket}`}get source(){return this.target.credentialsFile??"the backend's credentials"}credentials(){if(this.creds)return this.creds;let t=this.source,n;try{n=JSON.parse(this.target.credentialsJson??this.readFile(this.target.credentialsFile??""))}catch(r){throw new Y(`cannot read the credentials in ${t}: ${r.message}`)}if(n.type==="external_account"&&n.token_url&&n.audience&&n.credential_source&&(n.credential_source.file||n.credential_source.url))return this.creds=n;if(n.type==="service_account"&&n.client_email&&n.private_key)return this.creds=n;throw new Y(`${t} is not an external_account file with a credential_source file or url, nor a service_account key`)}async post(t,n,r,o){let s=await this.fetchFn(t,{method:"POST",headers:n,body:r}),i=await s.text();if(!s.ok)throw new Y(`${o}: ${s.status} ${Va(i)}`);try{return JSON.parse(i)}catch{throw new Y(`${o}: the answer is not JSON`)}}async subjectToken(t){let n=t.credential_source,r;if(n.file)try{r=this.readFile(n.file)}catch(i){throw new Y(`cannot read the OIDC token in ${n.file}: ${i.message}`)}else{let i=await this.fetchFn(n.url,{method:"GET",headers:n.headers??{}});if(r=await i.text(),!i.ok)throw new Y(`the OIDC token at ${n.url.split("?")[0]}: ${i.status} ${Va(r)}`)}let o=n.format?.type==="json"?n.format.subject_token_field_name:void 0,s=r.trim();if(o)try{s=String(JSON.parse(r)[o]??"")}catch{throw new Y(`the job's OIDC token is not JSON with ${o}`)}if(!s)throw new Y("the job's OIDC token is empty");return s}async exchange(t){let n=await this.post(t.token_url,{"content-type":"application/x-www-form-urlencoded"},new URLSearchParams({grant_type:"urn:ietf:params:oauth:grant-type:token-exchange",audience:t.audience,scope:SR,requested_token_type:"urn:ietf:params:oauth:token-type:access_token",subject_token:await this.subjectToken(t),subject_token_type:t.subject_token_type}).toString(),`Google STS refused the OIDC token for ${t.audience}`);if(typeof n.access_token!="string")throw new Y("Google STS answered without a token");let r={token:n.access_token,expires:Date.now()+Number(n.expires_in??3600)*1e3};if(!t.service_account_impersonation_url)return r;let o=await this.post(t.service_account_impersonation_url,{"content-type":"application/json",authorization:`Bearer ${r.token}`},JSON.stringify({scope:[SR],lifetime:"3600s"}),`impersonating ${iN(t.service_account_impersonation_url)??"the service account"}`);if(typeof o.accessToken!="string")throw new Y("IAM answered the impersonation without a token");let s=typeof o.expireTime=="string"?Date.parse(o.expireTime):NaN;return{token:o.accessToken,expires:Number.isNaN(s)?Date.now()+36e5:s}}async own(){if(this.target.accessToken)return{token:this.target.accessToken,expires:Date.now()+36e5};let t=this.credentials();return t.type==="service_account"?{token:p7(t,new Date),expires:Date.now()+36e5}:this.exchange(t)}async impersonating(t){let n=await this.own(),r=await this.post(`${(this.target.iamEndpoint??oN).replace(/\/+$/,"")}/v1/projects/-/serviceAccounts/${encodeURIComponent(t)}:generateAccessToken`,{"content-type":"application/json",authorization:`Bearer ${n.token}`},JSON.stringify({scope:[SR],lifetime:"3600s"}),`impersonating ${t}, which needs Service Account Token Creator for the identity`);if(typeof r.accessToken!="string")throw new Y(`IAM answered the impersonation of ${t} without a token`);let o=typeof r.expireTime=="string"?Date.parse(r.expireTime):NaN;return{token:r.accessToken,expires:Number.isNaN(o)?Date.now()+36e5:o}}async bearer(){let t=this.target.impersonate,n=()=>t?this.impersonating(t):this.own(),r=()=>this.token=n().catch(s=>{throw this.token=void 0,s}),o=await(this.token??r());return o.expires-Date.now()<6e4&&(o=await r()),o.token}async identityToken(){return this.target.impersonate?this.impersonating(this.target.impersonate):this.own()}async put(t,n,r,o){let s=this.target,i=o?"ifMatch"in o?o.ifMatch:"0":"",a=`${s.endpoint}/upload/storage/v1/b/${encodeURIComponent(s.bucket)}/o?uploadType=media&name=${Zt(t)}${i?`&ifGenerationMatch=${Zt(i)}`:""}`,c=await this.fetchFn(a,{method:"POST",headers:{"content-type":r,authorization:`Bearer ${await this.bearer()}`},body:n});if(c.status===412)throw new Er(`PUT ${this.location}/${t}: 412, it changed since it was read`);let u=await c.text();if(!c.ok)throw new Y(`PUT ${this.location}/${t}: ${c.status} ${Va(u)}`);let l;try{l=JSON.parse(u).generation}catch{}return l!==void 0?{etag:String(l)}:{}}async read(t){let n=this.target,r=`${n.endpoint}/storage/v1/b/${encodeURIComponent(n.bucket)}/o/${Zt(t)}?alt=media`,o=await this.fetchFn(r,{method:"GET",headers:{authorization:`Bearer ${await this.bearer()}`}});if(o.status===404)return{};if(!o.ok)throw new Y(`GET ${this.location}/${t}: ${o.status} ${Va(await o.text())}`);let s=o.headers?.get("x-goog-generation")??void 0;return{body:await o.text(),...s?{etag:s}:{}}}async get(t){return(await this.read(t)).body}objectUrl(t){return`${this.target.endpoint}/storage/v1/b/${encodeURIComponent(this.target.bucket)}/o/${Zt(t)}`}async head(t,n){let r=`${this.objectUrl(t)}${n?`?generation=${Zt(n)}`:""}`,o=await this.fetchFn(r,{method:"GET",headers:{authorization:`Bearer ${await this.bearer()}`}}),s=await o.text();if(o.status===404||n&&o.status===400)return{exists:!1};if(!o.ok)throw new Y(`GET ${this.location}/${t} metadata: ${o.status} ${Va(s)}`);let i;try{i=JSON.parse(s).generation}catch{}return{exists:!0,...i!=null&&i!==""?{generation:String(i)}:{}}}async readGeneration(t,n){let r=`${this.objectUrl(t)}?alt=media&generation=${Zt(n)}`,o=await this.fetchFn(r,{method:"GET",headers:{authorization:`Bearer ${await this.bearer()}`}});if(!(o.status===404||o.status===400)){if(!o.ok)throw new Y(`GET ${this.location}/${t}#${n}: ${o.status} ${Va(await o.text())}`);return o.text()}}async versioning(){let t=`${this.target.endpoint}/storage/v1/b/${encodeURIComponent(this.target.bucket)}?fields=versioning`,n=await this.fetchFn(t,{method:"GET",headers:{authorization:`Bearer ${await this.bearer()}`}}),r=await n.text();if(!(n.status===403||n.status===401)){if(!n.ok)throw new Y(`GET ${this.location} settings: ${n.status} ${Va(r)}`);try{return JSON.parse(r).versioning?.enabled===!0}catch{return}}}async putIfAbsent(t,n,r){try{return await this.put(t,n,r,{ifNoneMatch:"*"}),!0}catch(o){if(o instanceof Er)return!1;throw o}}async remove(t){let n=await this.fetchFn(this.objectUrl(t),{method:"DELETE",headers:{authorization:`Bearer ${await this.bearer()}`}});if(!n.ok&&n.status!==404)throw new Y(`DELETE ${this.location}/${t}: ${n.status} ${Va(await n.text())}`)}async presign(t,n,r=new Date){if(!Number.isInteger(n)||n<1||n>Jn)throw new Y(`a signed URL lives 1 to ${Jn} seconds, not ${n}`);let o,s,i=this.target.accessToken&&this.target.signAs?void 0:this.credentials();if(i)if(i.type==="service_account")o=i.client_email,s=async c=>aN("RSA-SHA256").update(c).sign(i.private_key);else{let c=i.service_account_impersonation_url?iN(i.service_account_impersonation_url):void 0;if(!c)throw new Y(`a signed URL needs a service account to sign it, and ${this.source} impersonates none: set oidc.gcp's service accounts`);o=c;let u=new URL(i.service_account_impersonation_url).origin;s=async l=>{let d=await this.post(`${u}/v1/projects/-/serviceAccounts/${encodeURIComponent(c)}:signBlob`,{"content-type":"application/json",authorization:`Bearer ${await this.bearer()}`},JSON.stringify({payload:Buffer.from(l).toString("base64")}),`signBlob as ${c}, which needs Service Account Token Creator on itself`);if(typeof d.signedBlob!="string")throw new Y(`signBlob as ${c} answered without a signature`);return Buffer.from(d.signedBlob,"base64")}}else{let c=this.target.signAs;o=c,s=async u=>{let l=await this.post(`${(this.target.iamEndpoint??oN).replace(/\/+$/,"")}/v1/projects/-/serviceAccounts/${encodeURIComponent(c)}:signBlob`,{"content-type":"application/json",authorization:`Bearer ${await this.bearer()}`},JSON.stringify({payload:Buffer.from(u).toString("base64")}),`signBlob as ${c}, which needs Service Account Token Creator on itself`);if(typeof l.signedBlob!="string")throw new Y(`signBlob as ${c} answered without a signature`);return Buffer.from(l.signedBlob,"base64")}}return{url:await f7(this.target.endpoint,this.target.bucket,t,o,n,r,s),expires:new Date(r.getTime()+n*1e3)}}};import{createHash as g7,createHmac as RR}from"node:crypto";import{readFileSync as m7}from"node:fs";function h7(e){let t=/^(?:s3:\/\/)?([^/]+)\/?$/.exec(e.trim());if(!t)throw new Y(`reports.bucket must be s3://<bucket>, not ${e}`);return t[1]}function dd(e,t=process.env){let n=e.endpoint??t.AWS_ENDPOINT_URL_S3??t.AWS_ENDPOINT_URL,r=t.AWS_REGION||t.AWS_DEFAULT_REGION||"us-east-1",o={bucket:h7(e.bucket),...n?{endpoint:n.replace(/\/+$/,"")}:{},region:r},s=t.AWS_WEB_IDENTITY_TOKEN_FILE,i=l=>({...o,webIdentity:{roleArn:l,tokenFile:s,sessionName:t.AWS_ROLE_SESSION_NAME||"terragucci-report",endpoint:(t.AWS_ENDPOINT_URL_STS||t.AWS_ENDPOINT_URL||`https://sts.${r}.amazonaws.com`).replace(/\/+$/,"")}}),a=Li(t);if(e.role&&a&&!s){let l=Ru(a,e.role);return{...o,accessKeyId:l.accessKeyId,secretAccessKey:l.secretAccessKey,...l.sessionToken?{sessionToken:l.sessionToken}:{}}}if(e.role){if(!s)throw new Y(`reports.role is set, but AWS_WEB_IDENTITY_TOKEN_FILE is not: the job needs an OIDC token to assume ${e.role}, which a job with oidc gets`);return i(e.role)}let c=t.AWS_ACCESS_KEY_ID,u=t.AWS_SECRET_ACCESS_KEY;if(c&&u)return{...o,accessKeyId:c,secretAccessKey:u,...t.AWS_SESSION_TOKEN?{sessionToken:t.AWS_SESSION_TOKEN}:{}};if(t.AWS_ROLE_ARN&&s)return i(t.AWS_ROLE_ARN);throw new Y("reports.bucket is set, but the job has no credentials for it: set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE (a job with oidc sets both), or reports.role")}async function Bf(e,t,n=r=>m7(r,"utf-8")){let r;try{r=n(e.tokenFile).trim()}catch(d){throw new Y(`cannot read the OIDC token in ${e.tokenFile}: ${d.message}`)}if(!r)throw new Y(`the OIDC token file ${e.tokenFile} is empty`);let o=new URLSearchParams({Action:"AssumeRoleWithWebIdentity",Version:"2011-06-15",RoleArn:e.roleArn,RoleSessionName:e.sessionName,WebIdentityToken:r}).toString(),s=await t(`${e.endpoint}/`,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded; charset=utf-8",accept:"application/xml"},body:o}),i=await s.text();if(!s.ok){let d=[hn(i,"Code"),hn(i,"Message")].filter(Boolean).join(": ")||i.slice(0,300);throw new Y(`AssumeRoleWithWebIdentity for ${e.roleArn}: ${s.status} ${d}`)}let a=hn(i,"AccessKeyId"),c=hn(i,"SecretAccessKey"),u=hn(i,"SessionToken");if(!a||!c||!u)throw new Y(`AssumeRoleWithWebIdentity for ${e.roleArn} answered without credentials`);let l=hn(i,"Expiration");return{accessKeyId:a,secretAccessKey:c,sessionToken:u,...l&&!Number.isNaN(Date.parse(l))?{expiration:new Date(l)}:{}}}var Uf=e=>g7("sha256").update(e).digest("hex"),Ya=(e,t)=>RR("sha256",e).update(t).digest();function zf(e,t,n,r,o=new Date,s,i={}){let a=tw(e,n);return{url:a,headers:xu(e,t,a,{...s?{"content-type":s}:{},...i},Uf(r),o)}}function xu(e,t,n,r,o,s,i="s3"){let a=new URL(n),c=s.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}/,""),u=c.slice(0,8),l={host:a.host,"x-amz-content-sha256":o,"x-amz-date":c,...Object.fromEntries(Object.entries(r).map(([k,v])=>[k.toLowerCase(),v])),...e.sessionToken?{"x-amz-security-token":e.sessionToken}:{}},d=Object.keys(l).sort(),p=[...a.searchParams].map(([k,v])=>`${Zt(k)}=${Zt(v)}`).sort().join("&"),f=[t,a.pathname,p,...d.map(k=>`${k}:${l[k].trim()}`),"",d.join(";"),o].join(`
45
45
  `),g=`${u}/${e.region}/${i}/aws4_request`,m=["AWS4-HMAC-SHA256",c,g,Uf(f)].join(`
46
- `),h=Ya(Ya(Ya(Ya(`AWS4${e.secretAccessKey}`,u),e.region),i),"aws4_request"),y=RR("sha256",h).update(m).digest("hex"),{host:w,...b}=l;return{...b,authorization:`AWS4-HMAC-SHA256 Credential=${e.accessKeyId}/${g}, SignedHeaders=${d.join(";")}, Signature=${y}`}}var tw=(e,t)=>`${e.endpoint?`${e.endpoint}/${e.bucket}`:`https://${e.bucket}.s3.${e.region}.amazonaws.com`}/${Xl(t)}`;function yX(e,t,n,r){if(!Number.isInteger(n)||n<1||n>Jn)throw new Y(`a presigned link lives 1 to ${Jn} seconds, not ${n}`);let o=new URL(t),s=r.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}/,""),i=`${s.slice(0,8)}/${e.region}/s3/aws4_request`,a={"X-Amz-Algorithm":"AWS4-HMAC-SHA256","X-Amz-Credential":`${e.accessKeyId}/${i}`,"X-Amz-Date":s,"X-Amz-Expires":String(n),...e.sessionToken?{"X-Amz-Security-Token":e.sessionToken}:{},"X-Amz-SignedHeaders":"host"},c=Object.keys(a).sort().map(p=>`${Zt(p)}=${Zt(a[p])}`).join("&"),u=["GET",o.pathname,c,`host:${o.host}`,"","host","UNSIGNED-PAYLOAD"].join(`
46
+ `),h=Ya(Ya(Ya(Ya(`AWS4${e.secretAccessKey}`,u),e.region),i),"aws4_request"),y=RR("sha256",h).update(m).digest("hex"),{host:w,...b}=l;return{...b,authorization:`AWS4-HMAC-SHA256 Credential=${e.accessKeyId}/${g}, SignedHeaders=${d.join(";")}, Signature=${y}`}}var tw=(e,t)=>`${e.endpoint?`${e.endpoint}/${e.bucket}`:`https://${e.bucket}.s3.${e.region}.amazonaws.com`}/${Xl(t)}`;function y7(e,t,n,r){if(!Number.isInteger(n)||n<1||n>Jn)throw new Y(`a presigned link lives 1 to ${Jn} seconds, not ${n}`);let o=new URL(t),s=r.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}/,""),i=`${s.slice(0,8)}/${e.region}/s3/aws4_request`,a={"X-Amz-Algorithm":"AWS4-HMAC-SHA256","X-Amz-Credential":`${e.accessKeyId}/${i}`,"X-Amz-Date":s,"X-Amz-Expires":String(n),...e.sessionToken?{"X-Amz-Security-Token":e.sessionToken}:{},"X-Amz-SignedHeaders":"host"},c=Object.keys(a).sort().map(p=>`${Zt(p)}=${Zt(a[p])}`).join("&"),u=["GET",o.pathname,c,`host:${o.host}`,"","host","UNSIGNED-PAYLOAD"].join(`
47
47
  `),l=["AWS4-HMAC-SHA256",s,i,Uf(u)].join(`
48
- `),d=Ya(Ya(Ya(Ya(`AWS4${e.secretAccessKey}`,s.slice(0,8)),e.region),"s3"),"aws4_request");return`${o.origin}${o.pathname}?${c}&X-Amz-Signature=${RR("sha256",d).update(l).digest("hex")}`}var ld=class{constructor(t,n=fetch){this.target=t;this.fetchFn=n}target;fetchFn;creds;conditional=!0;get location(){return`s3://${this.target.bucket}`}async signer(){let t=this.target;if(!("webIdentity"in t))return t;let n=()=>this.creds=Bf(t.webIdentity,this.fetchFn).catch(a=>{throw this.creds=void 0,a}),r=await(this.creds??n());r.expiration&&r.expiration.getTime()-Date.now()<6e4&&(r=await n());let{accessKeyId:o,secretAccessKey:s,sessionToken:i}=r;return{bucket:t.bucket,...t.endpoint?{endpoint:t.endpoint}:{},region:t.region,accessKeyId:o,secretAccessKey:s,...i?{sessionToken:i}:{}}}async put(t,n,r,o){let s=!o||!this.conditional?{}:"ifMatch"in o?{"if-match":o.ifMatch}:{"if-none-match":"*"},{url:i,headers:a}=zf(await this.signer(),"PUT",t,n,new Date,r,s),c=await this.fetchFn(i,{method:"PUT",headers:a,body:n});if(c.status===501&&Object.keys(s).length)return this.conditional=!1,this.put(t,n,r);if(c.status===412||c.status===409&&Object.keys(s).length)throw new Er(`PUT s3://${this.target.bucket}/${t}: ${c.status}, it changed since it was read`);if(!c.ok)throw new Y(`PUT s3://${this.target.bucket}/${t}: ${c.status} ${(await c.text()).slice(0,300)}`);let u=c.headers?.get("etag")??void 0;return u?{etag:u}:{}}async read(t){let{url:n,headers:r}=zf(await this.signer(),"GET",t,""),o=await this.fetchFn(n,{method:"GET",headers:r});if(o.status===404)return{};if(!o.ok)throw new Y(`GET s3://${this.target.bucket}/${t}: ${o.status} ${(await o.text()).slice(0,300)}`);let s=o.headers?.get("etag")??void 0;return{body:await o.text(),...s?{etag:s}:{}}}async presign(t,n,r=new Date){let o=await this.signer(),s=yX(o,tw(o,t),n,r),i=new Date(r.getTime()+n*1e3),a=this.creds?await this.creds:void 0;return a?.expiration&&a.expiration<i&&(i=a.expiration),{url:s,expires:i}}async get(t){return(await this.read(t)).body}async head(t){let{url:n,headers:r}=zf(await this.signer(),"HEAD",t,""),o=await this.fetchFn(n,{method:"HEAD",headers:r});if(o.status===404)return{exists:!1};if(!o.ok)throw new Y(`HEAD s3://${this.target.bucket}/${t}: ${o.status}`);let s=o.headers?.get("etag")??void 0,i=o.headers?.get("x-amz-version-id")??void 0;return{exists:!0,...s?{etag:s}:{},...i&&i!=="null"?{versionId:i}:{}}}async putIfAbsent(t,n,r){let{url:o,headers:s}=zf(await this.signer(),"PUT",t,n,new Date,r,{"if-none-match":"*"}),i=await this.fetchFn(o,{method:"PUT",headers:s,body:n});if(i.status===412||i.status===409)return!1;if(i.status===501)throw new Y(`PUT s3://${this.target.bucket}/${t}: the store does not take a conditional write (501)`);if(!i.ok)throw new Y(`PUT s3://${this.target.bucket}/${t}: ${i.status} ${(await i.text()).slice(0,300)}`);return!0}async readVersion(t,n){let r=await this.signer(),o=`${tw(r,t)}?versionId=${Zt(n)}`,s=await this.fetchFn(o,{method:"GET",headers:xu(r,"GET",o,{},Uf(""),new Date)});if(s.status!==404){if(!s.ok)throw new Y(`GET s3://${this.target.bucket}/${t}?versionId=${n}: ${s.status} ${(await s.text()).slice(0,300)}`);return s.text()}}async hasVersion(t,n){let r=await this.signer(),o=`${tw(r,t)}?versionId=${Zt(n)}`,s=await this.fetchFn(o,{method:"HEAD",headers:xu(r,"HEAD",o,{},Uf(""),new Date)});if(s.status===404||s.status===400)return!1;if(!s.ok)throw new Y(`HEAD s3://${this.target.bucket}/${t}?versionId=${n}: ${s.status}`);return!0}async remove(t){let{url:n,headers:r}=zf(await this.signer(),"DELETE",t,""),o=await this.fetchFn(n,{method:"DELETE",headers:r});if(!o.ok&&o.status!==404)throw new Y(`DELETE s3://${this.target.bucket}/${t}: ${o.status} ${(await o.text()).slice(0,300)}`)}};import{posix as pd,sep as uN}from"node:path";var fd=e=>({unresolved:e});function Gi(e){if(e!==void 0)return typeof e=="string"&&!/\$\{|%\{/.test(e)?e:null}function lN(e,t){try{let n=new URL(e.includes("://")?e:`http://${e}`),r=n.pathname.replace(/\/+$/,"");return`${t?`${n.protocol}//`:""}${n.host.toLowerCase()}${r}`}catch{return}}function wX(e){if(/^postgres(ql)?:\/\//i.test(e))try{let o=new URL(e),s=o.pathname.replace(/^\/+/,"")||o.searchParams.get("dbname"),i=o.host.toLowerCase()||o.searchParams.get("host");return i&&s?`${i}/${s}`:void 0}catch{return}let t=new Map([...e.matchAll(/(\w+)\s*=\s*('(?:[^'\\]|\\.)*'|\S+)/g)].map(o=>[o[1],o[2].replace(/^'|'$/g,"")])),n=t.get("host")?.toLowerCase(),r=t.get("dbname");if(!(!n||!r))return`${n}${t.get("port")?`:${t.get("port")}`:""}/${r}`}function gd(e,t,n){let r=(c,u)=>fd(t(c)===null?`its ${e} ${c} is an expression, not a plain string`:`its ${e} backend names no ${c} in the code (${u?`${u} or `:""}a -backend-config file supplies it)`);switch(e){case"local":{let c=t("path");if(c===null)return r("path");let u=(c??"terraform.tfstate").split(uN).join(pd.sep);return{key:`local:${pd.isAbsolute(u)?pd.normalize(u):pd.normalize(pd.join(n.split(uN).join(pd.sep)||".",u))}`}}case"pg":{let c=t("conn_str");if(!c)return r("conn_str","PG_CONN_STR");let u=wX(c);if(!u)return fd("its pg conn_str names no host and database");let l=t("schema_name"),d=t("table_name");return l===null?r("schema_name"):d===null?r("table_name"):{key:`pg:${u}/${l??"terraform_remote_state"}.${d??"states"}`}}case"http":{let c=t("address");if(!c)return r("address","TF_HTTP_ADDRESS");let u=lN(c,!0);return u?{key:`http:${u}`}:fd("its http address is not a URL")}case"consul":{let c=t("address"),u=t("path");if(!u)return r("path");if(!c)return r("address","CONSUL_HTTP_ADDR");let l=lN(c,!1);return l?{key:`consul:${l}/${u.replace(/^\/+/,"")}`}:fd("its consul address is not a host")}case"kubernetes":{let c=t("secret_suffix"),u=t("namespace");return c?u?{key:`kubernetes:${u}/${c}`}:r("namespace","KUBE_NAMESPACE"):r("secret_suffix")}case"remote":case"cloud":{let c=t("hostname"),u=t("organization"),l=t("name");return c===null?r("hostname"):u?l===null?fd(`its ${e} workspace name is an expression, not a plain string`):l===void 0?fd(`its ${e} workspaces block names no workspace by name (one picked by tags, prefix or TF_WORKSPACE cannot be read from the code)`):{key:`remote:${(c??"app.terraform.io").toLowerCase()}/${u}/${l}`}:r("organization",e==="cloud"?"TF_CLOUD_ORGANIZATION":void 0)}}let o=t("key"),s=t("prefix"),i=o||s;if(!i)return r(o===null?"key":s===null||e==="gcs"?"prefix":"key");let a=t("bucket");return a===null?r("bucket"):{...a?{bucket:a}:{},key:i}}var ar=e=>!("unsupported"in e)&&(e.backend==="s3"||e.backend==="gcs"||e.backend==="azurerm"),Wf="reads state versions from s3, gcs, azurerm, local and GitLab-managed http backends",ut=e=>typeof e=="string"&&e!==""?e:void 0,fN={pg:"a pg backend keeps one row per workspace, which each write replaces",kubernetes:"a kubernetes backend keeps one Secret per workspace, which each write replaces",consul:"a consul backend keeps one key per workspace, which each write replaces",http:"an http backend keeps what its server holds at the address and names no versions"};function $X(e,t={}){if(e.type in fN&&!(e.type==="http"&&Mf(ut(e.config.address)??t.TF_HTTP_ADDRESS)))return!1}function kX(e){let t=Array.isArray(e.config.workspaces)?e.config.workspaces[0]:e.config.workspaces,n=o=>Gi(e.config[o]??(t&&typeof t=="object"?t[o]:void 0)),r=gd(e.type,n,"");return"key"in r?r.key:void 0}function rw(e,t=process.env){let n=t.TF_DATA_DIR;return n?bX(n)?n:md(e,n):md(e,".terraform")}function _X(e,t=process.env){let n=md(rw(e,t),"terraform.tfstate");if(xR(n))try{let r=JSON.parse(ER(n,"utf-8")),o=ut(r.backend?.type);if(!o)return;let s=r.backend?.config&&typeof r.backend.config=="object"?r.backend.config:{};return{type:o,config:s}}catch{return}}var ow=".terragucci-workspace";function hd(e){let t=md(e,ow);return xR(t)&&ER(t,"utf-8").trim()||void 0}function ls(e,t){let n=hd(t);return n?{...e,TF_WORKSPACE:n}:e}function Fi(e,t){let n=hd(t);if(!n)return;let{TF_WORKSPACE:r,...o}=e;return{init:{...e,TF_WORKSPACE:"default"},select:["workspace","select","-or-create=true",n],selectEnv:o}}function SX(e,t=process.env){if(t.TF_WORKSPACE)return t.TF_WORKSPACE;let n=md(rw(e,t),"environment");if(xR(n)){let r=ER(n,"utf-8").trim();if(r)return r}return"default"}function RX(e,t,n="env:"){return t==="default"?e:`${n}/${t}/${e}`}function Hr(e,t=process.env,n=_X(e,t)){let r=SX(e,t);if(!n||n.type==="local"){let g=n?.config??{};return{backend:"local",path:r==="default"?ut(g.path)??"terraform.tfstate":md(ut(g.workspace_dir)??"terraform.tfstate.d",r,"terraform.tfstate")}}if(n.type==="http"){let g=QC(n.config,t);if(g)return{backend:"http",gitlab:g,location:xn(g.address)}}if(n.type==="gcs")return EX(n.config,r,t);if(n.type==="azurerm")return AX(n.config,r,t);if(n.type!=="s3"){let g=kX(n),m=g?{location:g}:{},h=`terragucci ${Wf}, and this root's backend is ${n.type==="http"?"an http backend whose address is not a GitLab project's state API":n.type}`;return $X(n,t)===!1?{backend:n.type,unsupported:h,...m,versions:{versioning:"off",note:fN[n.type]}}:{backend:n.type,unsupported:h,...m,versions:{versioning:"unknown",note:`a ${n.type} backend can keep versions of the state, which terragucci does not read`}}}let o=n.config,s=ut(o.bucket),i=ut(o.key);if(!s||!i)return{backend:"s3",unsupported:"the s3 backend's bucket or key is not in the configuration init recorded"};let a=o.endpoints&&typeof o.endpoints=="object"?o.endpoints:{},c=ut(a.s3)??ut(o.endpoint)??t.AWS_ENDPOINT_URL_S3??t.AWS_ENDPOINT_URL,u=ut(o.region)??t.AWS_REGION??t.AWS_DEFAULT_REGION??"us-east-1",l=ut(o.access_key),d=ut(o.secret_key),p={...t,AWS_REGION:u,...l&&d?{AWS_ACCESS_KEY_ID:l,AWS_SECRET_ACCESS_KEY:d,AWS_SESSION_TOKEN:ut(o.token)??""}:{}},f;try{f=dd({bucket:s,...c?{endpoint:c}:{}},p)}catch(g){return{backend:"s3",unsupported:`the job has no credentials to read s3://${s}: ${g.message}`}}return{backend:"s3",bucket:s,key:RX(i,r,ut(o.workspace_key_prefix)),region:u,...c?{endpoint:c.replace(/\/+$/,"")}:{},lockfile:o.use_lockfile===!0,dynamodb:ut(o.dynamodb_table)!==void 0,target:f}}var xX=e=>e.replace(/\/+$/,"").replace(/\/storage\/v1$/,"");function EX(e,t,n){let r=ut(e.bucket);if(!r)return{backend:"gcs",unsupported:"the gcs backend's bucket is not in the configuration init recorded"};let o=ut(e.prefix)??"",s=o===""||o.endsWith("/")?o:`${o}/`,i=`${s}${t}.tfstate`,a=xX(ut(e.storage_custom_endpoint)??n.GOOGLE_BACKEND_STORAGE_CUSTOM_ENDPOINT??n.GOOGLE_STORAGE_CUSTOM_ENDPOINT??ew),c=ut(e.impersonate_service_account)??n.GOOGLE_BACKEND_IMPERSONATE_SERVICE_ACCOUNT??n.GOOGLE_IMPERSONATE_SERVICE_ACCOUNT,u={bucket:r,endpoint:a,...c?{impersonate:c}:{}},l=ut(e.access_token)??n.GOOGLE_OAUTH_ACCESS_TOKEN,d=ut(e.credentials)??n.GOOGLE_BACKEND_CREDENTIALS??n.GOOGLE_CREDENTIALS,p;if(l)p={...u,accessToken:l};else if(d)p=d.trim().startsWith("{")?{...u,credentialsJson:d}:{...u,credentialsFile:d};else if(n.GOOGLE_APPLICATION_CREDENTIALS)p={...u,credentialsFile:n.GOOGLE_APPLICATION_CREDENTIALS};else return{backend:"gcs",unsupported:`the job has no credentials to read gs://${r}: give the job oidc.gcp (it sets GOOGLE_APPLICATION_CREDENTIALS), or set GOOGLE_CREDENTIALS or GOOGLE_OAUTH_ACCESS_TOKEN`};return{backend:"gcs",bucket:r,key:i,lock:`${s}${t}.tflock`,target:p}}var TX={public:{storage:"core.windows.net",authority:Qy},china:{storage:"core.chinacloudapi.cn",authority:"https://login.chinacloudapi.cn"},usgovernment:{storage:"core.usgovcloudapi.net",authority:"https://login.microsoftonline.us"}};function AX(e,t,n){let r=ut(e.storage_account_name),o=ut(e.container_name),s=ut(e.key);if(!r||!o||!s)return{backend:"azurerm",unsupported:"the azurerm backend's storage_account_name, container_name or key is not in the configuration init recorded"};let i=t==="default"?s:`${s}env:${t}`,a=TX[ut(e.environment)??n.ARM_ENVIRONMENT??"public"],c=ut(e.metadata_host)??n.ARM_METADATA_HOSTNAME??n.ARM_METADATA_HOST;if(!a&&!c)return{backend:"azurerm",unsupported:`the azurerm backend's environment ${ut(e.environment)??n.ARM_ENVIRONMENT} is not public, china or usgovernment, and it names no metadata_host`};let u=ut(e.access_key)??n.ARM_ACCESS_KEY,l=ut(e.sas_token)??n.ARM_SAS_TOKEN,d=ut(e.tenant_id)??n.ARM_TENANT_ID,p=ut(e.client_id)??n.ARM_CLIENT_ID,f=ut(e.oidc_token_file_path)??n.ARM_OIDC_TOKEN_FILE_PATH,g;if(u)g={accountKey:u};else if(l)g={sas:l};else if(d&&p&&f)g={oidc:{tenantId:d,clientId:p,tokenFile:f,authority:(n.AZURE_AUTHORITY_HOST||a?.authority||Qy).replace(/\/+$/,"")}};else return{backend:"azurerm",unsupported:`the job has no credentials to read the container ${o} of ${r}: give the job oidc.azure (it sets ARM_TENANT_ID, ARM_CLIENT_ID and ARM_OIDC_TOKEN_FILE_PATH), or set ARM_ACCESS_KEY`};return{backend:"azurerm",account:r,container:o,key:i,snapshot:e.snapshot===!0||n.ARM_SNAPSHOT==="true",...c?{metadataHost:c}:{endpoint:`https://${r}.blob.${a.storage}`},auth:g}}function sw(e){if("unsupported"in e)return;if("gitlab"in e)return e.location;if(e.backend==="local")return e.path;let t=e;return t.backend==="gcs"?`gs://${t.bucket}/${t.key}`:t.backend==="azurerm"?`az://${t.account}/${t.container}/${t.key}`:`s3://${t.bucket}/${t.key}`}function iw(e,t){return new ld(e.target,t)}var dN=e=>vX("sha256").update(e).digest("hex");function OX(e,t){let n=iw(e,t),r=`${e.key}.tflock`,o=async()=>{let s=await n.head(e.key);return s.exists?s.versionId?{exists:!0,versionId:s.versionId}:{exists:!0,off:`bucket versioning is off for ${e.bucket}, so it keeps only the latest state`}:{exists:!1}};return{backend:"s3",location:`s3://${e.bucket}/${e.key}`,lockLocation:`s3://${e.bucket}/${r}`,version:o,hasVersion:s=>n.hasVersion(e.key,s),readVersion:s=>n.readVersion(e.key,s),isAt:async s=>(await o()).versionId===s,heldLock:async()=>{let s=await n.get(r);if(s!==void 0)return{id:nw(s),info:s}},lock:s=>n.putIfAbsent(r,s,"application/json"),unlock:()=>n.remove(r),readBeside:s=>n.get(`${e.key}${s}`),writeBeside:async(s,i)=>{await n.put(`${e.key}${s}`,i,"application/json")},adopt:()=>{}}}function nw(e){try{let t=JSON.parse(e);return typeof t.ID=="string"?t.ID:""}catch{return""}}function PX(e,t){let n=new Za(e.target,t),r,o=async()=>{let s=await n.head(e.key);return s.exists?(r??=n.versioning(),await r===!1?{exists:!0,off:`object versioning is off for ${e.bucket}, so it keeps only the latest state`}:{exists:!0,...s.generation?{versionId:s.generation}:{}}):{exists:!1}};return{backend:"gcs",location:`gs://${e.bucket}/${e.key}`,lockLocation:`gs://${e.bucket}/${e.lock}`,version:o,hasVersion:async s=>(await n.head(e.key,s)).exists,readVersion:s=>n.readGeneration(e.key,s),isAt:async s=>(await n.head(e.key)).generation===s,heldLock:async()=>{let s=await n.head(e.lock),i=s.exists?await n.get(e.lock):void 0;if(!(!s.exists||i===void 0))return{id:s.generation??nw(i),info:i}},lock:s=>n.putIfAbsent(e.lock,s,"application/json"),unlock:()=>n.remove(e.lock),readBeside:s=>n.get(`${e.key}${s}`),writeBeside:async(s,i)=>{await n.put(`${e.key}${s}`,i,"application/json")},adopt:()=>{}}}var pN="terraformlockid";async function jX(e,t){if(e.endpoint)return e.endpoint;let n=`https://${e.metadataHost}/metadata/endpoints?api-version=2023-11-01`,r=await t(n,{method:"GET",headers:{accept:"application/json"}}),o=await r.text();if(!r.ok)throw new Y(`the Azure metadata at ${e.metadataHost}: ${r.status}`);let s;try{let i=JSON.parse(o);s=(Array.isArray(i)?i[0]:i)?.suffixes?.storage}catch{}if(typeof s!="string"||s==="")throw new Y(`the Azure metadata at ${e.metadataHost} names no storage suffix`);return`https://${e.account}.blob.${s.replace(/^\.+/,"")}`}async function IX(e,t=fetch){let n=await jX(e,t),r=new ud({account:e.account,container:e.container,endpoint:n,...e.auth},t),o,s=async a=>(await r.head(e.key)).versionId?{versionid:a}:{snapshot:a},i=async(a=!1)=>{let c=await r.head(e.key);return c.exists?c.versionId?{exists:!0,versionId:c.versionId}:e.snapshot?a?{exists:!0,versionId:await r.snapshot(e.key)}:{exists:!0}:{exists:!0,off:`blob versioning is off for ${e.account}, and the backend takes no snapshots (snapshot = true), so it keeps only the latest state`}:{exists:!1}};return{backend:"azurerm",location:`az://${e.account}/${e.container}/${e.key}`,lockLocation:`az://${e.account}/${e.container}/${e.key}`,version:i,hasVersion:async a=>(await r.head(e.key,await s(a))).exists,readVersion:async a=>r.readAt(e.key,await s(a)),isAt:async a=>{let c=await r.head(e.key);if(c.versionId)return c.versionId===a;let[u,l]=await Promise.all([r.readAt(e.key,{snapshot:a}),r.get(e.key)]);return u!==void 0&&l!==void 0&&dN(u)===dN(l)},heldLock:async()=>{let a=await r.head(e.key);if(!a.exists||a.leaseState!=="leased")return;let c=a.metadata[pN],u=c?Buffer.from(c,"base64").toString("utf-8"):"";return{id:nw(u),info:u}},lock:async a=>{let c=nw(a);return(await r.head(e.key)).exists||await r.putBlob(e.key,"","application/json",{ifNoneMatch:!0}),await r.lease(e.key,"acquire",c)?(o=c,await r.setMetadata(e.key,{[pN]:Buffer.from(a).toString("base64")},c),!0):!1},unlock:async()=>{if(!o)return;let a=o;await r.setMetadata(e.key,{},a),await r.lease(e.key,"release",a),o=void 0},write:async a=>{if(!o)throw new Y(`${e.key} is written under its lease, and none is held`);e.snapshot&&(await r.head(e.key)).exists&&await r.snapshot(e.key);let c=(await r.head(e.key)).metadata;await r.putBlob(e.key,a,"application/json",{leaseId:o,metadata:c})},readBeside:a=>r.get(`${e.key}${a}`),writeBeside:async(a,c)=>{await r.put(`${e.key}${a}`,c,"application/json")},adopt:a=>{o=a.id}}}async function Ws(e,t){return e.backend==="s3"?OX(e,t):e.backend==="gcs"?PX(e,t):IX(e,t)}async function Hf(e,t=process.env,n,r){let o=r?Hr(e,t,r):Hr(e,t);if("unsupported"in o)return{backend:o.backend,...o.location?{location:o.location}:{},versioning:o.versions?.versioning??"unknown",note:o.versions?.note??o.unsupported};if(o.backend==="local")return{backend:"local",location:o.path,versioning:"off",note:"a local backend keeps only the latest state"};if("gitlab"in o)try{let i=await Yy(o.gitlab,n??globalThis.fetch);return i?{backend:"http",location:o.location,version_id:String(i.serial),versioning:"on"}:{backend:"http",location:o.location,versioning:"unknown",note:"GitLab holds no state at this address"}}catch(i){return{backend:"http",location:o.location,versioning:"unknown",note:i.message}}if(!ar(o))return{backend:o.backend,versioning:"unknown",note:"terragucci reads no versions of this state"};let s=sw(o);try{let i=await(await Ws(o,n)).version(!0);return i.exists?i.versionId?{backend:o.backend,location:s,version_id:i.versionId,versioning:"on"}:i.off?{backend:o.backend,location:s,versioning:"off",note:i.off}:{backend:o.backend,location:s,versioning:"unknown",note:"the store gave no version id"}:{backend:o.backend,location:s,versioning:"unknown",note:`the state object is not in the ${o.backend==="azurerm"?"container":"bucket"}`}}catch(i){return{backend:o.backend,location:s,versioning:"unknown",note:i.message}}}import{execFile as CX}from"node:child_process";var NX=["TG_TOKEN","TG_MERGE_TOKEN","GITHUB_TOKEN","GH_TOKEN","GITLAB_TOKEN","CI_JOB_TOKEN","FORGEJO_TOKEN","GITEA_TOKEN","ACTIONS_RUNTIME_TOKEN"];function Ve(e){let t=new Set([e.TG_TOKEN,e.TG_MERGE_TOKEN].filter(r=>typeof r=="string"&&r.length>0)),n={};for(let[r,o]of Object.entries(e))NX.includes(r)||o!==void 0&&t.has(o)&&!r.startsWith("TF_")||(n[r]=o);return n}var Nn=(e,t,n)=>new Promise(r=>{CX(e,[...t],{cwd:n.cwd,env:Ve({...process.env,...n.env}),maxBuffer:256*1024*1024},(o,s,i)=>{let a=o?typeof o.code=="number"?o.code:null:0;r({code:a,stdout:String(s),stderr:o&&a===null?`${String(i)}${o.message}`:String(i)})})});import{existsSync as FR,readdirSync as FN,readFileSync as Qf,statSync as A7}from"node:fs";import{dirname as O7,join as eg,relative as fw,resolve as GR}from"node:path";import{execFile as qX}from"node:child_process";import{existsSync as yd,mkdirSync as EN,readFileSync as uw,realpathSync as JX,rmSync as TN,writeFileSync as KX}from"node:fs";import{dirname as VX,join as ds,resolve as Kf}from"node:path";function TR(e){let t=e,r=(Array.isArray(t?.resource_changes)?t.resource_changes:[]).map(s=>{let i=s??{},a=i.change??{};return{address:i.address,mode:i.mode,type:i.type,name:i.name,index:i.index,provider_name:i.provider_name,deposed:i.deposed,actions:a.actions,before:a.before,after:a.after,after_unknown:a.after_unknown,replace_paths:a.replace_paths,importing:a.importing}});r.sort((s,i)=>`${String(s.address)}\0${String(s.deposed??"")}`.localeCompare(`${String(i.address)}\0${String(i.deposed??"")}`));let o=Array.isArray(t?.action_invocations)?[...t.action_invocations].sort((s,i)=>JSON.stringify(s).localeCompare(JSON.stringify(i))):[];return{resourceChanges:r,outputChanges:t?.output_changes??{},...o.length>0?{actionInvocations:o}:{}}}function gN(e){return Rn("terraform-plan",TR(e))}var Tr=e=>e!==null&&typeof e=="object"&&!Array.isArray(e);function qf(e){return e===!0?!0:Array.isArray(e)?e.some(qf):Tr(e)?Object.values(e).some(qf):!1}function AR(e,t){if(e===t)return!0;if(Array.isArray(e)&&Array.isArray(t))return e.length===t.length&&e.every((n,r)=>AR(n,t[r]));if(Tr(e)&&Tr(t)){let n=Object.keys(e);return n.length===Object.keys(t).length&&n.every(r=>r in t&&AR(e[r],t[r]))}return!1}function nn(e){let t=(e??"terraform").split(/[\\/]/).pop()??"";return t.startsWith("choudoufu")?"choudoufu":t.startsWith("tofu")?"tofu":"terraform"}function DX(e){let t=Array.isArray(e)?e.map(String):[];if(t.length===2&&t.includes("delete")&&t.includes("create"))return"replace";if(t.length===1)switch(t[0]){case"create":case"update":case"delete":case"read":case"no-op":case"forget":return t[0]}throw new Error(`a plan entry has actions ${JSON.stringify(e)}, which the change set has no action for`)}function MX(e,t){switch(t){case"update":return"in-place";case"delete":return"destroy";case"replace":return e[0]==="create"?"replace":"destroy";default:return}}function LX(e){let n=/^((?:module\.[^.[\]]+(?:\[(?:"(?:[^"\\]|\\.)*"|\d+)\])?\.)*)(?:data\.)?([^.[\]]+)\.([^.[\]]+)(?:\[("(?:[^"\\]|\\.)*"|\d+)\])?$/.exec(e);if(!n)return{type:"unknown",name:e};let r=n[1]?n[1].slice(0,-1):void 0,o=n[4]===void 0?void 0:n[4].startsWith('"')?JSON.parse(n[4]):Number(n[4]);return{...r?{module:r}:{},type:n[2],name:n[3],...o!==void 0?{index:o}:{}}}function GX(e,t){if(t==="delete"||t==="no-op"||t==="forget"||t==="read")return[];let n=Tr(e.before)?e.before:{},r=Tr(e.after)?e.after:{},o=Tr(e.after_unknown)?e.after_unknown:{},s=Tr(e.before_sensitive)?e.before_sensitive:{},i=Tr(e.after_sensitive)?e.after_sensitive:{},a=new Set((Array.isArray(e.replace_paths)?e.replace_paths:[]).map(l=>Array.isArray(l)?l[0]:void 0).filter(l=>typeof l=="string")),c=[...new Set([...Object.keys(n),...Object.keys(r),...Object.keys(o)])].sort(),u=[];for(let l of c){let d=qf(o[l]),p=t!=="create"&&n[l]!==void 0&&n[l]!==null,f=r[l]!==void 0&&r[l]!==null;if(t==="create"?!f&&!d:!d&&AR(n[l]??null,r[l]??null))continue;let g=qf(s[l])||qf(i[l]);u.push({path:l,...g?{sensitive:!0}:{...p?{before:n[l]}:{},...f&&!d?{after:r[l]}:{}},...d?{unknown:!0}:{},...a.has(l)?{forcesReplacement:!0}:{}})}return u}function FX(e){for(let t of[e.after,e.before])if(Tr(t)&&typeof t.region=="string"&&t.region!=="")return t.region}function fo(e){let t=Tr(e.plan)?e.plan:{},n=e.planner??"terraform",o=(Array.isArray(t.resource_changes)?t.resource_changes:[]).map(a=>{let c=Tr(a)?a:{},u=Tr(c.change)?c.change:{},l=String(c.address??""),d=LX(l),p=DX(u.actions),f=MX(u.actions,p),g=FX(u),m=c.index!==void 0&&c.index!==null?c.index:d.index,h=typeof c.module_address=="string"?c.module_address:d.module;return{member:e.member,lexicon:"terraform",planner:n,address:l,type:typeof c.type=="string"?c.type:d.type,name:typeof c.name=="string"?c.name:d.name,...m!==void 0?{index:m}:{},...h?{module:h}:{},...typeof c.deposed=="string"?{deposed:c.deposed}:{},action:p,...Tr(u.importing)?{importing:!0}:{},...f?{disruption:f}:{},...g?{region:g}:{},...e.scope?{scope:e.scope}:{},attributes:GX(u,p)}}),s=(Array.isArray(t.action_invocations)?t.action_invocations:[]).map(zX),i=t.errored===!0;return{member:{member:e.member,lexicon:"terraform",planner:n,...e.scope?{scope:e.scope}:{},status:i?"failed":"planned",...i?{error:`${n} marked the plan errored`}:{},planDigest:gN(t),...e.nativeDigest?{nativeDigest:e.nativeDigest}:{},holes:[]},entries:o,...s.length>0?{sideEffects:s}:{}}}function zX(e){let t=Tr(e)?e:{},n=typeof t.type=="string"?t.type:"unknown",r=Tr(t.lifecycle_action_trigger)?t.lifecycle_action_trigger:{};return{address:typeof t.address=="string"?t.address:n,type:n,...typeof r.triggering_resource_address=="string"?{trigger:r.triggering_resource_address}:{},...typeof r.action_trigger_event=="string"?{event:r.action_trigger_event}:{}}}var Xa=e=>e!==null&&typeof e=="object"&&!Array.isArray(e);function OR(e){let t=e.replace(/\\/g,"/"),n=[];for(let o of t.split("/"))o===""||o==="."||(o===".."&&n.length>0&&n[n.length-1]!==".."?n.pop():n.push(o));let r=n.join("/");return t.startsWith("/")?`/${r}`:r||"."}var UX=e=>e.startsWith("/")||/^[A-Za-z]:[\\/]/.test(e);function PR(e,t,n){let r=t.replace(/\\/g,"/").replace(/(^|\/)terragrunt\.hcl$/,"");if(!UX(r))return OR(`${e}/${r}`);let o=OR(r);for(let s of typeof n=="string"?[n]:n){let i=OR(s);if(o===i)return".";if(o.startsWith(`${i}/`))return o.slice(i.length+1)}return o}function mN(e,t,n){let r=typeof t=="string"?JSON.parse(t):t;if(!Xa(r))throw new Error("terragrunt render --json did not print an object");let o=Xa(r.dependency)?r.dependency:{},s=[];for(let[i,a]of Object.entries(o)){if(!Xa(a)||typeof a.config_path!="string")continue;let c=Array.isArray(a.mock_outputs_allowed_terraform_commands)?a.mock_outputs_allowed_terraform_commands.filter(l=>typeof l=="string"):void 0,u=typeof a.mock_outputs_merge_strategy_with_state=="string"?a.mock_outputs_merge_strategy_with_state:a.mock_outputs_merge_with_state===!0?"shallow":void 0;s.push({name:typeof a.name=="string"&&a.name?a.name:i,upstream:PR(e,a.config_path,n),...Xa(a.mock_outputs)?{mockOutputs:a.mock_outputs}:{},...c?{mockAllowed:c}:{},...u&&u!=="no_merge"?{mergeStrategy:u}:{},...a.skip===!0||a.skip_outputs===!0?{skipOutputs:!0}:{},...a.enabled===!1?{disabled:!0}:{}})}return s.sort((i,a)=>i.name<a.name?-1:i.name>a.name?1:0)}function hN(e){let t=e.trim(),n=t.indexOf("{");if(n<0)return;let r;try{r=JSON.parse(t.slice(n))}catch{return}if(Xa(r))return Object.fromEntries(Object.entries(r).map(([o,s])=>[o,Xa(s)&&"value"in s?s.value:s]))}function yN(e){return["run","--working-dir",e,"--non-interactive","--no-color","--","output","-json"]}function aw(e){return["render","--json","--non-interactive","--no-color","--working-dir",e]}function wN(e,t,n,r=""){let o=[];for(let[s,i]of Object.entries(e)){let a=r?`${r}.${s}`:s;s in t?n&&Xa(i)&&Xa(t[s])&&o.push(...wN(i,t[s],n,a)):o.push(a)}return o.sort()}var BX=e=>!e.mockAllowed||e.mockAllowed.length===0||e.mockAllowed.includes("plan");function bN(e){let t=[];for(let[n,r]of e.dependencies)for(let o of r){let s={unit:n,dependency:o.name,upstream:o.upstream};if(o.disabled||o.skipOutputs){o.mockOutputs&&t.push({...s,reason:o.disabled?"disabled":"skip-outputs"});continue}let i=e.outputs.get(o.upstream)??{};if(Object.keys(i).length===0){t.push({...s,reason:"no-outputs"});continue}if(o.mockOutputs&&o.mergeStrategy&&BX(o)){let a=wN(o.mockOutputs,i,o.mergeStrategy!=="shallow");a.length>0&&t.push({...s,reason:"partial",keys:a})}}return t.sort((n,r)=>n.unit<r.unit?-1:n.unit>r.unit?1:n.dependency<r.dependency?-1:n.dependency>r.dependency?1:0)}function vN(e){let t=new Set;for(let n of e.values())for(let r of n)!r.disabled&&!r.skipOutputs&&t.add(r.upstream);return[...t].sort()}function WX(e){let t=`${e.unit} (dependency "${e.dependency}" on ${e.upstream})`;switch(e.reason){case"no-outputs":return`${t}: ${e.upstream} has no outputs yet; apply ${e.upstream} first`;case"partial":return`${t}: ${e.upstream}'s outputs lack ${e.keys.join(", ")}, which the merge strategy fills from mock_outputs; apply ${e.upstream} with those outputs first, or drop the merge strategy`;case"skip-outputs":return`${t}: skip_outputs = true with mock_outputs set always reads the mock; read the real outputs or drop mock_outputs`;case"disabled":return`${t}: enabled = false with mock_outputs set always reads the mock; enable the dependency or drop mock_outputs`}}function $N(e){let t=[...new Set(e.filter(r=>r.reason==="no-outputs"||r.reason==="partial").map(r=>r.upstream))].sort();return["this wave was not planned and is not gated: its plans would read mock_outputs, so nobody could approve them as real. "+(t.length>0?`Apply ${t.join(", ")} first, then plan the wave again.`:"Fix the dependency blocks below, then plan the wave again."),...e.map(r=>` ${WX(r)}`)].join(`
49
- `)}var HX=/Config (\S+?) is a dependency of (\S+?) that has no outputs, but mock outputs provided/g;function kN(e,t){let n=new Set,r=[];for(let o of e.matchAll(HX)){let s=PR(".",o[2],t),i=PR(".",o[1],t),a=`${s}\0${i}`;n.has(a)||(n.add(a),r.push({unit:s,upstream:i}))}return r.sort((o,s)=>o.unit<s.unit?-1:o.unit>s.unit?1:o.upstream<s.upstream?-1:1)}function _N(e,t){let n=new Map;for(let r of t)n.set(r.unit,[...n.get(r.unit)??[],r.upstream]);return e.map(r=>{let o=n.get(r.member.member);return o?{member:{...r.member,status:"failed",error:`planned on mock_outputs: ${o.join(", ")} had no outputs when Terragrunt planned it; apply ${o.join(", ")} first`,planDigest:null},entries:[]}:r})}function SN(e){return e.map(t=>({...t,member:{...t.member,provisional:!0}}))}var jR="PROVISIONAL";function IR(e){if(e.units.length===0)throw new Error("a Terragrunt wave needs at least one unit; with no path filter run --all would run every unit");if(e.parallelism!==void 0&&(!Number.isInteger(e.parallelism)||e.parallelism<1))throw new Error(`parallelism must be a whole number of 1 or more, got ${e.parallelism}`);return["run","--all","--non-interactive","--no-color","--no-filters-file",...[...new Set(e.units)].sort().flatMap(r=>["--filter",eC(r)]),...e.destroy?["--filter-allow-destroy"]:[],"--out-dir",e.outDir,...e.command==="plan"&&e.jsonOutDir?["--json-out-dir",e.jsonOutDir]:[],"--report-file",e.reportFile,"--report-format","json",...e.parallelism!==void 0?["--parallelism",String(e.parallelism)]:[],"--",e.command,...e.command==="plan"&&e.destroy?["-destroy"]:[],...e.extra??[]]}function zi(e){return e?{TG_TF_PATH:e}:{}}function Jf(e){let t=typeof e=="string"?JSON.parse(e.trim()===""?"[]":e):e,n=Array.isArray(t)?t:[],r=new Map;for(let o of n){if(o===null||typeof o!="object")continue;let s=o;if(typeof s.Name!="string"||typeof s.Result!="string")continue;let i=s.Name.replace(/\\/g,"/").replace(/^\.\//,"");r.set(i,{name:i,result:s.Result,...typeof s.Reason=="string"&&s.Reason?{reason:s.Reason}:{},...typeof s.Cause=="string"&&s.Cause?{cause:s.Cause.trim()}:{},...typeof s.Cmd=="string"?{cmd:s.Cmd}:{},...typeof s.Started=="string"?{started:s.Started}:{},...typeof s.Ended=="string"?{ended:s.Ended}:{}})}return r}function cw(e,t){return[...new Set(e)].sort().map(n=>{let r=t.get(n);if(!r)return{unit:n,status:"failed",result:"not run",error:"not in Terragrunt's run report, so it did not run"};if(r.result==="succeeded")return{unit:n,status:"succeeded",result:r.result};let o=[r.reason,r.cause].filter(Boolean).join(": ");return{unit:n,status:"failed",result:r.result,error:`${r.result}${o?` (${o})`:""}`}})}function RN(e){let t=e.scopeFor??jy;return cw(e.units,e.report).map(n=>{let r=t(n.unit),o=n.status==="succeeded"?e.planFor(n.unit):void 0;return n.status==="succeeded"&&o!==void 0?fo({member:n.unit,plan:o,planner:e.planner,...r?{scope:r}:{}}):{member:{member:n.unit,lexicon:"terraform",planner:e.planner,...r?{scope:r}:{},status:"failed",error:n.error??"Terragrunt reported the unit succeeded but wrote no plan JSON for it",planDigest:null,holes:[]},entries:[]}})}var Eu=(e,t,n)=>new Promise(r=>{qX(e,[...t],{cwd:n.cwd,env:{...process.env,...n.env},maxBuffer:256*1024*1024},(o,s,i)=>{let a=o?typeof o.code=="number"?o.code:null:0;r({code:a,stdout:String(s),stderr:o&&a===null?`${String(i)}${o.message}`:String(i)})})}),cr=class extends Error{constructor(t){super(t),this.name="TerragruntError"}};async function lw(e){let t=e.exec??Eu,n=e.terragrunt??"terragrunt",r=await t(n,["--version"],{cwd:e.dir,env:{}});if(r.code!==0)throw new cr(`\`${n} --version\` failed (exit ${r.code}): ${(r.stderr||r.stdout).trim()}`);let o=QI(r.stdout);if(o)throw new cr(o);return r.stdout.trim()}async function dw(e){let t=e.exec??Eu,n=e.terragrunt??"terragrunt",r=tC(e),o=await t(n,r,{cwd:e.dir,env:zi(e.binary)});if(o.code!==0)throw new cr(`\`${n} ${r.join(" ")}\` failed (exit ${o.code}): ${o.stderr.trim()}`);let s;try{s=Py(o.stdout)}catch(i){throw new cr(`could not read \`terragrunt find\` output: ${i instanceof Error?i.message:String(i)}`)}return{units:s,warnings:e.binary?YX(e.dir,s,e.binary):[]}}var ZX=/^\s*terraform_binary\s*=\s*(.+?)\s*$/m;function YX(e,t,n){let r=[];for(let o of t){let s=[ds(o.path,"terragrunt.hcl"),...Object.values(o.include??{})];for(let i of s){let a;try{a=uw(Kf(e,i),"utf8")}catch{continue}let c=ZX.exec(a);if(!c)continue;let u=/^"([^"$]*)"$/.exec(c[1]);if(u&&u[1]===n)break;r.push(`${o.path}: ${i} sets terraform_binary = ${c[1]}, but the project's binary is ${n}; TG_TF_PATH=${n} overrides it, so the unit runs ${n}`);break}}return r}function XX(e){return nn(e??"tofu")}var Hs=class extends cr{constructor(n){super($N(n));this.reads=n;this.name="TerragruntMockRefusal"}reads};async function xN(e,t,n){let r=new Array(e.length),o=0,s=async()=>{for(;o<e.length;){let i=o++;r[i]=await n(e[i])}};return await Promise.all(Array.from({length:Math.max(1,Math.min(t,e.length))},s)),r}function AN(e){let t=Kf(e);try{let n=JX(t);return n===t?[t]:[t,n]}catch{return[t]}}async function QX(e){let t=e.exec??Eu,n=e.terragrunt??"terragrunt",r=zi(e.binary),o=e.parallelism??8,s=AN(e.dir),i=[...new Set(e.units)].sort().filter(d=>yd(ds(Kf(e.dir),d,"terragrunt.hcl"))),a=await xN(i,o,async d=>{let p=aw(d),f=await t(n,p,{cwd:e.dir,env:r});if(f.code!==0)throw new cr(`\`${n} ${p.join(" ")}\` failed (exit ${f.code}), so the wave's dependencies are unknown: ${f.stderr.trim()}`);try{return[d,mN(d,f.stdout,s)]}catch(g){throw new cr(`could not read \`terragrunt render --json\` for ${d}: ${g instanceof Error?g.message:String(g)}`)}}),c=new Map(a),u=vN(c),l=await xN(u,o,async d=>{let p=yN(d),f=await t(n,p,{cwd:e.dir,env:r}),g=f.code===0?hN(f.stdout):void 0;if(!g)throw new cr(`could not read the outputs of ${d}, which the wave reads (\`${n} ${p.join(" ")}\` exit ${f.code}): ${(f.stderr||f.stdout).trim().slice(-2e3)}`);return[d,g]});return bN({dependencies:c,outputs:new Map(l)})}async function pw(e){let t=e.exec??Eu,n=e.terragrunt??"terragrunt",r=Kf(e.dir,e.workDir),o=ds(r,"plans"),s=ds(r,"json"),i=ds(r,"plan-report.json"),a=ds(r,jR);for(let m of[o,s,i,a])TN(m,{recursive:!0,force:!0});if(!e.provisional){let m=await QX({...e,exec:t});if(m.length>0)throw new Hs(m)}EN(r,{recursive:!0}),e.provisional&&KX(a,`planned before its upstream applied; never applied
50
- `);let c=IR({units:e.units,command:"plan",outDir:o,jsonOutDir:s,reportFile:i,...e.destroy?{destroy:!0}:{},...e.parallelism!==void 0?{parallelism:e.parallelism}:{}}),u=await t(n,c,{cwd:e.dir,env:zi(e.binary)}),l=yd(i)?Jf(uw(i,"utf8")):new Map,d=m=>{let h=ds(s,m,"tfplan.json");return yd(h)?JSON.parse(uw(h,"utf8")):void 0},p=RN({units:e.units,report:l,planFor:d,planner:XX(e.binary)}),f=new Set(e.units),g=kN(`${u.stderr}
51
- ${u.stdout}`,AN(e.dir)).filter(m=>f.has(m.unit));return{parts:e.provisional?SN(p):_N(p,g),provisional:e.provisional===!0,results:cw(e.units,l),code:u.code,log:u.stderr}}async function ON(e){let t=e.exec??Eu,n=e.terragrunt??"terragrunt",r=Kf(e.dir,e.workDir),o=ds(r,"plans");if(e.provisional||yd(ds(r,jR)))throw new cr(`the plans under ${r} are provisional: planned before their upstream applied, possibly on mock_outputs. They are never applied; plan the wave again once its upstream applied`);let s=[...new Set(e.units)].sort().filter(l=>!yd(ds(o,l,"tfplan.tfplan")));if(s.length>0)throw new cr(`no saved plan for ${s.join(", ")} under ${o}; plan the wave before applying it, so apply runs the plan that was reviewed`);let i=ds(r,"apply-report.json");TN(i,{force:!0}),EN(VX(i),{recursive:!0});let a=IR({units:e.units,command:"apply",outDir:o,reportFile:i,...e.destroy?{destroy:!0}:{},...e.parallelism!==void 0?{parallelism:e.parallelism}:{}}),c=await t(n,a,{cwd:e.dir,env:zi(e.binary)}),u=yd(i)?Jf(uw(i,"utf8")):new Map;return{results:cw(e.units,u),code:c.code,log:c.stderr}}import{readFileSync as R7}from"node:fs";import{join as x7}from"node:path";import{existsSync as d7,readdirSync as p7,readFileSync as f7}from"node:fs";import{join as DR,posix as Zf,relative as g7,resolve as m7,sep as h7}from"node:path";import{existsSync as e7,readdirSync as t7,readFileSync as n7,statSync as r7}from"node:fs";import{join as o7,posix as jN,relative as s7,resolve as CR,sep as i7}from"node:path";var a7=/\bsource\s*=\s*"(\.{1,2}\/[^"]*)"/g,c7=e=>e.split(i7).join("/");function PN(e,t){let n=c7(s7(e,t));return n===""?".":jN.normalize(n).replace(/\/+$/,"")}function u7(e){let t;try{t=t7(e)}catch{return[]}let n=[];for(let r of t){if(!r.endsWith(".tf")&&!r.endsWith(".tofu"))continue;let o;try{o=n7(o7(e,r),"utf8")}catch{continue}for(let s of o.matchAll(a7)){let i=CR(e,s[1].replace("//","/"));e7(i)&&r7(i).isDirectory()&&n.push(i)}}return n}function NR(e,t){let n=CR(e,t.dir),r=new Set,o=[n];for(;o.length>0;){let i=o.shift();r.has(i)||(r.add(i),o.push(...u7(i)))}let s=[...r].map(i=>PN(e,i));for(let i of t.varFiles??[])s.push(PN(e,CR(n,i)));return[...new Set(s)].sort()}function l7(e,t){return e==="."?!t.startsWith("../"):t===e||t.startsWith(`${e}/`)}function Vf(e,t,n){let r=n.map(s=>jN.normalize(s)),o=[];for(let[s,i]of Object.entries(t)){let a=NR(e,i);r.some(c=>a.some(u=>l7(u,c)))&&o.push(s)}return o.sort()}var IN=["terragrunt","removed","module-file","module-call","stack-template"],y7=/\.(tf|tofu)(\.json)?$/,NN=e=>e.split(h7).join("/"),Yf=e=>Zf.normalize(NN(e)).replace(/^\.\//,"").replace(/\/+$/,""),Tu=(e,t)=>e==="."||t===e||t.startsWith(`${e}/`);function w7(e){let t=[...hu,...e.exclude??[]];return["find","--json","--no-color","--no-filters-file","--filter",`[${e.base}...${e.head??"HEAD"}]`,...t.flatMap(n=>["--filter",hf(n)])]}function b7(e){return["diff","--name-only","--no-renames","--relative",`${e.base}...${e.head??"HEAD"}`]}function v7(e){let t=new Set;for(let n of e.reading??[])!y7.test(n)||Tu(e.path,n)||n.includes(".terragrunt-cache/")||t.add(Zf.dirname(n));return[...t].sort()}function MR(e,t,n){let r=Zf.dirname(Yf(t)),o=[],s=/\b(unit|stack)\s+"([^"]+)"\s*\{/g;for(let i=s.exec(n);i;i=s.exec(n)){let a=$7(n,s.lastIndex),c=CN(a,"source"),u=CN(a,"path");if(u===void 0)continue;let d=/^\s*no_dot_terragrunt_stack\s*=\s*true\b/m.test(a)?r:Zf.join(r,".terragrunt-stack"),p=Yf(Zf.join(d,u)),f;if(c!==void 0){let g=c.replace(/^\$\{get_terragrunt_dir\(\)\}\//,"./");/^\.{1,2}\//.test(g)&&(f=Yf(NN(g7(e,m7(e,r,g.replace("//","/"))))))}o.push({type:i[1],name:i[2],generated:p,...f!==void 0?{template:f}:{}})}return o}function $7(e,t){let n=1;for(let r=t;r<e.length;r++){let o=e[r];if(o==='"')for(r++;r<e.length&&e[r]!=='"';r++)e[r]==="\\"&&r++;else if(o==="#"||o==="/"&&e[r+1]==="/")for(;r<e.length&&e[r]!==`
48
+ `),d=Ya(Ya(Ya(Ya(`AWS4${e.secretAccessKey}`,s.slice(0,8)),e.region),"s3"),"aws4_request");return`${o.origin}${o.pathname}?${c}&X-Amz-Signature=${RR("sha256",d).update(l).digest("hex")}`}var ld=class{constructor(t,n=fetch){this.target=t;this.fetchFn=n}target;fetchFn;creds;conditional=!0;get location(){return`s3://${this.target.bucket}`}async signer(){let t=this.target;if(!("webIdentity"in t))return t;let n=()=>this.creds=Bf(t.webIdentity,this.fetchFn).catch(a=>{throw this.creds=void 0,a}),r=await(this.creds??n());r.expiration&&r.expiration.getTime()-Date.now()<6e4&&(r=await n());let{accessKeyId:o,secretAccessKey:s,sessionToken:i}=r;return{bucket:t.bucket,...t.endpoint?{endpoint:t.endpoint}:{},region:t.region,accessKeyId:o,secretAccessKey:s,...i?{sessionToken:i}:{}}}async put(t,n,r,o){let s=!o||!this.conditional?{}:"ifMatch"in o?{"if-match":o.ifMatch}:{"if-none-match":"*"},{url:i,headers:a}=zf(await this.signer(),"PUT",t,n,new Date,r,s),c=await this.fetchFn(i,{method:"PUT",headers:a,body:n});if(c.status===501&&Object.keys(s).length)return this.conditional=!1,this.put(t,n,r);if(c.status===412||c.status===409&&Object.keys(s).length)throw new Er(`PUT s3://${this.target.bucket}/${t}: ${c.status}, it changed since it was read`);if(!c.ok)throw new Y(`PUT s3://${this.target.bucket}/${t}: ${c.status} ${(await c.text()).slice(0,300)}`);let u=c.headers?.get("etag")??void 0;return u?{etag:u}:{}}async read(t){let{url:n,headers:r}=zf(await this.signer(),"GET",t,""),o=await this.fetchFn(n,{method:"GET",headers:r});if(o.status===404)return{};if(!o.ok)throw new Y(`GET s3://${this.target.bucket}/${t}: ${o.status} ${(await o.text()).slice(0,300)}`);let s=o.headers?.get("etag")??void 0;return{body:await o.text(),...s?{etag:s}:{}}}async presign(t,n,r=new Date){let o=await this.signer(),s=y7(o,tw(o,t),n,r),i=new Date(r.getTime()+n*1e3),a=this.creds?await this.creds:void 0;return a?.expiration&&a.expiration<i&&(i=a.expiration),{url:s,expires:i}}async get(t){return(await this.read(t)).body}async head(t){let{url:n,headers:r}=zf(await this.signer(),"HEAD",t,""),o=await this.fetchFn(n,{method:"HEAD",headers:r});if(o.status===404)return{exists:!1};if(!o.ok)throw new Y(`HEAD s3://${this.target.bucket}/${t}: ${o.status}`);let s=o.headers?.get("etag")??void 0,i=o.headers?.get("x-amz-version-id")??void 0;return{exists:!0,...s?{etag:s}:{},...i&&i!=="null"?{versionId:i}:{}}}async putIfAbsent(t,n,r){let{url:o,headers:s}=zf(await this.signer(),"PUT",t,n,new Date,r,{"if-none-match":"*"}),i=await this.fetchFn(o,{method:"PUT",headers:s,body:n});if(i.status===412||i.status===409)return!1;if(i.status===501)throw new Y(`PUT s3://${this.target.bucket}/${t}: the store does not take a conditional write (501)`);if(!i.ok)throw new Y(`PUT s3://${this.target.bucket}/${t}: ${i.status} ${(await i.text()).slice(0,300)}`);return!0}async readVersion(t,n){let r=await this.signer(),o=`${tw(r,t)}?versionId=${Zt(n)}`,s=await this.fetchFn(o,{method:"GET",headers:xu(r,"GET",o,{},Uf(""),new Date)});if(s.status!==404){if(!s.ok)throw new Y(`GET s3://${this.target.bucket}/${t}?versionId=${n}: ${s.status} ${(await s.text()).slice(0,300)}`);return s.text()}}async hasVersion(t,n){let r=await this.signer(),o=`${tw(r,t)}?versionId=${Zt(n)}`,s=await this.fetchFn(o,{method:"HEAD",headers:xu(r,"HEAD",o,{},Uf(""),new Date)});if(s.status===404||s.status===400)return!1;if(!s.ok)throw new Y(`HEAD s3://${this.target.bucket}/${t}?versionId=${n}: ${s.status}`);return!0}async remove(t){let{url:n,headers:r}=zf(await this.signer(),"DELETE",t,""),o=await this.fetchFn(n,{method:"DELETE",headers:r});if(!o.ok&&o.status!==404)throw new Y(`DELETE s3://${this.target.bucket}/${t}: ${o.status} ${(await o.text()).slice(0,300)}`)}};import{posix as pd,sep as uN}from"node:path";var fd=e=>({unresolved:e});function Gi(e){if(e!==void 0)return typeof e=="string"&&!/\$\{|%\{/.test(e)?e:null}function lN(e,t){try{let n=new URL(e.includes("://")?e:`http://${e}`),r=n.pathname.replace(/\/+$/,"");return`${t?`${n.protocol}//`:""}${n.host.toLowerCase()}${r}`}catch{return}}function w7(e){if(/^postgres(ql)?:\/\//i.test(e))try{let o=new URL(e),s=o.pathname.replace(/^\/+/,"")||o.searchParams.get("dbname"),i=o.host.toLowerCase()||o.searchParams.get("host");return i&&s?`${i}/${s}`:void 0}catch{return}let t=new Map([...e.matchAll(/(\w+)\s*=\s*('(?:[^'\\]|\\.)*'|\S+)/g)].map(o=>[o[1],o[2].replace(/^'|'$/g,"")])),n=t.get("host")?.toLowerCase(),r=t.get("dbname");if(!(!n||!r))return`${n}${t.get("port")?`:${t.get("port")}`:""}/${r}`}function gd(e,t,n){let r=(c,u)=>fd(t(c)===null?`its ${e} ${c} is an expression, not a plain string`:`its ${e} backend names no ${c} in the code (${u?`${u} or `:""}a -backend-config file supplies it)`);switch(e){case"local":{let c=t("path");if(c===null)return r("path");let u=(c??"terraform.tfstate").split(uN).join(pd.sep);return{key:`local:${pd.isAbsolute(u)?pd.normalize(u):pd.normalize(pd.join(n.split(uN).join(pd.sep)||".",u))}`}}case"pg":{let c=t("conn_str");if(!c)return r("conn_str","PG_CONN_STR");let u=w7(c);if(!u)return fd("its pg conn_str names no host and database");let l=t("schema_name"),d=t("table_name");return l===null?r("schema_name"):d===null?r("table_name"):{key:`pg:${u}/${l??"terraform_remote_state"}.${d??"states"}`}}case"http":{let c=t("address");if(!c)return r("address","TF_HTTP_ADDRESS");let u=lN(c,!0);return u?{key:`http:${u}`}:fd("its http address is not a URL")}case"consul":{let c=t("address"),u=t("path");if(!u)return r("path");if(!c)return r("address","CONSUL_HTTP_ADDR");let l=lN(c,!1);return l?{key:`consul:${l}/${u.replace(/^\/+/,"")}`}:fd("its consul address is not a host")}case"kubernetes":{let c=t("secret_suffix"),u=t("namespace");return c?u?{key:`kubernetes:${u}/${c}`}:r("namespace","KUBE_NAMESPACE"):r("secret_suffix")}case"remote":case"cloud":{let c=t("hostname"),u=t("organization"),l=t("name");return c===null?r("hostname"):u?l===null?fd(`its ${e} workspace name is an expression, not a plain string`):l===void 0?fd(`its ${e} workspaces block names no workspace by name (one picked by tags, prefix or TF_WORKSPACE cannot be read from the code)`):{key:`remote:${(c??"app.terraform.io").toLowerCase()}/${u}/${l}`}:r("organization",e==="cloud"?"TF_CLOUD_ORGANIZATION":void 0)}}let o=t("key"),s=t("prefix"),i=o||s;if(!i)return r(o===null?"key":s===null||e==="gcs"?"prefix":"key");let a=t("bucket");return a===null?r("bucket"):{...a?{bucket:a}:{},key:i}}var ar=e=>!("unsupported"in e)&&(e.backend==="s3"||e.backend==="gcs"||e.backend==="azurerm"),Wf="reads state versions from s3, gcs, azurerm, local and GitLab-managed http backends",ut=e=>typeof e=="string"&&e!==""?e:void 0,fN={pg:"a pg backend keeps one row per workspace, which each write replaces",kubernetes:"a kubernetes backend keeps one Secret per workspace, which each write replaces",consul:"a consul backend keeps one key per workspace, which each write replaces",http:"an http backend keeps what its server holds at the address and names no versions"};function $7(e,t={}){if(e.type in fN&&!(e.type==="http"&&Mf(ut(e.config.address)??t.TF_HTTP_ADDRESS)))return!1}function k7(e){let t=Array.isArray(e.config.workspaces)?e.config.workspaces[0]:e.config.workspaces,n=o=>Gi(e.config[o]??(t&&typeof t=="object"?t[o]:void 0)),r=gd(e.type,n,"");return"key"in r?r.key:void 0}function rw(e,t=process.env){let n=t.TF_DATA_DIR;return n?b7(n)?n:md(e,n):md(e,".terraform")}function _7(e,t=process.env){let n=md(rw(e,t),"terraform.tfstate");if(xR(n))try{let r=JSON.parse(ER(n,"utf-8")),o=ut(r.backend?.type);if(!o)return;let s=r.backend?.config&&typeof r.backend.config=="object"?r.backend.config:{};return{type:o,config:s}}catch{return}}var ow=".terragucci-workspace";function hd(e){let t=md(e,ow);return xR(t)&&ER(t,"utf-8").trim()||void 0}function ls(e,t){let n=hd(t);return n?{...e,TF_WORKSPACE:n}:e}function Fi(e,t){let n=hd(t);if(!n)return;let{TF_WORKSPACE:r,...o}=e;return{init:{...e,TF_WORKSPACE:"default"},select:["workspace","select","-or-create=true",n],selectEnv:o}}function S7(e,t=process.env){if(t.TF_WORKSPACE)return t.TF_WORKSPACE;let n=md(rw(e,t),"environment");if(xR(n)){let r=ER(n,"utf-8").trim();if(r)return r}return"default"}function R7(e,t,n="env:"){return t==="default"?e:`${n}/${t}/${e}`}function Hr(e,t=process.env,n=_7(e,t)){let r=S7(e,t);if(!n||n.type==="local"){let g=n?.config??{};return{backend:"local",path:r==="default"?ut(g.path)??"terraform.tfstate":md(ut(g.workspace_dir)??"terraform.tfstate.d",r,"terraform.tfstate")}}if(n.type==="http"){let g=QC(n.config,t);if(g)return{backend:"http",gitlab:g,location:xn(g.address)}}if(n.type==="gcs")return E7(n.config,r,t);if(n.type==="azurerm")return A7(n.config,r,t);if(n.type!=="s3"){let g=k7(n),m=g?{location:g}:{},h=`terragucci ${Wf}, and this root's backend is ${n.type==="http"?"an http backend whose address is not a GitLab project's state API":n.type}`;return $7(n,t)===!1?{backend:n.type,unsupported:h,...m,versions:{versioning:"off",note:fN[n.type]}}:{backend:n.type,unsupported:h,...m,versions:{versioning:"unknown",note:`a ${n.type} backend can keep versions of the state, which terragucci does not read`}}}let o=n.config,s=ut(o.bucket),i=ut(o.key);if(!s||!i)return{backend:"s3",unsupported:"the s3 backend's bucket or key is not in the configuration init recorded"};let a=o.endpoints&&typeof o.endpoints=="object"?o.endpoints:{},c=ut(a.s3)??ut(o.endpoint)??t.AWS_ENDPOINT_URL_S3??t.AWS_ENDPOINT_URL,u=ut(o.region)??t.AWS_REGION??t.AWS_DEFAULT_REGION??"us-east-1",l=ut(o.access_key),d=ut(o.secret_key),p={...t,AWS_REGION:u,...l&&d?{AWS_ACCESS_KEY_ID:l,AWS_SECRET_ACCESS_KEY:d,AWS_SESSION_TOKEN:ut(o.token)??""}:{}},f;try{f=dd({bucket:s,...c?{endpoint:c}:{}},p)}catch(g){return{backend:"s3",unsupported:`the job has no credentials to read s3://${s}: ${g.message}`}}return{backend:"s3",bucket:s,key:R7(i,r,ut(o.workspace_key_prefix)),region:u,...c?{endpoint:c.replace(/\/+$/,"")}:{},lockfile:o.use_lockfile===!0,dynamodb:ut(o.dynamodb_table)!==void 0,target:f}}var x7=e=>e.replace(/\/+$/,"").replace(/\/storage\/v1$/,"");function E7(e,t,n){let r=ut(e.bucket);if(!r)return{backend:"gcs",unsupported:"the gcs backend's bucket is not in the configuration init recorded"};let o=ut(e.prefix)??"",s=o===""||o.endsWith("/")?o:`${o}/`,i=`${s}${t}.tfstate`,a=x7(ut(e.storage_custom_endpoint)??n.GOOGLE_BACKEND_STORAGE_CUSTOM_ENDPOINT??n.GOOGLE_STORAGE_CUSTOM_ENDPOINT??ew),c=ut(e.impersonate_service_account)??n.GOOGLE_BACKEND_IMPERSONATE_SERVICE_ACCOUNT??n.GOOGLE_IMPERSONATE_SERVICE_ACCOUNT,u={bucket:r,endpoint:a,...c?{impersonate:c}:{}},l=ut(e.access_token)??n.GOOGLE_OAUTH_ACCESS_TOKEN,d=ut(e.credentials)??n.GOOGLE_BACKEND_CREDENTIALS??n.GOOGLE_CREDENTIALS,p;if(l)p={...u,accessToken:l};else if(d)p=d.trim().startsWith("{")?{...u,credentialsJson:d}:{...u,credentialsFile:d};else if(n.GOOGLE_APPLICATION_CREDENTIALS)p={...u,credentialsFile:n.GOOGLE_APPLICATION_CREDENTIALS};else return{backend:"gcs",unsupported:`the job has no credentials to read gs://${r}: give the job oidc.gcp (it sets GOOGLE_APPLICATION_CREDENTIALS), or set GOOGLE_CREDENTIALS or GOOGLE_OAUTH_ACCESS_TOKEN`};return{backend:"gcs",bucket:r,key:i,lock:`${s}${t}.tflock`,target:p}}var T7={public:{storage:"core.windows.net",authority:Qy},china:{storage:"core.chinacloudapi.cn",authority:"https://login.chinacloudapi.cn"},usgovernment:{storage:"core.usgovcloudapi.net",authority:"https://login.microsoftonline.us"}};function A7(e,t,n){let r=ut(e.storage_account_name),o=ut(e.container_name),s=ut(e.key);if(!r||!o||!s)return{backend:"azurerm",unsupported:"the azurerm backend's storage_account_name, container_name or key is not in the configuration init recorded"};let i=t==="default"?s:`${s}env:${t}`,a=T7[ut(e.environment)??n.ARM_ENVIRONMENT??"public"],c=ut(e.metadata_host)??n.ARM_METADATA_HOSTNAME??n.ARM_METADATA_HOST;if(!a&&!c)return{backend:"azurerm",unsupported:`the azurerm backend's environment ${ut(e.environment)??n.ARM_ENVIRONMENT} is not public, china or usgovernment, and it names no metadata_host`};let u=ut(e.access_key)??n.ARM_ACCESS_KEY,l=ut(e.sas_token)??n.ARM_SAS_TOKEN,d=ut(e.tenant_id)??n.ARM_TENANT_ID,p=ut(e.client_id)??n.ARM_CLIENT_ID,f=ut(e.oidc_token_file_path)??n.ARM_OIDC_TOKEN_FILE_PATH,g;if(u)g={accountKey:u};else if(l)g={sas:l};else if(d&&p&&f)g={oidc:{tenantId:d,clientId:p,tokenFile:f,authority:(n.AZURE_AUTHORITY_HOST||a?.authority||Qy).replace(/\/+$/,"")}};else return{backend:"azurerm",unsupported:`the job has no credentials to read the container ${o} of ${r}: give the job oidc.azure (it sets ARM_TENANT_ID, ARM_CLIENT_ID and ARM_OIDC_TOKEN_FILE_PATH), or set ARM_ACCESS_KEY`};return{backend:"azurerm",account:r,container:o,key:i,snapshot:e.snapshot===!0||n.ARM_SNAPSHOT==="true",...c?{metadataHost:c}:{endpoint:`https://${r}.blob.${a.storage}`},auth:g}}function sw(e){if("unsupported"in e)return;if("gitlab"in e)return e.location;if(e.backend==="local")return e.path;let t=e;return t.backend==="gcs"?`gs://${t.bucket}/${t.key}`:t.backend==="azurerm"?`az://${t.account}/${t.container}/${t.key}`:`s3://${t.bucket}/${t.key}`}function iw(e,t){return new ld(e.target,t)}var dN=e=>v7("sha256").update(e).digest("hex");function O7(e,t){let n=iw(e,t),r=`${e.key}.tflock`,o=async()=>{let s=await n.head(e.key);return s.exists?s.versionId?{exists:!0,versionId:s.versionId}:{exists:!0,off:`bucket versioning is off for ${e.bucket}, so it keeps only the latest state`}:{exists:!1}};return{backend:"s3",location:`s3://${e.bucket}/${e.key}`,lockLocation:`s3://${e.bucket}/${r}`,version:o,hasVersion:s=>n.hasVersion(e.key,s),readVersion:s=>n.readVersion(e.key,s),isAt:async s=>(await o()).versionId===s,heldLock:async()=>{let s=await n.get(r);if(s!==void 0)return{id:nw(s),info:s}},lock:s=>n.putIfAbsent(r,s,"application/json"),unlock:()=>n.remove(r),readBeside:s=>n.get(`${e.key}${s}`),writeBeside:async(s,i)=>{await n.put(`${e.key}${s}`,i,"application/json")},adopt:()=>{}}}function nw(e){try{let t=JSON.parse(e);return typeof t.ID=="string"?t.ID:""}catch{return""}}function P7(e,t){let n=new Za(e.target,t),r,o=async()=>{let s=await n.head(e.key);return s.exists?(r??=n.versioning(),await r===!1?{exists:!0,off:`object versioning is off for ${e.bucket}, so it keeps only the latest state`}:{exists:!0,...s.generation?{versionId:s.generation}:{}}):{exists:!1}};return{backend:"gcs",location:`gs://${e.bucket}/${e.key}`,lockLocation:`gs://${e.bucket}/${e.lock}`,version:o,hasVersion:async s=>(await n.head(e.key,s)).exists,readVersion:s=>n.readGeneration(e.key,s),isAt:async s=>(await n.head(e.key)).generation===s,heldLock:async()=>{let s=await n.head(e.lock),i=s.exists?await n.get(e.lock):void 0;if(!(!s.exists||i===void 0))return{id:s.generation??nw(i),info:i}},lock:s=>n.putIfAbsent(e.lock,s,"application/json"),unlock:()=>n.remove(e.lock),readBeside:s=>n.get(`${e.key}${s}`),writeBeside:async(s,i)=>{await n.put(`${e.key}${s}`,i,"application/json")},adopt:()=>{}}}var pN="terraformlockid";async function j7(e,t){if(e.endpoint)return e.endpoint;let n=`https://${e.metadataHost}/metadata/endpoints?api-version=2023-11-01`,r=await t(n,{method:"GET",headers:{accept:"application/json"}}),o=await r.text();if(!r.ok)throw new Y(`the Azure metadata at ${e.metadataHost}: ${r.status}`);let s;try{let i=JSON.parse(o);s=(Array.isArray(i)?i[0]:i)?.suffixes?.storage}catch{}if(typeof s!="string"||s==="")throw new Y(`the Azure metadata at ${e.metadataHost} names no storage suffix`);return`https://${e.account}.blob.${s.replace(/^\.+/,"")}`}async function I7(e,t=fetch){let n=await j7(e,t),r=new ud({account:e.account,container:e.container,endpoint:n,...e.auth},t),o,s=async a=>(await r.head(e.key)).versionId?{versionid:a}:{snapshot:a},i=async(a=!1)=>{let c=await r.head(e.key);return c.exists?c.versionId?{exists:!0,versionId:c.versionId}:e.snapshot?a?{exists:!0,versionId:await r.snapshot(e.key)}:{exists:!0}:{exists:!0,off:`blob versioning is off for ${e.account}, and the backend takes no snapshots (snapshot = true), so it keeps only the latest state`}:{exists:!1}};return{backend:"azurerm",location:`az://${e.account}/${e.container}/${e.key}`,lockLocation:`az://${e.account}/${e.container}/${e.key}`,version:i,hasVersion:async a=>(await r.head(e.key,await s(a))).exists,readVersion:async a=>r.readAt(e.key,await s(a)),isAt:async a=>{let c=await r.head(e.key);if(c.versionId)return c.versionId===a;let[u,l]=await Promise.all([r.readAt(e.key,{snapshot:a}),r.get(e.key)]);return u!==void 0&&l!==void 0&&dN(u)===dN(l)},heldLock:async()=>{let a=await r.head(e.key);if(!a.exists||a.leaseState!=="leased")return;let c=a.metadata[pN],u=c?Buffer.from(c,"base64").toString("utf-8"):"";return{id:nw(u),info:u}},lock:async a=>{let c=nw(a);return(await r.head(e.key)).exists||await r.putBlob(e.key,"","application/json",{ifNoneMatch:!0}),await r.lease(e.key,"acquire",c)?(o=c,await r.setMetadata(e.key,{[pN]:Buffer.from(a).toString("base64")},c),!0):!1},unlock:async()=>{if(!o)return;let a=o;await r.setMetadata(e.key,{},a),await r.lease(e.key,"release",a),o=void 0},write:async a=>{if(!o)throw new Y(`${e.key} is written under its lease, and none is held`);e.snapshot&&(await r.head(e.key)).exists&&await r.snapshot(e.key);let c=(await r.head(e.key)).metadata;await r.putBlob(e.key,a,"application/json",{leaseId:o,metadata:c})},readBeside:a=>r.get(`${e.key}${a}`),writeBeside:async(a,c)=>{await r.put(`${e.key}${a}`,c,"application/json")},adopt:a=>{o=a.id}}}async function Ws(e,t){return e.backend==="s3"?O7(e,t):e.backend==="gcs"?P7(e,t):I7(e,t)}async function Hf(e,t=process.env,n,r){let o=r?Hr(e,t,r):Hr(e,t);if("unsupported"in o)return{backend:o.backend,...o.location?{location:o.location}:{},versioning:o.versions?.versioning??"unknown",note:o.versions?.note??o.unsupported};if(o.backend==="local")return{backend:"local",location:o.path,versioning:"off",note:"a local backend keeps only the latest state"};if("gitlab"in o)try{let i=await Yy(o.gitlab,n??globalThis.fetch);return i?{backend:"http",location:o.location,version_id:String(i.serial),versioning:"on"}:{backend:"http",location:o.location,versioning:"unknown",note:"GitLab holds no state at this address"}}catch(i){return{backend:"http",location:o.location,versioning:"unknown",note:i.message}}if(!ar(o))return{backend:o.backend,versioning:"unknown",note:"terragucci reads no versions of this state"};let s=sw(o);try{let i=await(await Ws(o,n)).version(!0);return i.exists?i.versionId?{backend:o.backend,location:s,version_id:i.versionId,versioning:"on"}:i.off?{backend:o.backend,location:s,versioning:"off",note:i.off}:{backend:o.backend,location:s,versioning:"unknown",note:"the store gave no version id"}:{backend:o.backend,location:s,versioning:"unknown",note:`the state object is not in the ${o.backend==="azurerm"?"container":"bucket"}`}}catch(i){return{backend:o.backend,location:s,versioning:"unknown",note:i.message}}}import{execFile as C7}from"node:child_process";var N7=["TG_TOKEN","TG_MERGE_TOKEN","GITHUB_TOKEN","GH_TOKEN","GITLAB_TOKEN","CI_JOB_TOKEN","FORGEJO_TOKEN","GITEA_TOKEN","ACTIONS_RUNTIME_TOKEN"];function Ve(e){let t=new Set([e.TG_TOKEN,e.TG_MERGE_TOKEN].filter(r=>typeof r=="string"&&r.length>0)),n={};for(let[r,o]of Object.entries(e))N7.includes(r)||o!==void 0&&t.has(o)&&!r.startsWith("TF_")||(n[r]=o);return n}var Nn=(e,t,n)=>new Promise(r=>{C7(e,[...t],{cwd:n.cwd,env:Ve({...process.env,...n.env}),maxBuffer:256*1024*1024},(o,s,i)=>{let a=o?typeof o.code=="number"?o.code:null:0;r({code:a,stdout:String(s),stderr:o&&a===null?`${String(i)}${o.message}`:String(i)})})});import{existsSync as FR,readdirSync as FN,readFileSync as Qf,statSync as AX}from"node:fs";import{dirname as OX,join as eg,relative as fw,resolve as GR}from"node:path";import{execFile as q7}from"node:child_process";import{existsSync as yd,mkdirSync as EN,readFileSync as uw,realpathSync as J7,rmSync as TN,writeFileSync as K7}from"node:fs";import{dirname as V7,join as ds,resolve as Kf}from"node:path";function TR(e){let t=e,r=(Array.isArray(t?.resource_changes)?t.resource_changes:[]).map(s=>{let i=s??{},a=i.change??{};return{address:i.address,mode:i.mode,type:i.type,name:i.name,index:i.index,provider_name:i.provider_name,deposed:i.deposed,actions:a.actions,before:a.before,after:a.after,after_unknown:a.after_unknown,replace_paths:a.replace_paths,importing:a.importing}});r.sort((s,i)=>`${String(s.address)}\0${String(s.deposed??"")}`.localeCompare(`${String(i.address)}\0${String(i.deposed??"")}`));let o=Array.isArray(t?.action_invocations)?[...t.action_invocations].sort((s,i)=>JSON.stringify(s).localeCompare(JSON.stringify(i))):[];return{resourceChanges:r,outputChanges:t?.output_changes??{},...o.length>0?{actionInvocations:o}:{}}}function gN(e){return Rn("terraform-plan",TR(e))}var Tr=e=>e!==null&&typeof e=="object"&&!Array.isArray(e);function qf(e){return e===!0?!0:Array.isArray(e)?e.some(qf):Tr(e)?Object.values(e).some(qf):!1}function AR(e,t){if(e===t)return!0;if(Array.isArray(e)&&Array.isArray(t))return e.length===t.length&&e.every((n,r)=>AR(n,t[r]));if(Tr(e)&&Tr(t)){let n=Object.keys(e);return n.length===Object.keys(t).length&&n.every(r=>r in t&&AR(e[r],t[r]))}return!1}function nn(e){let t=(e??"terraform").split(/[\\/]/).pop()??"";return t.startsWith("choudoufu")?"choudoufu":t.startsWith("tofu")?"tofu":"terraform"}function D7(e){let t=Array.isArray(e)?e.map(String):[];if(t.length===2&&t.includes("delete")&&t.includes("create"))return"replace";if(t.length===1)switch(t[0]){case"create":case"update":case"delete":case"read":case"no-op":case"forget":return t[0]}throw new Error(`a plan entry has actions ${JSON.stringify(e)}, which the change set has no action for`)}function M7(e,t){switch(t){case"update":return"in-place";case"delete":return"destroy";case"replace":return e[0]==="create"?"replace":"destroy";default:return}}function L7(e){let n=/^((?:module\.[^.[\]]+(?:\[(?:"(?:[^"\\]|\\.)*"|\d+)\])?\.)*)(?:data\.)?([^.[\]]+)\.([^.[\]]+)(?:\[("(?:[^"\\]|\\.)*"|\d+)\])?$/.exec(e);if(!n)return{type:"unknown",name:e};let r=n[1]?n[1].slice(0,-1):void 0,o=n[4]===void 0?void 0:n[4].startsWith('"')?JSON.parse(n[4]):Number(n[4]);return{...r?{module:r}:{},type:n[2],name:n[3],...o!==void 0?{index:o}:{}}}function G7(e,t){if(t==="delete"||t==="no-op"||t==="forget"||t==="read")return[];let n=Tr(e.before)?e.before:{},r=Tr(e.after)?e.after:{},o=Tr(e.after_unknown)?e.after_unknown:{},s=Tr(e.before_sensitive)?e.before_sensitive:{},i=Tr(e.after_sensitive)?e.after_sensitive:{},a=new Set((Array.isArray(e.replace_paths)?e.replace_paths:[]).map(l=>Array.isArray(l)?l[0]:void 0).filter(l=>typeof l=="string")),c=[...new Set([...Object.keys(n),...Object.keys(r),...Object.keys(o)])].sort(),u=[];for(let l of c){let d=qf(o[l]),p=t!=="create"&&n[l]!==void 0&&n[l]!==null,f=r[l]!==void 0&&r[l]!==null;if(t==="create"?!f&&!d:!d&&AR(n[l]??null,r[l]??null))continue;let g=qf(s[l])||qf(i[l]);u.push({path:l,...g?{sensitive:!0}:{...p?{before:n[l]}:{},...f&&!d?{after:r[l]}:{}},...d?{unknown:!0}:{},...a.has(l)?{forcesReplacement:!0}:{}})}return u}function F7(e){for(let t of[e.after,e.before])if(Tr(t)&&typeof t.region=="string"&&t.region!=="")return t.region}function fo(e){let t=Tr(e.plan)?e.plan:{},n=e.planner??"terraform",o=(Array.isArray(t.resource_changes)?t.resource_changes:[]).map(a=>{let c=Tr(a)?a:{},u=Tr(c.change)?c.change:{},l=String(c.address??""),d=L7(l),p=D7(u.actions),f=M7(u.actions,p),g=F7(u),m=c.index!==void 0&&c.index!==null?c.index:d.index,h=typeof c.module_address=="string"?c.module_address:d.module;return{member:e.member,lexicon:"terraform",planner:n,address:l,type:typeof c.type=="string"?c.type:d.type,name:typeof c.name=="string"?c.name:d.name,...m!==void 0?{index:m}:{},...h?{module:h}:{},...typeof c.deposed=="string"?{deposed:c.deposed}:{},action:p,...Tr(u.importing)?{importing:!0}:{},...f?{disruption:f}:{},...g?{region:g}:{},...e.scope?{scope:e.scope}:{},attributes:G7(u,p)}}),s=(Array.isArray(t.action_invocations)?t.action_invocations:[]).map(z7),i=t.errored===!0;return{member:{member:e.member,lexicon:"terraform",planner:n,...e.scope?{scope:e.scope}:{},status:i?"failed":"planned",...i?{error:`${n} marked the plan errored`}:{},planDigest:gN(t),...e.nativeDigest?{nativeDigest:e.nativeDigest}:{},holes:[]},entries:o,...s.length>0?{sideEffects:s}:{}}}function z7(e){let t=Tr(e)?e:{},n=typeof t.type=="string"?t.type:"unknown",r=Tr(t.lifecycle_action_trigger)?t.lifecycle_action_trigger:{};return{address:typeof t.address=="string"?t.address:n,type:n,...typeof r.triggering_resource_address=="string"?{trigger:r.triggering_resource_address}:{},...typeof r.action_trigger_event=="string"?{event:r.action_trigger_event}:{}}}var Xa=e=>e!==null&&typeof e=="object"&&!Array.isArray(e);function OR(e){let t=e.replace(/\\/g,"/"),n=[];for(let o of t.split("/"))o===""||o==="."||(o===".."&&n.length>0&&n[n.length-1]!==".."?n.pop():n.push(o));let r=n.join("/");return t.startsWith("/")?`/${r}`:r||"."}var U7=e=>e.startsWith("/")||/^[A-Za-z]:[\\/]/.test(e);function PR(e,t,n){let r=t.replace(/\\/g,"/").replace(/(^|\/)terragrunt\.hcl$/,"");if(!U7(r))return OR(`${e}/${r}`);let o=OR(r);for(let s of typeof n=="string"?[n]:n){let i=OR(s);if(o===i)return".";if(o.startsWith(`${i}/`))return o.slice(i.length+1)}return o}function mN(e,t,n){let r=typeof t=="string"?JSON.parse(t):t;if(!Xa(r))throw new Error("terragrunt render --json did not print an object");let o=Xa(r.dependency)?r.dependency:{},s=[];for(let[i,a]of Object.entries(o)){if(!Xa(a)||typeof a.config_path!="string")continue;let c=Array.isArray(a.mock_outputs_allowed_terraform_commands)?a.mock_outputs_allowed_terraform_commands.filter(l=>typeof l=="string"):void 0,u=typeof a.mock_outputs_merge_strategy_with_state=="string"?a.mock_outputs_merge_strategy_with_state:a.mock_outputs_merge_with_state===!0?"shallow":void 0;s.push({name:typeof a.name=="string"&&a.name?a.name:i,upstream:PR(e,a.config_path,n),...Xa(a.mock_outputs)?{mockOutputs:a.mock_outputs}:{},...c?{mockAllowed:c}:{},...u&&u!=="no_merge"?{mergeStrategy:u}:{},...a.skip===!0||a.skip_outputs===!0?{skipOutputs:!0}:{},...a.enabled===!1?{disabled:!0}:{}})}return s.sort((i,a)=>i.name<a.name?-1:i.name>a.name?1:0)}function hN(e){let t=e.trim(),n=t.indexOf("{");if(n<0)return;let r;try{r=JSON.parse(t.slice(n))}catch{return}if(Xa(r))return Object.fromEntries(Object.entries(r).map(([o,s])=>[o,Xa(s)&&"value"in s?s.value:s]))}function yN(e){return["run","--working-dir",e,"--non-interactive","--no-color","--","output","-json"]}function aw(e){return["render","--json","--non-interactive","--no-color","--working-dir",e]}function wN(e,t,n,r=""){let o=[];for(let[s,i]of Object.entries(e)){let a=r?`${r}.${s}`:s;s in t?n&&Xa(i)&&Xa(t[s])&&o.push(...wN(i,t[s],n,a)):o.push(a)}return o.sort()}var B7=e=>!e.mockAllowed||e.mockAllowed.length===0||e.mockAllowed.includes("plan");function bN(e){let t=[];for(let[n,r]of e.dependencies)for(let o of r){let s={unit:n,dependency:o.name,upstream:o.upstream};if(o.disabled||o.skipOutputs){o.mockOutputs&&t.push({...s,reason:o.disabled?"disabled":"skip-outputs"});continue}let i=e.outputs.get(o.upstream)??{};if(Object.keys(i).length===0){t.push({...s,reason:"no-outputs"});continue}if(o.mockOutputs&&o.mergeStrategy&&B7(o)){let a=wN(o.mockOutputs,i,o.mergeStrategy!=="shallow");a.length>0&&t.push({...s,reason:"partial",keys:a})}}return t.sort((n,r)=>n.unit<r.unit?-1:n.unit>r.unit?1:n.dependency<r.dependency?-1:n.dependency>r.dependency?1:0)}function vN(e){let t=new Set;for(let n of e.values())for(let r of n)!r.disabled&&!r.skipOutputs&&t.add(r.upstream);return[...t].sort()}function W7(e){let t=`${e.unit} (dependency "${e.dependency}" on ${e.upstream})`;switch(e.reason){case"no-outputs":return`${t}: ${e.upstream} has no outputs yet; apply ${e.upstream} first`;case"partial":return`${t}: ${e.upstream}'s outputs lack ${e.keys.join(", ")}, which the merge strategy fills from mock_outputs; apply ${e.upstream} with those outputs first, or drop the merge strategy`;case"skip-outputs":return`${t}: skip_outputs = true with mock_outputs set always reads the mock; read the real outputs or drop mock_outputs`;case"disabled":return`${t}: enabled = false with mock_outputs set always reads the mock; enable the dependency or drop mock_outputs`}}function $N(e){let t=[...new Set(e.filter(r=>r.reason==="no-outputs"||r.reason==="partial").map(r=>r.upstream))].sort();return["this wave was not planned and is not gated: its plans would read mock_outputs, so nobody could approve them as real. "+(t.length>0?`Apply ${t.join(", ")} first, then plan the wave again.`:"Fix the dependency blocks below, then plan the wave again."),...e.map(r=>` ${W7(r)}`)].join(`
49
+ `)}var H7=/Config (\S+?) is a dependency of (\S+?) that has no outputs, but mock outputs provided/g;function kN(e,t){let n=new Set,r=[];for(let o of e.matchAll(H7)){let s=PR(".",o[2],t),i=PR(".",o[1],t),a=`${s}\0${i}`;n.has(a)||(n.add(a),r.push({unit:s,upstream:i}))}return r.sort((o,s)=>o.unit<s.unit?-1:o.unit>s.unit?1:o.upstream<s.upstream?-1:1)}function _N(e,t){let n=new Map;for(let r of t)n.set(r.unit,[...n.get(r.unit)??[],r.upstream]);return e.map(r=>{let o=n.get(r.member.member);return o?{member:{...r.member,status:"failed",error:`planned on mock_outputs: ${o.join(", ")} had no outputs when Terragrunt planned it; apply ${o.join(", ")} first`,planDigest:null},entries:[]}:r})}function SN(e){return e.map(t=>({...t,member:{...t.member,provisional:!0}}))}var jR="PROVISIONAL";function IR(e){if(e.units.length===0)throw new Error("a Terragrunt wave needs at least one unit; with no path filter run --all would run every unit");if(e.parallelism!==void 0&&(!Number.isInteger(e.parallelism)||e.parallelism<1))throw new Error(`parallelism must be a whole number of 1 or more, got ${e.parallelism}`);return["run","--all","--non-interactive","--no-color","--no-filters-file",...[...new Set(e.units)].sort().flatMap(r=>["--filter",eC(r)]),...e.destroy?["--filter-allow-destroy"]:[],"--out-dir",e.outDir,...e.command==="plan"&&e.jsonOutDir?["--json-out-dir",e.jsonOutDir]:[],"--report-file",e.reportFile,"--report-format","json",...e.parallelism!==void 0?["--parallelism",String(e.parallelism)]:[],"--",e.command,...e.command==="plan"&&e.destroy?["-destroy"]:[],...e.extra??[]]}function zi(e){return e?{TG_TF_PATH:e}:{}}function Jf(e){let t=typeof e=="string"?JSON.parse(e.trim()===""?"[]":e):e,n=Array.isArray(t)?t:[],r=new Map;for(let o of n){if(o===null||typeof o!="object")continue;let s=o;if(typeof s.Name!="string"||typeof s.Result!="string")continue;let i=s.Name.replace(/\\/g,"/").replace(/^\.\//,"");r.set(i,{name:i,result:s.Result,...typeof s.Reason=="string"&&s.Reason?{reason:s.Reason}:{},...typeof s.Cause=="string"&&s.Cause?{cause:s.Cause.trim()}:{},...typeof s.Cmd=="string"?{cmd:s.Cmd}:{},...typeof s.Started=="string"?{started:s.Started}:{},...typeof s.Ended=="string"?{ended:s.Ended}:{}})}return r}function cw(e,t){return[...new Set(e)].sort().map(n=>{let r=t.get(n);if(!r)return{unit:n,status:"failed",result:"not run",error:"not in Terragrunt's run report, so it did not run"};if(r.result==="succeeded")return{unit:n,status:"succeeded",result:r.result};let o=[r.reason,r.cause].filter(Boolean).join(": ");return{unit:n,status:"failed",result:r.result,error:`${r.result}${o?` (${o})`:""}`}})}function RN(e){let t=e.scopeFor??jy;return cw(e.units,e.report).map(n=>{let r=t(n.unit),o=n.status==="succeeded"?e.planFor(n.unit):void 0;return n.status==="succeeded"&&o!==void 0?fo({member:n.unit,plan:o,planner:e.planner,...r?{scope:r}:{}}):{member:{member:n.unit,lexicon:"terraform",planner:e.planner,...r?{scope:r}:{},status:"failed",error:n.error??"Terragrunt reported the unit succeeded but wrote no plan JSON for it",planDigest:null,holes:[]},entries:[]}})}var Eu=(e,t,n)=>new Promise(r=>{q7(e,[...t],{cwd:n.cwd,env:{...process.env,...n.env},maxBuffer:256*1024*1024},(o,s,i)=>{let a=o?typeof o.code=="number"?o.code:null:0;r({code:a,stdout:String(s),stderr:o&&a===null?`${String(i)}${o.message}`:String(i)})})}),cr=class extends Error{constructor(t){super(t),this.name="TerragruntError"}};async function lw(e){let t=e.exec??Eu,n=e.terragrunt??"terragrunt",r=await t(n,["--version"],{cwd:e.dir,env:{}});if(r.code!==0)throw new cr(`\`${n} --version\` failed (exit ${r.code}): ${(r.stderr||r.stdout).trim()}`);let o=QI(r.stdout);if(o)throw new cr(o);return r.stdout.trim()}async function dw(e){let t=e.exec??Eu,n=e.terragrunt??"terragrunt",r=tC(e),o=await t(n,r,{cwd:e.dir,env:zi(e.binary)});if(o.code!==0)throw new cr(`\`${n} ${r.join(" ")}\` failed (exit ${o.code}): ${o.stderr.trim()}`);let s;try{s=Py(o.stdout)}catch(i){throw new cr(`could not read \`terragrunt find\` output: ${i instanceof Error?i.message:String(i)}`)}return{units:s,warnings:e.binary?Y7(e.dir,s,e.binary):[]}}var Z7=/^\s*terraform_binary\s*=\s*(.+?)\s*$/m;function Y7(e,t,n){let r=[];for(let o of t){let s=[ds(o.path,"terragrunt.hcl"),...Object.values(o.include??{})];for(let i of s){let a;try{a=uw(Kf(e,i),"utf8")}catch{continue}let c=Z7.exec(a);if(!c)continue;let u=/^"([^"$]*)"$/.exec(c[1]);if(u&&u[1]===n)break;r.push(`${o.path}: ${i} sets terraform_binary = ${c[1]}, but the project's binary is ${n}; TG_TF_PATH=${n} overrides it, so the unit runs ${n}`);break}}return r}function X7(e){return nn(e??"tofu")}var Hs=class extends cr{constructor(n){super($N(n));this.reads=n;this.name="TerragruntMockRefusal"}reads};async function xN(e,t,n){let r=new Array(e.length),o=0,s=async()=>{for(;o<e.length;){let i=o++;r[i]=await n(e[i])}};return await Promise.all(Array.from({length:Math.max(1,Math.min(t,e.length))},s)),r}function AN(e){let t=Kf(e);try{let n=J7(t);return n===t?[t]:[t,n]}catch{return[t]}}async function Q7(e){let t=e.exec??Eu,n=e.terragrunt??"terragrunt",r=zi(e.binary),o=e.parallelism??8,s=AN(e.dir),i=[...new Set(e.units)].sort().filter(d=>yd(ds(Kf(e.dir),d,"terragrunt.hcl"))),a=await xN(i,o,async d=>{let p=aw(d),f=await t(n,p,{cwd:e.dir,env:r});if(f.code!==0)throw new cr(`\`${n} ${p.join(" ")}\` failed (exit ${f.code}), so the wave's dependencies are unknown: ${f.stderr.trim()}`);try{return[d,mN(d,f.stdout,s)]}catch(g){throw new cr(`could not read \`terragrunt render --json\` for ${d}: ${g instanceof Error?g.message:String(g)}`)}}),c=new Map(a),u=vN(c),l=await xN(u,o,async d=>{let p=yN(d),f=await t(n,p,{cwd:e.dir,env:r}),g=f.code===0?hN(f.stdout):void 0;if(!g)throw new cr(`could not read the outputs of ${d}, which the wave reads (\`${n} ${p.join(" ")}\` exit ${f.code}): ${(f.stderr||f.stdout).trim().slice(-2e3)}`);return[d,g]});return bN({dependencies:c,outputs:new Map(l)})}async function pw(e){let t=e.exec??Eu,n=e.terragrunt??"terragrunt",r=Kf(e.dir,e.workDir),o=ds(r,"plans"),s=ds(r,"json"),i=ds(r,"plan-report.json"),a=ds(r,jR);for(let m of[o,s,i,a])TN(m,{recursive:!0,force:!0});if(!e.provisional){let m=await Q7({...e,exec:t});if(m.length>0)throw new Hs(m)}EN(r,{recursive:!0}),e.provisional&&K7(a,`planned before its upstream applied; never applied
50
+ `);let c=IR({units:e.units,command:"plan",outDir:o,jsonOutDir:s,reportFile:i,...e.destroy?{destroy:!0}:{},...e.parallelism!==void 0?{parallelism:e.parallelism}:{}}),u=await t(n,c,{cwd:e.dir,env:zi(e.binary)}),l=yd(i)?Jf(uw(i,"utf8")):new Map,d=m=>{let h=ds(s,m,"tfplan.json");return yd(h)?JSON.parse(uw(h,"utf8")):void 0},p=RN({units:e.units,report:l,planFor:d,planner:X7(e.binary)}),f=new Set(e.units),g=kN(`${u.stderr}
51
+ ${u.stdout}`,AN(e.dir)).filter(m=>f.has(m.unit));return{parts:e.provisional?SN(p):_N(p,g),provisional:e.provisional===!0,results:cw(e.units,l),code:u.code,log:u.stderr}}async function ON(e){let t=e.exec??Eu,n=e.terragrunt??"terragrunt",r=Kf(e.dir,e.workDir),o=ds(r,"plans");if(e.provisional||yd(ds(r,jR)))throw new cr(`the plans under ${r} are provisional: planned before their upstream applied, possibly on mock_outputs. They are never applied; plan the wave again once its upstream applied`);let s=[...new Set(e.units)].sort().filter(l=>!yd(ds(o,l,"tfplan.tfplan")));if(s.length>0)throw new cr(`no saved plan for ${s.join(", ")} under ${o}; plan the wave before applying it, so apply runs the plan that was reviewed`);let i=ds(r,"apply-report.json");TN(i,{force:!0}),EN(V7(i),{recursive:!0});let a=IR({units:e.units,command:"apply",outDir:o,reportFile:i,...e.destroy?{destroy:!0}:{},...e.parallelism!==void 0?{parallelism:e.parallelism}:{}}),c=await t(n,a,{cwd:e.dir,env:zi(e.binary)}),u=yd(i)?Jf(uw(i,"utf8")):new Map;return{results:cw(e.units,u),code:c.code,log:c.stderr}}import{readFileSync as RX}from"node:fs";import{join as xX}from"node:path";import{existsSync as dX,readdirSync as pX,readFileSync as fX}from"node:fs";import{join as DR,posix as Zf,relative as gX,resolve as mX,sep as hX}from"node:path";import{existsSync as eX,readdirSync as tX,readFileSync as nX,statSync as rX}from"node:fs";import{join as oX,posix as jN,relative as sX,resolve as CR,sep as iX}from"node:path";var aX=/\bsource\s*=\s*"(\.{1,2}\/[^"]*)"/g,cX=e=>e.split(iX).join("/");function PN(e,t){let n=cX(sX(e,t));return n===""?".":jN.normalize(n).replace(/\/+$/,"")}function uX(e){let t;try{t=tX(e)}catch{return[]}let n=[];for(let r of t){if(!r.endsWith(".tf")&&!r.endsWith(".tofu"))continue;let o;try{o=nX(oX(e,r),"utf8")}catch{continue}for(let s of o.matchAll(aX)){let i=CR(e,s[1].replace("//","/"));eX(i)&&rX(i).isDirectory()&&n.push(i)}}return n}function NR(e,t){let n=CR(e,t.dir),r=new Set,o=[n];for(;o.length>0;){let i=o.shift();r.has(i)||(r.add(i),o.push(...uX(i)))}let s=[...r].map(i=>PN(e,i));for(let i of t.varFiles??[])s.push(PN(e,CR(n,i)));return[...new Set(s)].sort()}function lX(e,t){return e==="."?!t.startsWith("../"):t===e||t.startsWith(`${e}/`)}function Vf(e,t,n){let r=n.map(s=>jN.normalize(s)),o=[];for(let[s,i]of Object.entries(t)){let a=NR(e,i);r.some(c=>a.some(u=>lX(u,c)))&&o.push(s)}return o.sort()}var IN=["terragrunt","removed","module-file","module-call","stack-template"],yX=/\.(tf|tofu)(\.json)?$/,NN=e=>e.split(hX).join("/"),Yf=e=>Zf.normalize(NN(e)).replace(/^\.\//,"").replace(/\/+$/,""),Tu=(e,t)=>e==="."||t===e||t.startsWith(`${e}/`);function wX(e){let t=[...hu,...e.exclude??[]];return["find","--json","--no-color","--no-filters-file","--filter",`[${e.base}...${e.head??"HEAD"}]`,...t.flatMap(n=>["--filter",hf(n)])]}function bX(e){return["diff","--name-only","--no-renames","--relative",`${e.base}...${e.head??"HEAD"}`]}function vX(e){let t=new Set;for(let n of e.reading??[])!yX.test(n)||Tu(e.path,n)||n.includes(".terragrunt-cache/")||t.add(Zf.dirname(n));return[...t].sort()}function MR(e,t,n){let r=Zf.dirname(Yf(t)),o=[],s=/\b(unit|stack)\s+"([^"]+)"\s*\{/g;for(let i=s.exec(n);i;i=s.exec(n)){let a=$X(n,s.lastIndex),c=CN(a,"source"),u=CN(a,"path");if(u===void 0)continue;let d=/^\s*no_dot_terragrunt_stack\s*=\s*true\b/m.test(a)?r:Zf.join(r,".terragrunt-stack"),p=Yf(Zf.join(d,u)),f;if(c!==void 0){let g=c.replace(/^\$\{get_terragrunt_dir\(\)\}\//,"./");/^\.{1,2}\//.test(g)&&(f=Yf(NN(gX(e,mX(e,r,g.replace("//","/"))))))}o.push({type:i[1],name:i[2],generated:p,...f!==void 0?{template:f}:{}})}return o}function $X(e,t){let n=1;for(let r=t;r<e.length;r++){let o=e[r];if(o==='"')for(r++;r<e.length&&e[r]!=='"';r++)e[r]==="\\"&&r++;else if(o==="#"||o==="/"&&e[r+1]==="/")for(;r<e.length&&e[r]!==`
52
52
  `;)r++;else if(o==="{")n++;else if(o==="}"&&--n===0)return e.slice(t,r)}return e.slice(t)}function CN(e,t){let n=new RegExp(`^\\s*${t}\\s*=\\s*"([^"]*)"`),r=0;for(let o of e.split(`
53
- `)){if(r===0){let i=n.exec(o);if(i)return i[1]}let s=o.replace(/"(?:[^"\\]|\\.)*"/g,'""');r+=(s.match(/[{[]/g)??[]).length-(s.match(/[}\]]/g)??[]).length}}var k7=new Set([".git",".terragrunt-cache","node_modules",".terraform"]);function LR(e){let t=[],n=r=>{let o;try{o=p7(DR(e,r),{withFileTypes:!0})}catch{return}for(let s of o){let i=r?`${r}/${s.name}`:s.name;s.isDirectory()&&!k7.has(s.name)?n(i):s.isFile()&&s.name==="terragrunt.stack.hcl"&&t.push(i)}};return n(""),t.sort()}function _7(e){let t=e.lastIndexOf("/.terragrunt-stack/");return t<0?void 0:`${e.slice(0,t)}/terragrunt.stack.hcl`}function S7(e){let t=[...new Set(e.changedFiles.map(Yf))].sort(),n=new Map(e.units.map(a=>[a.path,a])),r=new Map,o=[],s=(a,c)=>{let u=r.get(a)??[];u.push(c),r.set(a,u)};for(let a of new Set(e.terragruntSelected.map(Yf))){let c=n.get(a);if(!c){d7(DR(e.dir,a,"terragrunt.hcl"))?o.push(`${a}: Terragrunt's git range selected it, but discovery left it out, so it is not affected here`):s(a,{kind:"removed",files:t.filter(l=>Tu(a,l))});continue}let u=new Set([...c.reading??[],...Object.values(c.include??{}),_7(c.path)].filter(l=>!!l));s(a,{kind:"terragrunt",files:t.filter(l=>Tu(c.path,l)||u.has(l))})}for(let a of e.units){let c=new Set(a.reading??[]),u=v7(a),l=new Map;for(let f of u)for(let g of NR(e.dir,{dir:f}))!u.includes(g)&&!l.has(g)&&l.set(g,f);let d=new Map,p=new Map;for(let f of t){if(c.has(f))continue;let g=[...l.keys()].filter(h=>Tu(h,f)).sort((h,y)=>y.length-h.length)[0];if(g!==void 0){p.set(g,[...p.get(g)??[],f]);continue}let m=u.filter(h=>Tu(h,f)).sort((h,y)=>y.length-h.length)[0];m!==void 0&&d.set(m,[...d.get(m)??[],f])}for(let[f,g]of d)s(a.path,{kind:"module-file",files:g,via:f});for(let[f,g]of p)s(a.path,{kind:"module-call",files:g,via:f})}for(let a of LR(e.dir)){let c;try{c=f7(DR(e.dir,a),"utf8")}catch{continue}for(let u of MR(e.dir,a,c)){if(u.template===void 0)continue;let l=t.filter(p=>Tu(u.template,p));if(l.length===0)continue;let d=u.type==="unit"?n.has(u.generated)?[u.generated]:[]:e.units.filter(p=>Tu(u.generated,p.path)).map(p=>p.path);d.length===0&&o.push(`${u.generated}: generated by ${u.type} "${u.name}" in ${a} from the changed template ${u.template}, but discovery did not list it; run \`terragrunt stack generate\` before discovery`);for(let p of d)s(p,{kind:"stack-template",files:l,via:u.template})}}return{units:[...r.entries()].map(([a,c])=>({path:a,reasons:c.sort((u,l)=>IN.indexOf(u.kind)-IN.indexOf(l.kind)||(u.via??"").localeCompare(l.via??""))})).sort((a,c)=>a.path<c.path?-1:a.path>c.path?1:0),notes:[...new Set(o)].sort()}}function DN(e){let t=e.files.join(", ");switch(e.kind){case"terragrunt":return t?`Terragrunt's git range selected it (${t})`:"Terragrunt's git range selected it";case"removed":return"removed in the range; Terragrunt plans its destroy";case"module-file":return`${t} changed under its module ${e.via}, which Terragrunt does not track`;case"module-call":return`${t} changed under ${e.via}, a module its module calls`;case"stack-template":return`${t} changed under ${e.via}, the stack template it is generated from`}}async function MN(e){let t=e.exec??Eu,n=e.terragrunt??"terragrunt",r=e.git??"git",o=b7(e),s=await t(r,o,{cwd:e.dir,env:{}});if(s.code!==0)throw new cr(`\`${r} ${o.join(" ")}\` failed (exit ${s.code}): ${s.stderr.trim()}`);let i=w7(e),a=await t(n,i,{cwd:e.dir,env:zi(e.binary)});if(a.code!==0)throw new cr(`\`${n} ${i.join(" ")}\` failed (exit ${a.code}): ${a.stderr.trim()}`);let c;try{c=Py(a.stdout).map(l=>l.path)}catch(l){throw new cr(`could not read \`terragrunt find\` output: ${l instanceof Error?l.message:String(l)}`)}let u=e.units??(await dw(e)).units;return S7({dir:e.dir,units:u,terragruntSelected:c,changedFiles:s.stdout.split(`
54
- `).map(l=>l.trim()).filter(l=>l!=="")})}var wd=".terragrunt-stack",E7=e=>e.split("\\").join("/");function T7(e){return LR(e).filter(t=>!t.split("/").includes(wd)).map(t=>t.includes("/")?t.slice(0,t.lastIndexOf("/")):".").sort()}function Qa(e){let t=E7(e);if(t.startsWith(`${wd}/`))return".";let n=t.lastIndexOf(`/${wd}/`);return n<0?void 0:t.slice(0,n)}function bd(e){return e==="."?"terragrunt.stack.hcl":`${e}/terragrunt.stack.hcl`}function Ui(e){let t=Qa(e);return t===void 0?{stack:jy(e)}:{stack:t,stack_file:bd(t)}}async function Bi(e,t={}){let n=T7(e);if(n.length===0)return[];let r=t.terragrunt??process.env.TERRAGUCCI_TERRAGRUNT??"terragrunt",o=t.exec??Nn,s={dir:e,terragrunt:r,...t.binary?{binary:t.binary}:{},exec:o};try{await lw(s)}catch(a){throw new S(`${n.map(bd).join(", ")}: an explicit stack's units are generated by terragrunt stack generate, and Terragrunt did not run (${a.message.split(`
53
+ `)){if(r===0){let i=n.exec(o);if(i)return i[1]}let s=o.replace(/"(?:[^"\\]|\\.)*"/g,'""');r+=(s.match(/[{[]/g)??[]).length-(s.match(/[}\]]/g)??[]).length}}var kX=new Set([".git",".terragrunt-cache","node_modules",".terraform"]);function LR(e){let t=[],n=r=>{let o;try{o=pX(DR(e,r),{withFileTypes:!0})}catch{return}for(let s of o){let i=r?`${r}/${s.name}`:s.name;s.isDirectory()&&!kX.has(s.name)?n(i):s.isFile()&&s.name==="terragrunt.stack.hcl"&&t.push(i)}};return n(""),t.sort()}function _X(e){let t=e.lastIndexOf("/.terragrunt-stack/");return t<0?void 0:`${e.slice(0,t)}/terragrunt.stack.hcl`}function SX(e){let t=[...new Set(e.changedFiles.map(Yf))].sort(),n=new Map(e.units.map(a=>[a.path,a])),r=new Map,o=[],s=(a,c)=>{let u=r.get(a)??[];u.push(c),r.set(a,u)};for(let a of new Set(e.terragruntSelected.map(Yf))){let c=n.get(a);if(!c){dX(DR(e.dir,a,"terragrunt.hcl"))?o.push(`${a}: Terragrunt's git range selected it, but discovery left it out, so it is not affected here`):s(a,{kind:"removed",files:t.filter(l=>Tu(a,l))});continue}let u=new Set([...c.reading??[],...Object.values(c.include??{}),_X(c.path)].filter(l=>!!l));s(a,{kind:"terragrunt",files:t.filter(l=>Tu(c.path,l)||u.has(l))})}for(let a of e.units){let c=new Set(a.reading??[]),u=vX(a),l=new Map;for(let f of u)for(let g of NR(e.dir,{dir:f}))!u.includes(g)&&!l.has(g)&&l.set(g,f);let d=new Map,p=new Map;for(let f of t){if(c.has(f))continue;let g=[...l.keys()].filter(h=>Tu(h,f)).sort((h,y)=>y.length-h.length)[0];if(g!==void 0){p.set(g,[...p.get(g)??[],f]);continue}let m=u.filter(h=>Tu(h,f)).sort((h,y)=>y.length-h.length)[0];m!==void 0&&d.set(m,[...d.get(m)??[],f])}for(let[f,g]of d)s(a.path,{kind:"module-file",files:g,via:f});for(let[f,g]of p)s(a.path,{kind:"module-call",files:g,via:f})}for(let a of LR(e.dir)){let c;try{c=fX(DR(e.dir,a),"utf8")}catch{continue}for(let u of MR(e.dir,a,c)){if(u.template===void 0)continue;let l=t.filter(p=>Tu(u.template,p));if(l.length===0)continue;let d=u.type==="unit"?n.has(u.generated)?[u.generated]:[]:e.units.filter(p=>Tu(u.generated,p.path)).map(p=>p.path);d.length===0&&o.push(`${u.generated}: generated by ${u.type} "${u.name}" in ${a} from the changed template ${u.template}, but discovery did not list it; run \`terragrunt stack generate\` before discovery`);for(let p of d)s(p,{kind:"stack-template",files:l,via:u.template})}}return{units:[...r.entries()].map(([a,c])=>({path:a,reasons:c.sort((u,l)=>IN.indexOf(u.kind)-IN.indexOf(l.kind)||(u.via??"").localeCompare(l.via??""))})).sort((a,c)=>a.path<c.path?-1:a.path>c.path?1:0),notes:[...new Set(o)].sort()}}function DN(e){let t=e.files.join(", ");switch(e.kind){case"terragrunt":return t?`Terragrunt's git range selected it (${t})`:"Terragrunt's git range selected it";case"removed":return"removed in the range; Terragrunt plans its destroy";case"module-file":return`${t} changed under its module ${e.via}, which Terragrunt does not track`;case"module-call":return`${t} changed under ${e.via}, a module its module calls`;case"stack-template":return`${t} changed under ${e.via}, the stack template it is generated from`}}async function MN(e){let t=e.exec??Eu,n=e.terragrunt??"terragrunt",r=e.git??"git",o=bX(e),s=await t(r,o,{cwd:e.dir,env:{}});if(s.code!==0)throw new cr(`\`${r} ${o.join(" ")}\` failed (exit ${s.code}): ${s.stderr.trim()}`);let i=wX(e),a=await t(n,i,{cwd:e.dir,env:zi(e.binary)});if(a.code!==0)throw new cr(`\`${n} ${i.join(" ")}\` failed (exit ${a.code}): ${a.stderr.trim()}`);let c;try{c=Py(a.stdout).map(l=>l.path)}catch(l){throw new cr(`could not read \`terragrunt find\` output: ${l instanceof Error?l.message:String(l)}`)}let u=e.units??(await dw(e)).units;return SX({dir:e.dir,units:u,terragruntSelected:c,changedFiles:s.stdout.split(`
54
+ `).map(l=>l.trim()).filter(l=>l!=="")})}var wd=".terragrunt-stack",EX=e=>e.split("\\").join("/");function TX(e){return LR(e).filter(t=>!t.split("/").includes(wd)).map(t=>t.includes("/")?t.slice(0,t.lastIndexOf("/")):".").sort()}function Qa(e){let t=EX(e);if(t.startsWith(`${wd}/`))return".";let n=t.lastIndexOf(`/${wd}/`);return n<0?void 0:t.slice(0,n)}function bd(e){return e==="."?"terragrunt.stack.hcl":`${e}/terragrunt.stack.hcl`}function Ui(e){let t=Qa(e);return t===void 0?{stack:jy(e)}:{stack:t,stack_file:bd(t)}}async function Bi(e,t={}){let n=TX(e);if(n.length===0)return[];let r=t.terragrunt??process.env.TERRAGUCCI_TERRAGRUNT??"terragrunt",o=t.exec??Nn,s={dir:e,terragrunt:r,...t.binary?{binary:t.binary}:{},exec:o};try{await lw(s)}catch(a){throw new S(`${n.map(bd).join(", ")}: an explicit stack's units are generated by terragrunt stack generate, and Terragrunt did not run (${a.message.split(`
55
55
  `)[0]}); put Terragrunt 1.1 or later on the path, or set TERRAGUCCI_TERRAGRUNT`)}let i=await o(r,["stack","generate","--non-interactive","--no-color"],{cwd:e,env:{TG_NON_INTERACTIVE:"true",...t.binary?{TG_TF_PATH:t.binary}:{}}});if(i.code!==0)throw new S(`terragrunt stack generate failed (exit ${i.code}):
56
56
  ${(i.stderr||i.stdout).trim().split(`
57
57
  `).slice(-20).join(`
58
- `)}`);return n}function LN(e,t){let n=[];for(let r of t){let o=bd(r),s=R7(x7(e,o),"utf-8");for(let i of MR(e,o,s)){if(i.template===void 0){let a=new RegExp(`\\b${i.type}\\s+"${i.name.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}"\\s*\\{`).exec(s),c=a?s.slice(a.index+a[0].length):"",u=c.search(/^\s*(unit|stack)\s+"/m),l=a?/^\s*source\s*=\s*"\$\{get_repo_root\(\)\}\/([^"$]*)"/m.exec(u<0?c:c.slice(0,u)):null;l&&(i.template=l[1].replace("//","/").replace(/\/+$/,""))}if(i.type==="stack")throw new S(`${o}: stack "${i.name}" nests a stack, and ${PC}`);n.push({unit:i.generated,file:o,name:i.name,...i.template!==void 0?{template:i.template}:{}})}}return n}var GN=["root.hcl","terragrunt.hcl","terragrunt.stack.hcl"],P7=new Set([".git",".terraform",".terragrunt-cache","node_modules",".terragucci","terragucci-report"]),gw=e=>e.split("\\").join("/");function zN(e,t,n=()=>!1){let r=o=>{let s;try{s=FN(o)}catch{return}t(o,s);for(let i of s){if(P7.has(i)||i.startsWith(".")&&!n(i))continue;let a=eg(o,i);A7(a).isDirectory()&&r(a)}};r(e)}function vd(e){let t=new Map,n=[];zN(e,(o,s)=>{let i=gw(fw(e,o))||".";for(let a of GN)s.includes(a)&&!t.has(a)&&t.set(a,i==="."?a:`${i}/${a}`);s.includes("terragrunt.stack.hcl")&&n.push(i)});let r=GN.find(o=>t.has(o));return r?{reason:t.get(r),stacks:n.sort()}:void 0}function Xf(e,t){let n=[],r=new RegExp(`^\\s*${t}\\b[^{\\n]*\\{`,"gm");for(let o=r.exec(e);o;o=r.exec(e)){let s=1,i=o.index+o[0].length,a=i;for(let c=!1;i<e.length&&s>0;i++){let u=e[i];c?u==="\\"?i++:u==='"'&&(c=!1):u==='"'?c=!0:u==="{"?s++:u==="}"&&s--}n.push(e.slice(a,i-1)),r.lastIndex=i}return n}function zR(e){let t=e.replace(/(^|[^:"$])(#|\/\/).*$/gm,"$1"),n=/^"([^"$]*)"$/,r=[];for(let o of Xf(t,"dependency")){let s=/^\s*config_path\s*=\s*("[^"\n]*")\s*$/m.exec(o),i=s&&n.exec(s[1]);i&&r.push(i[1])}for(let o of Xf(t,"dependencies")){let s=/\bpaths\s*=\s*\[([^\]]*)\]/.exec(o);for(let i of s?s[1].split(",").map(a=>a.trim()).filter(Boolean):[]){let a=n.exec(i);a&&r.push(a[1])}}return r}function Dn(e,t=[]){let n=[...hu,...t],r=[];zN(e,(s,i)=>{let a=gw(fw(e,s));if(!a||!i.includes("terragrunt.hcl")||n.some(l=>ql(a,l)))return;let c="";try{c=Qf(eg(s,"terragrunt.hcl"),"utf-8")}catch{}let u=zR(c).map(l=>gw(fw(e,GR(s,l))));r.push({path:a,dependencies:[...new Set(u)].sort()})},s=>s===wd);let o=new Set(r.map(s=>s.path));for(let s of r)s.dependencies=s.dependencies.filter(i=>o.has(i));return r.sort((s,i)=>s.path<i.path?-1:1)}async function qs(e,t={}){let n=t.terragrunt??process.env.TERRAGUCCI_TERRAGRUNT??"terragrunt",r={dir:e,terragrunt:n,...t.binary?{binary:t.binary}:{},exec:t.exec??Nn};await Bi(e,r);let o;try{await lw(r);let s=await dw({...r,...t.exclude?{exclude:t.exclude}:{}});return{units:s.units,source:"terragrunt find",notes:s.warnings}}catch(s){o=s.message}return{units:Dn(e,t.exclude),source:"terragrunt.hcl files",notes:[`units and their edges come from terragrunt.hcl files: Terragrunt discovery did not run (${o.split(`
59
- `)[0]}), so a dependency path built with a function is not followed; the apply jobs take the waves from terragrunt find`]}}function Js(e,t=[]){return iS(e,{canary:t}).filter(n=>n.length>0)}function mw(e,t){let n=new Map(t.map(s=>[s.path,s.dependencies])),r=new Map;e.forEach((s,i)=>s.forEach(a=>r.set(a,i)));let o=[];return e.forEach((s,i)=>{let a=new Set(s);for(let u of s){let l=(n.get(u)??[]).filter(d=>(r.get(d)??-1)>i);if(l.length>0)throw new S(`${u} reads ${l.join(", ")}, which the pipeline applies in a later wave; run terragucci init to cut the waves again`)}let c=s.map(u=>({path:u,dependencies:(n.get(u)??[]).filter(l=>a.has(l))}));o.push(...iS(c).filter(u=>u.length>0))}),o}function UR(e){return new Map(e.map(t=>[t.path,new Set(t.dependencies)]))}function j7(e){let t=eg(e,"root.hcl");if(!FR(t))return;let n=Qf(t,"utf-8").replace(/(^|[^:"])(#|\/\/).*$/gm,"$1"),r=/\bremote_state\s*\{[\s\S]*?\bbackend\s*=\s*"([^"]+)"/.exec(n);if(r)return{backend:r[1],gitlab:r[1]==="http"&&/\/api\/v4\/projects\/[^"]*\/terraform\/state\//.test(n)}}function UN(e,t={}){if(t.parallelism!==void 0)return{value:t.parallelism,reason:"terragucci.yml"};let n=j7(e);return n?.gitlab?{value:3,reason:"GitLab-managed state rate-limits concurrent inits"}:{value:16,reason:n?`the ${n.backend} backend`:"the default"}}function BN(e){let t=eg(e,"root.hcl");if(FR(t))return/terragrunt_version_constraint\s*=\s*"\s*=?\s*(\d+\.\d+\.\d+)\s*"/.exec(Qf(t,"utf-8"))?.[1]}var Au="TERRAGUCCI_TG_ROLES";function WN(e,t){return Object.entries(e).map(([n,r])=>[n,r[t]])}function I7(e,t){let n=s=>{try{return/^\s*iam_role\s*=/m.test(Qf(s,"utf-8"))}catch{return!1}},r=GR(e),o=GR(t);for(let s=o;s.startsWith(r);s=O7(s)){if((s===o?["terragrunt.hcl"]:FN(s).filter(a=>/^[^.].*\.hcl$/.test(a)&&a!=="terragrunt.hcl")).some(a=>n(eg(s,a))))return!0;if(s===r)break}return!1}function HN(e,t){let n=t.TERRAGUCCI_REPO??process.cwd(),r=gw(fw(n,e)),o;try{o=JSON.parse(t[Au]??"[]")}catch{throw new S(`${Au} is not JSON`)}if(I7(n,e))return{};let s=o.find(([c])=>ql(r,c));if(!s)return{};let i=Li(t);if(i){let c=Ru(i,s[1]);return{awsCredentials:{ACCESS_KEY_ID:c.accessKeyId,SECRET_ACCESS_KEY:c.secretAccessKey,...c.sessionToken?{SESSION_TOKEN:c.sessionToken}:{}}}}let a=t.AWS_WEB_IDENTITY_TOKEN_FILE;if(!a||!FR(a))throw new S(`${r} needs ${s[1]}, but the job has no OIDC token file`);return{awsRole:{roleARN:s[1],roleSessionName:`terragucci-${t.TERRAGUCCI_PHASE??"run"}`,webIdentityToken:Qf(a,"utf-8").trim()}}}var yw="1.230.1",ww="atmos.yaml",bw="terragucci atmos write";function vw(e){return tg(qr(e,ww))?ww:void 0}var YN=".terragucci-atmos.json",HR=".terragucci-terramate.json",G7="terragucci-atmos-reads.auto.tfvars.json",F7=["terraform.state","terraform.output","store","store.get"],JN=/^!(terraform\.state|terraform\.output|store\.get|store)(\s|$)/;function z7(e){let t=[];for(let n of e.matchAll(/"((?:[^"\\]|\\.)*)"|'([^']*)'|(\S+)/g))t.push(n[1]??n[2]??n[3]);return t}function U7(e,t,n,r){if(typeof r!="string"){let c=l=>typeof l=="string"?JN.test(l)?l:void 0:l&&typeof l=="object"?Object.values(l).map(c).find(d=>d):void 0,u=c(r);if(u)throw new S(`${e} sets ${n} with ${u.split(/\s/)[0]} inside a map or a list; terragucci reads a whole var only, so give the function a var of its own`);return}let o=r.match(JN);if(!o)return;let s=o[1];if(s==="store"||s==="store.get")throw new S(`${e} sets ${n} with !${s}, which terragucci does not read in the job; output the value from an instance and read it with !terraform.state`);let i=z7(r.slice(o[0].length));if(i.length!==2&&i.length!==3)throw new S(`${e} sets ${n} with "${r}"; terragucci reads !${s} <component> [<stack>] <output>`);let a=i[i.length-1];if(!/^\.?[A-Za-z_][\w-]*(\.[A-Za-z_][\w-]*)*$/.test(a))throw new S(`${e} sets ${n} with "${r}", whose expression ${a} terragucci does not evaluate; read an output by name or by a path of keys, such as .subnets.private`);return{var:n,component:i[0],stack:i.length===3?i[1]:t,output:a.replace(/^\./,"").split("."),function:r}}var yn=e=>e&&typeof e=="object"&&!Array.isArray(e)?e:{},ps=e=>typeof e=="string"&&e!==""?e:void 0,XN=e=>e.split(L7).join("/"),B7={ATMOS_TELEMETRY_ENABLED:"false",ATMOS_LOGS_LEVEL:"Warning"};async function Wi(e,t={}){let n=t.atmos??process.env.TERRAGUCCI_ATMOS??"atmos",r=t.exec??Nn,o;try{o=await r(n,["describe","stacks","--format","json","--component-types","terraform",...F7.flatMap(s=>["--skip",s])],{cwd:e,env:{...B7}})}catch(s){throw new S(`atmos describe stacks did not run (${s.message}); put Atmos ${yw} on the path, or set TERRAGUCCI_ATMOS`)}if(o.code!==0){let s=(o.stderr||o.stdout).trim().split(`
58
+ `)}`);return n}function LN(e,t){let n=[];for(let r of t){let o=bd(r),s=RX(xX(e,o),"utf-8");for(let i of MR(e,o,s)){if(i.template===void 0){let a=new RegExp(`\\b${i.type}\\s+"${i.name.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}"\\s*\\{`).exec(s),c=a?s.slice(a.index+a[0].length):"",u=c.search(/^\s*(unit|stack)\s+"/m),l=a?/^\s*source\s*=\s*"\$\{get_repo_root\(\)\}\/([^"$]*)"/m.exec(u<0?c:c.slice(0,u)):null;l&&(i.template=l[1].replace("//","/").replace(/\/+$/,""))}if(i.type==="stack")throw new S(`${o}: stack "${i.name}" nests a stack, and ${PC}`);n.push({unit:i.generated,file:o,name:i.name,...i.template!==void 0?{template:i.template}:{}})}}return n}var GN=["root.hcl","terragrunt.hcl","terragrunt.stack.hcl"],PX=new Set([".git",".terraform",".terragrunt-cache","node_modules",".terragucci","terragucci-report"]),gw=e=>e.split("\\").join("/");function zN(e,t,n=()=>!1){let r=o=>{let s;try{s=FN(o)}catch{return}t(o,s);for(let i of s){if(PX.has(i)||i.startsWith(".")&&!n(i))continue;let a=eg(o,i);AX(a).isDirectory()&&r(a)}};r(e)}function vd(e){let t=new Map,n=[];zN(e,(o,s)=>{let i=gw(fw(e,o))||".";for(let a of GN)s.includes(a)&&!t.has(a)&&t.set(a,i==="."?a:`${i}/${a}`);s.includes("terragrunt.stack.hcl")&&n.push(i)});let r=GN.find(o=>t.has(o));return r?{reason:t.get(r),stacks:n.sort()}:void 0}function Xf(e,t){let n=[],r=new RegExp(`^\\s*${t}\\b[^{\\n]*\\{`,"gm");for(let o=r.exec(e);o;o=r.exec(e)){let s=1,i=o.index+o[0].length,a=i;for(let c=!1;i<e.length&&s>0;i++){let u=e[i];c?u==="\\"?i++:u==='"'&&(c=!1):u==='"'?c=!0:u==="{"?s++:u==="}"&&s--}n.push(e.slice(a,i-1)),r.lastIndex=i}return n}function zR(e){let t=e.replace(/(^|[^:"$])(#|\/\/).*$/gm,"$1"),n=/^"([^"$]*)"$/,r=[];for(let o of Xf(t,"dependency")){let s=/^\s*config_path\s*=\s*("[^"\n]*")\s*$/m.exec(o),i=s&&n.exec(s[1]);i&&r.push(i[1])}for(let o of Xf(t,"dependencies")){let s=/\bpaths\s*=\s*\[([^\]]*)\]/.exec(o);for(let i of s?s[1].split(",").map(a=>a.trim()).filter(Boolean):[]){let a=n.exec(i);a&&r.push(a[1])}}return r}function Dn(e,t=[]){let n=[...hu,...t],r=[];zN(e,(s,i)=>{let a=gw(fw(e,s));if(!a||!i.includes("terragrunt.hcl")||n.some(l=>ql(a,l)))return;let c="";try{c=Qf(eg(s,"terragrunt.hcl"),"utf-8")}catch{}let u=zR(c).map(l=>gw(fw(e,GR(s,l))));r.push({path:a,dependencies:[...new Set(u)].sort()})},s=>s===wd);let o=new Set(r.map(s=>s.path));for(let s of r)s.dependencies=s.dependencies.filter(i=>o.has(i));return r.sort((s,i)=>s.path<i.path?-1:1)}async function qs(e,t={}){let n=t.terragrunt??process.env.TERRAGUCCI_TERRAGRUNT??"terragrunt",r={dir:e,terragrunt:n,...t.binary?{binary:t.binary}:{},exec:t.exec??Nn};await Bi(e,r);let o;try{await lw(r);let s=await dw({...r,...t.exclude?{exclude:t.exclude}:{}});return{units:s.units,source:"terragrunt find",notes:s.warnings}}catch(s){o=s.message}return{units:Dn(e,t.exclude),source:"terragrunt.hcl files",notes:[`units and their edges come from terragrunt.hcl files: Terragrunt discovery did not run (${o.split(`
59
+ `)[0]}), so a dependency path built with a function is not followed; the apply jobs take the waves from terragrunt find`]}}function Js(e,t=[]){return iS(e,{canary:t}).filter(n=>n.length>0)}function mw(e,t){let n=new Map(t.map(s=>[s.path,s.dependencies])),r=new Map;e.forEach((s,i)=>s.forEach(a=>r.set(a,i)));let o=[];return e.forEach((s,i)=>{let a=new Set(s);for(let u of s){let l=(n.get(u)??[]).filter(d=>(r.get(d)??-1)>i);if(l.length>0)throw new S(`${u} reads ${l.join(", ")}, which the pipeline applies in a later wave; run terragucci init to cut the waves again`)}let c=s.map(u=>({path:u,dependencies:(n.get(u)??[]).filter(l=>a.has(l))}));o.push(...iS(c).filter(u=>u.length>0))}),o}function UR(e){return new Map(e.map(t=>[t.path,new Set(t.dependencies)]))}function jX(e){let t=eg(e,"root.hcl");if(!FR(t))return;let n=Qf(t,"utf-8").replace(/(^|[^:"])(#|\/\/).*$/gm,"$1"),r=/\bremote_state\s*\{[\s\S]*?\bbackend\s*=\s*"([^"]+)"/.exec(n);if(r)return{backend:r[1],gitlab:r[1]==="http"&&/\/api\/v4\/projects\/[^"]*\/terraform\/state\//.test(n)}}function UN(e,t={}){if(t.parallelism!==void 0)return{value:t.parallelism,reason:"terragucci.yml"};let n=jX(e);return n?.gitlab?{value:3,reason:"GitLab-managed state rate-limits concurrent inits"}:{value:16,reason:n?`the ${n.backend} backend`:"the default"}}function BN(e){let t=eg(e,"root.hcl");if(FR(t))return/terragrunt_version_constraint\s*=\s*"\s*=?\s*(\d+\.\d+\.\d+)\s*"/.exec(Qf(t,"utf-8"))?.[1]}var Au="TERRAGUCCI_TG_ROLES";function WN(e,t){return Object.entries(e).map(([n,r])=>[n,r[t]])}function IX(e,t){let n=s=>{try{return/^\s*iam_role\s*=/m.test(Qf(s,"utf-8"))}catch{return!1}},r=GR(e),o=GR(t);for(let s=o;s.startsWith(r);s=OX(s)){if((s===o?["terragrunt.hcl"]:FN(s).filter(a=>/^[^.].*\.hcl$/.test(a)&&a!=="terragrunt.hcl")).some(a=>n(eg(s,a))))return!0;if(s===r)break}return!1}function HN(e,t){let n=t.TERRAGUCCI_REPO??process.cwd(),r=gw(fw(n,e)),o;try{o=JSON.parse(t[Au]??"[]")}catch{throw new S(`${Au} is not JSON`)}if(IX(n,e))return{};let s=o.find(([c])=>ql(r,c));if(!s)return{};let i=Li(t);if(i){let c=Ru(i,s[1]);return{awsCredentials:{ACCESS_KEY_ID:c.accessKeyId,SECRET_ACCESS_KEY:c.secretAccessKey,...c.sessionToken?{SESSION_TOKEN:c.sessionToken}:{}}}}let a=t.AWS_WEB_IDENTITY_TOKEN_FILE;if(!a||!FR(a))throw new S(`${r} needs ${s[1]}, but the job has no OIDC token file`);return{awsRole:{roleARN:s[1],roleSessionName:`terragucci-${t.TERRAGUCCI_PHASE??"run"}`,webIdentityToken:Qf(a,"utf-8").trim()}}}var yw="1.230.1",ww="atmos.yaml",bw="terragucci atmos write";function vw(e){return tg(qr(e,ww))?ww:void 0}var YN=".terragucci-atmos.json",HR=".terragucci-terramate.json",GX="terragucci-atmos-reads.auto.tfvars.json",FX=["terraform.state","terraform.output","store","store.get"],JN=/^!(terraform\.state|terraform\.output|store\.get|store)(\s|$)/;function zX(e){let t=[];for(let n of e.matchAll(/"((?:[^"\\]|\\.)*)"|'([^']*)'|(\S+)/g))t.push(n[1]??n[2]??n[3]);return t}function UX(e,t,n,r){if(typeof r!="string"){let c=l=>typeof l=="string"?JN.test(l)?l:void 0:l&&typeof l=="object"?Object.values(l).map(c).find(d=>d):void 0,u=c(r);if(u)throw new S(`${e} sets ${n} with ${u.split(/\s/)[0]} inside a map or a list; terragucci reads a whole var only, so give the function a var of its own`);return}let o=r.match(JN);if(!o)return;let s=o[1];if(s==="store"||s==="store.get")throw new S(`${e} sets ${n} with !${s}, which terragucci does not read in the job; output the value from an instance and read it with !terraform.state`);let i=zX(r.slice(o[0].length));if(i.length!==2&&i.length!==3)throw new S(`${e} sets ${n} with "${r}"; terragucci reads !${s} <component> [<stack>] <output>`);let a=i[i.length-1];if(!/^\.?[A-Za-z_][\w-]*(\.[A-Za-z_][\w-]*)*$/.test(a))throw new S(`${e} sets ${n} with "${r}", whose expression ${a} terragucci does not evaluate; read an output by name or by a path of keys, such as .subnets.private`);return{var:n,component:i[0],stack:i.length===3?i[1]:t,output:a.replace(/^\./,"").split("."),function:r}}var yn=e=>e&&typeof e=="object"&&!Array.isArray(e)?e:{},ps=e=>typeof e=="string"&&e!==""?e:void 0,XN=e=>e.split(LX).join("/"),BX={ATMOS_TELEMETRY_ENABLED:"false",ATMOS_LOGS_LEVEL:"Warning"};async function Wi(e,t={}){let n=t.atmos??process.env.TERRAGUCCI_ATMOS??"atmos",r=t.exec??Nn,o;try{o=await r(n,["describe","stacks","--format","json","--component-types","terraform",...FX.flatMap(s=>["--skip",s])],{cwd:e,env:{...BX}})}catch(s){throw new S(`atmos describe stacks did not run (${s.message}); put Atmos ${yw} on the path, or set TERRAGUCCI_ATMOS`)}if(o.code!==0){let s=(o.stderr||o.stdout).trim().split(`
60
60
  `).filter(i=>i.trim()).slice(0,12).join(`
61
61
  `);throw new S(o.code===null||/ENOENT|not found/.test(s)?`atmos describe stacks did not run (${s.split(`
62
62
  `)[0]}); put Atmos ${yw} on the path, or set TERRAGUCCI_ATMOS`:`atmos describe stacks failed (exit ${o.code}):
63
63
  ${s}`)}try{return yn(JSON.parse(o.stdout))}catch{throw new S(`atmos describe stacks printed no JSON:
64
- ${o.stdout.slice(0,400)}`)}}var hw=["namespace","tenant","environment","stage"];function W7(e){let t=[],n=o=>{let s=ps(o.component);if(!s)return;let i={};for(let a of hw)ps(o[a])&&(i[a]=o[a]);t.push({component:s,...ps(o.stack)?{stack:o.stack}:{},context:i})},r=yn(e.dependencies).components;if(Array.isArray(r))for(let o of r)n(yn(o));for(let o of Object.values(yn(yn(e.settings).depends_on)))n(yn(o));return t}function Hi(e){let t=[],n=new Set;for(let[o,s]of Object.entries(e))for(let[i,a]of Object.entries(yn(yn(yn(s).components).terraform))){let c=yn(a),u=yn(c.metadata);if(u.type==="abstract")continue;let l=`${o}/${i}`;if(u.enabled===!1){n.add(l);continue}for(let f of["env","generate"])if(Object.keys(yn(c[f])).length>0)throw new S(`${l} sets ${f}, which terragucci does not carry into the jobs yet; move it into the component's Terraform, or leave the instance out with metadata.enabled: false`);let d=Object.entries(yn(c.vars)).map(([f,g])=>U7(l,o,f,g)).filter(f=>f!==void 0),p=ps(yn(c.component_info).component_path)??`components/terraform/${ps(u.component)??ps(c.component)??i}`;t.push({path:l,stack:o,component:i,componentPath:XN(p),workspace:ps(c.workspace)??o,vars:yn(c.vars),backendType:ps(c.backend_type)??"",backend:yn(c.backend),providers:yn(c.providers),dependencies:[],reads:[],raw:W7(c),ctx:yn(c.vars),rawReads:d})}let r=new Map(t.map(o=>[o.path,o]));for(let o of t){let s=new Set;for(let i of o.raw){let a=i.stack;if(!a&&Object.keys(i.context).length>0){let u=Object.fromEntries(hw.map(d=>[d,i.context[d]??o.ctx[d]])),l=t.filter(d=>d.component===i.component&&hw.every(p=>u[p]===void 0||d.ctx[p]===u[p]));if(a=l.length===1?l[0].stack:void 0,!a){let d=hw.filter(p=>u[p]!==void 0).map(p=>`${p} ${String(u[p])}`).join(", ");throw new S(`${o.path} depends on ${i.component} in ${d}, which ${l.length===0?"no stack has":`${l.length} stacks have`}`)}}let c=`${a??o.stack}/${i.component}`;if(c!==o.path&&!n.has(c)){if(!r.has(c))throw new S(`${o.path} depends on ${c}, which no stack deploys`);s.add(c)}}for(let i of o.rawReads){let a=`${i.stack}/${i.component}`,c=`${o.path} reads ${i.var} from ${a} (${i.function})`;if(a===o.path)throw new S(`${c}, its own state`);if(n.has(a))throw new S(`${c}, which is disabled, so nothing ever applies it`);if(!r.has(a))throw new S(`${c}, which no stack deploys`);s.add(a),o.reads.push({var:i.var,upstream:a,output:i.output,function:i.function})}o.dependencies=[...s].sort()}return t.map(({raw:o,ctx:s,rawReads:i,...a})=>a).sort((o,s)=>o.path<s.path?-1:o.path>s.path?1:0)}function QN(e,t=[]){try{return Js(e.map(n=>({path:n.path,dependencies:n.dependencies})),t)}catch(n){throw new S(n.message)}}function H7(e){return e===".terraform"||e==="terraform.tfstate.d"||/\.tfstate(\.backup)?$/.test(e)||/\.planfile$/.test(e)||e==="backend.tf.json"||e==="providers_override.tf.json"||e.endsWith(".terraform.tfvars.json")}function q7(e,t,n,r){return e.replace(/(\bsource\s*=\s*")(\.\.?\/[^"]*)(")/g,(o,s,i,a)=>{let c=ZN(t,i);return qN(r,c).startsWith("..")?`${s}${XN(qN(n,c))}${a}`:o})}function eD(e,t,n){D7(t,{recursive:!0});for(let r of BR(e)){if(H7(r))continue;let o=qr(e,r),s=qr(t,r);VN(o).isDirectory()?eD(o,s,n):/\.(tf|tofu)$/.test(r)?WR(s,q7(KN(o,"utf-8"),e,t,n)):N7(o,s)}}function J7(e){let t=s=>`${JSON.stringify(s,null,2)}
64
+ ${o.stdout.slice(0,400)}`)}}var hw=["namespace","tenant","environment","stage"];function WX(e){let t=[],n=o=>{let s=ps(o.component);if(!s)return;let i={};for(let a of hw)ps(o[a])&&(i[a]=o[a]);t.push({component:s,...ps(o.stack)?{stack:o.stack}:{},context:i})},r=yn(e.dependencies).components;if(Array.isArray(r))for(let o of r)n(yn(o));for(let o of Object.values(yn(yn(e.settings).depends_on)))n(yn(o));return t}function Hi(e){let t=[],n=new Set;for(let[o,s]of Object.entries(e))for(let[i,a]of Object.entries(yn(yn(yn(s).components).terraform))){let c=yn(a),u=yn(c.metadata);if(u.type==="abstract")continue;let l=`${o}/${i}`;if(u.enabled===!1){n.add(l);continue}for(let f of["env","generate"])if(Object.keys(yn(c[f])).length>0)throw new S(`${l} sets ${f}, which terragucci does not carry into the jobs yet; move it into the component's Terraform, or leave the instance out with metadata.enabled: false`);let d=Object.entries(yn(c.vars)).map(([f,g])=>UX(l,o,f,g)).filter(f=>f!==void 0),p=ps(yn(c.component_info).component_path)??`components/terraform/${ps(u.component)??ps(c.component)??i}`;t.push({path:l,stack:o,component:i,componentPath:XN(p),workspace:ps(c.workspace)??o,vars:yn(c.vars),backendType:ps(c.backend_type)??"",backend:yn(c.backend),providers:yn(c.providers),dependencies:[],reads:[],raw:WX(c),ctx:yn(c.vars),rawReads:d})}let r=new Map(t.map(o=>[o.path,o]));for(let o of t){let s=new Set;for(let i of o.raw){let a=i.stack;if(!a&&Object.keys(i.context).length>0){let u=Object.fromEntries(hw.map(d=>[d,i.context[d]??o.ctx[d]])),l=t.filter(d=>d.component===i.component&&hw.every(p=>u[p]===void 0||d.ctx[p]===u[p]));if(a=l.length===1?l[0].stack:void 0,!a){let d=hw.filter(p=>u[p]!==void 0).map(p=>`${p} ${String(u[p])}`).join(", ");throw new S(`${o.path} depends on ${i.component} in ${d}, which ${l.length===0?"no stack has":`${l.length} stacks have`}`)}}let c=`${a??o.stack}/${i.component}`;if(c!==o.path&&!n.has(c)){if(!r.has(c))throw new S(`${o.path} depends on ${c}, which no stack deploys`);s.add(c)}}for(let i of o.rawReads){let a=`${i.stack}/${i.component}`,c=`${o.path} reads ${i.var} from ${a} (${i.function})`;if(a===o.path)throw new S(`${c}, its own state`);if(n.has(a))throw new S(`${c}, which is disabled, so nothing ever applies it`);if(!r.has(a))throw new S(`${c}, which no stack deploys`);s.add(a),o.reads.push({var:i.var,upstream:a,output:i.output,function:i.function})}o.dependencies=[...s].sort()}return t.map(({raw:o,ctx:s,rawReads:i,...a})=>a).sort((o,s)=>o.path<s.path?-1:o.path>s.path?1:0)}function QN(e,t=[]){try{return Js(e.map(n=>({path:n.path,dependencies:n.dependencies})),t)}catch(n){throw new S(n.message)}}function HX(e){return e===".terraform"||e==="terraform.tfstate.d"||/\.tfstate(\.backup)?$/.test(e)||/\.planfile$/.test(e)||e==="backend.tf.json"||e==="providers_override.tf.json"||e.endsWith(".terraform.tfvars.json")}function qX(e,t,n,r){return e.replace(/(\bsource\s*=\s*")(\.\.?\/[^"]*)(")/g,(o,s,i,a)=>{let c=ZN(t,i);return qN(r,c).startsWith("..")?`${s}${XN(qN(n,c))}${a}`:o})}function eD(e,t,n){DX(t,{recursive:!0});for(let r of BR(e)){if(HX(r))continue;let o=qr(e,r),s=qr(t,r);VN(o).isDirectory()?eD(o,s,n):/\.(tf|tofu)$/.test(r)?WR(s,qX(KN(o,"utf-8"),e,t,n)):NX(o,s)}}function JX(e){let t=s=>`${JSON.stringify(s,null,2)}
65
65
  `,n=new Set(e.reads.map(s=>s.var)),r=Object.fromEntries(Object.entries(e.vars).filter(([s])=>!n.has(s))),o={"terragucci-atmos.auto.tfvars.json":t(r),[ow]:`${e.workspace}
66
- `,[YN]:t({component:e.componentPath,dependencies:e.dependencies,reads:e.reads})};return e.backendType==="cloud"?o["backend.tf.json"]=t({terraform:{cloud:e.backend}}):e.backendType&&(o["backend.tf.json"]=t({terraform:{backend:{[e.backendType]:e.backend}}})),Object.keys(e.providers).length>0&&(o["providers_override.tf.json"]=t({provider:e.providers})),o}function K7(e,t){for(let n of t){let r=qr(e,n.componentPath);if(!tg(r)||!VN(r).isDirectory())throw new S(`${n.path} runs ${n.componentPath}, which the repo does not have`);let o=qr(e,n.path);if(tg(o)){if(!tg(qr(o,ow))&&BR(o).length>0)throw new S(`${n.path} is a directory of the repo, and the Atmos instance ${n.component} in stack ${n.stack} is written there; rename one of them`);for(let s of BR(o))s!==".terraform"&&M7(qr(o,s),{recursive:!0,force:!0})}eD(r,o,ZN(r));for(let[s,i]of Object.entries(J7(n)))WR(qr(o,s),i)}}async function tD(e,t={}){let n=Hi(await Wi(e,t));if(n.length===0)throw new S("atmos describe stacks lists no Terraform instance that is neither abstract nor disabled");return K7(e,n),n.map(r=>`${r.path}: ${r.componentPath} in workspace ${r.workspace}`)}function ec(e){let t=[qr(e,YN),qr(e,HR)].find(n=>tg(n));if(t)try{let n=JSON.parse(KN(t,"utf-8")),r=Array.isArray(n.dependencies)?n.dependencies.filter(s=>typeof s=="string"):[],o=(Array.isArray(n.reads)?n.reads:[]).filter(s=>!!s&&typeof s=="object"&&typeof s.var=="string"&&typeof s.upstream=="string"&&Array.isArray(s.output));return{...typeof n.component=="string"?{component:n.component}:{},dependencies:r,reads:o}}catch{return}}function nD(e,t){let n=new Map;for(let r of t){let o=ec(qr(e,r))?.reads??[];o.length>0&&n.set(r,new Set(o.map(s=>s.upstream)))}return n}function ng(e,t){let n=new Map;for(let r of t){let o=ec(qr(e,r))?.dependencies??[];o.length>0&&n.set(r,new Set(o))}return n}async function $w(e,t,n,r=o=>o()){let o=(u,l)=>new Promise(d=>{let p=C7(e,[`-chdir=${t}`,...u],{env:Ve(l),stdio:["ignore","pipe","pipe"]}),f=[],g=[];p.stdout.on("data",m=>f.push(m)),p.stderr.on("data",m=>g.push(m)),p.on("error",m=>g.push(Buffer.from(m.message))),p.on("close",m=>d({code:m,out:Buffer.concat(f).toString("utf-8"),err:Buffer.concat(g).toString("utf-8")}))}),s=u=>u.trim().split(`
66
+ `,[YN]:t({component:e.componentPath,dependencies:e.dependencies,reads:e.reads})};return e.backendType==="cloud"?o["backend.tf.json"]=t({terraform:{cloud:e.backend}}):e.backendType&&(o["backend.tf.json"]=t({terraform:{backend:{[e.backendType]:e.backend}}})),Object.keys(e.providers).length>0&&(o["providers_override.tf.json"]=t({provider:e.providers})),o}function KX(e,t){for(let n of t){let r=qr(e,n.componentPath);if(!tg(r)||!VN(r).isDirectory())throw new S(`${n.path} runs ${n.componentPath}, which the repo does not have`);let o=qr(e,n.path);if(tg(o)){if(!tg(qr(o,ow))&&BR(o).length>0)throw new S(`${n.path} is a directory of the repo, and the Atmos instance ${n.component} in stack ${n.stack} is written there; rename one of them`);for(let s of BR(o))s!==".terraform"&&MX(qr(o,s),{recursive:!0,force:!0})}eD(r,o,ZN(r));for(let[s,i]of Object.entries(JX(n)))WR(qr(o,s),i)}}async function tD(e,t={}){let n=Hi(await Wi(e,t));if(n.length===0)throw new S("atmos describe stacks lists no Terraform instance that is neither abstract nor disabled");return KX(e,n),n.map(r=>`${r.path}: ${r.componentPath} in workspace ${r.workspace}`)}function ec(e){let t=[qr(e,YN),qr(e,HR)].find(n=>tg(n));if(t)try{let n=JSON.parse(KN(t,"utf-8")),r=Array.isArray(n.dependencies)?n.dependencies.filter(s=>typeof s=="string"):[],o=(Array.isArray(n.reads)?n.reads:[]).filter(s=>!!s&&typeof s=="object"&&typeof s.var=="string"&&typeof s.upstream=="string"&&Array.isArray(s.output));return{...typeof n.component=="string"?{component:n.component}:{},dependencies:r,reads:o}}catch{return}}function nD(e,t){let n=new Map;for(let r of t){let o=ec(qr(e,r))?.reads??[];o.length>0&&n.set(r,new Set(o.map(s=>s.upstream)))}return n}function ng(e,t){let n=new Map;for(let r of t){let o=ec(qr(e,r))?.dependencies??[];o.length>0&&n.set(r,new Set(o))}return n}async function $w(e,t,n,r=o=>o()){let o=(u,l)=>new Promise(d=>{let p=CX(e,[`-chdir=${t}`,...u],{env:Ve(l),stdio:["ignore","pipe","pipe"]}),f=[],g=[];p.stdout.on("data",m=>f.push(m)),p.stderr.on("data",m=>g.push(m)),p.on("error",m=>g.push(Buffer.from(m.message))),p.on("close",m=>d({code:m,out:Buffer.concat(f).toString("utf-8"),err:Buffer.concat(g).toString("utf-8")}))}),s=u=>u.trim().split(`
67
67
  `).slice(-6).join(`
68
- `),i=Fi(n,t),a=await r(()=>o(["init","-input=false","-no-color"],i?.init??n));if(a.code!==0)return{error:`init failed: ${s(a.err||a.out)}`};if(i){let u=await o(i.select,i.selectEnv);if(u.code!==0)return{error:`workspace select failed: ${s(u.err||u.out)}`}}let c=await o(["output","-json","-no-color"],n);if(c.code!==0)return{error:`output -json failed: ${s(c.err||c.out)}`};try{let u=yn(JSON.parse(c.out||"{}"));return{outputs:Object.fromEntries(Object.entries(u).map(([l,d])=>[l,yn(d).value]))}}catch{return{error:`output -json printed no JSON: ${s(c.out)}`}}}function V7(e,t){let[n,...r]=t;if(!(n in e))return;let o=e[n];for(let s of r){if(!o||typeof o!="object"||Array.isArray(o)||!(s in o))return;o=o[s]}return{value:o}}async function kw(e,t,n){let r=ec(qr(e,t)),o={waiting:[],errors:[],filled:[]};if(!r||r.reads.length===0)return o;let s={};for(let i of r.reads){let a=await n(i.upstream);if("error"in a){o.errors.push(`${t} reads ${i.var} from ${i.upstream}, whose state could not be read: ${a.error}`);continue}let c=V7(a.outputs,i.output);if(!c){let u=Object.keys(a.outputs).length===0?"has no state yet":`has no output ${i.output.join(".")} yet`;o.waiting.push({read:i,why:u});continue}s[i.var]=c.value}return o.waiting.length===0&&o.errors.length===0&&(WR(qr(e,t,G7),`${JSON.stringify(s,null,2)}
69
- `),o.filled=Object.keys(s).sort()),o}function rg(e){let t=new Map;for(let n of e){let r=ps(n.backend.key)??"terraform.tfstate";n.backendType==="s3"?t.set(n.path,{...ps(n.backend.bucket)?{bucket:n.backend.bucket}:{},key:`${ps(n.backend.workspace_key_prefix)??n.component}/${n.workspace}/${r}`}):t.set(n.path,n.backendType?{key:`${n.backendType}:${n.workspace}`}:void 0)}return{states:t,reads:new Map(e.map(n=>[n.path,new Set(n.reads.map(r=>r.upstream))]))}}var Y7=new Set([".git",".terraform",".terragrunt-cache","node_modules",".terragucci"]);function gs(e){try{return Ew(e).filter(t=>t.endsWith(".tf")||t.endsWith(".tofu")||fs(t)).map(t=>Pt(e,t)).filter(t=>JR(t).isFile())}catch{return[]}}var fs=e=>e.endsWith(".tf.json")||e.endsWith(".tofu.json");function X7(e){let t=[],n=r=>{t.push(r);for(let o of Ew(r)){if(Y7.has(o)||o.startsWith("."))continue;let s=Pt(r,o);JR(s).isDirectory()&&n(s)}};return n(e),t}var Ji=e=>e.split("\\").join("/");function Q7(e){let t=gs(e);for(let r of t.filter(fs)){let o=eQ(Mn(r,"utf-8"));if(o)return o}let n=t.filter(r=>!fs(r)).map(r=>Ar(Mn(r,"utf-8")));for(let r of n){let o=r.match(/\bbackend\s+"([^"]+)"\s*\{/);if(o)return`backend ${o[1]}`}if(n.some(r=>/^\s*cloud\s*\{/m.test(r)))return"cloud block";if(n.some(tQ))return"choudoufu live block";for(let r of n){let o=r.match(/^\s*provider\s+"([^"]+)"\s*\{/m);if(o)return`provider ${o[1]}`}}function eQ(e){let t;try{t=JSON.parse(e)}catch{return}let n=i=>i&&typeof i=="object"&&!Array.isArray(i)?i:void 0,r=n(t)?.terraform,o=(Array.isArray(r)?r:[r]).map(n).filter(i=>i!==void 0);for(let i of o){let a=Object.keys(n(i.backend)??{})[0];if(a)return`backend ${a}`}if(o.some(i=>i.cloud!==void 0))return"cloud block";let s=Object.keys(n(n(t)?.provider)??{})[0];return s?`provider ${s}`:void 0}function tQ(e){for(let t of e.matchAll(/^\s*terraform\s*\{/gm)){let n=1,r="";for(let o=(t.index??0)+t[0].length;o<e.length&&n>0;o++){let s=e[o];if(s==="{"){if(n===1&&/^\s*live\s*$/.test(r))return!0;n++}else s==="}"&&n--;r=s===`
70
- `?"":r+s}}return!1}function Ar(e){return e.replace(/\/\*[\s\S]*?\*\//g,"").replace(/(^|[^:"])(#|\/\/).*$/gm,"$1")}function Pe(e,t){return ql(Ji(t).replace(/\/+$/,""),e)}function wt(e,t){return KR(e,t).map(n=>n.root)}function KR(e,t){let n=[];for(let r of X7(e)){let o=Ji(xw(e,r))||".";if(t){let s=t.find(i=>Pe(i,o));s!==void 0&&gs(r).length>0&&n.push({root:o,reason:`matches roots glob ${s}`})}else{let s=Q7(r);s&&n.push({root:o,reason:s})}}return n.sort((r,o)=>r.root<o.root?-1:r.root>o.root?1:0)}function rD(e){try{return sD(process.platform==="win32"?"where":"which",[e],{stdio:"ignore"}),!0}catch{return!1}}function Ks(e,t){return Jr(Pt(e,".opentofu-version"))?{value:"tofu",reason:".opentofu-version"}:Jr(Pt(e,".terraform-version"))?{value:"terraform",reason:".terraform-version"}:t.some(n=>Jr(Pt(e,n))&&Ew(Pt(e,n)).some(r=>r.endsWith(".tofu")))?{value:"tofu",reason:".tofu files"}:rD("tofu")?{value:"tofu",reason:"tofu on the path"}:rD("terraform")?{value:"terraform",reason:"terraform on the path"}:{value:"tofu",reason:"the default"}}function iD(e,t){let n=new Set;for(let r of t)for(let o of VR(Pt(e,r)))n.add(o);return n.size===1?[...n][0]:void 0}function VR(e){let t=[];for(let n of gs(e)){let r=Ar(Mn(n,"utf-8")).match(/required_version\s*=\s*"\s*=?\s*(\d+\.\d+\.\d+)\s*"/);r&&!t.includes(r[1])&&t.push(r[1])}return t}function Kr(e){if(Jr(Pt(e,".forgejo","workflows")))return{value:"forgejo",reason:".forgejo/workflows"};if(Jr(Pt(e,".gitea","workflows")))return{value:"forgejo",reason:".gitea/workflows"};if(Jr(Pt(e,".gitlab-ci.yml")))return{value:"gitlab",reason:".gitlab-ci.yml"};let t="";try{t=sD("git",["-C",e,"remote","get-url","origin"],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim()}catch{}let n=sg(t),r=n?ir(n):void 0;if(r)return{value:r,reason:`the origin remote (${n})`};if(Jr(Pt(e,".github","workflows")))return{value:"github",reason:".github/workflows"}}function sg(e){if(!e)return;let t=e.match(/^[a-z+]+:\/\/(?:[^@/]+@)?([^/]+)/i);if(t)return t[1];let n=e.match(/^(?:[^@]+@)?([^:/]+):/);return n?n[1]:void 0}function $t(e,t){let n=0;for(let r=e.indexOf("{",t);r<e.length;r++)if(e[r]==="{")n++;else if(e[r]==="}"&&--n===0)return e.slice(t,r+1);return e.slice(t)}function og(e,t){return e.match(new RegExp(`\\b${t}\\s*=\\s*"([^"]*)"`))?.[1]}var $d=(e,t)=>n=>{let r=e.match(new RegExp(`(?<![\\w.-])${n}\\s*=(?!=)\\s*(.)`));if(!r)return;if(r[1]!=='"')return null;let o=r.index+r[0].length,s="",i=0;for(let a=o;a<e.length;a++){if(e[a]==="\\"){s+=e[++a]??"";continue}if(t&&e[a]==="$"&&e[a+1]==="{"?i++:t&&i>0&&e[a]==="}"&&i--,e[a]==='"'&&i===0)return Gi(t?t(s):s)??null;s+=e[a]}return null},nQ=(e,t)=>n=>{for(let r=t.length-1;r>=0;r--){let o=t[r](n);if(o!==void 0)return o}return e(n)};function rQ(e){let t=[...e.matchAll(/"((?:[^"\\]|\\.)*)"|'([^']*)'|(\S+)/g)].map(r=>r[1]?.replace(/\\(.)/g,"$1")??r[2]??r[3]),n=[];for(let r=0;r<t.length;r++){let o=/^--?backend-config(?:=(.*))?$/.exec(t[r]);if(!o)continue;let s=o[1]??t[++r];s!==void 0&&n.push(s.replace(/^"(.*)"$/,"$1").replace(/^'(.*)'$/,"$1"))}return n}function Tw(e){let t;try{let r=fe(e);if(!r||r.endsWith(".ts"))return[];let o=Mn(r,"utf-8"),s=r.endsWith(".json")?JSON.parse(o):o.trim()===""?{}:Yl(o);t=Mo(s)?.env}catch{return[]}let n=Mo(t)??{};return[n.TF_CLI_ARGS,n.TF_CLI_ARGS_init].flatMap(r=>typeof r=="string"?rQ(r):[])}function oQ(e){try{return Ew(e).filter(t=>t==="backend.hcl"||t==="backend.tfvars"||t.endsWith(".tfbackend")).sort()}catch{return[]}}function sQ(e,t,n){let r={layers:[],files:[],missing:[]},o=Pt(e,t);for(let s of n){let i=s.indexOf("=");if(i>=0){let u=s.slice(0,i).trim(),l=s.slice(i+1);r.layers.push(d=>d===u?Gi(l)??null:void 0);continue}let a=Z7(s)?s:Sw(o,s),c=Ji(xw(e,a))||".";if(!Jr(a)||!JR(a).isFile()){r.missing.push(c);continue}r.files.push(c),r.layers.push($d(Ar(Mn(a,"utf-8"))))}return r}var aD="terragrunt.hcl";function iQ(e,t,n){let r=/^"?\$?\{?\s*find_in_parent_folders\(\s*(?:"([^"]+)")?\s*\)\s*\}?"?$/.exec(n);if(r){let i=r[1]??aD,a=Sw(e);for(let c=_w(Sw(t));;c=_w(c)){if(Jr(Pt(c,i)))return Pt(c,i);if(c===a||_w(c)===c)return}}let o=/^"\$\{\s*get_repo_root\(\s*\)\s*\}\/([^"$]+)"$/.exec(n);if(o)return Pt(e,o[1]);let s=/^"([^"$]+)"$/.exec(n);return s?Sw(t,s[1]):void 0}function cD(e,t){let n=Pt(e,t),r=Pt(n,aD);if(!Jr(r))return;let o=Ar(Mn(r,"utf-8")),s=[];for(let a of o.matchAll(/^\s*include(?:\s+"([^"]*)")?\s*\{/gm)){let c=/(?:^|[{\s])path\s*=\s*(.+?)\s*$/m.exec($t(o,a.index).replace(/^[^{]*\{/,"").replace(/\}$/,""))?.[1],u=c?iQ(e,n,c):void 0;u&&Jr(u)&&s.push({name:a[1]??"",file:u})}let i=[{file:r,text:o,include:s[0]},...s.map(a=>({file:a.file,text:Ar(Mn(a.file,"utf-8")),include:a}))];for(let a of i){let c=/^\s*remote_state\s*=?\s*\{/m.exec(a.text);if(!c)continue;let u=Ji(xw(e,a.file)),l=$t(a.text,c.index),d=h=>{let y=h===void 0?a.include:s.find(w=>w.name===h);return y?Ji(xw(_w(y.file),n))||".":h===void 0?".":void 0},p=h=>h.replace(/\$\{\s*path_relative_to_include\(\s*(?:"([^"]*)")?\s*\)\s*\}/g,(y,w)=>d(w)??y),f=$d(l)("backend");if(f==null)return{why:`the Terragrunt remote_state block in ${u} names its backend with an expression, not a plain string`};let g=/\bconfig\s*=\s*\{/.exec(l);if(!g)return{why:`the Terragrunt remote_state block in ${u} takes its config from an expression, not an object`};let m=qi(f,$d($t(l,g.index).replace(/^[^{]*\{/,""),p),t);return m.ref?{ref:m.ref}:{why:`the Terragrunt remote_state block in ${u}: ${m.why}`}}}var Mo=e=>e&&typeof e=="object"&&!Array.isArray(e)?e:void 0,Rw=e=>Mo(Array.isArray(e)?e[0]:e),qR=e=>t=>{let n=e?.[t]??Rw(e?.workspaces)?.[t];return Gi(n)};function qi(e,t,n){if(e===null)return{why:"its backend is an expression, not a plain string"};let r=gd(e??"local",t,n);return"unresolved"in r?{why:r.unresolved}:{ref:r}}function aQ(e,t,n=(r,o)=>qi(r,o,t)){let r,o={reads:[],unresolved:[],declared:!1};try{r=JSON.parse(e)}catch{return o}let s=Mo(r);for(let i of Array.isArray(s?.terraform)?s.terraform:[s?.terraform]){let a=Object.entries(Mo(Mo(i)?.backend)??{});Mo(i)?.cloud!==void 0&&a.push(["cloud",Mo(i).cloud]);for(let[c,u]of a){let l=c==="cloud"?qi(c,qR(Rw(u)),t):n(c,qR(Rw(u)));o.declared=!0,l.ref?(o.own=l.ref,delete o.ownUnresolved):o.ownUnresolved=l.why}}for(let i of Array.isArray(s?.data)?s.data:[s?.data]){let a=Mo(Mo(i)?.terraform_remote_state)??{};for(let[c,u]of Object.entries(a)){let l=Rw(u),d=Mo(l?.config),p=d===void 0&&l?.config!==void 0?{why:"its config is an expression, not an object"}:qi(Gi(l?.backend),qR(d),t);p.ref?o.reads.push({name:c,...p.ref,repeated:l?.count!==void 0||l?.for_each!==void 0}):o.unresolved.push({name:c,why:p.why})}}return o}function Lo(e,t,n=Tw(e)){let r={reads:[],unresolved:[]},o=!1,s=u=>{o=!0,u.ref?(r.own=u.ref,delete r.ownUnresolved):r.ownUnresolved=u.why},i=n.length?sQ(e,t,n):void 0,a=(u,l)=>{let d=qi(u,i?nQ(l,i.layers):l,t);if(d.ref)return d;let p=(y,w,b)=>y.length===1?w:b,f=i?.files??[],g=i?.missing??[],m=oQ(Pt(e,t)).map(y=>Ji(t==="."?y:`${t}/${y}`)).filter(y=>!f.includes(y)),h=[...f.length?[`the -backend-config ${p(f,"file","files")} ${f.join(", ")} from terragucci.yml's env ${p(f,"does","do")} not supply it either`]:[],...g.length?[`terragucci.yml's env names -backend-config ${g.join(", ")}, which ${p(g,"is","are")} not in the repo`]:[],...m.length?[`${m.join(", ")} ${p(m,"is","are")} beside it, but no -backend-config in terragucci.yml's env names ${p(m,"it","them")}`]:[]];return h.length?{why:`${d.why}; ${h.join("; ")}`}:d};for(let u of gs(Pt(e,t))){if(fs(u)){let d=aQ(Mn(u,"utf-8"),t,a);d.declared&&s(d.own?{ref:d.own}:{why:d.ownUnresolved}),r.reads.push(...d.reads),r.unresolved.push(...d.unresolved);continue}let l=Ar(Mn(u,"utf-8"));for(let d of l.matchAll(/\bbackend\s+"([^"]+)"\s*\{/g))s(a(d[1],$d($t(l,d.index))));for(let d of l.matchAll(/^\s*cloud\s*\{/gm))s(qi("cloud",$d($t(l,d.index)),t));for(let d of l.matchAll(/\bdata\s+"terraform_remote_state"\s+"([^"]+)"\s*\{/g)){let p=$t(l,d.index),f=$d(p),g=qi(f("backend"),f,t);g.ref?r.reads.push({name:d[1],...g.ref,repeated:/^\s*(count|for_each)\s*=/m.test(p)}):r.unresolved.push({name:d[1],why:g.why})}}o||s(qi("local",()=>{},t));let c=cD(e,t);return c?.ref?s(c):c?.why&&(delete r.own,r.ownUnresolved=c.why),r}function ig(e,t){let n=Tw(e),r=new Map(t.map(s=>[s,Lo(e,s,n)])),o=new Map(t.map(s=>[s,[]]));for(let[s,{reads:i}]of r)for(let a of i)for(let[c,{own:u}]of r)c===s||!u||u.key===a.key&&(!u.bucket||!a.bucket||u.bucket===a.bucket)&&o.get(s).push({name:a.name,upstream:c,repeated:a.repeated});return o}function ZR(e,t){let n=Tw(e),r=t.map(s=>[s,Lo(e,s,n)]),o=r.some(([,s])=>s.reads.length>0||s.unresolved.length>0);return r.map(([s,i])=>({root:s,...o&&i.ownUnresolved?{own:i.ownUnresolved}:{},reads:i.unresolved})).filter(s=>s.own!==void 0||s.reads.length>0)}function uD(e,t){return ZR(e,t).flatMap(n=>[...n.own?[`state: ${n.root} keeps its state where the code does not say (${n.own}), so a root that reads it through terraform_remote_state is not ordered after it`]:[],...n.reads.map(r=>`state: ${n.root} reads state through terraform_remote_state "${r.name}" where the code does not say (${r.why}), so it is not ordered after the root that writes it`)])}var oD=e=>`tofu-records/${e}`;function cQ(e,t,n){let r=Pt(e,t),{estate:o}=Go(r),s=[...n.reads];for(let c of gs(r)){if(fs(c))continue;let u=Ar(Mn(c,"utf-8"));for(let l of u.matchAll(/\bdata\s+"terraform_estate_outputs"\s+"([^"]+)"\s*\{/g)){let d=og($t(u,l.index),"estate");d&&s.push({name:l[1],key:oD(d),repeated:!1})}}let i=qi("local",()=>{},t).ref;return{own:o&&(!n.own||i&&pD(n.own,i))?{key:oD(o)}:n.own,reads:s}}function Aw(e,t){let n=Tw(e),r=new Map(t.map(i=>[i,cQ(e,i,Lo(e,i,n))])),o=[...r.values()].flatMap(i=>i.own?[i.own]:[]),s=new Map;for(let[i,{own:a,reads:c}]of r){let u=c.filter(l=>!o.some(d=>d!==a&&pD(d,l))).map(l=>({data:l.name,...l.bucket!==void 0?{bucket:l.bucket}:{},key:l.key}));s.set(i,{...a?{state:lD(a)}:{},external:u})}return s}var lD=e=>({...e.bucket!==void 0?{bucket:e.bucket}:{},key:e.key});function dD(e,t){return new Map(t.map(n=>{let r=cD(e,n)?.ref;return[n,{...r?{state:lD(r)}:{},external:[]}]}))}function Ow(e){for(let t of gs(e)){let n=Mn(t,"utf-8");if(fs(t)){let s;try{s=JSON.parse(n)}catch{continue}let i=s?.terraform;for(let a of Array.isArray(i)?i:[i]){if(!a||typeof a!="object")continue;if(a.cloud!==void 0)return{cloud:!0};let c=a.backend&&typeof a.backend=="object"?a.backend:{},u=Object.keys(c)[0];if(!u)continue;let l=Array.isArray(c[u])?c[u][0]:c[u],d=Object.fromEntries(Object.entries(l??{}).filter(([,p])=>typeof p=="string"));return{type:u,attrs:d}}continue}let r=Ar(n),o=r.match(/\bbackend\s+"([^"]+)"\s*\{/);if(o){let s=$t(r,o.index),i={};for(let a of s.matchAll(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*"([^"]*)"/gm))i[a[1]]=a[2];return{type:o[1],attrs:i}}if(/^\s*cloud\s*\{/m.test(r))return{cloud:!0}}}var pD=(e,t)=>e.key===t.key&&(!e.bucket||!t.bucket||e.bucket===t.bucket);function Go(e){let t,n=[],r=Pt(e,"estate.chdf.hcl");Jr(r)&&(t=og(Ar(Mn(r,"utf-8")),"estate"));for(let o of gs(e)){if(fs(o))continue;let s=Ar(Mn(o,"utf-8"));for(let i of s.matchAll(/^\s*terraform\s*\{/gm)){let a=$t(s,i.index),c=a.match(/\blive\s*\{/);c&&!t&&(t=og($t(a,c.index),"estate"))}for(let i of s.matchAll(/\bdata\s+"terraform_estate_outputs"\s+"[^"]+"\s*\{/g)){let a=og($t(s,i.index),"estate");a&&n.push(a)}}return{estate:t,reads:n}}function fD(e){let t=Pt(e,"estate.chdf.hcl");if(Jr(t))return Ar(Mn(t,"utf-8"));for(let n of gs(e)){if(fs(n))continue;let r=Ar(Mn(n,"utf-8"));for(let o of r.matchAll(/^\s*terraform\s*\{/gm)){let s=$t(r,o.index),i=s.match(/\blive\s*\{/);if(i)return $t(s,i.index)}}}function Pw(e){let t=[];for(let n of gs(e)){if(fs(n))continue;let r=Ar(Mn(n,"utf-8"));for(let o of r.matchAll(/\bdata\s+"terraform_estate_outputs"\s+"([^"]+)"\s*\{/g)){let s=og($t(r,o.index),"estate");s&&t.push({name:o[1],estate:s})}}return t}function gD(e){let t=new Map;for(let n of gs(e)){let r=Mn(n,"utf-8");if(fs(n)){try{let s=JSON.parse(r);for(let i of Array.isArray(s.locals)?s.locals:[s.locals])for(let[a,c]of Object.entries(Mo(i)??{}))t.set(a,JSON.stringify(c))}catch{}continue}let o=Ar(r);for(let s of o.matchAll(/^\s*locals\s*\{/gm)){let i=$t(o,s.index),a=i.slice(i.indexOf("{")+1,-1),c=0,u,l=[];for(let d of a.split(`
68
+ `),i=Fi(n,t),a=await r(()=>o(["init","-input=false","-no-color"],i?.init??n));if(a.code!==0)return{error:`init failed: ${s(a.err||a.out)}`};if(i){let u=await o(i.select,i.selectEnv);if(u.code!==0)return{error:`workspace select failed: ${s(u.err||u.out)}`}}let c=await o(["output","-json","-no-color"],n);if(c.code!==0)return{error:`output -json failed: ${s(c.err||c.out)}`};try{let u=yn(JSON.parse(c.out||"{}"));return{outputs:Object.fromEntries(Object.entries(u).map(([l,d])=>[l,yn(d).value]))}}catch{return{error:`output -json printed no JSON: ${s(c.out)}`}}}function VX(e,t){let[n,...r]=t;if(!(n in e))return;let o=e[n];for(let s of r){if(!o||typeof o!="object"||Array.isArray(o)||!(s in o))return;o=o[s]}return{value:o}}async function kw(e,t,n){let r=ec(qr(e,t)),o={waiting:[],errors:[],filled:[]};if(!r||r.reads.length===0)return o;let s={};for(let i of r.reads){let a=await n(i.upstream);if("error"in a){o.errors.push(`${t} reads ${i.var} from ${i.upstream}, whose state could not be read: ${a.error}`);continue}let c=VX(a.outputs,i.output);if(!c){let u=Object.keys(a.outputs).length===0?"has no state yet":`has no output ${i.output.join(".")} yet`;o.waiting.push({read:i,why:u});continue}s[i.var]=c.value}return o.waiting.length===0&&o.errors.length===0&&(WR(qr(e,t,GX),`${JSON.stringify(s,null,2)}
69
+ `),o.filled=Object.keys(s).sort()),o}function rg(e){let t=new Map;for(let n of e){let r=ps(n.backend.key)??"terraform.tfstate";n.backendType==="s3"?t.set(n.path,{...ps(n.backend.bucket)?{bucket:n.backend.bucket}:{},key:`${ps(n.backend.workspace_key_prefix)??n.component}/${n.workspace}/${r}`}):t.set(n.path,n.backendType?{key:`${n.backendType}:${n.workspace}`}:void 0)}return{states:t,reads:new Map(e.map(n=>[n.path,new Set(n.reads.map(r=>r.upstream))]))}}var YX=new Set([".git",".terraform",".terragrunt-cache","node_modules",".terragucci"]);function gs(e){try{return Ew(e).filter(t=>t.endsWith(".tf")||t.endsWith(".tofu")||fs(t)).map(t=>Pt(e,t)).filter(t=>JR(t).isFile())}catch{return[]}}var fs=e=>e.endsWith(".tf.json")||e.endsWith(".tofu.json");function XX(e){let t=[],n=r=>{t.push(r);for(let o of Ew(r)){if(YX.has(o)||o.startsWith("."))continue;let s=Pt(r,o);JR(s).isDirectory()&&n(s)}};return n(e),t}var Ji=e=>e.split("\\").join("/");function QX(e){let t=gs(e);for(let r of t.filter(fs)){let o=eQ(Mn(r,"utf-8"));if(o)return o}let n=t.filter(r=>!fs(r)).map(r=>Ar(Mn(r,"utf-8")));for(let r of n){let o=r.match(/\bbackend\s+"([^"]+)"\s*\{/);if(o)return`backend ${o[1]}`}if(n.some(r=>/^\s*cloud\s*\{/m.test(r)))return"cloud block";if(n.some(tQ))return"choudoufu live block";for(let r of n){let o=r.match(/^\s*provider\s+"([^"]+)"\s*\{/m);if(o)return`provider ${o[1]}`}}function eQ(e){let t;try{t=JSON.parse(e)}catch{return}let n=i=>i&&typeof i=="object"&&!Array.isArray(i)?i:void 0,r=n(t)?.terraform,o=(Array.isArray(r)?r:[r]).map(n).filter(i=>i!==void 0);for(let i of o){let a=Object.keys(n(i.backend)??{})[0];if(a)return`backend ${a}`}if(o.some(i=>i.cloud!==void 0))return"cloud block";let s=Object.keys(n(n(t)?.provider)??{})[0];return s?`provider ${s}`:void 0}function tQ(e){for(let t of e.matchAll(/^\s*terraform\s*\{/gm)){let n=1,r="";for(let o=(t.index??0)+t[0].length;o<e.length&&n>0;o++){let s=e[o];if(s==="{"){if(n===1&&/^\s*live\s*$/.test(r))return!0;n++}else s==="}"&&n--;r=s===`
70
+ `?"":r+s}}return!1}function Ar(e){return e.replace(/\/\*[\s\S]*?\*\//g,"").replace(/(^|[^:"])(#|\/\/).*$/gm,"$1")}function Pe(e,t){return ql(Ji(t).replace(/\/+$/,""),e)}function wt(e,t){return KR(e,t).map(n=>n.root)}function KR(e,t){let n=[];for(let r of XX(e)){let o=Ji(xw(e,r))||".";if(t){let s=t.find(i=>Pe(i,o));s!==void 0&&gs(r).length>0&&n.push({root:o,reason:`matches roots glob ${s}`})}else{let s=QX(r);s&&n.push({root:o,reason:s})}}return n.sort((r,o)=>r.root<o.root?-1:r.root>o.root?1:0)}function rD(e){try{return sD(process.platform==="win32"?"where":"which",[e],{stdio:"ignore"}),!0}catch{return!1}}function Ks(e,t){return Jr(Pt(e,".opentofu-version"))?{value:"tofu",reason:".opentofu-version"}:Jr(Pt(e,".terraform-version"))?{value:"terraform",reason:".terraform-version"}:t.some(n=>Jr(Pt(e,n))&&Ew(Pt(e,n)).some(r=>r.endsWith(".tofu")))?{value:"tofu",reason:".tofu files"}:rD("tofu")?{value:"tofu",reason:"tofu on the path"}:rD("terraform")?{value:"terraform",reason:"terraform on the path"}:{value:"tofu",reason:"the default"}}function iD(e,t){let n=new Set;for(let r of t)for(let o of VR(Pt(e,r)))n.add(o);return n.size===1?[...n][0]:void 0}function VR(e){let t=[];for(let n of gs(e)){let r=Ar(Mn(n,"utf-8")).match(/required_version\s*=\s*"\s*=?\s*(\d+\.\d+\.\d+)\s*"/);r&&!t.includes(r[1])&&t.push(r[1])}return t}function Kr(e){if(Jr(Pt(e,".forgejo","workflows")))return{value:"forgejo",reason:".forgejo/workflows"};if(Jr(Pt(e,".gitea","workflows")))return{value:"forgejo",reason:".gitea/workflows"};if(Jr(Pt(e,".gitlab-ci.yml")))return{value:"gitlab",reason:".gitlab-ci.yml"};let t="";try{t=sD("git",["-C",e,"remote","get-url","origin"],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim()}catch{}let n=sg(t),r=n?ir(n):void 0;if(r)return{value:r,reason:`the origin remote (${n})`};if(Jr(Pt(e,".github","workflows")))return{value:"github",reason:".github/workflows"}}function sg(e){if(!e)return;let t=e.match(/^[a-z+]+:\/\/(?:[^@/]+@)?([^/]+)/i);if(t)return t[1];let n=e.match(/^(?:[^@]+@)?([^:/]+):/);return n?n[1]:void 0}function $t(e,t){let n=0;for(let r=e.indexOf("{",t);r<e.length;r++)if(e[r]==="{")n++;else if(e[r]==="}"&&--n===0)return e.slice(t,r+1);return e.slice(t)}function og(e,t){return e.match(new RegExp(`\\b${t}\\s*=\\s*"([^"]*)"`))?.[1]}var $d=(e,t)=>n=>{let r=e.match(new RegExp(`(?<![\\w.-])${n}\\s*=(?!=)\\s*(.)`));if(!r)return;if(r[1]!=='"')return null;let o=r.index+r[0].length,s="",i=0;for(let a=o;a<e.length;a++){if(e[a]==="\\"){s+=e[++a]??"";continue}if(t&&e[a]==="$"&&e[a+1]==="{"?i++:t&&i>0&&e[a]==="}"&&i--,e[a]==='"'&&i===0)return Gi(t?t(s):s)??null;s+=e[a]}return null},nQ=(e,t)=>n=>{for(let r=t.length-1;r>=0;r--){let o=t[r](n);if(o!==void 0)return o}return e(n)};function rQ(e){let t=[...e.matchAll(/"((?:[^"\\]|\\.)*)"|'([^']*)'|(\S+)/g)].map(r=>r[1]?.replace(/\\(.)/g,"$1")??r[2]??r[3]),n=[];for(let r=0;r<t.length;r++){let o=/^--?backend-config(?:=(.*))?$/.exec(t[r]);if(!o)continue;let s=o[1]??t[++r];s!==void 0&&n.push(s.replace(/^"(.*)"$/,"$1").replace(/^'(.*)'$/,"$1"))}return n}function Tw(e){let t;try{let r=fe(e);if(!r||r.endsWith(".ts"))return[];let o=Mn(r,"utf-8"),s=r.endsWith(".json")?JSON.parse(o):o.trim()===""?{}:Yl(o);t=Mo(s)?.env}catch{return[]}let n=Mo(t)??{};return[n.TF_CLI_ARGS,n.TF_CLI_ARGS_init].flatMap(r=>typeof r=="string"?rQ(r):[])}function oQ(e){try{return Ew(e).filter(t=>t==="backend.hcl"||t==="backend.tfvars"||t.endsWith(".tfbackend")).sort()}catch{return[]}}function sQ(e,t,n){let r={layers:[],files:[],missing:[]},o=Pt(e,t);for(let s of n){let i=s.indexOf("=");if(i>=0){let u=s.slice(0,i).trim(),l=s.slice(i+1);r.layers.push(d=>d===u?Gi(l)??null:void 0);continue}let a=ZX(s)?s:Sw(o,s),c=Ji(xw(e,a))||".";if(!Jr(a)||!JR(a).isFile()){r.missing.push(c);continue}r.files.push(c),r.layers.push($d(Ar(Mn(a,"utf-8"))))}return r}var aD="terragrunt.hcl";function iQ(e,t,n){let r=/^"?\$?\{?\s*find_in_parent_folders\(\s*(?:"([^"]+)")?\s*\)\s*\}?"?$/.exec(n);if(r){let i=r[1]??aD,a=Sw(e);for(let c=_w(Sw(t));;c=_w(c)){if(Jr(Pt(c,i)))return Pt(c,i);if(c===a||_w(c)===c)return}}let o=/^"\$\{\s*get_repo_root\(\s*\)\s*\}\/([^"$]+)"$/.exec(n);if(o)return Pt(e,o[1]);let s=/^"([^"$]+)"$/.exec(n);return s?Sw(t,s[1]):void 0}function cD(e,t){let n=Pt(e,t),r=Pt(n,aD);if(!Jr(r))return;let o=Ar(Mn(r,"utf-8")),s=[];for(let a of o.matchAll(/^\s*include(?:\s+"([^"]*)")?\s*\{/gm)){let c=/(?:^|[{\s])path\s*=\s*(.+?)\s*$/m.exec($t(o,a.index).replace(/^[^{]*\{/,"").replace(/\}$/,""))?.[1],u=c?iQ(e,n,c):void 0;u&&Jr(u)&&s.push({name:a[1]??"",file:u})}let i=[{file:r,text:o,include:s[0]},...s.map(a=>({file:a.file,text:Ar(Mn(a.file,"utf-8")),include:a}))];for(let a of i){let c=/^\s*remote_state\s*=?\s*\{/m.exec(a.text);if(!c)continue;let u=Ji(xw(e,a.file)),l=$t(a.text,c.index),d=h=>{let y=h===void 0?a.include:s.find(w=>w.name===h);return y?Ji(xw(_w(y.file),n))||".":h===void 0?".":void 0},p=h=>h.replace(/\$\{\s*path_relative_to_include\(\s*(?:"([^"]*)")?\s*\)\s*\}/g,(y,w)=>d(w)??y),f=$d(l)("backend");if(f==null)return{why:`the Terragrunt remote_state block in ${u} names its backend with an expression, not a plain string`};let g=/\bconfig\s*=\s*\{/.exec(l);if(!g)return{why:`the Terragrunt remote_state block in ${u} takes its config from an expression, not an object`};let m=qi(f,$d($t(l,g.index).replace(/^[^{]*\{/,""),p),t);return m.ref?{ref:m.ref}:{why:`the Terragrunt remote_state block in ${u}: ${m.why}`}}}var Mo=e=>e&&typeof e=="object"&&!Array.isArray(e)?e:void 0,Rw=e=>Mo(Array.isArray(e)?e[0]:e),qR=e=>t=>{let n=e?.[t]??Rw(e?.workspaces)?.[t];return Gi(n)};function qi(e,t,n){if(e===null)return{why:"its backend is an expression, not a plain string"};let r=gd(e??"local",t,n);return"unresolved"in r?{why:r.unresolved}:{ref:r}}function aQ(e,t,n=(r,o)=>qi(r,o,t)){let r,o={reads:[],unresolved:[],declared:!1};try{r=JSON.parse(e)}catch{return o}let s=Mo(r);for(let i of Array.isArray(s?.terraform)?s.terraform:[s?.terraform]){let a=Object.entries(Mo(Mo(i)?.backend)??{});Mo(i)?.cloud!==void 0&&a.push(["cloud",Mo(i).cloud]);for(let[c,u]of a){let l=c==="cloud"?qi(c,qR(Rw(u)),t):n(c,qR(Rw(u)));o.declared=!0,l.ref?(o.own=l.ref,delete o.ownUnresolved):o.ownUnresolved=l.why}}for(let i of Array.isArray(s?.data)?s.data:[s?.data]){let a=Mo(Mo(i)?.terraform_remote_state)??{};for(let[c,u]of Object.entries(a)){let l=Rw(u),d=Mo(l?.config),p=d===void 0&&l?.config!==void 0?{why:"its config is an expression, not an object"}:qi(Gi(l?.backend),qR(d),t);p.ref?o.reads.push({name:c,...p.ref,repeated:l?.count!==void 0||l?.for_each!==void 0}):o.unresolved.push({name:c,why:p.why})}}return o}function Lo(e,t,n=Tw(e)){let r={reads:[],unresolved:[]},o=!1,s=u=>{o=!0,u.ref?(r.own=u.ref,delete r.ownUnresolved):r.ownUnresolved=u.why},i=n.length?sQ(e,t,n):void 0,a=(u,l)=>{let d=qi(u,i?nQ(l,i.layers):l,t);if(d.ref)return d;let p=(y,w,b)=>y.length===1?w:b,f=i?.files??[],g=i?.missing??[],m=oQ(Pt(e,t)).map(y=>Ji(t==="."?y:`${t}/${y}`)).filter(y=>!f.includes(y)),h=[...f.length?[`the -backend-config ${p(f,"file","files")} ${f.join(", ")} from terragucci.yml's env ${p(f,"does","do")} not supply it either`]:[],...g.length?[`terragucci.yml's env names -backend-config ${g.join(", ")}, which ${p(g,"is","are")} not in the repo`]:[],...m.length?[`${m.join(", ")} ${p(m,"is","are")} beside it, but no -backend-config in terragucci.yml's env names ${p(m,"it","them")}`]:[]];return h.length?{why:`${d.why}; ${h.join("; ")}`}:d};for(let u of gs(Pt(e,t))){if(fs(u)){let d=aQ(Mn(u,"utf-8"),t,a);d.declared&&s(d.own?{ref:d.own}:{why:d.ownUnresolved}),r.reads.push(...d.reads),r.unresolved.push(...d.unresolved);continue}let l=Ar(Mn(u,"utf-8"));for(let d of l.matchAll(/\bbackend\s+"([^"]+)"\s*\{/g))s(a(d[1],$d($t(l,d.index))));for(let d of l.matchAll(/^\s*cloud\s*\{/gm))s(qi("cloud",$d($t(l,d.index)),t));for(let d of l.matchAll(/\bdata\s+"terraform_remote_state"\s+"([^"]+)"\s*\{/g)){let p=$t(l,d.index),f=$d(p),g=qi(f("backend"),f,t);g.ref?r.reads.push({name:d[1],...g.ref,repeated:/^\s*(count|for_each)\s*=/m.test(p)}):r.unresolved.push({name:d[1],why:g.why})}}o||s(qi("local",()=>{},t));let c=cD(e,t);return c?.ref?s(c):c?.why&&(delete r.own,r.ownUnresolved=c.why),r}function ig(e,t){let n=Tw(e),r=new Map(t.map(s=>[s,Lo(e,s,n)])),o=new Map(t.map(s=>[s,[]]));for(let[s,{reads:i}]of r)for(let a of i)for(let[c,{own:u}]of r)c===s||!u||u.key===a.key&&(!u.bucket||!a.bucket||u.bucket===a.bucket)&&o.get(s).push({name:a.name,upstream:c,repeated:a.repeated});return o}function ZR(e,t){let n=Tw(e),r=t.map(s=>[s,Lo(e,s,n)]),o=r.some(([,s])=>s.reads.length>0||s.unresolved.length>0);return r.map(([s,i])=>({root:s,...o&&i.ownUnresolved?{own:i.ownUnresolved}:{},reads:i.unresolved})).filter(s=>s.own!==void 0||s.reads.length>0)}function uD(e,t){return ZR(e,t).flatMap(n=>[...n.own?[`state: ${n.root} keeps its state where the code does not say (${n.own}), so a root that reads it through terraform_remote_state is not ordered after it`]:[],...n.reads.map(r=>`state: ${n.root} reads state through terraform_remote_state "${r.name}" where the code does not say (${r.why}), so it is not ordered after the root that writes it`)])}var oD=e=>`tofu-records/${e}`;function cQ(e,t,n){let r=Pt(e,t),{estate:o}=Go(r),s=[...n.reads];for(let c of gs(r)){if(fs(c))continue;let u=Ar(Mn(c,"utf-8"));for(let l of u.matchAll(/\bdata\s+"terraform_estate_outputs"\s+"([^"]+)"\s*\{/g)){let d=og($t(u,l.index),"estate");d&&s.push({name:l[1],key:oD(d),repeated:!1})}}let i=qi("local",()=>{},t).ref;return{own:o&&(!n.own||i&&pD(n.own,i))?{key:oD(o)}:n.own,reads:s}}function Aw(e,t){let n=Tw(e),r=new Map(t.map(i=>[i,cQ(e,i,Lo(e,i,n))])),o=[...r.values()].flatMap(i=>i.own?[i.own]:[]),s=new Map;for(let[i,{own:a,reads:c}]of r){let u=c.filter(l=>!o.some(d=>d!==a&&pD(d,l))).map(l=>({data:l.name,...l.bucket!==void 0?{bucket:l.bucket}:{},key:l.key}));s.set(i,{...a?{state:lD(a)}:{},external:u})}return s}var lD=e=>({...e.bucket!==void 0?{bucket:e.bucket}:{},key:e.key});function dD(e,t){return new Map(t.map(n=>{let r=cD(e,n)?.ref;return[n,{...r?{state:lD(r)}:{},external:[]}]}))}function Ow(e){for(let t of gs(e)){let n=Mn(t,"utf-8");if(fs(t)){let s;try{s=JSON.parse(n)}catch{continue}let i=s?.terraform;for(let a of Array.isArray(i)?i:[i]){if(!a||typeof a!="object")continue;if(a.cloud!==void 0)return{cloud:!0};let c=a.backend&&typeof a.backend=="object"?a.backend:{},u=Object.keys(c)[0];if(!u)continue;let l=Array.isArray(c[u])?c[u][0]:c[u],d=Object.fromEntries(Object.entries(l??{}).filter(([,p])=>typeof p=="string"));return{type:u,attrs:d}}continue}let r=Ar(n),o=r.match(/\bbackend\s+"([^"]+)"\s*\{/);if(o){let s=$t(r,o.index),i={};for(let a of s.matchAll(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*"([^"]*)"/gm))i[a[1]]=a[2];return{type:o[1],attrs:i}}if(/^\s*cloud\s*\{/m.test(r))return{cloud:!0}}}var pD=(e,t)=>e.key===t.key&&(!e.bucket||!t.bucket||e.bucket===t.bucket);function Go(e){let t,n=[],r=Pt(e,"estate.chdf.hcl");Jr(r)&&(t=og(Ar(Mn(r,"utf-8")),"estate"));for(let o of gs(e)){if(fs(o))continue;let s=Ar(Mn(o,"utf-8"));for(let i of s.matchAll(/^\s*terraform\s*\{/gm)){let a=$t(s,i.index),c=a.match(/\blive\s*\{/);c&&!t&&(t=og($t(a,c.index),"estate"))}for(let i of s.matchAll(/\bdata\s+"terraform_estate_outputs"\s+"[^"]+"\s*\{/g)){let a=og($t(s,i.index),"estate");a&&n.push(a)}}return{estate:t,reads:n}}function fD(e){let t=Pt(e,"estate.chdf.hcl");if(Jr(t))return Ar(Mn(t,"utf-8"));for(let n of gs(e)){if(fs(n))continue;let r=Ar(Mn(n,"utf-8"));for(let o of r.matchAll(/^\s*terraform\s*\{/gm)){let s=$t(r,o.index),i=s.match(/\blive\s*\{/);if(i)return $t(s,i.index)}}}function Pw(e){let t=[];for(let n of gs(e)){if(fs(n))continue;let r=Ar(Mn(n,"utf-8"));for(let o of r.matchAll(/\bdata\s+"terraform_estate_outputs"\s+"([^"]+)"\s*\{/g)){let s=og($t(r,o.index),"estate");s&&t.push({name:o[1],estate:s})}}return t}function gD(e){let t=new Map;for(let n of gs(e)){let r=Mn(n,"utf-8");if(fs(n)){try{let s=JSON.parse(r);for(let i of Array.isArray(s.locals)?s.locals:[s.locals])for(let[a,c]of Object.entries(Mo(i)??{}))t.set(a,JSON.stringify(c))}catch{}continue}let o=Ar(r);for(let s of o.matchAll(/^\s*locals\s*\{/gm)){let i=$t(o,s.index),a=i.slice(i.indexOf("{")+1,-1),c=0,u,l=[];for(let d of a.split(`
71
71
  `)){let p=c===0?/^\s*([A-Za-z_][\w-]*)\s*=(?!=)/.exec(d):null;p?(u&&t.set(u,l.join(`
72
72
  `)),u=p[1],l=[d.slice(p[0].length)]):l.push(d);for(let f of d.replace(/"(?:[^"\\]|\\.)*"/g,'""'))f==="{"||f==="["||f==="("?c++:(f==="}"||f==="]"||f===")")&&c--}u&&t.set(u,l.join(`
73
73
  `))}}return t}function ms(e,t){return t.filter(n=>{let r=Pt(e,n);return Jr(Pt(r,"estate.chdf.hcl"))?!0:gs(r).some(o=>{if(fs(o))return!1;let s=Ar(Mn(o,"utf-8"));return[...s.matchAll(/^\s*terraform\s*\{/gm)].some(i=>/\blive\s*\{/.test($t(s,i.index)))})})}function wn(e,t,{estates:n=!0}={}){let r=ig(e,t),o=nD(e,t),s=new Map(t.map(a=>[a,n?Go(Pt(e,a)):{reads:[]}])),i=new Map;for(let[a,c]of s)"estate"in c&&c.estate&&i.set(c.estate,a);return new Map(t.map(a=>{let c=new Set([...r.get(a).map(u=>u.upstream),...o.get(a)??[]]);for(let u of s.get(a).reads){let l=i.get(u);l&&l!==a&&c.add(l)}return[a,c]}))}function Fo(e,t){let n=new Map;if(!e)return n;let r=i=>t.filter(a=>a===Ji(i).replace(/\/+$/,"")||Pe(i,a)),o=[],s=[];for(let[i,a]of Object.entries(e)){let c=r(i);c.length===0&&o.push(i);for(let u of a){let l=r(u);if(l.length===0){o.includes(u)||o.push(u);continue}for(let d of c)for(let p of l){if(p===d){Ji(i)===d&&Ji(u)===d&&!s.includes(d)&&s.push(d);continue}n.has(d)||n.set(d,new Set),n.get(d).add(p)}}}if(o.length)throw new S(`waves.after names ${o.map(i=>JSON.stringify(i)).join(", ")}, which ${o.length===1?"matches":"match"} no root; the roots are ${[...t].sort().join(", ")}`);if(s.length)throw new S(`waves.after puts ${s.join(", ")} after ${s.length===1?"itself":"themselves"}`);return n}function Vs(e,t,n){let r=wn(e,t);for(let[o,s]of Fo(n,t))for(let i of s)r.get(o).add(i);return r}function tc(e,t,n){let r=Fo(n,t),o=Vs(e,t,n),s=[],i=new Set;for(;i.size<t.length;){let a=t.filter(c=>!i.has(c)&&[...o.get(c)].every(u=>i.has(u)));if(a.length===0){let c=t.filter(l=>!i.has(l)),u=uQ(o,c);throw u.some((l,d)=>r.get(l)?.has(u[(d+1)%u.length]))?new S(`waves.after puts these roots in a cycle: ${[...u,u[0]].join(" after ")}`):new Error(`these roots read each other's state in a cycle: ${c.join(", ")}`)}a.forEach(c=>i.add(c)),s.push(a)}return s}function uQ(e,t){let n=new Set(t),r=[],o=t[0];for(;!r.includes(o);)r.push(o),o=[...e.get(o)].find(s=>n.has(s));return r.slice(r.indexOf(o))}function hs(e,t){for(let[n,r]of Object.entries(t.environments??{}))if((r.roots??[]).some(o=>Pe(o,e)))return n}var hD="on-destructive";function XR(e,t){let n=hs(e,t),r={gate:lo(t.gate)??hD,...t.oidc?{oidc:t.oidc}:{},...t.runner!==void 0?{runner:t.runner}:{},...t.parallelism!==void 0?{parallelism:t.parallelism}:{}};if(n===void 0)return r;let o=t.environments[n],s=lQ(t.oidc,o);return{...r,environment:n,...o.gate!==void 0?{gate:lo(o.gate)??r.gate}:{},...s?{oidc:s}:{},...o.runner!==void 0?{runner:o.runner}:{},...o.parallelism!==void 0?{parallelism:o.parallelism}:{},forge_environment:o.forge_environment??n}}function lQ(e,t){let n=t.oidc;if(!n)return e;let r={...e??{}};return n.plan_role&&n.apply_role&&Object.assign(r,{plan_role:n.plan_role,apply_role:n.apply_role}),n.gcp&&e?.gcp&&(r.gcp={...e.gcp,...n.gcp}),n.azure&&e?.azure&&(r.azure={...e.azure,...n.azure}),r}var mD={never:0,"on-destructive":1,always:2};function yD(e,t=hD){let n;for(let r of e)(n===void 0||mD[r]>mD[n])&&(n=r);return n??t}function jw(e,t,n){return!t.environments||e.length===0?n:yD(e.map(r=>{let o=hs(r,t),s=o===void 0?void 0:t.environments[o].gate;return(s!==void 0?lo(s):void 0)??n}),n)}function Iw(e,t){let n=Object.values(e.environments??{}).map(r=>r.gate!==void 0?lo(r.gate):void 0).filter(r=>r!==void 0);return yD([t,...n],t)}function QR(e){return Object.values(e.environments??{}).map(t=>t.gate!==void 0?lo(t.gate):void 0).filter(t=>t!==void 0)}function YR(e,t,n){let r={...e??{}};for(let o of t)o in r||(r[o]=n);return r}function Zs(e,t){let n=Object.values(t??{}).filter(o=>o.oidc&&(o.oidc.plan_role||o.oidc.gcp||o.oidc.azure));if(n.length===0)return e;let r={...e??{}};for(let o of n){let s=o.oidc,i=o.roots??[];s.plan_role&&s.apply_role&&(r.roles=YR(r.roles,i,{plan:s.plan_role,apply:s.apply_role})),s.gcp&&r.gcp&&(r.gcp={...r.gcp,roles:YR(r.gcp.roles,i,{plan:s.gcp.plan_service_account,apply:s.gcp.apply_service_account})}),s.azure&&r.azure&&(r.azure={...r.azure,roles:YR(r.azure.roles,i,{plan:s.azure.plan_client_id,apply:s.azure.apply_client_id})})}return r}function wD(e,t,n="config"){let r=Object.entries(t.environments??{});if(r.length===0)return[];let o=[],s=[["oidc.roles","plan_role",t.oidc?.roles],["oidc.gcp.roles","gcp",t.oidc?.gcp?.roles],["oidc.azure.roles","azure",t.oidc?.azure?.roles]];for(let i of e){let a=r.filter(([,l])=>(l.roots??[]).some(d=>Pe(d,i))).map(([l])=>l);a.length>1&&o.push(`${n}.environments: ${i} is a root of ${a.join(" and ")}; a root belongs to one environment, so narrow their roots globs`);let c=a[0];if(c===void 0)continue;let u=t.environments[c].oidc;if(u)for(let[l,d,p]of s){if(u[d]===void 0||!p)continue;let f=Object.keys(p).find(g=>Pe(g,i));f!==void 0&&o.push(`${n}.environments.${c}.oidc: ${i} takes identities from both environments.${c}.oidc and ${l} (${f}); set them in one place`)}}return o}import{existsSync as rM,readdirSync as oM,readFileSync as sM}from"node:fs";import{join as oc,posix as eM}from"node:path";var dQ=/^v?\d+(\.\d+){0,2}(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$/,pQ=/^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[0-9a-fA-F]{32,}$/;function ag(e){let t=e.trim().replace(/^=\s*/,"");return dQ.test(t)?t:null}function bD(e){let t=e.indexOf("?");if(t<0)return{base:e,params:[]};let n=e.slice(t+1).split("&").filter(r=>r.length>0).map(r=>{let o=r.indexOf("=");return o<0?{key:r,value:void 0,raw:r}:{key:r.slice(0,o),value:fQ(r.slice(o+1)),raw:r}});return{base:e.slice(0,t),params:n}}function fQ(e){try{return decodeURIComponent(e)}catch{return e}}function ex(e,t){return t.length===0?e:`${e}?${t.join("&")}`}function gQ(e){return e.startsWith("./")||e.startsWith("../")}function mQ(e){return e.startsWith("oci://")}function hQ(e){return e.startsWith("git::")||e.startsWith("git@")||/^(github\.com|bitbucket\.org)\//.test(e)||/\.git(\/\/|\?|$)/.test(e)}function Ki(e,t){let n=yQ(e,t),r=n.at==="version"?t:n.pin;return r!=null&&/[$%]\{/.test(r)?{...n,pin:null,unpinned:`the pin "${r}" is an expression, so there is no literal version to move`}:n}function yQ(e,t){if(t!==void 0){let c=ag(t);return c?{module:e,at:"version",pin:c}:{module:e,at:"version",pin:null,unpinned:`version "${t}" is a constraint, not a pin: there is no one version to move`}}let{base:n,params:r}=bD(e),o=c=>ex(n,r.filter(u=>u.key!==c).map(u=>u.raw)),s=c=>r.find(u=>u.key===c);if(mQ(e)){let c=s("tag"),u=s("digest");if(c&&u)return{module:ex(n,r.filter(d=>d.key!=="tag"&&d.key!=="digest").map(d=>d.raw)),at:"source",pin:null,unpinned:"the oci source names both a tag and a digest"};let l=u??c;return!l||!l.value?{module:e,at:"source",pin:null,unpinned:"the oci source names no tag or digest, so it resolves whatever the registry calls latest"}:{module:o(l.key),at:"source",param:l.key,pin:l.value}}let i=s("ref");if(i?.value)return{module:o("ref"),at:"source",param:"ref",pin:i.value};let a=s("version");if(a?.value){let c=ag(a.value);return c?{module:o("version"),at:"source",param:"version",pin:c}:{module:o("version"),at:"source",param:"version",pin:null,unpinned:`version "${a.value}" is a constraint, not a pin: there is no one version to move`}}return gQ(e)?{module:e,at:"source",pin:null,unpinned:"a local path has no version to pin"}:hQ(e)?{module:e,at:"source",pin:null,unpinned:"the git source names no ref, so it follows the default branch"}:{module:e,at:"source",pin:null,unpinned:"the source has no version argument and no pin in its address, so it resolves the newest release"}}function wQ(e,t,n,r){let{base:o,params:s}=bD(e);return ex(o,s.map(i=>i.key===t?`${n}=${r}`:i.raw))}function tx(e,t,n){let r=Ki(e,t);if(r.module!==n.module)return null;if(r.pin===null)return{outcome:"refused",reason:r.unpinned??"no pin"};if(r.pin===n.to)return{outcome:"already",pin:r.pin};if(r.pin!==n.from)return{outcome:"elsewhere",pin:r.pin};if(r.at==="version"){let s=t.lastIndexOf(r.pin);return{outcome:"moved",from:n.from,to:n.to,source:e,version:t.slice(0,s)+n.to+t.slice(s+r.pin.length)}}let o=r.param==="tag"||r.param==="digest"?pQ.test(n.to)?"digest":"tag":r.param;return{outcome:"moved",from:n.from,to:n.to,source:wQ(e,r.param,o,n.to)}}var bQ=/[A-Za-z_]/,vQ=/[A-Za-z0-9_-]/,nc=class extends Error{constructor(t,n){super(`${t}: ${n}`),this.name="HclScanError"}};function $D(e,t,n){let r=t+1,o=!1;for(;r<e.length;){let s=e[r];if(s==="\\"){r+=2;continue}if(s==='"')return{end:r+1,template:o};if(s===`
@@ -438,7 +438,7 @@ ${Kse(e)}
438
438
  ${JSON.stringify(e).replace(/<\//g,"<\\/").replace(/<!--/g,"<\\u0021--")}
439
439
  </script>
440
440
  </main></body></html>
441
- `}async function ZG(e,t,n,r,o=new Date().toISOString(),s){let i=Yg(n.project,n.commit,t),{value:a}=await aa(e,`${i}/run.json`,c=>Wse(c,n,r,o),`wave ${r.number}'s row`,s);return await e.put(`${i}/run.html`,Zse(a),"text/html; charset=utf-8"),`${i}/run.html`}import{spawnSync as Bfe}from"node:child_process";import{spawn as Vpe,spawnSync as pO}from"node:child_process";import{chmodSync as FB,existsSync as dp,mkdirSync as pp,mkdtempSync as Km,readdirSync as zB,readFileSync as jc,realpathSync as UB,rmSync as Jm,statSync as Zpe,writeFileSync as Ra}from"node:fs";import{tmpdir as fO}from"node:os";import{basename as gO,join as Ne,relative as BB,resolve as Rs,sep as WB}from"node:path";var Pr="0.4.23";import{existsSync as Xse,readFileSync as Qse}from"node:fs";import{join as eie}from"node:path";function YG(e,t,n,r){return e?{mode:e,source:`approval: ${e} in the config ${r}`,...e!=="sealed"&&t>0?{note:`chant.workspace.json ${r} still lists gates under identity.gates, and terragucci approve refuses an unsigned approval of a gate it lists; run terragucci init to drop them`}:{}}:t>0?{mode:"sealed",source:`identity.gates in chant.workspace.json ${r}, with no approval key`,note:"set approval: sealed in terragucci.yml to keep sealed approvals, or approval: ledger and run terragucci init to drop the gates"}:n?{mode:n,source:"the pipeline's --approval"}:{mode:"ledger",source:"the default"}}function Xg(e){if(e===void 0)return 0;try{return Object.keys(JSON.parse(e).identity?.gates??{}).length}catch{return 0}}async function Yr(e,t={}){let n=t.at??bs(e),r=WM(e,n),o=await ln(e,n,t.config?{config:t.config}:{});if("error"in o)throw new S(`approval is read from the config at base, and it could not be read (${o.error}), so the gate cannot be decided`);let s=!o.config.projects,i=s?Bs(o.config.approval):void 0,a=s&&qC(o.config.approval),c=s&&typeof o.config.agent?.token_env=="string"?o.config.agent.token_env:void 0,u=s&&typeof o.config.agent?.login=="string"&&o.config.agent.login?o.config.agent.login:void 0,l=s&&Array.isArray(o.config.policy?.override)?o.config.policy.override.filter(p=>typeof p=="string"):[],d=s&&typeof o.config.apply?.point=="string"?o.config.apply.point:void 0;return{...YG(i,r.gates.size,t.flag,"at base"),...r,base:n,overriders:l,...d?{point:d}:{},...a?{requireSigned:a}:{},...c?{agentTokenEnv:c}:{},...u?{agentLogin:u}:{}}}function Yu(e,t){if(t.projects)return;let n=eie(e,"chant.workspace.json");return YG(Bs(t.approval),Xg(Xse(n)?Qse(n,"utf-8"):void 0),void 0,"here")}var tie=(e,t)=>`-estate-outputs-from=${e}=${t}`;function XG(e,t,n,r,o){let s=[],i=[],a=new Map;for(let c of t){let u=n.get(c.estate);if(!u||u===e)continue;let l=f=>{i.push({upstream:u,data:c.name,outputs:"applied",why:f})};if(!r(u)){l("this change does not reach it, so its records stand");continue}let d=o(u);if(!d){l("it did not plan in this run");continue}let p=Wo(d.plan);p?p.changed?(i.push({upstream:u,data:c.name,outputs:"planned"}),a.has(c.estate)||(a.set(c.estate,u),s.push(tie(c.estate,d.file)))):l("its plan changes no output, so its records stand"):l("its plan names no output changes")}return{args:s,reads:i,upstreamOf:a}}function QG(e){let t=e.replace(/^[ \t]*[│╷╵]/gm," ").replace(/\s+/g," "),n=[],r=/Estate "([^"]+)"'s planned output "([^"]+)" \(in .*?\) is (known only after|sensitive)/g;for(let o of t.matchAll(r)){let s={kind:o[3]==="sensitive"?"sensitive":"unknown",estate:o[1],output:o[2]};n.some(i=>i.kind===s.kind&&i.estate===s.estate&&i.output===s.output)||n.push(s)}return n}var eF=e=>"`"+e+"`";function tF(e,t,n){let r=[...new Set(e.map(s=>s.output))].sort(),o=[...new Set(e.map(s=>t.get(s.estate)??s.estate))].sort();return`reads ${r.map(eF).join(", ")} of ${o.join(", ")}, unknown until ${n.length?`wave ${n.join(", ")}`:"it"} applies`}function nF(e,t){let n=[...new Set(e.map(o=>o.output))].sort(),r=[...new Set(e.map(o=>t.get(o.estate)??o.estate))].sort();return`reads sensitive ${n.length===1?"output":"outputs"} ${n.map(eF).join(", ")} of ${r.join(", ")}, which choudoufu never hands to another estate`}import{existsSync as nie,readdirSync as rie,readFileSync as iF,rmSync as oie,statSync as sie,writeFileSync as tT}from"node:fs";import{join as aF}from"node:path";function nT(e){return JSON.stringify(e).replace(/\$\{/g,()=>"$${").replace(/%\{/g,()=>"%%{")}function Qg(e,t,n){if(t===!0)return n;if(Array.isArray(e)||Array.isArray(t)){let o=Array.isArray(e)?e:[],s=Array.isArray(t)?t:[],i=Math.max(o.length,s.length);return`[${Array.from({length:i},(a,c)=>Qg(o[c],s[c],n)).join(", ")}]`}let r=o=>!!o&&typeof o=="object";if(r(e)||r(t)){let o=r(e)?e:{},s=r(t)?t:{};return`{ ${[...new Set([...Object.keys(o),...Object.keys(s).filter(a=>mc(s[a]))])].sort().map(a=>`${nT(a)} = ${Qg(o[a],s[a],n)}`).join(", ")} }`}return e==null?"null":typeof e=="string"?nT(e):JSON.stringify(e)}var iie=e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),em=(e,t="g")=>new RegExp(`\\bdata\\.terraform_remote_state\\.${iie(e)}(?![\\w-])`,t);function ov(e,t){let n=new RegExp(`${em(t,"").source}(\\.outputs(?:\\.([A-Za-z_][\\w-]*)|\\[\\s*"([^"]+)"\\s*\\])?)?`,"g"),r=new Set;for(let o of e)for(let s of o.matchAll(n)){let i=s[2]??s[3];if(!i)return;r.add(i)}return r}function tm(e){try{return rie(e).filter(t=>t.endsWith(".tf")||t.endsWith(".tofu")||t.endsWith(".tf.json")||t.endsWith(".tofu.json")).map(t=>aF(e,t)).filter(t=>sie(t).isFile())}catch{return[]}}function rT(e,t){return ov(tm(e).map(n=>iF(n,"utf-8")),t)}var rF="terragucci_linked.tf",oF="terragucci_unknown",sF=e=>`terragucci_linked_${e}`;function cF(e,t){let n=aF(e,rF);if(nie(n))throw new Error(`${rF} is already in the root`);let r=tm(e),o=new Map(r.map(l=>[l,iF(l,"utf-8")])),s=[...o.values()],i=[],a=!1,c=[` ${oF} = jsondecode(timestamp())`];for(let l of t){let d=Gb(l.upstream,l.name,l.outputs,ov(s,l.name));d.unknown&&(a=!0),i.push(d);let p=[...l.outputs].sort(([f],[g])=>f<g?-1:1).map(([f,g])=>{let m=Qg(g.value,g.unknown,`local.${oF}`);return`${nT(f)} = ${g.sensitive?`sensitive(${m})`:m}`});c.push(` ${sF(l.name)} = { outputs = { ${p.join(", ")} } }`)}let u=()=>{for(let[l,d]of o)tT(l,d);oie(n,{force:!0})};try{for(let[l,d]of o){let p=d;for(let f of t)p=p.replace(em(f.name),`local.${sF(f.name)}`);p!==d&&tT(l,p)}tT(n,`# Written by terragucci for a linked plan, and removed once it is made.
441
+ `}async function ZG(e,t,n,r,o=new Date().toISOString(),s){let i=Yg(n.project,n.commit,t),{value:a}=await aa(e,`${i}/run.json`,c=>Wse(c,n,r,o),`wave ${r.number}'s row`,s);return await e.put(`${i}/run.html`,Zse(a),"text/html; charset=utf-8"),`${i}/run.html`}import{spawnSync as Bfe}from"node:child_process";import{spawn as Vpe,spawnSync as pO}from"node:child_process";import{chmodSync as FB,existsSync as dp,mkdirSync as pp,mkdtempSync as Km,readdirSync as zB,readFileSync as jc,realpathSync as UB,rmSync as Jm,statSync as Zpe,writeFileSync as Ra}from"node:fs";import{tmpdir as fO}from"node:os";import{basename as gO,join as Ne,relative as BB,resolve as Rs,sep as WB}from"node:path";var Pr="0.4.25";import{existsSync as Xse,readFileSync as Qse}from"node:fs";import{join as eie}from"node:path";function YG(e,t,n,r){return e?{mode:e,source:`approval: ${e} in the config ${r}`,...e!=="sealed"&&t>0?{note:`chant.workspace.json ${r} still lists gates under identity.gates, and terragucci approve refuses an unsigned approval of a gate it lists; run terragucci init to drop them`}:{}}:t>0?{mode:"sealed",source:`identity.gates in chant.workspace.json ${r}, with no approval key`,note:"set approval: sealed in terragucci.yml to keep sealed approvals, or approval: ledger and run terragucci init to drop the gates"}:n?{mode:n,source:"the pipeline's --approval"}:{mode:"ledger",source:"the default"}}function Xg(e){if(e===void 0)return 0;try{return Object.keys(JSON.parse(e).identity?.gates??{}).length}catch{return 0}}async function Yr(e,t={}){let n=t.at??bs(e),r=WM(e,n),o=await ln(e,n,t.config?{config:t.config}:{});if("error"in o)throw new S(`approval is read from the config at base, and it could not be read (${o.error}), so the gate cannot be decided`);let s=!o.config.projects,i=s?Bs(o.config.approval):void 0,a=s&&qC(o.config.approval),c=s&&typeof o.config.agent?.token_env=="string"?o.config.agent.token_env:void 0,u=s&&typeof o.config.agent?.login=="string"&&o.config.agent.login?o.config.agent.login:void 0,l=s&&Array.isArray(o.config.policy?.override)?o.config.policy.override.filter(p=>typeof p=="string"):[],d=s&&typeof o.config.apply?.point=="string"?o.config.apply.point:void 0;return{...YG(i,r.gates.size,t.flag,"at base"),...r,base:n,overriders:l,...d?{point:d}:{},...a?{requireSigned:a}:{},...c?{agentTokenEnv:c}:{},...u?{agentLogin:u}:{}}}function Yu(e,t){if(t.projects)return;let n=eie(e,"chant.workspace.json");return YG(Bs(t.approval),Xg(Xse(n)?Qse(n,"utf-8"):void 0),void 0,"here")}var tie=(e,t)=>`-estate-outputs-from=${e}=${t}`;function XG(e,t,n,r,o){let s=[],i=[],a=new Map;for(let c of t){let u=n.get(c.estate);if(!u||u===e)continue;let l=f=>{i.push({upstream:u,data:c.name,outputs:"applied",why:f})};if(!r(u)){l("this change does not reach it, so its records stand");continue}let d=o(u);if(!d){l("it did not plan in this run");continue}let p=Wo(d.plan);p?p.changed?(i.push({upstream:u,data:c.name,outputs:"planned"}),a.has(c.estate)||(a.set(c.estate,u),s.push(tie(c.estate,d.file)))):l("its plan changes no output, so its records stand"):l("its plan names no output changes")}return{args:s,reads:i,upstreamOf:a}}function QG(e){let t=e.replace(/^[ \t]*[│╷╵]/gm," ").replace(/\s+/g," "),n=[],r=/Estate "([^"]+)"'s planned output "([^"]+)" \(in .*?\) is (known only after|sensitive)/g;for(let o of t.matchAll(r)){let s={kind:o[3]==="sensitive"?"sensitive":"unknown",estate:o[1],output:o[2]};n.some(i=>i.kind===s.kind&&i.estate===s.estate&&i.output===s.output)||n.push(s)}return n}var eF=e=>"`"+e+"`";function tF(e,t,n){let r=[...new Set(e.map(s=>s.output))].sort(),o=[...new Set(e.map(s=>t.get(s.estate)??s.estate))].sort();return`reads ${r.map(eF).join(", ")} of ${o.join(", ")}, unknown until ${n.length?`wave ${n.join(", ")}`:"it"} applies`}function nF(e,t){let n=[...new Set(e.map(o=>o.output))].sort(),r=[...new Set(e.map(o=>t.get(o.estate)??o.estate))].sort();return`reads sensitive ${n.length===1?"output":"outputs"} ${n.map(eF).join(", ")} of ${r.join(", ")}, which choudoufu never hands to another estate`}import{existsSync as nie,readdirSync as rie,readFileSync as iF,rmSync as oie,statSync as sie,writeFileSync as tT}from"node:fs";import{join as aF}from"node:path";function nT(e){return JSON.stringify(e).replace(/\$\{/g,()=>"$${").replace(/%\{/g,()=>"%%{")}function Qg(e,t,n){if(t===!0)return n;if(Array.isArray(e)||Array.isArray(t)){let o=Array.isArray(e)?e:[],s=Array.isArray(t)?t:[],i=Math.max(o.length,s.length);return`[${Array.from({length:i},(a,c)=>Qg(o[c],s[c],n)).join(", ")}]`}let r=o=>!!o&&typeof o=="object";if(r(e)||r(t)){let o=r(e)?e:{},s=r(t)?t:{};return`{ ${[...new Set([...Object.keys(o),...Object.keys(s).filter(a=>mc(s[a]))])].sort().map(a=>`${nT(a)} = ${Qg(o[a],s[a],n)}`).join(", ")} }`}return e==null?"null":typeof e=="string"?nT(e):JSON.stringify(e)}var iie=e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),em=(e,t="g")=>new RegExp(`\\bdata\\.terraform_remote_state\\.${iie(e)}(?![\\w-])`,t);function ov(e,t){let n=new RegExp(`${em(t,"").source}(\\.outputs(?:\\.([A-Za-z_][\\w-]*)|\\[\\s*"([^"]+)"\\s*\\])?)?`,"g"),r=new Set;for(let o of e)for(let s of o.matchAll(n)){let i=s[2]??s[3];if(!i)return;r.add(i)}return r}function tm(e){try{return rie(e).filter(t=>t.endsWith(".tf")||t.endsWith(".tofu")||t.endsWith(".tf.json")||t.endsWith(".tofu.json")).map(t=>aF(e,t)).filter(t=>sie(t).isFile())}catch{return[]}}function rT(e,t){return ov(tm(e).map(n=>iF(n,"utf-8")),t)}var rF="terragucci_linked.tf",oF="terragucci_unknown",sF=e=>`terragucci_linked_${e}`;function cF(e,t){let n=aF(e,rF);if(nie(n))throw new Error(`${rF} is already in the root`);let r=tm(e),o=new Map(r.map(l=>[l,iF(l,"utf-8")])),s=[...o.values()],i=[],a=!1,c=[` ${oF} = jsondecode(timestamp())`];for(let l of t){let d=Gb(l.upstream,l.name,l.outputs,ov(s,l.name));d.unknown&&(a=!0),i.push(d);let p=[...l.outputs].sort(([f],[g])=>f<g?-1:1).map(([f,g])=>{let m=Qg(g.value,g.unknown,`local.${oF}`);return`${nT(f)} = ${g.sensitive?`sensitive(${m})`:m}`});c.push(` ${sF(l.name)} = { outputs = { ${p.join(", ")} } }`)}let u=()=>{for(let[l,d]of o)tT(l,d);oie(n,{force:!0})};try{for(let[l,d]of o){let p=d;for(let f of t)p=p.replace(em(f.name),`local.${sF(f.name)}`);p!==d&&tT(l,p)}tT(n,`# Written by terragucci for a linked plan, and removed once it is made.
442
442
  locals {
443
443
  ${c.join(`
444
444
  `)}
@@ -468,7 +468,7 @@ ${n}`).digest("hex").slice(0,16)}`;if(kv("git",["-C",e,"fetch","-q","--no-tags",
468
468
  `).join(`
469
469
  `)}function UT(e,t){let[n,r]=t.split(".");if(!n||!r||!fce(e))return;let o=new RegExp(`^\\s*resource\\s+"${n}"\\s+"${r}"\\s*\\{`,"m");return gce(e).filter(s=>s.endsWith(".tf")).sort().find(s=>o.test(mce(hce(e,s),"utf-8")))}function fz(e,t){return`${e.replace(/\n*$/,`
470
470
  `)}
471
- ${t}`}import{spawnSync as Ece}from"node:child_process";import{createHash as wce}from"node:crypto";var BT={"ghcr.io/intentius/terragucci-tofu:0.4.23-tofu1.13.1":"sha256:830319f3ca4d9d141bf145646d2a7db826235ea8036d9ac9e3f3b85723405b3c","ghcr.io/intentius/terragucci-terraform:0.4.23-tf1.14.9":"sha256:8d605c34fec65c3905f0a087b3433729a3ade9e49f4ccd5a133c3e73a4bb2da9","ghcr.io/intentius/terragucci-terragrunt:0.4.23-tg1.1.6-tofu1.13.1":"sha256:9b44b3e22bda52e0c1fa33d29747313da35ba380001d82ae4ab60cb2409f9147","ghcr.io/intentius/terragucci-choudoufu:0.4.23-choudoufu0.28.0":"sha256:21bbddd722bef0b8a5649c3fa13a9de98ce3c485cf7c14e4f16d2933edd21818"};var gz="ghcr.io/intentius",ai={tofu:"1.13.1",terraform:"1.14.9",terragrunt:"1.1.6",choudoufu:"0.28.0"};function mz(e,t=Pr){return e==="terragrunt"?`${t}-tg${ai.terragrunt}-tofu${ai.tofu}`:`${t}-${e==="terraform"?"tf":e}${ai[e]}`}function HT(e,t=BT){let n=`${gz}/terragucci-${e}`,r=mz(e);return{repository:n,tag:r,digest:t[`${n}:${r}`]}}function hz(e=BT){let t=`${gz}/terragucci-terragrunt`,n=mz("terragrunt");return{repository:t,tag:n,digest:e[`${t}:${n}`]}}function qT(e){return e.digest?`${e.repository}:${e.tag}@${e.digest}`:`${e.repository}:${e.tag}`}var WT={laya:"0.3.28",torch:"2.14.0",pip:"26.2.1",checkpoint:{repo:"convaiinnovations/laya",name:"english",revision:"55cf4c4ebb4ebe31b2550e8bdf3bd21b99753851",weightsSha256:"891102d372688fc2a094dac56a384bc537b87c63f21f9f3dac0be2b7cbc8d86c"},port:8790},yz=`laya-${WT.laya}-${WT.checkpoint.name}@${WT.checkpoint.revision.slice(0,12)}`;var bce="https://api.typesafe.ai",vce={noul:.8,choice:.7,score:.7},$ce={laya:!0,jev:!0,von:!1,decider:!1};function kce(e,t){let n=r=>{throw new Error(`decide: question ${e} ${r}`)};if(/^[A-Za-z0-9_-]{1,64}$/.test(e)||n("needs a name of letters, digits, - and _"),t.instructions||n("has no instructions"),t.threshold!==void 0&&!(t.threshold>0&&t.threshold<=1)&&n("has a threshold outside (0, 1]"),t.type==="noul")(!t.criteria?.true||!t.criteria?.false)&&n("is a noul and needs criteria.true and criteria.false");else if(t.type==="choice"){let r=Object.keys(t.criteria??{}).length;(r<2||r>255)&&n(`is a choice with ${r} options; use 2 to 255`)}else if(t.type==="score"){let r=t.criteria?.length??0;(r<2||r>10)&&n(`is a score with ${r} levels; use 2 to 10`)}else n(`has type ${JSON.stringify(t.type)}; use noul, choice or score`)}function wz(e,t){return e.threshold??t?.thresholds?.[e.type]??vce[e.type]}var Ev=e=>typeof e=="number"&&Number.isFinite(e)&&e>=0&&e<=1;function _ce(e){let t=e.url??(e.backend==="jev"?bce:void 0);if(!t)return;let n=t.replace(/\/+$/,"");return n.endsWith("/v1/systemone")?n:`${n}/v1/systemone`}function Sce(e){return e.model??(e.backend==="laya"?yz:void 0)}function Rce(e,t,n,r){let o={question:e,type:t.type,threshold:r},s=d=>({...o,status:"unavailable",reason:d});if(n===null||typeof n!="object")return s("the response has no answer for it");let i=n;if(i.type!==t.type)return s(`the answer's type is ${JSON.stringify(i.type)}, not ${t.type}`);let a,c,u,l;if(t.type==="noul"){if(!Ev(i.noul))return s("the noul answer is not a probability");a=i.noul>=.5?"true":"false",c=Math.max(i.noul,1-i.noul),u={true:i.noul,false:1-i.noul}}else{let d=i.probabilities;if(d===null||typeof d!="object"||!Object.values(d).every(Ev))return s("the answer has no probabilities");if(u=d,t.type==="choice"){if(typeof i.choice!="string"||!(i.choice in t.criteria))return s(`the choice ${JSON.stringify(i.choice)} is not one of the options`);if(!Ev(u[i.choice]))return s("the chosen option has no probability");a=i.choice,c=u[i.choice]}else{let p=t.criteria.map((g,m)=>String(m));if(!p.every(g=>Ev(u[g])))return s("the score's probabilities do not cover every level");let f=p.reduce((g,m)=>u[m]>u[g]?m:g,p[0]);a=t.criteria[Number(f)],c=u[f],typeof i.score=="number"&&Number.isFinite(i.score)&&(l=i.score)}}return{...o,status:c>=r?"confident":"not-confident",answer:a,probability:c,probabilities:u,...l===void 0?{}:{score:l}}}async function Xd(e,t,n,r={}){for(let[v,$]of Object.entries(n))kce(v,$);let o=`sha256:${wce("sha256").update(JSON.stringify(t)).digest("hex")}`,s=(v,$)=>Object.fromEntries(Object.entries(n).map(([_,E])=>[_,{question:_,type:E.type,status:v,threshold:wz(E,e),reason:$}]));if(!e)return{stateDigest:o,decisions:s("off","decide is not configured")};let i=_ce(e),a=Sce(e),c={backend:e.backend,url:i,model:a,stateDigest:o};if(!i)return{...c,decisions:s("unavailable","decide.url is not set")};let u={"content-type":"application/json",accept:"application/json"};if(e.token_env){let v=(r.env??process.env)[e.token_env];if(!v)return{...c,decisions:s("unavailable",`${e.token_env} is not set`)};u.authorization=`Bearer ${v}`}let l=Object.fromEntries(Object.entries(n).map(([v,$])=>[v,{type:$.type,instructions:$.instructions,criteria:$.criteria}])),d=JSON.stringify({...a?{model:a}:{},state:t,questions:l}),p=r.fetch??globalThis.fetch,f=Date.now(),g,m;try{let v=await p(i,{method:"POST",headers:u,body:d,signal:AbortSignal.timeout(r.timeoutMs??3e4)});if(g=v.status,m=await v.text(),!v.ok){let $=m.slice(0,300);try{let _=JSON.parse(m),E=_.detail??_.error;E!==void 0&&($=typeof E=="string"?E:JSON.stringify(E))}catch{}return{...c,ms:Date.now()-f,decisions:s("unavailable",`the service answered HTTP ${g}: ${$}`)}}}catch(v){return{...c,ms:Date.now()-f,decisions:s("unavailable",`the service did not answer: ${v.message}`)}}let h=Date.now()-f,y;try{y=JSON.parse(m)}catch{return{...c,ms:h,decisions:s("unavailable","the response is not JSON")}}if(y===null||typeof y!="object"||y.answers===null||typeof y.answers!="object")return{...c,ms:h,decisions:s("unavailable","the response has no answers")};let w=typeof y.model=="string"?y.model:void 0;if($ce[e.backend]&&a&&w!==a)return{...c,model:w??a,ms:h,decisions:s("unavailable",`the service answered as ${w??"no model"}, and decide.model pins ${a}`)};let b=y.answers,k=Object.fromEntries(Object.entries(n).map(([v,$])=>[v,Rce(v,$,b[v],wz($,e))]));return{...c,model:w??a,ms:h,decisions:k}}function Qd(e){return e?.status==="confident"}function _c(e,t){let n=t.model?`, ${t.model}`:"";if(e.status==="off")return`${e.question}: not asked; decide is not configured`;if(e.status==="unavailable")return`${e.question}: no decision; ${e.reason}`;let r=(e.probability??0).toFixed(2),o=e.threshold.toFixed(2);return e.status==="confident"?`${e.question}: ${e.answer} (${r}, threshold ${o}${n})`:`${e.question}: ${e.answer} (${r}, below the ${o} threshold, so not used${n})`}var JT={type:"noul",instructions:"Read the pull request's title and description, then the summary of what its plan does. Does the description leave out or misstate a destroy or a replacement the plan makes?",criteria:{true:"the description does not describe the plan: a destroy or replacement in the plan is missing from it or contradicted by it",false:"the description describes what the plan does, including every destroy and replacement"}},KT={type:"choice",instructions:"An attribute of a resource managed by Terraform changed outside Terraform. From the resource, the attribute and the two values, which kind of change is it most likely?",criteria:{controller:"a controller or the cloud service wrote it, as autoscaling, a scheduler or a service that adds tags does",human:"a person edited it by hand in a console or with a CLI","provider-default":"the provider or the cloud API changed a default value it reports"}},xce={type:"choice",instructions:"These are the commits to a Terraform module since its last release, and a summary of its diff. Which semantic version bump does the change call for?",criteria:{major:"a breaking change: a variable or output removed or renamed, a required variable added, or a resource replaced for every caller",minor:"a new feature that keeps every existing caller working, such as a new optional variable, output or resource",patch:"a fix or an internal change that callers do not see"}},bz={prIntent:JT,driftActor:KT,versionBump:xce};var wm=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),tl=e=>typeof e=="number",Tce=/^(aws:|eks:|elasticbeanstalk:|kubernetes\.io\/|k8s\.io\/|karpenter\.sh\/)/;function Ace(e){let t=wm(e.before)?e.before:{},n=wm(e.live)?e.live:{},r=[...new Set([...Object.keys(t),...Object.keys(n)])].filter(o=>JSON.stringify(t[o]??null)!==JSON.stringify(n[o]??null));return r.length>0&&r.every(o=>Tce.test(o))}var Oce=e=>t=>{let n=Array.isArray(t.before)?t.before[0]:t.before,r=Array.isArray(t.live)?t.live[0]:t.live;if(!wm(n)||!wm(r))return!1;let o=[...new Set([...Object.keys(n),...Object.keys(r)])].filter(s=>JSON.stringify(n[s]??null)!==JSON.stringify(r[s]??null));return o.length>0&&o.every(s=>s===e)},Pce=[{type:"aws_ecs_service",path:"desired_count",actor:"controller",why:"Application Auto Scaling sets an ECS service's task count",when:e=>tl(e.live)},{type:"aws_autoscaling_group",path:"desired_capacity",actor:"controller",why:"the group's scaling policies and scheduled actions set its desired capacity",when:e=>tl(e.live)},{type:"aws_eks_node_group",path:"scaling_config",actor:"controller",why:"Cluster Autoscaler or Karpenter sets a node group's desired size",when:Oce("desired_size")},{type:"aws_dynamodb_table",path:"read_capacity",actor:"controller",why:"Application Auto Scaling adjusts a provisioned table's read capacity",when:e=>tl(e.live)},{type:"aws_dynamodb_table",path:"write_capacity",actor:"controller",why:"Application Auto Scaling adjusts a provisioned table's write capacity",when:e=>tl(e.live)},{type:"aws_appautoscaling_target",path:"min_capacity",actor:"controller",why:"a scheduled action on the scalable target moves its minimum",when:e=>tl(e.live)},{type:"aws_appautoscaling_target",path:"max_capacity",actor:"controller",why:"a scheduled action on the scalable target moves its maximum",when:e=>tl(e.live)},{type:"aws_db_instance",path:"engine_version",actor:"controller",why:"RDS applies minor engine upgrades itself when auto_minor_version_upgrade is on",when:e=>typeof e.live=="string"&&typeof e.before=="string"},{type:"aws_launch_template",path:"latest_version",actor:"controller",why:"a service that publishes a launch template version (EC2 Image Builder, Karpenter) moves latest_version",when:e=>tl(e.live)},{type:"aws_elasticache_replication_group",path:"engine_version_actual",actor:"controller",why:"ElastiCache applies minor engine upgrades itself"},...["tags","tags_all"].map(e=>({type:"*",path:e,actor:"controller",why:"a service adds tags in its own namespace (aws:, eks:, karpenter.sh/ and the like)",when:Ace}))];function jce(e,t,n){return Pce.find(r=>(r.type===e||r.type==="*")&&r.path===t&&(r.when?.(n)??!0))}var Ice=/terraform|opentofu|tofu/i;function Cce(e){let t=e.userIdentity??{},n=t.invokedBy??e.invokedBy;if(t.type==="AWSService"||n&&/\.amazonaws\.com$/.test(n))return{actor:"controller",who:n??"an AWS service"};let o=(t.arn??"").split("/").at(-1)??"";if(t.type==="IAMUser")return{actor:"human",who:t.userName??o};if(t.type==="Root")return{actor:"human",who:"the root user"};if(t.type==="IdentityCenterUser"||t.type==="FederatedUser")return{actor:"human",who:t.userName??o};if(t.type==="AssumedRole"){let s=t.sessionContext?.sessionIssuer?.userName??"";if(/^AWSReservedSSO_/.test(s)||o.includes("@"))return{actor:"human",who:o||s}}}function Nce(e){let n=e.filter(o=>o.readOnly!==!0&&o.readOnly!=="true"&&!Ice.test(o.userAgent??"")).sort((o,s)=>String(s.eventTime??"").localeCompare(String(o.eventTime??"")))[0],r=n&&Cce(n);return n&&r?{status:"found",...r,event:n.eventName??"an event",at:n.eventTime??""}:{status:"silent"}}function bm(e={}){let t=e.run??(n=>{let r=Ece("aws",n,{encoding:"utf-8",maxBuffer:67108864});return{status:r.status,stdout:r.stdout??"",stderr:r.stderr??"",error:r.error}});return{async lookup(n){if(!n.type.startsWith("aws_"))return{status:"unavailable",reason:`no audit log reader for ${n.type}`};let r=new Date((e.now?.()??new Date).getTime()-(e.days??14)*864e5).toISOString(),o=t(["cloudtrail","lookup-events","--output","json","--max-results","50","--start-time",r,"--lookup-attributes",`AttributeKey=ResourceName,AttributeValue=${n.ref}`,...e.region?["--region",e.region]:[]]);if(o.error?.code==="ENOENT")return{status:"unavailable",reason:"the aws CLI is not installed"};if(o.error||o.status!==0)return{status:"unavailable",reason:(o.error?.message??(o.stderr.trim()||`aws exited ${o.status}`)).split(`
471
+ ${t}`}import{spawnSync as Ece}from"node:child_process";import{createHash as wce}from"node:crypto";var BT={"ghcr.io/intentius/terragucci-tofu:0.4.25-tofu1.13.1":"sha256:94b2bf5639e1389a4bcaa34b59f692e48401e19410604bdaac6fdb0973b1edf1","ghcr.io/intentius/terragucci-terraform:0.4.25-tf1.14.9":"sha256:df20b48b6266325d277f2b77aee0187b00fa09aefe9d90eceda373e3e83af58b","ghcr.io/intentius/terragucci-terragrunt:0.4.25-tg1.1.6-tofu1.13.1":"sha256:2709bc60b4287dc10a1658e0e09907e9e6cdc1f199a16afee65fcdf33e9eb997","ghcr.io/intentius/terragucci-choudoufu:0.4.25-choudoufu0.28.0":"sha256:d2bb4a9d7bbeedda14a0bdf7da5f4f960ff32fd7d883043daabd23830b96b9ba"};var gz="ghcr.io/intentius",ai={tofu:"1.13.1",terraform:"1.14.9",terragrunt:"1.1.6",choudoufu:"0.28.0"};function mz(e,t=Pr){return e==="terragrunt"?`${t}-tg${ai.terragrunt}-tofu${ai.tofu}`:`${t}-${e==="terraform"?"tf":e}${ai[e]}`}function HT(e,t=BT){let n=`${gz}/terragucci-${e}`,r=mz(e);return{repository:n,tag:r,digest:t[`${n}:${r}`]}}function hz(e=BT){let t=`${gz}/terragucci-terragrunt`,n=mz("terragrunt");return{repository:t,tag:n,digest:e[`${t}:${n}`]}}function qT(e){return e.digest?`${e.repository}:${e.tag}@${e.digest}`:`${e.repository}:${e.tag}`}var WT={laya:"0.3.28",torch:"2.14.0",pip:"26.2.1",checkpoint:{repo:"convaiinnovations/laya",name:"english",revision:"55cf4c4ebb4ebe31b2550e8bdf3bd21b99753851",weightsSha256:"891102d372688fc2a094dac56a384bc537b87c63f21f9f3dac0be2b7cbc8d86c"},port:8790},yz=`laya-${WT.laya}-${WT.checkpoint.name}@${WT.checkpoint.revision.slice(0,12)}`;var bce="https://api.typesafe.ai",vce={noul:.8,choice:.7,score:.7},$ce={laya:!0,jev:!0,von:!1,decider:!1};function kce(e,t){let n=r=>{throw new Error(`decide: question ${e} ${r}`)};if(/^[A-Za-z0-9_-]{1,64}$/.test(e)||n("needs a name of letters, digits, - and _"),t.instructions||n("has no instructions"),t.threshold!==void 0&&!(t.threshold>0&&t.threshold<=1)&&n("has a threshold outside (0, 1]"),t.type==="noul")(!t.criteria?.true||!t.criteria?.false)&&n("is a noul and needs criteria.true and criteria.false");else if(t.type==="choice"){let r=Object.keys(t.criteria??{}).length;(r<2||r>255)&&n(`is a choice with ${r} options; use 2 to 255`)}else if(t.type==="score"){let r=t.criteria?.length??0;(r<2||r>10)&&n(`is a score with ${r} levels; use 2 to 10`)}else n(`has type ${JSON.stringify(t.type)}; use noul, choice or score`)}function wz(e,t){return e.threshold??t?.thresholds?.[e.type]??vce[e.type]}var Ev=e=>typeof e=="number"&&Number.isFinite(e)&&e>=0&&e<=1;function _ce(e){let t=e.url??(e.backend==="jev"?bce:void 0);if(!t)return;let n=t.replace(/\/+$/,"");return n.endsWith("/v1/systemone")?n:`${n}/v1/systemone`}function Sce(e){return e.model??(e.backend==="laya"?yz:void 0)}function Rce(e,t,n,r){let o={question:e,type:t.type,threshold:r},s=d=>({...o,status:"unavailable",reason:d});if(n===null||typeof n!="object")return s("the response has no answer for it");let i=n;if(i.type!==t.type)return s(`the answer's type is ${JSON.stringify(i.type)}, not ${t.type}`);let a,c,u,l;if(t.type==="noul"){if(!Ev(i.noul))return s("the noul answer is not a probability");a=i.noul>=.5?"true":"false",c=Math.max(i.noul,1-i.noul),u={true:i.noul,false:1-i.noul}}else{let d=i.probabilities;if(d===null||typeof d!="object"||!Object.values(d).every(Ev))return s("the answer has no probabilities");if(u=d,t.type==="choice"){if(typeof i.choice!="string"||!(i.choice in t.criteria))return s(`the choice ${JSON.stringify(i.choice)} is not one of the options`);if(!Ev(u[i.choice]))return s("the chosen option has no probability");a=i.choice,c=u[i.choice]}else{let p=t.criteria.map((g,m)=>String(m));if(!p.every(g=>Ev(u[g])))return s("the score's probabilities do not cover every level");let f=p.reduce((g,m)=>u[m]>u[g]?m:g,p[0]);a=t.criteria[Number(f)],c=u[f],typeof i.score=="number"&&Number.isFinite(i.score)&&(l=i.score)}}return{...o,status:c>=r?"confident":"not-confident",answer:a,probability:c,probabilities:u,...l===void 0?{}:{score:l}}}async function Xd(e,t,n,r={}){for(let[v,$]of Object.entries(n))kce(v,$);let o=`sha256:${wce("sha256").update(JSON.stringify(t)).digest("hex")}`,s=(v,$)=>Object.fromEntries(Object.entries(n).map(([_,E])=>[_,{question:_,type:E.type,status:v,threshold:wz(E,e),reason:$}]));if(!e)return{stateDigest:o,decisions:s("off","decide is not configured")};let i=_ce(e),a=Sce(e),c={backend:e.backend,url:i,model:a,stateDigest:o};if(!i)return{...c,decisions:s("unavailable","decide.url is not set")};let u={"content-type":"application/json",accept:"application/json"};if(e.token_env){let v=(r.env??process.env)[e.token_env];if(!v)return{...c,decisions:s("unavailable",`${e.token_env} is not set`)};u.authorization=`Bearer ${v}`}let l=Object.fromEntries(Object.entries(n).map(([v,$])=>[v,{type:$.type,instructions:$.instructions,criteria:$.criteria}])),d=JSON.stringify({...a?{model:a}:{},state:t,questions:l}),p=r.fetch??globalThis.fetch,f=Date.now(),g,m;try{let v=await p(i,{method:"POST",headers:u,body:d,signal:AbortSignal.timeout(r.timeoutMs??3e4)});if(g=v.status,m=await v.text(),!v.ok){let $=m.slice(0,300);try{let _=JSON.parse(m),E=_.detail??_.error;E!==void 0&&($=typeof E=="string"?E:JSON.stringify(E))}catch{}return{...c,ms:Date.now()-f,decisions:s("unavailable",`the service answered HTTP ${g}: ${$}`)}}}catch(v){return{...c,ms:Date.now()-f,decisions:s("unavailable",`the service did not answer: ${v.message}`)}}let h=Date.now()-f,y;try{y=JSON.parse(m)}catch{return{...c,ms:h,decisions:s("unavailable","the response is not JSON")}}if(y===null||typeof y!="object"||y.answers===null||typeof y.answers!="object")return{...c,ms:h,decisions:s("unavailable","the response has no answers")};let w=typeof y.model=="string"?y.model:void 0;if($ce[e.backend]&&a&&w!==a)return{...c,model:w??a,ms:h,decisions:s("unavailable",`the service answered as ${w??"no model"}, and decide.model pins ${a}`)};let b=y.answers,k=Object.fromEntries(Object.entries(n).map(([v,$])=>[v,Rce(v,$,b[v],wz($,e))]));return{...c,model:w??a,ms:h,decisions:k}}function Qd(e){return e?.status==="confident"}function _c(e,t){let n=t.model?`, ${t.model}`:"";if(e.status==="off")return`${e.question}: not asked; decide is not configured`;if(e.status==="unavailable")return`${e.question}: no decision; ${e.reason}`;let r=(e.probability??0).toFixed(2),o=e.threshold.toFixed(2);return e.status==="confident"?`${e.question}: ${e.answer} (${r}, threshold ${o}${n})`:`${e.question}: ${e.answer} (${r}, below the ${o} threshold, so not used${n})`}var JT={type:"noul",instructions:"Read the pull request's title and description, then the summary of what its plan does. Does the description leave out or misstate a destroy or a replacement the plan makes?",criteria:{true:"the description does not describe the plan: a destroy or replacement in the plan is missing from it or contradicted by it",false:"the description describes what the plan does, including every destroy and replacement"}},KT={type:"choice",instructions:"An attribute of a resource managed by Terraform changed outside Terraform. From the resource, the attribute and the two values, which kind of change is it most likely?",criteria:{controller:"a controller or the cloud service wrote it, as autoscaling, a scheduler or a service that adds tags does",human:"a person edited it by hand in a console or with a CLI","provider-default":"the provider or the cloud API changed a default value it reports"}},xce={type:"choice",instructions:"These are the commits to a Terraform module since its last release, and a summary of its diff. Which semantic version bump does the change call for?",criteria:{major:"a breaking change: a variable or output removed or renamed, a required variable added, or a resource replaced for every caller",minor:"a new feature that keeps every existing caller working, such as a new optional variable, output or resource",patch:"a fix or an internal change that callers do not see"}},bz={prIntent:JT,driftActor:KT,versionBump:xce};var wm=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),tl=e=>typeof e=="number",Tce=/^(aws:|eks:|elasticbeanstalk:|kubernetes\.io\/|k8s\.io\/|karpenter\.sh\/)/;function Ace(e){let t=wm(e.before)?e.before:{},n=wm(e.live)?e.live:{},r=[...new Set([...Object.keys(t),...Object.keys(n)])].filter(o=>JSON.stringify(t[o]??null)!==JSON.stringify(n[o]??null));return r.length>0&&r.every(o=>Tce.test(o))}var Oce=e=>t=>{let n=Array.isArray(t.before)?t.before[0]:t.before,r=Array.isArray(t.live)?t.live[0]:t.live;if(!wm(n)||!wm(r))return!1;let o=[...new Set([...Object.keys(n),...Object.keys(r)])].filter(s=>JSON.stringify(n[s]??null)!==JSON.stringify(r[s]??null));return o.length>0&&o.every(s=>s===e)},Pce=[{type:"aws_ecs_service",path:"desired_count",actor:"controller",why:"Application Auto Scaling sets an ECS service's task count",when:e=>tl(e.live)},{type:"aws_autoscaling_group",path:"desired_capacity",actor:"controller",why:"the group's scaling policies and scheduled actions set its desired capacity",when:e=>tl(e.live)},{type:"aws_eks_node_group",path:"scaling_config",actor:"controller",why:"Cluster Autoscaler or Karpenter sets a node group's desired size",when:Oce("desired_size")},{type:"aws_dynamodb_table",path:"read_capacity",actor:"controller",why:"Application Auto Scaling adjusts a provisioned table's read capacity",when:e=>tl(e.live)},{type:"aws_dynamodb_table",path:"write_capacity",actor:"controller",why:"Application Auto Scaling adjusts a provisioned table's write capacity",when:e=>tl(e.live)},{type:"aws_appautoscaling_target",path:"min_capacity",actor:"controller",why:"a scheduled action on the scalable target moves its minimum",when:e=>tl(e.live)},{type:"aws_appautoscaling_target",path:"max_capacity",actor:"controller",why:"a scheduled action on the scalable target moves its maximum",when:e=>tl(e.live)},{type:"aws_db_instance",path:"engine_version",actor:"controller",why:"RDS applies minor engine upgrades itself when auto_minor_version_upgrade is on",when:e=>typeof e.live=="string"&&typeof e.before=="string"},{type:"aws_launch_template",path:"latest_version",actor:"controller",why:"a service that publishes a launch template version (EC2 Image Builder, Karpenter) moves latest_version",when:e=>tl(e.live)},{type:"aws_elasticache_replication_group",path:"engine_version_actual",actor:"controller",why:"ElastiCache applies minor engine upgrades itself"},...["tags","tags_all"].map(e=>({type:"*",path:e,actor:"controller",why:"a service adds tags in its own namespace (aws:, eks:, karpenter.sh/ and the like)",when:Ace}))];function jce(e,t,n){return Pce.find(r=>(r.type===e||r.type==="*")&&r.path===t&&(r.when?.(n)??!0))}var Ice=/terraform|opentofu|tofu/i;function Cce(e){let t=e.userIdentity??{},n=t.invokedBy??e.invokedBy;if(t.type==="AWSService"||n&&/\.amazonaws\.com$/.test(n))return{actor:"controller",who:n??"an AWS service"};let o=(t.arn??"").split("/").at(-1)??"";if(t.type==="IAMUser")return{actor:"human",who:t.userName??o};if(t.type==="Root")return{actor:"human",who:"the root user"};if(t.type==="IdentityCenterUser"||t.type==="FederatedUser")return{actor:"human",who:t.userName??o};if(t.type==="AssumedRole"){let s=t.sessionContext?.sessionIssuer?.userName??"";if(/^AWSReservedSSO_/.test(s)||o.includes("@"))return{actor:"human",who:o||s}}}function Nce(e){let n=e.filter(o=>o.readOnly!==!0&&o.readOnly!=="true"&&!Ice.test(o.userAgent??"")).sort((o,s)=>String(s.eventTime??"").localeCompare(String(o.eventTime??"")))[0],r=n&&Cce(n);return n&&r?{status:"found",...r,event:n.eventName??"an event",at:n.eventTime??""}:{status:"silent"}}function bm(e={}){let t=e.run??(n=>{let r=Ece("aws",n,{encoding:"utf-8",maxBuffer:67108864});return{status:r.status,stdout:r.stdout??"",stderr:r.stderr??"",error:r.error}});return{async lookup(n){if(!n.type.startsWith("aws_"))return{status:"unavailable",reason:`no audit log reader for ${n.type}`};let r=new Date((e.now?.()??new Date).getTime()-(e.days??14)*864e5).toISOString(),o=t(["cloudtrail","lookup-events","--output","json","--max-results","50","--start-time",r,"--lookup-attributes",`AttributeKey=ResourceName,AttributeValue=${n.ref}`,...e.region?["--region",e.region]:[]]);if(o.error?.code==="ENOENT")return{status:"unavailable",reason:"the aws CLI is not installed"};if(o.error||o.status!==0)return{status:"unavailable",reason:(o.error?.message??(o.stderr.trim()||`aws exited ${o.status}`)).split(`
472
472
  `)[0]};let s;try{s=JSON.parse(o.stdout)}catch{return{status:"unavailable",reason:"aws printed no JSON"}}let i=[];for(let a of s.Events??[])try{i.push({eventName:a.EventName,eventTime:a.EventTime,...JSON.parse(a.CloudTrailEvent??"{}")})}catch{}return Nce(i)}}}function vz(e,t){return t?"(sensitive)":e==null?null:typeof e=="number"||typeof e=="boolean"?e:typeof e=="string"?`(a string of ${e.length} characters)`:Array.isArray(e)?`(a list of ${e.length})`:wm(e)?`(a map with keys ${Object.keys(e).slice(0,12).join(", ")})`:"(a value)"}var vm="attributions.json";async function ep(e,t,n={}){let r=[],o=[],s=new Map,i;for(let a of t)for(let c of a.attributes){let u={root:e,address:a.address,path:c.path},l=c.sensitive?void 0:jce(a.type,c.path,c);if(l){r.push({...u,actor:l.actor,source:"table",detail:l.why});continue}if(n.audit&&a.ref&&i===void 0){let d=`${a.type}\0${a.ref}`,p=s.get(d);if(p||(p=await n.audit.lookup({type:a.type,address:a.address,ref:a.ref}),s.set(d,p)),p.status==="found"){r.push({...u,actor:p.actor,source:"audit",detail:`${p.event} by ${p.who}${p.at?` at ${p.at}`:""}`});continue}p.status==="unavailable"&&(i=p.reason,o.push(`audit log unavailable: ${p.reason}`))}if(n.decide){let d={resource_type:a.type,attribute:c.path,value_in_code:vz(c.before,c.sensitive),live_value:vz(c.live,c.sensitive)},p=await Xd(n.decide,d,{actor:KT},n.options),f=p.decisions.actor;if(Qd(f)){r.push({...u,actor:f.answer,source:"model",detail:_c(f,p),probability:f.probability});continue}o.push(`${a.address} ${c.path}: ${_c(f,p)}`)}r.push({...u,source:"unattributed",detail:"neither the known-writes table nor the audit log answered"+(n.decide?", and the decision was not used":"")})}return{attributions:r,notes:o}}var Dce={table:"known write",audit:"audit log",model:"model",unattributed:"unattributed"};function VT(e){let t=new Map,n=[];for(let r of e){let o=`\`${r.address}\` \`${r.path}\``;if(r.source==="unattributed"){n.push(`- unattributed: ${o}: ${r.detail}; the default response runs`);continue}let s=`${Dce[r.source]}: ${r.detail}`;if(r.actor==="human"){n.push(`- human edit: ${o} (${s}); the pull request codifies it for the owner to accept or revert`);continue}let i=t.get(r.address)??new Set;i.add(r.path),t.set(r.address,i),r.actor==="controller"?n.push(`- controller write: ${o} (${s}); add \`lifecycle { ignore_changes = [${r.path}] }\` to the resource, and leave it out of the code`):n.push(`- provider default change: ${o} (${s}); pin the version that kept the old value, or set \`${r.path}\` to the value you want`)}return{leave:t,lines:n}}function ZT(e,t){return e.map(n=>({...n,attributes:n.attributes.filter(r=>!t.get(n.address)?.has(r.path))})).filter((n,r)=>n.attributes.length>0||e[r].attributes.length===0)}import{existsSync as kz,readdirSync as _z,readFileSync as Mce}from"node:fs";import{join as Lce,posix as Gce}from"node:path";var Sz=(e,t)=>JSON.stringify(e??null)===JSON.stringify(t??null);function nl(e){return(e?.resource_drift??[]).filter(n=>n.mode!=="data").map(n=>{let r=n.change.before??{},o=n.change.after??{},s=n.change.actions.includes("delete")?"delete":"update",i=u=>{let l=n.change.before_sensitive?.[u]??n.change.after_sensitive?.[u];return l!==void 0&&l!==!1&&!(typeof l=="object"&&l!==null&&Object.keys(l).length===0)},a=s==="delete"?[]:[...new Set([...Object.keys(r),...Object.keys(o)])].sort().filter(u=>!Sz(r[u],o[u])).map(u=>({path:u,before:r[u],live:o[u],...i(u)?{sensitive:!0}:{}})),c=["name","id","function_name","bucket"].map(u=>o[u]??r[u]).find(u=>typeof u=="string"&&u!=="");return{address:n.address,action:s,attributes:a,type:n.type,name:n.name,...c?{ref:c}:{},...n.module_address?{module:n.module_address}:{},...n.index!==void 0?{index:n.index}:{}}})}function Tv(e){let t=e.trim().replace(/\s*(#|\/\/).*$/,"");if(/^-?\d+(\.\d+)?$/.test(t))return{value:Number(t)};if(t==="true"||t==="false")return{value:t==="true"};if(/^"(?:[^"\\$%]|\\.|\$(?!\{)|%(?!\{))*"$/.test(t))try{return{value:JSON.parse(t)}}catch{return}}function YT(e){if(typeof e=="number"||typeof e=="boolean")return String(e);if(typeof e=="string")return JSON.stringify(e).replace(/\$\{/g,()=>"$${").replace(/%\{/g,()=>"%%{")}function Fce(e){return kz(e)?_z(e).filter(t=>t.endsWith(".tf")||t.endsWith(".tofu")).sort():[]}function $z(e,t,n){let r=new RegExp(`^\\s*resource\\s+"${t}"\\s+"${n}"\\s*\\{`),o=e.findIndex(i=>r.test(i));if(o<0)return;let s=0;for(let i=o;i<e.length;i++){for(let a of e[i].replace(/"(?:[^"\\]|\\.)*"/g,'""').replace(/#.*$/,""))(a==="{"||a==="["||a==="(")&&s++,(a==="}"||a==="]"||a===")")&&s--;if(s===0)return[o,i]}}function Av(e,t,n,r=new Map){let o=[],s=[],i=a=>r.get(a)??Mce(Lce(t,a),"utf-8");for(let a of n){let c=(g,m)=>s.push({root:e,address:a.address,...m?{path:m}:{},reason:g});if(a.action==="delete"){c("deleted outside Terraform; the next apply makes it again, or remove it from the code if that was the intent");continue}if(a.module){c(`reached through ${a.module}; the value is set in a module`);continue}if(a.index!==void 0){c("an instance of count or for_each; one literal sets every instance");continue}let u=Fce(t).find(g=>$z(i(g).split(`
473
473
  `),a.type,a.name));if(!u){c("its resource block is not in the root's files");continue}let l=i(u).split(`
474
474
  `),[d,p]=$z(l,a.type,a.name);for(let g of a.attributes){let m=0,h=-1;for(let k=d+1;k<p&&h<0;k++){m===0&&new RegExp(`^\\s*${g.path}\\s*=`).test(l[k])&&(h=k);for(let v of l[k].replace(/"(?:[^"\\]|\\.)*"/g,'""').replace(/#.*$/,""))(v==="{"||v==="["||v==="(")&&m++,(v==="}"||v==="]"||v===")")&&m--}if(h<0){c("not set in the root's block; it comes from a default or the provider",g.path);continue}let y=/^(\s*\S+\s*=\s*)(.*?)(\s*(?:#.*|\/\/.*)?)$/.exec(l[h]),w=Tv(y[2]);if(!w){c(`set from an expression (${y[2].trim()})`,g.path);continue}if(!Sz(w.value,g.before)){c("the root's value is not the one last applied, so the code moved too",g.path);continue}let b=YT(g.live);if(b===void 0){c("its live value is a list, a map or null",g.path);continue}l[h]=`${y[1]}${b}${y[3]}`,o.push({root:e,address:a.address,path:g.path,file:Gce.join(e,u),from:y[2].trim(),to:b})}let f=l.join(`